Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: Yuk. I guess it would help a lot to reproduce path.cc:check_shortcut(*) in utils as close as possible. Afaics it doesn't use any code which would be restricted to Cygwin, except for the call to mount_table-conv_to_posix_path in the posixify method. I started down that road, trying to come up with a slick method for sharing the code so that we don't need to maintain two copies. After poking at it for a while I came to the realization that the two are just plumbed too differently to share code directly. In the Cygwin code, the check if this is a valid symlink and the read its contents are kind of lumped together as the symlink_info class provides a convenient location to store the data. But in the cygcheck implementation we have only is_symlink() and readlink(), with both take just a HANDLE and share nothing, and no pflags to worry about, etc. And of course there's the obvious that cygcheck has no Win32-POSIX conversion capability which makes it hard to support reading reparse points because readlink() is supposed to return the POSIX link target. Anyway, the attached is the result of what happened when I started with the Cygwin code and whittled it down. It fixes the bug in the grandparent of this email where it was reading the Win32 path out of a shortcut that didn't have an ITEMIDLIST, and it supports the new-style shortcut where the target MAX_PATH gets stored at the end. It does not attempt to do anything with reparse points however. Another factor was that the file IO in symlink_info::check_shortcut was using the native API, which I rewrote to use the plain Win32 flavor in case we want to keep cygcheck working on 9x/ME. I don't think this will matter if we want to make cygcheck support long paths though, since it's just ReadFile, SetFilePointer, and GetFileInformationByHandle -- the HANDLE is already open so this should require no change to support WCHAR. Brian2008-03-15 Brian Dessent [EMAIL PROTECTED] * path.cc: Include malloc.h for alloca. (is_symlink): Rewrite. Just read the whole file in memory rather than by parts. Account for an ITEMIDLIST if present, as well as the new style of Cygwin shortcut supporting targets MAX_PATH. path.cc | 96 +++- 1 file changed, 47 insertions(+), 49 deletions(-) Index: path.cc === RCS file: /cvs/src/src/winsup/utils/path.cc,v retrieving revision 1.14 diff -u -p -r1.14 path.cc --- path.cc 11 Mar 2008 17:20:02 - 1.14 +++ path.cc 15 Mar 2008 13:12:45 - @@ -18,6 +18,7 @@ details. */ #include windows.h #include stdio.h #include stdlib.h +#include malloc.h #include path.h #include cygwin/include/cygwin/version.h #include cygwin/include/sys/mount.h @@ -172,60 +173,57 @@ is_symlink (HANDLE fh) bool readlink (HANDLE fh, char *path, int maxlen) { - int got; - int magic = get_word (fh, 0x0); + DWORD rv; + char *buf, *cp; + unsigned short len; + win_shortcut_hdr *file_header; + BY_HANDLE_FILE_INFORMATION fi; + + if (!GetFileInformationByHandle (fh, fi) + || fi.nFileSizeHigh != 0 + || fi.nFileSizeLow 8192) +return false; - if (magic == SHORTCUT_MAGIC) -{ - int offset = get_word (fh, 0x4c); - int slen = get_word (fh, 0x4c + offset + 2); - if (slen = maxlen) - { - SetLastError (ERROR_FILENAME_EXCED_RANGE); - return false; - } - if (SetFilePointer (fh, 0x4c + offset + 4, 0, FILE_BEGIN) == - INVALID_SET_FILE_POINTER GetLastError () != NO_ERROR) - return false; + buf = (char *) alloca (fi.nFileSizeLow + 1); + file_header = (win_shortcut_hdr *) buf; - if (!ReadFile (fh, path, slen, (DWORD *) got, 0)) - return false; - else if (got slen) - { - SetLastError (ERROR_READ_FAULT); - return false; - } - else - path[got] = '\0'; -} - else if (magic == SYMLINK_MAGIC) + if (SetFilePointer (fh, 0L, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER + || !ReadFile (fh, buf, fi.nFileSizeLow, rv, NULL) + || rv != fi.nFileSizeLow) +return false; + + if (fi.nFileSizeLow sizeof (file_header) + cmp_shortcut_header (file_header)) { - char cookie_buf[sizeof (SYMLINK_COOKIE) - 1]; - - if (SetFilePointer (fh, 0, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER - GetLastError () != NO_ERROR) - return false; - - if (!ReadFile (fh, cookie_buf, sizeof (cookie_buf), (DWORD *) got, 0)) - return false; - else if (got == sizeof (cookie_buf) - memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0) - { - if (!ReadFile (fh, path, maxlen, (DWORD *) got, 0)) - return false; - else if (got = maxlen) - { - SetLastError (ERROR_FILENAME_EXCED_RANGE); - path[0] = '\0'; - return
Re: [patch] cygcheck.cc update for cygpath()
On Mar 10 21:10, Corinna Vinschen wrote: On Mar 10 15:08, Christopher Faylor wrote: However, I don't understand what a mingw app would see when it is started from Cygwin now. What would a standard windows app think that its cwd would be if it's cd'ed deep into a 32K long path. Right now, Cygwin copies its CWD into the user parameter block, as long as it is 260 chars. When a Cygwin process cd's into a long path, this copy just doesn't happen. So, the cwd of a MingW application started from that Cygwin process would be the last Cygwin cwd path 260 characters within this process tree. This is what I started to discuss in http://cygwin.com/ml/cygwin-developers/2007-10/msg8.html As a result of this discussion we had five options what to do when spawning a native app from Cygwin, if the Cygwin process is in a long cwd: 1. Return ENAMETOOLONG and don't start the native child. 2. CWD for the native child is set to $SYSTEMROOT. 3. CWD is set to the root of the current drive (either X:\ or \\server\share). 4. CWD is set to the longest leading path component of CWD which still fits into MAX_PATH. 5. Start the native app in the last CWD we were in which was MAX_PATH. Implemented right now is option 5 since that's the most easy to implement because it practically didn't need any changes to the existing code. The general consensus seemed to lean towards option 1 or 3, so maybe this whole problem is going to be a non-issue...? Sigh, somehow it would be a pity if our own tools suffer from that restriction. I applied a patch which enables option 1 for all long and virtual paths. So, for now, we don't have to take paths MAX_PATH into account for any MingW utility. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
On Mar 11 08:36, Brian Dessent wrote: Corinna Vinschen wrote: Given that Cygwin changes to support long path names, I don't really like to see new code still using MAX_PATH and Win32 Ansi functions in the utils dir. I know that the Win32 cwd is always restricted to 259 chars. However, there *is* a way to recognize the current working directory of the parent Cygwin application. Here's an updated version of the patch. It addresses the problem of resolving symlink targets relative to the dir of the link without a gratuitous Get/SetCurrentDirectory sequence by introducing cygpath_rel(). It does not yet address the issue of modernizing the symlink reading code, that will follow. This patch still has two cases of MAX_PATH usage: one in a buffer that is used for GetCurrentDirectory(), so I don't see how making it larger there helps. The second is in a static buffer for the dirname() helper. I could simply make this one larger, however, the context where this dirname() is used is a filename that's used with CreateFile() so until that is plumbed to use WCHAR and \\?\ I don't really think it makes sense to use more than MAX_PATH. I could update that instance of CreateFile, but the thing that provides the filename passed here is itself driven by GetFileAttributes(), so it would need to be updated too... and so on. It looks like a lot of work to go completely longfile-clean here. The patch looks basically ok with me. Please check in. Btw., you don't need to make the buffers MAX_PATH + 1. MAX_PATH is defined including the trailing NUL. Existing code shows a lot of irritation about this... Thanks, Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: Btw., you don't need to make the buffers MAX_PATH + 1. MAX_PATH is defined including the trailing NUL. Existing code shows a lot of irritation about this... Oh, I wasn't even thinking of that... the reason I used MAX_PATH + 1 was because earlier I had written + static char tmp[SYMLINK_MAX + 1]; so that the following sizes would not need to be SYMLINK_MAX - 1, + if (!readlink (fh, tmp, SYMLINK_MAX)) + strncpy (tmp, cygpath (papp, NULL), SYMLINK_MAX); + strncpy (lastsep+1, ptr, SYMLINK_MAX - (lastsep-tmp)); I.e. pure lazyness of wanting to type the least necessary. But now that you mention it, it makes more sense to have the - 1 than the + 1 form, so I'll change that. Brian
Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: Urgh. MAX_PATH is defined with trailing 0, SYMLINK_MAX is defined without trailing 0 (like NAME_MAX). You should better change the SYMLINK_MAX stuff back, afaics... D'oh! 'Kay.
Re: [patch] cygcheck.cc update for cygpath()
On Mar 10 15:08, Christopher Faylor wrote: However, I don't understand what a mingw app would see when it is started from Cygwin now. What would a standard windows app think that its cwd would be if it's cd'ed deep into a 32K long path. Right now, Cygwin copies its CWD into the user parameter block, as long as it is 260 chars. When a Cygwin process cd's into a long path, this copy just doesn't happen. So, the cwd of a MingW application started from that Cygwin process would be the last Cygwin cwd path 260 characters within this process tree. This is what I started to discuss in http://cygwin.com/ml/cygwin-developers/2007-10/msg8.html As a result of this discussion we had five options what to do when spawning a native app from Cygwin, if the Cygwin process is in a long cwd: 1. Return ENAMETOOLONG and don't start the native child. 2. CWD for the native child is set to $SYSTEMROOT. 3. CWD is set to the root of the current drive (either X:\ or \\server\share). 4. CWD is set to the longest leading path component of CWD which still fits into MAX_PATH. 5. Start the native app in the last CWD we were in which was MAX_PATH. Implemented right now is option 5 since that's the most easy to implement because it practically didn't need any changes to the existing code. The general consensus seemed to lean towards option 1 or 3, so maybe this whole problem is going to be a non-issue...? Sigh, somehow it would be a pity if our own tools suffer from that restriction. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
Hi Brian, Thanks for your patch. I have a few nits, sorry. On Mar 8 20:13, Brian Dessent wrote: Index: cygcheck.cc === RCS file: /cvs/src/src/winsup/utils/cygcheck.cc,v retrieving revision 1.97 diff -u -p -r1.97 cygcheck.cc --- cygcheck.cc 13 Jan 2008 13:41:45 - 1.97 +++ cygcheck.cc 9 Mar 2008 03:52:07 - @@ -807,6 +807,31 @@ ls (char *f) display_error (ls: CloseHandle()); } +/* If s is non-NULL, save the CWD in a static buffer and set the CWD + to the dirname part of s. If s is NULL, restore the CWD last + saved. */ +static +void save_cwd_helper (const char *s) +{ + static char cwdbuf[MAX_PATH + 1]; + char dirnamebuf[MAX_PATH + 1]; + + if (s) +{ + GetCurrentDirectory (sizeof (cwdbuf), cwdbuf); + + /* Remove the filename part from s. */ + strncpy (dirnamebuf, s, MAX_PATH); + dirnamebuf[MAX_PATH] = '\0'; // just in case strlen(s) MAX_PATH + char *lastsep = strrchr (dirnamebuf, '\\'); + if (lastsep) +lastsep[1] = '\0'; + SetCurrentDirectory (dirnamebuf); +} + else +SetCurrentDirectory (cwdbuf); +} Given that Cygwin changes to support long path names, I don't really like to see new code still using MAX_PATH and Win32 Ansi functions in the utils dir. I know that the Win32 cwd is always restricted to 259 chars. However, there *is* a way to recognize the current working directory of the parent Cygwin application. Bash as well as tcsh, as well as zsh (and probbaly pdksh, too) create an environment variable $PWD. Maybe Cygwin should create $PWD for native apps if it's not already available through the parent shell. I'd suggest that the Cygwin utils first try to fetch $PWD from the environment and use that as cwd. Only if that fails, use GetCurrentDirectory. Never use SetCurrentDirectory, rather convert the path to an absolute path, prepend \\?\ and call the Win32 unicode functions (CreateFileW, etc). // Find a real application on the path (possibly following symlinks) static const char * find_app_on_path (const char *app, bool showall = false) @@ -822,25 +847,27 @@ find_app_on_path (const char *app, bool if (is_symlink (fh)) { static char tmp[4000] = ; SYMLINK_MAX is PATH_MAX - 1 == 4095. I'm wondering if you would like to tweak the readlink functions, too. Cygwin shortcuts can now have the path name appended to the actual shortcut data. This hack was necessary to support pathnames longer than 2000 chars. See the comment and code in cygwin/path.cc, line 3139ff. Thanks, Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: Given that Cygwin changes to support long path names, I don't really like to see new code still using MAX_PATH and Win32 Ansi functions in the utils dir. Regardless of this patch, path.cc:rel_vconcat() currently uses GetCurrentDirectory() to resolve relative paths. It would be nice if rel_vconcat() (or really, cygpath()) had an interface that let the caller supply a CWD instead, as that would bypass the whole issue of length since what this patch is doing is simply setting CWD just so that rel_vconcat() can then get it again. I thought about doing it that way but it seemed more invasive. I know that the Win32 cwd is always restricted to 259 chars. However, there *is* a way to recognize the current working directory of the parent Cygwin application. Bash as well as tcsh, as well as zsh (and probbaly pdksh, too) create an environment variable $PWD. Maybe Cygwin should create $PWD for native apps if it's not already available through the parent shell. I'd suggest that the Cygwin utils first try to fetch $PWD from the environment and use that as cwd. Only if that fails, use GetCurrentDirectory. I will work on a patch that both adds an interface to allow the caller to supply a CWD as well as trying to use $PWD to get the value otherwise. Never use SetCurrentDirectory, rather convert the path to an absolute path, prepend \\?\ and call the Win32 unicode functions (CreateFileW, etc). Setting the CWD can be totally avoided I think, by the above replumbing. SYMLINK_MAX is PATH_MAX - 1 == 4095. I'm wondering if you would like to tweak the readlink functions, too. Cygwin shortcuts can now have the path name appended to the actual shortcut data. This hack was necessary to support pathnames longer than 2000 chars. See the comment and code in cygwin/path.cc, line 3139ff. Oh, I didn't know that. I'll add that to the list. Brian
Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: I'm wondering if you would like to tweak the readlink functions, too. Cygwin shortcuts can now have the path name appended to the actual shortcut data. This hack was necessary to support pathnames longer than 2000 chars. See the comment and code in cygwin/path.cc, line 3139ff. Oh, I didn't know that. I'll add that to the list. Thanks again. I'm finally seeing light at the end of the long path name tunnel :) Actually I'm a little confused now. It seems like the code in utils/path.cc:readlink() reads the Win32 path out of shortcut symlinks but the POSIX path out of old-style symlinks -- not that it has any choice since they don't contain the win32 path. If that is the case (and assuming I'm reading the new long filename symlink code correctly) then it doesn't need any chaging since the [path too long] workaround only applies to the POSIX link target stored in the 'description' field, right? But the semantics of sometimes you get an absolute Win32 path, sometimes you get a relative POSIX path that readlink() seems to provide baffles my mind. More and more it seems that a lot of how these non-Cygwin tools successfully process paths happens seemingly out of luck. I'll have to go and research the callers of readlink() but it seems like it should be always returning the POSIX target, since that's the only sane behavior in the face of old and new styles. Brian
Re: [patch] cygcheck.cc update for cygpath()
On Mar 9 03:32, Brian Dessent wrote: Corinna Vinschen wrote: I'm wondering if you would like to tweak the readlink functions, too. Cygwin shortcuts can now have the path name appended to the actual shortcut data. This hack was necessary to support pathnames longer than 2000 chars. See the comment and code in cygwin/path.cc, line 3139ff. Oh, I didn't know that. I'll add that to the list. Thanks again. I'm finally seeing light at the end of the long path name tunnel :) Actually I'm a little confused now. It seems like the code in utils/path.cc:readlink() reads the Win32 path out of shortcut symlinks but the POSIX path out of old-style symlinks -- not that it has any choice since they don't contain the win32 path. If that is the case (and assuming I'm reading the new long filename symlink code correctly) then it doesn't need any chaging since the [path too long] workaround only applies to the POSIX link target stored in the 'description' field, right? Now that you mention it... did you see the comment in path.cc, line 3112ff? There's a good chance that Windows shortcuts are not capable of long path names. I didn't test it so far, but it would be certainly better for readlink to use the POSIX path in the symlink either way. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: Now that you mention it... did you see the comment in path.cc, line 3112ff? There's a good chance that Windows shortcuts are not capable of long path names. I didn't test it so far, but it would be certainly better for readlink to use the POSIX path in the symlink either way. Check this out. I modified cygcheck to have a command line option to dump out whatever readlink() returns. $ cd /tmp $ echo fileone fileone $ ln -s fileone linkone $ ln -s filetwo linktwo# filetwo doesn't exist yet $ echo filetwo filetwo $ cat linkone fileone $ cat linktwo filetwo $ ./cygcheck -x linkone linktwo linkone - fileone linktwo - c:\tmp\filetwo $ ls -l linkone linktwo lrwxrwxrwx 1 brian None 7 Mar 9 04:56 linkone - fileone lrwxrwxrwx 1 brian None 7 Mar 9 04:56 linktwo - filetwo So, the fact that the link was dangling at the time it was created caused readlink to read it as a Win32 path -- which also causes it to now be an absolute target instead of a relative target. Apparently this is due to the fact that if the target doesn't exist at creation time the ParseDisplayName thing fails which results in a different structure for the .lnk file, which confuses readlink()'s puny little brain which only knows how to look at a fixed offset in the file, which results in it reading a different slot. Sigh. Brian
Re: [patch] cygcheck.cc update for cygpath()
On Mar 9 05:02, Brian Dessent wrote: Corinna Vinschen wrote: Now that you mention it... did you see the comment in path.cc, line 3112ff? There's a good chance that Windows shortcuts are not capable of long path names. I didn't test it so far, but it would be certainly better for readlink to use the POSIX path in the symlink either way. Check this out. I modified cygcheck to have a command line option to dump out whatever readlink() returns. $ cd /tmp $ echo fileone fileone $ ln -s fileone linkone $ ln -s filetwo linktwo# filetwo doesn't exist yet $ echo filetwo filetwo $ cat linkone fileone $ cat linktwo filetwo $ ./cygcheck -x linkone linktwo linkone - fileone linktwo - c:\tmp\filetwo $ ls -l linkone linktwo lrwxrwxrwx 1 brian None 7 Mar 9 04:56 linkone - fileone lrwxrwxrwx 1 brian None 7 Mar 9 04:56 linktwo - filetwo So, the fact that the link was dangling at the time it was created caused readlink to read it as a Win32 path -- which also causes it to now be an absolute target instead of a relative target. Apparently this is due to the fact that if the target doesn't exist at creation time the ParseDisplayName thing fails which results in a different structure for the .lnk file, which confuses readlink()'s puny little brain which only knows how to look at a fixed offset in the file, which results in it reading a different slot. Sigh. Yuk. I guess it would help a lot to reproduce path.cc:check_shortcut(*) in utils as close as possible. Afaics it doesn't use any code which would be restricted to Cygwin, except for the call to mount_table-conv_to_posix_path in the posixify method. Corinna (*) and, FWIW, symlink_info::check_reparse_point and symlink_info::check_sysfile. -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
On Sun, Mar 09, 2008 at 10:28:06AM +0100, Corinna Vinschen wrote: Hi Brian, Thanks for your patch. I have a few nits, sorry. On Mar 8 20:13, Brian Dessent wrote: Index: cygcheck.cc === RCS file: /cvs/src/src/winsup/utils/cygcheck.cc,v retrieving revision 1.97 diff -u -p -r1.97 cygcheck.cc --- cygcheck.cc 13 Jan 2008 13:41:45 - 1.97 +++ cygcheck.cc 9 Mar 2008 03:52:07 - @@ -807,6 +807,31 @@ ls (char *f) display_error (ls: CloseHandle()); } +/* If s is non-NULL, save the CWD in a static buffer and set the CWD + to the dirname part of s. If s is NULL, restore the CWD last + saved. */ +static +void save_cwd_helper (const char *s) +{ + static char cwdbuf[MAX_PATH + 1]; + char dirnamebuf[MAX_PATH + 1]; + + if (s) +{ + GetCurrentDirectory (sizeof (cwdbuf), cwdbuf); + + /* Remove the filename part from s. */ + strncpy (dirnamebuf, s, MAX_PATH); + dirnamebuf[MAX_PATH] = '\0'; // just in case strlen(s) MAX_PATH + char *lastsep = strrchr (dirnamebuf, '\\'); + if (lastsep) +lastsep[1] = '\0'; + SetCurrentDirectory (dirnamebuf); +} + else +SetCurrentDirectory (cwdbuf); +} Given that Cygwin changes to support long path names, I don't really like to see new code still using MAX_PATH and Win32 Ansi functions in the utils dir. I know that the Win32 cwd is always restricted to 259 chars. However, there *is* a way to recognize the current working directory of the parent Cygwin application. Bash as well as tcsh, as well as zsh (and probbaly pdksh, too) create an environment variable $PWD. Maybe Cygwin should create $PWD for native apps if it's not already available through the parent shell. I'd really rather not do that. I don't think Cygwin should be polluting the environment any more than it has to. Even if this worked, it is easily defeatable by setting a PWD environment variable before running cygwin, so you'd have to keep track of this value through multiple levels of process invocation. I know everyone hates it but a cygwin_internal interface could be used to get the current working directory for applications that need it. I would think that only mingw-like applications working in close conjunction with cygwin would care about this. cgf
Re: [patch] cygcheck.cc update for cygpath()
On Mar 9 10:38, Christopher Faylor wrote: On Sun, Mar 09, 2008 at 10:28:06AM +0100, Corinna Vinschen wrote: Bash as well as tcsh, as well as zsh (and probbaly pdksh, too) create an environment variable $PWD. Maybe Cygwin should create $PWD for native apps if it's not already available through the parent shell. I'd really rather not do that. I don't think Cygwin should be polluting the environment any more than it has to. Even if this worked, it is easily defeatable by setting a PWD environment variable before running cygwin, so you'd have to keep track of this value through multiple levels of process invocation. Nothing against adding a cygwin_internal for such a purpose, but how is that going to work? Assuming the MingW application is called from a Cygwin application. If the parent application's cwd is a long path, the MingW child gets its own cwd for apparent reasons. If it loads the cygwin DLL dynamically, as cygcheck already does, how is that new invocation of the DLL supposed to know the cwd of the parent process? Maybe I miss something, but I don't see how that could work without using another mechanism to transmit the cwd of the parent application to the child, and the environment seems like a pretty simple way to do it. What about just using PWD if it's set, but not to invent it in Cygwin if it doesn't exist? I see two situations which probably cover 99% of the cases. The first case is starting cygcheck from the native command shell. That shell doesn't understand long paths anyway and always has a cwd which can be fetched by GetCurrentDirectory. The second case is starting cygcheck from a Cygwin shell. The Cygwin shell sets $PWD anyway, at least bash, tcsh and zsh. Corinna -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
On Sun, Mar 09, 2008 at 04:14:40PM +0100, Corinna Vinschen wrote: On Mar 9 10:38, Christopher Faylor wrote: On Sun, Mar 09, 2008 at 10:28:06AM +0100, Corinna Vinschen wrote: Bash as well as tcsh, as well as zsh (and probbaly pdksh, too) create an environment variable $PWD. Maybe Cygwin should create $PWD for native apps if it's not already available through the parent shell. I'd really rather not do that. I don't think Cygwin should be polluting the environment any more than it has to. Even if this worked, it is easily defeatable by setting a PWD environment variable before running cygwin, so you'd have to keep track of this value through multiple levels of process invocation. Nothing against adding a cygwin_internal for such a purpose, but how is that going to work? Assuming the MingW application is called from a Cygwin application. If the parent application's cwd is a long path, the MingW child gets its own cwd for apparent reasons. If it loads the cygwin DLL dynamically, as cygcheck already does, how is that new invocation of the DLL supposed to know the cwd of the parent process? I guess I misunderstood. I thought that the current working directory could be derived through some complicated combination of Nt*() calls. Maybe I miss something, but I don't see how that could work without using another mechanism to transmit the cwd of the parent application to the child, and the environment seems like a pretty simple way to do it. What about just using PWD if it's set, but not to invent it in Cygwin if it doesn't exist? I see two situations which probably cover 99% of the cases. The problem with environment variables are that they are under the user's control. If the user decides to modify PWD, then it can cause issues. That's why I was looking for a more foolproof solution. That + I hate the thought of adding YA special environment variable for Cygwin to worry about. A real OS would never consider passing stuff around in environment variables. cgf
Re: [patch] cygcheck.cc update for cygpath()
Christopher Faylor wrote: I guess I misunderstood. I thought that the current working directory could be derived through some complicated combination of Nt*() calls. I could be wrong here but the way I understood it, there is no concept of a working directory at the NT level, that is something that is maintained by the Win32 layer. My question is, what does GetCurrentDirectoryW() return if the current directory is greater than the 260 limit? Does it choke or does it switch to the \.\c:\foo syntax? Brian
Re: [patch] cygcheck.cc update for cygpath()
On Mar 9 11:03, Brian Dessent wrote: Christopher Faylor wrote: I guess I misunderstood. I thought that the current working directory could be derived through some complicated combination of Nt*() calls. I could be wrong here but the way I understood it, there is no concept of a working directory at the NT level, that is something that is maintained by the Win32 layer. That's right. NT doesn't have a notion what a cwd is. It only has the OBJECT_ATTRIBUTES structure which defines an object by an absolute path, or by a path relative to a directory handle. The cwd is maintained by kernel32.dll in a per-process structure called RTL_USER_PROCESS_PARAMETERS. The cwd is stored as path (always with trailing backslash) and as handle. Sometimes the Win32 functions use the cwd's path to create an absolute path from a relative path, sometimes they use the cwd's handle and the relative path in calls to NT functions. My question is, what does GetCurrentDirectoryW() return if the current directory is greater than the 260 limit? Does it choke or does it switch to the \.\c:\foo syntax? It can't do that. See the MSDN man page for SetCurrentDirectory: http://msdn2.microsoft.com/en-us/library/aa365530(VS.85).aspx The string must not exceed MAX_PATH characters including the terminating null character. The problem is that the cwd is stored as UNICODE_STRING with a statically allocated buffer in the user parameter block. The MaximumLength is set to 520. SetCurrentDirectory refuses to take paths longer than that. In theory it would be possible to define a longer cwd by defining a new buffer in the cwd's UNICODE_STRING. But I never tried that. I don't really know if that's possible and what happens if you call CreateProcess or, FWIW, any Win32 file access function after doing that. Nobody keeps us from trying, but I have this gut feeling that different NT versions will show different behaviour... Corinna (*) See cygwin/ntdll.h, struct _RTL_USER_PROCESS_PARAMETERS. -- Corinna Vinschen Please, send mails regarding Cygwin to Cygwin Project Co-Leader cygwin AT cygwin DOT com Red Hat
Re: [patch] cygcheck.cc update for cygpath()
On Sun, Mar 09, 2008 at 08:55:09PM +0100, Corinna Vinschen wrote: On Mar 9 11:03, Brian Dessent wrote: Christopher Faylor wrote: I guess I misunderstood. I thought that the current working directory could be derived through some complicated combination of Nt*() calls. I could be wrong here but the way I understood it, there is no concept of a working directory at the NT level, that is something that is maintained by the Win32 layer. That's right. NT doesn't have a notion what a cwd is. It only has the OBJECT_ATTRIBUTES structure which defines an object by an absolute path, or by a path relative to a directory handle. The cwd is maintained by kernel32.dll in a per-process structure called RTL_USER_PROCESS_PARAMETERS. The cwd is stored as path (always with trailing backslash) and as handle. Duh, right. I knew that. I've seen the code. So, maybe we could make sure the handle was inherited and pass it along in a _CYGWIN_PWD=0x239487 format to the child? cgf
Re: [patch] cygcheck.cc update for cygpath()
Corinna Vinschen wrote: The problem is that the cwd is stored as UNICODE_STRING with a statically allocated buffer in the user parameter block. The MaximumLength is set to 520. SetCurrentDirectory refuses to take paths longer than that. In theory it would be possible to define a longer cwd by defining a new buffer in the cwd's UNICODE_STRING. But I never tried that. I don't really know if that's possible and what happens if you call CreateProcess or, FWIW, any Win32 file access function after doing that. Nobody keeps us from trying, but I have this gut feeling that different NT versions will show different behaviour... How does this fit in with the practice of maintaining our own Cygwin CWD state separate from the Win32 CWD so that unlink(.) and the like can succeed? Or is that precisely how we are able to support a CWD = 260? If it is the case that we can only support a CWD = 260 by faking it, i.e. not trying to sync the Win32 CWD to the actual long CWD, then it seems we are limited to two choices for how to deal with a long CWD in a non-Cygwin process: a) not supported, b) supported only through some special hook (such as cgf's idea of handle inheritance of the Cygwin CWD handle) or through relying on the shell to set PWD. Brian
Re: [patch] cygcheck.cc update for cygpath()
Christopher Faylor wrote: It looks like yo can still unindent this by changing the == to !=, putting the temppath under that and keeping all of the if's at the same level: Oh, I see now what you mean. If the if block is that small, then I think I'd prefer just one comment at the beginning which describes what it is doing. Otherwise, I got lost in what was happening while trying to see where the comments line up. I don't feel really strongly about that, though, so feel free to ignore me. I would prefer not having the nested if's though. Otherwise, this looks good. If you make the above suggestions, feel free to check this in. I chopped each comment down to a single line //-style which I think helps the clutter, and removed the nesting. Also, there are a few tweaks to cygcheck.cc necessary as a result, see attached. The main idea is that when normalizing a link's target in find_app_on_path, we should temporarily set the CWD to the same dir as the link, otherwise relative links will get normalized relative to whatever dir cygcheck was run from. Brian2008-03-08 Brian Dessent [EMAIL PROTECTED] * cygcheck.cc (save_cwd_helper): New helper function for saving the current directory. (find_app_on_path): Use sizeof instead of hardcoded array sizes throughout. Change into the dir of the link when normalizing its target. Don't worry about converting slashes as cygpath () now handles that. cygcheck.cc | 45 - 1 file changed, 36 insertions(+), 9 deletions(-) Index: cygcheck.cc === RCS file: /cvs/src/src/winsup/utils/cygcheck.cc,v retrieving revision 1.97 diff -u -p -r1.97 cygcheck.cc --- cygcheck.cc 13 Jan 2008 13:41:45 - 1.97 +++ cygcheck.cc 9 Mar 2008 03:52:07 - @@ -807,6 +807,31 @@ ls (char *f) display_error (ls: CloseHandle()); } +/* If s is non-NULL, save the CWD in a static buffer and set the CWD + to the dirname part of s. If s is NULL, restore the CWD last + saved. */ +static +void save_cwd_helper (const char *s) +{ + static char cwdbuf[MAX_PATH + 1]; + char dirnamebuf[MAX_PATH + 1]; + + if (s) +{ + GetCurrentDirectory (sizeof (cwdbuf), cwdbuf); + + /* Remove the filename part from s. */ + strncpy (dirnamebuf, s, MAX_PATH); + dirnamebuf[MAX_PATH] = '\0'; // just in case strlen(s) MAX_PATH + char *lastsep = strrchr (dirnamebuf, '\\'); + if (lastsep) +lastsep[1] = '\0'; + SetCurrentDirectory (dirnamebuf); +} + else +SetCurrentDirectory (cwdbuf); +} + // Find a real application on the path (possibly following symlinks) static const char * find_app_on_path (const char *app, bool showall = false) @@ -822,25 +847,27 @@ find_app_on_path (const char *app, bool if (is_symlink (fh)) { static char tmp[4000] = ; - char *ptr; - if (!readlink (fh, tmp, 3999)) + if (!readlink (fh, tmp, sizeof (tmp)-1)) display_error(readlink failed); - ptr = cygpath (tmp, NULL); - for (char *p = ptr; (p = strchr (p, '/')); p++) - *p = '\\'; + + /* When resolving the linkname, set the CWD to the context of + the link, so that relative links are correctly resolved. */ + save_cwd_helper (papp); + char *ptr = cygpath (tmp, NULL); + save_cwd_helper (NULL); printf ( - %s\n, ptr); if (!strchr (ptr, '\\')) { char *lastsep; - strncpy (tmp, cygpath (papp, NULL), 3999); - for (char *p = tmp; (p = strchr (p, '/')); p++) - *p = '\\'; + strncpy (tmp, cygpath (papp, NULL), sizeof (tmp)-1); lastsep = strrchr (tmp, '\\'); - strncpy (lastsep+1, ptr, 3999-(lastsep-tmp)); + strncpy (lastsep+1, ptr, (sizeof (tmp)-1) - (lastsep-tmp)); ptr = tmp; } if (!CloseHandle (fh)) display_error (find_app_on_path: CloseHandle()); + /* FIXME: We leak the ptr returned by cygpath() here which is a + malloc()d string. */ return find_app_on_path (ptr, showall); }