From 4635b6ebd8eba1a7755f985db509aff8c3c06859 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 3 Jul 2006 18:30:08 +0000 Subject: * autoload.cc (NtQueryEaFile): Define. (NtSetEaFile): Define. * fhandler.cc (fhandler_base::open): Use appropriate open flags in query case when allow_ntea is set. * ntdll.h (struct _FILE_GET_EA_INFORMATION): Define. (struct _FILE_FULL_EA_INFORMATION): Define. (NtQueryEaFile): Declare. (NtSetEaFile): Declare. * ntea.cc (read_ea): Rename from NTReadEA and rewrite using NtQueryEaFile. (write_ea): Rename from NTWriteEA and rewrite using NtSetEaFile. * path.cc (get_symlink_ea): Make static. Add handle parameter to accomodate new read_ea call. (set_symlink_ea): Make static. Add handle parameter to accomodate new write_ea call. (symlink_worker): Call set_symlink_ea while file is still open. (symlink_info::check): Call get_symlink_ea after file has been opened. * security.cc (get_file_attribute): Accomodate new read_ea call. (set_file_attribute): Accomodate new write_ea call. * security.h (read_ea): Change declaration accordingly. (write_ea): Ditto. --- winsup/cygwin/ntea.cc | 397 ++++++++++++++++---------------------------------- 1 file changed, 122 insertions(+), 275 deletions(-) (limited to 'winsup/cygwin/ntea.cc') diff --git a/winsup/cygwin/ntea.cc b/winsup/cygwin/ntea.cc index f33d82250..72463feb0 100644 --- a/winsup/cygwin/ntea.cc +++ b/winsup/cygwin/ntea.cc @@ -1,6 +1,6 @@ /* ntea.cc: code for manipulating NTEA information - Copyright 1997, 1998, 2000, 2001 Red Hat, Inc. + Copyright 1997, 1998, 2000, 2001, 2006 Red Hat, Inc. Written by Sergey S. Okhapkin (sos@prospect.com.ru) @@ -11,315 +11,162 @@ Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" -#include #include +#include #include "security.h" +#include "ntdll.h" /* Default to not using NTEA information */ bool allow_ntea; /* -From Windows NT DDK: - -FILE_FULL_EA_INFORMATION provides extended attribute information. -This structure is used primarily by network drivers. - -Members - -NextEntryOffset -The offset of the next FILE_FULL_EA_INFORMATION-type entry. This member is -zero if no other entries follow this one. - -Flags -Can be zero or can be set with FILE_NEED_EA, indicating that the file to which -the EA belongs cannot be interpreted without understanding the associated -extended attributes. - -EaNameLength -The length in bytes of the EaName array. This value does not include a -zero-terminator to EaName. - -EaValueLength -The length in bytes of each EA value in the array. - -EaName -An array of characters naming the EA for this entry. - -Comments -This structure is longword-aligned. If a set of FILE_FULL_EA_INFORMATION -entries is buffered, NextEntryOffset value in each entry, except the last, -falls on a longword boundary. -The value(s) associated with each entry follows the EaName array. That is, an -EA's values are located at EaName + (EaNameLength + 1). -*/ - -typedef struct _FILE_FULL_EA_INFORMATION { - ULONG NextEntryOffset; - UCHAR Flags; - UCHAR EaNameLength; - USHORT EaValueLength; - CHAR EaName[1]; -} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION; - -/* Functions prototypes */ - -int NTReadEA (const char *file, const char *attrname, char *buf, int len); -static PFILE_FULL_EA_INFORMATION NTReadEARaw (HANDLE file, int *len); -BOOL NTWriteEA(const char *file, const char *attrname, char *buf, int len); - -/* - * NTReadEA - read file's Extended Attribute. + * read_ea - read file's Extended Attribute. * * Parameters: * file - pointer to filename - * attrname- pointer to EA name (case insensitivy. EAs are sored in upper - * case). + * attrname- pointer to EA name (case insensitiv) * attrbuf - pointer to buffer to store EA's value. * len - length of attrbuf. * Return value: * 0 - if file or attribute "attrname" not found. - * N - number of bytes stored in attrbuf if succes. + * N - number of bytes stored in attrbuf if success. * -1 - attrbuf too small for EA value. */ int __stdcall -NTReadEA (const char *file, const char *attrname, char *attrbuf, int len) -{ - HANDLE hFileSource; - int eafound = 0; - PFILE_FULL_EA_INFORMATION ea, sea; - int easize = 0; - - hFileSource = CreateFile (file, FILE_READ_EA, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, // sa - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - - if (hFileSource == INVALID_HANDLE_VALUE) - return 0; - - /* Read in raw array of EAs */ - ea = sea = NTReadEARaw (hFileSource, &easize); - - /* Search for requested attribute */ - while (sea) - { - if (strcasematch (ea->EaName, attrname)) /* EA found */ - { - if (ea->EaValueLength > len) - { - eafound = -1; /* buffer too small */ - break; - } - memcpy (attrbuf, ea->EaName + (ea->EaNameLength + 1), - ea->EaValueLength); - eafound = ea->EaValueLength; - break; - } - if ((ea->NextEntryOffset == 0) || ((int) ea->NextEntryOffset > easize)) - break; - ea = (PFILE_FULL_EA_INFORMATION) ((char *) ea + ea->NextEntryOffset); - } - - if (sea) - free (sea); - CloseHandle (hFileSource); - - return eafound; -} - -/* - * NTReadEARaw - internal routine to read EAs array to malloced buffer. The - * caller should free this buffer after usage. - * Parameters: - * hFileSource - handle to file. This handle should have FILE_READ_EA - * rights. - * len - pointer to int variable where length of buffer will - * be stored. - * Return value: - * pointer to buffer with file's EAs, or NULL if any error occured. - */ - -static PFILE_FULL_EA_INFORMATION -NTReadEARaw (HANDLE hFileSource, int *len) +read_ea (HANDLE hdl, const char *file, const char *attrname, char *attrbuf, + int len) { - WIN32_STREAM_ID StreamId; - DWORD dwBytesWritten; - LPVOID lpContext; - DWORD StreamSize; - PFILE_FULL_EA_INFORMATION eafound = NULL; - - lpContext = NULL; - StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**); - - /* Read the WIN32_STREAM_ID in */ - - while (BackupRead (hFileSource, (LPBYTE) &StreamId, StreamSize, - &dwBytesWritten, - FALSE, // don't abort yet - FALSE, // don't process security - &lpContext)) + IO_STATUS_BLOCK io; + + /* Prepare buffer which receives the result. */ + ULONG flen = sizeof (FILE_FULL_EA_INFORMATION) + strlen (attrname) + + len + 1; + PFILE_FULL_EA_INFORMATION fea = (PFILE_FULL_EA_INFORMATION) alloca (flen); + /* Prepare buffer specifying the EA to search for. */ + ULONG glen = sizeof (FILE_GET_EA_INFORMATION) + strlen (attrname); + PFILE_GET_EA_INFORMATION gea = (PFILE_GET_EA_INFORMATION) alloca (glen); + gea->NextEntryOffset = 0; + gea->EaNameLength = strlen (attrname); + strcpy (gea->EaName, attrname); + + /* If no incoming hdl is given, the loop only runs once, trying to + open the file and to query the EA. If an incoming hdl is given, + the loop runs twice, first trying to query with the given hdl. + If this fails it tries to open the file and to query with that + handle again. */ + HANDLE h = hdl; + NTSTATUS status = STATUS_SUCCESS; + int ret = 0; + while (true) { - DWORD sl,sh; - - if (dwBytesWritten == 0) /* No more Stream IDs */ - break; - /* skip StreamName */ - if (StreamId.dwStreamNameSize) + if (!hdl && (h = CreateFile (file, FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL)) + == INVALID_HANDLE_VALUE) { - unsigned char *buf; - buf = (unsigned char *) malloc (StreamId.dwStreamNameSize); - - if (buf == NULL) - break; - - if (!BackupRead (hFileSource, buf, // buffer to read - StreamId.dwStreamNameSize, // num bytes to read - &dwBytesWritten, - FALSE, // don't abort yet - FALSE, // don't process security - &lpContext)) // Stream name read error - { - free (buf); - break; - } - free (buf); - } - - /* Is it EA stream? */ - if (StreamId.dwStreamId == BACKUP_EA_DATA) - { - unsigned char *buf; - buf = (unsigned char *) malloc (StreamId.Size.LowPart); - - if (buf == NULL) - break; - if (!BackupRead (hFileSource, buf, // buffer to read - StreamId.Size.LowPart, // num bytes to write - &dwBytesWritten, - FALSE, // don't abort yet - FALSE, // don't process security - &lpContext)) - { - free (buf); /* EA read error */ - break; - } - eafound = (PFILE_FULL_EA_INFORMATION) buf; - *len = StreamId.Size.LowPart; - break; + debug_printf ("Opening %s for querying EA %s failed, %E", + file, attrname); + goto out; } - /* Skip current stream */ - if (!BackupSeek (hFileSource, - StreamId.Size.LowPart, - StreamId.Size.HighPart, - &sl, - &sh, - &lpContext)) - break; + status = NtQueryEaFile (h, &io, fea, flen, FALSE, gea, glen, NULL, TRUE); + if (NT_SUCCESS (status) || !hdl) + break; + debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d", + status, file, attrname, RtlNtStatusToDosError (status)); + hdl = NULL; + } + if (!hdl) + CloseHandle (h); + if (!NT_SUCCESS (status)) + { + ret = -1; + debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d", + status, file, attrname, RtlNtStatusToDosError (status)); + } + if (!fea->EaValueLength) + ret = 0; + else + { + memcpy (attrbuf, fea->EaName + fea->EaNameLength + 1, + fea->EaValueLength); + ret = fea->EaValueLength; } - /* free context */ - BackupRead ( - hFileSource, - NULL, // buffer to write - 0, // number of bytes to write - &dwBytesWritten, - TRUE, // abort - FALSE, // don't process security - &lpContext); - - return eafound; +out: + debug_printf ("%d = read_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname, + attrbuf, len); + return ret; } /* - * NTWriteEA - write file's Extended Attribute. + * write_ea - write file's Extended Attribute. * * Parameters: * file - pointer to filename - * attrname- pointer to EA name (case insensitivy. EAs are sored in upper - * case). - * buf - pointer to buffer with EA value. - * len - length of buf. + * attrname- pointer to EA name (case insensitiv) + * attrbuf - pointer to buffer with EA value. + * len - length of attrbuf. * Return value: * true if success, false otherwice. * Note: if len=0 given EA will be deleted. */ BOOL __stdcall -NTWriteEA (const char *file, const char *attrname, const char *buf, int len) +write_ea (HANDLE hdl, const char *file, const char *attrname, + const char *attrbuf, int len) { - HANDLE hFileSource; - WIN32_STREAM_ID StreamId; - DWORD dwBytesWritten; - LPVOID lpContext; - DWORD StreamSize, easize; - bool bSuccess = false; - PFILE_FULL_EA_INFORMATION ea; - - hFileSource = CreateFile (file, FILE_WRITE_EA, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, // sa - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, - NULL); - - if (hFileSource == INVALID_HANDLE_VALUE) - return FALSE; - - lpContext = NULL; - StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**); - - /* FILE_FULL_EA_INFORMATION structure is longword-aligned */ - easize = sizeof (*ea) - sizeof (WCHAR**) + strlen (attrname) + 1 + len - + (sizeof (DWORD) - 1); - easize &= ~(sizeof (DWORD) - 1); - - if ((ea = (PFILE_FULL_EA_INFORMATION) malloc (easize)) == NULL) - goto cleanup; - - memset (ea, 0, easize); - ea->EaNameLength = strlen (attrname); - ea->EaValueLength = len; - strcpy (ea->EaName, attrname); - memcpy (ea->EaName + (ea->EaNameLength + 1), buf, len); - - StreamId.dwStreamId = BACKUP_EA_DATA; - StreamId.dwStreamAttributes = 0; - StreamId.Size.HighPart = 0; - StreamId.Size.LowPart = easize; - StreamId.dwStreamNameSize = 0; - - if (!BackupWrite (hFileSource, (LPBYTE) &StreamId, StreamSize, - &dwBytesWritten, - FALSE, // don't abort yet - FALSE, // don't process security - &lpContext)) - goto cleanup; - - if (!BackupWrite (hFileSource, (LPBYTE) ea, easize, - &dwBytesWritten, - FALSE, // don't abort yet - FALSE, // don't process security - &lpContext)) - goto cleanup; - - bSuccess = true; - /* free context */ - -cleanup: - BackupRead (hFileSource, - NULL, // buffer to write - 0, // number of bytes to write - &dwBytesWritten, - TRUE, // abort - FALSE, // don't process security - &lpContext); - - CloseHandle (hFileSource); - if (ea) - free (ea); - - return bSuccess; + IO_STATUS_BLOCK io; + + /* Prepare buffer specifying the EA to write back. */ + ULONG flen = sizeof (FILE_FULL_EA_INFORMATION) + strlen (attrname) + + len + 1; + PFILE_FULL_EA_INFORMATION fea = (PFILE_FULL_EA_INFORMATION) alloca (flen); + fea->NextEntryOffset = 0; + fea->Flags = 0; + fea->EaNameLength = strlen (attrname); + fea->EaValueLength = len; + strcpy (fea->EaName, attrname); + memcpy (fea->EaName + fea->EaNameLength + 1, attrbuf, len); + + /* If no incoming hdl is given, the loop only runs once, trying to + open the file and to set the EA. If an incoming hdl is given, + the loop runs twice, first trying to set the EA with the given hdl. + If this fails it tries to open the file and to set the EA with that + handle again. */ + HANDLE h = hdl; + NTSTATUS status = STATUS_SUCCESS; + bool ret = false; + while (true) + { + if (!hdl && (h = CreateFile (file, FILE_READ_EA, + FILE_SHARE_READ | FILE_SHARE_WRITE, + &sec_none_nih, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL)) + == INVALID_HANDLE_VALUE) + { + debug_printf ("Opening %s for setting EA %s failed, %E", + file, attrname); + goto out; + } + status = NtSetEaFile (h, &io, fea, flen); + if (NT_SUCCESS (status) || !hdl) + break; + debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d", + status, file, attrname, RtlNtStatusToDosError (status)); + hdl = NULL; + } + if (!hdl) + CloseHandle (h); + if (!NT_SUCCESS (status)) + debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d", + status, file, attrname, RtlNtStatusToDosError (status)); + else + ret = true; + +out: + debug_printf ("%d = write_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname, + attrbuf, len); + return ret; } -- cgit v1.2.3