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
);
26 enum executable_states
29 dont_care_if_executable
,
30 not_executable
= dont_care_if_executable
,
31 dont_know_if_executable
37 suffix_info (const char *s
): name (s
) {}
40 extern suffix_info stat_suffixes
[];
42 /* DO NOT copy any of these files into the same set of flags as the
43 below path_types. Ever. */
46 PC_SYM_FOLLOW
= _BIT ( 0), /* follow symlinks */
47 PC_SYM_NOFOLLOW
= _BIT ( 1), /* don't follow symlinks (but honor
49 PC_SYM_NOFOLLOW_REP
= _BIT ( 2), /* don't follow dir reparse point */
50 PC_SYM_CONTENTS
= _BIT ( 3), /* don't follow, return content only */
51 PC_NOFULL
= _BIT ( 4), /* keep relative path */
52 PC_NULLEMPTY
= _BIT ( 5), /* empty path is no error */
53 PC_NONULLEMPTY
= _BIT ( 6), /* override PC_NULLEMPTY default */
54 PC_POSIX
= _BIT ( 7), /* return normalized posix path */
55 PC_OPEN
= _BIT ( 9), /* use open semantics */
56 PC_CTTY
= _BIT (10), /* could later be used as ctty */
57 PC_SYM_NOFOLLOW_PROCFD
= _BIT (11), /* allow /proc/PID/fd redirection */
58 PC_KEEP_HANDLE
= _BIT (12), /* keep handle for later stat calls */
59 PC_NO_ACCESS_CHECK
= _BIT (13), /* helper flag for error check */
60 PC_SYM_NOFOLLOW_DIR
= _BIT (14), /* don't follow a trailing slash */
61 PC_DONT_USE
= _BIT (31) /* conversion to signed happens. */
66 PATH_CTTY
= _BIT ( 0), /* could later be used as ctty */
67 PATH_OPEN
= _BIT ( 1), /* use open semantics */
68 PATH_LNK
= _BIT ( 2), /* *.lnk-type symlink */
69 PATH_REP
= _BIT ( 3), /* reparse point known to Cygwin */
70 PATH_SYMLINK
= _BIT ( 4), /* symlink understood by Cygwin */
71 PATH_SOCKET
= _BIT ( 5), /* AF_UNIX socket file */
72 PATH_RESOLVE_PROCFD
= _BIT ( 6), /* fd symlink via /proc */
73 PATH_REP_NOAPI
= _BIT ( 7), /* rep. point unknown to WinAPI */
74 PATH_DONT_USE
= _BIT (31) /* conversion to signed happens. */
79 FFH_LINKAT
= (1 << 0),
82 NTSTATUS
file_get_fai (HANDLE
, PFILE_ALL_INFORMATION
);
83 int check_reparse_point_target (HANDLE
, bool, PREPARSE_DATA_BUFFER
,
88 class path_conv_handle
92 FILE_ALL_INFORMATION _fai
;
97 path_conv_handle () : hdl (NULL
) {}
98 inline void set (HANDLE h
) { hdl
= h
; }
105 inline void dup (const path_conv_handle
&pch
)
108 && !DuplicateHandle (GetCurrentProcess (), pch
.handle (),
109 GetCurrentProcess (), &hdl
,
110 0, TRUE
, DUPLICATE_SAME_ACCESS
))
113 inline HANDLE
handle () const { return hdl
; }
114 inline PFILE_ALL_INFORMATION
fai () const
115 { return (PFILE_ALL_INFORMATION
) &attribs
._fai
; }
116 inline struct fattr3
*nfsattr () const
117 { return (struct fattr3
*) &attribs
._fattr3
; }
118 inline NTSTATUS
get_finfo (HANDLE h
, bool nfs
)
120 return nfs
? nfs_fetch_fattr3 (h
, nfsattr ()) : file_get_fai (h
, fai ());
122 inline ino_t
get_ino (bool nfs
) const
124 return nfs
? nfsattr ()->fileid
125 : fai ()->InternalInformation
.IndexNumber
.QuadPart
;
127 inline DWORD
get_dosattr (HANDLE h
, bool nfs
) const
132 FILE_BASIC_INFORMATION fbi
;
134 NtQueryInformationFile (h
, &io
, &fbi
, sizeof fbi
, FileBasicInformation
);
135 return fbi
.FileAttributes
;
137 return fai ()->BasicInformation
.FileAttributes
;
144 ULONG caseinsensitive
;
148 UNICODE_STRING uni_path
;
149 DWORD symlink_length
;
151 uint32_t mount_flags
;
154 const char *posix_path
;
155 path_conv_handle conv_handle
;
157 void add_ext_from_sym (symlink_info
&);
158 char *modifiable_path () {return (char *) path
;}
164 void *serialize (HANDLE
, unsigned int &) const;
165 HANDLE
deserialize (void *);
167 const char *known_suffix () { return suffix
; }
168 bool isremote () const {return fs
.is_remote_drive ();}
169 ULONG
objcaseinsensitive () const {return caseinsensitive
;}
170 bool has_acls () const {return !(mount_flags
& MOUNT_NOACL
)
172 bool hasgood_inode () const {return !(mount_flags
& MOUNT_IHASH
); }
173 bool isgood_inode (ino_t ino
) const;
174 bool support_sparse () const
176 return (fs_flags () & FILE_SUPPORTS_SPARSE_FILES
)
177 && (fs
.is_ssd () || (mount_flags
& MOUNT_SPARSE
));
179 int has_dos_filenames_only () const {return mount_flags
& MOUNT_DOS
;}
180 int has_buggy_reopen () const {return fs
.has_buggy_reopen ();}
181 int has_buggy_fileid_dirinfo () const {return fs
.has_buggy_fileid_dirinfo ();}
182 int has_buggy_basic_info () const {return fs
.has_buggy_basic_info ();}
185 return (mount_flags
& MOUNT_TEXT
) ? O_TEXT
: O_BINARY
;
187 int issymlink () const {return path_flags
& PATH_SYMLINK
;}
188 int is_lnk_symlink () const {return path_flags
& PATH_LNK
;}
189 /* This indicates any known reparse point */
190 int is_known_reparse_point () const {return path_flags
& PATH_REP
;}
191 /* This indicates any known reparse point, handled sanely by WinAPI.
192 The difference is crucial: WSL symlinks, for instance, are known
193 reparse points, so we want to open them as reparse points usually.
194 However they are foreign to WinAPI and not handled sanely. If one
195 is part of $PATH, WinAPI functions may fail under the hood with
196 STATUS_IO_REPARSE_TAG_NOT_HANDLED. */
197 int is_winapi_reparse_point () const
199 return (path_flags
& (PATH_REP
| PATH_REP_NOAPI
)) == PATH_REP
;
201 int isdevice () const {return dev
.not_device (FH_FS
) && dev
.not_device (FH_FIFO
);}
202 int isfifo () const {return dev
.is_device (FH_FIFO
);}
203 int isspecial () const {return dev
.not_device (FH_FS
);}
204 int iscygdrive () const {return dev
.is_device (FH_CYGDRIVE
);}
205 int is_fs_special () const {return dev
.is_fs_special ();}
207 int is_lnk_special () const {return (isdevice () && is_fs_special ()
209 || isfifo () || is_lnk_symlink ();}
210 #ifdef __WITH_AF_UNIX
211 int issocket () const {return dev
.is_device (FH_LOCAL
)
212 || dev
.is_device (FH_UNIX
);}
214 int issocket () const {return dev
.is_device (FH_LOCAL
);}
215 #endif /* __WITH_AF_UNIX */
216 int iscygexec () const {return mount_flags
& MOUNT_CYGWIN_EXEC
;}
217 int isopen () const {return path_flags
& PATH_OPEN
;}
218 int isctty_capable () const {return path_flags
& PATH_CTTY
;}
219 int follow_fd_symlink () const {return path_flags
& PATH_RESOLVE_PROCFD
;}
220 void set_cygexec (bool isset
)
223 mount_flags
|= MOUNT_CYGWIN_EXEC
;
225 mount_flags
&= ~MOUNT_CYGWIN_EXEC
;
227 void set_cygexec (void *target
)
230 mount_flags
|= MOUNT_CYGWIN_EXEC
;
232 mount_flags
&= ~MOUNT_CYGWIN_EXEC
;
234 bool isro () const {return !!(mount_flags
& MOUNT_RO
);}
235 bool exists () const {return fileattr
!= INVALID_FILE_ATTRIBUTES
;}
236 bool has_attribute (DWORD x
) const {return exists () && (fileattr
& x
);}
237 int isdir () const {return has_attribute (FILE_ATTRIBUTE_DIRECTORY
);}
238 executable_states
exec_state ()
240 extern int _check_for_executable
;
241 if (mount_flags
& (MOUNT_CYGWIN_EXEC
| MOUNT_EXEC
))
242 return is_executable
;
243 if (mount_flags
& MOUNT_NOTEXEC
)
244 return not_executable
;
245 if (!_check_for_executable
)
246 return dont_care_if_executable
;
247 return dont_know_if_executable
;
250 void set_symlink (DWORD n
) {path_flags
|= PATH_SYMLINK
; symlink_length
= n
;}
251 void set_exec (int x
= 1) {mount_flags
|= x
? MOUNT_EXEC
: MOUNT_NOTEXEC
;}
253 void check (const UNICODE_STRING
*upath
, uint32_t opt
= PC_SYM_FOLLOW
,
254 const suffix_info
*suffixes
= NULL
);
255 void check (const char *src
, uint32_t opt
= PC_SYM_FOLLOW
,
256 const suffix_info
*suffixes
= NULL
);
258 path_conv (const device
& in_dev
)
259 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
260 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
),
261 error (0), dev (in_dev
)
263 set_path (in_dev
.native ());
266 path_conv (const UNICODE_STRING
*src
, uint32_t opt
= PC_SYM_FOLLOW
,
267 const suffix_info
*suffixes
= NULL
)
268 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
269 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
), error (0)
271 check (src
, opt
| ((opt
& PC_NONULLEMPTY
) ? 0 : PC_NULLEMPTY
), suffixes
);
274 path_conv (const char *src
, uint32_t opt
= PC_SYM_FOLLOW
,
275 const suffix_info
*suffixes
= NULL
)
276 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
277 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
), error (0)
279 check (src
, opt
| ((opt
& PC_NONULLEMPTY
) ? 0 : PC_NULLEMPTY
), suffixes
);
283 : fileattr (INVALID_FILE_ATTRIBUTES
), wide_path (NULL
), path (NULL
),
284 mount_flags (0), path_flags (0), suffix (NULL
), posix_path (NULL
), error (0)
288 inline const char *get_win32 () const { return path
; }
289 void set_nt_native_path (PUNICODE_STRING
);
290 PUNICODE_STRING
get_nt_native_path (PUNICODE_STRING
= NULL
);
291 inline POBJECT_ATTRIBUTES
get_object_attr (OBJECT_ATTRIBUTES
&attr
,
292 SECURITY_ATTRIBUTES
&sa
)
294 if (!get_nt_native_path ())
296 InitializeObjectAttributes (&attr
, &uni_path
,
297 objcaseinsensitive ()
298 | (sa
.bInheritHandle
? OBJ_INHERIT
: 0),
299 NULL
, sa
.lpSecurityDescriptor
);
302 inline POBJECT_ATTRIBUTES
init_reopen_attr (OBJECT_ATTRIBUTES
&attr
, HANDLE h
)
304 if (has_buggy_reopen ())
305 InitializeObjectAttributes (&attr
, get_nt_native_path (),
306 objcaseinsensitive (), NULL
, NULL
)
308 InitializeObjectAttributes (&attr
, &ro_u_empty
, objcaseinsensitive (),
312 inline size_t get_wide_win32_path_len ()
314 get_nt_native_path ();
315 return uni_path
.Length
/ sizeof (WCHAR
);
318 PWCHAR
get_wide_win32_path (PWCHAR wc
);
319 operator DWORD
&() {return fileattr
;}
320 operator int () {return fileattr
; }
321 # define cfree_and_null(x) \
324 cfree ((void *) (x)); \
329 cfree_and_null (path
);
330 cfree_and_null (posix_path
);
331 cfree_and_null (wide_path
);
333 path_conv
& eq_worker (const path_conv
& pc
, const char *in_path
)
336 memcpy ((void *) this, &pc
, sizeof pc
);
337 /* The device info might contain pointers to allocated strings, in
338 contrast to statically allocated strings. Calling device::dup()
339 will duplicate the string if the source was allocated. */
342 path
= cstrdup (in_path
);
343 conv_handle
.dup (pc
.conv_handle
);
345 posix_path
= cstrdup(pc
.posix_path
);
348 wide_path
= cwcsdup (uni_path
.Buffer
);
350 api_fatal ("cwcsdup would have returned NULL");
351 uni_path
.Buffer
= wide_path
;
356 path_conv
&operator << (const path_conv
& pc
)
358 const char *save_path
;
364 save_path
= (char *) alloca (strlen (path
) + 1);
365 strcpy ((char *) save_path
, path
);
367 return eq_worker (pc
, save_path
);
370 path_conv
&operator =(const path_conv
& pc
)
372 return eq_worker (pc
, pc
.path
);
374 dev_t
get_device () {return dev
.get_device ();}
375 DWORD
file_attributes () const {return fileattr
;}
376 void file_attributes (DWORD new_attr
) {fileattr
= new_attr
;}
377 DWORD
fs_flags () const {return fs
.flags ();}
378 DWORD
fs_name_len () const {return fs
.name_len ();}
379 bool fs_got_fs () const { return fs
.got_fs (); }
380 bool fs_is_fat () const {return fs
.is_fat ();}
381 bool fs_is_exfat () const {return fs
.is_exfat ();}
382 bool fs_is_any_fat () const {return fs
.is_fat () || fs
.is_exfat ();}
383 bool fs_is_ntfs () const {return fs
.is_ntfs ();}
384 bool fs_is_refs () const {return fs
.is_refs ();}
385 bool fs_is_samba () const {return fs
.is_samba ();}
386 bool fs_is_nfs () const {return fs
.is_nfs ();}
387 bool fs_is_netapp () const {return fs
.is_netapp ();}
388 bool fs_is_cdrom () const {return fs
.is_cdrom ();}
389 bool fs_is_mvfs () const {return fs
.is_mvfs ();}
390 bool fs_is_cifs () const {return fs
.is_cifs ();}
391 bool fs_is_nwfs () const {return fs
.is_nwfs ();}
392 bool fs_is_ncfsd () const {return fs
.is_ncfsd ();}
393 bool fs_is_afs () const {return fs
.is_afs ();}
394 bool fs_is_prlfs () const {return fs
.is_prlfs ();}
395 fs_info_type
fs_type () const {return fs
.what_fs ();}
396 ULONG
fs_serial_number () const {return fs
.serial_number ();}
397 inline const char *set_path (const char *p
)
400 cfree (modifiable_path ());
401 char *new_path
= (char *) cmalloc_abort (HEAP_STR
, strlen (p
) + 7);
402 strcpy (new_path
, p
);
403 return path
= new_path
;
407 HANDLE
handle () const { return conv_handle
.handle (); }
408 PFILE_ALL_INFORMATION
fai () { return conv_handle
.fai (); }
409 struct fattr3
*nfsattr () { return conv_handle
.nfsattr (); }
410 inline NTSTATUS
get_finfo (HANDLE h
)
412 return conv_handle
.get_finfo (h
, fs
.is_nfs ());
414 inline ino_t
get_ino () const { return conv_handle
.get_ino (fs
.is_nfs ()); }
415 void close_conv_handle () { conv_handle
.close (); }
417 ino_t
get_ino_by_handle (HANDLE h
);
418 inline const char *get_posix () const { return posix_path
; }
419 void set_posix (const char *);
420 DWORD
get_symlink_length () { return symlink_length
; };
424 #define SYMLINK_COOKIE "!<symlink>"
427 #define SOCKET_COOKIE "!<socket >"
429 /* Interix symlink marker */
430 #define INTERIX_SYMLINK_COOKIE "IntxLNK\1"
434 FE_NADA
= 0, /* Nothing special */
435 FE_NNF
= 1, /* Return NULL if not found */
436 FE_CWD
= 4, /* Search CWD for program */
437 FE_DLL
= 8 /* Search for DLLs, not executables. */
439 const char *find_exec (const char *name
, path_conv
& buf
,
440 const char *search
= "PATH",
441 unsigned opt
= FE_NADA
,
442 const char **known_suffix
= NULL
);
444 /* Common macros for checking for invalid path names */
445 #define isdrive(s) (isalpha (*(s)) && (s)[1] == ':')
446 #define iswdrive(s) (iswalpha (*(s)) && (s)[1] == L':')
449 has_exec_chars (const char *buf
, int len
)
452 ((buf
[0] == '#' && buf
[1] == '!') ||
453 (buf
[0] == ':' && buf
[1] == '\n') ||
454 (buf
[0] == 'M' && buf
[1] == 'Z'));
457 int pathmatch (const char *path1
, const char *path2
, bool caseinsensitive
);
458 int pathnmatch (const char *path1
, const char *path2
, int len
, bool caseinsensitive
);
459 bool has_dot_last_component (const char *dir
, bool test_dot_dot
);
461 int path_prefix_p (const char *path1
, const char *path2
, int len1
,
462 bool caseinsensitive
);
464 int normalize_win32_path (const char *, char *, char *&);
465 int normalize_posix_path (const char *, char *, char *&);
466 PUNICODE_STRING
get_nt_native_path (const char *, UNICODE_STRING
&, bool);
468 int symlink_worker (const char *, path_conv
&, bool);