diff options
Diffstat (limited to '')
-rw-r--r-- | CPP/Windows/FileDir.cpp | 211 |
1 files changed, 164 insertions, 47 deletions
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index dfeed82..ad0d8c9 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp | |||
@@ -15,8 +15,9 @@ | |||
15 | #include <sys/stat.h> | 15 | #include <sys/stat.h> |
16 | #include <sys/types.h> | 16 | #include <sys/types.h> |
17 | 17 | ||
18 | #include "../Common/StringConvert.h" | ||
19 | #include "../Common/C_FileIO.h" | 18 | #include "../Common/C_FileIO.h" |
19 | #include "../Common/MyBuffer2.h" | ||
20 | #include "../Common/StringConvert.h" | ||
20 | #endif | 21 | #endif |
21 | 22 | ||
22 | #include "FileDir.h" | 23 | #include "FileDir.h" |
@@ -123,7 +124,7 @@ bool GetSystemDir(FString &path) | |||
123 | #endif // UNDER_CE | 124 | #endif // UNDER_CE |
124 | 125 | ||
125 | 126 | ||
126 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | 127 | static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, DWORD dwFlagsAndAttributes) |
127 | { | 128 | { |
128 | #ifndef _UNICODE | 129 | #ifndef _UNICODE |
129 | if (!g_IsNT) | 130 | if (!g_IsNT) |
@@ -136,14 +137,14 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF | |||
136 | HANDLE hDir = INVALID_HANDLE_VALUE; | 137 | HANDLE hDir = INVALID_HANDLE_VALUE; |
137 | IF_USE_MAIN_PATH | 138 | IF_USE_MAIN_PATH |
138 | hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | 139 | hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, |
139 | NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 140 | NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); |
140 | #ifdef Z7_LONG_PATH | 141 | #ifdef Z7_LONG_PATH |
141 | if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) | 142 | if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH) |
142 | { | 143 | { |
143 | UString superPath; | 144 | UString superPath; |
144 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) | 145 | if (GetSuperPath(path, superPath, USE_MAIN_PATH)) |
145 | hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, | 146 | hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, |
146 | NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); | 147 | NULL, OPEN_EXISTING, dwFlagsAndAttributes, NULL); |
147 | } | 148 | } |
148 | #endif | 149 | #endif |
149 | 150 | ||
@@ -156,6 +157,15 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF | |||
156 | return res; | 157 | return res; |
157 | } | 158 | } |
158 | 159 | ||
160 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
161 | { | ||
162 | return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS); | ||
163 | } | ||
164 | |||
165 | bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
166 | { | ||
167 | return SetFileTime_Base(path, cTime, aTime, mTime, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT); | ||
168 | } | ||
159 | 169 | ||
160 | 170 | ||
161 | bool SetFileAttrib(CFSTR path, DWORD attrib) | 171 | bool SetFileAttrib(CFSTR path, DWORD attrib) |
@@ -222,6 +232,8 @@ bool RemoveDir(CFSTR path) | |||
222 | } | 232 | } |
223 | 233 | ||
224 | 234 | ||
235 | // When moving a directory, oldFile and newFile must be on the same drive. | ||
236 | |||
225 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | 237 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) |
226 | { | 238 | { |
227 | #ifndef _UNICODE | 239 | #ifndef _UNICODE |
@@ -250,6 +262,59 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | |||
250 | return false; | 262 | return false; |
251 | } | 263 | } |
252 | 264 | ||
265 | #if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500 | ||
266 | static DWORD WINAPI CopyProgressRoutine_to_ICopyFileProgress( | ||
267 | LARGE_INTEGER TotalFileSize, // file size | ||
268 | LARGE_INTEGER TotalBytesTransferred, // bytes transferred | ||
269 | LARGE_INTEGER /* StreamSize */, // bytes in stream | ||
270 | LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream | ||
271 | DWORD /* dwStreamNumber */, // current stream | ||
272 | DWORD /* dwCallbackReason */, // callback reason | ||
273 | HANDLE /* hSourceFile */, // handle to source file | ||
274 | HANDLE /* hDestinationFile */, // handle to destination file | ||
275 | LPVOID lpData // from CopyFileEx | ||
276 | ) | ||
277 | { | ||
278 | return ((ICopyFileProgress *)lpData)->CopyFileProgress( | ||
279 | (UInt64)TotalFileSize.QuadPart, | ||
280 | (UInt64)TotalBytesTransferred.QuadPart); | ||
281 | } | ||
282 | #endif | ||
283 | |||
284 | bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, | ||
285 | ICopyFileProgress *progress) | ||
286 | { | ||
287 | #if defined(Z7_WIN32_WINNT_MIN) && Z7_WIN32_WINNT_MIN >= 0x0500 | ||
288 | #ifndef _UNICODE | ||
289 | if (g_IsNT) | ||
290 | #endif | ||
291 | if (progress) | ||
292 | { | ||
293 | IF_USE_MAIN_PATH_2(oldFile, newFile) | ||
294 | { | ||
295 | if (::MoveFileWithProgressW(fs2us(oldFile), fs2us(newFile), | ||
296 | CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED)) | ||
297 | return true; | ||
298 | if (::GetLastError() == ERROR_REQUEST_ABORTED) | ||
299 | return false; | ||
300 | } | ||
301 | #ifdef Z7_LONG_PATH | ||
302 | if (USE_SUPER_PATH_2) | ||
303 | { | ||
304 | UString d1, d2; | ||
305 | if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2)) | ||
306 | return BOOLToBool(::MoveFileWithProgressW(d1, d2, | ||
307 | CopyProgressRoutine_to_ICopyFileProgress, progress, MOVEFILE_COPY_ALLOWED)); | ||
308 | } | ||
309 | #endif | ||
310 | return false; | ||
311 | } | ||
312 | #else | ||
313 | UNUSED_VAR(progress) | ||
314 | #endif | ||
315 | return MyMoveFile(oldFile, newFile); | ||
316 | } | ||
317 | |||
253 | #ifndef UNDER_CE | 318 | #ifndef UNDER_CE |
254 | #if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 | 319 | #if !defined(Z7_WIN32_WINNT_MIN) || Z7_WIN32_WINNT_MIN < 0x0500 // Win2000 |
255 | #define Z7_USE_DYN_CreateHardLink | 320 | #define Z7_USE_DYN_CreateHardLink |
@@ -595,6 +660,35 @@ bool RemoveDirWithSubItems(const FString &path) | |||
595 | return RemoveDir(path); | 660 | return RemoveDir(path); |
596 | } | 661 | } |
597 | 662 | ||
663 | bool RemoveDirAlways_if_Empty(const FString &path) | ||
664 | { | ||
665 | const DWORD attrib = NFind::GetFileAttrib(path); | ||
666 | if (attrib != INVALID_FILE_ATTRIBUTES | ||
667 | && (attrib & FILE_ATTRIBUTE_READONLY)) | ||
668 | { | ||
669 | bool need_ClearAttrib = true; | ||
670 | if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0) | ||
671 | { | ||
672 | FString s (path); | ||
673 | s.Add_PathSepar(); | ||
674 | NFind::CEnumerator enumerator; | ||
675 | enumerator.SetDirPrefix(s); | ||
676 | NFind::CDirEntry fi; | ||
677 | if (enumerator.Next(fi)) | ||
678 | { | ||
679 | // we don't want to change attributes, if there are files | ||
680 | // in directory, because RemoveDir(path) will fail. | ||
681 | need_ClearAttrib = false; | ||
682 | // SetLastError(ERROR_DIR_NOT_EMPTY); | ||
683 | // return false; | ||
684 | } | ||
685 | } | ||
686 | if (need_ClearAttrib) | ||
687 | SetFileAttrib(path, 0); // we clear read-only attrib to remove read-only dir | ||
688 | } | ||
689 | return RemoveDir(path); | ||
690 | } | ||
691 | |||
598 | #endif // _WIN32 | 692 | #endif // _WIN32 |
599 | 693 | ||
600 | #ifdef UNDER_CE | 694 | #ifdef UNDER_CE |
@@ -878,9 +972,9 @@ bool CTempFile::Remove() | |||
878 | return !_mustBeDeleted; | 972 | return !_mustBeDeleted; |
879 | } | 973 | } |
880 | 974 | ||
881 | bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) | 975 | bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore, |
976 | ICopyFileProgress *progress) | ||
882 | { | 977 | { |
883 | // DWORD attrib = 0; | ||
884 | if (deleteDestBefore) | 978 | if (deleteDestBefore) |
885 | { | 979 | { |
886 | if (NFind::DoesFileExist_Raw(name)) | 980 | if (NFind::DoesFileExist_Raw(name)) |
@@ -891,8 +985,8 @@ bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) | |||
891 | } | 985 | } |
892 | } | 986 | } |
893 | DisableDeleting(); | 987 | DisableDeleting(); |
894 | return MyMoveFile(_path, name); | 988 | // if (!progress) return MyMoveFile(_path, name); |
895 | 989 | return MyMoveFile_with_Progress(_path, name, progress); | |
896 | /* | 990 | /* |
897 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) | 991 | if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY)) |
898 | { | 992 | { |
@@ -941,34 +1035,59 @@ bool RemoveDir(CFSTR path) | |||
941 | } | 1035 | } |
942 | 1036 | ||
943 | 1037 | ||
944 | static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) | 1038 | static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile, ICopyFileProgress *progress) |
945 | { | 1039 | { |
946 | NWindows::NFile::NIO::COutFile outFile; | ||
947 | if (!outFile.Create_NEW(newFile)) | ||
948 | return FALSE; | ||
949 | |||
950 | NWindows::NFile::NIO::CInFile inFile; | ||
951 | if (!inFile.Open(oldFile)) | ||
952 | return FALSE; | ||
953 | |||
954 | char buf[1 << 14]; | ||
955 | |||
956 | for (;;) | ||
957 | { | 1040 | { |
958 | const ssize_t num = inFile.read_part(buf, sizeof(buf)); | 1041 | NIO::COutFile outFile; |
959 | if (num == 0) | 1042 | if (!outFile.Create_NEW(newFile)) |
960 | return TRUE; | ||
961 | if (num < 0) | ||
962 | return FALSE; | 1043 | return FALSE; |
963 | size_t processed; | 1044 | NIO::CInFile inFile; |
964 | const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); | 1045 | if (!inFile.Open(oldFile)) |
965 | if (num2 != num || processed != (size_t)num) | ||
966 | return FALSE; | 1046 | return FALSE; |
1047 | |||
1048 | const size_t k_BufSize = 1 << 16; | ||
1049 | CAlignedBuffer1 buf(k_BufSize); | ||
1050 | |||
1051 | UInt64 length = 0; | ||
1052 | if (progress && !inFile.GetLength(length)) | ||
1053 | length = 0; | ||
1054 | UInt64 prev = 0; | ||
1055 | UInt64 cur = 0; | ||
1056 | for (;;) | ||
1057 | { | ||
1058 | const ssize_t num = inFile.read_part(buf, k_BufSize); | ||
1059 | if (num == 0) | ||
1060 | return TRUE; | ||
1061 | if (num < 0) | ||
1062 | break; | ||
1063 | size_t processed; | ||
1064 | const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); | ||
1065 | if (num2 != num || processed != (size_t)num) | ||
1066 | break; | ||
1067 | cur += (size_t)num2; | ||
1068 | if (progress && cur - prev >= (1u << 20)) | ||
1069 | { | ||
1070 | prev = cur; | ||
1071 | if (progress->CopyFileProgress(length, cur) != PROGRESS_CONTINUE) | ||
1072 | { | ||
1073 | errno = EINTR; // instead of WIN32::ERROR_REQUEST_ABORTED | ||
1074 | break; | ||
1075 | } | ||
1076 | } | ||
1077 | } | ||
967 | } | 1078 | } |
1079 | // There is file IO error or process was interrupted by user. | ||
1080 | // We close output file and delete it. | ||
1081 | // DeleteFileAlways doesn't change errno (if successed), but we restore errno. | ||
1082 | const int errno_save = errno; | ||
1083 | DeleteFileAlways(newFile); | ||
1084 | errno = errno_save; | ||
1085 | return FALSE; | ||
968 | } | 1086 | } |
969 | 1087 | ||
970 | 1088 | ||
971 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | 1089 | bool MyMoveFile_with_Progress(CFSTR oldFile, CFSTR newFile, |
1090 | ICopyFileProgress *progress) | ||
972 | { | 1091 | { |
973 | int res = rename(oldFile, newFile); | 1092 | int res = rename(oldFile, newFile); |
974 | if (res == 0) | 1093 | if (res == 0) |
@@ -976,7 +1095,7 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | |||
976 | if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) | 1095 | if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) |
977 | return false; | 1096 | return false; |
978 | 1097 | ||
979 | if (My_CopyFile(oldFile, newFile) == FALSE) | 1098 | if (My_CopyFile(oldFile, newFile, progress) == FALSE) |
980 | return false; | 1099 | return false; |
981 | 1100 | ||
982 | struct stat info_file; | 1101 | struct stat info_file; |
@@ -990,6 +1109,11 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | |||
990 | return (unlink(oldFile) == 0); | 1109 | return (unlink(oldFile) == 0); |
991 | } | 1110 | } |
992 | 1111 | ||
1112 | bool MyMoveFile(CFSTR oldFile, CFSTR newFile) | ||
1113 | { | ||
1114 | return MyMoveFile_with_Progress(oldFile, newFile, NULL); | ||
1115 | } | ||
1116 | |||
993 | 1117 | ||
994 | bool CreateDir(CFSTR path) | 1118 | bool CreateDir(CFSTR path) |
995 | { | 1119 | { |
@@ -1058,17 +1182,15 @@ bool GetCurrentDir(FString &path) | |||
1058 | 1182 | ||
1059 | 1183 | ||
1060 | 1184 | ||
1061 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | 1185 | static bool SetFileTime_Base(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime, const int flags) |
1062 | { | 1186 | { |
1063 | // need testing | 1187 | // need testing |
1064 | /* | 1188 | /* |
1065 | struct utimbuf buf; | 1189 | struct utimbuf buf; |
1066 | struct stat st; | 1190 | struct stat st; |
1067 | UNUSED_VAR(cTime) | 1191 | UNUSED_VAR(cTime) |
1068 | |||
1069 | printf("\nstat = %s\n", path); | 1192 | printf("\nstat = %s\n", path); |
1070 | int ret = stat(path, &st); | 1193 | int ret = stat(path, &st); |
1071 | |||
1072 | if (ret == 0) | 1194 | if (ret == 0) |
1073 | { | 1195 | { |
1074 | buf.actime = st.st_atime; | 1196 | buf.actime = st.st_atime; |
@@ -1080,47 +1202,42 @@ bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CF | |||
1080 | buf.actime = cur_time; | 1202 | buf.actime = cur_time; |
1081 | buf.modtime = cur_time; | 1203 | buf.modtime = cur_time; |
1082 | } | 1204 | } |
1083 | |||
1084 | if (aTime) | 1205 | if (aTime) |
1085 | { | 1206 | { |
1086 | UInt32 ut; | 1207 | UInt32 ut; |
1087 | if (NTime::FileTimeToUnixTime(*aTime, ut)) | 1208 | if (NTime::FileTimeToUnixTime(*aTime, ut)) |
1088 | buf.actime = ut; | 1209 | buf.actime = ut; |
1089 | } | 1210 | } |
1090 | |||
1091 | if (mTime) | 1211 | if (mTime) |
1092 | { | 1212 | { |
1093 | UInt32 ut; | 1213 | UInt32 ut; |
1094 | if (NTime::FileTimeToUnixTime(*mTime, ut)) | 1214 | if (NTime::FileTimeToUnixTime(*mTime, ut)) |
1095 | buf.modtime = ut; | 1215 | buf.modtime = ut; |
1096 | } | 1216 | } |
1097 | |||
1098 | return utime(path, &buf) == 0; | 1217 | return utime(path, &buf) == 0; |
1099 | */ | 1218 | */ |
1100 | 1219 | ||
1101 | // if (!aTime && !mTime) return true; | 1220 | // if (!aTime && !mTime) return true; |
1102 | |||
1103 | struct timespec times[2]; | 1221 | struct timespec times[2]; |
1104 | UNUSED_VAR(cTime) | 1222 | UNUSED_VAR(cTime) |
1105 | |||
1106 | bool needChange; | 1223 | bool needChange; |
1107 | needChange = FiTime_To_timespec(aTime, times[0]); | 1224 | needChange = FiTime_To_timespec(aTime, times[0]); |
1108 | needChange |= FiTime_To_timespec(mTime, times[1]); | 1225 | needChange |= FiTime_To_timespec(mTime, times[1]); |
1109 | 1226 | // if (mTime) { printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); } | |
1110 | /* | ||
1111 | if (mTime) | ||
1112 | { | ||
1113 | printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec); | ||
1114 | } | ||
1115 | */ | ||
1116 | |||
1117 | if (!needChange) | 1227 | if (!needChange) |
1118 | return true; | 1228 | return true; |
1119 | const int flags = 0; // follow link | ||
1120 | // = AT_SYMLINK_NOFOLLOW; // don't follow link | ||
1121 | return utimensat(AT_FDCWD, path, times, flags) == 0; | 1229 | return utimensat(AT_FDCWD, path, times, flags) == 0; |
1122 | } | 1230 | } |
1123 | 1231 | ||
1232 | bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
1233 | { | ||
1234 | return SetFileTime_Base(path, cTime, aTime, mTime, 0); // (flags = 0) means follow_link | ||
1235 | } | ||
1236 | |||
1237 | bool SetLinkFileTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) | ||
1238 | { | ||
1239 | return SetFileTime_Base(path, cTime, aTime, mTime, AT_SYMLINK_NOFOLLOW); | ||
1240 | } | ||
1124 | 1241 | ||
1125 | 1242 | ||
1126 | struct C_umask | 1243 | struct C_umask |