/* * Copyright (c) 1987 University of Maryland Department of Computer Science. * 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.4 87/06/16 18:29:03 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 { 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); }