diff options
author | Christopher Faylor <me@cgf.cx> | 2008-12-25 15:55:31 +0000 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2008-12-25 15:55:31 +0000 |
commit | 5829832825e44ecd7fd35e36867d54ee3acced3c (patch) | |
tree | 33f2ad6d8dca0a99a8e30fe615f7f212b03ddb3c /winsup/cygwin/mount.cc | |
parent | 58402a3f63a23a8706c5dc58305c06b3df228170 (diff) | |
download | cygnal-5829832825e44ecd7fd35e36867d54ee3acced3c.tar.gz cygnal-5829832825e44ecd7fd35e36867d54ee3acced3c.tar.bz2 cygnal-5829832825e44ecd7fd35e36867d54ee3acced3c.zip |
* mount.cc: Change comment.
(smb_extended_info): Move here from path.cc.
(fs_info::update): Ditto.
(mount_info::create_root_entry): Delay conversion to slashes and use passed in
buffer to figure out fs type.
* path.cc (smb_extended_info): Move.
(fs_info::update): Ditto.
* mount.h: New file. Move mount information here.
* path.h: (fs_info::update): Move.
* shared_info.h (mount_item): Ditto.
Diffstat (limited to 'winsup/cygwin/mount.cc')
-rw-r--r-- | winsup/cygwin/mount.cc | 205 |
1 files changed, 201 insertions, 4 deletions
diff --git a/winsup/cygwin/mount.cc b/winsup/cygwin/mount.cc index 2768ce53c..34b7b72ff 100644 --- a/winsup/cygwin/mount.cc +++ b/winsup/cygwin/mount.cc @@ -1,4 +1,4 @@ -/* path.cc: path support. +/* mount.cc: mount handling. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. @@ -13,6 +13,7 @@ details. */ #include "miscfuncs.h" #include <mntent.h> #include <ctype.h> +#include <winioctl.h> #include <wingdi.h> #include <winuser.h> #include <winnetwk.h> @@ -21,10 +22,10 @@ details. */ #include "cygerrno.h" #include "security.h" #include "path.h" +#include "shared_info.h" #include "fhandler.h" #include "dtable.h" #include "cygheap.h" -#include "shared_info.h" #include "cygtls.h" #include "tls_pbuf.h" #include <ntdll.h> @@ -82,6 +83,201 @@ win32_device_name (const char *src_path, char *win32_path, device& dev) return true; } +/* Beginning with Samba 3.0.28a, Samba allows to get version information using + the ExtendedInfo member returned by a FileFsObjectIdInformation request. + We just store the samba_version information for now. Older versions than + 3.2 are still guessed at by testing the file system flags. */ +#define SAMBA_EXTENDED_INFO_MAGIC 0x536d4261 /* "SmBa" */ +#define SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH 28 +#pragma pack(push,4) +struct smb_extended_info { + DWORD samba_magic; /* Always SAMBA_EXTENDED_INFO_MAGIC */ + DWORD samba_version; /* Major/Minor/Release/Revision */ + DWORD samba_subversion; /* Prerelease/RC/Vendor patch */ + LARGE_INTEGER samba_gitcommitdate; + char samba_version_string[SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH]; +}; +#pragma pack(pop) + +bool +fs_info::update (PUNICODE_STRING upath, HANDLE in_vol) +{ + NTSTATUS status = STATUS_OBJECT_NAME_NOT_FOUND; + HANDLE vol; + OBJECT_ATTRIBUTES attr; + IO_STATUS_BLOCK io; + bool no_media = false; + FILE_FS_DEVICE_INFORMATION ffdi; + FILE_FS_OBJECTID_INFORMATION ffoi; + struct { + FILE_FS_ATTRIBUTE_INFORMATION ffai; + WCHAR buf[NAME_MAX + 1]; + } ffai_buf; + struct { + FILE_FS_VOLUME_INFORMATION ffvi; + WCHAR buf[NAME_MAX + 1]; + } ffvi_buf; + UNICODE_STRING fsname, testname; + + clear (); + if (in_vol) + vol = in_vol; + else + { + /* Always caseinsensitive. We really just need access to the drive. */ + InitializeObjectAttributes (&attr, upath, OBJ_CASE_INSENSITIVE, NULL, + NULL); + status = NtOpenFile (&vol, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, FILE_OPEN_FOR_BACKUP_INTENT); + while (!NT_SUCCESS (status) + && (attr.ObjectName->Length > 7 * sizeof (WCHAR) + || status == STATUS_NO_MEDIA_IN_DEVICE)) + { + UNICODE_STRING dir; + RtlSplitUnicodePath (attr.ObjectName, &dir, NULL); + attr.ObjectName = &dir; + if (status == STATUS_NO_MEDIA_IN_DEVICE) + { + no_media = true; + dir.Length = 6 * sizeof (WCHAR); + } + else if (dir.Length > 7 * sizeof (WCHAR)) + dir.Length -= sizeof (WCHAR); + status = NtOpenFile (&vol, READ_CONTROL, &attr, &io, + FILE_SHARE_VALID_FLAGS, + FILE_OPEN_FOR_BACKUP_INTENT); + } + if (!NT_SUCCESS (status)) + { + debug_printf ("Cannot access path %S, status %08lx", + attr.ObjectName, status); + NtClose (vol); + return false; + } + } + + status = NtQueryVolumeInformationFile (vol, &io, &ffvi_buf.ffvi, + sizeof ffvi_buf, + FileFsVolumeInformation); + sernum = NT_SUCCESS (status) ? ffvi_buf.ffvi.VolumeSerialNumber : 0; + status = NtQueryVolumeInformationFile (vol, &io, &ffdi, sizeof ffdi, + FileFsDeviceInformation); + if (!NT_SUCCESS (status)) + ffdi.DeviceType = ffdi.Characteristics = 0; + + if (ffdi.Characteristics & FILE_REMOTE_DEVICE + || (!ffdi.DeviceType + && RtlEqualUnicodePathPrefix (attr.ObjectName, L"\\??\\UNC\\", TRUE))) + is_remote_drive (true); + else + is_remote_drive (false); + + if (!no_media) + status = NtQueryVolumeInformationFile (vol, &io, &ffai_buf.ffai, + sizeof ffai_buf, + FileFsAttributeInformation); + if (no_media || !NT_SUCCESS (status)) + { + debug_printf ("Cannot get volume attributes (%S), %08lx", + attr.ObjectName, status); + if (!in_vol) + NtClose (vol); + return false; + } + flags (ffai_buf.ffai.FileSystemAttributes); + name_len (ffai_buf.ffai.MaximumComponentNameLength); +/* 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) +#define TEST_GVI(f,m) (((f) & GETVOLINFO_VALID_MASK) == (m)) + +/* Volume quotas are potentially supported since Samba 3.0, object ids and + the unicode on disk flag since Samba 3.2. */ +#define SAMBA_IGNORE (FILE_VOLUME_QUOTAS \ + | FILE_SUPPORTS_OBJECT_IDS \ + | FILE_UNICODE_ON_DISK) +#define FS_IS_SAMBA TEST_GVI(flags () & ~SAMBA_IGNORE, \ + FILE_CASE_SENSITIVE_SEARCH \ + | FILE_CASE_PRESERVED_NAMES \ + | FILE_PERSISTENT_ACLS) +#define FS_IS_NETAPP_DATAONTAP TEST_GVI(flags (), \ + FILE_CASE_SENSITIVE_SEARCH \ + | FILE_CASE_PRESERVED_NAMES \ + | FILE_UNICODE_ON_DISK \ + | FILE_PERSISTENT_ACLS \ + | FILE_NAMED_STREAMS) + RtlInitCountedUnicodeString (&fsname, ffai_buf.ffai.FileSystemName, + ffai_buf.ffai.FileSystemNameLength); + is_fat (RtlEqualUnicodePathPrefix (&fsname, L"FAT", TRUE)); + RtlInitUnicodeString (&testname, L"NTFS"); + if (is_remote_drive ()) + { + /* This always fails on NT4. */ + status = NtQueryVolumeInformationFile (vol, &io, &ffoi, sizeof ffoi, + FileFsObjectIdInformation); + if (NT_SUCCESS (status)) + { + smb_extended_info *extended_info = (smb_extended_info *) + &ffoi.ExtendedInfo; + if (extended_info->samba_magic == SAMBA_EXTENDED_INFO_MAGIC) + { + is_samba (true); + samba_version (extended_info->samba_version); + } + } + /* Test for Samba on NT4 or for older Samba releases not supporting + extended info. */ + if (!is_samba ()) + is_samba (RtlEqualUnicodeString (&fsname, &testname, FALSE) + && FS_IS_SAMBA); + + if (!is_samba ()) + { + is_netapp (RtlEqualUnicodeString (&fsname, &testname, FALSE) + && FS_IS_NETAPP_DATAONTAP); + + RtlInitUnicodeString (&testname, L"NFS"); + is_nfs (RtlEqualUnicodeString (&fsname, &testname, FALSE)); + + if (!is_nfs ()) + { + /* Known remote file systems which can't handle calls to + NtQueryDirectoryFile(FileIdBothDirectoryInformation) */ + RtlInitUnicodeString (&testname, L"UNIXFS"); + has_buggy_fileid_dirinfo (RtlEqualUnicodeString (&fsname, + &testname, + FALSE)); + + /* Known remote file systems with buggy open calls. Further + explanation in fhandler.cc (fhandler_disk_file::open). */ + RtlInitUnicodeString (&testname, L"SUNWNFS"); + has_buggy_open (RtlEqualUnicodeString (&fsname, &testname, + FALSE)); + } + } + } + is_ntfs (RtlEqualUnicodeString (&fsname, &testname, FALSE) + && !is_samba () && !is_netapp ()); + is_cdrom (ffdi.DeviceType == FILE_DEVICE_CD_ROM); + + has_acls (flags () & FS_PERSISTENT_ACLS); + hasgood_inode (((flags () & FILE_PERSISTENT_ACLS) && !is_netapp ()) + || is_nfs ()); + /* Case sensitivity is supported if FILE_CASE_SENSITIVE_SEARCH is set, + except on Samba which handles Windows clients case insensitive. + NFS doesn't set the FILE_CASE_SENSITIVE_SEARCH flag but is case + sensitive. */ + caseinsensitive ((!(flags () & FILE_CASE_SENSITIVE_SEARCH) || is_samba ()) + && !is_nfs ()); + + if (!in_vol) + NtClose (vol); + return true; +} + inline void mount_info::create_root_entry (const PWCHAR root) { @@ -1122,7 +1318,6 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) table because the mount table might change, causing weird effects from the getmntent user's point of view. */ - slashify (native_path, _my_tls.locals.mnt_fsname, false); ret.mnt_fsname = _my_tls.locals.mnt_fsname; strcpy (_my_tls.locals.mnt_dir, posix_path); ret.mnt_dir = _my_tls.locals.mnt_dir; @@ -1135,7 +1330,7 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) tmp_pathbuf tp; UNICODE_STRING unat; tp.u_get (&unat); - get_nt_native_path (_my_tls.locals.mnt_fsname, unat); + get_nt_native_path (native_path, unat); if (append_bs) RtlAppendUnicodeToString (&unat, L"\\"); mntinfo.update (&unat, NULL); @@ -1157,6 +1352,8 @@ fillout_mntent (const char *native_path, const char *posix_path, unsigned flags) ret.mnt_type = _my_tls.locals.mnt_type; + slashify (native_path, _my_tls.locals.mnt_fsname, false); + /* mnt_opts is a string that details mount params such as binary or textmode, or exec. We don't print `silent' here; it's a magic internal thing. */ |