* 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.
This commit is contained in:
		| @@ -1,3 +1,27 @@ | ||||
| 2006-07-03  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* 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. | ||||
|  | ||||
| 2006-07-03  Kazuhiro Fujieda  <fujieda@jaist.ac.jp> | ||||
|  | ||||
| 	* fhandler.h (class dev_console): Add `metabit' indicating the | ||||
|   | ||||
| @@ -392,6 +392,7 @@ LoadDLLfuncNt (NtOpenFile, 24, ntdll) | ||||
| LoadDLLfuncNt (NtOpenSection, 12, ntdll) | ||||
| LoadDLLfuncNt (NtQueryDirectoryObject, 28, ntdll) | ||||
| LoadDLLfuncNt (NtQueryDirectoryFile, 44, ntdll) | ||||
| LoadDLLfuncNt (NtQueryEaFile, 36, ntdll) | ||||
| LoadDLLfuncNt (NtQueryInformationFile, 20, ntdll) | ||||
| LoadDLLfuncNt (NtQueryInformationProcess, 20, ntdll) | ||||
| LoadDLLfuncNt (NtQueryObject, 20, ntdll) | ||||
| @@ -399,6 +400,7 @@ LoadDLLfuncNt (NtQuerySystemInformation, 16, ntdll) | ||||
| LoadDLLfuncNt (NtQuerySecurityObject, 20, ntdll) | ||||
| LoadDLLfuncNt (NtQueryVirtualMemory, 24, ntdll) | ||||
| LoadDLLfuncNt (NtQueryVolumeInformationFile, 20, ntdll) | ||||
| LoadDLLfuncNt (NtSetEaFile, 16, ntdll) | ||||
| LoadDLLfuncNt (NtSetSecurityObject, 12, ntdll) | ||||
| LoadDLLfuncNt (NtUnlockVirtualMemory, 16, ntdll) | ||||
| LoadDLLfuncNt (NtUnmapViewOfSection, 8, ntdll) | ||||
|   | ||||
| @@ -590,11 +590,13 @@ fhandler_base::open (int flags, mode_t mode) | ||||
| 	create_options = FILE_OPEN_FOR_BACKUP_INTENT; | ||||
| 	break; | ||||
|       case query_stat_control: | ||||
| 	access = READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_READ_DATA; | ||||
| 	access = READ_CONTROL | FILE_READ_ATTRIBUTES | ||||
| 		 | (allow_ntea ? FILE_READ_EA : 0); | ||||
| 	create_options = FILE_OPEN_FOR_BACKUP_INTENT; | ||||
| 	break; | ||||
|       case query_write_control: | ||||
| 	access = READ_CONTROL | WRITE_OWNER | WRITE_DAC | FILE_WRITE_ATTRIBUTES; | ||||
| 	access = READ_CONTROL | WRITE_OWNER | WRITE_DAC | FILE_WRITE_ATTRIBUTES | ||||
| 		 | (allow_ntea ? FILE_WRITE_EA : 0); | ||||
| 	create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY; | ||||
| 	break; | ||||
|       case query_write_attributes: | ||||
|   | ||||
| @@ -581,6 +581,23 @@ typedef struct _DIRECTORY_BASIC_INFORMATION | ||||
|   UNICODE_STRING ObjectTypeName; | ||||
| } DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION; | ||||
|  | ||||
| typedef struct _FILE_GET_EA_INFORMATION | ||||
| { | ||||
|   ULONG   NextEntryOffset; | ||||
|   UCHAR   EaNameLength; | ||||
|   CHAR    EaName[1]; | ||||
| } FILE_GET_EA_INFORMATION, *PFILE_GET_EA_INFORMATION; | ||||
|  | ||||
|  | ||||
| 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; | ||||
|  | ||||
| /* Function declarations for ntdll.dll.  These don't appear in any | ||||
|    standard Win32 header.  */ | ||||
| extern "C" | ||||
| @@ -611,6 +628,8 @@ extern "C" | ||||
| 				      PUNICODE_STRING, BOOLEAN); | ||||
|   NTSTATUS NTAPI NtQueryDirectoryObject (HANDLE, PVOID, ULONG, BOOLEAN, | ||||
|   					 BOOLEAN, PULONG, PULONG); | ||||
|   NTSTATUS NTAPI NtQueryEaFile (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, | ||||
| 				BOOLEAN, PVOID, ULONG, PULONG, BOOLEAN); | ||||
|   NTSTATUS NTAPI NtQueryInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID, | ||||
| 					 ULONG, FILE_INFORMATION_CLASS); | ||||
|   NTSTATUS NTAPI NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, | ||||
| @@ -626,6 +645,7 @@ extern "C" | ||||
|   NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *, | ||||
| 					       VOID *, ULONG, | ||||
| 					       FS_INFORMATION_CLASS); | ||||
|   NTSTATUS NTAPI NtSetEaFile (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG); | ||||
|   NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION, | ||||
| 				      PSECURITY_DESCRIPTOR); | ||||
|   NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); | ||||
|   | ||||
| @@ -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 <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <ntdef.h> | ||||
| #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) | ||||
| read_ea (HANDLE hdl, const char *file, const char *attrname, char *attrbuf, | ||||
| 	 int len) | ||||
| { | ||||
|     HANDLE hFileSource; | ||||
|     int eafound = 0; | ||||
|     PFILE_FULL_EA_INFORMATION ea, sea; | ||||
|     int easize = 0; | ||||
|   IO_STATUS_BLOCK io; | ||||
|  | ||||
|     hFileSource = CreateFile (file, FILE_READ_EA, | ||||
|   /* 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) | ||||
|     { | ||||
|       if (!hdl && (h = 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) | ||||
| 				   &sec_none_nih, OPEN_EXISTING, | ||||
| 				   FILE_FLAG_BACKUP_SEMANTICS, NULL)) | ||||
| 		  == INVALID_HANDLE_VALUE) | ||||
| 	{ | ||||
| 	if (strcasematch (ea->EaName, attrname)) /* EA found */ | ||||
| 	  { | ||||
| 	    if (ea->EaValueLength > len) | ||||
| 	      { | ||||
| 		eafound = -1;		/* buffer too small */ | ||||
| 		break; | ||||
| 	  debug_printf ("Opening %s for querying EA %s failed, %E", | ||||
| 	  		file, attrname); | ||||
| 	  goto out; | ||||
| 	} | ||||
| 	    memcpy (attrbuf, ea->EaName + (ea->EaNameLength + 1), | ||||
| 		    ea->EaValueLength); | ||||
| 	    eafound = ea->EaValueLength; | ||||
|       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 ((ea->NextEntryOffset == 0) || ((int) ea->NextEntryOffset > easize)) | ||||
| 	  break; | ||||
| 	ea = (PFILE_FULL_EA_INFORMATION) ((char *) ea + ea->NextEntryOffset); | ||||
|   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; | ||||
|     } | ||||
|  | ||||
|     if (sea) | ||||
|       free (sea); | ||||
|     CloseHandle (hFileSource); | ||||
|  | ||||
|     return eafound; | ||||
| out: | ||||
|   debug_printf ("%d = read_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname, | ||||
|   		attrbuf, len); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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) | ||||
| { | ||||
|   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)) | ||||
|     { | ||||
|       DWORD sl,sh; | ||||
|  | ||||
|       if (dwBytesWritten == 0) /* No more Stream IDs */ | ||||
| 	break; | ||||
|       /* skip StreamName */ | ||||
|       if (StreamId.dwStreamNameSize) | ||||
| 	{ | ||||
| 	  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; | ||||
| 	} | ||||
| 	/* Skip current stream */ | ||||
| 	if (!BackupSeek (hFileSource, | ||||
| 			 StreamId.Size.LowPart, | ||||
| 			 StreamId.Size.HighPart, | ||||
| 			 &sl, | ||||
| 			 &sh, | ||||
| 			 &lpContext)) | ||||
| 	  break; | ||||
|     } | ||||
|  | ||||
|   /* 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; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * 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; | ||||
|   IO_STATUS_BLOCK io; | ||||
|  | ||||
|   hFileSource = CreateFile (file, FILE_WRITE_EA, | ||||
|   /* 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, // sa | ||||
| 			    OPEN_EXISTING, | ||||
| 			    FILE_FLAG_BACKUP_SEMANTICS, | ||||
| 			    NULL); | ||||
| 				   &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; | ||||
|  | ||||
|   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; | ||||
| out: | ||||
|   debug_printf ("%d = write_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname, | ||||
|   		attrbuf, len); | ||||
|   return ret; | ||||
| } | ||||
|   | ||||
| @@ -2694,20 +2694,20 @@ endmntent (FILE *) | ||||
| /********************** Symbolic Link Support **************************/ | ||||
|  | ||||
| /* Read symlink from Extended Attribute */ | ||||
| int | ||||
| get_symlink_ea (const char* frompath, char* buf, int buf_size) | ||||
| static int | ||||
| get_symlink_ea (HANDLE hdl, const char* frompath, char* buf, int buf_size) | ||||
| { | ||||
|   int res = NTReadEA (frompath, SYMLINK_EA_NAME, buf, buf_size); | ||||
|   int res = read_ea (hdl, frompath, SYMLINK_EA_NAME, buf, buf_size); | ||||
|   if (res == 0) | ||||
|     debug_printf ("Cannot read symlink from EA"); | ||||
|   return (res - 1); | ||||
| } | ||||
|  | ||||
| /* Save symlink to Extended Attribute */ | ||||
| bool | ||||
| set_symlink_ea (const char* frompath, const char* topath) | ||||
| static bool | ||||
| set_symlink_ea (HANDLE hdl, const char* frompath, const char* topath) | ||||
| { | ||||
|   if (!NTWriteEA (frompath, SYMLINK_EA_NAME, topath, strlen (topath) + 1)) | ||||
|   if (!write_ea (hdl, frompath, SYMLINK_EA_NAME, topath, strlen (topath) + 1)) | ||||
|     { | ||||
|       debug_printf ("Cannot save symlink in EA"); | ||||
|       return false; | ||||
| @@ -2926,6 +2926,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym, | ||||
| 	} | ||||
|       if (success) | ||||
| 	{ | ||||
| 	  if (!isdevice && win32_path.fs_has_ea ()) | ||||
| 	    set_symlink_ea (h, win32_path, oldpath); | ||||
| 	  CloseHandle (h); | ||||
| 	  if (!allow_ntsec && allow_ntea) | ||||
| 	    set_file_attribute (false, NULL, win32_path.get_win32 (), | ||||
| @@ -2940,8 +2942,6 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym, | ||||
| #endif | ||||
| 	  SetFileAttributes (win32_path, attr); | ||||
|  | ||||
| 	  if (!isdevice && win32_path.fs_has_ea ()) | ||||
| 	    set_symlink_ea (win32_path, oldpath); | ||||
| 	  res = 0; | ||||
| 	} | ||||
|       else | ||||
| @@ -3340,16 +3340,6 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) | ||||
|       if (!sym_check) | ||||
| 	goto file_not_symlink; | ||||
|  | ||||
|       if (sym_check > 0 && opt & PC_CHECK_EA && | ||||
| 	  (res = get_symlink_ea (suffix.path, contents, sizeof (contents))) > 0) | ||||
| 	{ | ||||
| 	  pflags = PATH_SYMLINK | pflags_or; | ||||
| 	  if (sym_check == 1) | ||||
| 	    pflags |= PATH_LNK; | ||||
| 	  debug_printf ("Got symlink from EA: %s", contents); | ||||
| 	  break; | ||||
| 	} | ||||
|  | ||||
|       /* Open the file.  */ | ||||
|  | ||||
|       h = CreateFile (suffix.path, GENERIC_READ, FILE_SHARE_READ, | ||||
| @@ -3358,8 +3348,17 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) | ||||
|       if (h == INVALID_HANDLE_VALUE) | ||||
| 	goto file_not_symlink; | ||||
|  | ||||
|       /* FIXME: if symlink isn't present in EA, but EAs are supported, | ||||
| 	 should we write it there?  */ | ||||
|       if (sym_check > 0 && opt & PC_CHECK_EA | ||||
| 	  && (res = get_symlink_ea (h, suffix.path, contents, | ||||
| 				    sizeof (contents))) > 0) | ||||
| 	{ | ||||
| 	  pflags = PATH_SYMLINK | pflags_or; | ||||
| 	  if (sym_check == 1) | ||||
| 	    pflags |= PATH_LNK; | ||||
| 	  debug_printf ("Got symlink from EA: %s", contents); | ||||
| 	  break; | ||||
| 	} | ||||
|  | ||||
|       switch (sym_check) | ||||
| 	{ | ||||
| 	case 1: | ||||
|   | ||||
| @@ -1405,7 +1405,8 @@ get_file_attribute (int use_ntsec, HANDLE handle, const char *file, | ||||
|   if (allow_ntea) | ||||
|     { | ||||
|       int oatt = *attribute; | ||||
|       res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof (*attribute)); | ||||
|       res = read_ea (handle, file, ".UNIXATTR", (char *)attribute, | ||||
| 		     sizeof (*attribute)); | ||||
|       *attribute |= oatt; | ||||
|     } | ||||
|   else | ||||
| @@ -1801,8 +1802,8 @@ set_file_attribute (bool use_ntsec, HANDLE handle, const char *file, | ||||
|  | ||||
|   if (use_ntsec && allow_ntsec) | ||||
|     ret = set_nt_attribute (handle, file, uid, gid, attribute); | ||||
|   else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute, | ||||
| 				     sizeof (attribute))) | ||||
|   else if (allow_ntea && !write_ea (handle, file, ".UNIXATTR", | ||||
| 				    (char *) &attribute, sizeof (attribute))) | ||||
|     { | ||||
|       __seterrno (); | ||||
|       ret = -1; | ||||
|   | ||||
| @@ -378,8 +378,10 @@ extern SECURITY_ATTRIBUTES *__stdcall __sec_user (PVOID sa_buf, PSID sid1, PSID | ||||
| extern bool sec_acl (PACL acl, bool original, bool admins, PSID sid1 = NO_SID, | ||||
| 		     PSID sid2 = NO_SID, DWORD access2 = 0); | ||||
|  | ||||
| int __stdcall NTReadEA (const char *file, const char *attrname, char *buf, int len); | ||||
| BOOL __stdcall NTWriteEA (const char *file, const char *attrname, const char *buf, int len); | ||||
| int __stdcall read_ea (HANDLE hdl, const char *file, const char *attrname, | ||||
| 		       char *buf, int len); | ||||
| BOOL __stdcall write_ea (HANDLE hdl, const char *file, const char *attrname, | ||||
| 			 const char *buf, int len); | ||||
|  | ||||
| /* Note: sid1 is usually (read: currently always) the current user's | ||||
|    effective sid (cygheap->user.sid ()). */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user