1 /* path.h: path data structures
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
11 #include "cygheap_malloc.h"
14 #include <sys/mount.h>
15 #include <sys/ioctl.h>
20 has_attribute (DWORD attributes
, DWORD attribs_to_test
)
22 return attributes
!= INVALID_FILE_ATTRIBUTES
23 && (attributes
& attribs_to_test
);
27 isoffline (DWORD attributes
)
29 return has_attribute (attributes
, FILE_ATTRIBUTE_OFFLINE
30 | FILE_ATTRIBUTE_RECALL_ON_OPEN
31 | FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
);
34 enum executable_states
37 dont_care_if_executable
,
38 not_executable
= dont_care_if_executable
,
39 dont_know_if_executable
45 suffix_info (const char *s
): name (s
) {}
48 extern suffix_info stat_suffixes
[];
50 /* DO NOT copy any of these files into the same set of flags as the
51 below path_types. Ever. */
54 PC_SYM_FOLLOW
= _BIT ( 0), /* follow symlinks */
55 PC_SYM_NOFOLLOW
= _BIT ( 1), /* don't follow symlinks (but honor
57 PC_SYM_NOFOLLOW_REP
= _BIT ( 2), /* don't follow dir reparse point */
58 PC_SYM_CONTENTS
= _BIT ( 3), /* don't follow, return content only */
59 PC_NOFULL
= _BIT ( 4), /* keep relative path */
60 PC_NULLEMPTY
= _BIT ( 5), /* empty path is no error */
61 PC_NONULLEMPTY
= _BIT ( 6), /* override PC_NULLEMPTY default */
62 PC_POSIX
= _BIT ( 7), /* return normalized posix path */
63 PC_OPEN
= _BIT ( 9), /* use open semantics */
64 PC_CTTY
= _BIT (10), /* could later be used as ctty */
65 PC_SYM_NOFOLLOW_PROCFD
= _BIT (11), /* allow /proc/PID/fd redirection */
66 PC_KEEP_HANDLE
= _BIT (12), /* keep handle for later stat calls */
67 PC_NO_ACCESS_CHECK
= _BIT (13), /* helper flag for error check */
68 PC_SYM_NOFOLLOW_DIR
= _BIT (14), /* don't follow a trailing slash */
69 PC_DONT_USE
= _BIT (31) /* conversion to signed happens. */
74 PATH_CTTY
= _BIT ( 0), /* could later be used as ctty */
75 PATH_OPEN
= _BIT ( 1), /* use open semantics */
76 PATH_LNK
= _BIT ( 2), /* *.lnk-type symlink */
77 PATH_REP
= _BIT ( 3), /* reparse point known to Cygwin */
78 PATH_SYMLINK
= _BIT ( 4), /* symlink understood by Cygwin */
79 PATH_SOCKET
= _BIT ( 5), /* AF_UNIX socket file */
80 PATH_RESOLVE_PROCFD
= _BIT ( 6), /* fd symlink via /proc */
81 PATH_REP_NOAPI
= _BIT ( 7), /* rep. point unknown to WinAPI */
82 PATH_DONT_USE
= _BIT (31) /* conversion to signed happens. */
87 FFH_LINKAT
= (1 << 0),
90 NTSTATUS
file_get_fai (HANDLE
, PFILE_ALL_INFORMATION
);
91 int check_reparse_point_target (HANDLE
, bool, PREPARSE_DATA_BUFFER
,
96 class path_conv_handle
100 FILE_ALL_INFORMATION _fai
;
105 path_conv_handle () : hdl (NULL
) {}
106 inline void set (HANDLE h
) { hdl
= h
; }
113 inline void dup (const path_conv_handle
&pch
)
116 && !DuplicateHandle (GetCurrentProcess (), pch
.handle (),
117 GetCurrentProcess (), &hdl
,
118 0, TRUE
, DUPLICATE_SAME_ACCESS
))
121 inline HANDLE
handle () const { return hdl
; }
122 inline PFILE_ALL_INFORMATION
fai () const
123 { return (PFILE_ALL_INFORMATION
) &attribs
._fai
; }
124 inline struct fattr3
*nfsattr () const
125 { return (struct fattr3
*) &attribs
._fattr3
; }
126 inline NTSTATUS
get_finfo (HANDLE h
, bool nfs
)
128 return nfs
? nfs_fetch_fattr3 (h
, nfsattr ()) : file_get_fai (h
, fai ());
130 inline ino_t
get_ino (bool nfs
) const
132 return nfs
? nfsattr ()->fileid
133 : fai ()->InternalInformation
.IndexNumber
.QuadPart
;
135 inline DWORD
get_dosattr (HANDLE h
, bool nfs
) const
140 FILE_BASIC_INFORMATION fbi
;
142 NtQueryInformationFile (h
, &io
, &fbi
, sizeof fbi
, FileBasicInformation
);
143 return fbi
.FileAttributes
;
145 return fai ()->BasicInformation
.FileAttributes
;
152 ULONG caseinsensitive
;
156 UNICODE_STRING uni_path
;
157 DWORD symlink_length
;
159 uint32_t mount_flags
;
162 const char *posix_path
;
163 path_conv_handle conv_handle
;
164 /* virt_fileid is used by and unique within each fhandler_virtual class.
165 We need it here to avoid calling the exists() method too often, in
166 case the derived class has a costly exists() operation.
167 virt_fileid is evaluated by the fhandler_virtual::exists() call in
168 path_conv::check and propageted to the caller's path_conv. */
171 void add_ext_from_sym (symlink_info
&);
172 char *modifiable_path () {return (char *) path
;}
178 int &virt_fileid() { return _virt_fileid
; }
180 void *serialize (HANDLE
, unsigned int &) const;
181 HANDLE
deserialize (void *);
183 const char *known_suffix () { return suffix
; }
184 bool isremote () const {return fs
.is_remote_drive ();}
185 ULONG
objcaseinsensitive () const {return caseinsensitive
;}
186 bool has_acls () const {return !(mount_flags
& MOUNT_NOACL
)
188 bool hasgood_inode () const {return !(mount_flags
& MOUNT_IHASH
); }
189 bool isgood_inode (ino_t ino
) const;
190 bool support_sparse () const
192 return (fs_flags () & FILE_SUPPORTS_SPARSE_FILES
)
193 && (fs
.is_ssd () || (mount_flags
& MOUNT_SPARSE
));
195 int has_dos_filenames_only () const {return mount_flags
& MOUNT_DOS
;}
196 int has_buggy_reopen () const {return fs
.has_buggy_reopen ();}
197 int has_buggy_fileid_dirinfo () const {return fs
.has_buggy_fileid_dirinfo ();}
198 int has_buggy_basic_info () const {return fs
.has_buggy_basic_info ();}
201 return (mount_flags
& MOUNT_TEXT
) ? O_TEXT
: O_BINARY
;
203 int issymlink () const {return path_flags
& PATH_SYMLINK
;}
204 int is_lnk_symlink () const {return path_flags
& PATH_LNK
;}
205 /* This indicates any known reparse point */
206 int is_known_reparse_point () const {return path_flags
& PATH_REP
;}
207 /* This indicates any known reparse point, handled sanely by WinAPI.
208 The difference is crucial: WSL symlinks, for instance, are known
209 reparse points, so we want to open them as reparse points usually.
210 However they are foreign to WinAPI and not handled sanely. If one
211 is part of $PATH, WinAPI functions may fail under the hood with
212 STATUS_IO_REPARSE_TAG_NOT_HANDLED. */
213 int is_winapi_reparse_point () const
215 return (path_flags
& (PATH_REP
| PATH_REP_NOAPI
)) == PATH_REP
;
217 int isdevice () const {return dev
.not_device (FH_FS
) && dev
.not_device (FH_FIFO
);}
218 int isfifo () const {return dev
.is_device (FH_FIFO
);}
219 int isspecial () const {return dev
.not_device (FH_FS
);}
220 int iscygdrive () const {return dev
.is_device (FH_CYGDRIVE
);}
221 int is_fs_special () const {return dev
.is_fs_special ();}
223 int is_lnk_special () const {return (isdevice () && is_fs_special ()
225 || isfifo () || is_lnk_symlink ();}
226 #ifdef __WITH_AF_UNIX
227 int issocket () const {return dev
.is_device (FH_LOCAL
)
228 || dev
.is_device (FH_UNIX
);}
230 int issocket () const {return dev
.is_device (FH_LOCAL
);}
231 #endif /* __WITH_AF_UNIX */
232 int iscygexec () const {return mount_flags
& MOUNT_CYGWIN_EXEC
;}
233 int isopen () const {return path_flags
& PATH_OPEN
;}
234 int isctty_capable () const {return path_flags
& PATH_CTTY
;}
235 int follow_fd_symlink () const {return path_flags
& PATH_RESOLVE_PROCFD
;}
236 void set_cygexec (bool isset
)
239 mount_flags
|= MOUNT_CYGWIN_EXEC
;
241 mount_flags
&= ~MOUNT_CYGWIN_EXEC
;
243 void set_cygexec (void *target
)
246 mount_flags
|= MOUNT_CYGWIN_EXEC
;
248 mount_flags
&= ~MOUNT_CYGWIN_EXEC
;
250 bool isro () const {return !!(mount_flags
& MOUNT_RO
);}
251 bool exists () const {return fileattr
!= INVALID_FILE_ATTRIBUTES
;}
252 bool has_attribute (DWORD x
) const {return exists () && (fileattr
& x
);}
253 int isdir () const {return has_attribute (FILE_ATTRIBUTE_DIRECTORY
);}
254 bool isoffline () const
256 return has_attribute (FILE_ATTRIBUTE_OFFLINE
257 | FILE_ATTRIBUTE_RECALL_ON_OPEN
258 | FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS
);
260 executable_states
exec_state ()
262 extern int _check_for_executable
;
263 if (mount_flags
& (MOUNT_CYGWIN_EXEC
| MOUNT_EXEC
))
264 return is_executable
;
265 if (mount_flags
& MOUNT_NOTEXEC
)
266 return not_executable
;
267 if (isoffline () || !_check_for_executable
)
268 return dont_care_if_executable
;
269 return dont_know_if_executable
;
272 void set_symlink (DWORD n
) {path_flags
|= PATH_SYMLINK
; symlink_length
= n
;}
273 void set_exec (int x
= 1) {mount_flags
|= x
? MOUNT_EXEC
: MOUNT_NOTEXEC
;}
275 void check (const UNICODE_STRING
*upath
, uint32_t opt
= PC_SYM_FOLLOW
,
276 const suffix_info
*suffixes
= NULL
);
277 void check (const char *src
, uint32_t opt
= PC_SYM_FOLLOW
,
278 const suffix_info
*suffixes
= NULL
);
280 path_conv (const device
& in_dev
)
281 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
282 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
),
283 error (0), dev (in_dev
)
285 set_path (in_dev
.native ());
288 path_conv (const UNICODE_STRING
*src
, uint32_t opt
= PC_SYM_FOLLOW
,
289 const suffix_info
*suffixes
= NULL
)
290 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
291 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
), error (0)
293 check (src
, opt
| ((opt
& PC_NONULLEMPTY
) ? 0 : PC_NULLEMPTY
), suffixes
);
296 path_conv (const char *src
, uint32_t opt
= PC_SYM_FOLLOW
,
297 const suffix_info
*suffixes
= NULL
)
298 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
299 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
), error (0)
301 check (src
, opt
| ((opt
& PC_NONULLEMPTY
) ? 0 : PC_NULLEMPTY
), suffixes
);
305 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
306 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
), error (0)
310 inline const char *get_win32 () const { return path
; }
311 void set_nt_native_path (PUNICODE_STRING
);
312 PUNICODE_STRING
get_nt_native_path (PUNICODE_STRING
= NULL
);
313 inline POBJECT_ATTRIBUTES
get_object_attr (OBJECT_ATTRIBUTES
&attr
,
314 SECURITY_ATTRIBUTES
&sa
)
316 if (!get_nt_native_path ())
318 InitializeObjectAttributes (&attr
, &uni_path
,
319 objcaseinsensitive ()
320 | (sa
.bInheritHandle
? OBJ_INHERIT
: 0),
321 NULL
, sa
.lpSecurityDescriptor
);
324 inline POBJECT_ATTRIBUTES
init_reopen_attr (OBJECT_ATTRIBUTES
&attr
, HANDLE h
)
326 if (has_buggy_reopen ())
327 InitializeObjectAttributes (&attr
, get_nt_native_path (),
328 objcaseinsensitive (), NULL
, NULL
)
330 InitializeObjectAttributes (&attr
, &ro_u_empty
, objcaseinsensitive (),
334 inline size_t get_wide_win32_path_len ()
336 get_nt_native_path ();
337 return uni_path
.Length
/ sizeof (WCHAR
);
340 PWCHAR
get_wide_win32_path (PWCHAR wc
);
341 operator DWORD
&() {return fileattr
;}
342 operator int () {return fileattr
; }
343 # define cfree_and_null(x) \
346 cfree ((void *) (x)); \
351 cfree_and_null (path
);
352 cfree_and_null (posix_path
);
353 cfree_and_null (wide_path
);
355 path_conv
& eq_worker (const path_conv
& pc
, const char *in_path
)
358 memcpy ((void *) this, &pc
, sizeof pc
);
359 /* The device info might contain pointers to allocated strings, in
360 contrast to statically allocated strings. Calling device::dup()
361 will duplicate the string if the source was allocated. */
364 path
= cstrdup (in_path
);
365 conv_handle
.dup (pc
.conv_handle
);
367 posix_path
= cstrdup(pc
.posix_path
);
370 wide_path
= cwcsdup (uni_path
.Buffer
);
372 api_fatal ("cwcsdup would have returned NULL");
373 uni_path
.Buffer
= wide_path
;
378 path_conv
&operator << (const path_conv
& pc
)
380 const char *save_path
;
386 save_path
= (char *) alloca (strlen (path
) + 1);
387 strcpy ((char *) save_path
, path
);
389 return eq_worker (pc
, save_path
);
392 path_conv
&operator =(const path_conv
& pc
)
394 return eq_worker (pc
, pc
.path
);
396 dev_t
get_device () {return dev
.get_device ();}
397 DWORD
file_attributes () const {return fileattr
;}
398 void file_attributes (DWORD new_attr
) {fileattr
= new_attr
;}
399 DWORD
fs_flags () const {return fs
.flags ();}
400 DWORD
fs_name_len () const {return fs
.name_len ();}
401 bool fs_got_fs () const { return fs
.got_fs (); }
402 bool fs_is_fat () const {return fs
.is_fat ();}
403 bool fs_is_exfat () const {return fs
.is_exfat ();}
404 bool fs_is_any_fat () const {return fs
.is_fat () || fs
.is_exfat ();}
405 bool fs_is_ntfs () const {return fs
.is_ntfs ();}
406 bool fs_is_refs () const {return fs
.is_refs ();}
407 bool fs_is_samba () const {return fs
.is_samba ();}
408 bool fs_is_nfs () const {return fs
.is_nfs ();}
409 bool fs_is_netapp () const {return fs
.is_netapp ();}
410 bool fs_is_cdrom () const {return fs
.is_cdrom ();}
411 bool fs_is_mvfs () const {return fs
.is_mvfs ();}
412 bool fs_is_cifs () const {return fs
.is_cifs ();}
413 bool fs_is_nwfs () const {return fs
.is_nwfs ();}
414 bool fs_is_ncfsd () const {return fs
.is_ncfsd ();}
415 bool fs_is_afs () const {return fs
.is_afs ();}
416 bool fs_is_prlfs () const {return fs
.is_prlfs ();}
417 fs_info_type
fs_type () const {return fs
.what_fs ();}
418 ULONG
fs_serial_number () const {return fs
.serial_number ();}
419 inline const char *set_path (const char *p
)
422 cfree (modifiable_path ());
423 char *new_path
= (char *) cmalloc_abort (HEAP_STR
, strlen (p
) + 7);
424 strcpy (new_path
, p
);
425 return path
= new_path
;
429 HANDLE
handle () const { return conv_handle
.handle (); }
430 PFILE_ALL_INFORMATION
fai () { return conv_handle
.fai (); }
431 struct fattr3
*nfsattr () { return conv_handle
.nfsattr (); }
432 inline NTSTATUS
get_finfo (HANDLE h
)
434 return conv_handle
.get_finfo (h
, fs
.is_nfs ());
436 inline ino_t
get_ino () const { return conv_handle
.get_ino (fs
.is_nfs ()); }
437 void close_conv_handle () { conv_handle
.close (); }
439 ino_t
get_ino_by_handle (HANDLE h
);
440 inline const char *get_posix () const { return posix_path
; }
441 void set_posix (const char *);
442 DWORD
get_symlink_length () { return symlink_length
; };
446 #define SYMLINK_COOKIE "!<symlink>"
449 #define SOCKET_COOKIE "!<socket >"
451 /* Interix symlink marker */
452 #define INTERIX_SYMLINK_COOKIE "IntxLNK\1"
456 FE_NADA
= 0, /* Nothing special */
457 FE_NNF
= 1, /* Return NULL if not found */
458 FE_CWD
= 4, /* Search CWD for program */
459 FE_DLL
= 8 /* Search for DLLs, not executables. */
461 const char *find_exec (const char *name
, path_conv
& buf
,
462 const char *search
= "PATH",
463 unsigned opt
= FE_NADA
,
464 const char **known_suffix
= NULL
);
466 /* Common macros for checking for invalid path names */
467 #define isdrive(s) (isalpha (*(s)) && (s)[1] == ':')
468 #define iswdrive(s) (iswalpha (*(s)) && (s)[1] == L':')
471 has_exec_chars (const char *buf
, int len
)
474 ((buf
[0] == '#' && buf
[1] == '!') ||
475 (buf
[0] == ':' && buf
[1] == '\n') ||
476 (buf
[0] == 'M' && buf
[1] == 'Z'));
479 int pathmatch (const char *path1
, const char *path2
, bool caseinsensitive
);
480 int pathnmatch (const char *path1
, const char *path2
, int len
, bool caseinsensitive
);
481 bool has_dot_last_component (const char *dir
, bool test_dot_dot
);
483 int path_prefix_p (const char *path1
, const char *path2
, int len1
,
484 bool caseinsensitive
);
486 int normalize_win32_path (const char *, char *, char *&);
487 int normalize_posix_path (const char *, char *, char *&);
488 PUNICODE_STRING
get_nt_native_path (const char *, UNICODE_STRING
&, bool);
490 int symlink_worker (const char *, path_conv
&, bool);