From 202d75b36ddfb403e20448a189bb3d80bb7e85e0 Mon Sep 17 00:00:00 2001 From: corinna Date: Mon, 26 May 2003 09:54:00 +0000 Subject: [PATCH] * fhandler.h: Rename FH_W95LSBUG flag to FH_LSEEKED. (fhandler_base::set_did_lseek): Rename from set_check_win95_lseek_bug. (fhandler_base::get_did_lseek): Rename from get_check_win95_lseek_bug. (fhandler_base::set_fs_flags): New method. (fhandler_base::get_fs_flags): Ditto. * fhandler.cc (fhandler_base::write): Make 64 bit clean. Convert file to a "sparse" file when writing after a long lseek (>64K) beyond EOF. (fhandler_base::lseek): Call set_did_lseek() instead of set_check_win95_lseek_bug(). (fhandler_base::fhandler_base): Initialize fs_flags to 0. * fhandler_disk_file.cc (fhandler_disk_file::open): Don't create files as "sparse" unconditionally. Set fs_flags member. --- winsup/cygwin/ChangeLog | 15 ++++++ winsup/cygwin/fhandler.cc | 102 +++++++++++++++++++++++------------- winsup/cygwin/fhandler.h | 14 +++-- winsup/cygwin/fhandler_disk_file.cc | 15 +----- 4 files changed, 92 insertions(+), 54 deletions(-) diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 95f949315c..6c4d65c8a3 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,18 @@ +2003-05-26 Corinna Vinschen + + * fhandler.h: Rename FH_W95LSBUG flag to FH_LSEEKED. + (fhandler_base::set_did_lseek): Rename from set_check_win95_lseek_bug. + (fhandler_base::get_did_lseek): Rename from get_check_win95_lseek_bug. + (fhandler_base::set_fs_flags): New method. + (fhandler_base::get_fs_flags): Ditto. + * fhandler.cc (fhandler_base::write): Make 64 bit clean. Convert file + to a "sparse" file when writing after a long lseek (>64K) beyond EOF. + (fhandler_base::lseek): Call set_did_lseek() instead of + set_check_win95_lseek_bug(). + (fhandler_base::fhandler_base): Initialize fs_flags to 0. + * fhandler_disk_file.cc (fhandler_disk_file::open): Don't create files + as "sparse" unconditionally. Set fs_flags member. + 2003-05-25 Pierre Humblet * autoload.cc (GetDiskFreeSpaceEx): Add. diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index bdbe2883d9..83302dd73b 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -27,6 +27,7 @@ details. */ #include "pinfo.h" #include #include +#include static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */ @@ -610,47 +611,75 @@ fhandler_base::write (const void *ptr, size_t len) if (get_append_p ()) SetFilePointer (get_handle (), 0, 0, FILE_END); - else if (wincap.has_lseek_bug () && get_check_win95_lseek_bug ()) + else if (get_did_lseek ()) { - /* Note: this bug doesn't happen on NT4, even though the documentation - for WriteFile() says that it *may* happen on any OS. */ - int actual_length, current_position; - set_check_win95_lseek_bug (0); /* don't do it again */ - actual_length = GetFileSize (get_handle (), NULL); - current_position = SetFilePointer (get_handle (), 0, 0, FILE_CURRENT); + _off64_t actual_length, current_position; + DWORD size_high = 0; + LONG pos_high = 0; + + set_did_lseek (0); /* don't do it again */ + + actual_length = GetFileSize (get_handle (), &size_high); + actual_length += ((_off64_t) size_high) << 32; + + current_position = SetFilePointer (get_handle (), 0, &pos_high, + FILE_CURRENT); + current_position += ((_off64_t) pos_high) << 32; + if (current_position > actual_length) { - /* Oops, this is the bug case - Win95 uses whatever is on the disk - instead of some known (safe) value, so we must seek back and - fill in the gap with zeros. - DJ */ - char zeros[512]; - int number_of_zeros_to_write = current_position - actual_length; - memset (zeros, 0, 512); - SetFilePointer (get_handle (), 0, 0, FILE_END); - while (number_of_zeros_to_write > 0) + if ((get_fs_flags (FILE_SUPPORTS_SPARSE_FILES)) + && current_position >= actual_length + (64 * 1024)) { - DWORD zeros_this_time = (number_of_zeros_to_write > 512 - ? 512 : number_of_zeros_to_write); - DWORD written; - if (!WriteFile (get_handle (), zeros, zeros_this_time, &written, - NULL)) - { - __seterrno (); - if (get_errno () == EPIPE) - raise (SIGPIPE); - /* This might fail, but it's the best we can hope for */ - SetFilePointer (get_handle (), current_position, 0, FILE_BEGIN); - return -1; - - } - if (written < zeros_this_time) /* just in case */ + /* If the file systemn supports sparse files and the application + is writing after a long seek beyond EOF, convert the file to + a sparse file. */ + DWORD dw; + HANDLE h = get_handle (); + BOOL r = DeviceIoControl (h, FSCTL_SET_SPARSE, NULL, 0, NULL, + 0, &dw, NULL); + syscall_printf ("%d = DeviceIoControl(0x%x, FSCTL_SET_SPARSE, " + "NULL, 0, NULL, 0, &dw, NULL)", r, h); + } + else if (wincap.has_lseek_bug ()) + { + /* Oops, this is the bug case - Win95 uses whatever is on the + disk instead of some known (safe) value, so we must seek + back and fill in the gap with zeros. - DJ + Note: this bug doesn't happen on NT4, even though the + documentation for WriteFile() says that it *may* happen + on any OS. */ + char zeros[512]; + int number_of_zeros_to_write = current_position - actual_length; + memset (zeros, 0, 512); + SetFilePointer (get_handle (), 0, NULL, FILE_END); + while (number_of_zeros_to_write > 0) { - set_errno (ENOSPC); - /* This might fail, but it's the best we can hope for */ - SetFilePointer (get_handle (), current_position, 0, FILE_BEGIN); - return -1; + DWORD zeros_this_time = (number_of_zeros_to_write > 512 + ? 512 : number_of_zeros_to_write); + DWORD written; + if (!WriteFile (get_handle (), zeros, zeros_this_time, + &written, NULL)) + { + __seterrno (); + if (get_errno () == EPIPE) + raise (SIGPIPE); + /* This might fail, but it's the best we can hope for */ + SetFilePointer (get_handle (), current_position, NULL, + FILE_BEGIN); + return -1; + + } + if (written < zeros_this_time) /* just in case */ + { + set_errno (ENOSPC); + /* This might fail, but it's the best we can hope for */ + SetFilePointer (get_handle (), current_position, NULL, + FILE_BEGIN); + return -1; + } + number_of_zeros_to_write -= written; } - number_of_zeros_to_write -= written; } } } @@ -876,7 +905,7 @@ fhandler_base::lseek (_off64_t offset, int whence) { /* When next we write(), we will check to see if *this* seek went beyond the end of the file, and back-seek and fill with zeros if so - DJ */ - set_check_win95_lseek_bug (); + set_did_lseek (); /* If this was a SEEK_CUR with offset 0, we still might have readahead that we have to take into account when calculating @@ -1165,6 +1194,7 @@ fhandler_base::fhandler_base (DWORD devtype, int unit): unix_path_name (NULL), win32_path_name (NULL), open_status (0), + fs_flags (0), read_state (NULL) { } diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 8138d1d889..ae3becc32d 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -28,9 +28,10 @@ enum FH_SYMLINK = 0x00100000, /* is a symlink */ FH_EXECABL = 0x00200000, /* file looked like it would run: * ends in .exe or .bat or begins with #! */ - FH_W95LSBUG = 0x00400000, /* set when lseek is called as a flag that + FH_LSEEKED = 0x00400000, /* set when lseek is called as a flag that * _write should check if we've moved beyond - * EOF, zero filling if so. */ + * EOF, zero filling or making file sparse + if so. */ FH_NOHANDLE = 0x00800000, /* No handle associated with fhandler. */ FH_NOEINTR = 0x01000000, /* Set if I/O should be uninterruptible. */ FH_FFIXUP = 0x02000000, /* Set if need to fixup after fork. */ @@ -167,6 +168,7 @@ class fhandler_base const char *unix_path_name; const char *win32_path_name; DWORD open_status; + DWORD fs_flags; HANDLE read_state; public: @@ -234,8 +236,8 @@ class fhandler_base return get_close_on_exec () ? &sec_none_nih : &sec_none; } - void set_check_win95_lseek_bug (int b = 1) { FHCONDSETF (b, W95LSBUG); } - bool get_check_win95_lseek_bug () { return FHISSETF (W95LSBUG); } + void set_did_lseek (int b = 1) { FHCONDSETF (b, LSEEKED); } + bool get_did_lseek () { return FHISSETF (LSEEKED); } bool get_need_fork_fixup () { return FHISSETF (FFIXUP); } void set_need_fork_fixup () { FHSETF (FFIXUP); } @@ -268,6 +270,10 @@ class fhandler_base void set_append_p (int val) { FHCONDSETF (val, APPEND); } void set_append_p () { FHSETF (APPEND); } + void set_fs_flags (DWORD flags) { fs_flags = flags; } + bool get_fs_flags (DWORD flagval = 0xffffffffUL) + { return (fs_flags & (flagval)); } + bool get_query_open () { return FHISSETF (QUERYOPEN); } void set_query_open (bool val) { FHCONDSETF (val, QUERYOPEN); } diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 98d1531f40..64e1a73ce0 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -26,7 +26,6 @@ details. */ #include "pinfo.h" #include #include -#include #define _COMPILING_NEWLIB #include @@ -395,19 +394,7 @@ fhandler_disk_file::open (path_conv *real_path, int flags, mode_t mode) && !allow_ntsec && allow_ntea) set_file_attribute (has_acls (), get_win32_name (), mode); - /* Set newly created and truncated files as sparse files. */ - if ((real_path->fs_flags () & FILE_SUPPORTS_SPARSE_FILES) - && (get_access () & GENERIC_WRITE) == GENERIC_WRITE - && (get_flags () & (O_CREAT | O_TRUNC))) - { - DWORD dw; - HANDLE h = get_handle (); - BOOL r = DeviceIoControl (h , FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dw, - NULL); - syscall_printf ("%d = DeviceIoControl(0x%x, FSCTL_SET_SPARSE, NULL, 0, " - "NULL, 0, &dw, NULL)", r, h); - } - + set_fs_flags (real_path->fs_flags ()); set_symlink_p (real_path->issymlink ()); set_execable_p (real_path->exec_state ()); set_socket_p (real_path->issocket ()); -- 2.11.0