From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2155) id 01E9D385773C; Wed, 9 Aug 2023 15:25:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 01E9D385773C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1691594722; bh=FGkU6pv0GSnUXkdzc3cFO/u98swuObQk7zkufCEIsTM=; h=From:To:Subject:Date:From; b=NyOX4sdu5PtI9B2OGbimdyOx+w40ymg/O/KvLR4bZOyXeMRXHnUbxXJDG0pg9/2jX 7v5n1KQH0xCN/dOsfs1So5t5YcWHBJABbLrXPurRMZvmYgT8QYf83Hm9aBfGRARchf HhoicQ2ri1ZsJOW9fhhDBET3pWupHJ8+8TuioTh4= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Corinna Vinschen To: cygwin-cvs@sourceware.org Subject: [newlib-cygwin/main] Cygwin: lseek: implement SEEK_DATA and SEEK_HOLE for files X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/main X-Git-Oldrev: b6fbe0fc2e062e6f0d155009da235574e39dbbe2 X-Git-Newrev: edfa581d3c5a783ace9f837be1cbaccb97330c34 Message-Id: <20230809152522.01E9D385773C@sourceware.org> Date: Wed, 9 Aug 2023 15:25:21 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3Dedfa581d3c5= a783ace9f837be1cbaccb97330c34 commit edfa581d3c5a783ace9f837be1cbaccb97330c34 Author: Corinna Vinschen AuthorDate: Wed Aug 9 17:18:14 2023 +0200 Commit: Corinna Vinschen CommitDate: Wed Aug 9 17:18:14 2023 +0200 Cygwin: lseek: implement SEEK_DATA and SEEK_HOLE for files =20 Signed-off-by: Corinna Vinschen Diff: --- winsup/cygwin/fhandler/base.cc | 85 ++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/fhandler/base.cc b/winsup/cygwin/fhandler/base.cc index 9b49ec7b9ede..d8351d7a642e 100644 --- a/winsup/cygwin/fhandler/base.cc +++ b/winsup/cygwin/fhandler/base.cc @@ -1109,7 +1109,7 @@ fhandler_base::lseek (off_t offset, int whence) } fpi.CurrentByteOffset.QuadPart +=3D offset; break; - default: /* SEEK_END */ + case SEEK_END: status =3D NtQueryInformationFile (get_handle (), &io, &fsi, sizeof = fsi, FileStandardInformation); if (!NT_SUCCESS (status)) @@ -1119,6 +1119,89 @@ fhandler_base::lseek (off_t offset, int whence) } fpi.CurrentByteOffset.QuadPart =3D fsi.EndOfFile.QuadPart + offset; break; + case SEEK_DATA: + case SEEK_HOLE: + { + FILE_ALLOCATED_RANGE_BUFFER inp, out; + + status =3D NtQueryInformationFile (get_handle (), &io, &fsi, sizeof fsi, + FileStandardInformation); + if (!NT_SUCCESS (status)) + { + __seterrno_from_nt_status (status); + return -1; + } + /* Per Linux man page, ENXIO if offset is beyond EOF */ + if (offset > fsi.EndOfFile.QuadPart) + { + set_errno (ENXIO); + return -1; + } + if (!pc.support_sparse ()) + { + /* Default behaviour if sparse files are not supported: + SEEK_DATA: seek to offset + SEEK_HOLE: seek to EOF */ + fpi.CurrentByteOffset.QuadPart =3D (whence =3D=3D SEEK_DATA) + ? offset + : fsi.EndOfFile.QuadPart; + break; + } + inp.FileOffset.QuadPart =3D offset; + inp.Length.QuadPart =3D fsi.EndOfFile.QuadPart - offset; + /* Note that we only fetch a single region, so we expect the + function to fail with STATUS_BUFFER_OVERFLOW. It still + returns the data region containing offset, or the next + region after offset, if offset is within a hole. */ + status =3D NtFsControlFile (get_output_handle (), NULL, NULL, NULL, + &io, FSCTL_QUERY_ALLOCATED_RANGES, + &inp, sizeof inp, + &out, sizeof out); + if (!NT_SUCCESS (status) && status !=3D STATUS_BUFFER_OVERFLOW) + { + /* On error, fall back to default behaviour, see above. */ + fpi.CurrentByteOffset.QuadPart =3D (whence =3D=3D SEEK_DATA) + ? offset + : fsi.EndOfFile.QuadPart; + break; + } + if (io.Information =3D=3D 0) + { + /* No valid region, so offset is within a hole at EOF. + SEEK_DATA: ENXIO + SEEK_HOLE: seek to offset */ + if (whence =3D=3D SEEK_DATA) + { + set_errno (ENXIO); + return -1; + } + fpi.CurrentByteOffset.QuadPart =3D offset; + } + else if (out.FileOffset.QuadPart =3D=3D offset) + { + /* offset within valid data range? In that case, that region + supposedly starts at offset, and the region length is corrected + accordingly. That's quite helpful. + SEEK_DATA: seek to offset + SEEK_HOLE: seek to end of range */ + fpi.CurrentByteOffset.QuadPart =3D offset; + if (whence =3D=3D SEEK_HOLE) + fpi.CurrentByteOffset.QuadPart +=3D out.Length.QuadPart; + } + else + { + /* Is range beyond offset? + SEEK_DATA: seek to start of range + SEEK_HOLE: seek to offset */ + fpi.CurrentByteOffset.QuadPart =3D (whence =3D=3D SEEK_DATA) + ? out.FileOffset.QuadPart + : offset; + } + } + break; + default: /* Should never be reached */ + set_errno (EINVAL); + return -1; } =20 debug_printf ("setting file pointer to %U", fpi.CurrentByteOffset.QuadPa= rt);