mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-01-18 12:29:32 +08:00
* fhandler.cc (fhandler_base::open): Drop local create_options variable.
Use options member instead. * fhandler.h (class fhandler_base): Change type of access member to ACCESS_MASK. Change get_access and set_access methods accordingly. Add options member. Add get_options and set_options methods. (class fhandler_disk_file): Add prw_handle. (fhandler_disk_file::prw_open): Declare. (fhandler_disk_file::close): Declare. (fhandler_disk_file::dup): Declare. (fhandler_disk_file::fixup_after_fork): Declare. * fhandler_disk_file.cc (fhandler_disk_file::fhandler_disk_file): Initialize prw_handle to NULL. (fhandler_disk_file::close): Close prw_handle. (fhandler_disk_file::dup): New method. (fhandler_disk_file::fixup_after_fork): Set prw_handle to NULL since prw_handle is not inherited. (fhandler_disk_file::prw_open): New method. Add long comment to explain current behaviour. (fhandler_disk_file::pread): Revert previous change. Change to use prw_handle if possible. (fhandler_disk_file::pwrite): Change to use prw_handle if possible.
This commit is contained in:
parent
a716252619
commit
c36cd56c54
@ -1,3 +1,27 @@
|
|||||||
|
2011-06-17 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
|
* fhandler.cc (fhandler_base::open): Drop local create_options variable.
|
||||||
|
Use options member instead.
|
||||||
|
* fhandler.h (class fhandler_base): Change type of access member to
|
||||||
|
ACCESS_MASK. Change get_access and set_access methods accordingly.
|
||||||
|
Add options member. Add get_options and set_options methods.
|
||||||
|
(class fhandler_disk_file): Add prw_handle.
|
||||||
|
(fhandler_disk_file::prw_open): Declare.
|
||||||
|
(fhandler_disk_file::close): Declare.
|
||||||
|
(fhandler_disk_file::dup): Declare.
|
||||||
|
(fhandler_disk_file::fixup_after_fork): Declare.
|
||||||
|
* fhandler_disk_file.cc (fhandler_disk_file::fhandler_disk_file):
|
||||||
|
Initialize prw_handle to NULL.
|
||||||
|
(fhandler_disk_file::close): Close prw_handle.
|
||||||
|
(fhandler_disk_file::dup): New method.
|
||||||
|
(fhandler_disk_file::fixup_after_fork): Set prw_handle to NULL since
|
||||||
|
prw_handle is not inherited.
|
||||||
|
(fhandler_disk_file::prw_open): New method. Add long comment to
|
||||||
|
explain current behaviour.
|
||||||
|
(fhandler_disk_file::pread): Revert previous change. Change to use
|
||||||
|
prw_handle if possible.
|
||||||
|
(fhandler_disk_file::pwrite): Change to use prw_handle if possible.
|
||||||
|
|
||||||
2011-06-17 Corinna Vinschen <corinna@vinschen.de>
|
2011-06-17 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* dcrt0.cc (dll_crt0_1): Call strace.dll_info after call to pinfo_init.
|
* dcrt0.cc (dll_crt0_1): Call strace.dll_info after call to pinfo_init.
|
||||||
|
@ -492,7 +492,6 @@ fhandler_base::open (int flags, mode_t mode)
|
|||||||
ULONG file_attributes = 0;
|
ULONG file_attributes = 0;
|
||||||
ULONG shared = (get_major () == DEV_TAPE_MAJOR ? 0 : FILE_SHARE_VALID_FLAGS);
|
ULONG shared = (get_major () == DEV_TAPE_MAJOR ? 0 : FILE_SHARE_VALID_FLAGS);
|
||||||
ULONG create_disposition;
|
ULONG create_disposition;
|
||||||
ULONG create_options = FILE_OPEN_FOR_BACKUP_INTENT;
|
|
||||||
OBJECT_ATTRIBUTES attr;
|
OBJECT_ATTRIBUTES attr;
|
||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
@ -503,6 +502,7 @@ fhandler_base::open (int flags, mode_t mode)
|
|||||||
|
|
||||||
pc.get_object_attr (attr, *sec_none_cloexec (flags));
|
pc.get_object_attr (attr, *sec_none_cloexec (flags));
|
||||||
|
|
||||||
|
options = FILE_OPEN_FOR_BACKUP_INTENT;
|
||||||
switch (query_open ())
|
switch (query_open ())
|
||||||
{
|
{
|
||||||
case query_read_control:
|
case query_read_control:
|
||||||
@ -528,12 +528,12 @@ fhandler_base::open (int flags, mode_t mode)
|
|||||||
else
|
else
|
||||||
access = GENERIC_READ | GENERIC_WRITE;
|
access = GENERIC_READ | GENERIC_WRITE;
|
||||||
if (flags & O_SYNC)
|
if (flags & O_SYNC)
|
||||||
create_options |= FILE_WRITE_THROUGH;
|
options |= FILE_WRITE_THROUGH;
|
||||||
if (flags & O_DIRECT)
|
if (flags & O_DIRECT)
|
||||||
create_options |= FILE_NO_INTERMEDIATE_BUFFERING;
|
options |= FILE_NO_INTERMEDIATE_BUFFERING;
|
||||||
if (get_major () != DEV_SERIAL_MAJOR && get_major () != DEV_TAPE_MAJOR)
|
if (get_major () != DEV_SERIAL_MAJOR && get_major () != DEV_TAPE_MAJOR)
|
||||||
{
|
{
|
||||||
create_options |= FILE_SYNCHRONOUS_IO_NONALERT;
|
options |= FILE_SYNCHRONOUS_IO_NONALERT;
|
||||||
access |= SYNCHRONIZE;
|
access |= SYNCHRONIZE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -574,7 +574,7 @@ fhandler_base::open (int flags, mode_t mode)
|
|||||||
/* Add the reparse point flag to native symlinks, otherwise we open the
|
/* Add the reparse point flag to native symlinks, otherwise we open the
|
||||||
target, not the symlink. This would break lstat. */
|
target, not the symlink. This would break lstat. */
|
||||||
if (pc.is_rep_symlink ())
|
if (pc.is_rep_symlink ())
|
||||||
create_options |= FILE_OPEN_REPARSE_POINT;
|
options |= FILE_OPEN_REPARSE_POINT;
|
||||||
|
|
||||||
/* Starting with Windows 2000, when trying to overwrite an already
|
/* Starting with Windows 2000, when trying to overwrite an already
|
||||||
existing file with FILE_ATTRIBUTE_HIDDEN and/or FILE_ATTRIBUTE_SYSTEM
|
existing file with FILE_ATTRIBUTE_HIDDEN and/or FILE_ATTRIBUTE_SYSTEM
|
||||||
@ -626,7 +626,7 @@ fhandler_base::open (int flags, mode_t mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
status = NtCreateFile (&fh, access, &attr, &io, NULL, file_attributes, shared,
|
status = NtCreateFile (&fh, access, &attr, &io, NULL, file_attributes, shared,
|
||||||
create_disposition, create_options, p, plen);
|
create_disposition, options, p, plen);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
/* Trying to create a directory should return EISDIR, not ENOENT. */
|
/* Trying to create a directory should return EISDIR, not ENOENT. */
|
||||||
@ -672,7 +672,7 @@ done:
|
|||||||
debug_printf ("%x = NtCreateFile "
|
debug_printf ("%x = NtCreateFile "
|
||||||
"(%p, %x, %S, io, NULL, %x, %x, %x, %x, NULL, 0)",
|
"(%p, %x, %S, io, NULL, %x, %x, %x, %x, NULL, 0)",
|
||||||
status, fh, access, pc.get_nt_native_path (), file_attributes,
|
status, fh, access, pc.get_nt_native_path (), file_attributes,
|
||||||
shared, create_disposition, create_options);
|
shared, create_disposition, options);
|
||||||
|
|
||||||
syscall_printf ("%d = fhandler_base::open (%S, %p)",
|
syscall_printf ("%d = fhandler_base::open (%S, %p)",
|
||||||
res, pc.get_nt_native_path (), flags);
|
res, pc.get_nt_native_path (), flags);
|
||||||
|
@ -152,7 +152,9 @@ class fhandler_base
|
|||||||
} status, open_status;
|
} status, open_status;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int access;
|
ACCESS_MASK access;
|
||||||
|
ULONG options;
|
||||||
|
|
||||||
HANDLE io_handle;
|
HANDLE io_handle;
|
||||||
|
|
||||||
__ino64_t ino; /* file ID or hashed filename, depends on FS. */
|
__ino64_t ino; /* file ID or hashed filename, depends on FS. */
|
||||||
@ -206,8 +208,11 @@ class fhandler_base
|
|||||||
DWORD get_minor () { return dev ().get_minor (); }
|
DWORD get_minor () { return dev ().get_minor (); }
|
||||||
virtual int get_unit () { return dev ().get_minor (); }
|
virtual int get_unit () { return dev ().get_minor (); }
|
||||||
|
|
||||||
int get_access () const { return access; }
|
ACCESS_MASK get_access () const { return access; }
|
||||||
void set_access (int x) { access = x; }
|
void set_access (ACCESS_MASK x) { access = x; }
|
||||||
|
|
||||||
|
ULONG get_options () const { return options; }
|
||||||
|
void set_options (ULONG x) { options = x; }
|
||||||
|
|
||||||
int get_flags () { return openflags; }
|
int get_flags () { return openflags; }
|
||||||
void set_flags (int x, int supplied_bin = 0);
|
void set_flags (int x, int supplied_bin = 0);
|
||||||
@ -801,13 +806,19 @@ class fhandler_dev_tape: public fhandler_dev_raw
|
|||||||
|
|
||||||
class fhandler_disk_file: public fhandler_base
|
class fhandler_disk_file: public fhandler_base
|
||||||
{
|
{
|
||||||
|
HANDLE prw_handle;
|
||||||
int readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname) __attribute__ ((regparm (3)));
|
int readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname) __attribute__ ((regparm (3)));
|
||||||
|
|
||||||
|
int prw_open (bool);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
fhandler_disk_file ();
|
fhandler_disk_file ();
|
||||||
fhandler_disk_file (path_conv &pc);
|
fhandler_disk_file (path_conv &pc);
|
||||||
|
|
||||||
int open (int flags, mode_t mode);
|
int open (int flags, mode_t mode);
|
||||||
|
int close ();
|
||||||
|
int dup (fhandler_base *child);
|
||||||
|
void fixup_after_fork (HANDLE parent);
|
||||||
int lock (int, struct __flock64 *);
|
int lock (int, struct __flock64 *);
|
||||||
bool isdevice () const { return false; }
|
bool isdevice () const { return false; }
|
||||||
int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
|
int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
|
||||||
|
@ -1356,12 +1356,12 @@ fhandler_base::utimens_fs (const struct timespec *tvp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fhandler_disk_file::fhandler_disk_file () :
|
fhandler_disk_file::fhandler_disk_file () :
|
||||||
fhandler_base ()
|
fhandler_base (), prw_handle (NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fhandler_disk_file::fhandler_disk_file (path_conv &pc) :
|
fhandler_disk_file::fhandler_disk_file (path_conv &pc) :
|
||||||
fhandler_base ()
|
fhandler_base (), prw_handle (NULL)
|
||||||
{
|
{
|
||||||
set_name (pc);
|
set_name (pc);
|
||||||
}
|
}
|
||||||
@ -1372,6 +1372,35 @@ fhandler_disk_file::open (int flags, mode_t mode)
|
|||||||
return open_fs (flags, mode);
|
return open_fs (flags, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_disk_file::close ()
|
||||||
|
{
|
||||||
|
if (prw_handle)
|
||||||
|
NtClose (prw_handle);
|
||||||
|
return fhandler_base::close ();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_disk_file::dup (fhandler_base *child)
|
||||||
|
{
|
||||||
|
fhandler_disk_file *fhc = (fhandler_disk_file *) child;
|
||||||
|
|
||||||
|
int ret = fhandler_base::dup (child);
|
||||||
|
if (!ret && prw_handle
|
||||||
|
&& !DuplicateHandle (GetCurrentProcess (), prw_handle,
|
||||||
|
GetCurrentProcess (), &fhc->prw_handle,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||||
|
prw_handle = NULL;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fhandler_disk_file::fixup_after_fork (HANDLE parent)
|
||||||
|
{
|
||||||
|
prw_handle = NULL;
|
||||||
|
fhandler_base::fixup_after_fork (parent);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fhandler_base::open_fs (int flags, mode_t mode)
|
fhandler_base::open_fs (int flags, mode_t mode)
|
||||||
{
|
{
|
||||||
@ -1412,6 +1441,73 @@ out:
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* POSIX demands that pread/pwrite don't change the current file position.
|
||||||
|
While NtReadFile/NtWriteFile support atomic seek-and-io, both change the
|
||||||
|
file pointer if the file handle has been opened for synchonous I/O.
|
||||||
|
Using this handle for pread/pwrite would break atomicity, because the
|
||||||
|
read/write operation would have to be followed by a seek back to the old
|
||||||
|
file position. What we do is to open another handle to the file on the
|
||||||
|
first call to either pread or pwrite. This is used for any subsequent
|
||||||
|
pread/pwrite. Thus the current file position of the "normal" file
|
||||||
|
handle is not touched.
|
||||||
|
|
||||||
|
FIXME:
|
||||||
|
|
||||||
|
Note that this is just a hack. The problem with this approach is that
|
||||||
|
a change to the file permissions might disallow to open the file with
|
||||||
|
the required permissions to read or write. This appears to be a border case,
|
||||||
|
but that's exactly what git does. It creates the file for reading and
|
||||||
|
writing and after writing it, it chmods the file to read-only. Then it
|
||||||
|
calls pread on the file to examine the content. This works, but if git
|
||||||
|
would use the original handle to pwrite to the file, it would be broken
|
||||||
|
with our approach.
|
||||||
|
|
||||||
|
One way to implement this is to open the pread/pwrite handle right at
|
||||||
|
file open time. We would simply maintain two handles, which wouldn't
|
||||||
|
be much of a problem given how we do that for other fhandler types as
|
||||||
|
well.
|
||||||
|
|
||||||
|
However, ultimately fhandler_disk_file should become a derived class of
|
||||||
|
fhandler_base_overlapped. Each raw_read or raw_write would fetch the
|
||||||
|
actual file position, read/write from there, and then set the file
|
||||||
|
position again. Fortunately, while the file position is not maintained
|
||||||
|
by the I/O manager, it can be fetched and set to a new value by all
|
||||||
|
processes holding a handle to that file object. Pread and pwrite differ
|
||||||
|
from raw_read and raw_write just by not touching the current file pos.
|
||||||
|
Actually they could be merged with raw_read/raw_write if we add a position
|
||||||
|
parameter to the latter. */
|
||||||
|
|
||||||
|
int
|
||||||
|
fhandler_disk_file::prw_open (bool write)
|
||||||
|
{
|
||||||
|
NTSTATUS status;
|
||||||
|
IO_STATUS_BLOCK io;
|
||||||
|
OBJECT_ATTRIBUTES attr;
|
||||||
|
|
||||||
|
/* First try to open with the original access mask */
|
||||||
|
ACCESS_MASK access = get_access ();
|
||||||
|
pc.init_reopen_attr (&attr, get_handle ());
|
||||||
|
status = NtOpenFile (&prw_handle, access, &attr, &io,
|
||||||
|
FILE_SHARE_VALID_FLAGS, get_options ());
|
||||||
|
if (status == STATUS_ACCESS_DENIED)
|
||||||
|
{
|
||||||
|
/* If we get an access denied, chmod has been called. Try again
|
||||||
|
with just the required rights to perform the called function. */
|
||||||
|
access &= write ? ~GENERIC_READ : ~GENERIC_WRITE;
|
||||||
|
status = NtOpenFile (&prw_handle, access, &attr, &io,
|
||||||
|
FILE_SHARE_VALID_FLAGS, get_options ());
|
||||||
|
}
|
||||||
|
debug_printf ("%x = NtOpenFile (%p, %x, %S, io, %x, %x)",
|
||||||
|
status, prw_handle, access, pc.get_nt_native_path (),
|
||||||
|
FILE_SHARE_VALID_FLAGS, get_options ());
|
||||||
|
if (!NT_SUCCESS (status))
|
||||||
|
{
|
||||||
|
__seterrno_from_nt_status (status);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t __stdcall
|
ssize_t __stdcall
|
||||||
fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
|
fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
|
||||||
{
|
{
|
||||||
@ -1429,7 +1525,9 @@ fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
|
|||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
LARGE_INTEGER off = { QuadPart:offset };
|
LARGE_INTEGER off = { QuadPart:offset };
|
||||||
|
|
||||||
status = NtReadFile (get_handle (), NULL, NULL, NULL, &io, buf, count,
|
if (!prw_handle && prw_open (false))
|
||||||
|
goto non_atomic;
|
||||||
|
status = NtReadFile (prw_handle, NULL, NULL, NULL, &io, buf, count,
|
||||||
&off, NULL);
|
&off, NULL);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
@ -1440,15 +1538,15 @@ fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
|
|||||||
}
|
}
|
||||||
if (status == (NTSTATUS) STATUS_ACCESS_VIOLATION)
|
if (status == (NTSTATUS) STATUS_ACCESS_VIOLATION)
|
||||||
{
|
{
|
||||||
if (is_at_eof (get_handle ()))
|
if (is_at_eof (prw_handle))
|
||||||
return 0;
|
return 0;
|
||||||
switch (mmap_is_attached_or_noreserve (buf, count))
|
switch (mmap_is_attached_or_noreserve (buf, count))
|
||||||
{
|
{
|
||||||
case MMAP_NORESERVE_COMMITED:
|
case MMAP_NORESERVE_COMMITED:
|
||||||
status = NtReadFile (get_handle (), NULL, NULL, NULL, &io,
|
status = NtReadFile (prw_handle, NULL, NULL, NULL, &io,
|
||||||
buf, count, &off, NULL);
|
buf, count, &off, NULL);
|
||||||
if (NT_SUCCESS (status))
|
if (NT_SUCCESS (status))
|
||||||
goto success;
|
return io.Information;
|
||||||
break;
|
break;
|
||||||
case MMAP_RAISE_SIGBUS:
|
case MMAP_RAISE_SIGBUS:
|
||||||
raise (SIGBUS);
|
raise (SIGBUS);
|
||||||
@ -1459,12 +1557,9 @@ fhandler_disk_file::pread (void *buf, size_t count, _off64_t offset)
|
|||||||
__seterrno_from_nt_status (status);
|
__seterrno_from_nt_status (status);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
success:
|
|
||||||
lseek (-io.Information, SEEK_CUR);
|
|
||||||
return io.Information;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
non_atomic:
|
||||||
/* Text mode stays slow and non-atomic. */
|
/* Text mode stays slow and non-atomic. */
|
||||||
ssize_t res;
|
ssize_t res;
|
||||||
_off64_t curpos = lseek (0, SEEK_CUR);
|
_off64_t curpos = lseek (0, SEEK_CUR);
|
||||||
@ -1499,7 +1594,9 @@ fhandler_disk_file::pwrite (void *buf, size_t count, _off64_t offset)
|
|||||||
IO_STATUS_BLOCK io;
|
IO_STATUS_BLOCK io;
|
||||||
LARGE_INTEGER off = { QuadPart:offset };
|
LARGE_INTEGER off = { QuadPart:offset };
|
||||||
|
|
||||||
status = NtWriteFile (get_handle (), NULL, NULL, NULL, &io, buf, count,
|
if (!prw_handle && prw_open (true))
|
||||||
|
goto non_atomic;
|
||||||
|
status = NtWriteFile (prw_handle, NULL, NULL, NULL, &io, buf, count,
|
||||||
&off, NULL);
|
&off, NULL);
|
||||||
if (!NT_SUCCESS (status))
|
if (!NT_SUCCESS (status))
|
||||||
{
|
{
|
||||||
@ -1508,6 +1605,8 @@ fhandler_disk_file::pwrite (void *buf, size_t count, _off64_t offset)
|
|||||||
}
|
}
|
||||||
return io.Information;
|
return io.Information;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
non_atomic:
|
||||||
/* Text mode stays slow and non-atomic. */
|
/* Text mode stays slow and non-atomic. */
|
||||||
int res;
|
int res;
|
||||||
_off64_t curpos = lseek (0, SEEK_CUR);
|
_off64_t curpos = lseek (0, SEEK_CUR);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user