easy way to determine if a stream or fd is seekable
Alexander Best
arundel at freebsd.org
Fri Nov 18 21:06:16 UTC 2011
On Fri Nov 18 11, Alexander Best wrote:
> On Fri Nov 18 11, Tim Kientzle wrote:
> > On Nov 17, 2011, at 1:48 PM, Alexander Best wrote:
> >
> > > On Thu Nov 17 11, Dieter BSD wrote:
> > >>> lseek() on a tape drive does not return an error, nor does it
> > >>> actually do anything.
> > >>
> > >> IIRC some tape drives can seek, while others cannot.
> > >> Vague memories that it is supposed to be possible to put a
> > >> filesystem on a DECtape and mount the filesystem.
> > >
> > > or how about the following:
> > >
> > > 1) if the file argument we're seeking on is a tape drive, just do a regular
> > > seek operation.
> > > 2) afterwards use ftell() to verify that the seek REALLY happend. if it didn't,
> > > return -1 and set errno = EBADF.
> >
> > ftell() can't tell whether the seek really happened or not.
> > All it can do is ask the kernel, and the kernel doesn't know.
> >
> > Here is my current understanding:
> >
> > When you call lseek(), the kernel just stores the requested
> > offset in the file descriptor. lseek() always succeeds because
> > storing the requested offset in the file descriptor always succeeds.
> > (Except that the kernel specially checks if the file descriptor
> > is a pipe.)
> >
> > ftell() just obtains the data from the file descriptor.
> > So it always succeeds and always returns the data from
> > the previous seek request, regardless of whether that seek
> > actually did anything.
> >
> > With the next read or write request, the device driver may inspect the
> > offset information in the file descriptor. Or it can ignore
> > it. Almost all tape device drivers ignore it. Filesystems
> > uniformly support it. Disk drivers uniformly support it.
> > Other drivers vary considerably.
> >
> > In short: No, there is no "easy way" to determine if an
> > arbitrary stream or fd is seekable. If you try to create
> > a function that determines this, be certain to include
> > "Don't Know" as a possible return value.
>
> well it really depends what the goal is. it appears fixing fseek() for all
> cases is impossible then. however from a pragmatic point of view:
>
> why does a user have to wait for a command such as hd(1) or dd(1) working on
> files such as /dev/zero, /dev/null, /dev/(u)random or even /dev/ada* (only
> hd(1) -- dd(1) supports seeking here) for ages, although it could suceed in
> less than a second?
>
> the fact is: users care for speed and freebsd is slower than linux and openbsd
> in these cases. users aren't interested in the fact that lseek() won't work
> with tapes. most of them have probably never seen one (me included).
>
> if we return an error from within lseek() whenever lseek() was fired at a tape
> drive, wouldn't that cover 99% of all the possible cases?
something like the following inside lseek() would take care of tape drives:
if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
if (ioctl(io->fd, FIODTYPE, &type) == -1)
err(1, "%s", io->name);
if (type & D_TAPE)
return(EBADF)
}
cheers.
alex
>
> cheers.
> alex
>
> >
> > Tim
More information about the freebsd-hackers
mailing list