1 // Windows/FileIO.h 2 3 #ifndef ZIP7_INC_WINDOWS_FILE_IO_H 4 #define ZIP7_INC_WINDOWS_FILE_IO_H 5 6 #include "../Common/MyWindows.h" 7 8 #define Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) 9 #define Z7_WIN_IO_REPARSE_TAG_SYMLINK (0xA000000CL) 10 #define Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) 11 12 #define Z7_WIN_SYMLINK_FLAG_RELATIVE 1 13 14 // what the meaning of that FLAG or field (2)? 15 #define Z7_WIN_LX_SYMLINK_FLAG 2 16 17 #ifdef _WIN32 18 19 #if defined(_WIN32) && !defined(UNDER_CE) 20 #include <winioctl.h> 21 #endif 22 23 #else 24 25 #include <sys/types.h> 26 #include <sys/stat.h> 27 28 #endif 29 30 #include "../Common/MyString.h" 31 #include "../Common/MyBuffer.h" 32 33 #include "../Windows/TimeUtils.h" 34 35 #include "Defs.h" 36 37 HRESULT GetLastError_noZero_HRESULT(); 38 39 #define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER 40 #define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER 41 #define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER 42 43 namespace NWindows { 44 namespace NFile { 45 46 #if defined(_WIN32) && !defined(UNDER_CE) 47 bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); 48 #endif 49 50 struct CReparseShortInfo 51 { 52 unsigned Offset; 53 unsigned Size; 54 55 bool Parse(const Byte *p, size_t size); 56 }; 57 58 struct CReparseAttr 59 { 60 UInt32 Tag; 61 UInt32 Flags; 62 UString SubsName; 63 UString PrintName; 64 65 AString WslName; 66 67 bool HeaderError; 68 bool TagIsUnknown; 69 bool MinorError; 70 DWORD ErrorCode; 71 CReparseAttrCReparseAttr72 CReparseAttr(): Tag(0), Flags(0) {} 73 74 // Parse() 75 // returns (true) and (ErrorCode = 0), if (it'a correct known link) 76 // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag 77 bool Parse(const Byte *p, size_t size); 78 IsMountPointCReparseAttr79 bool IsMountPoint() const { return Tag == Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction IsSymLink_WinCReparseAttr80 bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } IsSymLink_WSLCReparseAttr81 bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } 82 IsRelative_WinCReparseAttr83 bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } 84 IsRelative_WSLCReparseAttr85 bool IsRelative_WSL() const 86 { 87 if (WslName.IsEmpty()) 88 return true; 89 char c = WslName[0]; 90 return !IS_PATH_SEPAR(c); 91 } 92 93 // bool IsVolume() const; 94 95 bool IsOkNamePair() const; 96 UString GetPath() const; 97 }; 98 99 #ifdef _WIN32 100 #define CFiInfo BY_HANDLE_FILE_INFORMATION 101 #define ST_MTIME(st) (st).ftLastWriteTime 102 #else 103 #define CFiInfo stat 104 #endif 105 106 #ifdef _WIN32 107 108 namespace NIO { 109 110 bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); 111 bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); 112 bool DeleteReparseData(CFSTR path); 113 114 class CFileBase MY_UNCOPYABLE 115 { 116 protected: 117 HANDLE _handle; 118 119 bool Create(CFSTR path, DWORD desiredAccess, 120 DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); 121 122 public: 123 124 bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize, 125 LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const 126 { 127 return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize, 128 outBuffer, outSize, bytesReturned, overlapped)); 129 } 130 DeviceIoControlOut(DWORD controlCode,LPVOID outBuffer,DWORD outSize,LPDWORD bytesReturned)131 bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const 132 { 133 return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned); 134 } 135 DeviceIoControlOut(DWORD controlCode,LPVOID outBuffer,DWORD outSize)136 bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const 137 { 138 DWORD bytesReturned; 139 return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned); 140 } 141 142 public: 143 bool PreserveATime; 144 #if 0 145 bool IsStdStream; 146 bool IsStdPipeStream; 147 #endif 148 #ifdef Z7_DEVICE_FILE 149 bool IsDeviceFile; 150 bool SizeDefined; 151 UInt64 Size; // it can be larger than real available size 152 #endif 153 CFileBase()154 CFileBase(): 155 _handle(INVALID_HANDLE_VALUE), 156 PreserveATime(false) 157 #if 0 158 , IsStdStream(false), 159 , IsStdPipeStream(false) 160 #endif 161 {} ~CFileBase()162 ~CFileBase() { Close(); } 163 GetHandle()164 HANDLE GetHandle() const { return _handle; } 165 166 // void Detach() { _handle = INVALID_HANDLE_VALUE; } 167 168 bool Close() throw(); 169 170 bool GetPosition(UInt64 &position) const throw(); 171 bool GetLength(UInt64 &length) const throw(); 172 173 bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw(); 174 bool Seek(UInt64 position, UInt64 &newPosition) const throw(); 175 bool SeekToBegin() const throw(); 176 bool SeekToEnd(UInt64 &newPosition) const throw(); 177 GetFileInformation(BY_HANDLE_FILE_INFORMATION * info)178 bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const 179 { return BOOLToBool(GetFileInformationByHandle(_handle, info)); } 180 GetFileInformation(CFSTR path,BY_HANDLE_FILE_INFORMATION * info)181 static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) 182 { 183 // probably it can work for complex paths: unsupported by another things 184 NIO::CFileBase file; 185 if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) 186 return false; 187 return file.GetFileInformation(info); 188 } 189 }; 190 191 #ifndef UNDER_CE 192 #define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM 193 #define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) 194 // #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) 195 196 // IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP 197 #define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) 198 199 struct my_DISK_GEOMETRY_EX 200 { 201 DISK_GEOMETRY Geometry; 202 LARGE_INTEGER DiskSize; 203 BYTE Data[1]; 204 }; 205 #endif 206 207 class CInFile: public CFileBase 208 { 209 #ifdef Z7_DEVICE_FILE 210 211 #ifndef UNDER_CE 212 GetGeometry(DISK_GEOMETRY * res)213 bool GetGeometry(DISK_GEOMETRY *res) const 214 { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } 215 GetGeometryEx(my_DISK_GEOMETRY_EX * res)216 bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const 217 { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); } 218 GetCdRomGeometry(DISK_GEOMETRY * res)219 bool GetCdRomGeometry(DISK_GEOMETRY *res) const 220 { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } 221 GetPartitionInfo(PARTITION_INFORMATION * res)222 bool GetPartitionInfo(PARTITION_INFORMATION *res) 223 { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); } 224 225 #endif 226 227 void CorrectDeviceSize(); 228 void CalcDeviceSize(CFSTR name); 229 230 #endif 231 232 public: 233 bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); 234 bool OpenShared(CFSTR fileName, bool shareForWrite); 235 bool Open(CFSTR fileName); 236 237 #if 0 238 bool AttachStdIn() 239 { 240 IsDeviceFile = false; 241 const HANDLE h = GetStdHandle(STD_INPUT_HANDLE); 242 if (h == INVALID_HANDLE_VALUE || !h) 243 return false; 244 IsStdStream = true; 245 IsStdPipeStream = true; 246 _handle = h; 247 return true; 248 } 249 #endif 250 251 #ifndef UNDER_CE 252 Open_for_ReadAttributes(CFSTR fileName)253 bool Open_for_ReadAttributes(CFSTR fileName) 254 { 255 return Create(fileName, FILE_READ_ATTRIBUTES, 256 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 257 OPEN_EXISTING, 258 FILE_FLAG_BACKUP_SEMANTICS); 259 // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. 260 } 261 Open_for_FileRenameInformation(CFSTR fileName)262 bool Open_for_FileRenameInformation(CFSTR fileName) 263 { 264 return Create(fileName, DELETE | SYNCHRONIZE | GENERIC_READ, 265 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 266 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); 267 // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. 268 } 269 OpenReparse(CFSTR fileName)270 bool OpenReparse(CFSTR fileName) 271 { 272 // 17.02 fix: to support Windows XP compatibility junctions: 273 // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ 274 return 275 Create(fileName, 0, 276 // Open(fileName, 277 FILE_SHARE_READ, OPEN_EXISTING, 278 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); 279 } 280 281 #endif 282 283 bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); 284 bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); 285 bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); 286 bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); 287 }; 288 289 class COutFile: public CFileBase 290 { 291 bool Open_Disposition(CFSTR fileName, DWORD creationDisposition); 292 public: 293 bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); Open_EXISTING(CFSTR fileName)294 bool Open_EXISTING(CFSTR fileName) 295 { return Open_Disposition(fileName, OPEN_EXISTING); } Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName,bool createAlways)296 bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways) 297 { return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : OPEN_ALWAYS); } Create_ALWAYS_or_NEW(CFSTR fileName,bool createAlways)298 bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways) 299 { return Open_Disposition(fileName, createAlways ? CREATE_ALWAYS : CREATE_NEW); } Create_ALWAYS(CFSTR fileName)300 bool Create_ALWAYS(CFSTR fileName) 301 { return Open_Disposition(fileName, CREATE_ALWAYS); } Create_NEW(CFSTR fileName)302 bool Create_NEW(CFSTR fileName) 303 { return Open_Disposition(fileName, CREATE_NEW); } 304 305 bool Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes); 306 307 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); 308 bool SetMTime(const CFiTime *mTime) throw(); 309 bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); 310 bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); 311 bool WriteFull(const void *data, size_t size) throw(); 312 bool SetEndOfFile() throw(); 313 bool SetLength(UInt64 length) throw(); 314 bool SetLength_KeepPosition(UInt64 length) throw(); 315 }; 316 317 } 318 319 320 #else // _WIN32 321 322 namespace NIO { 323 324 bool GetReparseData(CFSTR path, CByteBuffer &reparseData); 325 // bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); 326 327 // parameters are in reverse order of symlink() function !!! 328 bool SetSymLink(CFSTR from, CFSTR to); 329 bool SetSymLink_UString(CFSTR from, const UString &to); 330 331 332 class CFileBase 333 { 334 protected: 335 int _handle; 336 337 /* 338 bool IsDeviceFile; 339 bool SizeDefined; 340 UInt64 Size; // it can be larger than real available size 341 */ 342 343 bool OpenBinary(const char *name, int flags, mode_t mode = 0666); 344 public: 345 bool PreserveATime; 346 #if 0 347 bool IsStdStream; 348 #endif 349 CFileBase()350 CFileBase(): _handle(-1), PreserveATime(false) 351 #if 0 352 , IsStdStream(false) 353 #endif 354 {} ~CFileBase()355 ~CFileBase() { Close(); } 356 // void Detach() { _handle = -1; } 357 bool Close(); 358 bool GetLength(UInt64 &length) const; 359 off_t seek(off_t distanceToMove, int moveMethod) const; 360 off_t seekToBegin() const throw(); 361 off_t seekToCur() const throw(); 362 // bool SeekToBegin() throw(); my_fstat(struct stat * st)363 int my_fstat(struct stat *st) const { return fstat(_handle, st); } 364 /* 365 int my_ioctl_BLKGETSIZE64(unsigned long long *val); 366 int GetDeviceSize_InBytes(UInt64 &size); 367 void CalcDeviceSize(CFSTR s); 368 */ 369 }; 370 371 class CInFile: public CFileBase 372 { 373 public: 374 bool Open(const char *name); 375 bool OpenShared(const char *name, bool shareForWrite); 376 #if 0 377 bool AttachStdIn() 378 { 379 _handle = GetStdHandle(STD_INPUT_HANDLE); 380 if (_handle == INVALID_HANDLE_VALUE || !_handle) 381 return false; 382 IsStdStream = true; 383 } 384 #endif 385 ssize_t read_part(void *data, size_t size) throw(); 386 // ssize_t read_full(void *data, size_t size, size_t &processed); 387 bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); 388 }; 389 390 class COutFile: public CFileBase 391 { 392 bool CTime_defined; 393 bool ATime_defined; 394 bool MTime_defined; 395 CFiTime CTime; 396 CFiTime ATime; 397 CFiTime MTime; 398 399 AString Path; 400 ssize_t write_part(const void *data, size_t size) throw(); 401 bool OpenBinary_forWrite_oflag(const char *name, int oflag); 402 public: 403 mode_t mode_for_Create; 404 COutFile()405 COutFile(): 406 CTime_defined(false), 407 ATime_defined(false), 408 MTime_defined(false), 409 mode_for_Create(0666) 410 {} 411 412 bool Close(); 413 414 bool Open_EXISTING(CFSTR fileName); 415 bool Create_ALWAYS_or_Open_ALWAYS(CFSTR fileName, bool createAlways); 416 bool Create_ALWAYS(CFSTR fileName); 417 bool Create_NEW(CFSTR fileName); 418 // bool Create_ALWAYS_or_NEW(CFSTR fileName, bool createAlways); 419 // bool Open_Disposition(const char *name, DWORD creationDisposition); 420 421 ssize_t write_full(const void *data, size_t size, size_t &processed) throw(); 422 WriteFull(const void * data,size_t size)423 bool WriteFull(const void *data, size_t size) throw() 424 { 425 size_t processed; 426 ssize_t res = write_full(data, size, processed); 427 if (res == -1) 428 return false; 429 return processed == size; 430 } 431 432 bool SetLength(UInt64 length) throw(); SetLength_KeepPosition(UInt64 length)433 bool SetLength_KeepPosition(UInt64 length) throw() 434 { 435 return SetLength(length); 436 } 437 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); 438 bool SetMTime(const CFiTime *mTime) throw(); 439 }; 440 441 } 442 443 #endif // _WIN32 444 445 }} 446 447 448 #endif 449