* 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.
This commit is contained in:
parent
7b3a9e6e00
commit
fac297d5f8
|
@ -1,3 +1,18 @@
|
|||
2003-05-26 Corinna Vinschen <corinna@vinschen.de>
|
||||
|
||||
* 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 <pierre.humblet@ieee.org>
|
||||
|
||||
* autoload.cc (GetDiskFreeSpaceEx): Add.
|
||||
|
|
|
@ -27,6 +27,7 @@ details. */
|
|||
#include "pinfo.h"
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
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))
|
||||
/* 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)
|
||||
{
|
||||
__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;
|
||||
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;
|
||||
}
|
||||
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, 0, FILE_BEGIN);
|
||||
return -1;
|
||||
}
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -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); }
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ details. */
|
|||
#include "pinfo.h"
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <winioctl.h>
|
||||
|
||||
#define _COMPILING_NEWLIB
|
||||
#include <dirent.h>
|
||||
|
@ -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 ());
|
||||
|
|
Loading…
Reference in New Issue