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