* 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.
This commit is contained in:
parent
c43e19442c
commit
6ff06a0726
|
@ -1,3 +1,21 @@
|
|||
2010-04-22 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* 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.
|
||||
|
||||
2010-04-22 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* path.cc (symlink_info::check): Fix a comment.
|
||||
|
|
|
@ -208,9 +208,12 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
|
|||
/* Should be reevaluated for each new OS. Right now this mask is valid up
|
||||
to Vista. The important point here is to test only flags indicating
|
||||
capabilities and to ignore flags indicating a specific state of this
|
||||
volume. At present these flags to ignore are FILE_VOLUME_IS_COMPRESSED
|
||||
and FILE_READ_ONLY_VOLUME. */
|
||||
#define GETVOLINFO_VALID_MASK (0x003701ffUL)
|
||||
volume. At present these flags to ignore are FILE_VOLUME_IS_COMPRESSED,
|
||||
FILE_READ_ONLY_VOLUME, and FILE_SEQUENTIAL_WRITE_ONCE. The additional
|
||||
filesystem flags supported since Windows 7 are also ignored for now.
|
||||
They add information, but only on W7 and later, and only for filesystems
|
||||
also supporting these flags, right now only NTFS. */
|
||||
#define GETVOLINFO_VALID_MASK (0x002701ffUL)
|
||||
#define TEST_GVI(f,m) (((f) & GETVOLINFO_VALID_MASK) == (m))
|
||||
|
||||
/* FIXME: This flag twist is getting awkward. There should really be some
|
||||
|
@ -244,6 +247,11 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
|
|||
| FILE_FILE_COMPRESSION)
|
||||
#define FS_IS_WINDOWS_NTFS TEST_GVI(flags () & MINIMAL_WIN_NTFS_FLAGS, \
|
||||
MINIMAL_WIN_NTFS_FLAGS)
|
||||
/* These are the exact flags of a real Windows FAT/FAT32 filesystem.
|
||||
Anything else is a filesystem faking to be FAT. */
|
||||
#define WIN_FAT_FLAGS (FILE_CASE_PRESERVED_NAMES | FILE_UNICODE_ON_DISK)
|
||||
#define FS_IS_WINDOWS_FAT TEST_GVI(flags (), WIN_FAT_FLAGS)
|
||||
|
||||
/* This always fails on NT4. */
|
||||
status = NtQueryVolumeInformationFile (vol, &io, &ffoi, sizeof ffoi,
|
||||
FileFsObjectIdInformation);
|
||||
|
@ -266,6 +274,11 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
|
|||
&& !is_netapp (FS_IS_NETAPP_DATAONTAP))
|
||||
/* Any other remote FS faking to be NTFS. */
|
||||
is_cifs (!FS_IS_WINDOWS_NTFS);
|
||||
/* Then check the remote filesystems faking to be FAT. Right now all
|
||||
of them are subsumed under the "CIFS" filesystem type. */
|
||||
if (!got_fs ()
|
||||
&& is_fat (RtlEqualUnicodePathPrefix (&fsname, &ro_u_fat, TRUE)))
|
||||
is_cifs (!FS_IS_WINDOWS_FAT);
|
||||
/* Then check remote filesystems honest about their name. */
|
||||
if (!got_fs ()
|
||||
/* Microsoft NFS needs distinct access methods for metadata. */
|
||||
|
@ -274,6 +287,8 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
|
|||
drawbacks, like not supporting DOS attributes other than R/O
|
||||
and stuff like that. */
|
||||
&& !is_mvfs (RtlEqualUnicodePathPrefix (&fsname, &ro_u_mvfs, FALSE))
|
||||
/* NWFS == Novell Netware FS. Broken info class, see below. */
|
||||
&& !is_nwfs (RtlEqualUnicodeString (&fsname, &ro_u_nwfs, FALSE))
|
||||
/* Known remote file system which can't handle calls to
|
||||
NtQueryDirectoryFile(FileIdBothDirectoryInformation) */
|
||||
&& !is_unixfs (RtlEqualUnicodeString (&fsname, &ro_u_unixfs, FALSE)))
|
||||
|
@ -283,18 +298,31 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
|
|||
is_sunwnfs (RtlEqualUnicodeString (&fsname, &ro_u_sunwnfs, FALSE));
|
||||
has_buggy_open (is_sunwnfs ());
|
||||
}
|
||||
/* Not only UNIXFS is known to choke on FileIdBothDirectoryInformation.
|
||||
Some other CIFS servers have problems with this call as well.
|
||||
Know example: EMC NS-702. We just don't use that info class on
|
||||
any remote CIFS. */
|
||||
if (got_fs ())
|
||||
has_buggy_fileid_dirinfo (is_cifs () || is_unixfs ());
|
||||
{
|
||||
/* UNIXFS is known to choke on FileIdBothDirectoryInformation.
|
||||
Some other CIFS servers have problems with this call as well.
|
||||
Know example: EMC NS-702. We just don't use that info class on
|
||||
any remote CIFS. */
|
||||
has_buggy_fileid_dirinfo (is_cifs () || is_unixfs ());
|
||||
/* NWFS is known to have a broken FileBasicInformation info class.
|
||||
It can't be used to fetch information, only to set information.
|
||||
Therefore, for NWFS we have to fallback to the
|
||||
FileNetworkOpenInformation info class. Unfortunately we can't
|
||||
use FileNetworkOpenInformation all the time since that fails on
|
||||
other filesystems like NFS. */
|
||||
has_buggy_basic_info (is_nwfs ());
|
||||
/* Netapp ans NWFS are too dumb to allow non-DOS filesystems
|
||||
containing trailing dots and spaces when accessed from Windows
|
||||
clients. We subsume CIFS into this class of filesystems right
|
||||
away since at least some of them are not capable either. */
|
||||
has_dos_filenames_only (is_netapp () || is_nwfs () || is_cifs ());
|
||||
}
|
||||
}
|
||||
if (!got_fs ()
|
||||
&& !is_ntfs (RtlEqualUnicodeString (&fsname, &ro_u_ntfs, FALSE))
|
||||
&& !is_fat (RtlEqualUnicodePathPrefix (&fsname, &ro_u_fat, TRUE))
|
||||
&& !is_csc_cache (RtlEqualUnicodeString (&fsname, &ro_u_csc, FALSE))
|
||||
&& !is_nwfs (RtlEqualUnicodeString (&fsname, &ro_u_nwfs, FALSE))
|
||||
&& is_cdrom (ffdi.DeviceType == FILE_DEVICE_CD_ROM))
|
||||
is_udf (RtlEqualUnicodeString (&fsname, &ro_u_udf, FALSE));
|
||||
if (!got_fs ())
|
||||
|
@ -308,12 +336,6 @@ fs_info::update (PUNICODE_STRING upath, HANDLE in_vol)
|
|||
has_acls (flags () & FS_PERSISTENT_ACLS);
|
||||
/* Netapp inode numbers are fly-by-night. */
|
||||
hasgood_inode ((has_acls () && !is_netapp ()) || is_nfs ());
|
||||
/* NWFS is known to have a broken FileBasicInformation info class. It
|
||||
can't be used to fetch information, only to set information. Therefore,
|
||||
for NWFS we have to fallback to the FileNetworkOpenInformation info
|
||||
class. Unfortunately we can't use FileNetworkOpenInformation all the
|
||||
time since that fails on other filesystems like NFS. */
|
||||
has_buggy_basic_info (is_nwfs ());
|
||||
/* Case sensitivity is supported if FILE_CASE_SENSITIVE_SEARCH is set,
|
||||
except on Samba which handles Windows clients case insensitive.
|
||||
|
||||
|
|
|
@ -51,6 +51,7 @@ class fs_info
|
|||
unsigned has_buggy_open : 1;
|
||||
unsigned has_buggy_fileid_dirinfo : 1;
|
||||
unsigned has_buggy_basic_info : 1;
|
||||
unsigned has_dos_filenames_only : 1;
|
||||
} status;
|
||||
ULONG sernum; /* Volume Serial Number */
|
||||
char fsn[80]; /* Windows filesystem name */
|
||||
|
@ -75,6 +76,7 @@ class fs_info
|
|||
IMPLEMENT_STATUS_FLAG (bool, has_buggy_open)
|
||||
IMPLEMENT_STATUS_FLAG (bool, has_buggy_fileid_dirinfo)
|
||||
IMPLEMENT_STATUS_FLAG (bool, has_buggy_basic_info)
|
||||
IMPLEMENT_STATUS_FLAG (bool, has_dos_filenames_only)
|
||||
IMPLEMENT_FS_FLAG (is_fat, fat)
|
||||
IMPLEMENT_FS_FLAG (is_ntfs, ntfs)
|
||||
IMPLEMENT_FS_FLAG (is_samba, samba)
|
||||
|
|
|
@ -2170,29 +2170,39 @@ 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';
|
||||
|
||||
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;
|
||||
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;
|
||||
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);
|
||||
ext_here = suffix.has (path, suffixes);
|
||||
extn = ext_here - path;
|
||||
|
||||
PVOID eabuf = &nfs_aol_ffei;
|
||||
ULONG easize = sizeof nfs_aol_ffei;
|
||||
|
@ -2200,9 +2210,6 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt,
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue