summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/path.cc
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2010-04-22 17:33:28 +0000
committerCorinna Vinschen <corinna@vinschen.de>2010-04-22 17:33:28 +0000
commit6ff06a072611d796f40e03dd2af6abad582b341f (patch)
treee83285a1086bc2eacc2ebdb9bc5dbacfc9e6868a /winsup/cygwin/path.cc
parentc43e19442c9bb0d0ed9addff635972f62cef77cf (diff)
downloadcygnal-6ff06a072611d796f40e03dd2af6abad582b341f.tar.gz
cygnal-6ff06a072611d796f40e03dd2af6abad582b341f.tar.bz2
cygnal-6ff06a072611d796f40e03dd2af6abad582b341f.zip
* mount.cc (GETVOLINFO_VALID_MASK): Drop FILE_SEQUENTIAL_WRITE_ONCE
from mask. Expand the comment a bit. (WIN_FAT_FLAGS): New define. (FS_IS_WINDOWS_FAT): New macro. (fs_info::update): Handle remote FS faking to be FAT. Subsume under CIFS. Check for NWFS and has_buggy_basic_info only for remote filesystems. Add check for has_dos_filenames_only. * mount.h (class fs_info): Add has_dos_filenames_only status flag. Implement accessors. * path.cc (symlink_info::check): Rearrange variable definitions to clear them up. Add a restart label to allow a clean restart within the method. Add a check for broken filesystems only allowing DOS pathnames in case we encounter a STATUS_OBJECT_NAME_NOT_FOUND status. If all checks point to one of that, restart method with tweaked incoming path. Add lengthy comments to explain what we do.
Diffstat (limited to 'winsup/cygwin/path.cc')
-rw-r--r--winsup/cygwin/path.cc121
1 files changed, 83 insertions, 38 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index 2401ce163..3163f9e61 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -2170,39 +2170,46 @@ int
symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt,
fs_info &fs)
{
- HANDLE h = NULL;
- int res = 0;
+ int res;
+ HANDLE h;
+ NTSTATUS status;
+ UNICODE_STRING upath;
+ OBJECT_ATTRIBUTES attr;
+ IO_STATUS_BLOCK io;
+ FILE_BASIC_INFORMATION fbi;
suffix_scan suffix;
- contents[0] = '\0';
- issymlink = true;
- isdevice = false;
- ext_here = suffix.has (path, suffixes);
- extn = ext_here - path;
- major = 0;
- minor = 0;
- mode = 0;
- pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
ULONG ci_flag = cygwin_shared->obcaseinsensitive || (pflags & PATH_NOPOSIX)
? OBJ_CASE_INSENSITIVE : 0;
-
/* TODO: Temporarily do all char->UNICODE conversion here. This should
already be slightly faster than using Ascii functions. */
tmp_pathbuf tp;
- UNICODE_STRING upath;
- OBJECT_ATTRIBUTES attr;
tp.u_get (&upath);
InitializeObjectAttributes (&attr, &upath, ci_flag, NULL, NULL);
+ /* This label is used in case we encounter a FS which only handles
+ DOS paths. See below. */
+restart:
+
+ h = NULL;
+ res = 0;
+ contents[0] = '\0';
+ issymlink = true;
+ isdevice = false;
+ major = 0;
+ minor = 0;
+ mode = 0;
+ pflags &= ~(PATH_SYMLINK | PATH_LNK | PATH_REP);
+
+ ext_here = suffix.has (path, suffixes);
+ extn = ext_here - path;
+
PVOID eabuf = &nfs_aol_ffei;
ULONG easize = sizeof nfs_aol_ffei;
bool had_ext = !!*ext_here;
while (suffix.next ())
{
- FILE_BASIC_INFORMATION fbi;
- NTSTATUS status;
- IO_STATUS_BLOCK io;
bool no_ea = false;
bool fs_update_called = false;
@@ -2251,28 +2258,66 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt,
| FILE_OPEN_FOR_BACKUP_INTENT);
debug_printf ("%p = NtOpenFile (no-EA, %S)", status, &upath);
}
- if (status == STATUS_OBJECT_NAME_NOT_FOUND && ci_flag == 0
- && wincap.has_broken_udf ())
- {
- /* On NT 5.x UDF is broken (at least) in terms of case sensitivity.
- When trying to open a file case sensitive, the file appears to be
- non-existant. Another bug is described in fs_info::update. */
- attr.Attributes = OBJ_CASE_INSENSITIVE;
- status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
- &attr, &io, FILE_SHARE_VALID_FLAGS,
- FILE_OPEN_REPARSE_POINT
- | FILE_OPEN_FOR_BACKUP_INTENT);
- debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
- attr.Attributes = 0;
- if (NT_SUCCESS (status))
+ if (status == STATUS_OBJECT_NAME_NOT_FOUND)
+ {
+ if (ci_flag == 0 && wincap.has_broken_udf ())
{
- fs.update (&upath, h);
- if (fs.is_udf ())
- fs_update_called = true;
- else
- {
- NtClose (h);
- status = STATUS_OBJECT_NAME_NOT_FOUND;
+ /* On NT 5.x UDF is broken (at least) in terms of case
+ sensitivity. When trying to open a file case sensitive,
+ the file appears to be non-existant. Another bug is
+ described in fs_info::update. */
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES,
+ &attr, &io, FILE_SHARE_VALID_FLAGS,
+ FILE_OPEN_REPARSE_POINT
+ | FILE_OPEN_FOR_BACKUP_INTENT);
+ debug_printf ("%p = NtOpenFile (broken-UDF, %S)", status, &upath);
+ attr.Attributes = 0;
+ if (NT_SUCCESS (status))
+ {
+ fs.update (&upath, h);
+ if (fs.is_udf ())
+ fs_update_called = true;
+ else
+ {
+ NtClose (h);
+ status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ }
+ }
+ /* There are filesystems out in the wild (Netapp, NWFS, and others)
+ which are uncapable of generating pathnames outside the Win32
+ rules. That means, filenames on these FSes must not have a
+ leading space or trailing dots and spaces. This code snippet
+ manages them. I really hope it's streamlined enough not to
+ slow down normal operation. This extra check only kicks in if
+ we encountered a STATUS_OBJECT_NAME_NOT_FOUND *and* we didn't
+ already attach a suffix *and* the above special case for UDF
+ on XP didn't succeeed. */
+ if (!*ext_here && !fs_update_called)
+ {
+ /* Check for leading space or trailing dot or space in
+ last component. */
+ char *pend = ext_here;
+ while (pend[-1] == '.' || pend[-1] == ' ')
+ --pend;
+ char *pbeg = pend;
+ while (pbeg[-1] != '\\')
+ --pbeg;
+ /* If so, call fs.update to check if the filesystem is one of
+ the broken ones. */
+ if ((*pbeg == ' ' || *pend != '\0')
+ && fs.update (&upath, NULL)
+ && fs.has_dos_filenames_only ())
+ {
+ /* If so, strip leading spaces and trailing dots and spaces
+ from filename and... */
+ if (pbeg)
+ while (*pbeg == ' ')
+ memmove (pbeg, pbeg + 1, --pend - pbeg);
+ *pend = '\0';
+ /* ...try again. */
+ goto restart;
}
}
}