• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Windows/FileIO.h
2 
3 #ifndef __WINDOWS_FILE_IO_H
4 #define __WINDOWS_FILE_IO_H
5 
6 #include "../Common/MyWindows.h"
7 
8 #define _my_IO_REPARSE_TAG_MOUNT_POINT  (0xA0000003L)
9 #define _my_IO_REPARSE_TAG_SYMLINK      (0xA000000CL)
10 #define _my_IO_REPARSE_TAG_LX_SYMLINK   (0xA000001DL)
11 
12 #define _my_SYMLINK_FLAG_RELATIVE 1
13 
14 // what the meaning of that FLAG or field (2)?
15 #define _my_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 == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction
IsSymLink_WinCReparseAttr80   bool IsSymLink_Win() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; }
IsSymLink_WSLCReparseAttr81   bool IsSymLink_WSL() const { return Tag == _my_IO_REPARSE_TAG_LX_SYMLINK; }
82 
IsRelative_WinCReparseAttr83   bool IsRelative_Win() const { return Flags == _my_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 SUPPORT_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   bool Close() throw();
156 
157   bool GetPosition(UInt64 &position) const throw();
158   bool GetLength(UInt64 &length) const throw();
159 
160   bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw();
161   bool Seek(UInt64 position, UInt64 &newPosition) const throw();
162   bool SeekToBegin() const throw();
163   bool SeekToEnd(UInt64 &newPosition) const throw();
164 
GetFileInformation(BY_HANDLE_FILE_INFORMATION * info)165   bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const
166     { return BOOLToBool(GetFileInformationByHandle(_handle, info)); }
167 
GetFileInformation(CFSTR path,BY_HANDLE_FILE_INFORMATION * info)168   static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info)
169   {
170     // probably it can work for complex paths: unsupported by another things
171     NIO::CFileBase file;
172     if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS))
173       return false;
174     return file.GetFileInformation(info);
175   }
176 };
177 
178 #ifndef UNDER_CE
179 #define IOCTL_CDROM_BASE  FILE_DEVICE_CD_ROM
180 #define IOCTL_CDROM_GET_DRIVE_GEOMETRY  CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
181 // #define IOCTL_CDROM_MEDIA_REMOVAL  CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
182 
183 // IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP
184 #define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX  CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS)
185 
186 struct my_DISK_GEOMETRY_EX
187 {
188   DISK_GEOMETRY Geometry;
189   LARGE_INTEGER DiskSize;
190   BYTE Data[1];
191 };
192 #endif
193 
194 class CInFile: public CFileBase
195 {
196   #ifdef SUPPORT_DEVICE_FILE
197 
198   #ifndef UNDER_CE
199 
GetGeometry(DISK_GEOMETRY * res)200   bool GetGeometry(DISK_GEOMETRY *res) const
201     { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
202 
GetGeometryEx(my_DISK_GEOMETRY_EX * res)203   bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const
204     { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); }
205 
GetCdRomGeometry(DISK_GEOMETRY * res)206   bool GetCdRomGeometry(DISK_GEOMETRY *res) const
207     { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
208 
GetPartitionInfo(PARTITION_INFORMATION * res)209   bool GetPartitionInfo(PARTITION_INFORMATION *res)
210     { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); }
211 
212   #endif
213 
214   void CorrectDeviceSize();
215   void CalcDeviceSize(CFSTR name);
216 
217   #endif
218 
219 public:
220   bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
221   bool OpenShared(CFSTR fileName, bool shareForWrite);
222   bool Open(CFSTR fileName);
223 
224   #ifndef UNDER_CE
225 
Open_for_ReadAttributes(CFSTR fileName)226   bool Open_for_ReadAttributes(CFSTR fileName)
227   {
228     return Create(fileName, FILE_READ_ATTRIBUTES,
229         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
230         OPEN_EXISTING,
231         FILE_FLAG_BACKUP_SEMANTICS);
232     // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory.
233   }
234 
OpenReparse(CFSTR fileName)235   bool OpenReparse(CFSTR fileName)
236   {
237     // 17.02 fix: to support Windows XP compatibility junctions:
238     //   we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ
239     return
240         Create(fileName, 0,
241         // Open(fileName,
242         FILE_SHARE_READ, OPEN_EXISTING,
243         FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
244   }
245 
246   #endif
247 
248   bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw();
249   bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw();
250   bool Read(void *data, UInt32 size, UInt32 &processedSize) throw();
251   bool ReadFull(void *data, size_t size, size_t &processedSize) throw();
252 };
253 
254 class COutFile: public CFileBase
255 {
256 public:
257   bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
258   bool Open(CFSTR fileName, DWORD creationDisposition);
259   bool Create(CFSTR fileName, bool createAlways);
260   bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes);
261 
262   bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
263   bool SetMTime(const CFiTime *mTime) throw();
264   bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();
265   bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw();
266   bool WriteFull(const void *data, size_t size) throw();
267   bool SetEndOfFile() throw();
268   bool SetLength(UInt64 length) throw();
269   bool SetLength_KeepPosition(UInt64 length) throw();
270 };
271 
272 }
273 
274 
275 #else // _WIN32
276 
277 namespace NIO {
278 
279 bool GetReparseData(CFSTR path, CByteBuffer &reparseData);
280 // bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size);
281 
282 // parameters are in reverse order of symlink() function !!!
283 bool SetSymLink(CFSTR from, CFSTR to);
284 bool SetSymLink_UString(CFSTR from, const UString &to);
285 
286 
287 class CFileBase
288 {
289 protected:
290   int _handle;
291 
292   /*
293   bool IsDeviceFile;
294   bool SizeDefined;
295   UInt64 Size; // it can be larger than real available size
296   */
297 
298   bool OpenBinary(const char *name, int flags);
299 public:
300   bool PreserveATime;
301 
CFileBase()302   CFileBase(): _handle(-1), PreserveATime(false) {};
~CFileBase()303   ~CFileBase() { Close(); }
304   bool Close();
305   bool GetLength(UInt64 &length) const;
306   off_t seek(off_t distanceToMove, int moveMethod) const;
307   off_t seekToBegin() const throw();
308   off_t seekToCur() const throw();
309   // bool SeekToBegin() throw();
my_fstat(struct stat * st)310   int my_fstat(struct stat *st) const  { return fstat(_handle, st); }
311   /*
312   int my_ioctl_BLKGETSIZE64(unsigned long long *val);
313   int GetDeviceSize_InBytes(UInt64 &size);
314   void CalcDeviceSize(CFSTR s);
315   */
316 };
317 
318 class CInFile: public CFileBase
319 {
320 public:
321   bool Open(const char *name);
322   bool OpenShared(const char *name, bool shareForWrite);
323   ssize_t read_part(void *data, size_t size) throw();
324   // ssize_t read_full(void *data, size_t size, size_t &processed);
325   bool ReadFull(void *data, size_t size, size_t &processedSize) throw();
326 };
327 
328 class COutFile: public CFileBase
329 {
330   bool CTime_defined;
331   bool ATime_defined;
332   bool MTime_defined;
333 
334   CFiTime CTime;
335   CFiTime ATime;
336   CFiTime MTime;
337 
338   AString Path;
339   ssize_t write_part(const void *data, size_t size) throw();
340 public:
COutFile()341   COutFile():
342       CTime_defined(false),
343       ATime_defined(false),
344       MTime_defined(false)
345       {}
346 
347   bool Close();
348   bool Create(const char *name, bool createAlways);
349   bool Open(const char *name, DWORD creationDisposition);
350   ssize_t write_full(const void *data, size_t size, size_t &processed) throw();
351 
WriteFull(const void * data,size_t size)352   bool WriteFull(const void *data, size_t size) throw()
353   {
354     size_t processed;
355     ssize_t res = write_full(data, size, processed);
356     if (res == -1)
357       return false;
358     return processed == size;
359   }
360 
361   bool SetLength(UInt64 length) throw();
SetLength_KeepPosition(UInt64 length)362   bool SetLength_KeepPosition(UInt64 length) throw()
363   {
364     return SetLength(length);
365   }
366   bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
367   bool SetMTime(const CFiTime *mTime) throw();
368 };
369 
370 }
371 
372 #endif  // _WIN32
373 
374 }}
375 
376 
377 #endif
378