* dtable.cc (dtable::dup_worker): Reset path_conv handle in duplicated
fhandler. * fhandler.cc (fhandler_base::fstatvfs): Keep handle in created path_conv. * fhandler.h (fhandler_base::get_stat_access): New method. (fhandler_base::get_stat_handle): New method. * fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Use handle returned by get_stat_handle. Only request inode from system if it isn't already set in the fhandler, and only for filesystems supporting them. (fhandler_base::fstat_fs): Use handle returned by get_stat_handle. Change the way open_fs is called. Explain why. (fhandler_base::fstat_helper): Use handle returned by get_stat_handle. Never use 0 inode number. Simplify executable recognition by re-using get_stat_handle if file could be opened with sufficient rights. (fhandler_disk_file::fstatvfs): Use handle returned by get_stat_handle. (fhandler_disk_file::facl): Use handle returned by get_stat_handle in GETACL and GETACLCNT cases. (fhandler_disk_file::link): Use handle returned by get_stat_handle instead of opening file here again. Add comment. (readdir_get_ino): Keep handle in created path_conv and drop opening file. * ntdll.h (wait_pending): New helper function. * path.cc (symlink_info::check): Drop unused 'opt' parameter from declaration. Add path_conv_handle argument. (path_conv::check): Make sure conv_handle is closed. Keep PC_KEEP_HANDLE flag in pflags_or. Accommodate call to sym.check to new args. (path_conv::~path_conv): Close conv_handle. (symlink_info::check_shortcut): Don't re-open file here, just use incoming handle. Drop goto's and label out. (symlink_info::check_sysfile): Don't re-open file here, just use incoming handle. Keep track of file position to accommodate the fact that file has been opened asynchronously in calling function. (symlink_info::check_nfs_symlink): Don't re-open file here, just use incoming handle. (symlink_info::check): Drop unused 'opt' parameter. Add path_conv_handle argument. Always try to open file with GENERIC_READ rights first to allow reading file content w/o having to re-open the file. Drop back to READ_CONTROL | FILE_READ_ATTRIBUTES otherwise. Call symlink test functions (except for check_reparse_point) only if file could be opened with GENERIC_READ. Keep file handle open if PC_KEEP_HANDLE is set in pflags. * path.h (enum pathconv_arg): Add PC_KEEP_HANDLE flag. (class path_conv_handle): New class. (class path_conv): Add conv_handle member. (path_conv::operator =): Duplicate conv_handle. (path_conv::handle): New method. (path_conv::access): New method. (path_conv::reset_conv_handle): New method. (path_conv::close_conv_handle): New method.
This commit is contained in:
		| @@ -1,3 +1,57 @@ | ||||
| 2010-06-15  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* dtable.cc (dtable::dup_worker): Reset path_conv handle in duplicated | ||||
| 	fhandler. | ||||
| 	* fhandler.cc (fhandler_base::fstatvfs): Keep handle in created | ||||
| 	path_conv. | ||||
| 	* fhandler.h (fhandler_base::get_stat_access): New method. | ||||
| 	(fhandler_base::get_stat_handle): New method. | ||||
| 	* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Use handle | ||||
| 	returned by get_stat_handle.  Only request inode from system if it | ||||
| 	isn't already set in the fhandler, and only for filesystems supporting | ||||
| 	them. | ||||
| 	(fhandler_base::fstat_fs): Use handle returned by get_stat_handle. | ||||
| 	Change the way open_fs is called.  Explain why. | ||||
| 	(fhandler_base::fstat_helper): Use handle returned by get_stat_handle. | ||||
| 	Never use 0 inode number.  Simplify executable recognition by re-using | ||||
| 	get_stat_handle if file could be opened with sufficient rights. | ||||
| 	(fhandler_disk_file::fstatvfs): Use handle returned by get_stat_handle. | ||||
| 	(fhandler_disk_file::facl): Use handle returned by get_stat_handle in | ||||
| 	GETACL and GETACLCNT cases. | ||||
| 	(fhandler_disk_file::link): Use handle returned by get_stat_handle | ||||
| 	instead of opening file here again.  Add comment. | ||||
| 	(readdir_get_ino): Keep handle in created path_conv and drop | ||||
| 	opening file. | ||||
| 	* ntdll.h (wait_pending): New helper function. | ||||
| 	* path.cc (symlink_info::check): Drop unused 'opt' parameter from | ||||
| 	declaration.  Add path_conv_handle argument. | ||||
| 	(path_conv::check): Make sure conv_handle is closed.  Keep | ||||
| 	PC_KEEP_HANDLE flag in pflags_or.  Accommodate call to sym.check to | ||||
| 	new args. | ||||
| 	(path_conv::~path_conv): Close conv_handle. | ||||
| 	(symlink_info::check_shortcut): Don't re-open file here, just use | ||||
| 	incoming handle.  Drop goto's and label out. | ||||
| 	(symlink_info::check_sysfile): Don't re-open file here, just use | ||||
| 	incoming handle.  Keep track of file position to accommodate the fact | ||||
| 	that file has been opened asynchronously in calling function. | ||||
| 	(symlink_info::check_nfs_symlink): Don't re-open file here, just use | ||||
| 	incoming handle. | ||||
| 	(symlink_info::check): Drop unused 'opt' parameter.  Add | ||||
| 	path_conv_handle argument.  Always try to open file with GENERIC_READ | ||||
| 	rights first to allow reading file content w/o having to re-open the | ||||
| 	file.  Drop back to READ_CONTROL | FILE_READ_ATTRIBUTES otherwise. | ||||
| 	Call symlink test functions (except for check_reparse_point) only if | ||||
| 	file could be opened with GENERIC_READ.  Keep file handle open if | ||||
| 	PC_KEEP_HANDLE is set in pflags. | ||||
| 	* path.h (enum pathconv_arg): Add PC_KEEP_HANDLE flag. | ||||
| 	(class path_conv_handle): New class. | ||||
| 	(class path_conv): Add conv_handle member. | ||||
| 	(path_conv::operator =): Duplicate conv_handle. | ||||
| 	(path_conv::handle): New method. | ||||
| 	(path_conv::access): New method. | ||||
| 	(path_conv::reset_conv_handle): New method. | ||||
| 	(path_conv::close_conv_handle): New method. | ||||
|  | ||||
| 2010-06-15  Corinna Vinschen  <corinna@vinschen.de> | ||||
|  | ||||
| 	* fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Fix indentation. | ||||
|   | ||||
| @@ -582,6 +582,7 @@ dtable::dup_worker (fhandler_base *oldfh, int flags) | ||||
|     { | ||||
|       *newfh = *oldfh; | ||||
|       newfh->set_io_handle (NULL); | ||||
|       newfh->pc.reset_conv_handle (); | ||||
|       if (oldfh->dup (newfh)) | ||||
| 	{ | ||||
| 	  delete newfh; | ||||
|   | ||||
| @@ -1124,7 +1124,7 @@ fhandler_base::fstatvfs (struct statvfs *sfs) | ||||
| { | ||||
|   /* If we hit this base implementation, it's some device in /dev. | ||||
|      Just call statvfs on /dev for simplicity. */ | ||||
|   path_conv pc ("/dev"); | ||||
|   path_conv pc ("/dev", PC_KEEP_HANDLE); | ||||
|   fhandler_disk_file fh (pc); | ||||
|   return fh.fstatvfs (sfs); | ||||
| } | ||||
|   | ||||
| @@ -181,6 +181,7 @@ class fhandler_base | ||||
|  | ||||
|   int get_access () const { return access; } | ||||
|   void set_access (int x) { access = x; } | ||||
|   int get_stat_access () const { return pc.handle () ? pc.access () : access; } | ||||
|  | ||||
|   int get_flags () { return openflags; } | ||||
|   void set_flags (int x, int supplied_bin = 0); | ||||
| @@ -355,6 +356,7 @@ class fhandler_base | ||||
|   virtual HANDLE& get_handle () { return io_handle; } | ||||
|   virtual HANDLE& get_io_handle () { return io_handle; } | ||||
|   virtual HANDLE& get_output_handle () { return io_handle; } | ||||
|   virtual HANDLE get_stat_handle () { return pc.handle () ?: io_handle; } | ||||
|   virtual bool hit_eof () {return false;} | ||||
|   virtual select_record *select_read (select_stuff *); | ||||
|   virtual select_record *select_write (select_stuff *); | ||||
|   | ||||
| @@ -333,6 +333,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) | ||||
| { | ||||
|   NTSTATUS status; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   HANDLE h = get_stat_handle (); | ||||
|  | ||||
|   if (pc.fs_is_nfs ()) | ||||
|     return fstat_by_nfs_ea (buf); | ||||
| @@ -351,22 +352,22 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) | ||||
|  | ||||
|   if (pc.has_buggy_basic_info ()) | ||||
|     { | ||||
|       status = NtQueryInformationFile (get_handle (), &io, &fi, sizeof fi, | ||||
|       status = NtQueryInformationFile (h, &io, &fi, sizeof fi, | ||||
| 				       FileNetworkOpenInformation); | ||||
|       /* The timestamps are in the same relative memory location, only | ||||
| 	 the DOS attributes have to be moved. */ | ||||
|       fi.fbi.FileAttributes = fi.fnoi.FileAttributes; | ||||
|     } | ||||
|   else | ||||
|     status = NtQueryInformationFile (get_handle (), &io, &fi.fbi, sizeof fi.fbi, | ||||
| 				     FileBasicInformation); | ||||
|     status = NtQueryInformationFile (h, &io, &fi.fbi, | ||||
| 				     sizeof fi.fbi, FileBasicInformation); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     { | ||||
|       debug_printf ("%p = NtQueryInformationFile(%S, FileBasicInformation)", | ||||
| 		    status, pc.get_nt_native_path ()); | ||||
|       return -1; | ||||
|     } | ||||
|   status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, | ||||
|   status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi, | ||||
| 				   FileStandardInformation); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     { | ||||
| @@ -374,7 +375,9 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) | ||||
| 		    status, pc.get_nt_native_path ()); | ||||
|       return -1; | ||||
|     } | ||||
|   status = NtQueryInformationFile (get_handle (), &io, &fii, sizeof fii, | ||||
|   if (!ino && pc.hasgood_inode ()) | ||||
|     { | ||||
|       status = NtQueryInformationFile (h, &io, &fii, sizeof fii, | ||||
| 				       FileInternalInformation); | ||||
|       if (!NT_SUCCESS (status)) | ||||
| 	{ | ||||
| @@ -382,6 +385,8 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) | ||||
| 			status, pc.get_nt_native_path ()); | ||||
| 	  return -1; | ||||
| 	} | ||||
|       ino = fii.FileId.QuadPart; | ||||
|     } | ||||
|   /* If the change time is 0, it's a file system which doesn't | ||||
|      support a change timestamp.  In that case use the LastWriteTime | ||||
|      entry, as in other calls to fstat_helper. */ | ||||
| @@ -397,7 +402,7 @@ fhandler_base::fstat_by_handle (struct __stat64 *buf) | ||||
| 		       get_dev (), | ||||
| 		       fsi.EndOfFile.QuadPart, | ||||
| 		       fsi.AllocationSize.QuadPart, | ||||
| 		       fii.FileId.QuadPart, | ||||
| 		       ino, | ||||
| 		       fsi.NumberOfLinks, | ||||
| 		       fi.fbi.FileAttributes); | ||||
| } | ||||
| @@ -492,7 +497,7 @@ fhandler_base::fstat_fs (struct __stat64 *buf) | ||||
|   int oret; | ||||
|   int open_flags = O_RDONLY | O_BINARY; | ||||
|  | ||||
|   if (get_handle ()) | ||||
|   if (get_stat_handle ()) | ||||
|     { | ||||
|       if (!nohandle () && !is_fs_special ()) | ||||
| 	res = fstat_by_handle (buf); | ||||
| @@ -500,8 +505,16 @@ fhandler_base::fstat_fs (struct __stat64 *buf) | ||||
| 	res = fstat_by_name (buf); | ||||
|       return res; | ||||
|     } | ||||
|   /* First try to open with generic read access.  This allows to read the file | ||||
|      in fstat_helper (when checking for executability) without having to | ||||
|      re-open it.  Opening a file can take a lot of time on network drives | ||||
|      so we try to avoid that. */ | ||||
|   oret = open_fs (open_flags, 0); | ||||
|   if (!oret) | ||||
|     { | ||||
|       query_open (query_read_attributes); | ||||
|       oret = open_fs (open_flags, 0); | ||||
|     } | ||||
|   if (oret) | ||||
|     { | ||||
|       /* We now have a valid handle, regardless of the "nohandle" state. | ||||
| @@ -546,6 +559,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, | ||||
| { | ||||
|   IO_STATUS_BLOCK st; | ||||
|   FILE_COMPRESSION_INFORMATION fci; | ||||
|   HANDLE h = get_stat_handle (); | ||||
|  | ||||
|   to_timestruc_t ((PFILETIME) LastAccessTime, &buf->st_atim); | ||||
|   to_timestruc_t ((PFILETIME) LastWriteTime, &buf->st_mtim); | ||||
| @@ -563,7 +577,7 @@ fhandler_base::fstat_helper (struct __stat64 *buf, | ||||
| #endif | ||||
|  | ||||
|   /* Enforce namehash as inode number on untrusted file systems. */ | ||||
|   if (pc.isgood_inode (nFileIndex)) | ||||
|   if (nFileIndex && pc.isgood_inode (nFileIndex)) | ||||
|     buf->st_ino = (__ino64_t) nFileIndex; | ||||
|   else | ||||
|     buf->st_ino = get_ino (); | ||||
| @@ -576,9 +590,9 @@ fhandler_base::fstat_helper (struct __stat64 *buf, | ||||
|     buf->st_blocks = (nAllocSize + S_BLKSIZE - 1) / S_BLKSIZE; | ||||
|   else if (::has_attribute (dwFileAttributes, FILE_ATTRIBUTE_COMPRESSED | ||||
| 					      | FILE_ATTRIBUTE_SPARSE_FILE) | ||||
| 	   && get_handle () && !is_fs_special () | ||||
| 	   && !NtQueryInformationFile (get_handle (), &st, (PVOID) &fci, | ||||
| 				      sizeof fci, FileCompressionInformation)) | ||||
| 	   && h && !is_fs_special () | ||||
| 	   && !NtQueryInformationFile (h, &st, (PVOID) &fci, sizeof fci, | ||||
| 				       FileCompressionInformation)) | ||||
|     /* Otherwise we request the actual amount of bytes allocated for | ||||
|        compressed and sparsed files. */ | ||||
|     buf->st_blocks = (fci.CompressedFileSize.QuadPart + S_BLKSIZE - 1) | ||||
| @@ -597,15 +611,14 @@ fhandler_base::fstat_helper (struct __stat64 *buf, | ||||
|       buf->st_size = pc.get_symlink_length (); | ||||
|       /* symlinks are everything for everyone! */ | ||||
|       buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO; | ||||
|       get_file_attribute (get_handle (), pc, NULL, | ||||
|       get_file_attribute (h, pc, NULL, | ||||
| 			  &buf->st_uid, &buf->st_gid); | ||||
|       goto done; | ||||
|     } | ||||
|   else if (pc.issocket ()) | ||||
|     buf->st_mode = S_IFSOCK; | ||||
|  | ||||
|   if (!get_file_attribute (is_fs_special () && !pc.issocket () | ||||
| 			   ? NULL : get_handle (), pc, | ||||
|   if (!get_file_attribute (is_fs_special () && !pc.issocket () ? NULL : h, pc, | ||||
| 			   &buf->st_mode, &buf->st_uid, &buf->st_gid)) | ||||
|     { | ||||
|       /* If read-only attribute is set, modify ntsec return value */ | ||||
| @@ -658,51 +671,27 @@ fhandler_base::fstat_helper (struct __stat64 *buf, | ||||
| 	  /* No known suffix, check file header.  This catches binaries and | ||||
| 	     shebang scripts. */ | ||||
| 	  if (pc.exec_state () == dont_know_if_executable) | ||||
| 	    { | ||||
| 	      OBJECT_ATTRIBUTES attr; | ||||
| 	      NTSTATUS status; | ||||
| 	      HANDLE h; | ||||
| 	      IO_STATUS_BLOCK io; | ||||
|  | ||||
| 	      /* The NWFS implementation is frighteningly incomplete.  When | ||||
| 	         re-opening a file by handle, the subsequent NtReadFile | ||||
| 		 returns with the weird status STATUS_FILE_IS_A_DIRECTORY. | ||||
| 		 We're still using the re-open by handle method for all | ||||
| 		 other filesystems since it's 8-10% faster than opening | ||||
| 		 by name. */ | ||||
| 	      if (pc.fs_is_nwfs ()) | ||||
| 		InitializeObjectAttributes (&attr, pc.get_nt_native_path (), | ||||
| 					    OBJ_CASE_INSENSITIVE, NULL, NULL) | ||||
| 	      else | ||||
| 		InitializeObjectAttributes (&attr, &ro_u_empty, 0, | ||||
| 					    get_handle (), NULL); | ||||
| 	      status = NtOpenFile (&h, SYNCHRONIZE | FILE_READ_DATA, | ||||
| 				   &attr, &io, FILE_SHARE_VALID_FLAGS, | ||||
| 				   FILE_SYNCHRONOUS_IO_NONALERT); | ||||
| 	      if (NT_SUCCESS (status)) | ||||
| 	    { | ||||
| 	      LARGE_INTEGER off = { QuadPart:0LL }; | ||||
| 	      char magic[3]; | ||||
| 	      NTSTATUS status; | ||||
| 	      IO_STATUS_BLOCK io; | ||||
|  | ||||
| 		  status = NtReadFile (h, NULL, NULL, NULL, &io, magic, | ||||
| 				       3, &off, NULL); | ||||
| 		  if (NT_SUCCESS (status)) | ||||
| 	      if (get_stat_access () & (GENERIC_READ | FILE_READ_DATA)) | ||||
| 		{ | ||||
| 		      if (has_exec_chars (magic, io.Information)) | ||||
| 		  status = NtReadFile (h, NULL, NULL, NULL, | ||||
| 				       &io, magic, 3, &off, NULL); | ||||
| 		  status = wait_pending (status, h, io); | ||||
| 		  if (!NT_SUCCESS (status)) | ||||
| 		    debug_printf ("%p = NtReadFile(%S)", status, | ||||
| 				  pc.get_nt_native_path ()); | ||||
| 		  else if (has_exec_chars (magic, io.Information)) | ||||
| 		    { | ||||
| 		      /* Heureka, it's an executable */ | ||||
| 		      pc.set_exec (); | ||||
| 		      buf->st_mode |= STD_XBITS; | ||||
| 		    } | ||||
| 		} | ||||
| 		  else | ||||
| 		    debug_printf ("%p = NtReadFile(%S)", status, | ||||
| 				  pc.get_nt_native_path ()); | ||||
| 		  NtClose (h); | ||||
| 		} | ||||
| 	      else | ||||
| 		debug_printf ("%p = NtOpenFile(%S)", status, | ||||
| 			      pc.get_nt_native_path ()); | ||||
| 	    } | ||||
| 	} | ||||
|       if (pc.exec_state () == is_executable) | ||||
| @@ -740,7 +729,7 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs) | ||||
|   IO_STATUS_BLOCK io; | ||||
|   FILE_FS_FULL_SIZE_INFORMATION full_fsi; | ||||
|   FILE_FS_SIZE_INFORMATION fsi; | ||||
|   HANDLE fh = get_handle (); | ||||
|   HANDLE fh = get_stat_handle (); | ||||
|  | ||||
|   if (!fh) | ||||
|     { | ||||
| @@ -1050,7 +1039,8 @@ cant_access_acl: | ||||
|     } | ||||
|   else | ||||
|     { | ||||
|       if (!get_handle ()) | ||||
|       if ((cmd == SETACL && !get_handle ()) | ||||
| 	  || (cmd != SETACL && !get_stat_handle ())) | ||||
| 	{ | ||||
| 	  query_open (cmd == SETACL ? query_write_control : query_read_control); | ||||
| 	  if (!(oret = open (O_BINARY, 0))) | ||||
| @@ -1087,10 +1077,10 @@ cant_access_acl: | ||||
| 	    if (!aclbufp) | ||||
| 	      set_errno(EFAULT); | ||||
| 	    else | ||||
| 	      res = getacl (get_handle (), pc, nentries, aclbufp); | ||||
| 	      res = getacl (get_stat_handle (), pc, nentries, aclbufp); | ||||
| 	    break; | ||||
| 	  case GETACLCNT: | ||||
| 	    res = getacl (get_handle (), pc, 0, NULL); | ||||
| 	    res = getacl (get_stat_handle (), pc, 0, NULL); | ||||
| 	    break; | ||||
| 	  default: | ||||
| 	    set_errno (EINVAL); | ||||
| @@ -1277,17 +1267,13 @@ fhandler_disk_file::link (const char *newpath) | ||||
| 	} | ||||
|     } | ||||
|  | ||||
|   HANDLE fh; | ||||
|   NTSTATUS status; | ||||
|   OBJECT_ATTRIBUTES attr; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   status = NtOpenFile (&fh, READ_CONTROL, | ||||
| 		       pc.get_object_attr (attr, sec_none_nih), &io, | ||||
| 		       FILE_SHARE_VALID_FLAGS, | ||||
| 		       FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|   /* We only need READ_CONTROL access so the handle returned in pc is | ||||
|      sufficient.  And if the file couldn't be opened with READ_CONTROL | ||||
|      access in path_conv, we won't be able to do it here anyway. */ | ||||
|   HANDLE fh = get_stat_handle (); | ||||
|   if (!fh) | ||||
|     { | ||||
|       __seterrno_from_nt_status (status); | ||||
|       set_errno (EACCES); | ||||
|       return -1; | ||||
|     } | ||||
|   PUNICODE_STRING tgt = newpc.get_nt_native_path (); | ||||
| @@ -1296,8 +1282,10 @@ fhandler_disk_file::link (const char *newpath) | ||||
|   pfli->ReplaceIfExists = FALSE; | ||||
|   pfli->RootDirectory = NULL; | ||||
|   memcpy (pfli->FileName, tgt->Buffer, pfli->FileNameLength = tgt->Length); | ||||
|  | ||||
|   NTSTATUS status; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   status = NtSetInformationFile (fh, &io, pfli, size, FileLinkInformation); | ||||
|   NtClose (fh); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     { | ||||
|       if (status == STATUS_INVALID_DEVICE_REQUEST) | ||||
| @@ -1764,8 +1752,6 @@ readdir_get_ino (const char *path, bool dot_dot) | ||||
|   char *fname; | ||||
|   struct __stat64 st; | ||||
|   HANDLE hdl; | ||||
|   OBJECT_ATTRIBUTES attr; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   __ino64_t ino = 0; | ||||
|  | ||||
|   if (dot_dot) | ||||
| @@ -1777,7 +1763,7 @@ readdir_get_ino (const char *path, bool dot_dot) | ||||
|       strcpy (c, ".."); | ||||
|       path = fname; | ||||
|     } | ||||
|   path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX | PC_NOWARN); | ||||
|   path_conv pc (path, PC_SYM_NOFOLLOW | PC_POSIX | PC_NOWARN | PC_KEEP_HANDLE); | ||||
|   if (pc.isspecial ()) | ||||
|     { | ||||
|       if (!stat_worker (pc, &st)) | ||||
| @@ -1785,17 +1771,11 @@ readdir_get_ino (const char *path, bool dot_dot) | ||||
|     } | ||||
|   else if (!pc.hasgood_inode ()) | ||||
|     ino = hash_path_name (0, pc.get_nt_native_path ()); | ||||
|   else if (NT_SUCCESS (NtOpenFile (&hdl, READ_CONTROL, | ||||
| 				   pc.get_object_attr (attr, sec_none_nih), | ||||
| 				   &io, FILE_SHARE_VALID_FLAGS, | ||||
| 				   FILE_OPEN_FOR_BACKUP_INTENT | ||||
| 				   | (pc.is_rep_symlink () | ||||
| 				      ? FILE_OPEN_REPARSE_POINT : 0)))) | ||||
|   else if ((hdl = pc.handle ()) != NULL) | ||||
|     { | ||||
|       ino = pc.get_ino_by_handle (hdl); | ||||
|       if (!ino) | ||||
| 	ino = hash_path_name (0, pc.get_nt_native_path ()); | ||||
|       NtClose (hdl); | ||||
|     } | ||||
|   return ino; | ||||
| } | ||||
|   | ||||
| @@ -868,6 +868,16 @@ typedef enum _EVENT_INFORMATION_CLASS | ||||
| #define NtCurrentProcess() ((HANDLE) 0xffffffff) | ||||
| #define NtCurrentThread()  ((HANDLE) 0xfffffffe) | ||||
|  | ||||
| /* Helper macro for sync I/O with async handle. */ | ||||
| inline NTSTATUS | ||||
| wait_pending (NTSTATUS status, HANDLE h, IO_STATUS_BLOCK &io) | ||||
| { | ||||
|   if (status != STATUS_PENDING) | ||||
|     return status; | ||||
|   WaitForSingleObject (h, INFINITE); | ||||
|   return io.Status; | ||||
| } | ||||
|  | ||||
| extern "C" | ||||
| { | ||||
|   NTSTATUS NTAPI NtAdjustPrivilegesToken (HANDLE, BOOLEAN, PTOKEN_PRIVILEGES, | ||||
|   | ||||
| @@ -96,8 +96,8 @@ struct symlink_info | ||||
|   _major_t major; | ||||
|   _minor_t minor; | ||||
|   _mode_t mode; | ||||
|   int check (char *path, const suffix_info *suffixes, unsigned opt, | ||||
| 	     fs_info &fs); | ||||
|   int check (char *path, const suffix_info *suffixes, fs_info &fs, | ||||
| 	     path_conv_handle &conv_hdl); | ||||
|   int set (char *path); | ||||
|   bool parse_device (const char *); | ||||
|   int check_sysfile (HANDLE h); | ||||
| @@ -639,6 +639,7 @@ path_conv::check (const char *src, unsigned opt, | ||||
|       cfree (modifiable_path ()); | ||||
|       path = NULL; | ||||
|     } | ||||
|   close_conv_handle (); | ||||
|   memset (&dev, 0, sizeof (dev)); | ||||
|   fs.clear (); | ||||
|   if (normalized_path) | ||||
| @@ -695,7 +696,9 @@ path_conv::check (const char *src, unsigned opt, | ||||
|  | ||||
|       int symlen = 0; | ||||
|  | ||||
|       for (unsigned pflags_or = opt & PC_NO_ACCESS_CHECK; ; pflags_or = 0) | ||||
|       for (unsigned pflags_or = opt & (PC_NO_ACCESS_CHECK | PC_KEEP_HANDLE); | ||||
| 	   ; | ||||
| 	   pflags_or = 0) | ||||
| 	{ | ||||
| 	  const suffix_info *suff; | ||||
| 	  char *full_path; | ||||
| @@ -823,7 +826,7 @@ path_conv::check (const char *src, unsigned opt, | ||||
| 	  if (is_msdos) | ||||
| 	    sym.pflags |= PATH_NOPOSIX | PATH_NOACL; | ||||
|  | ||||
| 	  symlen = sym.check (full_path, suff, opt, fs); | ||||
| 	  symlen = sym.check (full_path, suff, fs, conv_handle); | ||||
|  | ||||
| is_virtual_symlink: | ||||
|  | ||||
| @@ -1124,6 +1127,7 @@ path_conv::~path_conv () | ||||
|       cfree (wide_path); | ||||
|       wide_path = NULL; | ||||
|     } | ||||
|   close_conv_handle (); | ||||
| } | ||||
|  | ||||
| bool | ||||
| @@ -1683,55 +1687,50 @@ cmp_shortcut_header (win_shortcut_hdr *file_header) | ||||
| } | ||||
|  | ||||
| int | ||||
| symlink_info::check_shortcut (HANDLE in_h) | ||||
| symlink_info::check_shortcut (HANDLE h) | ||||
| { | ||||
|   tmp_pathbuf tp; | ||||
|   win_shortcut_hdr *file_header; | ||||
|   char *buf, *cp; | ||||
|   unsigned short len; | ||||
|   int res = 0; | ||||
|   OBJECT_ATTRIBUTES attr; | ||||
|   NTSTATUS status; | ||||
|   HANDLE h; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   FILE_STANDARD_INFORMATION fsi; | ||||
|   LARGE_INTEGER off = { QuadPart:0LL }; | ||||
|  | ||||
|   InitializeObjectAttributes (&attr, &ro_u_empty, 0, in_h, NULL); | ||||
|   status = NtOpenFile (&h, FILE_READ_DATA | SYNCHRONIZE, | ||||
| 		       &attr, &io, FILE_SHARE_VALID_FLAGS, | ||||
| 		       FILE_OPEN_FOR_BACKUP_INTENT | ||||
| 		       | FILE_SYNCHRONOUS_IO_NONALERT); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     return 0; | ||||
|   status = NtQueryInformationFile (h, &io, &fsi, sizeof fsi, | ||||
| 				   FileStandardInformation); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     { | ||||
|       set_error (EIO); | ||||
|       goto out; | ||||
|       return 0; | ||||
|     } | ||||
|   if (fsi.EndOfFile.QuadPart <= sizeof (win_shortcut_hdr) | ||||
|       || fsi.EndOfFile.QuadPart > 4 * 65536) | ||||
|     goto out; | ||||
|     return 0; | ||||
|   if (fsi.EndOfFile.LowPart < NT_MAX_PATH * sizeof (WCHAR)) | ||||
|     buf = (char *) tp.w_get (); | ||||
|   else | ||||
|     buf = (char *) alloca (fsi.EndOfFile.LowPart + 1); | ||||
|   if (!NT_SUCCESS (NtReadFile (h, NULL, NULL, NULL, | ||||
| 			       &io, buf, fsi.EndOfFile.LowPart, NULL, NULL))) | ||||
|   status = NtReadFile (h, NULL, NULL, NULL, &io, buf, fsi.EndOfFile.LowPart, | ||||
| 		       &off, NULL); | ||||
|   status = wait_pending (status, h, io); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     { | ||||
|       if (status != STATUS_END_OF_FILE) | ||||
| 	set_error (EIO); | ||||
|       goto out; | ||||
|       return 0; | ||||
|     } | ||||
|   file_header = (win_shortcut_hdr *) buf; | ||||
|   if (io.Information != fsi.EndOfFile.LowPart | ||||
|       || !cmp_shortcut_header (file_header)) | ||||
|     goto out; | ||||
|     return 0; | ||||
|   cp = buf + sizeof (win_shortcut_hdr); | ||||
|   if (file_header->flags & WSH_FLAG_IDLIST) /* Skip ITEMIDLIST */ | ||||
|     cp += *(unsigned short *) cp + 2; | ||||
|   if (!(len = *(unsigned short *) cp)) | ||||
|     goto out; | ||||
|     return 0; | ||||
|   cp += 2; | ||||
|   /* Check if this is a device file - these start with the sequence :\\ */ | ||||
|   if (strncmp (cp, ":\\", 2) == 0) | ||||
| @@ -1751,11 +1750,11 @@ symlink_info::check_shortcut (HANDLE in_h) | ||||
| 	  char *tmpbuf = tp.c_get (); | ||||
| 	  if (sys_wcstombs (tmpbuf, NT_MAX_PATH, (PWCHAR) (cp + 2)) | ||||
| 	      > SYMLINK_MAX + 1) | ||||
| 	    goto out; | ||||
| 	    return 0; | ||||
| 	  res = posixify (tmpbuf); | ||||
| 	} | ||||
|       else if (len > SYMLINK_MAX) | ||||
| 	goto out; | ||||
| 	return 0; | ||||
|       else | ||||
| 	{ | ||||
| 	  cp[len] = '\0'; | ||||
| @@ -1764,41 +1763,33 @@ symlink_info::check_shortcut (HANDLE in_h) | ||||
|     } | ||||
|   if (res) /* It's a symlink.  */ | ||||
|     pflags |= PATH_SYMLINK | PATH_LNK; | ||||
|  | ||||
| out: | ||||
|   NtClose (h); | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| int | ||||
| symlink_info::check_sysfile (HANDLE in_h) | ||||
| symlink_info::check_sysfile (HANDLE h) | ||||
| { | ||||
|   tmp_pathbuf tp; | ||||
|   char cookie_buf[sizeof (SYMLINK_COOKIE) - 1]; | ||||
|   char *srcbuf = tp.c_get (); | ||||
|   int res = 0; | ||||
|   OBJECT_ATTRIBUTES attr; | ||||
|   NTSTATUS status; | ||||
|   HANDLE h; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   bool interix_symlink = false; | ||||
|   LARGE_INTEGER off = { QuadPart:0LL }; | ||||
|  | ||||
|   InitializeObjectAttributes (&attr, &ro_u_empty, 0, in_h, NULL); | ||||
|   status = NtOpenFile (&h, FILE_READ_DATA | SYNCHRONIZE, | ||||
| 		       &attr, &io, FILE_SHARE_VALID_FLAGS, | ||||
| 		       FILE_OPEN_FOR_BACKUP_INTENT | ||||
| 		       | FILE_SYNCHRONOUS_IO_NONALERT); | ||||
|   status = NtReadFile (h, NULL, NULL, NULL, &io, cookie_buf, | ||||
| 		       sizeof (cookie_buf), &off, NULL); | ||||
|   status = wait_pending (status, h, io); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     return 0; | ||||
|   else if (!NT_SUCCESS (status = NtReadFile (h, NULL, NULL, NULL, &io, | ||||
| 					     cookie_buf, sizeof (cookie_buf), | ||||
| 					     NULL, NULL))) | ||||
|     { | ||||
|       debug_printf ("ReadFile1 failed %p", status); | ||||
|       if (status != STATUS_END_OF_FILE) | ||||
| 	set_error (EIO); | ||||
|       return 0; | ||||
|     } | ||||
|   else if (io.Information == sizeof (cookie_buf) | ||||
|   off.QuadPart = io.Information; | ||||
|   if (io.Information == sizeof (cookie_buf) | ||||
| 	   && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0) | ||||
|     { | ||||
|       /* It's a symlink.  */ | ||||
| @@ -1817,14 +1808,13 @@ symlink_info::check_sysfile (HANDLE in_h) | ||||
|       /* Interix symlink cookies are shorter than Cygwin symlink cookies, so | ||||
|          in case of an Interix symlink cooky we have read too far into the | ||||
| 	 file.  Set file pointer back to the position right after the cookie. */ | ||||
|       FILE_POSITION_INFORMATION fpi; | ||||
|       fpi.CurrentByteOffset.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1; | ||||
|       NtSetInformationFile (h, &io, &fpi, sizeof fpi, FilePositionInformation); | ||||
|       off.QuadPart = sizeof (INTERIX_SYMLINK_COOKIE) - 1; | ||||
|     } | ||||
|   if (pflags & PATH_SYMLINK) | ||||
|     { | ||||
|       status = NtReadFile (h, NULL, NULL, NULL, &io, srcbuf, | ||||
| 			   NT_MAX_PATH, NULL, NULL); | ||||
| 			   NT_MAX_PATH, &off, NULL); | ||||
|       status = wait_pending (status, h, io); | ||||
|       if (!NT_SUCCESS (status)) | ||||
| 	{ | ||||
| 	  debug_printf ("ReadFile2 failed"); | ||||
| @@ -1852,7 +1842,6 @@ symlink_info::check_sysfile (HANDLE in_h) | ||||
|       else | ||||
| 	res = posixify (srcbuf); | ||||
|     } | ||||
|   NtClose (h); | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| @@ -1916,7 +1905,6 @@ symlink_info::check_nfs_symlink (HANDLE h) | ||||
| { | ||||
|   tmp_pathbuf tp; | ||||
|   NTSTATUS status; | ||||
|   OBJECT_ATTRIBUTES attr; | ||||
|   IO_STATUS_BLOCK io; | ||||
|   struct { | ||||
|     FILE_GET_EA_INFORMATION fgei; | ||||
| @@ -1925,11 +1913,6 @@ symlink_info::check_nfs_symlink (HANDLE h) | ||||
|   PFILE_FULL_EA_INFORMATION pffei; | ||||
|   int res = 0; | ||||
|  | ||||
|   InitializeObjectAttributes (&attr, &ro_u_empty, 0, h, NULL); | ||||
|   status = NtOpenFile (&h, FILE_READ_EA, &attr, &io, FILE_SHARE_VALID_FLAGS, | ||||
| 		       FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT); | ||||
|   if (!NT_SUCCESS (status)) | ||||
|     return 0; | ||||
|   /* To find out if the file is a symlink and to get the symlink target, | ||||
|      try to fetch the NfsSymlinkTargetName EA. */ | ||||
|   fgei_buf.fgei.NextEntryOffset = 0; | ||||
| @@ -1938,13 +1921,12 @@ symlink_info::check_nfs_symlink (HANDLE h) | ||||
|   pffei = (PFILE_FULL_EA_INFORMATION) tp.w_get (); | ||||
|   status = NtQueryEaFile (h, &io, pffei, NT_MAX_PATH * sizeof (WCHAR), TRUE, | ||||
| 			  &fgei_buf.fgei, sizeof fgei_buf, NULL, TRUE); | ||||
|   NtClose (h); | ||||
|   if (NT_SUCCESS (status) && pffei->EaValueLength > 0) | ||||
|     { | ||||
|       PWCHAR spath = (PWCHAR) | ||||
| 		     (pffei->EaName + pffei->EaNameLength + 1); | ||||
|       res = sys_wcstombs (contents, SYMLINK_MAX + 1, | ||||
| 		      spath, pffei->EaValueLength); | ||||
| 			  spath, pffei->EaValueLength) - 1; | ||||
|       pflags |= PATH_SYMLINK; | ||||
|     } | ||||
|   return res; | ||||
| @@ -2197,8 +2179,8 @@ symlink_info::parse_device (const char *contents) | ||||
|    stored into BUF if PATH is a symlink.  */ | ||||
|  | ||||
| int | ||||
| symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt, | ||||
| 		     fs_info &fs) | ||||
| symlink_info::check (char *path, const suffix_info *suffixes, fs_info &fs, | ||||
| 		     path_conv_handle &conv_hdl) | ||||
| { | ||||
|   int res; | ||||
|   HANDLE h; | ||||
| @@ -2238,6 +2220,10 @@ restart: | ||||
|   PVOID eabuf = &nfs_aol_ffei; | ||||
|   ULONG easize = sizeof nfs_aol_ffei; | ||||
|  | ||||
| # define MIN_STAT_ACCESS	(READ_CONTROL | FILE_READ_ATTRIBUTES) | ||||
| # define FULL_STAT_ACCESS	(SYNCHRONIZE | GENERIC_READ) | ||||
|   ACCESS_MASK access = 0; | ||||
|  | ||||
|   bool had_ext = !!*ext_here; | ||||
|   while (suffix.next ()) | ||||
|     { | ||||
| @@ -2255,14 +2241,22 @@ restart: | ||||
| 	 symlink (which would spoil the task of this method quite a bit). | ||||
| 	 Fortunately it's ignored on most other file systems so we don't have | ||||
| 	 to special case NFS too much. */ | ||||
|       status = NtCreateFile (&h, | ||||
| 			     READ_CONTROL | FILE_READ_ATTRIBUTES, | ||||
| 			     &attr, &io, NULL, 0, FILE_SHARE_VALID_FLAGS, | ||||
| 			     FILE_OPEN, | ||||
|       status = NtCreateFile (&h, access = FULL_STAT_ACCESS, &attr, &io, NULL, | ||||
| 			     0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, | ||||
| 			     FILE_OPEN_REPARSE_POINT | ||||
| 			     | FILE_OPEN_FOR_BACKUP_INTENT, | ||||
| 			     eabuf, easize); | ||||
|       debug_printf ("%p = NtCreateFile (%S)", status, &upath); | ||||
|       if (status == STATUS_ACCESS_DENIED) | ||||
| 	{ | ||||
| 	  status = NtCreateFile (&h, access = MIN_STAT_ACCESS, &attr, &io, | ||||
| 				 NULL, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, | ||||
| 				 FILE_OPEN_REPARSE_POINT | ||||
| 				 | FILE_OPEN_FOR_BACKUP_INTENT, | ||||
| 				 eabuf, easize); | ||||
| 	  debug_printf ("%p = NtCreateFile (2:%S)", status, &upath); | ||||
| 	} | ||||
|       else | ||||
| 	debug_printf ("%p = NtCreateFile (1:%S)", status, &upath); | ||||
|       /* No right to access EAs or EAs not supported? */ | ||||
|       if (!NT_SUCCESS (status) | ||||
| 	  && (status == STATUS_ACCESS_DENIED | ||||
| @@ -2282,11 +2276,20 @@ restart: | ||||
| 	      eabuf = NULL; | ||||
| 	      easize = 0; | ||||
| 	    } | ||||
| 	  status = NtOpenFile (&h, READ_CONTROL | FILE_READ_ATTRIBUTES, | ||||
| 			       &attr, &io, FILE_SHARE_VALID_FLAGS, | ||||
| 	  status = NtOpenFile (&h, access = FULL_STAT_ACCESS, &attr, &io, | ||||
| 			       FILE_SHARE_VALID_FLAGS, | ||||
| 			       FILE_OPEN_REPARSE_POINT | ||||
| 			       | FILE_OPEN_FOR_BACKUP_INTENT); | ||||
| 	  debug_printf ("%p = NtOpenFile (no-EA, %S)", status, &upath); | ||||
| 	  if (status == STATUS_ACCESS_DENIED) | ||||
| 	    { | ||||
| 	      status = NtOpenFile (&h, access = MIN_STAT_ACCESS, &attr, &io, | ||||
| 				   FILE_SHARE_VALID_FLAGS, | ||||
| 				   FILE_OPEN_REPARSE_POINT | ||||
| 				   | FILE_OPEN_FOR_BACKUP_INTENT); | ||||
| 	      debug_printf ("%p = NtOpenFile (no-EAs 2:%S)", status, &upath); | ||||
| 	    } | ||||
| 	  else | ||||
| 	    debug_printf ("%p = NtOpenFile (no-EA 1:%S)", status, &upath); | ||||
| 	} | ||||
|       if (status == STATUS_OBJECT_NAME_NOT_FOUND) | ||||
| 	{ | ||||
| @@ -2478,6 +2481,9 @@ restart: | ||||
|       if ((fileattr & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) | ||||
| 	  == FILE_ATTRIBUTE_READONLY && suffix.lnk_match ()) | ||||
| 	{ | ||||
| 	  if (!(access & GENERIC_READ)) | ||||
| 	    res = 0; | ||||
| 	  else | ||||
| 	    res = check_shortcut (h); | ||||
| 	  if (!res) | ||||
| 	    { | ||||
| @@ -2538,16 +2544,22 @@ restart: | ||||
|       else if ((fileattr & (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY)) | ||||
| 	       == FILE_ATTRIBUTE_SYSTEM) | ||||
| 	{ | ||||
| 	  if (!(access & GENERIC_READ)) | ||||
| 	    res = 0; | ||||
| 	  else | ||||
| 	    res = check_sysfile (h); | ||||
| 	  if (res) | ||||
| 	    break; | ||||
| 	} | ||||
|  | ||||
|       /* If the file could be opened with FILE_READ_EA, and if it's on a | ||||
| 	 NFS share, check if it's a symlink.  Only files can be symlinks | ||||
|       /* If the file is on an NFS share and could be opened with extended | ||||
| 	 attributes, check if it's a symlink.  Only files can be symlinks | ||||
| 	 (which can be symlinks to directories). */ | ||||
|       else if (fs.is_nfs () && !no_ea && !(fileattr & FILE_ATTRIBUTE_DIRECTORY)) | ||||
| 	{ | ||||
| 	  if (!(access & GENERIC_READ)) | ||||
| 	    res = 0; | ||||
| 	  else | ||||
| 	    res = check_nfs_symlink (h); | ||||
| 	  if (res) | ||||
| 	    break; | ||||
| @@ -2562,7 +2574,12 @@ restart: | ||||
|     } | ||||
|  | ||||
|   if (h) | ||||
|     { | ||||
|       if (pflags & PC_KEEP_HANDLE) | ||||
| 	conv_hdl.set (h, access); | ||||
|       else | ||||
| 	NtClose (h); | ||||
|     } | ||||
|  | ||||
|   syscall_printf ("%d = symlink.check (%s, %p) (%p)", | ||||
| 		  res, suffix.path, contents, pflags); | ||||
|   | ||||
| @@ -57,6 +57,7 @@ enum pathconv_arg | ||||
|   PC_CHECK_EA		= 0x0040, | ||||
|   PC_POSIX		= 0x0080, | ||||
|   PC_NOWARN		= 0x0100, | ||||
|   PC_KEEP_HANDLE	= 0x00400000, | ||||
|   PC_NO_ACCESS_CHECK	= 0x00800000 | ||||
| }; | ||||
|  | ||||
| @@ -86,6 +87,33 @@ enum path_types | ||||
|   PATH_SOCKET		= 0x40000000 | ||||
| }; | ||||
|  | ||||
| class path_conv_handle | ||||
| { | ||||
|   HANDLE      hdl; | ||||
|   ACCESS_MASK acc; | ||||
| public: | ||||
|   path_conv_handle () : hdl (NULL), acc (0) {} | ||||
|   inline void set (HANDLE h, ACCESS_MASK a) { hdl = h; acc = a; } | ||||
|   inline void close () | ||||
|   { | ||||
|     if (hdl) | ||||
|       CloseHandle (hdl); | ||||
|     set (NULL, 0); | ||||
|   } | ||||
|   inline void dup (path_conv_handle &pch) | ||||
|   { | ||||
|     if (!DuplicateHandle (GetCurrentProcess (), pch.handle (), | ||||
| 			  GetCurrentProcess (), &hdl, | ||||
| 			  0, TRUE, DUPLICATE_SAME_ACCESS)) | ||||
|       { | ||||
| 	hdl = NULL; | ||||
| 	acc = 0; | ||||
|       } | ||||
|   } | ||||
|   inline HANDLE handle () const { return hdl; } | ||||
|   inline ACCESS_MASK access () const { return acc; } | ||||
| }; | ||||
|  | ||||
| class symlink_info; | ||||
|  | ||||
| class path_conv | ||||
| @@ -98,6 +126,7 @@ class path_conv | ||||
|   void add_ext_from_sym (symlink_info&); | ||||
|   DWORD symlink_length; | ||||
|   const char *path; | ||||
|   path_conv_handle conv_handle; | ||||
|  public: | ||||
|   unsigned path_flags; | ||||
|   const char *known_suffix; | ||||
| @@ -220,6 +249,7 @@ class path_conv | ||||
|   { | ||||
|     memcpy (this, &pc, sizeof pc); | ||||
|     path = cstrdup (pc.path); | ||||
|     conv_handle.dup (pc.conv_handle); | ||||
|     normalized_path = cstrdup(pc.normalized_path); | ||||
|     wide_path = NULL; | ||||
|     return *this; | ||||
| @@ -250,6 +280,11 @@ class path_conv | ||||
|   } | ||||
|   bool is_binary (); | ||||
|  | ||||
|   HANDLE handle () const { return conv_handle.handle (); } | ||||
|   ACCESS_MASK access () const { return conv_handle.access (); } | ||||
|   void reset_conv_handle () { conv_handle.set (NULL, 0); } | ||||
|   void close_conv_handle () { conv_handle.close (); } | ||||
|  | ||||
|   __ino64_t get_ino_by_handle (HANDLE h); | ||||
| #if 0 /* obsolete, method still exists in fhandler_disk_file.cc */ | ||||
|   unsigned __stdcall ndisk_links (DWORD); | ||||
|   | ||||
| @@ -419,7 +419,8 @@ acl_worker (const char *path, int cmd, int nentries, __aclent32_t *aclbufp, | ||||
| 	    unsigned fmode) | ||||
| { | ||||
|   int res = -1; | ||||
|   fhandler_base *fh = build_fh_name (path, fmode, stat_suffixes); | ||||
|   fhandler_base *fh = build_fh_name (path, fmode | PC_KEEP_HANDLE, | ||||
| 				     stat_suffixes); | ||||
|   if (fh->error ()) | ||||
|     { | ||||
|       debug_printf ("got %d error from build_fh_name", fh->error ()); | ||||
|   | ||||
| @@ -1169,7 +1169,8 @@ link (const char *oldpath, const char *newpath) | ||||
|   int res = -1; | ||||
|   fhandler_base *fh; | ||||
|  | ||||
|   if (!(fh = build_fh_name (oldpath, PC_SYM_NOFOLLOW, stat_suffixes))) | ||||
|   if (!(fh = build_fh_name (oldpath, PC_SYM_NOFOLLOW | PC_KEEP_HANDLE, | ||||
| 			    stat_suffixes))) | ||||
|     goto error; | ||||
|  | ||||
|   if (fh->error ()) | ||||
| @@ -1542,7 +1543,7 @@ extern "C" int | ||||
| stat64 (const char *name, struct __stat64 *buf) | ||||
| { | ||||
|   syscall_printf ("entering"); | ||||
|   path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX, stat_suffixes); | ||||
|   path_conv pc (name, PC_SYM_FOLLOW | PC_POSIX | PC_KEEP_HANDLE, stat_suffixes); | ||||
|   return stat_worker (pc, buf); | ||||
| } | ||||
|  | ||||
| @@ -1581,7 +1582,8 @@ extern "C" int | ||||
| lstat64 (const char *name, struct __stat64 *buf) | ||||
| { | ||||
|   syscall_printf ("entering"); | ||||
|   path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX, stat_suffixes); | ||||
|   path_conv pc (name, PC_SYM_NOFOLLOW | PC_POSIX | PC_KEEP_HANDLE, | ||||
| 		stat_suffixes); | ||||
|   return stat_worker (pc, buf); | ||||
| } | ||||
|  | ||||
| @@ -2561,7 +2563,8 @@ statvfs (const char *name, struct statvfs *sfs) | ||||
|   if (efault.faulted (EFAULT)) | ||||
|     goto error; | ||||
|  | ||||
|   if (!(fh = build_fh_name (name, PC_SYM_FOLLOW, stat_suffixes))) | ||||
|   if (!(fh = build_fh_name (name, PC_SYM_FOLLOW | PC_KEEP_HANDLE, | ||||
| 			    stat_suffixes))) | ||||
|     goto error; | ||||
|  | ||||
|   if (fh->error ()) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user