diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index da4d7216e..5f291312b 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,34 @@ +Sat Jun 2 14:07:28 2001 Christopher Faylor + + * cygheap.cc (cygheap_root::cygheap_rot): Remove constructor. + (cygheap_root::~cygheap_root): Remove destructor. + (cygheap_root::operator =): Remove. + (cygheap_root::set): New method. + * cygheap.h (cygheap_root): Reflect above changes. Store root info in + mount-like structure. + (cygheap_root:posix_ok): New method. + (cygheap_root::ischroot_native): Ditto. + (cygheap_root::unchroot): Ditto. + (cygheap_root::exists): Ditto. + (cygheap_root::posix_length): Ditto. + (cygheap_root::posix_path): Ditto. + (cygheap_root::native_length): Ditto. + (cygheap_root::native_path): Ditto. + * dir.cc (opendir): Remove special chroot test. + * path.cc (path_prefix_p): Remove front end. + (normalize_posix_path): Reorganize chroot tests to accomodate new + convention of allowing paths using posix chroot prefix. + (path_conv::check): Pass a "already ran normalize" option to + conv_to_win32_path. Return if there is an error from this function. + (mount_info::conv_to_win32_path): Add extra argument. Don't call + normalize_posix_path if caller has already done so. Substitute chroot + setting, if any, for root translation. Add chroot checking to final + output step. + * shared_info (mount_info): Accomodate additional argument to + conv_to_win32_path. + * syscalls.cc (chroot): Store both normalized posix path and native + path in chroot. + Fri Jun 1 10:57:19 2001 Christopher Faylor * path.cc (chdir): Really make sure that isspace gets only an unsigned diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc index 7cad22b5e..e22a91060 100644 --- a/winsup/cygwin/cygheap.cc +++ b/winsup/cygwin/cygheap.cc @@ -290,40 +290,20 @@ cstrdup1 (const char *s) return p; } -cygheap_root::cygheap_root (cygheap_root &nroot) +void +cygheap_root::set (const char *posix, const char *native) { - rootlen = nroot.rootlen; - root = nroot.root ? cstrdup (nroot.root) : NULL; -} + if (!m) + m = (struct cygheap_root_mount_info *) ccalloc (HEAP_MOUNT, 1, sizeof (*m)); + strcpy (m->posix_path, posix); + m->posix_pathlen = strlen (posix); + if (m->posix_pathlen >= 1 && m->posix_path[m->posix_pathlen - 1] == '/') + m->posix_path[--m->posix_pathlen] = '\0'; -cygheap_root::~cygheap_root () -{ - if (root) - cfree (root); -} - -char * -cygheap_root::operator =(const char *new_root) -{ - if (root) - { - cfree (root); - root = NULL; - } - rootlen = 0; - if (new_root && *new_root) - { - root = cstrdup (new_root); - rootlen = strlen (root); - if (rootlen >= 1 && root[rootlen - 1] == '/') - root[--rootlen] = '\0'; - if (!rootlen) - { - cfree (root); - root = NULL; - } - } - return root; + strcpy (m->native_path, native); + m->native_pathlen = strlen (native); + if (m->native_pathlen >= 1 && m->native_path[m->native_pathlen - 1] == '\\') + m->native_path[--m->native_pathlen] = '\0'; } cygheap_user::~cygheap_user () diff --git a/winsup/cygwin/cygheap.h b/winsup/cygwin/cygheap.h index 6a8e56290..cc953a764 100644 --- a/winsup/cygwin/cygheap.h +++ b/winsup/cygwin/cygheap.h @@ -16,6 +16,7 @@ enum cygheap_types HEAP_STR, HEAP_ARGV, HEAP_BUF, + HEAP_MOUNT, HEAP_1_START, HEAP_1_STR, HEAP_1_ARGV, @@ -37,18 +38,51 @@ struct _cmalloc_entry char data[0]; }; +struct cygheap_root_mount_info +{ + char posix_path[MAX_PATH]; + unsigned posix_pathlen; + char native_path[MAX_PATH]; + unsigned native_pathlen; +}; + class cygheap_root { /* Root directory information. This is used after a chroot is called. */ - size_t rootlen; - char *root; + struct cygheap_root_mount_info *m; + public: - cygheap_root (cygheap_root &nroot); - ~cygheap_root (); - char *operator =(const char *new_root); - size_t length () const { return rootlen; } - const char *path () const { return root; } + bool posix_ok (const char *path) + { + extern int path_prefix_p (const char *, const char *, int); + if (!m) + return 1; + return path_prefix_p (m->posix_path, path, m->posix_pathlen); + } + bool ischroot_native (const char *path) + { + if (!m) + return 1; + return strncasematch (m->native_path, path, m->native_pathlen) + && (path[m->native_pathlen] == '\\' || !path[m->native_pathlen]); + + } + const char *unchroot (const char *path) + { + if (!m) + return path; + const char *p = path + m->posix_pathlen; + if (!*p) + p = "/"; + return p; + } + bool exists () {return !!m;} + void set (const char *posix, const char *native); + size_t posix_length () const { return m->posix_pathlen; } + const char *posix_path () const { return m->posix_path; } + size_t native_length () const { return m->native_pathlen; } + const char *native_path () const { return m->native_path; } }; class cygheap_user diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc index 9e154b010..f55cbe31e 100644 --- a/winsup/cygwin/dir.cc +++ b/winsup/cygwin/dir.cc @@ -78,8 +78,7 @@ opendir (const char *dirname) goto failed; } - if (stat (cygheap->root.length () ? dirname : real_dirname.get_win32 (), - &statbuf) == -1) + if (stat (real_dirname, &statbuf) == -1) goto failed; if (!(statbuf.st_mode & S_IFDIR)) @@ -88,7 +87,7 @@ opendir (const char *dirname) goto failed; } - len = strlen (real_dirname.get_win32 ()); + len = strlen (real_dirname); if (len > MAX_PATH - 3) { set_errno (ENAMETOOLONG); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 21df976cd..20629913a 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -89,7 +89,7 @@ static DWORD available_drives; static int normalize_win32_path (const char *src, char *dst); static void slashify (const char *src, char *dst, int trailing_slash_p); static void backslashify (const char *src, char *dst, int trailing_slash_p); -static int path_prefix_p_ (const char *path1, const char *path2, int len1); +static int path_prefix_p (const char *path1, const char *path2, int len1); struct symlink_info { @@ -108,10 +108,6 @@ struct symlink_info int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */ -#define path_prefix_p(p1, p2, l1) \ - ((cyg_tolower(*(p1))==cyg_tolower(*(p2))) && \ - path_prefix_p_(p1, p2, l1)) - /* Determine if path prefix matches current cygdrive */ #define iscygdrive(path) \ (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len)) @@ -121,12 +117,6 @@ int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */ (isdirsep(path[mount_table->cygdrive_len + 1]) || \ !path[mount_table->cygdrive_len + 1])) -#define ischrootpath(p) \ - (cygheap->root.length () && \ - strncasematch (cygheap->root.path (), p, cygheap->root.length ()) && \ - (p[cygheap->root.length ()] == '/' \ - || p[cygheap->root.length ()] == '\0')) - /* Return non-zero if PATH1 is a prefix of PATH2. Both are assumed to be of the same path style and / vs \ usage. Neither may be "". @@ -141,8 +131,8 @@ int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */ /foo is not a prefix of /foobar */ -static int -path_prefix_p_ (const char *path1, const char *path2, int len1) +int +path_prefix_p (const char *path1, const char *path2, int len1) { /* Handle case where PATH1 has trailing '/' and when it doesn't. */ if (len1 > 0 && SLASH_P (path1[len1 - 1])) @@ -182,7 +172,7 @@ pathmatch (const char *path1, const char *path2) #define isslash(c) ((c) == '/') -static int +int normalize_posix_path (const char *src, char *dst) { const char *src_start = src; @@ -211,11 +201,6 @@ normalize_posix_path (const char *src, char *dst) /* Two leading /'s? If so, preserve them. */ else if (isslash (src[1])) { - if (cygheap->root.length ()) - { - debug_printf ("ENOENT = normalize_posix_path (%s)", src); - return ENOENT; - } *dst++ = '/'; *dst++ = '/'; src += 2; @@ -226,12 +211,6 @@ normalize_posix_path (const char *src, char *dst) src = src_start + 1; } } - /* Exactly one leading slash. Absolute path. Check for chroot. */ - else if (cygheap->root.length ()) - { - strcpy (dst, cygheap->root.path ()); - dst += cygheap->root.length (); - } else *dst = '\0'; @@ -264,14 +243,6 @@ normalize_posix_path (const char *src, char *dst) } else if (src[2] && !isslash (src[2])) break; - else - { - if (!ischrootpath (dst_start) || - dst - dst_start != (int) cygheap->root.length ()) - while (dst > dst_start && !isslash (*--dst)) - continue; - src++; - } } *dst++ = '/'; @@ -442,7 +413,10 @@ 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); + unit, &sym.pflags, 1); + + if (error) + return; /* devn should not be a device. If it is, then stop parsing now. */ if (devn != FH_BAD) @@ -891,25 +865,9 @@ normalize_win32_path (const char *src, char *dst) if (beg_src_slash && isdirsep (src[1])) { - if (cygheap->root.length ()) - { - debug_printf ("ENOENT = normalize_win32_path (%s)", src); - return ENOENT; - } *dst++ = '\\'; ++src; } - /* If absolute path, care for chroot. */ - else if (beg_src_slash && cygheap->root.length ()) - { - strcpy (dst, cygheap->root.path ()); - char *c; - while ((c = strchr (dst, '/')) != NULL) - *c = '\\'; - dst += cygheap->root.length (); - dst_root_start = dst; - *dst++ = '\\'; - } else if (strchr (src, ':') == NULL && *src != '/') { if (!cygheap->cwd.get (dst, 0)) @@ -1127,7 +1085,8 @@ mount_info::init () int mount_info::conv_to_win32_path (const char *src_path, char *dst, - DWORD &devn, int &unit, unsigned *flags) + DWORD &devn, int &unit, unsigned *flags, + bool no_normalize) { while (sys_mount_table_counter < cygwin_shared->sys_mount_table_counter) { @@ -1137,6 +1096,7 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, int src_path_len = strlen (src_path); MALLOC_CHECK; unsigned dummy_flags; + int chroot_ok = !cygheap->root.exists (); devn = FH_BAD; unit = 0; @@ -1173,22 +1133,6 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, } *flags = set_flags_from_win32_path (dst); - if (cygheap->root.length () && dst[0] && dst[1] == ':') - { - char posix_path[MAX_PATH + 1]; - - rc = mount_table->conv_to_posix_path (dst, posix_path, 0); - if (rc) - { - debug_printf ("conv_to_posix_path failed, rc %d", rc); - return rc; - } - if (!ischrootpath (posix_path)) - { - debug_printf ("ischrootpath failed"); - return ENOENT; - } - } goto out; } @@ -1208,20 +1152,26 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, converting it to a DOS-style path, looking up the appropriate drive in the mount table. */ - rc = normalize_posix_path (src_path, pathbuf); - - if (rc) + if (no_normalize) + strcpy (pathbuf, src_path); + else { - debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path); - *flags = 0; - return rc; + rc = normalize_posix_path (src_path, pathbuf); + + if (rc) + { + debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path); + *flags = 0; + return rc; + } } /* See if this is a cygwin "device" */ if (win32_device_name (pathbuf, dst, devn, unit)) { *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */ - goto out; + rc = 0; + goto out_no_chroot_check; } /* Check if the cygdrive prefix was specified. If so, just strip @@ -1235,11 +1185,33 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, goto out; } + int chrooted_path_len; + chrooted_path_len = 0; /* Check the mount table for prefix matches. */ for (i = 0; i < nmounts; i++) { + const char *path; + int len; + mi = mount + posix_sorted[i]; - if (path_prefix_p (mi->posix_path, pathbuf, mi->posix_pathlen)) + if (!cygheap->root.exists () + || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/')) + { + path = mi->posix_path; + len = mi->posix_pathlen; + } + else if (cygheap->root.posix_ok (mi->posix_path)) + { + path = cygheap->root.unchroot (mi->posix_path); + chrooted_path_len = len = strlen (path); + } + else + { + chrooted_path_len = 0; + continue; + } + + if (path_prefix_p (path, pathbuf, len)) break; } @@ -1250,9 +1222,26 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, } else { - int n = mi->native_pathlen; - memcpy (dst, mi->native_path, n + 1); - char *p = pathbuf + mi->posix_pathlen; + int n; + const char *native_path; + int posix_pathlen; + if (chroot_ok || chrooted_path_len || mi->posix_pathlen != 1 + || mi->posix_path[0] != '/') + { + n = mi->native_pathlen; + native_path = mi->native_path; + posix_pathlen = chrooted_path_len ?: mi->posix_pathlen; + chroot_ok = 1; + } + else + { + n = cygheap->root.native_length (); + native_path = cygheap->root.native_path (); + posix_pathlen = mi->posix_pathlen; + chroot_ok = 1; + } + memcpy (dst, native_path, n + 1); + const char *p = pathbuf + posix_pathlen; if (*p == '/') /* nothing */; else if ((isdrive (dst) && !dst[2]) || *p) @@ -1262,10 +1251,20 @@ mount_info::conv_to_win32_path (const char *src_path, char *dst, *flags = mi->flags; } -out: + out: MALLOC_CHECK; - debug_printf ("src_path %s, dst %s, flags %p", src_path, dst, *flags); - return 0; + if (chroot_ok || cygheap->root.ischroot_native (dst)) + rc = 0; + else + { + debug_printf ("attempt to access outside of chroot '%s = %s'", + cygheap->root.posix_path (), cygheap->root.native_path ()); + rc = ENOENT; + } + + out_no_chroot_check: + debug_printf ("src_path %s, dst %s, flags %p, rc %d", src_path, dst, *flags, rc); + return rc; } /* cygdrive_posix_path: Build POSIX path used as the @@ -1370,6 +1369,9 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen)) continue; + if (cygheap->root.exists () && !cygheap->root.posix_ok (mi.posix_path)) + continue; + /* SRC_PATH is in the mount table. */ int nextchar; const char *p = pathbuf + mi.native_pathlen; @@ -1391,9 +1393,31 @@ mount_info::conv_to_posix_path (const char *src_path, char *posix_path, slashify (p, posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen), trailing_slash_p); + + if (cygheap->root.exists ()) + { + const char *p = cygheap->root.unchroot (posix_path); + memmove (posix_path, p, strlen (p) + 1); + } goto out; } + if (!cygheap->root.exists ()) + /* nothing */; + else if (cygheap->root.ischroot_native (pathbuf)) + { + const char *p = pathbuf + cygheap->root.native_length (); + if (*p) + slashify (p, posix_path, trailing_slash_p); + else + { + posix_path[0] = '/'; + posix_path[1] = '\0'; + } + } + else + return ENOENT; + /* Not in the database. This should [theoretically] only happen if either the path begins with //, or / isn't mounted, or the path has a drive letter not covered by the mount table. If it's a relative path then the @@ -3336,11 +3360,9 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen) if (!need_posix) tocopy = win32; else - tocopy = with_chroot && ischrootpath(posix) ? - posix + cygheap->root.length () : posix; + tocopy = posix; - debug_printf("cygheap->root: %s, posix: %s", - (const char *) cygheap->root.path (), posix); + debug_printf("posix %s", posix); if (strlen (tocopy) >= ulen) { set_errno (ERANGE); diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index cf61cbab8..40ddb9662 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -77,7 +77,7 @@ class mount_info unsigned set_flags_from_win32_path (const char *path); int conv_to_win32_path (const char *src_path, char *dst, DWORD &devn, - int &unit, unsigned *flags = NULL); + int &unit, unsigned *flags = NULL, bool no_normalize = 0); int conv_to_posix_path (const char *src_path, char *posix_path, int keep_rel_p); struct mntent *getmntent (int x); diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index 0a59e730b..f4fcb464c 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -38,6 +38,8 @@ details. */ #include "security.h" #include "cygheap.h" +extern int normalize_posix_path (const char *, char *); + SYSTEM_INFO system_info; /* Close all files and process any queued deletions. @@ -2195,19 +2197,14 @@ chroot (const char *newroot) set_errno (ENOENT); goto done; } - if (! (path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)) + if (!(path.file_attributes () & FILE_ATTRIBUTE_DIRECTORY)) { set_errno (ENOTDIR); goto done; } - char buf[MAX_PATH + 1]; - ret = mount_table->conv_to_posix_path (path.get_win32 (), buf, 0); - if (ret) - { - set_errno (ret); - goto done; - } - cygheap->root = buf; + char buf[MAX_PATH]; + normalize_posix_path (newroot, buf); + cygheap->root.set (buf, path); ret = 0; done: