Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watmath!clyde!rutgers!seismo!mimsy!chris From: chris@mimsy.UUCP Newsgroups: comp.unix.wizards Subject: Re: Seek on a pipe Message-ID: <7074@mimsy.UUCP> Date: Tue, 16-Jun-87 11:46:22 EDT Article-I.D.: mimsy.7074 Posted: Tue Jun 16 11:46:22 1987 Date-Received: Thu, 18-Jun-87 02:35:40 EDT References: <7359@brl-adm.ARPA> <983@bobkat.UUCP> <5872@brl-smoke.ARPA> <791@mcgill-vision.UUCP> Organization: U of Maryland, Dept. of Computer Science, Coll. Pk., MD 20742 Lines: 144 In article <791@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: >A program that expects to do seeks should ensure that the object can >seek ... ... which is exactly why I wrote a routine to do this. /* * Copyright (c) 1987 University of Maryland Computer Science Department. * All rights reserved. * Permission to copy for any purpose is hereby granted so long as this * copyright notice remains intact. */ #ifndef lint static char rcsid[] = "$Header: seek.c,v 2.3 87/04/15 18:38:30 chris Exp $"; #endif /* * Seekable is a predicate which returns true iff a Unix fd is seekable. * * MakeSeekable forces an input stdio file to be seekable, by copying to * a temporary file if necessary. */ #include #ifdef sys5 #include #include #else #include #endif #include #include long lseek(); char *getenv(); int Seekable(fd) int fd; { return (lseek(fd, 0L, 1) >= 0 && !isatty(fd)); } /* * We use the despicable trick of unlinking an open temporary file. * The alternatives are too painful. If it becomes necessary to * do this another way, however, here is a method suggested by Fred * Blonder: fork, and have the parent wait for the child to exit. * (The parent must avoid being killed during this phase.) When * the child exits, the parent should then remove the temporary file, * then exit with the same status, or send itself the same signal. */ int MakeSeekable(f) register FILE *f; { register int tf, n; int mypid, tries, blksize; char *tmpdir; #ifdef MAXBSIZE char buf[MAXBSIZE]; struct stat st; #else char buf[BUFSIZ]; #endif if (Seekable(fileno(f))) return (0); if ((tmpdir = getenv("TMPDIR")) == 0) tmpdir = "/tmp"; /* compose a suitable temporary file name, and get an r/w descriptor */ mypid = getpid(); n = 0; tries = 0; do { (void) sprintf(buf, "%s/#%d.%d", tmpdir, mypid, n++); (void) unlink(buf); #ifdef O_CREAT /* have three-argument open syscall */ tries++; tf = open(buf, O_RDWR | O_CREAT | O_EXCL, 0666); #else if (access(buf, 0) == 0) { /* * Skip existing files. Note that tf might * not be set yet. */ tf = -1; continue; } tries++; tf = creat(buf, 0666); if (tf >= 0) { (void) close(tf); tf = open(buf, 2); if (tf < 0) (void) unlink(buf); } #endif } while (tf < 0 && tries < 20); if (tf < 0) /* probably unrecoverable user error */ return (-1); (void) unlink(buf); /* copy from input file to temp file */ #ifdef MAXBSIZE if (fstat(tf, &st)) /* how can this ever fail? */ blksize = MAXBSIZE; else blksize = MIN(MAXBSIZE, st.st_blksize); #else blksize = BUFSIZ; #endif while ((n = fread(buf, 1, blksize, f)) > 0) { if (write(tf, buf, n) != n) { (void) close(tf); return (-1); } } /* ferror() is broken in Ultrix 1.2; hence the && */ if (ferror(f) && !feof(f)) { (void) close(tf); return (-1); } /* * Now switch f to point at the temp file. Since we hit EOF, there * is nothing in f's stdio buffers, so we can play a dirty trick: */ clearerr(f); if (dup2(tf, fileno(f))) { (void) close(tf); return (-1); } (void) close(tf); return (0); } -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: seismo!mimsy!chris