diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index d0be7942b..85ffa11f7 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,61 @@ +2008-03-12 Corinna Vinschen + + * winsup.h (NT_MAX_PATH): Revert ill-advised change to 32767. + Accommodate change throughout. + + * cygwin.din (cygwin_conv_path): Export. + (cygwin_conv_path_list): Export. + (cygwin_create_path): Export. + * dcrt0.cc (dll_crt0_1): Use cygwin_conv_path. + * dtable.cc (handle_to_fn): Ditto. Don't expect UNICODE_STRING being + 0-terminated. + * environ.cc (env_plist_to_posix): New helper function. + (env_plist_to_win32): Ditto. + (env_path_to_posix): Ditto. + (env_path_to_win32): Ditto. + (return_MAX_PATH): Remove. + (conv_envvars): Use new helper functions. Drop removed members. + (win_env::operator =): Accommodate removal of path length functions. + (win_env::add_cache): Accommodate new env helper function API. + (posify): Ditto. + * environ.h (struct win_env): Ditto. Remove path length function + pointers since they are unused. + * path.cc (warn_msdos): Use cygwin_conv_path. + (getfileattr): Use new tmp_pathbuf::u_get method. + (fillout_mntent): Ditto. + (symlink_info::check): Ditto. + (path_conv::check): Use sizeof (WCHAR) instead of constant 2. + (symlink_info::check_reparse_point): Ditto. + (conv_path_list): Get max size of target string as argument. Call + cygwin_conv_path as helper function. + (cygwin_conv_path): New function. + (cygwin_create_path): New function. + (cygwin_conv_to_win32_path): Just call cygwin_conv_path with size set + to MAX_PATH. + (cygwin_conv_to_full_win32_path): Ditto. + (cygwin_conv_to_posix_path): Ditto. + (cygwin_conv_to_full_posix_path): Ditto. + (conv_path_list_buf_size): Add FIXME comment. + (env_PATH_to_posix): Rename from env_win32_to_posix_path_list. + Add size argument as required for env helper functions. + (cygwin_win32_to_posix_path_list): Call conv_path_list with size set to + MAX_PATH. + (cygwin_posix_to_win32_path_list): Ditto. + (cygwin_conv_path_list): New function. + (cwdstuff::get): Fix length argument in call to sys_wcstombs. + * spawn.cc (find_exec): Use cygwin_conv_path_list. + * tls_pbuf.h (tmp_pathbuf::u_get: New method. + * uinfo.cc (cygheap_user::ontherange): Allocate temporary path buffers + using tmp_pathbuf. Use cygwin_conv_path. + * winf.cc (av::unshift): Use cygwin_conv_path. + * include/cygwin/version.h: Bump API minor number. + * include/sys/cygwin.h: Comment out old cygwin32_XXX API. + Mark old path handling API as deprecated. + (cygwin_conv_path_t): Typedef. Define values. + (cygwin_conv_path): Declare. + (cygwin_create_path): Declare. + (cygwin_conv_path_list): Declare. + 2008-03-11 Corinna Vinschen * dlfcn.cc (get_full_path_of_dll): Allow paths up to PATH_MAX. diff --git a/winsup/cygwin/cygtls.cc b/winsup/cygwin/cygtls.cc index 749af0158..8769a6a1b 100644 --- a/winsup/cygwin/cygtls.cc +++ b/winsup/cygwin/cygtls.cc @@ -249,18 +249,6 @@ _cygtls::init_exception_handler (exception_handler *eh) Windows 2008, which irremediably gets into an endless loop, taking 100% CPU. That's why we reverted to a normal SEH chain and changed the way the exception handler returns to the application. */ - /* 2008-03-28 - The fun continues. Revert to doing something sorta like - before. Just make sure *only* the cygwin exception handler is installed - rather than honoring other exception handlers. The theory here is that - cygwin should be in control and there should be no Windows voodoo going - on behind the scenes. - - This change was made so that this function could be called from - handle_exceptions to essentially "clean up" the exception handling - linked list. - - The open question is whether making this NULL will have an adverse effect - on Windows functions. */ + el.prev = _except_list; _except_list = ⪙ - el.prev = NULL; } diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index da6b986dd..c57629cd9 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -237,10 +237,13 @@ cygwin32_win32_to_posix_path_list = cygwin_win32_to_posix_path_list SIGFE cygwin32_win32_to_posix_path_list_buf_size = cygwin_win32_to_posix_path_list_buf_size SIGFE cygwin32_winpid_to_pid = cygwin_winpid_to_pid SIGFE cygwin_attach_handle_to_fd SIGFE +cygwin_conv_path SIGFE +cygwin_conv_path_list SIGFE cygwin_conv_to_full_posix_path SIGFE cygwin_conv_to_full_win32_path SIGFE cygwin_conv_to_posix_path SIGFE cygwin_conv_to_win32_path SIGFE +cygwin_create_path SIGFE cygwin_detach_dll SIGFE_MAYBE cygwin_dll_init NOSIGFE cygwin_internal NOSIGFE diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc index 7468fe04b..ac42aaa3b 100644 --- a/winsup/cygwin/dcrt0.cc +++ b/winsup/cygwin/dcrt0.cc @@ -859,7 +859,8 @@ dll_crt0_1 (void *) if ((strchr (__argv[0], ':')) || (strchr (__argv[0], '\\'))) { char *new_argv0 = (char *) malloc (NT_MAX_PATH); - cygwin_conv_to_posix_path (__argv[0], new_argv0); + cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, __argv[0], + new_argv0, NT_MAX_PATH); __argv[0] = (char *) realloc (new_argv0, strlen (new_argv0) + 1); } } diff --git a/winsup/cygwin/dtable.cc b/winsup/cygwin/dtable.cc index 7cf4136f6..f1eb20fd3 100644 --- a/winsup/cygwin/dtable.cc +++ b/winsup/cygwin/dtable.cc @@ -854,7 +854,7 @@ handle_to_fn (HANDLE h, char *posix_fn) memset (fnbuf, 0, len); ntfn = (OBJECT_NAME_INFORMATION *) fnbuf; - ntfn->Name.MaximumLength = NT_MAX_PATH * sizeof (WCHAR); + ntfn->Name.MaximumLength = (NT_MAX_PATH - 1) * sizeof (WCHAR); ntfn->Name.Buffer = (WCHAR *) (ntfn + 1); NTSTATUS res = NtQueryObject (h, ObjectNameInformation, ntfn, len, NULL); @@ -876,7 +876,8 @@ handle_to_fn (HANDLE h, char *posix_fn) ntfn->Name.Buffer[ntfn->Name.Length / sizeof (WCHAR)] = 0; char *win32_fn = tp.c_get (); - sys_wcstombs (win32_fn, NT_MAX_PATH, ntfn->Name.Buffer); + sys_wcstombs (win32_fn, NT_MAX_PATH, ntfn->Name.Buffer, + ntfn->Name.Length / sizeof (WCHAR)); debug_printf ("nt name '%s'", win32_fn); if (!strncasematch (win32_fn, DEVICE_PREFIX, DEVICE_PREFIX_LEN) || !QueryDosDevice (NULL, fnbuf, len)) @@ -947,7 +948,8 @@ handle_to_fn (HANDLE h, char *posix_fn) } if (!justslash) - cygwin_conv_to_full_posix_path (w32, posix_fn); + cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, w32, posix_fn, + NT_MAX_PATH); else { char *s, *d; diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 76c6820fb..514aa5c54 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -47,7 +47,37 @@ extern bool allow_server; static char **lastenviron; -extern "C" int env_win32_to_posix_path_list (const char *, char *posix); +/* Helper functions for the below environment variables which have to + be converted Win32<->POSIX. */ +extern "C" ssize_t env_PATH_to_posix (const void *, void *, size_t); + +ssize_t +env_plist_to_posix (const void *win32, void *posix, size_t size) +{ + return cygwin_conv_path_list (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, win32, + posix, size); +} + +ssize_t +env_plist_to_win32 (const void *posix, void *win32, size_t size) +{ + return cygwin_conv_path_list (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, posix, + win32, size); +} + +ssize_t +env_path_to_posix (const void *win32, void *posix, size_t size) +{ + return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, win32, + posix, size); +} + +ssize_t +env_path_to_win32 (const void *posix, void *win32, size_t size) +{ + return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, posix, + win32, size); +} #define ENVMALLOC \ (CYGWIN_VERSION_DLL_MAKE_COMBINED (user_data->api_major, user_data->api_minor) \ @@ -60,26 +90,16 @@ extern "C" int env_win32_to_posix_path_list (const char *, char *posix); PATH needs to be here because CreateProcess uses it and gdb uses CreateProcess. HOME is here because most shells use it and would be confused by Windows style path names. */ -static int return_MAX_PATH (const char *) {return CYG_MAX_PATH;} static win_env conv_envvars[] = { - {NL ("PATH="), NULL, NULL, env_win32_to_posix_path_list, - cygwin_posix_to_win32_path_list, - cygwin_win32_to_posix_path_list_buf_size, - cygwin_posix_to_win32_path_list_buf_size, true}, - {NL ("HOME="), NULL, NULL, cygwin_conv_to_full_posix_path, - cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH, false}, - {NL ("LD_LIBRARY_PATH="), NULL, NULL, cygwin_win32_to_posix_path_list, - cygwin_posix_to_win32_path_list, - cygwin_win32_to_posix_path_list_buf_size, - cygwin_posix_to_win32_path_list_buf_size, true}, - {NL ("TMPDIR="), NULL, NULL, cygwin_conv_to_full_posix_path, - cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH, false}, - {NL ("TMP="), NULL, NULL, cygwin_conv_to_full_posix_path, - cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH, false}, - {NL ("TEMP="), NULL, NULL, cygwin_conv_to_full_posix_path, - cygwin_conv_to_full_win32_path, return_MAX_PATH, return_MAX_PATH, false}, - {NULL, 0, NULL, NULL, NULL, NULL, 0, 0} + {NL ("PATH="), NULL, NULL, env_PATH_to_posix, env_plist_to_win32, true}, + {NL ("HOME="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, + {NL ("LD_LIBRARY_PATH="), NULL, NULL, + env_plist_to_posix, env_plist_to_win32, true}, + {NL ("TMPDIR="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, + {NL ("TMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, + {NL ("TEMP="), NULL, NULL, env_path_to_posix, env_path_to_win32, false}, + {NULL, 0, NULL, NULL, 0, 0} }; static unsigned char conv_start_chars[256] = {0}; @@ -91,8 +111,6 @@ win_env::operator = (struct win_env& x) namelen = x.namelen; toposix = x.toposix; towin32 = x.towin32; - posix_len = x.posix_len; - win32_len = x.win32_len; immediate = false; return *this; } @@ -122,7 +140,7 @@ win_env::add_cache (const char *in_posix, const char *in_native) tmp_pathbuf tp; char *buf = tp.c_get (); strcpy (buf, name + namelen); - towin32 (in_posix, buf); + towin32 (in_posix, buf, NT_MAX_PATH); native = (char *) realloc (native, namelen + 1 + strlen (buf)); strcpy (native, name); strcpy (native + namelen, buf); @@ -191,14 +209,15 @@ posify (char **here, const char *value, char *outenv) memcpy (outenv, src, len); char *newvalue = outenv + len; - if (!conv->toposix (value, newvalue) || _impure_ptr->_errno != EIDRM) + if (!conv->toposix (value, newvalue, NT_MAX_PATH - len) + || _impure_ptr->_errno != EIDRM) conv->add_cache (newvalue, *value != '/' ? value : NULL); else { /* The conversion routine removed elements from a path list so we have to recalculate the windows path to remove elements there, too. */ char cleanvalue[strlen (value) + 1]; - conv->towin32 (newvalue, cleanvalue); + conv->towin32 (newvalue, cleanvalue, sizeof cleanvalue); conv->add_cache (newvalue, cleanvalue); } diff --git a/winsup/cygwin/environ.h b/winsup/cygwin/environ.h index c2c29cf9a..a50ef5bad 100644 --- a/winsup/cygwin/environ.h +++ b/winsup/cygwin/environ.h @@ -23,10 +23,8 @@ struct win_env size_t namelen; char *posix; char *native; - int (*toposix) (const char *, char *); - int (*towin32) (const char *, char *); - int (*posix_len) (const char *); - int (*win32_len) (const char *); + ssize_t (*toposix) (const void *, void *, size_t); + ssize_t (*towin32) (const void *, void *, size_t); bool immediate; void add_cache (const char *in_posix, const char *in_native = NULL) __attribute__ ((regparm (3))); diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index 71c15d5f7..6eb17153a 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -470,6 +470,8 @@ rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e) /* Main exception handler. */ +extern exception_list *_except_list asm ("%fs:0"); + extern "C" char *__progname; int _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *) @@ -623,9 +625,10 @@ _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT me.copy_context (in); - /* Reinitialize exception handler list to include just ourselves so that any - exceptions that occur in a signal handler will be properly caught. */ - me.init_exception_handler (handle_exceptions); + /* Temporarily replace windows top level SEH with our own handler. + We don't want any Windows magic kicking in. This top level frame + will be removed automatically after our exception handler returns. */ + _except_list->handler = _cygtls::handle_exceptions; if (masked || &me == _sig_tls @@ -634,7 +637,6 @@ _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR) { - rtl_unwind (frame, e); /* Print the exception to the console */ if (!myself->cygstarted) for (int i = 0; status_info[i].name; i++) @@ -656,6 +658,7 @@ _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT return 0; } + rtl_unwind (frame, e); open_stackdumpfile (); exception (e, in); stackdump ((DWORD) ebp, 0, 1); diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index da6f3ceae..afad4beba 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -323,12 +323,13 @@ details. */ 180: Export getxattr, lgetxattr, fgetxattr, listxattr, llistxattr, flistxattr, setxattr, lsetxattr, fsetxattr, removexattr, lremovexattr, fremovexattr. + 181: Export cygwin_conv_path, cygwin_create_path, cygwin_conv_path_list. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 180 +#define CYGWIN_VERSION_API_MINOR 181 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/cygwin.h b/winsup/cygwin/include/sys/cygwin.h index 51247e54a..26daf0f7c 100644 --- a/winsup/cygwin/include/sys/cygwin.h +++ b/winsup/cygwin/include/sys/cygwin.h @@ -20,6 +20,7 @@ extern "C" { #define _CYGWIN_SIGNAL_STRING "cYgSiGw00f" +#if 0 /* ENTIRELY DEPRECATED INTERFACES. */ extern pid_t cygwin32_winpid_to_pid (int); extern void cygwin32_win32_to_posix_path_list (const char *, char *); extern int cygwin32_win32_to_posix_path_list_buf_size (const char *); @@ -31,16 +32,64 @@ extern void cygwin32_conv_to_posix_path (const char *, char *); extern void cygwin32_conv_to_full_posix_path (const char *, char *); extern int cygwin32_posix_path_list_p (const char *); extern void cygwin32_split_path (const char *, char *, char *); +#endif + +/* DEPRECATED INTERFACES. These are restricted to MAX_PATH length. + Don't use in modern applications. */ +extern int cygwin_win32_to_posix_path_list (const char *, char *) + __attribute__ ((deprecated)); +extern int cygwin_win32_to_posix_path_list_buf_size (const char *) + __attribute__ ((deprecated)); +extern int cygwin_posix_to_win32_path_list (const char *, char *) + __attribute__ ((deprecated)); +extern int cygwin_posix_to_win32_path_list_buf_size (const char *) + __attribute__ ((deprecated)); +extern int cygwin_conv_to_win32_path (const char *, char *) + __attribute__ ((deprecated)); +extern int cygwin_conv_to_full_win32_path (const char *, char *) + __attribute__ ((deprecated)); +extern int cygwin_conv_to_posix_path (const char *, char *) + __attribute__ ((deprecated)); +extern int cygwin_conv_to_full_posix_path (const char *, char *) + __attribute__ ((deprecated)); + +/* Use these interfaces in favor of the above. */ + +/* Possible 'what' values in calls to cygwin_conv_path/cygwin_create_path. */ +enum +{ + CCP_POSIX_TO_WIN_A = 0, /* from is char*, to is char* */ + CCP_POSIX_TO_WIN_W, /* from is char*, to is wchar_t* */ + CCP_WIN_A_TO_POSIX, /* from is char*, to is char* */ + CCP_WIN_W_TO_POSIX, /* from is wchar_t*, to is char* */ + + /* Or these values to the above as needed. */ + CCP_ABSOLUTE = 0, /* Request absolute path (default). */ + CCP_RELATIVE = 0x100 /* Request to keep path relative. */ +}; +typedef unsigned int cygwin_conv_path_t; + +/* If size is 0, cygwin_conv_path returns the required buffer size in bytes. + Otherwise, it returns 0 on success, or -1 on error and errno is set to + one of the below values: + + EINVAL what has an invalid value. + EFAULT from or to point into nirvana. + ENAMETOOLONG the resulting path is longer than 32K, or, in case + of what == CCP_POSIX_TO_WIN_A, longer than MAX_PATH. + ENOSPC size is less than required for the conversion. +*/ +extern ssize_t cygwin_conv_path (cygwin_conv_path_t what, const void *from, + void *to, size_t size); +/* Same, but handles path lists separated by colon or semicolon. */ +extern ssize_t cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, + void *to, size_t size); +/* Allocate a buffer for the conversion result using malloc(3), and return + a pointer to it. Returns NULL if something goes wrong with errno set + to one of the above values, or to ENOMEM if malloc fails. */ +extern void *cygwin_create_path (cygwin_conv_path_t what, const void *from); extern pid_t cygwin_winpid_to_pid (int); -extern int cygwin_win32_to_posix_path_list (const char *, char *); -extern int cygwin_win32_to_posix_path_list_buf_size (const char *); -extern int cygwin_posix_to_win32_path_list (const char *, char *); -extern int cygwin_posix_to_win32_path_list_buf_size (const char *); -extern int cygwin_conv_to_win32_path (const char *, char *); -extern int cygwin_conv_to_full_win32_path (const char *, char *); -extern int cygwin_conv_to_posix_path (const char *, char *); -extern int cygwin_conv_to_full_posix_path (const char *, char *); extern int cygwin_posix_path_list_p (const char *); extern void cygwin_split_path (const char *, char *, char *); diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 1ddf9cda0..af6b06c59 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -652,7 +652,8 @@ warn_msdos (const char *src) tmp_pathbuf tp; char *posix_path = tp.c_get (); small_printf ("cygwin warning:\n"); - if (cygwin_conv_to_full_posix_path (src, posix_path)) + if (cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, src, + posix_path, NT_MAX_PATH)) small_printf (" MS-DOS style path detected: %s\n POSIX equivalent preferred.\n", src); else @@ -661,7 +662,6 @@ warn_msdos (const char *src) small_printf (" CYGWIN environment variable option \"nodosfilewarning\" turns off this warning.\n" " Consult the user's guide for more details about POSIX paths:\n" " http://cygwin.com/cygwin-ug-net/using.html#using-pathnames\n"); - user_shared->warned_msdos = true; } @@ -675,7 +675,7 @@ getfileattr (const char *path) /* path has to be always absolute. */ NTSTATUS status; IO_STATUS_BLOCK io; - RtlInitEmptyUnicodeString (&upath, tp.w_get (), NT_MAX_PATH * sizeof (WCHAR)); + tp.u_get (&upath); InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); get_nt_native_path (path, upath); @@ -742,7 +742,7 @@ path_conv::check (PUNICODE_STRING src, unsigned opt, char *path = tp.c_get (); user_shared->warned_msdos = true; - sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / 2); + sys_wcstombs (path, NT_MAX_PATH, src->Buffer, src->Length / sizeof (WCHAR)); path_conv::check (path, opt, suffixes); } @@ -1504,22 +1504,22 @@ nofinalslash (const char *src, char *dst) /* conv_path_list: Convert a list of path names to/from Win32/POSIX. */ static int -conv_path_list (const char *src, char *dst, int to_posix) +conv_path_list (const char *src, char *dst, size_t size, int to_posix) { char src_delim, dst_delim; - int (*conv_fn) (const char *, char *); + cygwin_conv_path_t conv_fn; if (to_posix) { src_delim = ';'; dst_delim = ':'; - conv_fn = cygwin_conv_to_posix_path; + conv_fn = CCP_WIN_A_TO_POSIX | CCP_RELATIVE; } else { src_delim = ':'; dst_delim = ';'; - conv_fn = cygwin_conv_to_win32_path; + conv_fn = CCP_POSIX_TO_WIN_A | CCP_RELATIVE; } char *srcbuf = (char *) alloca (strlen (src) + 1); @@ -1530,16 +1530,22 @@ conv_path_list (const char *src, char *dst, int to_posix) do { char *s = strccpy (srcbuf, &src, src_delim); - int len = s - srcbuf; + size_t len = s - srcbuf; if (len >= NT_MAX_PATH) { err = ENAMETOOLONG; break; } if (len) - err = conv_fn (srcbuf, ++d); + { + ++d; + err = cygwin_conv_path (conv_fn, srcbuf, d, size - (d - dst)); + } else if (!to_posix) - err = conv_fn (".", ++d); + { + ++d; + err = cygwin_conv_path (conv_fn, ".", d, size - (d - dst)); + } else { if (to_posix == ENV_CVT) @@ -2767,7 +2773,7 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) fs_info mntinfo; tmp_pathbuf tp; UNICODE_STRING unat; - RtlInitEmptyUnicodeString (&unat, tp.w_get (), NT_MAX_PATH * sizeof (WCHAR)); + tp.u_get (&unat); get_nt_native_path (native_path, unat); if (append_bs) RtlAppendUnicodeToString (&unat, L"\\"); @@ -3431,7 +3437,7 @@ symlink_info::check_reparse_point (HANDLE h) sys_wcstombs (srcbuf, SYMLINK_MAX + 1, (WCHAR *)((char *)rp->SymbolicLinkReparseBuffer.PathBuffer + rp->SymbolicLinkReparseBuffer.SubstituteNameOffset), - rp->SymbolicLinkReparseBuffer.SubstituteNameLength / 2); + rp->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof (WCHAR)); pflags = PATH_SYMLINK | PATH_REP; fileattr &= ~FILE_ATTRIBUTE_DIRECTORY; } @@ -3445,7 +3451,7 @@ symlink_info::check_reparse_point (HANDLE h) sys_wcstombs (srcbuf, SYMLINK_MAX + 1, (WCHAR *)((char *)rp->MountPointReparseBuffer.PathBuffer + rp->MountPointReparseBuffer.SubstituteNameOffset), - rp->MountPointReparseBuffer.SubstituteNameLength / 2); + rp->MountPointReparseBuffer.SubstituteNameLength / sizeof (WCHAR)); pflags = PATH_SYMLINK | PATH_REP; fileattr &= ~FILE_ATTRIBUTE_DIRECTORY; } @@ -3724,7 +3730,7 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) tmp_pathbuf tp; UNICODE_STRING upath; OBJECT_ATTRIBUTES attr; - RtlInitEmptyUnicodeString (&upath, tp.w_get (), NT_MAX_PATH * sizeof (WCHAR)); + tp.u_get (&upath); InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL); while (suffix.next ()) @@ -4154,36 +4160,114 @@ fchdir (int fd) return -1;\ } while (0) +extern "C" ssize_t +cygwin_conv_path (cygwin_conv_path_t what, const void *from, void *to, + size_t size) +{ + myfault efault; + if (efault.faulted (EFAULT)) + return -1; + + path_conv p; + tmp_pathbuf tp; + size_t lsiz = 0; + char *buf = NULL; + int error = 0; + bool relative = !!(what & CCP_RELATIVE); + what &= ~CCP_RELATIVE; + + switch (what) + { + case CCP_POSIX_TO_WIN_A: + p.check ((const char *) from, + PC_POSIX | PC_SYM_FOLLOW | PC_NO_ACCESS_CHECK | PC_NOWARN + | (relative ? PC_NOFULL : 0)); + if (p.error) + return_with_errno (p.error); + PUNICODE_STRING up = p.get_nt_native_path (); + buf = tp.c_get (); + sys_wcstombs (buf, NT_MAX_PATH, up->Buffer, up->Length / sizeof (WCHAR)); + buf += 4; /* Skip \??\ */ + if (ascii_strncasematch (buf, "UNC\\", 4)) + *(buf += 2) = '\\'; + lsiz = strlen (buf) + 1; + break; + case CCP_POSIX_TO_WIN_W: + p.check ((const char *) from, + PC_POSIX | PC_SYM_FOLLOW | PC_NO_ACCESS_CHECK | PC_NOWARN + | (relative ? PC_NOFULL : 0)); + if (p.error) + return_with_errno (p.error); + lsiz = (p.get_wide_win32_path_len () + 1) * sizeof (WCHAR); + break; + case CCP_WIN_A_TO_POSIX: + buf = tp.c_get (); + error = mount_table->conv_to_posix_path ((const char *) from, buf, + relative); + if (error) + return_with_errno (error); + lsiz = strlen (buf) + 1; + break; + case CCP_WIN_W_TO_POSIX: + buf = tp.c_get (); + error = mount_table->conv_to_posix_path ((const PWCHAR) from, buf, + relative); + if (error) + return_with_errno (error); + lsiz = strlen (buf) + 1; + break; + default: + set_errno (EINVAL); + return -1; + } + if (!size) + return lsiz; + if (size < lsiz) + { + set_errno (ENOSPC); + return -1; + } + switch (what) + { + case CCP_POSIX_TO_WIN_A: + case CCP_WIN_A_TO_POSIX: + case CCP_WIN_W_TO_POSIX: + strcpy ((char *) to, buf); + break; + case CCP_POSIX_TO_WIN_W: + p.get_wide_win32_path ((PWCHAR) to); + break; + } + return 0; +} + +extern "C" void * +cygwin_create_path (cygwin_conv_path_t what, const void *from) +{ + void *to; + ssize_t size = cygwin_conv_path (what, from, NULL, 0); + if (size <= 0) + return NULL; + if (!(to = malloc (size))) + return NULL; + if (cygwin_conv_path (what, from, to, size) == -1) + return NULL; + return to; +} + + extern "C" int cygwin_conv_to_win32_path (const char *path, char *win32_path) { - path_conv p (path, PC_SYM_FOLLOW | PC_NO_ACCESS_CHECK | PC_NOFULL | PC_NOWARN); - if (p.error) - { - win32_path[0] = '\0'; - set_errno (p.error); - return -1; - } - - - strcpy (win32_path, - strcmp (p.get_win32 (), ".\\") == 0 ? "." : p.get_win32 ()); - return 0; + return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_RELATIVE, path, win32_path, + MAX_PATH); } extern "C" int cygwin_conv_to_full_win32_path (const char *path, char *win32_path) { - path_conv p (path, PC_SYM_FOLLOW | PC_NO_ACCESS_CHECK | PC_NOWARN); - if (p.error) - { - win32_path[0] = '\0'; - set_errno (p.error); - return -1; - } - - strcpy (win32_path, p.get_win32 ()); - return 0; + return cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, path, win32_path, + MAX_PATH); } /* This is exported to the world as cygwin_foo by cygwin.din. */ @@ -4191,29 +4275,15 @@ cygwin_conv_to_full_win32_path (const char *path, char *win32_path) extern "C" int cygwin_conv_to_posix_path (const char *path, char *posix_path) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!*path) - { - set_errno (ENOENT); - return -1; - } - return_with_errno (mount_table->conv_to_posix_path (path, posix_path, 1)); + return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, path, posix_path, + MAX_PATH); } extern "C" int cygwin_conv_to_full_posix_path (const char *path, char *posix_path) { - myfault efault; - if (efault.faulted (EFAULT)) - return -1; - if (!*path) - { - set_errno (ENOENT); - return -1; - } - return_with_errno (mount_table->conv_to_posix_path (path, posix_path, 0)); + return cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, path, posix_path, + MAX_PATH); } /* The realpath function is supported on some UNIX systems. */ @@ -4322,6 +4392,7 @@ conv_path_list_buf_size (const char *path_list, bool to_posix) path_conv pc(".", PC_POSIX); /* The theory is that an upper bound is current_size + (num_elms * max_mount_path_len) */ + /* FIXME: This method is questionable in the long run. */ unsigned nrel; char delim = to_posix ? ';' : ':'; @@ -4365,22 +4436,51 @@ cygwin_posix_to_win32_path_list_buf_size (const char *path_list) return conv_path_list_buf_size (path_list, false); } -extern "C" int -env_win32_to_posix_path_list (const char *win32, char *posix) +extern "C" ssize_t +env_PATH_to_posix (const void *win32, void *posix, size_t size) { - return_with_errno (conv_path_list (win32, posix, ENV_CVT)); + return_with_errno (conv_path_list ((const char *) win32, (char *) posix, + size, ENV_CVT)); } extern "C" int cygwin_win32_to_posix_path_list (const char *win32, char *posix) { - return_with_errno (conv_path_list (win32, posix, 1)); + return_with_errno (conv_path_list (win32, posix, MAX_PATH, 1)); } extern "C" int cygwin_posix_to_win32_path_list (const char *posix, char *win32) { - return_with_errno (conv_path_list (posix, win32, 0)); + return_with_errno (conv_path_list (posix, win32, MAX_PATH, 0)); +} + +extern "C" ssize_t +cygwin_conv_path_list (cygwin_conv_path_t what, const void *from, void *to, + size_t size) +{ + /* FIXME: Path lists are (so far) always retaining relative paths. */ + what &= ~CCP_RELATIVE; + switch (what) + { + case CCP_WIN_W_TO_POSIX: + case CCP_POSIX_TO_WIN_W: + /*FIXME*/ + api_fatal ("wide char path lists not yet supported"); + break; + case CCP_WIN_A_TO_POSIX: + case CCP_POSIX_TO_WIN_A: + if (size == 0) + return conv_path_list_buf_size ((const char *) from, + what == CCP_WIN_A_TO_POSIX); + return_with_errno (conv_path_list ((const char *) from, (char *) to, + size, what == CCP_WIN_A_TO_POSIX)); + break; + default: + break; + } + set_errno (EINVAL); + return -1; } /* cygwin_split_path: Split a path into directory and file name parts. @@ -4685,7 +4785,8 @@ cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen) if (!need_posix) { tocopy = tp.c_get (); - sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer, win32.Length); + sys_wcstombs (tocopy, NT_MAX_PATH, win32.Buffer, + win32.Length / sizeof (WCHAR)); } else tocopy = posix; diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc index 79b0494a4..cb5af8017 100644 --- a/winsup/cygwin/spawn.cc +++ b/winsup/cygwin/spawn.cc @@ -138,9 +138,9 @@ find_exec (const char *name, path_conv& buf, const char *mywinenv, if (strchr (mywinenv, '/')) { /* it's not really an environment variable at all */ - int n = cygwin_posix_to_win32_path_list_buf_size (mywinenv); - char *s = (char *) alloca (n + 1); - if (cygwin_posix_to_win32_path_list (mywinenv, s)) + int n = cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, mywinenv, NULL, 0); + char *s = (char *) alloca (n); + if (cygwin_conv_path_list (CCP_POSIX_TO_WIN_A, mywinenv, s, n)) goto errout; path = s; posix_path = mywinenv - 1; diff --git a/winsup/cygwin/tls_pbuf.cc b/winsup/cygwin/tls_pbuf.cc index 802885ebc..704f3bfc9 100644 --- a/winsup/cygwin/tls_pbuf.cc +++ b/winsup/cygwin/tls_pbuf.cc @@ -42,7 +42,7 @@ tmp_pathbuf::c_get () if (tls_pbuf.c_cnt >= TP_NUM_C_BUFS) api_fatal ("Internal error: TP_NUM_C_BUFS too small."); if (!tls_pbuf.c_buf[tls_pbuf.c_cnt] - && !(tls_pbuf.c_buf[tls_pbuf.c_cnt] = (char *) malloc (NT_MAX_PATH + 1))) + && !(tls_pbuf.c_buf[tls_pbuf.c_cnt] = (char *) malloc (NT_MAX_PATH))) api_fatal ("Internal error: Out of memory for new path buf."); return tls_pbuf.c_buf[tls_pbuf.c_cnt++]; } @@ -54,7 +54,7 @@ tmp_pathbuf::w_get () api_fatal ("Internal error: TP_NUM_W_BUFS too small."); if (!tls_pbuf.w_buf[tls_pbuf.w_cnt] && !(tls_pbuf.w_buf[tls_pbuf.w_cnt] - = (PWCHAR) malloc ((NT_MAX_PATH + 1) * sizeof (WCHAR)))) + = (PWCHAR) malloc (NT_MAX_PATH * sizeof (WCHAR)))) api_fatal ("Internal error: Out of memory for new wide path buf."); return tls_pbuf.w_buf[tls_pbuf.w_cnt++]; } diff --git a/winsup/cygwin/tls_pbuf.h b/winsup/cygwin/tls_pbuf.h index b4a2a7a37..d4143aaf1 100644 --- a/winsup/cygwin/tls_pbuf.h +++ b/winsup/cygwin/tls_pbuf.h @@ -17,4 +17,11 @@ public: char *c_get (); /* Create temporary TLS path buf of size NT_MAX_PATH. */ PWCHAR w_get (); /* Create temporary TLS path buf of size 2 * NT_MAX_PATH. */ inline char *t_get () { return (char *) w_get (); } + inline PUNICODE_STRING u_get (PUNICODE_STRING up) + { + up->Length = 0; + up->MaximumLength = (NT_MAX_PATH - 1) * sizeof (WCHAR); + up->Buffer = w_get (); + return up; + } }; diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc index ae7e85cdd..6f1dd9784 100644 --- a/winsup/cygwin/uinfo.cc +++ b/winsup/cygwin/uinfo.cc @@ -30,6 +30,7 @@ details. */ #include "child_info.h" #include "environ.h" #include "pwdgrp.h" +#include "tls_pbuf.h" #include "ntdll.h" /* Initialize the part of cygheap_user that does not depend on files. @@ -240,11 +241,10 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw) LPUSER_INFO_3 ui = NULL; WCHAR wuser[UNLEN + 1]; NET_API_STATUS ret; - char homepath_env_buf[CYG_MAX_PATH]; char homedrive_env_buf[3]; char *newhomedrive = NULL; char *newhomepath = NULL; - + tmp_pathbuf tp; debug_printf ("what %d, pw %p", what, pw); if (what == CH_HOME) @@ -273,11 +273,12 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw) setenv ("HOME", "/", 1); else { - char home[CYG_MAX_PATH]; - char buf[CYG_MAX_PATH]; + char *home = tp.c_get (); + char *buf = tp.c_get (); strcpy (buf, newhomedrive); strcat (buf, newhomepath); - cygwin_conv_to_full_posix_path (buf, home); + cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, buf, home, + NT_MAX_PATH); debug_printf ("Set HOME (from HOMEDRIVE/HOMEPATH) to %s", home); setenv ("HOME", home, 1); } @@ -286,10 +287,12 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw) if (what != CH_HOME && homepath == NULL && newhomepath == NULL) { + char *homepath_env_buf = tp.c_get (); if (!pw) pw = internal_getpwnam (name ()); if (pw && pw->pw_dir && *pw->pw_dir) - cygwin_conv_to_full_win32_path (pw->pw_dir, homepath_env_buf); + cygwin_conv_path (CCP_POSIX_TO_WIN_A, pw->pw_dir, homepath_env_buf, + NT_MAX_PATH); else { homepath_env_buf[0] = homepath_env_buf[1] = '\0'; @@ -301,16 +304,17 @@ cygheap_user::ontherange (homebodies what, struct passwd *pw) sys_mbstowcs (wuser, sizeof (wuser) / sizeof (*wuser), winname ()); if (!(ret = NetUserGetInfo (wlogsrv, wuser, 3, (LPBYTE *) &ui))) { - sys_wcstombs (homepath_env_buf, CYG_MAX_PATH, + sys_wcstombs (homepath_env_buf, NT_MAX_PATH, ui->usri3_home_dir); if (!homepath_env_buf[0]) { - sys_wcstombs (homepath_env_buf, CYG_MAX_PATH, + sys_wcstombs (homepath_env_buf, NT_MAX_PATH, ui->usri3_home_dir_drive); if (homepath_env_buf[0]) strcat (homepath_env_buf, "\\"); else - cygwin_conv_to_full_win32_path ("/", homepath_env_buf); + cygwin_conv_path (CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, + "/", homepath_env_buf, NT_MAX_PATH); } } } diff --git a/winsup/cygwin/winf.cc b/winsup/cygwin/winf.cc index 033de7b1e..4be4002a7 100644 --- a/winsup/cygwin/winf.cc +++ b/winsup/cygwin/winf.cc @@ -141,7 +141,8 @@ av::unshift (const char *what, int conv) char *buf = tp.c_get (); if (conv) { - cygwin_conv_to_posix_path (what, buf); + cygwin_conv_path (CCP_WIN_A_TO_POSIX | CCP_RELATIVE, what, buf, + NT_MAX_PATH); char *p = strchr (buf, '\0') - 4; if (p > buf && ascii_strcasematch (p, ".exe")) *p = '\0'; diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index e10ffe989..55db72960 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -81,13 +81,8 @@ extern unsigned long cygwin_inet_addr (const char *cp); buffer sizes. As MAX_PATH and PATH_MAX, this is defined including the trailing 0. Internal buffers and internal path routines should use NT_MAX_PATH. PATH_MAX as defined in limits.h is the maximum length of - application provided path strings we handle. - - Note that it's defined one less than 32K. This is not only big enough, - it also allows to use the value in UNICODE_STRING fields Length and - MaximumLength when multiplied with sizeof (WCHAR). Both fields are - USHORT... */ -#define NT_MAX_PATH 32767 + application provided path strings we handle. */ +#define NT_MAX_PATH 32768 #ifdef __cplusplus