1 // Windows/FileFind.h
2
3 #ifndef __WINDOWS_FILE_FIND_H
4 #define __WINDOWS_FILE_FIND_H
5
6 #ifndef _WIN32
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <dirent.h>
10 #endif
11
12 #include "../Common/MyLinux.h"
13 #include "../Common/MyString.h"
14 #include "../Common/MyWindows.h"
15
16 #include "Defs.h"
17
18 #include "FileIO.h"
19
20 namespace NWindows {
21 namespace NFile {
22 namespace NFind {
23
24 // bool DoesFileExist(CFSTR name, bool followLink);
25 bool DoesFileExist_Raw(CFSTR name);
26 bool DoesFileExist_FollowLink(CFSTR name);
27 bool DoesDirExist(CFSTR name, bool followLink);
28
DoesDirExist(CFSTR name)29 inline bool DoesDirExist(CFSTR name)
30 { return DoesDirExist(name, false); }
DoesDirExist_FollowLink(CFSTR name)31 inline bool DoesDirExist_FollowLink(CFSTR name)
32 { return DoesDirExist(name, true); }
33
34 // it's always _Raw
35 bool DoesFileOrDirExist(CFSTR name);
36
37 DWORD GetFileAttrib(CFSTR path);
38
39 #ifdef _WIN32
40
41 namespace NAttributes
42 {
IsReadOnly(DWORD attrib)43 inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; }
IsHidden(DWORD attrib)44 inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; }
IsSystem(DWORD attrib)45 inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; }
IsDir(DWORD attrib)46 inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; }
IsArchived(DWORD attrib)47 inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
IsCompressed(DWORD attrib)48 inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
IsEncrypted(DWORD attrib)49 inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
50
Get_PosixMode_From_WinAttrib(DWORD attrib)51 inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib)
52 {
53 UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG;
54 /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY).
55 So extracting at Linux will be allowed to write files inside (0777) directories. */
56 v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777);
57 return v;
58 }
59 }
60
61 #else
62
63 UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode);
64
65 #endif
66
67 class CFileInfoBase
68 {
69 #ifdef _WIN32
MatchesMask(UINT32 mask)70 bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
71 #endif
72 public:
73 UInt64 Size;
74 CFiTime CTime;
75 CFiTime ATime;
76 CFiTime MTime;
77 #ifdef _WIN32
78 DWORD Attrib;
79 bool IsAltStream;
80 bool IsDevice;
81
82 /*
83 #ifdef UNDER_CE
84 DWORD ObjectID;
85 #else
86 UINT32 ReparseTag;
87 #endif
88 */
89 #else
90 dev_t dev; /* ID of device containing file */
91 ino_t ino;
92 mode_t mode;
93 nlink_t nlink;
94 uid_t uid; /* user ID of owner */
95 gid_t gid; /* group ID of owner */
96 dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */
97 // bool Use_lstat;
98 #endif
99
CFileInfoBase()100 CFileInfoBase() { ClearBase(); }
101 void ClearBase() throw();
102
103 #ifdef _WIN32
104
105 bool Fill_From_ByHandleFileInfo(CFSTR path);
SetAsDir()106 void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16));
SetAsFile()107 void SetAsFile() { Attrib = 0; }
108
IsArchived()109 bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
IsCompressed()110 bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
IsDir()111 bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
IsEncrypted()112 bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); }
IsHidden()113 bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); }
IsNormal()114 bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); }
IsOffline()115 bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); }
IsReadOnly()116 bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); }
HasReparsePoint()117 bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); }
IsSparse()118 bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); }
IsSystem()119 bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
IsTemporary()120 bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
121
GetWinAttrib()122 UInt32 GetWinAttrib() const { return Attrib; }
GetPosixAttrib()123 UInt32 GetPosixAttrib() const
124 {
125 return NAttributes::Get_PosixMode_From_WinAttrib(Attrib);
126 }
Has_Attrib_ReparsePoint()127 bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; }
128
129 #else
130
GetPosixAttrib()131 UInt32 GetPosixAttrib() const { return mode; }
GetWinAttrib()132 UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); }
133
IsDir()134 bool IsDir() const { return S_ISDIR(mode); }
SetAsDir()135 void SetAsDir() { mode = S_IFDIR; }
SetAsFile()136 void SetAsFile() { mode = S_IFREG; }
137
IsReadOnly()138 bool IsReadOnly() const
139 {
140 // does linux support writing to ReadOnly files?
141 if ((mode & 0222) == 0) // S_IWUSR in p7zip
142 return true;
143 return false;
144 }
145
IsPosixLink()146 bool IsPosixLink() const { return S_ISLNK(mode); }
147
148 #endif
149
IsOsSymLink()150 bool IsOsSymLink() const
151 {
152 #ifdef _WIN32
153 return HasReparsePoint();
154 #else
155 return IsPosixLink();
156 #endif
157 }
158 };
159
160 struct CFileInfo: public CFileInfoBase
161 {
162 FString Name;
163 #if defined(_WIN32) && !defined(UNDER_CE)
164 // FString ShortName;
165 #endif
166
167 bool IsDots() const throw();
168 bool Find(CFSTR path, bool followLink = false);
Find_FollowLinkCFileInfo169 bool Find_FollowLink(CFSTR path) { return Find(path, true); }
170
171 #ifdef _WIN32
172 // bool Fill_From_ByHandleFileInfo(CFSTR path);
173 // bool FollowReparse(CFSTR path, bool isDir);
174 #else
175 bool Find_DontFill_Name(CFSTR path, bool followLink = false);
176 void SetFrom_stat(const struct stat &st);
177 #endif
178 };
179
180
181 #ifdef _WIN32
182
183 class CFindFileBase MY_UNCOPYABLE
184 {
185 protected:
186 HANDLE _handle;
187 public:
IsHandleAllocated()188 bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; }
CFindFileBase()189 CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {}
~CFindFileBase()190 ~CFindFileBase() { Close(); }
191 bool Close() throw();
192 };
193
194 class CFindFile: public CFindFileBase
195 {
196 public:
197 bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo);
198 bool FindNext(CFileInfo &fileInfo);
199 };
200
201 #if defined(_WIN32) && !defined(UNDER_CE)
202
203 struct CStreamInfo
204 {
205 UString Name;
206 UInt64 Size;
207
208 UString GetReducedName() const; // returns ":Name"
209 // UString GetReducedName2() const; // returns "Name"
210 bool IsMainStream() const throw();
211 };
212
213 class CFindStream: public CFindFileBase
214 {
215 public:
216 bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo);
217 bool FindNext(CStreamInfo &streamInfo);
218 };
219
220 class CStreamEnumerator MY_UNCOPYABLE
221 {
222 CFindStream _find;
223 FString _filePath;
224
225 bool NextAny(CFileInfo &fileInfo, bool &found);
226 public:
CStreamEnumerator(const FString & filePath)227 CStreamEnumerator(const FString &filePath): _filePath(filePath) {}
228 bool Next(CStreamInfo &streamInfo, bool &found);
229 };
230
231 #endif // defined(_WIN32) && !defined(UNDER_CE)
232
233
234 class CEnumerator MY_UNCOPYABLE
235 {
236 CFindFile _findFile;
237 FString _wildcard;
238
239 bool NextAny(CFileInfo &fileInfo);
240 public:
241 void SetDirPrefix(const FString &dirPrefix);
242 bool Next(CFileInfo &fileInfo);
243 bool Next(CFileInfo &fileInfo, bool &found);
244 };
245
246
247 class CFindChangeNotification MY_UNCOPYABLE
248 {
249 HANDLE _handle;
250 public:
HANDLE()251 operator HANDLE () { return _handle; }
IsHandleAllocated()252 bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; }
CFindChangeNotification()253 CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {}
~CFindChangeNotification()254 ~CFindChangeNotification() { Close(); }
255 bool Close() throw();
256 HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter);
FindNext()257 bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); }
258 };
259
260 #ifndef UNDER_CE
261 bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings);
262 #endif
263
264 typedef CFileInfo CDirEntry;
265
266
267 #else // WIN32
268
269
270 struct CDirEntry
271 {
272 ino_t iNode;
273 #if !defined(_AIX)
274 Byte Type;
275 #endif
276 FString Name;
277
278 /*
279 #if !defined(_AIX)
280 bool IsDir() const
281 {
282 // (Type == DT_UNKNOWN) on some systems
283 return Type == DT_DIR;
284 }
285 #endif
286 */
287
288 bool IsDots() const throw();
289 };
290
291 class CEnumerator MY_UNCOPYABLE
292 {
293 DIR *_dir;
294 FString _wildcard;
295
296 bool NextAny(CDirEntry &fileInfo, bool &found);
297 public:
CEnumerator()298 CEnumerator(): _dir(NULL) {}
299 ~CEnumerator();
300 void SetDirPrefix(const FString &dirPrefix);
301
302 bool Next(CDirEntry &fileInfo, bool &found);
303 bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const;
DirEntry_IsDir(const CDirEntry & de,bool followLink)304 bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const
305 {
306 #if !defined(_AIX)
307 if (de.Type == DT_DIR)
308 return true;
309 if (de.Type != DT_UNKNOWN)
310 return false;
311 #endif
312 CFileInfo fileInfo;
313 if (Fill_FileInfo(de, fileInfo, followLink))
314 {
315 return fileInfo.IsDir();
316 }
317 return false; // change it
318 }
319 };
320
321 /*
322 inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode)
323 {
324 UInt32 attrib = S_ISDIR(mode) ?
325 FILE_ATTRIBUTE_DIRECTORY :
326 FILE_ATTRIBUTE_ARCHIVE;
327 if ((st.st_mode & 0222) == 0) // check it !!!
328 attrib |= FILE_ATTRIBUTE_READONLY;
329 return attrib;
330 }
331 */
332
333 // UInt32 Get_WinAttrib_From_stat(const struct stat &st);
334
335
336 #endif // WIN32
337
338 }}}
339
340 #endif
341