diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 19aadbedd..7d82ed2f4 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,12 @@ +2008-01-22 Corinna Vinschen + + * ntdll.h (struct _FILE_FS_OBJECTID_INFORMATION): Define. + * path.cc (struct smb_extended_info): Define. + (fs_info::update): Request object id info to get Samba information. + Set flags according to new implementation. + * path.h (struct fs_info): Add samba_version to status_flags. + Implement flags() and samba_version() using IMPLEMENT_STATUS_FLAG. + 2008-01-21 Corinna Vinschen * fhandler_disk_file.cc (fhandler_disk_file::link): Open file with diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index fa1beee8d..91ddf28dd 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -712,6 +712,11 @@ typedef struct _FILE_FS_FULL_SIZE_INFORMATION ULONG BytesPerSector; } FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION; +typedef struct _FILE_FS_OBJECTID_INFORMATION { + UCHAR ObjectId[16]; + UCHAR ExtendedInfo[48]; +} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION; + typedef enum _FSINFOCLASS { FileFsVolumeInformation = 1, FileFsLabelInformation, diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc index 2f7746489..d24d859de 100644 --- a/winsup/cygwin/path.cc +++ b/winsup/cygwin/path.cc @@ -378,6 +378,22 @@ mkrelpath (char *path) strcpy (path, "."); } +/* Beginning with Samba 3.2, 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, bool exists) { @@ -387,6 +403,7 @@ fs_info::update (PUNICODE_STRING upath, bool exists) IO_STATUS_BLOCK io; bool no_media = false; FILE_FS_DEVICE_INFORMATION ffdi; + FILE_FS_OBJECTID_INFORMATION ffoi; PFILE_FS_ATTRIBUTE_INFORMATION pffai; UNICODE_STRING fsname, testname; @@ -444,11 +461,11 @@ fs_info::update (PUNICODE_STRING upath, bool exists) debug_printf ("Cannot get volume attributes (%S), %08lx", attr.ObjectName, status); has_buggy_open (false); - flags () = 0; + flags (0); NtClose (vol); return false; } - flags () = pffai->FileSystemAttributes; + flags (pffai->FileSystemAttributes); /* 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 @@ -476,12 +493,30 @@ fs_info::update (PUNICODE_STRING upath, bool exists) pffai->FileSystemNameLength); is_fat (RtlEqualUnicodePathPrefix (&fsname, L"FAT", TRUE)); RtlInitUnicodeString (&testname, L"NTFS"); - is_samba (RtlEqualUnicodeString (&fsname, &testname, FALSE) - && (ffdi.Characteristics & FILE_REMOTE_DEVICE) - && (FS_IS_SAMBA || FS_IS_SAMBA_WITH_QUOTA)); - is_netapp (RtlEqualUnicodeString (&fsname, &testname, FALSE) - && (ffdi.Characteristics & FILE_REMOTE_DEVICE) - && FS_IS_NETAPP_DATAONTAP); + 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 older Samba releases not supporting the extended info. */ + if (!is_samba ()) + is_samba (RtlEqualUnicodeString (&fsname, &testname, FALSE) + && (FS_IS_SAMBA || FS_IS_SAMBA_WITH_QUOTA)); + + is_netapp (!is_samba () + && RtlEqualUnicodeString (&fsname, &testname, FALSE) + && FS_IS_NETAPP_DATAONTAP); + } is_ntfs (RtlEqualUnicodeString (&fsname, &testname, FALSE) && !is_samba () && !is_netapp ()); RtlInitUnicodeString (&testname, L"NFS"); diff --git a/winsup/cygwin/path.h b/winsup/cygwin/path.h index 5bf9717e3..a19f382bc 100644 --- a/winsup/cygwin/path.h +++ b/winsup/cygwin/path.h @@ -97,7 +97,8 @@ struct fs_info private: struct status_flags { - DWORD flags; /* Volume flags */ + DWORD flags; /* Volume flags */ + DWORD samba_version; /* Samba version if available */ unsigned is_remote_drive : 1; unsigned has_buggy_open : 1; unsigned has_acls : 1; @@ -110,11 +111,11 @@ struct fs_info unsigned is_cdrom : 1; } status; public: - void clear () { memset (this, 0 , sizeof *this); } + void clear () { memset (&status, 0 , sizeof status); } fs_info () { clear (); } - inline DWORD& flags () {return status.flags;}; - + IMPLEMENT_STATUS_FLAG (DWORD, flags) + IMPLEMENT_STATUS_FLAG (DWORD, samba_version) IMPLEMENT_STATUS_FLAG (bool, is_remote_drive) IMPLEMENT_STATUS_FLAG (bool, has_buggy_open) IMPLEMENT_STATUS_FLAG (bool, has_acls)