* 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> | 2006-07-03  Kazuhiro Fujieda  <fujieda@jaist.ac.jp> | ||||||
|  |  | ||||||
| 	* fhandler.h (class dev_console): Add `metabit' indicating the | 	* fhandler.h (class dev_console): Add `metabit' indicating the | ||||||
|   | |||||||
| @@ -392,6 +392,7 @@ LoadDLLfuncNt (NtOpenFile, 24, ntdll) | |||||||
| LoadDLLfuncNt (NtOpenSection, 12, ntdll) | LoadDLLfuncNt (NtOpenSection, 12, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryDirectoryObject, 28, ntdll) | LoadDLLfuncNt (NtQueryDirectoryObject, 28, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryDirectoryFile, 44, ntdll) | LoadDLLfuncNt (NtQueryDirectoryFile, 44, ntdll) | ||||||
|  | LoadDLLfuncNt (NtQueryEaFile, 36, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryInformationFile, 20, ntdll) | LoadDLLfuncNt (NtQueryInformationFile, 20, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryInformationProcess, 20, ntdll) | LoadDLLfuncNt (NtQueryInformationProcess, 20, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryObject, 20, ntdll) | LoadDLLfuncNt (NtQueryObject, 20, ntdll) | ||||||
| @@ -399,6 +400,7 @@ LoadDLLfuncNt (NtQuerySystemInformation, 16, ntdll) | |||||||
| LoadDLLfuncNt (NtQuerySecurityObject, 20, ntdll) | LoadDLLfuncNt (NtQuerySecurityObject, 20, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryVirtualMemory, 24, ntdll) | LoadDLLfuncNt (NtQueryVirtualMemory, 24, ntdll) | ||||||
| LoadDLLfuncNt (NtQueryVolumeInformationFile, 20, ntdll) | LoadDLLfuncNt (NtQueryVolumeInformationFile, 20, ntdll) | ||||||
|  | LoadDLLfuncNt (NtSetEaFile, 16, ntdll) | ||||||
| LoadDLLfuncNt (NtSetSecurityObject, 12, ntdll) | LoadDLLfuncNt (NtSetSecurityObject, 12, ntdll) | ||||||
| LoadDLLfuncNt (NtUnlockVirtualMemory, 16, ntdll) | LoadDLLfuncNt (NtUnlockVirtualMemory, 16, ntdll) | ||||||
| LoadDLLfuncNt (NtUnmapViewOfSection, 8, ntdll) | LoadDLLfuncNt (NtUnmapViewOfSection, 8, ntdll) | ||||||
|   | |||||||
| @@ -590,11 +590,13 @@ fhandler_base::open (int flags, mode_t mode) | |||||||
| 	create_options = FILE_OPEN_FOR_BACKUP_INTENT; | 	create_options = FILE_OPEN_FOR_BACKUP_INTENT; | ||||||
| 	break; | 	break; | ||||||
|       case query_stat_control: |       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; | 	create_options = FILE_OPEN_FOR_BACKUP_INTENT; | ||||||
| 	break; | 	break; | ||||||
|       case query_write_control: |       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; | 	create_options = FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY; | ||||||
| 	break; | 	break; | ||||||
|       case query_write_attributes: |       case query_write_attributes: | ||||||
|   | |||||||
| @@ -581,6 +581,23 @@ typedef struct _DIRECTORY_BASIC_INFORMATION | |||||||
|   UNICODE_STRING ObjectTypeName; |   UNICODE_STRING ObjectTypeName; | ||||||
| } DIRECTORY_BASIC_INFORMATION, *PDIRECTORY_BASIC_INFORMATION; | } 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 | /* Function declarations for ntdll.dll.  These don't appear in any | ||||||
|    standard Win32 header.  */ |    standard Win32 header.  */ | ||||||
| extern "C" | extern "C" | ||||||
| @@ -611,6 +628,8 @@ extern "C" | |||||||
| 				      PUNICODE_STRING, BOOLEAN); | 				      PUNICODE_STRING, BOOLEAN); | ||||||
|   NTSTATUS NTAPI NtQueryDirectoryObject (HANDLE, PVOID, ULONG, BOOLEAN, |   NTSTATUS NTAPI NtQueryDirectoryObject (HANDLE, PVOID, ULONG, BOOLEAN, | ||||||
|   					 BOOLEAN, PULONG, PULONG); |   					 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, |   NTSTATUS NTAPI NtQueryInformationFile (HANDLE, PIO_STATUS_BLOCK, PVOID, | ||||||
| 					 ULONG, FILE_INFORMATION_CLASS); | 					 ULONG, FILE_INFORMATION_CLASS); | ||||||
|   NTSTATUS NTAPI NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, |   NTSTATUS NTAPI NtQueryInformationProcess (HANDLE, PROCESSINFOCLASS, | ||||||
| @@ -626,6 +645,7 @@ extern "C" | |||||||
|   NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *, |   NTSTATUS NTAPI NtQueryVolumeInformationFile (HANDLE, IO_STATUS_BLOCK *, | ||||||
| 					       VOID *, ULONG, | 					       VOID *, ULONG, | ||||||
| 					       FS_INFORMATION_CLASS); | 					       FS_INFORMATION_CLASS); | ||||||
|  |   NTSTATUS NTAPI NtSetEaFile (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG); | ||||||
|   NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION, |   NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION, | ||||||
| 				      PSECURITY_DESCRIPTOR); | 				      PSECURITY_DESCRIPTOR); | ||||||
|   NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); |   NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); | ||||||
|   | |||||||
| @@ -1,6 +1,6 @@ | |||||||
| /* ntea.cc: code for manipulating NTEA information | /* 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) |    Written by Sergey S. Okhapkin (sos@prospect.com.ru) | ||||||
|  |  | ||||||
| @@ -11,315 +11,162 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for | |||||||
| details. */ | details. */ | ||||||
|  |  | ||||||
| #include "winsup.h" | #include "winsup.h" | ||||||
| #include <stdio.h> |  | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  | #include <ntdef.h> | ||||||
| #include "security.h" | #include "security.h" | ||||||
|  | #include "ntdll.h" | ||||||
|  |  | ||||||
| /* Default to not using NTEA information */ | /* Default to not using NTEA information */ | ||||||
| bool allow_ntea; | bool allow_ntea; | ||||||
|  |  | ||||||
| /* | /* | ||||||
| From Windows NT DDK: |  * read_ea - read file's Extended Attribute. | ||||||
|  |  | ||||||
| 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. |  | ||||||
|  * |  * | ||||||
|  * Parameters: |  * Parameters: | ||||||
|  *	file	- pointer to filename |  *	file	- pointer to filename | ||||||
|  *	attrname- pointer to EA name (case insensitivy. EAs are sored in upper |  *	attrname- pointer to EA name (case insensitiv) | ||||||
|  *		  case). |  | ||||||
|  *	attrbuf - pointer to buffer to store EA's value. |  *	attrbuf - pointer to buffer to store EA's value. | ||||||
|  *	len	- length of attrbuf. |  *	len	- length of attrbuf. | ||||||
|  * Return value: |  * Return value: | ||||||
|  *	0	- if file or attribute "attrname" not found. |  *	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. |  *	-1	- attrbuf too small for EA value. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| int __stdcall | 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; |   IO_STATUS_BLOCK io; | ||||||
|     int eafound = 0; |  | ||||||
|     PFILE_FULL_EA_INFORMATION ea, sea; |  | ||||||
|     int easize = 0; |  | ||||||
|  |  | ||||||
|     hFileSource = CreateFile (file, FILE_READ_EA, |   /* Prepare buffer which receives the result. */ | ||||||
| 			      FILE_SHARE_READ | FILE_SHARE_WRITE, |   ULONG flen = sizeof (FILE_FULL_EA_INFORMATION) + strlen (attrname) | ||||||
| 			      &sec_none_nih, // sa | 	       + len + 1; | ||||||
| 			      OPEN_EXISTING, |   PFILE_FULL_EA_INFORMATION fea = (PFILE_FULL_EA_INFORMATION) alloca (flen); | ||||||
| 			      FILE_FLAG_BACKUP_SEMANTICS, |   /* Prepare buffer specifying the EA to search for. */ | ||||||
| 			      NULL); |   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 (hFileSource == INVALID_HANDLE_VALUE) |   /* If no incoming hdl is given, the loop only runs once, trying to | ||||||
| 	return 0; |      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. | ||||||
|     /* Read in raw array of EAs */ |      If this fails it tries to open the file and to query with that | ||||||
|     ea = sea = NTReadEARaw (hFileSource, &easize); |      handle again. */ | ||||||
|  |   HANDLE h = hdl; | ||||||
|     /* Search for requested attribute */ |   NTSTATUS status = STATUS_SUCCESS; | ||||||
|     while (sea) |   int ret = 0; | ||||||
|       { |   while (true) | ||||||
| 	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) |  | ||||||
| { |  | ||||||
|   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 (!hdl && (h = CreateFile (file, FILE_READ_EA, | ||||||
|  | 				   FILE_SHARE_READ | FILE_SHARE_WRITE, | ||||||
|       if (dwBytesWritten == 0) /* No more Stream IDs */ | 				   &sec_none_nih, OPEN_EXISTING, | ||||||
| 	break; | 				   FILE_FLAG_BACKUP_SEMANTICS, NULL)) | ||||||
|       /* skip StreamName */ | 		  == INVALID_HANDLE_VALUE) | ||||||
|       if (StreamId.dwStreamNameSize) |  | ||||||
| 	{ | 	{ | ||||||
| 	  unsigned char *buf; | 	  debug_printf ("Opening %s for querying EA %s failed, %E", | ||||||
| 	  buf = (unsigned char *) malloc (StreamId.dwStreamNameSize); | 	  		file, attrname); | ||||||
|  | 	  goto out; | ||||||
| 	  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); |  | ||||||
| 	} | 	} | ||||||
|  |       status = NtQueryEaFile (h, &io, fea, flen, FALSE, gea, glen, NULL, TRUE); | ||||||
| 	/* Is it EA stream? */ |       if (NT_SUCCESS (status) || !hdl) | ||||||
| 	if (StreamId.dwStreamId == BACKUP_EA_DATA) |         break; | ||||||
| 	  { |       debug_printf ("1. chance, %x = NtQueryEaFile (%s, %s), Win32 error %d", | ||||||
| 	    unsigned char *buf; | 		    status, file, attrname, RtlNtStatusToDosError (status)); | ||||||
| 	    buf = (unsigned char *) malloc (StreamId.Size.LowPart); |       hdl = NULL; | ||||||
|  |     } | ||||||
| 	    if (buf == NULL) |   if (!hdl) | ||||||
| 	      break; |     CloseHandle (h); | ||||||
| 	    if (!BackupRead (hFileSource, buf,	// buffer to read |   if (!NT_SUCCESS (status)) | ||||||
| 			     StreamId.Size.LowPart, // num bytes to write |     { | ||||||
| 			     &dwBytesWritten, |       ret = -1; | ||||||
| 			     FALSE,		// don't abort yet |       debug_printf ("%x = NtQueryEaFile (%s, %s), Win32 error %d", | ||||||
| 			     FALSE,		// don't process security | 		    status, file, attrname, RtlNtStatusToDosError (status)); | ||||||
| 			     &lpContext)) |     } | ||||||
| 	      { |   if (!fea->EaValueLength) | ||||||
| 		free (buf);	/* EA read error */ |     ret = 0; | ||||||
| 		break; |   else | ||||||
| 	      } |     { | ||||||
| 	    eafound = (PFILE_FULL_EA_INFORMATION) buf; |       memcpy (attrbuf, fea->EaName + fea->EaNameLength + 1, | ||||||
| 	    *len = StreamId.Size.LowPart; | 	      fea->EaValueLength); | ||||||
| 	    break; |       ret = fea->EaValueLength; | ||||||
| 	} |  | ||||||
| 	/* Skip current stream */ |  | ||||||
| 	if (!BackupSeek (hFileSource, |  | ||||||
| 			 StreamId.Size.LowPart, |  | ||||||
| 			 StreamId.Size.HighPart, |  | ||||||
| 			 &sl, |  | ||||||
| 			 &sh, |  | ||||||
| 			 &lpContext)) |  | ||||||
| 	  break; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   /* free context */ | out: | ||||||
|   BackupRead ( |   debug_printf ("%d = read_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname, | ||||||
|       hFileSource, |   		attrbuf, len); | ||||||
|       NULL,		// buffer to write |   return ret; | ||||||
|       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: |  * Parameters: | ||||||
|  *	file	- pointer to filename |  *	file	- pointer to filename | ||||||
|  *	attrname- pointer to EA name (case insensitivy. EAs are sored in upper |  *	attrname- pointer to EA name (case insensitiv) | ||||||
|  *		  case). |  *	attrbuf	- pointer to buffer with EA value. | ||||||
|  *	buf	- pointer to buffer with EA value. |  *	len	- length of attrbuf. | ||||||
|  *	len	- length of buf. |  | ||||||
|  * Return value: |  * Return value: | ||||||
|  *	true if success, false otherwice. |  *	true if success, false otherwice. | ||||||
|  * Note: if len=0 given EA will be deleted. |  * Note: if len=0 given EA will be deleted. | ||||||
|  */ |  */ | ||||||
|  |  | ||||||
| BOOL __stdcall | 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; |   IO_STATUS_BLOCK io; | ||||||
|   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, |   /* Prepare buffer specifying the EA to write back. */ | ||||||
| 			    FILE_SHARE_READ | FILE_SHARE_WRITE, |   ULONG flen = sizeof (FILE_FULL_EA_INFORMATION) + strlen (attrname) | ||||||
| 			    &sec_none_nih, // sa | 	       + len + 1; | ||||||
| 			    OPEN_EXISTING, |   PFILE_FULL_EA_INFORMATION fea = (PFILE_FULL_EA_INFORMATION) alloca (flen); | ||||||
| 			    FILE_FLAG_BACKUP_SEMANTICS, |   fea->NextEntryOffset = 0; | ||||||
| 			    NULL); |   fea->Flags = 0; | ||||||
|  |   fea->EaNameLength = strlen (attrname); | ||||||
|  |   fea->EaValueLength = len; | ||||||
|  |   strcpy (fea->EaName, attrname); | ||||||
|  |   memcpy (fea->EaName + fea->EaNameLength + 1, attrbuf, len); | ||||||
|  |  | ||||||
|   if (hFileSource == INVALID_HANDLE_VALUE) |   /* If no incoming hdl is given, the loop only runs once, trying to | ||||||
|     return FALSE; |      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; | ||||||
|  |  | ||||||
|   lpContext = NULL; | out: | ||||||
|   StreamSize = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**); |   debug_printf ("%d = write_ea (%x, %s, %s, %x, %d)", ret, hdl, file, attrname, | ||||||
|  |   		attrbuf, len); | ||||||
|   /* FILE_FULL_EA_INFORMATION structure is longword-aligned */ |   return ret; | ||||||
|   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; |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2694,20 +2694,20 @@ endmntent (FILE *) | |||||||
| /********************** Symbolic Link Support **************************/ | /********************** Symbolic Link Support **************************/ | ||||||
|  |  | ||||||
| /* Read symlink from Extended Attribute */ | /* Read symlink from Extended Attribute */ | ||||||
| int | static int | ||||||
| get_symlink_ea (const char* frompath, char* buf, int buf_size) | 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) |   if (res == 0) | ||||||
|     debug_printf ("Cannot read symlink from EA"); |     debug_printf ("Cannot read symlink from EA"); | ||||||
|   return (res - 1); |   return (res - 1); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Save symlink to Extended Attribute */ | /* Save symlink to Extended Attribute */ | ||||||
| bool | static bool | ||||||
| set_symlink_ea (const char* frompath, const char* topath) | 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"); |       debug_printf ("Cannot save symlink in EA"); | ||||||
|       return false; |       return false; | ||||||
| @@ -2926,6 +2926,8 @@ symlink_worker (const char *oldpath, const char *newpath, bool use_winsym, | |||||||
| 	} | 	} | ||||||
|       if (success) |       if (success) | ||||||
| 	{ | 	{ | ||||||
|  | 	  if (!isdevice && win32_path.fs_has_ea ()) | ||||||
|  | 	    set_symlink_ea (h, win32_path, oldpath); | ||||||
| 	  CloseHandle (h); | 	  CloseHandle (h); | ||||||
| 	  if (!allow_ntsec && allow_ntea) | 	  if (!allow_ntsec && allow_ntea) | ||||||
| 	    set_file_attribute (false, NULL, win32_path.get_win32 (), | 	    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 | #endif | ||||||
| 	  SetFileAttributes (win32_path, attr); | 	  SetFileAttributes (win32_path, attr); | ||||||
|  |  | ||||||
| 	  if (!isdevice && win32_path.fs_has_ea ()) |  | ||||||
| 	    set_symlink_ea (win32_path, oldpath); |  | ||||||
| 	  res = 0; | 	  res = 0; | ||||||
| 	} | 	} | ||||||
|       else |       else | ||||||
| @@ -3340,16 +3340,6 @@ symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt) | |||||||
|       if (!sym_check) |       if (!sym_check) | ||||||
| 	goto file_not_symlink; | 	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.  */ |       /* Open the file.  */ | ||||||
|  |  | ||||||
|       h = CreateFile (suffix.path, GENERIC_READ, FILE_SHARE_READ, |       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) |       if (h == INVALID_HANDLE_VALUE) | ||||||
| 	goto file_not_symlink; | 	goto file_not_symlink; | ||||||
|  |  | ||||||
|       /* FIXME: if symlink isn't present in EA, but EAs are supported, |       if (sym_check > 0 && opt & PC_CHECK_EA | ||||||
| 	 should we write it there?  */ | 	  && (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) |       switch (sym_check) | ||||||
| 	{ | 	{ | ||||||
| 	case 1: | 	case 1: | ||||||
|   | |||||||
| @@ -1405,7 +1405,8 @@ get_file_attribute (int use_ntsec, HANDLE handle, const char *file, | |||||||
|   if (allow_ntea) |   if (allow_ntea) | ||||||
|     { |     { | ||||||
|       int oatt = *attribute; |       int oatt = *attribute; | ||||||
|       res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof (*attribute)); |       res = read_ea (handle, file, ".UNIXATTR", (char *)attribute, | ||||||
|  | 		     sizeof (*attribute)); | ||||||
|       *attribute |= oatt; |       *attribute |= oatt; | ||||||
|     } |     } | ||||||
|   else |   else | ||||||
| @@ -1801,8 +1802,8 @@ set_file_attribute (bool use_ntsec, HANDLE handle, const char *file, | |||||||
|  |  | ||||||
|   if (use_ntsec && allow_ntsec) |   if (use_ntsec && allow_ntsec) | ||||||
|     ret = set_nt_attribute (handle, file, uid, gid, attribute); |     ret = set_nt_attribute (handle, file, uid, gid, attribute); | ||||||
|   else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute, |   else if (allow_ntea && !write_ea (handle, file, ".UNIXATTR", | ||||||
| 				     sizeof (attribute))) | 				    (char *) &attribute, sizeof (attribute))) | ||||||
|     { |     { | ||||||
|       __seterrno (); |       __seterrno (); | ||||||
|       ret = -1; |       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, | extern bool sec_acl (PACL acl, bool original, bool admins, PSID sid1 = NO_SID, | ||||||
| 		     PSID sid2 = NO_SID, DWORD access2 = 0); | 		     PSID sid2 = NO_SID, DWORD access2 = 0); | ||||||
|  |  | ||||||
| int __stdcall NTReadEA (const char *file, const char *attrname, char *buf, int len); | int __stdcall read_ea (HANDLE hdl, const char *file, const char *attrname, | ||||||
| BOOL __stdcall NTWriteEA (const char *file, const char *attrname, const char *buf, int len); | 		       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 | /* Note: sid1 is usually (read: currently always) the current user's | ||||||
|    effective sid (cygheap->user.sid ()). */ |    effective sid (cygheap->user.sid ()). */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user