diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index aed46e6cd..256ae5d89 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,4 +1,19 @@ -2007-10-12 Corinna Vinschen +2007-10-14 Corinna Vinschen + + * fhandler.cc (is_at_eof): Rewrite using NT functions. + (off_current): New static variable. + (off_append): Ditto. + (fhandler_base::raw_write): Use NtWriteFile. Accommodate O_APPEND here. + (fhandler_base::write): Drop O_APPEND hack. Use NT functions. + (fhandler_base::lseek): Rewrite using NT functions. + * fhandler_disk_file.cc (fhandler_disk_file::fstatvfs): Add space in + debug output. + (fhandler_disk_file::ftruncate): Ditto. + * ntdll.h (STATUS_DISK_FULL): Define. + (FILE_USE_FILE_POINTER_POSITION): Define. + (FILE_WRITE_TO_END_OF_FILE): Define. + +2007-10-13 Corinna Vinschen * ntdll.h (STATUS_END_OF_FILE): Define. * path.cc (symlink_info::check_shortcut): Use NT function to get file diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc index c7ba078e1..ac29256e4 100644 --- a/winsup/cygwin/fhandler.cc +++ b/winsup/cygwin/fhandler.cc @@ -171,17 +171,16 @@ char *fhandler_base::get_proc_fd_name (char *buf) static int __stdcall is_at_eof (HANDLE h, DWORD err) { - DWORD size, upper1, curr; - - size = GetFileSize (h, &upper1); - if (size != INVALID_FILE_SIZE || GetLastError () == NO_ERROR) - { - LONG upper2 = 0; - curr = SetFilePointer (h, 0, &upper2, FILE_CURRENT); - if (curr == size && upper1 == (DWORD) upper2) - return 1; - } + IO_STATUS_BLOCK io; + FILE_POSITION_INFORMATION fpi; + FILE_STANDARD_INFORMATION fsi; + if (NT_SUCCESS (NtQueryInformationFile (h, &io, &fsi, sizeof fsi, + FileStandardInformation)) + && NT_SUCCESS (NtQueryInformationFile (h, &io, &fpi, sizeof fpi, + FilePositionInformation)) + && fsi.EndOfFile.QuadPart == fpi.CurrentByteOffset.QuadPart) + return 1; SetLastError (err); return 0; } @@ -284,22 +283,30 @@ retry: /* Cover function to WriteFile to provide Posix interface and semantics (as much as possible). */ +static LARGE_INTEGER off_current = { QuadPart:FILE_USE_FILE_POINTER_POSITION }; +static LARGE_INTEGER off_append = { QuadPart:FILE_WRITE_TO_END_OF_FILE }; + int fhandler_base::raw_write (const void *ptr, size_t len) { - DWORD bytes_written; + NTSTATUS status; + IO_STATUS_BLOCK io; - if (!WriteFile (get_output_handle (), ptr, len, &bytes_written, 0)) + status = NtWriteFile (get_output_handle (), NULL, NULL, NULL, &io, + (PVOID) ptr, len, + (get_flags () & O_APPEND) ? &off_append : &off_current, + NULL); + if (!NT_SUCCESS (status)) { - if (GetLastError () == ERROR_DISK_FULL && bytes_written > 0) + if (status == STATUS_DISK_FULL && io.Information > 0) goto written; - __seterrno (); + __seterrno_from_nt_status (status); if (get_errno () == EPIPE) raise (SIGPIPE); return -1; } written: - return bytes_written; + return io.Information; } int @@ -697,45 +704,33 @@ int fhandler_base::write (const void *ptr, size_t len) { int res; + IO_STATUS_BLOCK io; + FILE_POSITION_INFORMATION fpi; + FILE_STANDARD_INFORMATION fsi; - if (get_flags () & O_APPEND) + if (did_lseek ()) { - LONG off_high = 0; - DWORD ret = SetFilePointer (get_output_handle (), 0, &off_high, FILE_END); - if (ret == INVALID_SET_FILE_POINTER && GetLastError () != NO_ERROR) - { - debug_printf ("Seeking to EOF in append mode failed"); - __seterrno (); - return -1; - } - } - else if (did_lseek ()) - { - _off64_t actual_length, current_position; - DWORD size_high = 0; - LONG pos_high = 0; - did_lseek (false); /* don't do it again */ - actual_length = GetFileSize (get_output_handle (), &size_high); - actual_length += ((_off64_t) size_high) << 32; - - current_position = SetFilePointer (get_output_handle (), 0, &pos_high, - FILE_CURRENT); - current_position += ((_off64_t) pos_high) << 32; - - if (current_position >= actual_length + (128 * 1024) + if (!(get_flags () & O_APPEND) + && NT_SUCCESS (NtQueryInformationFile (get_output_handle (), + &io, &fsi, sizeof fsi, + FileStandardInformation)) + && NT_SUCCESS (NtQueryInformationFile (get_output_handle (), + &io, &fpi, sizeof fpi, + FilePositionInformation)) + && fpi.CurrentByteOffset.QuadPart + >= fsi.EndOfFile.QuadPart + (128 * 1024) && get_fs_flags (FILE_SUPPORTS_SPARSE_FILES)) { /* If the file system 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_output_handle (); - BOOL r = DeviceIoControl (h, FSCTL_SET_SPARSE, NULL, 0, NULL, - 0, &dw, NULL); - syscall_printf ("%d = DeviceIoControl(%p, FSCTL_SET_SPARSE)", - r, h); + NTSTATUS status; + status = NtFsControlFile (get_output_handle (), NULL, NULL, NULL, + &io, FSCTL_SET_SPARSE, NULL, 0, NULL, 0); + syscall_printf ("%p = NtFsControlFile(%S, FSCTL_SET_SPARSE)", + status, pc.get_nt_native_path ()); } } @@ -912,7 +907,10 @@ fhandler_base::writev (const struct iovec *const iov, const int iovcnt, _off64_t fhandler_base::lseek (_off64_t offset, int whence) { - _off64_t res; + NTSTATUS status; + IO_STATUS_BLOCK io; + FILE_POSITION_INFORMATION fpi; + FILE_STANDARD_INFORMATION fsi; /* Seeks on text files is tough, we rewind and read till we get to the right place. */ @@ -924,35 +922,52 @@ fhandler_base::lseek (_off64_t offset, int whence) set_readahead_valid (0); } - debug_printf ("lseek (%s, %D, %d)", get_name (), offset, whence); - - DWORD win32_whence = whence == SEEK_SET ? FILE_BEGIN - : (whence == SEEK_CUR ? FILE_CURRENT : FILE_END); - - LONG off_low = ((__uint64_t) offset) & UINT32_MAX; - LONG off_high = ((__uint64_t) offset) >> 32LL; - - debug_printf ("setting file pointer to %u (high), %u (low)", off_high, off_low); - res = SetFilePointer (get_handle (), off_low, &off_high, win32_whence); - if (res == INVALID_SET_FILE_POINTER && GetLastError ()) + switch (whence) { - __seterrno (); - res = -1; + case SEEK_SET: + fpi.CurrentByteOffset.QuadPart = offset; + break; + case SEEK_CUR: + status = NtQueryInformationFile (get_handle (), &io, &fpi, sizeof fpi, + FilePositionInformation); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + return -1; + } + fpi.CurrentByteOffset.QuadPart += offset; + break; + default: /* SEEK_END */ + status = NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, + FileStandardInformation); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + return -1; + } + fpi.CurrentByteOffset.QuadPart = fsi.EndOfFile.QuadPart + offset; + break; } - else + + debug_printf ("setting file pointer to %U", fpi.CurrentByteOffset.QuadPart); + status = NtSetInformationFile (get_handle (), &io, &fpi, sizeof fpi, + FilePositionInformation); + if (!NT_SUCCESS (status)) { - res += (_off64_t) off_high << 32; - - /* When next we write(), we will check to see if *this* seek went beyond - the end of the file and if so, potentially sparsify the file. */ - did_lseek (true); - - /* If this was a SEEK_CUR with offset 0, we still might have - readahead that we have to take into account when calculating - the actual position for the application. */ - if (whence == SEEK_CUR) - res -= ralen - raixget; + __seterrno_from_nt_status (status); + return -1; } + _off64_t res = fpi.CurrentByteOffset.QuadPart; + + /* When next we write(), we will check to see if *this* seek went beyond + the end of the file and if so, potentially sparsify the file. */ + did_lseek (true); + + /* If this was a SEEK_CUR with offset 0, we still might have + readahead that we have to take into account when calculating + the actual position for the application. */ + if (whence == SEEK_CUR) + res -= ralen - raixget; return res; } diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 095c779e8..051ad77aa 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -698,7 +698,7 @@ fhandler_disk_file::fstatvfs (struct statvfs *sfs) FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &nvdb, sizeof nvdb); if (!NT_SUCCESS (status)) - debug_printf ("%p = NtFsControlFile(%S,FSCTL_GET_NTFS_VOLUME_DATA)", + debug_printf ("%p = NtFsControlFile(%S, FSCTL_GET_NTFS_VOLUME_DATA)", status, pc.get_nt_native_path ()); else sfs->f_blocks = nvdb.TotalClusters.QuadPart; @@ -1030,7 +1030,7 @@ fhandler_disk_file::ftruncate (_off64_t length, bool allow_truncate) { status = NtFsControlFile (get_handle (), NULL, NULL, NULL, &io, FSCTL_SET_SPARSE, NULL, 0, NULL, 0); - syscall_printf ("%p = NtFsControlFile(%S,FSCTL_SET_SPARSE)", + syscall_printf ("%p = NtFsControlFile(%S, FSCTL_SET_SPARSE)", status, pc.get_nt_native_path ()); } status = NtSetInformationFile (get_handle (), &io, diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 57bbfbb0f..d74095a57 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -26,6 +26,7 @@ #define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xc000003A) #define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xc0000043) #define STATUS_DELETE_PENDING ((NTSTATUS) 0xc0000056) +#define STATUS_DISK_FULL ((NTSTATUS) 0xc000007f) #define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1) #define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xc00000bb) #define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xc0000101) @@ -53,6 +54,9 @@ #define FILE_EXISTS 4 #define FILE_DOES_NOT_EXIST 5 +#define FILE_WRITE_TO_END_OF_FILE (-1LL) +#define FILE_USE_FILE_POINTER_POSITION (-2LL) + /* Device Characteristics. */ #define FILE_REMOVABLE_MEDIA 0x00000001 #define FILE_READ_ONLY_DEVICE 0x00000002