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