* 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:
Corinna Vinschen 2006-04-26 16:51:09 +00:00
parent 13ac451951
commit 330a2faed9
6 changed files with 124 additions and 95 deletions

View File

@ -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

View File

@ -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)));

View File

@ -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;

View File

@ -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)

View File

@ -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"));

View File

@ -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);