On Wed Nov 16 11, Alexander Best wrote: > On Wed Nov 16 11, Alexander Best wrote: > > On Wed Nov 16 11, Alexander Best wrote: > > > On Tue Nov 15 11, Brandon Gooch wrote: > > > > On Nov 15, 2011 2:25 PM, "Alexander Best" <arun...@freebsd.org> wrote: > > > > > > > > > > hi there, > > > > > > > > > > one of the things i'm missing is an easy way to determine, whether a > > > > stream or > > > > > fd is seekable. i checked the dd(1) and hd(1) sources and those tools > > > > > are > > > > > performing so much stuff just to find out if this is the case, and > > > > > they > > > > still > > > > > are doing a very poor job. > > > > > > > > > > dd(1) e.g. identifies /dev/zero as non-seekable, even though it is. > > > > > the > > > > result: > > > > > > > > > > `dd if=/dev/zero bs=1m count=1 skip=100000`: > > > > > > > > > > on freebsd: > > > > > 57,41 real 0,05 user 43,21 sys > > > > > > > > > > on openbsd: > > > > > 0,88 real 0,00 user 0,07 sys > > > > > > > > > > on freebsd dd(1) is very easy fixable (1 line diff). the point > > > > > however is: > > > > > > > > > > there doesn't seem to exist a unified way of checking seekable == > > > > > TRUE. so > > > > > every userspace application seems to do it differently and most of > > > > > them > > > > (dd(1) > > > > > and hd(1) e.g) aren't doing it right. hd(1) e.g. believes that only > > > > regular > > > > > files are seekable. this means that hd(1) fired at /dev/ada* with a > > > > > high > > > > skip > > > > > value takes ages! dd(1) is a bit smarter in this case, but still not > > > > correct. > > > > > > > > > > idealy there would be something like stat.st_mode (see stat(2)) where > > > > > one > > > > > could simply do a S_ISSEEK(m). so far the best and easiest solution > > > > > i've > > > > seen > > > > > is: > > > > > > > > > > fd = open(argv[1], O_RDONLY); > > > > > if (fd == -1) > > > > > exit(1); > > > > > if (lseek(fd, 0, SEEK_CUR) != -1) > > > > > printf ("%d is seekable.\n", fd); > > > > > else > > > > > printf ("%d is not seekable.\n", fd); > > > > > > > > > > seeing an application iterate through a stream or fd via getchar(), > > > > although > > > > > a simple seek() would work is very frustrating. i think what would be > > > > needed > > > > > is a simple function or macro that userspace applications can make > > > > > use of. > > > > > maybe such a thing already exists in linux, openbsd, netbsd, > > > > > dragonflybsd, > > > > > solaris or plan9? > > > > > > > > > > cheers. > > > > > alex > > > > > > > > > > references: > > > > > [1] > > > > http://www.mavetju.org/mail/view_thread.php?list=freebsd-hackers&id=3290708&thread=yes > > > > > [2] http://www.freebsd.org/cgi/query-pr.cgi?pr=152485 > > > > > [3] http://www.freebsd.org/cgi/query-pr.cgi?pr=86485 > > > > > > > > So, according to APUE 2nd Edition, seek should be supported on anything > > > > that's not a pipe, FIFO, or socket. In fact, the "test for seekability" > > > > you've provided above closely resembles the example given in that text. > > > > > > if this really is the case, things could even be easier in a freebsd > > > specific > > > manor than the code above: > > > > > > !S_ISFIFO(m) && !S_ISSOCK(m) > > > > > > this means it would be trivial to write a new macro S_ISSEEK which would > > > test > > > stat.st_mode against the according bits. > > > > here's a patch, which also fixes a comment. > > hmmm...the patch doesn't seem to work for directories and symbolic links > unfortunately. does anybody spot the problem? > > i've attached two testing applications. mode.c will do the tests via the S_IS* > macros and requires the patch i've posted beforehand to stat.h. the other > application is seekable.c, which will use lseek(2) to test, whether a file > argument is seekable or not. basically both applications should report the > same!
grrrr...the attachments got scrubbed! > > cheers. > > > > > cheers. > > alex > > > > > > > > cheers. > > > alex > > > > > > > > > > > Need to think about this more before commenting further... > > > > > > > > -Brandon > > > diff --git a/sys/sys/stat.h b/sys/sys/stat.h > > index 1b03bd2..ab5ae44 100644 > > --- a/sys/sys/stat.h > > +++ b/sys/sys/stat.h > > @@ -238,10 +238,11 @@ struct nstat { > > #define S_ISCHR(m) (((m) & 0170000) == 0020000) /* char special > > */ > > #define S_ISBLK(m) (((m) & 0170000) == 0060000) /* block > > special */ > > #define S_ISREG(m) (((m) & 0170000) == 0100000) /* regular file > > */ > > -#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* fifo or > > socket */ > > +#define S_ISFIFO(m) (((m) & 0170000) == 0010000) /* pipe or fifo > > */ > > #if __POSIX_VISIBLE >= 200112 > > #define S_ISLNK(m) (((m) & 0170000) == 0120000) /* symbolic > > link */ > > #define S_ISSOCK(m) (((m) & 0170000) == 0140000) /* socket */ > > +#define S_ISSEEK(m) (((m) & 0150000) == 0) /* seekable > > file */ > > #endif > > #if __BSD_VISIBLE > > #define S_ISWHT(m) (((m) & 0170000) == 0160000) /* whiteout */ >
#include <sys/types.h> #include <sys/stat.h> #include <err.h> #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { int m; int bflag, iscflag, isdflag, isfflag, islflag, isregflag, issflag, isseflag; int iswflag; bflag = iscflag = isdflag = isfflag = islflag = isregflag = isseflag = 0; issflag = iswflag = 0; if (argc != 2) { fprintf(stderr, "usage: mode filename\n"); exit(1); } struct stat *test_stat; test_stat = malloc(sizeof(test_stat)); m = lstat(argv[1], test_stat); if (m == -1) err(1, "lstat failed"); if(S_ISBLK(test_stat->st_mode)) bflag = 1; if(S_ISCHR(test_stat->st_mode)) iscflag = 1; if(S_ISDIR(test_stat->st_mode)) isdflag = 1; if(S_ISFIFO(test_stat->st_mode)) isfflag = 1; if(S_ISLNK(test_stat->st_mode)) islflag = 1; if(S_ISREG(test_stat->st_mode)) isregflag = 1; if(S_ISSOCK(test_stat->st_mode)) issflag = 1; if(S_ISWHT(test_stat->st_mode)) iswflag = 1; if(S_ISSEEK(test_stat->st_mode)) isseflag = 1; printf("Block special file: %d\n" "Character special file: %d\n" "Directory: %d\n" "Pipe or FIFO special file: %d\n" "Symbolic link: %d\n" "Regular file: %d\n" "Socket: %d\n" "Whiteout: %d\n" "Seekable: %d\n" "st_mode: %u\n", bflag, iscflag, isdflag, isfflag, islflag, isregflag, issflag, iswflag, isseflag, test_stat->st_mode); exit(0); }
#include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> int main (int argc, char **argv) { int fd; if (argc != 2) { fprintf(stderr, "usage: seekable filename\n"); exit(1); } fd = open(argv[1], O_RDONLY); if (fd == -1) err(1, "open failed"); if (lseek(fd, 0, SEEK_CUR) != -1) printf ("%d is seekable.\n", fd); else printf ("%d is not seekable.\n", fd); exit(0); }
_______________________________________________ freebsd-hackers@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-hackers To unsubscribe, send any mail to "freebsd-hackers-unsubscr...@freebsd.org"