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 37HRESULT 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 43namespace NWindows { 44namespace NFile { 45 46#if defined(_WIN32) && !defined(UNDER_CE) 47bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); 48#endif 49 50struct CReparseShortInfo 51{ 52 unsigned Offset; 53 unsigned Size; 54 55 bool Parse(const Byte *p, size_t size); 56}; 57 58struct 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 72 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 79 bool IsMountPoint() const { return Tag == Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction 80 bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; } 81 bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; } 82 83 bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; } 84 85 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 108namespace NIO { 109 110bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); 111bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); 112bool DeleteReparseData(CFSTR path); 113 114class CFileBase MY_UNCOPYABLE 115{ 116protected: 117 HANDLE _handle; 118 119 bool Create(CFSTR path, DWORD desiredAccess, 120 DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); 121 122public: 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 131 bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const 132 { 133 return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned); 134 } 135 136 bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const 137 { 138 DWORD bytesReturned; 139 return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned); 140 } 141 142public: 143 bool PreserveATime; 144 #ifdef Z7_DEVICE_FILE 145 bool IsDeviceFile; 146 bool SizeDefined; 147 UInt64 Size; // it can be larger than real available size 148 #endif 149 150 CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {} 151 ~CFileBase() { Close(); } 152 153 HANDLE GetHandle() const { return _handle; } 154 155 // void Detach() { _handle = INVALID_HANDLE_VALUE; } 156 157 bool Close() throw(); 158 159 bool GetPosition(UInt64 &position) const throw(); 160 bool GetLength(UInt64 &length) const throw(); 161 162 bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw(); 163 bool Seek(UInt64 position, UInt64 &newPosition) const throw(); 164 bool SeekToBegin() const throw(); 165 bool SeekToEnd(UInt64 &newPosition) const throw(); 166 167 bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const 168 { return BOOLToBool(GetFileInformationByHandle(_handle, info)); } 169 170 static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) 171 { 172 // probably it can work for complex paths: unsupported by another things 173 NIO::CFileBase file; 174 if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) 175 return false; 176 return file.GetFileInformation(info); 177 } 178}; 179 180#ifndef UNDER_CE 181#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM 182#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS) 183// #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS) 184 185// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP 186#define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS) 187 188struct my_DISK_GEOMETRY_EX 189{ 190 DISK_GEOMETRY Geometry; 191 LARGE_INTEGER DiskSize; 192 BYTE Data[1]; 193}; 194#endif 195 196class CInFile: public CFileBase 197{ 198 #ifdef Z7_DEVICE_FILE 199 200 #ifndef UNDER_CE 201 202 bool GetGeometry(DISK_GEOMETRY *res) const 203 { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } 204 205 bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const 206 { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); } 207 208 bool GetCdRomGeometry(DISK_GEOMETRY *res) const 209 { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); } 210 211 bool GetPartitionInfo(PARTITION_INFORMATION *res) 212 { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); } 213 214 #endif 215 216 void CorrectDeviceSize(); 217 void CalcDeviceSize(CFSTR name); 218 219 #endif 220 221public: 222 bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); 223 bool OpenShared(CFSTR fileName, bool shareForWrite); 224 bool Open(CFSTR fileName); 225 226 #ifndef UNDER_CE 227 228 bool Open_for_ReadAttributes(CFSTR fileName) 229 { 230 return Create(fileName, FILE_READ_ATTRIBUTES, 231 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 232 OPEN_EXISTING, 233 FILE_FLAG_BACKUP_SEMANTICS); 234 // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. 235 } 236 237 bool Open_for_FileRenameInformation(CFSTR fileName) 238 { 239 return Create(fileName, DELETE | SYNCHRONIZE | GENERIC_READ, 240 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 241 OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); 242 // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory. 243 } 244 245 bool OpenReparse(CFSTR fileName) 246 { 247 // 17.02 fix: to support Windows XP compatibility junctions: 248 // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ 249 return 250 Create(fileName, 0, 251 // Open(fileName, 252 FILE_SHARE_READ, OPEN_EXISTING, 253 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS); 254 } 255 256 #endif 257 258 bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); 259 bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); 260 bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); 261 bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); 262}; 263 264class COutFile: public CFileBase 265{ 266public: 267 bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); 268 bool Open(CFSTR fileName, DWORD creationDisposition); 269 bool Create(CFSTR fileName, bool createAlways); 270 bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes); 271 272 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); 273 bool SetMTime(const CFiTime *mTime) throw(); 274 bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw(); 275 bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw(); 276 bool WriteFull(const void *data, size_t size) throw(); 277 bool SetEndOfFile() throw(); 278 bool SetLength(UInt64 length) throw(); 279 bool SetLength_KeepPosition(UInt64 length) throw(); 280}; 281 282} 283 284 285#else // _WIN32 286 287namespace NIO { 288 289bool GetReparseData(CFSTR path, CByteBuffer &reparseData); 290// bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); 291 292// parameters are in reverse order of symlink() function !!! 293bool SetSymLink(CFSTR from, CFSTR to); 294bool SetSymLink_UString(CFSTR from, const UString &to); 295 296 297class CFileBase 298{ 299protected: 300 int _handle; 301 302 /* 303 bool IsDeviceFile; 304 bool SizeDefined; 305 UInt64 Size; // it can be larger than real available size 306 */ 307 308 bool OpenBinary(const char *name, int flags, mode_t mode = 0666); 309public: 310 bool PreserveATime; 311 312 CFileBase(): _handle(-1), PreserveATime(false) {} 313 ~CFileBase() { Close(); } 314 // void Detach() { _handle = -1; } 315 bool Close(); 316 bool GetLength(UInt64 &length) const; 317 off_t seek(off_t distanceToMove, int moveMethod) const; 318 off_t seekToBegin() const throw(); 319 off_t seekToCur() const throw(); 320 // bool SeekToBegin() throw(); 321 int my_fstat(struct stat *st) const { return fstat(_handle, st); } 322 /* 323 int my_ioctl_BLKGETSIZE64(unsigned long long *val); 324 int GetDeviceSize_InBytes(UInt64 &size); 325 void CalcDeviceSize(CFSTR s); 326 */ 327}; 328 329class CInFile: public CFileBase 330{ 331public: 332 bool Open(const char *name); 333 bool OpenShared(const char *name, bool shareForWrite); 334 ssize_t read_part(void *data, size_t size) throw(); 335 // ssize_t read_full(void *data, size_t size, size_t &processed); 336 bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); 337}; 338 339class COutFile: public CFileBase 340{ 341 bool CTime_defined; 342 bool ATime_defined; 343 bool MTime_defined; 344 CFiTime CTime; 345 CFiTime ATime; 346 CFiTime MTime; 347 348 AString Path; 349 ssize_t write_part(const void *data, size_t size) throw(); 350public: 351 mode_t mode_for_Create; 352 353 COutFile(): 354 CTime_defined(false), 355 ATime_defined(false), 356 MTime_defined(false), 357 mode_for_Create(0666) 358 {} 359 360 bool Close(); 361 bool Create(const char *name, bool createAlways); 362 bool Open(const char *name, DWORD creationDisposition); 363 ssize_t write_full(const void *data, size_t size, size_t &processed) throw(); 364 365 bool WriteFull(const void *data, size_t size) throw() 366 { 367 size_t processed; 368 ssize_t res = write_full(data, size, processed); 369 if (res == -1) 370 return false; 371 return processed == size; 372 } 373 374 bool SetLength(UInt64 length) throw(); 375 bool SetLength_KeepPosition(UInt64 length) throw() 376 { 377 return SetLength(length); 378 } 379 bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw(); 380 bool SetMTime(const CFiTime *mTime) throw(); 381}; 382 383} 384 385#endif // _WIN32 386 387}} 388 389 390#endif 391