This is the mail archive of the cygwin mailing list for the Cygwin project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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

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++
# ./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 :-)




Problem reports:
Unsubscribe info:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]