From 520fcc974702602a1a3b246346e726492bad52e6 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 24 Jul 2008 18:25:52 +0000 Subject: [PATCH] * shared.cc (user_shared_initialize): Fetch potentially changed Cygwin username from /etc/passwd before loading mount table. (shared_info::init_installation_root): New function fetching Cygwin's installation root dir and storing as native NT path in global shared memory. (shared_info::initialize): Call init_installation_root exactly once at first startup. * shared_info.h (SHARED_INFO_CB): Accommodate change to shared_info. (CURR_SHARED_MAGIC): Ditto. (class shared_info): Add installation_root member. (shared_info::init_installation_root): Declare. * grp.cc (pwdgrp::read_group): Call pwdgrp::load with native WCHAR path. * passwd.cc (pwdgrp::read_passwd): Ditto. Avoid recursion. (etc::init): Take POBJECT_ATTRIBUTES instead of path_conv. * path.h (etc::init): Change prototype accordingly. * pwdgrp.h (class pwdgrp): Store path as UNICODE_STRING/PWCHAR instead of as path_conv. (pwdgrp::load): Accommodate prototype. * uinfo.cc (pwdgrp::load): Change argument type from char to wchar_t. Create native NT path here instead of calling path_conv. * mount.cc (find_root_from_cygwin_dll): Drop in favor of global initializaion in shared_info. (mount_info::init): Fetch native NT root dir from cygwin_shared. (mount_info::from_fstab): Expect native NT path and use native NT functions to access file. Convert username part in user fstab path according to special char transformation rules. * path.cc (tfx_chars): Convert slash to backslash. (transform_chars): Implement for path given as PWCHAR. (transform_chars): PUNICODE_STRING version calls PWCHAR version. Remove useless commented code. --- winsup/cygwin/ChangeLog | 35 ++++++++++++++++ winsup/cygwin/grp.cc | 2 +- winsup/cygwin/mount.cc | 83 +++++++++++++++++-------------------- winsup/cygwin/passwd.cc | 3 +- winsup/cygwin/path.cc | 32 +++++++------- winsup/cygwin/path.h | 2 +- winsup/cygwin/pwdgrp.h | 5 ++- winsup/cygwin/shared.cc | 53 +++++++++++++++++++++-- winsup/cygwin/shared_info.h | 7 +++- winsup/cygwin/uinfo.cc | 38 +++++++++-------- 10 files changed, 170 insertions(+), 90 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 8d8495380..4c844bebd 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,38 @@ +2008-07-24 Corinna Vinschen + + * shared.cc (user_shared_initialize): Fetch potentially changed Cygwin + username from /etc/passwd before loading mount table. + (shared_info::init_installation_root): New function fetching Cygwin's + installation root dir and storing as native NT path in global shared + memory. + (shared_info::initialize): Call init_installation_root exactly once at + first startup. + * shared_info.h (SHARED_INFO_CB): Accommodate change to shared_info. + (CURR_SHARED_MAGIC): Ditto. + (class shared_info): Add installation_root member. + (shared_info::init_installation_root): Declare. + + * grp.cc (pwdgrp::read_group): Call pwdgrp::load with native WCHAR path. + * passwd.cc (pwdgrp::read_passwd): Ditto. Avoid recursion. + (etc::init): Take POBJECT_ATTRIBUTES instead of path_conv. + * path.h (etc::init): Change prototype accordingly. + * pwdgrp.h (class pwdgrp): Store path as UNICODE_STRING/PWCHAR instead + of as path_conv. + (pwdgrp::load): Accommodate prototype. + * uinfo.cc (pwdgrp::load): Change argument type from char to wchar_t. + Create native NT path here instead of calling path_conv. + + * mount.cc (find_root_from_cygwin_dll): Drop in favor of global + initializaion in shared_info. + (mount_info::init): Fetch native NT root dir from cygwin_shared. + (mount_info::from_fstab): Expect native NT path and use native NT + functions to access file. Convert username part in user fstab path + according to special char transformation rules. + * path.cc (tfx_chars): Convert slash to backslash. + (transform_chars): Implement for path given as PWCHAR. + (transform_chars): PUNICODE_STRING version calls PWCHAR version. + Remove useless commented code. + 2008-07-22 Corinna Vinschen * spawn.cc (spawn_guts): Fix previous patch for UNC paths. diff --git a/winsup/cygwin/grp.cc b/winsup/cygwin/grp.cc index f38888e1b..a007ae657 100644 --- a/winsup/cygwin/grp.cc +++ b/winsup/cygwin/grp.cc @@ -72,7 +72,7 @@ pwdgrp::read_group () if ((*group_buf)[i].gr_mem != &null_ptr) free ((*group_buf)[i].gr_mem); - load ("/etc/group"); + load (L"\\etc\\group"); /* Complete /etc/group in memory if needed */ if (!internal_getgrgid (myself->gid)) diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index 7febd9016..4ef1f0fe2 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -72,32 +72,6 @@ win32_device_name (const char *src_path, char *win32_path, device& dev) return true; } -/* Use absolute path of cygwin1.dll to derive a "root". - Return false if GetModuleFileNameW fails or path is "funny". - Otherwise return true. */ -static inline PWCHAR -find_root_from_cygwin_dll (WCHAR *path) -{ - if (!GetModuleFileNameW (cygwin_hmodule, path, NT_MAX_PATH)) - { - debug_printf ("GetModuleFileNameW(%p, %p, %u), %E", cygwin_hmodule, path, NT_MAX_PATH); - return NULL; - } - PWCHAR w = wcsrchr (path, L'\\'); - if (w) - { - *w = L'\0'; - w = wcsrchr (path, L'\\'); - } - if (!w) - { - debug_printf ("Invalid DLL path"); - return NULL; - } - *w = L'\0'; - return w; -} - inline void mount_info::create_root_entry (const PWCHAR root) { @@ -121,14 +95,13 @@ mount_info::init () nmounts = 0; PWCHAR pathend; WCHAR path[NT_MAX_PATH]; - if ((pathend = find_root_from_cygwin_dll (path))) - { - create_root_entry (path); - pathend = wcpcpy (pathend, L"\\etc\\fstab"); - if (from_fstab (false, path, pathend) /* The single | is correct! */ - | from_fstab (true, path, pathend)) - return; - } + + pathend = wcpcpy (path, cygwin_shared->installation_root); + create_root_entry (path); + pathend = wcpcpy (pathend, L"\\etc\\fstab"); + if (from_fstab (false, path, pathend) /* The single | is correct! */ + | from_fstab (true, path, pathend)) + return; /* FIXME: Remove warning message before releasing 1.7.0. */ small_printf ("Huh? No /etc/fstab file? Using default root and cygdrive prefix...\n"); @@ -737,27 +710,45 @@ mount_info::from_fstab_line (char *line, bool user) bool mount_info::from_fstab (bool user, WCHAR fstab[], PWCHAR fstab_end) { + UNICODE_STRING upath; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE fh; + if (user) - sys_mbstowcs (wcpcpy (fstab_end, L".d\\"), - NT_MAX_PATH - (fstab_end - fstab), - cygheap->user.name ()); - debug_printf ("Try to read mounts from %W", fstab); - HANDLE h = CreateFileW (fstab, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (h == INVALID_HANDLE_VALUE) { - debug_printf ("CreateFileW, %E"); + extern void transform_chars (PWCHAR, PWCHAR); + PWCHAR username; + sys_mbstowcs (username = wcpcpy (fstab_end, L".d\\"), + NT_MAX_PATH - (fstab_end - fstab), + cygheap->user.name ()); + /* Make sure special chars in the username are converted according to + the rules. */ + transform_chars (username, username + wcslen (username) - 1); + } + RtlInitUnicodeString (&upath, fstab); + InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); + debug_printf ("Try to read mounts from %W", fstab); + status = NtOpenFile (&fh, SYNCHRONIZE | FILE_READ_DATA, &attr, &io, + FILE_SHARE_VALID_FLAGS, FILE_SYNCHRONOUS_IO_NONALERT); + if (!NT_SUCCESS (status)) + { + system_printf ("NtOpenFile(%S) failed, %p", &upath, status); return false; } + char buf[NT_MAX_PATH]; char *got = buf; DWORD len = 0; unsigned line = 1; /* Using buffer size - 2 leaves space to append two \0. */ - while (ReadFile (h, got, (sizeof (buf) - 2) - (got - buf), &len, NULL)) + while (NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, got, + (sizeof (buf) - 2) - (got - buf), NULL, NULL))) { char *end; + len = io.Information; /* Set end marker. */ got[len] = got[len + 1] = '\0'; /* Set len to the absolute len of bytes in buf. */ @@ -783,8 +774,10 @@ retry: if (!got_nl) { system_printf ("%W: Line %d too long, skipping...", fstab, line); - while (ReadFile (h, buf, (sizeof (buf) - 2), &len, NULL)) + while (NT_SUCCESS (NtReadFile (fh, NULL, NULL, NULL, &io, buf, + (sizeof (buf) - 2), NULL, NULL))) { + len = io.Information; buf[len] = buf[len + 1] = '\0'; got = strchr (buf, '\n'); if (got) @@ -809,7 +802,7 @@ retry: if (got > buf) from_fstab_line (got, user); done: - CloseHandle (h); + NtClose (fh); return true; } diff --git a/winsup/cygwin/passwd.cc b/winsup/cygwin/passwd.cc index 14d0cee5c..1773de507 100644 --- a/winsup/cygwin/passwd.cc +++ b/winsup/cygwin/passwd.cc @@ -51,7 +51,7 @@ pwdgrp::parse_passwd () void pwdgrp::read_passwd () { - load ("/etc/passwd"); + load (L"\\etc\\passwd"); char strbuf[128] = ""; bool searchentry = true; @@ -72,7 +72,6 @@ pwdgrp::read_passwd () { static char linebuf[1024]; // must be static and // should not be NO_COPY - cygheap->user.ontherange (CH_HOME, NULL); snprintf (linebuf, sizeof (linebuf), "%s:*:%lu:%lu:,%s:%s:/bin/sh", cygheap->user.name (), myself->uid == ILLEGAL_UID ? UNKNOWN_UID : myself->uid, diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index d550203ea..ae105491d 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -574,7 +574,7 @@ WCHAR tfx_chars[] NO_COPY = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, '!', 0xf000 | '"', '#', '$', '%', '&', 39, - '(', ')', 0xf000 | '*', '+', ',', '-', '.', '/', + '(', ')', 0xf000 | '*', '+', ',', '-', '.', '\\', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0xf000 | ':', ';', 0xf000 | '<', '=', 0xf000 | '>', 0xf000 | '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', @@ -587,22 +587,20 @@ WCHAR tfx_chars[] NO_COPY = { 'x', 'y', 'z', '{', 0xf000 | '|', '}', '~', 127 }; -static void +void +transform_chars (PWCHAR path, PWCHAR path_end) +{ + for (; path <= path_end; ++path) + if (*path < 128) + *path = tfx_chars[*path]; +} + +static inline +void transform_chars (PUNICODE_STRING upath, USHORT start_idx) { - register PWCHAR buf = upath->Buffer; - register PWCHAR end = buf + upath->Length / sizeof (WCHAR) - 1; - for (buf += start_idx; buf <= end; ++buf) - if (*buf < 128) - *buf = tfx_chars[*buf]; -#if 0 - /* Win32 can't handle trailing dots and spaces. Transform the last of them - to the private use area, too, to create a valid Win32 filename. */ - if (*end == L'\\') - --end; - if (*end == L'.' || *end == L' ') - *end |= 0xf000; -#endif + transform_chars (upath->Buffer + start_idx, + upath->Buffer + upath->Length / sizeof (WCHAR) - 1); } PUNICODE_STRING @@ -3391,7 +3389,7 @@ OBJECT_ATTRIBUTES etc::fn[MAX_ETC_FILES + 1]; LARGE_INTEGER etc::last_modified[MAX_ETC_FILES + 1]; int -etc::init (int n, path_conv &pc) +etc::init (int n, POBJECT_ATTRIBUTES attr) { if (n > 0) /* ok */; @@ -3400,7 +3398,7 @@ etc::init (int n, path_conv &pc) else api_fatal ("internal error"); - pc.get_object_attr (fn[n], sec_none_nih); + fn[n] = *attr; change_possible[n] = false; test_file_change (n); paranoid_printf ("fn[%d] %S, curr_ix %d", n, fn[n].ObjectName, curr_ix); diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 32c46a537..a9f0cc32f 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -350,7 +350,7 @@ class etc static OBJECT_ATTRIBUTES fn[MAX_ETC_FILES + 1]; static LARGE_INTEGER last_modified[MAX_ETC_FILES + 1]; static bool dir_changed (int); - static int init (int, path_conv &pc); + static int init (int, POBJECT_ATTRIBUTES); static bool file_changed (int); static bool test_file_change (int); friend class pwdgrp; diff --git a/winsup/cygwin/pwdgrp.h b/winsup/cygwin/pwdgrp.h index 94631c5e6..7db722c12 100644 --- a/winsup/cygwin/pwdgrp.h +++ b/winsup/cygwin/pwdgrp.h @@ -35,7 +35,8 @@ class pwdgrp void (pwdgrp::*read) (); bool (pwdgrp::*parse) (); int etc_ix; - path_conv pc; + UNICODE_STRING upath; + PWCHAR path; char *buf, *lptr; int max_lines; bool initialized; @@ -67,7 +68,7 @@ class pwdgrp public: int curr_lines; - void load (const char *); + void load (const wchar_t *); inline void refresh (bool check) { if (!check && initialized) diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc index 8f2537915..fca79e487 100644 --- a/winsup/cygwin/shared.cc +++ b/winsup/cygwin/shared.cc @@ -22,8 +22,10 @@ details. */ #include "shared_info_magic.h" #include "registry.h" #include "cygwin_version.h" +#include "pwdgrp.h" #include "ntdll.h" #include +#include shared_info NO_COPY *cygwin_shared; user_info NO_COPY *user_shared; @@ -225,7 +227,12 @@ user_shared_initialize (bool reinit) /* Initialize the Cygwin per-user shared, if necessary */ if (!sversion) { - debug_printf ("initializing user shared"); + cygpsid sid (cygheap->user.sid ()); + struct passwd *pw = internal_getpwsid (sid); + /* Correct the user name with what's defined in /etc/passwd before + loading the user fstab file. */ + if (pw) + cygheap->user.set_name (pw->pw_name); user_shared->mountinfo.init (); /* Initialize the mount table. */ user_shared->cb = sizeof (*user_shared); } @@ -240,6 +247,46 @@ user_shared_initialize (bool reinit) } } +/* Use absolute path of cygwin1.dll to derive the Win32 dir which + is our installation root. Note that we can't handle Cygwin installation + root dirs of more than 4K path length. I assume that's ok... */ +void +shared_info::init_installation_root () +{ + if (!GetModuleFileNameW (cygwin_hmodule, installation_root, PATH_MAX)) + api_fatal ("Can't initialize Cygwin installation root dir.\n" + "GetModuleFileNameW(%p, %p, %u), %E", + cygwin_hmodule, installation_root, PATH_MAX); + PWCHAR p = installation_root; + if (wcsncmp (p, L"\\\\?\\", 4)) /* No long path prefix. */ + { + if (!wcsncasecmp (p, L"\\\\", 2)) /* UNC */ + { + p = wcpcpy (p, L"\\??\\UN"); + GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 6); + *p = L'C'; + } + else + { + p = wcpcpy (p, L"\\??\\"); + GetModuleFileNameW (cygwin_hmodule, p, PATH_MAX - 4); + } + } + installation_root[1] = L'?'; + + PWCHAR w = wcsrchr (installation_root, L'\\'); + if (w) + { + *w = L'\0'; + w = wcsrchr (installation_root, L'\\'); + } + if (!w) + api_fatal ("Can't initialize Cygwin installation root dir.\n" + "Invalid DLL path"); + + *w = L'\0'; +} + /* Initialize obcaseinsensitive. Default to case insensitive on pre-XP. */ void shared_info::init_obcaseinsensitive () @@ -279,10 +326,10 @@ shared_info::initialize () if (!sversion) { - + init_installation_root ();/* Initialize installation root dir. */ + init_obcaseinsensitive ();/* Initialize obcaseinsensitive. */ tty.init (); /* Initialize tty table. */ mt.initialize (); /* Initialize shared tape information. */ - init_obcaseinsensitive ();/* Initialize obcaseinsensitive. */ cb = sizeof (*this); /* Do last, after all shared memory initialization */ } diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h index 3b0036286..684a84a66 100644 --- a/winsup/cygwin/shared_info.h +++ b/winsup/cygwin/shared_info.h @@ -11,6 +11,7 @@ details. */ #include "tty.h" #include "security.h" #include "mtinfo.h" +#include "limits.h" /* Mount table entry */ @@ -117,9 +118,9 @@ public: cygwin_version.api_minor) #define SHARED_VERSION_MAGIC CYGWIN_VERSION_MAGIC (SHARED_MAGIC, SHARED_VERSION) -#define SHARED_INFO_CB 31136 +#define SHARED_INFO_CB 39328 -#define CURR_SHARED_MAGIC 0x18da899eU +#define CURR_SHARED_MAGIC 0x22f9ff0bU /* NOTE: Do not make gratuitous changes to the names or organization of the below class. The layout is checksummed to determine compatibility between @@ -135,10 +136,12 @@ class shared_info DWORD sys_mount_table_counter; tty_list tty; LONG last_used_bindresvport; + WCHAR installation_root[PATH_MAX]; DWORD obcaseinsensitive; mtinfo mt; void initialize (); + void init_installation_root (); void init_obcaseinsensitive (); unsigned heap_chunk_size (); unsigned heap_slop_size (); diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index cc8beeb23..9d7a5cef0 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -13,6 +13,7 @@ details. */ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ details. */ #include "fhandler.h" #include "dtable.h" #include "cygheap.h" +#include "shared_info.h" #include "registry.h" #include "child_info.h" #include "environ.h" @@ -508,7 +510,7 @@ pwdgrp::add_line (char *eptr) } void -pwdgrp::load (const char *posix_fname) +pwdgrp::load (const wchar_t *rel_path) { static const char failed[] = "failed"; static const char succeeded[] = "succeeded"; @@ -526,23 +528,26 @@ pwdgrp::load (const char *posix_fname) buf = NULL; curr_lines = 0; - pc.check (posix_fname); - etc_ix = etc::init (etc_ix, pc); - - paranoid_printf ("%s", posix_fname); - - if (pc.error || !pc.exists () || pc.isdir ()) + if (!path && + !(path = (PWCHAR) malloc ((wcslen (cygwin_shared->installation_root) + + wcslen (rel_path) + 1) * sizeof (WCHAR)))) { - paranoid_printf ("strange path_conv problem"); + paranoid_printf ("malloc (%W) failed", rel_path); goto out; } - status = NtOpenFile (&fh, FILE_READ_DATA, - pc.get_object_attr (attr, sec_none_nih), &io, + wcpcpy (wcpcpy (path, cygwin_shared->installation_root), rel_path); + RtlInitUnicodeString (&upath, path); + + InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); + etc_ix = etc::init (etc_ix, &attr); + + paranoid_printf ("%S", &upath); + + status = NtOpenFile (&fh, FILE_READ_DATA, &attr, &io, FILE_SHARE_VALID_FLAGS, 0); if (!NT_SUCCESS (status)) { - paranoid_printf ("NtOpenFile(%S) failed, status %p", - pc.get_nt_native_path (), status); + paranoid_printf ("NtOpenFile(%S) failed, status %p", &upath, status); goto out; } status = NtQueryInformationFile (fh, &io, &fsi, sizeof fsi, @@ -550,7 +555,7 @@ pwdgrp::load (const char *posix_fname) if (!NT_SUCCESS (status)) { paranoid_printf ("NtQueryInformationFile(%S) failed, status %p", - pc.get_nt_native_path (), status); + &upath, status); goto out; } /* FIXME: Should we test for HighPart set? If so, the @@ -567,8 +572,7 @@ pwdgrp::load (const char *posix_fname) fsi.EndOfFile.LowPart, &off, NULL); if (!NT_SUCCESS (status)) { - paranoid_printf ("NtReadFile(%S) failed, status %p", - pc.get_nt_native_path (), status); + paranoid_printf ("NtReadFile(%S) failed, status %p", &upath, status); free (buf); goto out; } @@ -576,12 +580,12 @@ pwdgrp::load (const char *posix_fname) char *eptr = buf; while ((eptr = add_line (eptr))) continue; - debug_printf ("%s curr_lines %d", posix_fname, curr_lines); + debug_printf ("%W curr_lines %d", rel_path, curr_lines); res = succeeded; out: if (fh) NtClose (fh); - debug_printf ("%s load %s", posix_fname, res); + debug_printf ("%W load %s", rel_path, res); initialized = true; }