aboutsummaryrefslogtreecommitdiff
path: root/CPP/Windows/FileDir.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CPP/Windows/FileDir.cpp211
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
126bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) 127static 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
160bool 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
165bool 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
161bool SetFileAttrib(CFSTR path, DWORD attrib) 171bool 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
225bool MyMoveFile(CFSTR oldFile, CFSTR newFile) 237bool 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
266static 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
284bool 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
663bool 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
881bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) 975bool 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
944static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile) 1038static 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
971bool MyMoveFile(CFSTR oldFile, CFSTR newFile) 1089bool 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
1112bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
1113{
1114 return MyMoveFile_with_Progress(oldFile, newFile, NULL);
1115}
1116
993 1117
994bool CreateDir(CFSTR path) 1118bool CreateDir(CFSTR path)
995{ 1119{
@@ -1058,17 +1182,15 @@ bool GetCurrentDir(FString &path)
1058 1182
1059 1183
1060 1184
1061bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) 1185static 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
1232bool 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
1237bool 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
1126struct C_umask 1243struct C_umask