pread() from /dev/sda fails with: Illegal seek

Christian Franke Christian.Franke@t-online.de
Sun Jan 12 16:59:00 GMT 2020


David Balažic wrote:
> I'm porting an app from Linux to Cygwin and stumbled on this problem:
>
> pread on /dev/sda fails with Illegal seek.
>
> The simplified code is:
>
> #include <fcntl.h>
> #include <stdio.h>
> #include <unistd.h>
> #include <stdlib.h>
>
> int main(int argc, char *argv[])
> {
>    unsigned int sector_size = 512;
>    void *buf = calloc(sector_size,1);
>    int fd = open("/dev/sda", O_DIRECT | O_RDONLY);
>    if (-1 == pread(fd, buf, sector_size, 0)) {
>      perror("pread failed");
>    }
> }
>
> # g++ test.cc
> # ./a  # run as adnministrator
> pread failed: Illegal seek
>
> Why is that?


Cygwin implements pread() and pwrite() only for regular disk files. For 
all other file types (including raw devices) these functions fail with 
errno EPIPE ("Illegal seek").

According to POSIX, "pread() ... shall read from a given position in the 
file without changing the file offset", see [1]. This must also hold if 
the file descriptor is used in multiple threads or is duplicated or is 
inherited from/to other processes. This cannot be easily emulated with 
Windows API. See [2] for a related long comment in source code.

If the app you want to port uses the fd only locally in a single thread, 
then something like this function may work:

ssize_t emul_pread(int fd, void *buf, size_t n, off_t offset)
{
   off_t oldoffs = lseek(fd, 0, SEEK_CUR);
   if (oldoffs == (off_t)-1)
     return -1;
   if (lseek(fd, offset, SEEK_SET) == (off_t)-1)
     return -1;
   ssize_t nr = read(fd, buf, n);
   if (lseek(fd, oldoffs, SEEK_SET) == (off_t)-1)
     return -1;
   return nr;
}

Sorry, not tested :-)

Regards,
Christian

[1]
https://pubs.opengroup.org/onlinepubs/9699919799/functions/pread.html

[2]
https://cygwin.com/git/gitweb.cgi?p=newlib-cygwin.git;a=blob;f=winsup/cygwin/fhandler_disk_file.cc;h=32381a0b0dbff6b7983ec8c4cec2f67dc5821939#l1479


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple



More information about the Cygwin mailing list