xref: /aosp_15_r20/external/lzma/CPP/Windows/FileIO.h (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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