📄 path.cc
字号:
/* Scan path_copy from right to left looking either for a symlink or an actual existing file. If an existing file is found, just return. If a symlink is found exit the for loop. Also: be careful to preserve the errno returned from symlink.check as the caller may need it. */ /* FIXME: Do we have to worry about multiple \'s here? */ int component = 0; // Number of translated components sym.contents[0] = '\0'; for (;;) { const suffix_info *suff; char pathbuf[MAX_PATH]; char *full_path; /* Don't allow symlink.check to set anything in the path_conv class if we're working on an inner component of the path */ if (component) { suff = NULL; sym.pflags = 0; full_path = pathbuf; } else { suff = suffixes; sym.pflags = path_flags; full_path = this->path; } /* 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); if (error) return; if (devn == FH_CYGDRIVE) { if (!component) fileattr = FILE_ATTRIBUTE_DIRECTORY; else { devn = FH_BAD; fileattr = GetFileAttributes (this->path); } goto out; } else if (isvirtual_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); int file_type = fh->exists (); switch (file_type) { case 1: case 2: fileattr = FILE_ATTRIBUTE_DIRECTORY; break; case -1: fileattr = 0; break; default: 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) { fileattr = 0; path_flags = sym.pflags; if (component) { error = ENOTDIR; return; } goto out; /* Found a device. Stop parsing. */ } if (!fs.update (full_path)) fs.root_dir[0] = '\0'; /* Eat trailing slashes */ char *dostail = strchr (full_path, '\0'); /* If path is only a drivename, Windows interprets it as the current working directory on this drive instead of the root dir which is what we want. So we need the trailing backslash in this case. */ while (dostail > full_path + 3 && (*--dostail == '\\')) *tail = '\0'; if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0') { full_path[2] = '\\'; full_path[3] = '\0'; } if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED) { fileattr = GetFileAttributes (this->path); goto out; } int len = sym.check (full_path, suff, opt | fs.sym_opt); if (sym.case_clash) { if (pcheck_case == PCHECK_STRICT) { case_clash = TRUE; error = ENOENT; goto out; } /* If pcheck_case==PCHECK_ADJUST the case_clash is remembered if the last component is concerned. This allows functions which shall create files to avoid overriding already existing files with another case. */ if (!component) case_clash = TRUE; } if (!(opt & PC_SYM_IGNORE)) { if (!component) { fileattr = sym.fileattr; path_flags = sym.pflags; } /* If symlink.check found an existing non-symlink file, then it sets the appropriate flag. It also sets any suffix found into `ext_here'. */ if (!sym.is_symlink && sym.fileattr != INVALID_FILE_ATTRIBUTES) { error = sym.error; if (component == 0) add_ext_from_sym (sym); if (pcheck_case == PCHECK_RELAXED) goto out; // file found /* Avoid further symlink evaluation. Only case checks are done now. */ opt |= PC_SYM_IGNORE; } /* Found a symlink if len > 0. If component == 0, then the src path itself was a symlink. If !follow_mode then we're done. Otherwise we have to insert the path found into the full path that we are building and perform all of these operations again on the newly derived path. */ else if (len > 0) { saw_symlinks = 1; if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW)) { set_symlink (); // last component of path is a symlink. if (opt & PC_SYM_CONTENTS) { strcpy (path, sym.contents); goto out; } add_ext_from_sym (sym); if (pcheck_case == PCHECK_RELAXED) goto out; /* Avoid further symlink evaluation. Only case checks are done now. */ opt |= PC_SYM_IGNORE; } else break; } /* No existing file found. */ } /* Find the "tail" of the path, e.g. in '/for/bar/baz', /baz is the tail. */ char *newtail = strrchr (path_copy, '/'); if (tail != path_end) *tail = '/'; /* Exit loop if there is no tail or we are at the beginning of a UNC path */ if (!newtail || newtail == path_copy || (newtail == path_copy + 1 && newtail[-1] == '/')) goto out; // all done tail = newtail; /* Haven't found an existing pathname component yet. Pinch off the tail and try again. */ *tail = '\0'; component++; } /* Arrive here if above loop detected a symlink. */ if (++loop > MAX_LINK_DEPTH) { error = ELOOP; // Eep. return; } MALLOC_CHECK; /* The tail is pointing at a null pointer. Increment it and get the length. If the tail was empty then this increment will end up pointing to the extra \0 added to path_copy above. */ int taillen = strlen (++tail); int buflen = strlen (sym.contents); if (buflen + taillen > MAX_PATH) { error = ENAMETOOLONG; strcpy (path, "::ENAMETOOLONG::"); return; } /* Strip off current directory component since this is the part that refers to the symbolic link. */ if ((p = strrchr (path_copy, '/')) == NULL) p = path_copy; else if (p == path_copy) p++; *p = '\0'; char *headptr; if (isabspath (sym.contents)) headptr = tmp_buf; /* absolute path */ else { /* Copy the first part of the path and point to the end. */ strcpy (tmp_buf, path_copy); headptr = strchr (tmp_buf, '\0'); } /* See if we need to separate first part + symlink contents with a / */ if (headptr > tmp_buf && headptr[-1] != '/') *headptr++ = '/'; /* Copy the symlink contents to the end of tmp_buf. Convert slashes. FIXME? */ for (p = sym.contents; *p; p++) *headptr++ = *p == '\\' ? '/' : *p; /* Copy any tail component */ if (tail >= path_end) *headptr = '\0'; else { *headptr++ = '/'; strcpy (headptr, tail); } /* Now evaluate everything all over again. */ src = tmp_buf; } if (!(opt & PC_SYM_CONTENTS)) 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) /* nothing to do */; else if (fileattr & FILE_ATTRIBUTE_DIRECTORY) path_flags &= ~PATH_SYMLINK; else { debug_printf ("%s is a non-directory", path); error = ENOTDIR; return; } if (devn == FH_BAD) { if (!fs.update (path)) { fs.root_dir[0] = '\0'; set_has_acls (false); set_has_buggy_open (false); } else { 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 (!allow_smbntsec && fs.is_remote_drive) set_has_acls (false); else set_has_acls (fs.flags & FS_PERSISTENT_ACLS); /* 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); } }#if 0 if (issocket ()) devn = FH_SOCKET;#endif if (!(opt & PC_FULL)) { if (is_relpath) mkrelpath (this->path); if (need_directory) { size_t n = strlen (this->path); /* Do not add trailing \ to UNC device names like \\.\a: */ if (this->path[n - 1] != '\\' && (strncmp (this->path, "\\\\.\\", 4) != 0 || !strncasematch (this->path + 4, "unc\\", 4))) { this->path[n] = '\\'; this->path[n + 1] = '\0'; } } } if (saw_symlinks) set_has_symlinks (); if (!error && !isdir () && !(path_flags & PATH_ALL_EXEC)) { const char *p = strchr (path, '\0') - 4; if (p >= path && (strcasematch (".exe", p) || strcasematch (".bat", p) || strcasematch (".com", p))) path_flags |= PATH_EXEC; }#if 0 if (!error) { last_path_conv = *this; strcpy (last_src, src); }#endif}static __inline intdigits (const char *name){ char *p; int n = strtol (name, &p, 10); 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 __stdcallget_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; 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -