xref: /third_party/lzma/CPP/Windows/FileIO.h (revision 370b324c)
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