* fhandler.h (fhandler_base): Change fstat_helper prototype
to take file size and inode number as 64 bit values. * fhandler_disk_file.cc (FS_IS_SAMBA): Move to path.cc (FS_IS_SAMBA_WITH_QUOTA): Ditto. (path_conv::hasgood_inode): Delete. (path_conv::is_samba): Delete. (path_conv::isgood_inode): Centralized function to recognize a good inode number. (fhandler_base::fstat_by_handle): Constify fvi_size and fai_size. Accomodate argument change in fstat_helper. (fhandler_base::fstat_by_name): Ditto. (fhandler_base::fstat_helper): Accomodate argument change. Call path_conv::isgood_inode to recognize good inodes. (fhandler_disk_file::opendir): Explain Samba weirdness here. Call path_conv::fs_is_samba instead of path_conv::is_samba. (fhandler_disk_file::readdir): Add STATUS_INVALID_INFO_CLASS as valid return code from NtQueryDirectoryFile to indicate that FileIdBothDirectoryInformation is not supported. Call path_conv::isgood_inode to recognize good inodes. * ntdll.h (STATUS_INVALID_INFO_CLASS): Define. * path.cc (fs_info::update): Rework file system recognition and set appropriate flags. * path.h (struct fs_info): Add is_ntfs, is_samba and is_nfs flags. Constify pure read accessors.
This commit is contained in:
parent
13ac451951
commit
330a2faed9
@ -1,3 +1,30 @@
|
||||
2006-04-26 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* fhandler.h (fhandler_base): Change fstat_helper prototype
|
||||
to take file size and inode number as 64 bit values.
|
||||
* fhandler_disk_file.cc (FS_IS_SAMBA): Move to path.cc
|
||||
(FS_IS_SAMBA_WITH_QUOTA): Ditto.
|
||||
(path_conv::hasgood_inode): Delete.
|
||||
(path_conv::is_samba): Delete.
|
||||
(path_conv::isgood_inode): Centralized function to recognize
|
||||
a good inode number.
|
||||
(fhandler_base::fstat_by_handle): Constify fvi_size and fai_size.
|
||||
Accomodate argument change in fstat_helper.
|
||||
(fhandler_base::fstat_by_name): Ditto.
|
||||
(fhandler_base::fstat_helper): Accomodate argument change. Call
|
||||
path_conv::isgood_inode to recognize good inodes.
|
||||
(fhandler_disk_file::opendir): Explain Samba weirdness here.
|
||||
Call path_conv::fs_is_samba instead of path_conv::is_samba.
|
||||
(fhandler_disk_file::readdir): Add STATUS_INVALID_INFO_CLASS
|
||||
as valid return code from NtQueryDirectoryFile to indicate that
|
||||
FileIdBothDirectoryInformation is not supported.
|
||||
Call path_conv::isgood_inode to recognize good inodes.
|
||||
* ntdll.h (STATUS_INVALID_INFO_CLASS): Define.
|
||||
* path.cc (fs_info::update): Rework file system recognition
|
||||
and set appropriate flags.
|
||||
* path.h (struct fs_info): Add is_ntfs, is_samba and is_nfs flags.
|
||||
Constify pure read accessors.
|
||||
|
||||
2006-04-24 Christopher Faylor <cgf@timesys.com>
|
||||
|
||||
* environ.cc (getearly): Force correct dereference order when
|
||||
|
@ -266,11 +266,9 @@ class fhandler_base
|
||||
FILETIME ftLastAccessTime,
|
||||
FILETIME ftLastWriteTime,
|
||||
DWORD dwVolumeSerialNumber,
|
||||
DWORD nFileSizeHigh,
|
||||
DWORD nFileSizeLow,
|
||||
ULONGLONG nFileSize,
|
||||
LONGLONG nAllocSize,
|
||||
DWORD nFileIndexHigh,
|
||||
DWORD nFileIndexLow,
|
||||
ULONGLONG nFileIndex,
|
||||
DWORD nNumberOfLinks,
|
||||
DWORD dwFileAttributes)
|
||||
__attribute__ ((regparm (3)));
|
||||
|
@ -196,46 +196,15 @@ path_conv::ndisk_links (DWORD nNumberOfLinks)
|
||||
return count + saw_dot;
|
||||
}
|
||||
|
||||
#define FS_IS_SAMBA (FILE_CASE_SENSITIVE_SEARCH \
|
||||
| FILE_CASE_PRESERVED_NAMES \
|
||||
| FILE_PERSISTENT_ACLS)
|
||||
|
||||
#define FS_IS_SAMBA_WITH_QUOTA \
|
||||
(FILE_CASE_SENSITIVE_SEARCH \
|
||||
| FILE_CASE_PRESERVED_NAMES \
|
||||
| FILE_PERSISTENT_ACLS \
|
||||
| FILE_VOLUME_QUOTAS)
|
||||
|
||||
inline bool
|
||||
path_conv::hasgood_inode ()
|
||||
path_conv::isgood_inode (__ino64_t ino) const
|
||||
{
|
||||
/* Assume that if a drive has ACL support it MAY have valid "inodes".
|
||||
It definitely does not have valid inodes if it does not have ACL
|
||||
support. Decouple from has_acls() which follows smbntsec setting. */
|
||||
return ((fs_flags () & FILE_PERSISTENT_ACLS)
|
||||
&& drive_type () != DRIVE_UNKNOWN);
|
||||
}
|
||||
|
||||
inline bool
|
||||
path_conv::is_samba ()
|
||||
{
|
||||
/* Something weird happens on Samba up to version 3.0.21c, which is
|
||||
fixed in 3.0.22. FileIdBothDirectoryInformation seems to work
|
||||
nicely, but only up to the 128th entry in the directory. After
|
||||
reaching this entry, the next call to
|
||||
NtQueryDirectoryFile(FileIdBothDirectoryInformation) returns
|
||||
STATUS_INVAILD_LEVEL. Why should we care, we can just switch to
|
||||
FileBothDirectoryInformation, isn't it? Nope! The next call to
|
||||
NtQueryDirectoryFile(FileBothDirectoryInformation) actually returns
|
||||
STATUS_NO_MORE_FILES, regardless how many files are left unread in
|
||||
the directory. This does not happen when using
|
||||
FileBothDirectoryInformation right from the start. In that case we
|
||||
can read the whole directory unmolested. So we have to excempt
|
||||
Samba from the usage of FileIdBothDirectoryInformation entirely,
|
||||
even though Samba returns valid File IDs. */
|
||||
return drive_type () == DRIVE_REMOTE
|
||||
&& (fs_flags () == FS_IS_SAMBA
|
||||
|| fs_flags () == FS_IS_SAMBA_WITH_QUOTA);
|
||||
/* We can't trust remote inode numbers of only 32 bit. That means,
|
||||
all remote inode numbers when running under NT4, as well as remote NT4
|
||||
NTFS, as well as shares of Samba version < 3.0.
|
||||
The known exception are SFU NFS shares, which return the valid 32 bit
|
||||
inode number from the remote file system unchanged. */
|
||||
return hasgood_inode () && (ino > UINT32_MAX || !isremote () || fs_is_nfs ());
|
||||
}
|
||||
|
||||
int __stdcall
|
||||
@ -248,8 +217,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||
NTSTATUS status;
|
||||
IO_STATUS_BLOCK io;
|
||||
/* The entries potentially contain a name of MAX_PATH wide characters. */
|
||||
DWORD fvi_size = 2 * CYG_MAX_PATH + sizeof (FILE_FS_VOLUME_INFORMATION);
|
||||
DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
|
||||
const DWORD fvi_size = 2 * CYG_MAX_PATH
|
||||
+ sizeof (FILE_FS_VOLUME_INFORMATION);
|
||||
const DWORD fai_size = 2 * CYG_MAX_PATH + sizeof (FILE_ALL_INFORMATION);
|
||||
|
||||
PFILE_FS_VOLUME_INFORMATION pfvi = (PFILE_FS_VOLUME_INFORMATION)
|
||||
alloca (fvi_size);
|
||||
@ -278,11 +248,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||
*(FILETIME *) &pfai->BasicInformation.LastAccessTime,
|
||||
*(FILETIME *) &pfai->BasicInformation.LastWriteTime,
|
||||
pfvi->VolumeSerialNumber,
|
||||
pfai->StandardInformation.EndOfFile.HighPart,
|
||||
pfai->StandardInformation.EndOfFile.LowPart,
|
||||
pfai->StandardInformation.EndOfFile.QuadPart,
|
||||
pfai->StandardInformation.AllocationSize.QuadPart,
|
||||
pfai->InternalInformation.FileId.HighPart,
|
||||
pfai->InternalInformation.FileId.LowPart,
|
||||
pfai->InternalInformation.FileId.QuadPart,
|
||||
pfai->StandardInformation.NumberOfLinks,
|
||||
pfai->BasicInformation.FileAttributes);
|
||||
}
|
||||
@ -313,11 +281,11 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf)
|
||||
local.ftLastAccessTime,
|
||||
local.ftLastWriteTime,
|
||||
local.dwVolumeSerialNumber,
|
||||
local.nFileSizeHigh,
|
||||
local.nFileSizeLow,
|
||||
(ULONGLONG) local.nFileSizeHigh << 32
|
||||
| local.nFileSizeLow,
|
||||
-1LL,
|
||||
local.nFileIndexHigh,
|
||||
local.nFileIndexLow,
|
||||
(ULONGLONG) local.nFileIndexHigh << 32
|
||||
| local.nFileIndexLow,
|
||||
local.nNumberOfLinks,
|
||||
local.dwFileAttributes);
|
||||
}
|
||||
@ -344,18 +312,17 @@ fhandler_base::fstat_by_name (struct __stat64 *buf)
|
||||
local.ftLastAccessTime,
|
||||
local.ftLastWriteTime,
|
||||
pc.volser (),
|
||||
local.nFileSizeHigh,
|
||||
local.nFileSizeLow,
|
||||
(ULONGLONG) local.nFileSizeHigh << 32
|
||||
| local.nFileSizeLow,
|
||||
-1LL,
|
||||
0,
|
||||
0,
|
||||
0ULL,
|
||||
1,
|
||||
local.dwFileAttributes);
|
||||
}
|
||||
else if (pc.isdir ())
|
||||
{
|
||||
FILETIME ft = {};
|
||||
res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0, 0, -1LL, 0, 0, 1,
|
||||
res = fstat_helper (buf, ft, ft, ft, pc.volser (), 0ULL, -1LL, 0ULL, 1,
|
||||
FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
else
|
||||
@ -433,11 +400,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
|
||||
FILETIME ftLastAccessTime,
|
||||
FILETIME ftLastWriteTime,
|
||||
DWORD dwVolumeSerialNumber,
|
||||
DWORD nFileSizeHigh,
|
||||
DWORD nFileSizeLow,
|
||||
ULONGLONG nFileSize,
|
||||
LONGLONG nAllocSize,
|
||||
DWORD nFileIndexHigh,
|
||||
DWORD nFileIndexLow,
|
||||
ULONGLONG nFileIndex,
|
||||
DWORD nNumberOfLinks,
|
||||
DWORD dwFileAttributes)
|
||||
{
|
||||
@ -448,7 +413,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
|
||||
to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
|
||||
to_timestruc_t (&ftChangeTime, &buf->st_ctim);
|
||||
buf->st_dev = dwVolumeSerialNumber ?: pc.volser ();
|
||||
buf->st_size = ((_off64_t) nFileSizeHigh << 32) + nFileSizeLow;
|
||||
buf->st_size = (_off64_t) nFileSize;
|
||||
/* The number of links to a directory includes the
|
||||
number of subdirectories in the directory, since all
|
||||
those subdirectories point to it.
|
||||
@ -457,12 +422,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
|
||||
let's try it with `1' as link count. */
|
||||
buf->st_nlink = pc.ndisk_links (nNumberOfLinks);
|
||||
|
||||
/* We can't trust remote inode numbers of only 32 bit. That means,
|
||||
all remote inode numbers when running under NT4, as well as remote NT4
|
||||
NTFS, as well as shares of Samba version < 3.0. */
|
||||
if (pc.hasgood_inode () && (nFileIndexHigh || !pc.isremote ()))
|
||||
buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
|
||||
| (__ino64_t) nFileIndexLow;
|
||||
/* Enforce namehash as inode number on untrusted file systems. */
|
||||
if (pc.isgood_inode (nFileIndex))
|
||||
buf->st_ino = (__ino64_t) nFileIndex;
|
||||
else
|
||||
buf->st_ino = get_namehash ();
|
||||
|
||||
@ -1586,7 +1548,23 @@ fhandler_disk_file::opendir ()
|
||||
if (pc.hasgood_inode ())
|
||||
{
|
||||
dir->__flags |= dirent_set_d_ino;
|
||||
if (wincap.has_fileid_dirinfo () && !pc.is_samba ())
|
||||
/* Something weird happens on Samba up to version 3.0.21c,
|
||||
which is fixed in 3.0.22. FileIdBothDirectoryInformation
|
||||
seems to work nicely, but only up to the 128th entry in
|
||||
the directory. After reaching this entry, the next call
|
||||
to NtQueryDirectoryFile(FileIdBothDirectoryInformation)
|
||||
returns STATUS_INVALID_LEVEL. Why should we care, we can
|
||||
just switch to FileBothDirectoryInformation, isn't it?
|
||||
Nope! The next call to
|
||||
NtQueryDirectoryFile(FileBothDirectoryInformation)
|
||||
actually returns STATUS_NO_MORE_FILES, regardless how
|
||||
many files are left unread in the directory. This does
|
||||
not happen when using FileBothDirectoryInformation right
|
||||
from the start. In that case we can read the whole
|
||||
directory unmolested. So we have to excempt Samba from
|
||||
the usage of FileIdBothDirectoryInformation entirely,
|
||||
even though Samba returns valid File IDs. */
|
||||
if (wincap.has_fileid_dirinfo () && !pc.fs_is_samba ())
|
||||
dir->__flags |= dirent_get_d_ino;
|
||||
}
|
||||
}
|
||||
@ -1736,7 +1714,8 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
|
||||
back to using a standard directory query in this case and note
|
||||
this case using the dirent_get_d_ino flag. */
|
||||
if (status == STATUS_INVALID_LEVEL
|
||||
|| status == STATUS_INVALID_PARAMETER)
|
||||
|| status == STATUS_INVALID_PARAMETER
|
||||
|| status == STATUS_INVALID_INFO_CLASS)
|
||||
dir->__flags &= ~dirent_get_d_ino;
|
||||
}
|
||||
if (!(dir->__flags & dirent_get_d_ino))
|
||||
@ -1788,10 +1767,8 @@ fhandler_disk_file::readdir (DIR *dir, dirent *de)
|
||||
CloseHandle (hdl);
|
||||
}
|
||||
}
|
||||
/* We can't trust remote inode numbers of only 32 bit. That means,
|
||||
all remote inode numbers when running under NT4, as well as
|
||||
remote NT4 NTFS, as well as shares of Samba version < 3.0. */
|
||||
if (de->d_ino <= UINT32_MAX && pc.isremote ())
|
||||
/* Enforce namehash as inode number on untrusted file systems. */
|
||||
if (!pc.isgood_inode (de->d_ino))
|
||||
{
|
||||
dir->__flags &= ~dirent_set_d_ino;
|
||||
de->d_ino = 0;
|
||||
|
@ -8,6 +8,7 @@
|
||||
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
||||
details. */
|
||||
|
||||
#define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xc0000003)
|
||||
#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004)
|
||||
#define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xc000000d)
|
||||
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023)
|
||||
|
@ -423,15 +423,26 @@ fs_info::update (const char *win32_path)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* FIXME: Samba by default returns "NTFS" in file system name, but
|
||||
* doesn't support Extended Attributes. If there's some fast way to
|
||||
* distinguish between samba and real ntfs, it should be implemented
|
||||
* here.
|
||||
*/
|
||||
has_ea (!is_remote_drive () && strcmp (fsname, "NTFS") == 0);
|
||||
#define FS_IS_SAMBA (FILE_CASE_SENSITIVE_SEARCH \
|
||||
| FILE_CASE_PRESERVED_NAMES \
|
||||
| FILE_PERSISTENT_ACLS)
|
||||
#define FS_IS_SAMBA_WITH_QUOTA \
|
||||
(FILE_CASE_SENSITIVE_SEARCH \
|
||||
| FILE_CASE_PRESERVED_NAMES \
|
||||
| FILE_PERSISTENT_ACLS \
|
||||
| FILE_VOLUME_QUOTAS)
|
||||
is_fat (strncasematch (fsname, "FAT", 3));
|
||||
is_samba (strcmp (fsname, "NTFS") == 0 && is_remote_drive ()
|
||||
&& (flags () == FS_IS_SAMBA || flags () == FS_IS_SAMBA_WITH_QUOTA));
|
||||
is_ntfs (strcmp (fsname, "NTFS") == 0 && !is_samba ());
|
||||
is_nfs (strcmp (fsname, "NFS") == 0);
|
||||
|
||||
has_ea (is_ntfs ());
|
||||
has_acls ((flags () & FS_PERSISTENT_ACLS)
|
||||
&& (allow_smbntsec || !is_remote_drive ()));
|
||||
is_fat (strncasematch (fsname, "FAT", 3));
|
||||
hasgood_inode (((flags () & FILE_PERSISTENT_ACLS)
|
||||
&& drive_type () != DRIVE_UNKNOWN)
|
||||
|| is_nfs ());
|
||||
/* Known file systems with buggy open calls. Further explanation
|
||||
in fhandler.cc (fhandler_disk_file::open). */
|
||||
has_buggy_open (!strcmp (fsname, "SUNWNFS"));
|
||||
|
@ -92,8 +92,12 @@ struct fs_info
|
||||
unsigned has_buggy_open : 1;
|
||||
unsigned has_ea : 1;
|
||||
unsigned has_acls : 1;
|
||||
unsigned is_fat : 1;
|
||||
unsigned hasgood_inode : 1;
|
||||
unsigned drive_type : 3;
|
||||
unsigned is_fat : 1;
|
||||
unsigned is_ntfs : 1;
|
||||
unsigned is_samba : 1;
|
||||
unsigned is_nfs : 1;
|
||||
} status;
|
||||
public:
|
||||
void clear ()
|
||||
@ -104,18 +108,26 @@ struct fs_info
|
||||
has_buggy_open (false);
|
||||
has_ea (false);
|
||||
has_acls (false);
|
||||
is_fat (false);
|
||||
hasgood_inode (false);
|
||||
drive_type (false);
|
||||
is_fat (false);
|
||||
is_ntfs (false);
|
||||
is_samba (false);
|
||||
is_nfs (false);
|
||||
}
|
||||
inline DWORD& flags () {return status.flags;};
|
||||
inline DWORD& serial () {return status.serial;};
|
||||
|
||||
IMPLEMENT_STATUS_FLAG (bool, is_remote_drive)
|
||||
IMPLEMENT_STATUS_FLAG (bool, has_buggy_open)
|
||||
IMPLEMENT_STATUS_FLAG (bool, is_fat)
|
||||
IMPLEMENT_STATUS_FLAG (bool, has_ea)
|
||||
IMPLEMENT_STATUS_FLAG (bool, has_acls)
|
||||
IMPLEMENT_STATUS_FLAG (bool, hasgood_inode)
|
||||
IMPLEMENT_STATUS_FLAG (DWORD, drive_type)
|
||||
IMPLEMENT_STATUS_FLAG (bool, is_fat)
|
||||
IMPLEMENT_STATUS_FLAG (bool, is_ntfs)
|
||||
IMPLEMENT_STATUS_FLAG (bool, is_samba)
|
||||
IMPLEMENT_STATUS_FLAG (bool, is_nfs)
|
||||
|
||||
bool update (const char *);
|
||||
};
|
||||
@ -133,13 +145,13 @@ class path_conv
|
||||
device dev;
|
||||
bool case_clash;
|
||||
|
||||
bool isremote () {return fs.is_remote_drive ();}
|
||||
int has_acls () const {return fs.has_acls (); }
|
||||
bool isremote () const {return fs.is_remote_drive ();}
|
||||
bool has_acls () const {return fs.has_acls (); }
|
||||
bool hasgood_inode () const {return fs.hasgood_inode (); }
|
||||
bool isgood_inode (__ino64_t ino) const;
|
||||
int has_symlinks () const {return path_flags & PATH_HAS_SYMLINKS;}
|
||||
bool hasgood_inode (); /* Implemented in fhandler_disk_file.cc */
|
||||
bool is_samba (); /* Implemented in fhandler_disk_file.cc */
|
||||
int has_buggy_open () const {return fs.has_buggy_open ();}
|
||||
bool isencoded () {return path_flags & PATH_ENC;}
|
||||
bool isencoded () const {return path_flags & PATH_ENC;}
|
||||
int binmode () const
|
||||
{
|
||||
if (path_flags & PATH_BINARY)
|
||||
@ -222,14 +234,17 @@ class path_conv
|
||||
operator DWORD &() {return fileattr;}
|
||||
operator int () {return fileattr; }
|
||||
char operator [](int i) const {return path[i];}
|
||||
DWORD get_devn () {return dev.devn;}
|
||||
short get_unitn () {return dev.minor;}
|
||||
DWORD file_attributes () {return fileattr;}
|
||||
DWORD get_devn () const {return dev.devn;}
|
||||
short get_unitn () const {return dev.minor;}
|
||||
DWORD file_attributes () const {return fileattr;}
|
||||
void file_attributes (DWORD new_attr) {fileattr = new_attr;}
|
||||
DWORD drive_type () {return fs.drive_type ();}
|
||||
DWORD drive_type () const {return fs.drive_type ();}
|
||||
DWORD fs_flags () {return fs.flags ();}
|
||||
bool fs_has_ea () {return fs.has_ea ();}
|
||||
bool fs_is_fat () {return fs.is_fat ();}
|
||||
bool fs_has_ea () const {return fs.has_ea ();}
|
||||
bool fs_is_fat () const {return fs.is_fat ();}
|
||||
bool fs_is_ntfs () const {return fs.is_ntfs ();}
|
||||
bool fs_is_samba () const {return fs.is_samba ();}
|
||||
bool fs_is_nfs () const {return fs.is_nfs ();}
|
||||
void set_path (const char *p) {strcpy (path, p);}
|
||||
DWORD volser () { return fs.serial (); }
|
||||
void fillin (HANDLE h);
|
||||
|
Loading…
Reference in New Issue
Block a user