• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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   #ifdef Z7_DEVICE_FILE
145   bool IsDeviceFile;
146   bool SizeDefined;
147   UInt64 Size; // it can be larger than real available size
148   #endif
149 
CFileBase()150   CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {}
~CFileBase()151   ~CFileBase() { Close(); }
152 
GetHandle()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 
GetFileInformation(BY_HANDLE_FILE_INFORMATION * info)167   bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const
168     { return BOOLToBool(GetFileInformationByHandle(_handle, info)); }
169 
GetFileInformation(CFSTR path,BY_HANDLE_FILE_INFORMATION * info)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 
188 struct my_DISK_GEOMETRY_EX
189 {
190   DISK_GEOMETRY Geometry;
191   LARGE_INTEGER DiskSize;
192   BYTE Data[1];
193 };
194 #endif
195 
196 class CInFile: public CFileBase
197 {
198   #ifdef Z7_DEVICE_FILE
199 
200   #ifndef UNDER_CE
201 
GetGeometry(DISK_GEOMETRY * res)202   bool GetGeometry(DISK_GEOMETRY *res) const
203     { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
204 
GetGeometryEx(my_DISK_GEOMETRY_EX * res)205   bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const
206     { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); }
207 
GetCdRomGeometry(DISK_GEOMETRY * res)208   bool GetCdRomGeometry(DISK_GEOMETRY *res) const
209     { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
210 
GetPartitionInfo(PARTITION_INFORMATION * res)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 
221 public:
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 
Open_for_ReadAttributes(CFSTR fileName)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 
Open_for_FileRenameInformation(CFSTR fileName)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 
OpenReparse(CFSTR fileName)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 
264 class COutFile: public CFileBase
265 {
266 public:
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 
287 namespace NIO {
288 
289 bool 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 !!!
293 bool SetSymLink(CFSTR from, CFSTR to);
294 bool SetSymLink_UString(CFSTR from, const UString &to);
295 
296 
297 class CFileBase
298 {
299 protected:
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);
309 public:
310   bool PreserveATime;
311 
CFileBase()312   CFileBase(): _handle(-1), PreserveATime(false) {}
~CFileBase()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();
my_fstat(struct stat * st)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 
329 class CInFile: public CFileBase
330 {
331 public:
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 
339 class 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();
350 public:
351   mode_t mode_for_Create;
352 
COutFile()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 
WriteFull(const void * data,size_t size)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();
SetLength_KeepPosition(UInt64 length)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