diff options
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r-- | winsup/cygwin/path.cc | 544 |
1 files changed, 189 insertions, 355 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index b0108777e..d1e31ad9c 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -63,8 +63,8 @@ details. */ #include <cygwin/version.h> #include "cygerrno.h" #include "security.h" -#include "fhandler.h" #include "path.h" +#include "fhandler.h" #include "sync.h" #include "sigproc.h" #include "pinfo.h" @@ -97,7 +97,11 @@ struct symlink_info bool ext_tacked_on; int error; bool case_clash; + _major_t major; + _minor_t minor; + _mode_t mode; int check (char *path, const suffix_info *suffixes, unsigned opt); + bool parse_device (const char *); BOOL case_check (char *path); }; @@ -354,27 +358,27 @@ fs_info::update (const char *win32_path) if (!rootdir (tmp_buf)) { debug_printf ("Cannot get root component of path %s", win32_path); - name [0] = '\0'; - sym_opt = flags = serial = 0; + name_storage [0] = '\0'; + sym_opt_storage = flags_storage = serial_storage = 0; return false; } - if (strcmp (tmp_buf, root_dir) == 0) + if (strcmp (tmp_buf, root_dir_storage) == 0) return 1; - strncpy (root_dir, tmp_buf, MAX_PATH); - drive_type = GetDriveType (root_dir); - if (drive_type == DRIVE_REMOTE || (drive_type == DRIVE_UNKNOWN && (root_dir[0] == '\\' && root_dir[1] == '\\'))) - is_remote_drive = 1; + strncpy (root_dir_storage, tmp_buf, MAX_PATH); + drive_type_storage = GetDriveType (root_dir_storage); + if (drive_type_storage == DRIVE_REMOTE || (drive_type_storage == DRIVE_UNKNOWN && (root_dir_storage[0] == '\\' && root_dir_storage[1] == '\\'))) + is_remote_drive_storage = 1; else - is_remote_drive = 0; + is_remote_drive_storage = 0; - if (!GetVolumeInformation (root_dir, NULL, 0, &serial, NULL, &flags, - name, sizeof (name))) + if (!GetVolumeInformation (root_dir_storage, NULL, 0, &serial_storage, NULL, &flags_storage, + name_storage, sizeof (name_storage))) { - debug_printf ("Cannot get volume information (%s), %E", root_dir); - name [0] = '\0'; - sym_opt = flags = serial = 0; + debug_printf ("Cannot get volume information (%s), %E", root_dir_storage); + name_storage[0] = '\0'; + sym_opt_storage = flags_storage = serial_storage = 0; return false; } /* FIXME: Samba by default returns "NTFS" in file system name, but @@ -382,19 +386,11 @@ fs_info::update (const char *win32_path) * distinguish between samba and real ntfs, it should be implemented * here. */ - sym_opt = (!is_remote_drive && strcmp (name, "NTFS") == 0) ? PC_CHECK_EA : 0; + sym_opt_storage = (!is_remote_drive_storage && strcmp (name_storage, "NTFS") == 0) ? PC_CHECK_EA : 0; return true; } -char * -path_conv::return_and_clear_normalized_path () -{ - char *s = normalized_path; - normalized_path = NULL; - return s; -} - void path_conv::fillin (HANDLE h) { @@ -402,14 +398,31 @@ path_conv::fillin (HANDLE h) if (!GetFileInformationByHandle (h, &local)) { fileattr = INVALID_FILE_ATTRIBUTES; - fs.serial = 0; + fs.serial () = 0; } else { fileattr = local.dwFileAttributes; - fs.serial = local.dwVolumeSerialNumber; + fs.serial () = local.dwVolumeSerialNumber; + } + fs.drive_type () = DRIVE_UNKNOWN; +} + +void +path_conv::set_normalized_path (const char *path_copy) +{ + char *eopath = strchr (path, '\0'); + size_t n = strlen (path_copy) + 1; + + normalized_path = path + sizeof (path) - n; + if (normalized_path > eopath) + normalized_path_size = n; + else + { + normalized_path = (char *) cmalloc (HEAP_STR, n); + normalized_path_size = 0; } - fs.drive_type = DRIVE_UNKNOWN; + memcpy (normalized_path, path_copy, n); } /* Convert an arbitrary path SRC to a pure Win32 path, suitable for @@ -457,13 +470,13 @@ path_conv::check (const char *src, unsigned opt, known_suffix = NULL; fileattr = INVALID_FILE_ATTRIBUTES; case_clash = false; - devn = unit = 0; - fs.root_dir[0] = '\0'; - fs.name[0] = '\0'; - fs.flags = fs.serial = 0; - fs.sym_opt = 0; - fs.drive_type = 0; - fs.is_remote_drive = 0; + memset (&dev, 0, sizeof (dev)); + fs.root_dir ()[0] = '\0'; + fs.name ()[0] = '\0'; + fs.flags () = fs.serial () = 0; + fs.sym_opt () = 0; + fs.drive_type () = 0; + fs.is_remote_drive () = 0; normalized_path = NULL; if (!(opt & PC_NULLEMPTY)) @@ -528,29 +541,29 @@ path_conv::check (const char *src, unsigned opt, } /* Convert to native path spec sans symbolic link info. */ - error = mount_table->conv_to_win32_path (path_copy, full_path, devn, - unit, &sym.pflags, 1); + error = mount_table->conv_to_win32_path (path_copy, full_path, dev, + &sym.pflags, 1); if (error) return; - if (devn == FH_CYGDRIVE) + if (dev.major == DEV_CYGDRIVE_MAJOR) { if (!component) fileattr = FILE_ATTRIBUTE_DIRECTORY; else { - devn = FH_BAD; + dev.devn = FH_FS; fileattr = GetFileAttributes (this->path); } goto out; } - else if (isvirtual_dev (devn)) + else if (isvirtual_dev (dev.devn)) { /* FIXME: Calling build_fhandler here is not the right way to handle this. */ - fhandler_virtual *fh = - (fhandler_virtual *) cygheap->fdtab.build_fhandler (-1, devn, (const char *) path_copy, NULL, unit); + fhandler_virtual *fh = (fhandler_virtual *) build_fh_dev (dev, path_copy); int file_type = fh->exists (); + delete fh; switch (file_type) { case 1: @@ -564,11 +577,10 @@ path_conv::check (const char *src, unsigned opt, fileattr = INVALID_FILE_ATTRIBUTES; break; } - delete fh; goto out; } /* devn should not be a device. If it is, then stop parsing now. */ - else if (devn != FH_BAD) + else if (dev.devn != FH_FS) { fileattr = 0; path_flags = sym.pflags; @@ -581,7 +593,7 @@ path_conv::check (const char *src, unsigned opt, } if (!fs.update (full_path)) - fs.root_dir[0] = '\0'; + fs.root_dir ()[0] = '\0'; /* Eat trailing slashes */ char *dostail = strchr (full_path, '\0'); @@ -605,7 +617,19 @@ path_conv::check (const char *src, unsigned opt, goto out; } - int len = sym.check (full_path, suff, opt | fs.sym_opt); + int len = sym.check (full_path, suff, opt | fs.sym_opt ()); + + if (sym.minor || sym.major) + { + dev.parse (sym.major, sym.minor); + dev.setfs (1); + dev.mode = sym.mode; + fileattr = sym.fileattr; + goto out; + } + + if (sym.pflags & PATH_SOCKET) + dev.setfs (1); if (sym.case_clash) { @@ -757,12 +781,6 @@ path_conv::check (const char *src, unsigned opt, add_ext_from_sym (sym); out: - if (opt & PC_POSIX) - { - if (tail[1] != '\0') - *tail = '/'; - normalized_path = cstrdup (path_copy); - } /* Deal with Windows stupidity which considers filename\. to be valid even when "filename" is not a directory. */ if (!need_directory || error) @@ -776,11 +794,11 @@ out: return; } - if (devn == FH_BAD) + if (dev.devn == FH_FS) { if (!fs.update (path)) { - fs.root_dir[0] = '\0'; + fs.root_dir ()[0] = '\0'; set_has_acls (false); // already implied but... set_has_buggy_open (false); // ditto } @@ -788,8 +806,8 @@ out: { set_isdisk (); debug_printf ("root_dir(%s), this->path(%s), set_has_acls(%d)", - fs.root_dir, this->path, fs.flags & FS_PERSISTENT_ACLS); - if (!(fs.flags & FS_PERSISTENT_ACLS) || (!allow_smbntsec && fs.is_remote_drive)) + fs.root_dir (), this->path, fs.flags () & FS_PERSISTENT_ACLS); + if (!(fs.flags () & FS_PERSISTENT_ACLS) || (!allow_smbntsec && fs.is_remote_drive ())) set_has_acls (false); else { @@ -801,7 +819,7 @@ out: } /* Known file systems with buggy open calls. Further explanation in fhandler.cc (fhandler_disk_file::open). */ - set_has_buggy_open (strcmp (fs.name, "SUNWNFS") == 0); + set_has_buggy_open (strcmp (fs.name (), "SUNWNFS") == 0); } if (exec_state () != dont_know_if_executable) /* ok */; @@ -810,8 +828,11 @@ out: else if (issymlink () || issocket ()) set_exec (0); } + +#if 0 if (issocket ()) devn = FH_SOCKET; +#endif if (!(opt & PC_FULL)) { @@ -844,6 +865,15 @@ out: path_flags |= PATH_EXEC; } + if (!(opt & PC_POSIX)) + normalized_path_size = 0; + else + { + if (tail[1] != '\0') + *tail = '/'; + set_normalized_path (path_copy); + } + #if 0 if (!error) { @@ -862,293 +892,30 @@ digits (const char *name) return p > name && !*p ? n : -1; } -const char *windows_device_names[] NO_COPY = -{ - NULL, - "\\dev\\console", - "conin", - "conout", - "\\dev\\ttym", - "\\dev\\tty%d", - "\\dev\\ptym", - "\\\\.\\com%d", - "\\dev\\pipe", - "\\dev\\piper", - "\\dev\\pipew", - "\\dev\\socket", - "\\dev\\windows", - - NULL, NULL, NULL, - - "\\dev\\disk", - "\\dev\\fd%d", - "\\dev\\st%d", - "nul", - "\\dev\\zero", - "\\dev\\%srandom", - "\\dev\\mem", - "\\dev\\clipboard", - "\\dev\\dsp" -}; - -#define deveq(s) (strcasematch (name, (s))) -#define deveqn(s, n) (strncasematch (name, (s), (n))) -#define wdeveq(s) (strcasematch (w32_path, (s))) -#define wdeveqn(s, n) (strncasematch (w32_path, (s), (n))) -#define udeveq(s) (strcasematch (unix_path, (s))) -#define udeveqn(s, n) (strncasematch (unix_path, (s), (n))) - -static int __stdcall -get_devn (const char *name, int &unit) -{ - int devn = FH_BAD; - name += 5; - if (deveq ("tty")) - { - if (real_tty_attached (myself)) - { - unit = myself->ctty; - devn = FH_TTYS; - } - else if (myself->ctty > 0) - devn = FH_CONSOLE; - } - else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0) - devn = FH_TTYS; - else if (deveq ("ttym")) - devn = FH_TTYM; - else if (deveq ("ptmx")) - devn = FH_PTYM; - else if (deveq ("windows")) - devn = FH_WINDOWS; - else if (deveq ("dsp")) - devn = FH_OSS_DSP; - else if (deveq ("conin")) - devn = FH_CONIN; - else if (deveq ("conout")) - devn = FH_CONOUT; - else if (deveq ("null")) - devn = FH_NULL; - else if (deveq ("zero")) - devn = FH_ZERO; - else if (deveq ("random") || deveq ("urandom")) - { - devn = FH_RANDOM; - unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */ - } - else if (deveq ("mem")) - { - devn = FH_MEM; - unit = 1; - } - else if (deveq ("clipboard")) - devn = FH_CLIPBOARD; - else if (deveq ("port")) - { - devn = FH_MEM; - unit = 4; - } - else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0 && unit < 100) - devn = FH_SERIAL; - else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0) - { - devn = FH_SERIAL; - unit++; - } - else if (deveq ("pipe")) - devn = FH_PIPE; - else if (deveq ("piper")) - devn = FH_PIPER; - else if (deveq ("pipew")) - devn = FH_PIPEW; - else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket") - || deveq ("dgsocket")) - { - devn = FH_SOCKET; - unit = tolower (*name) - 'a'; - } - - return devn; -} - -/* - major minor POSIX filename NT filename - ----- ----- -------------- ------------------------- - FH_TAPE 0 /dev/st0 \device\tape0 - FH_TAPE 1 /dev/st1 \device\tape1 - ... - FH_TAPE 128 /dev/nst0 \device\tape0 - FH_TAPE 129 /dev/nst1 \device\tape1 - ... - - FH_FLOPPY 0 /dev/fd0 \device\floppy0 - FH_FLOPPY 1 /dev/fd1 \device\floppy1 - ... - - FH_FLOPPY 16 /dev/scd0 \device\cdrom0 - FH_FLOPPY 17 /dev/scd0 \device\cdrom1 - ... - - FH_FLOPPY 32 /dev/sda \device\harddisk0\partition0 - FH_FLOPPY 33 /dev/sda1 \device\harddisk0\partition1 - ... - FH_FLOPPY 47 /dev/sda15 \device\harddisk0\partition15 - - FH_FLOPPY 48 /dev/sdb \device\harddisk1\partition0 - FH_FLOPPY 33 /dev/sdb1 \device\harddisk1\partition1 - ... - FH_FLOPPY 208 /dev/sdl \device\harddisk11\partition0 - ... - FH_FLOPPY 223 /dev/sdl15 \device\harddisk11\partition15 - - The following are needed to maintain backward compatibility with - the old Win32 partitioning scheme on W2K/XP. - - FH_FLOPPY 224 from mount tab \\.\A: - ... - FH_FLOPPY 250 from mount tab \\.\Z: -*/ -static int -get_raw_device_number (const char *name, const char *w32_path, int &unit) -{ - DWORD devn = FH_BAD; - - if (!w32_path) /* New approach using fixed device names. */ - { - if (deveqn ("st", 2)) - { - unit = digits (name + 2); - if (unit >= 0 && unit < 128) - devn = FH_TAPE; - } - else if (deveqn ("nst", 3)) - { - unit = digits (name + 3) + 128; - if (unit >= 128 && unit < 256) - devn = FH_TAPE; - } - else if (deveqn ("fd", 2)) - { - unit = digits (name + 2); - if (unit >= 0 && unit < 16) - devn = FH_FLOPPY; - } - else if (deveqn ("scd", 3)) - { - unit = digits (name + 3) + 16; - if (unit >= 16 && unit < 32) - devn = FH_FLOPPY; - } - else if (deveqn ("sd", 2) && isalpha (name[2])) - { - unit = (cyg_tolower (name[2]) - 'a') * 16 + 32; - if (unit >= 32 && unit < 224) - if (!name[3]) - devn = FH_FLOPPY; - else - { - int d = digits (name + 3); - if (d >= 1 && d < 16) - { - unit += d; - devn = FH_FLOPPY; - } - } - } - } - else /* Backward compatible checking of mount table device mapping. */ - { - if (wdeveqn ("tape", 4)) - { - unit = digits (w32_path + 4); - /* Norewind tape devices have leading n in name. */ - if (deveqn ("n", 1)) - unit += 128; - devn = FH_TAPE; - } - else if (wdeveqn ("physicaldrive", 13)) - { - unit = digits (w32_path + 13) * 16 + 32; - devn = FH_FLOPPY; - } - else if (isdrive (w32_path)) - { - unit = cyg_tolower (w32_path[0]) - 'a' + 224; - devn = FH_FLOPPY; - } - } - return devn; -} - -static int __stdcall get_device_number (const char *unix_path, - const char *w32_path, int &unit) - __attribute__ ((regparm(3))); -static int __stdcall -get_device_number (const char *unix_path, const char *w32_path, int &unit) -{ - DWORD devn = FH_BAD; - unit = 0; - - if (*unix_path == '/' && udeveqn ("/dev/", 5)) - { - devn = get_devn (unix_path, unit); - if (devn == FH_BAD && *w32_path == '\\' && wdeveqn ("\\dev\\", 5)) - devn = get_devn (w32_path, unit); - if (devn == FH_BAD && wdeveqn ("\\\\.\\", 4)) - devn = get_raw_device_number (unix_path + 5, w32_path + 4, unit); - if (devn == FH_BAD) - devn = get_raw_device_number (unix_path + 5, NULL, unit); - } - - return devn; -} - /* Return TRUE if src_path is a Win32 device name, filling out the device name in win32_path */ static BOOL -win32_device_name (const char *src_path, char *win32_path, - DWORD &devn, int &unit) +win32_device_name (const char *src_path, char *win32_path, device& dev) { - const char *devfmt; - - devn = get_device_number (src_path, win32_path, unit); + dev.parse (src_path); - if (devn == FH_BAD) + if (dev.devn == FH_FS) return false; - if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL) - return false; - switch (devn) + switch (dev.devn) { - case FH_SOCKET: - char *c; - strcpy (win32_path, src_path); - while ((c = strchr (win32_path, '/'))) - *c = '\\'; - break; - case FH_RANDOM: - __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u"); - break; case FH_TAPE: - __small_sprintf (win32_path, "\\Device\\Tape%d", unit % 128); + __small_sprintf (win32_path, dev.fmt, dev.minor % 128); break; - case FH_FLOPPY: - if (unit < 16) - __small_sprintf (win32_path, "\\Device\\Floppy%d", unit); - else if (unit < 32) - __small_sprintf (win32_path, "\\Device\\CdRom%d", unit - 16); - else if (unit < 224) - __small_sprintf (win32_path, "\\Device\\Harddisk%d\\Partition%d", - (unit - 32) / 16, unit % 16); - else - __small_sprintf (win32_path, "\\DosDevices\\%c:", unit - 224 + 'A'); + case FH_RAWDRIVE: + __small_sprintf (win32_path, dev.fmt, dev.minor - 224 + 'A'); break; default: - __small_sprintf (win32_path, devfmt, unit); + __small_sprintf (win32_path, dev.fmt, dev.minor); break; } - return TRUE; + return true; } /* Normalize a Win32 path. @@ -1529,9 +1296,8 @@ mount_item::build_win32 (char *dst, const char *src, unsigned *outflags, unsigne {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */ int -mount_info::conv_to_win32_path (const char *src_path, char *dst, - DWORD &devn, int &unit, unsigned *flags, - bool no_normalize) +mount_info::conv_to_win32_path (const char *src_path, char *dst, device& dev, + unsigned *flags, bool no_normalize) { bool chroot_ok = !cygheap->root.exists (); while (sys_mount_table_counter < cygwin_shared->sys_mount_table_counter) @@ -1543,8 +1309,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, MALLOC_CHECK; unsigned dummy_flags; - devn = FH_BAD; - unit = 0; + dev.devn = FH_FS; if (!flags) flags = &dummy_flags; @@ -1595,7 +1360,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, } /* See if this is a cygwin "device" */ - if (win32_device_name (pathbuf, dst, devn, unit)) + if (win32_device_name (pathbuf, dst, dev)) { *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */ rc = 0; @@ -1607,20 +1372,23 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, MALLOC_CHECK; if (isproc (pathbuf)) { - devn = fhandler_proc::get_proc_fhandler (pathbuf); - if (devn == FH_BAD) + dev = *proc_dev; + dev.devn = fhandler_proc::get_proc_fhandler (pathbuf); + if (dev.devn == FH_BAD) return ENOENT; } else if (iscygdrive (pathbuf)) { int n = mount_table->cygdrive_len - 1; + int unit; + if (!pathbuf[n] || (pathbuf[n] == '/' && pathbuf[n + 1] == '.' && !pathbuf[n + 2])) { unit = 0; dst[0] = '\0'; if (mount_table->cygdrive_len > 1) - devn = FH_CYGDRIVE; + dev = *cygdrive_dev; } else if (cygdrive_win32_path (pathbuf, dst, unit)) { @@ -1678,8 +1446,8 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, chroot_ok = !cygheap->root.exists (); } - if (!isvirtual_dev (devn)) - win32_device_name (src_path, dst, devn, unit); + if (!isvirtual_dev (dev.devn)) + win32_device_name (src_path, dst, dev); out: MALLOC_CHECK; @@ -1734,7 +1502,7 @@ mount_info::cygdrive_win32_path (const char *src, char *dst, int& unit) const char *p = src + cygdrive_len; if (!isalpha (*p) || (!isdirsep (p[1]) && p[1])) { - unit = -1; + unit = -1; /* FIXME: should be zero, maybe? */ dst[0] = '\0'; res = 0; } @@ -2700,6 +2468,13 @@ int allow_winsymlinks = TRUE; extern "C" int symlink (const char *topath, const char *frompath) { + return symlink_worker (topath, frompath, allow_winsymlinks, false); +} + +int +symlink_worker (const char *topath, const char *frompath, bool use_winsym, + bool isdevice) +{ HANDLE h; int res = -1; path_conv win32_path, win32_topath; @@ -2723,7 +2498,7 @@ symlink (const char *topath, const char *frompath) } win32_path.check (frompath, PC_SYM_NOFOLLOW); - if (allow_winsymlinks && !win32_path.exists ()) + if (use_winsym && !win32_path.exists ()) { strcpy (from, frompath); strcat (from, ".lnk"); @@ -2738,13 +2513,22 @@ symlink (const char *topath, const char *frompath) syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ()); - if (win32_path.is_device () || win32_path.exists ()) + if (win32_path.is_auto_device ()) { set_errno (EEXIST); goto done; } - if (allow_winsymlinks) + DWORD create_how; + if (!use_winsym) + create_how = CREATE_NEW; + else if (isdevice) + { + strcpy (w32topath, topath); + create_how = CREATE_ALWAYS; + (void) SetFileAttributes (win32_path, FILE_ATTRIBUTE_NORMAL); + } + else { if (!isabspath (topath)) { @@ -2768,21 +2552,22 @@ symlink (const char *topath, const char *frompath) *cp = c; chdir (cwd); } + create_how = CREATE_NEW; } if (allow_ntsec && win32_path.has_acls ()) set_security_attribute (S_IFLNK | STD_RBITS | STD_WBITS, &sa, alloca (4096), 4096); - h = CreateFile (win32_path, GENERIC_WRITE, 0, &sa, - CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + h = CreateFile (win32_path, GENERIC_WRITE, 0, &sa, create_how, + FILE_ATTRIBUTE_NORMAL, 0); if (h == INVALID_HANDLE_VALUE) __seterrno (); else { BOOL success; - if (allow_winsymlinks) + if (use_winsym) { create_shortcut_header (); /* Don't change the datatypes of `len' and `win_len' since @@ -2822,16 +2607,16 @@ symlink (const char *topath, const char *frompath) win32_path.get_win32 (), S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO); - DWORD attr = allow_winsymlinks ? FILE_ATTRIBUTE_READONLY - : FILE_ATTRIBUTE_SYSTEM; + DWORD attr = use_winsym ? FILE_ATTRIBUTE_READONLY + : FILE_ATTRIBUTE_SYSTEM; #ifdef HIDDEN_DOT_FILES cp = strrchr (win32_path, '\\'); if ((cp && cp[1] == '.') || *win32_path == '.') attr |= FILE_ATTRIBUTE_HIDDEN; #endif - SetFileAttributes (win32_path.get_win32 (), attr); + SetFileAttributes (win32_path, attr); - if (win32_path.fs_fast_ea ()) + if (!isdevice && win32_path.fs_fast_ea ()) set_symlink_ea (win32_path, topath); res = 0; } @@ -2844,7 +2629,8 @@ symlink (const char *topath, const char *frompath) } done: - syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath); + syscall_printf ("%d = symlink_worker (%s, %s, %d, %d)", res, topath, + frompath, use_winsym, isdevice); return res; } @@ -3086,6 +2872,48 @@ suffix_scan::next () } } +bool +symlink_info::parse_device (const char *contents) +{ + char *endptr; + _major_t mymajor; + _major_t myminor; + _mode_t mymode; + + mymajor = strtol (++contents, &endptr, 16); + if (endptr == contents) + return false; + + contents = endptr; + myminor = strtol (++contents, &endptr, 16); + if (endptr == contents) + return false; + + contents = endptr; + mymode = strtol (++contents, &endptr, 16); + if (endptr == contents) + return false; + + switch (mymode & S_IFMT) + { + case S_IFIFO: + mymajor = _major (FH_FIFO); + myminor = _minor (FH_FIFO); + break; + case S_IFBLK: + case S_IFCHR: + if (mymajor || myminor) + break; + default: + return false; + } + + major = mymajor; + minor = myminor; + mode = mymode; + return true; +} + /* Check if PATH is a symlink. PATH must be a valid Win32 path name. If PATH is a symlink, put the value of the symlink--the file to @@ -3114,6 +2942,8 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) is_symlink = true; ext_here = suffix.has (path, suffixes); extn = ext_here - path; + major = 0; + minor = 0; pflags &= ~(PATH_SYMLINK | PATH_LNK); @@ -3179,13 +3009,16 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) goto file_not_symlink; /* FIXME: if symlink isn't present in EA, but EAs are supported, - * should we write it there? - */ + should we write it there? */ switch (sym_check) { case 1: res = check_shortcut (suffix.path, fileattr, h, contents, &error, &pflags); - if (res) + if (!res) + /* check more below */; + else if (*contents == ':' && parse_device (contents)) + goto file_not_symlink; + else break; /* If searching for `foo' and then finding a `foo.lnk' which is no shortcut, return the same as if file not found. */ @@ -3204,7 +3037,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) file_not_symlink: is_symlink = false; - syscall_printf ("not a symlink"); + syscall_printf ("%s", (major || minor) ? "is a device" : "not a symlink"); res = 0; break; } @@ -3652,7 +3485,8 @@ conv_path_list_buf_size (const char *path_list, bool to_posix) + (nrel * strlen (to_posix ? pc.normalized_path : pc.get_win32 ())) + 100; - cfree (pc.normalized_path); // FIXME - probably should be in a destructor but + if (!pc.normalized_path_size && pc.normalized_path) + cfree (pc.normalized_path); // FIXME - probably should be in a destructor but // it's hard to justify a destructor for the few // places where this is needed return size; |