#include "pinfo.h"
#include <assert.h>
#include <limits.h>
+#include <winioctl.h>
static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */
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;
}
}
}
{
/* 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
unix_path_name (NULL),
win32_path_name (NULL),
open_status (0),
+ fs_flags (0),
read_state (NULL)
{
}
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. */
const char *unix_path_name;
const char *win32_path_name;
DWORD open_status;
+ DWORD fs_flags;
HANDLE read_state;
public:
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); }
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); }
#include "pinfo.h"
#include <assert.h>
#include <ctype.h>
-#include <winioctl.h>
#define _COMPILING_NEWLIB
#include <dirent.h>
&& !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 ());