rsalz@uunet.uu.net (Rich Salz) (02/04/89)
Submitted-by: Mark H. Colburn <mark@jhereg.jhereg.mn.org> Posting-number: Volume 17, Issue 78 Archive-name: pax/part05 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 5 (of 6)." # Contents: buffer.c paxdir.c # Wrapped by mark@jhereg on Tue Dec 27 19:37:59 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f buffer.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"buffer.c\" else echo shar: Extracting \"buffer.c\" \(17360 characters\) sed "s/^X//" >buffer.c <<'END_OF_buffer.c' X/* $Source: /u/mark/src/pax/RCS/buffer.c,v $ X * X * $Revision: 1.1 $ X * X * buffer.c - Buffer management functions X * X * DESCRIPTION X * X * These functions handle buffer manipulations for the archiving X * formats. Functions are provided to get memory for buffers, X * flush buffers, read and write buffers and de-allocate buffers. X * Several housekeeping functions are provided as well to get some X * information about how full buffers are, etc. X * X * AUTHOR X * X * Mark H. Colburn, NAPS International (mark@jhereg.mn.org) X * X * Sponsored by The USENIX Association for public distribution. X * X * Copyright (c) 1989 Mark H. Colburn. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice is duplicated in all such X * forms and that any documentation, advertising materials, and other X * materials related to such distribution and use acknowledge that the X * software was developed * by Mark H. Colburn and sponsored by The X * USENIX Association. X * X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X * X * $Log: buffer.c,v $ X * Revision 1.1 88/12/23 18:02:01 mark X * Initial revision X * X */ X X#ifndef lint Xstatic char *ident = "$Id: buffer.c,v 1.1 88/12/23 18:02:01 mark Rel $"; Xstatic char *copyright = "Copyright (c) 1989 Mark H. Colburn.\nAll rights reserved.\n"; X#endif /* ! lint */ X X X/* Headers */ X X#include "pax.h" X X X/* Function Prototypes */ X X#ifdef __STDC__ X Xstatic int ar_write(int, char *, uint); Xstatic void buf_pad(OFFSET); Xstatic int indata(int, OFFSET, char *); Xstatic void outflush(void); Xstatic void buf_use(uint); Xstatic int buf_in_avail(char **, uint *); Xstatic uint buf_out_avail(char **); X X#else /* !__STDC__ */ X Xstatic int ar_write(); Xstatic void buf_pad(); Xstatic int indata(); Xstatic void outflush(); Xstatic void buf_use(); Xstatic int buf_in_avail(); Xstatic uint buf_out_avail(); X X#endif /* __STDC__ */ X X X/* inentry - install a single archive entry X * X * DESCRIPTION X * X * Inentry reads an archive entry from the archive file and writes it X * out the the named file. If we are in PASS mode during archive X * processing, the pass() function is called, otherwise we will X * extract from the archive file. X * X * Inentry actaully calls indata to process the actual data to the X * file. X * X * PARAMETERS X * X * char *name - name of the file to extract from the archive X * Stat *asb - stat block of the file to be extracted from the X * archive. X * X * RETURNS X * X * Returns zero if successful, -1 otherwise. X */ X X#ifdef __STDC__ X Xint inentry(char *name, Stat *asb) X X#else X Xint inentry(name, asb) Xchar *name; XStat *asb; X X#endif X{ X Link *linkp; X int ifd; X int ofd; X time_t tstamp[2]; X X if ((ofd = openo(name, asb, linkp = linkfrom(name, asb), 0)) > 0) { X if (asb->sb_size || linkp == NULL || linkp->l_size == 0) { X close(indata(ofd, asb->sb_size, name)); X } else if ((ifd = open(linkp->l_path->p_name, O_RDONLY)) < 0) { X warn(linkp->l_path->p_name, syserr()); X } else { X passdata(linkp->l_path->p_name, ifd, name, ofd); X close(ifd); X close(ofd); X } X } else { X return(buf_skip((OFFSET) asb->sb_size) >= 0); X } X tstamp[0] = (!f_pass && f_access_time) ? asb->sb_atime : time((time_t *) 0); X tstamp[1] = f_modification_time ? asb->sb_mtime : time((time_t *) 0); X utime(name, tstamp); X return (0); X} X X X/* outdata - write archive data X * X * DESCRIPTION X * X * Outdata transfers data from the named file to the archive buffer. X * It knows about the file padding which is required by tar, but no X * by cpio. Outdata continues after file read errors, padding with X * null characters if neccessary. Closes the input file descriptor X * when finished. X * X * PARAMETERS X * X * int fd - file descriptor of file to read data from X * char *name - name of file X * OFFSET size - size of the file X * X */ X X#ifdef __STDC__ X Xvoid outdata(int fd, char *name, OFFSET size) X X#else X Xvoid outdata(fd, name, size) Xint fd; Xchar *name; XOFFSET size; X X#endif X{ X uint chunk; X int got; X int oops; X uint avail; X int pad; X char *buf; X X oops = got = 0; X if (pad = (size % BLOCKSIZE)) { X pad = (BLOCKSIZE - pad); X } X while (size) { X avail = buf_out_avail(&buf); X size -= (chunk = size < avail ? (uint) size : avail); X if (oops == 0 && (got = read(fd, buf, (unsigned int) chunk)) < 0) { X oops = -1; X warn(name, syserr()); X got = 0; X } X if (got < chunk) { X if (oops == NULL) { X oops = -1; X } X warn(name, "Early EOF"); X while (got < chunk) { X buf[got++] = '\0'; X } X } X buf_use(chunk); X } X close(fd); X if (ar_format == TAR) { X buf_pad((OFFSET) pad); X } X} X X X/* write_eot - write the end of archive record(s) X * X * DESCRIPTION X * X * Write out an End-Of-Tape record. We actually zero at least one X * record, through the end of the block. Old tar writes garbage after X * two zeroed records -- and PDtar used to. X */ X X#ifdef __STDC__ X Xvoid write_eot(void) X X#else X Xvoid write_eot() X X#endif X{ X OFFSET pad; X char header[M_STRLEN + H_STRLEN + 1]; X X if (ar_format == TAR) { X /* write out two zero blocks for trailer */ X pad = 2 * BLOCKSIZE; X } else { X if (pad = (total + M_STRLEN + H_STRLEN + TRAILZ) % BLOCKSIZE) { X pad = BLOCKSIZE - pad; X } X strcpy(header, M_ASCII); X sprintf(header + M_STRLEN, H_PRINT, 0, 0, X 0, 0, 0, 1, 0, (time_t) 0, TRAILZ, pad); X outwrite(header, M_STRLEN + H_STRLEN); X outwrite(TRAILER, TRAILZ); X } X buf_pad((OFFSET) pad); X outflush(); X} X X X/* outwrite - write archive data X * X * DESCRIPTION X * X * Writes out data in the archive buffer to the archive file. The X * buffer index and the total byte count are incremented by the number X * of data bytes written. X * X * PARAMETERS X * X * char *idx - pointer to data to write X * uint len - length of the data to write X */ X X#ifdef __STDC__ X Xvoid outwrite(char *idx, uint len) X X#else X Xvoid outwrite(idx, len) Xchar *idx; /* pointer to data to write */ Xuint len; /* length of data to write */ X X#endif X{ X uint have; X uint want; X char *endx; X X endx = idx + len; X while (want = endx - idx) { X if (bufend - bufidx < 0) { X fatal("Buffer overlow in out_write\n"); X } X if ((have = bufend - bufidx) == 0) { X outflush(); X } X if (have > want) { X have = want; X } X memcpy(bufidx, idx, (int) have); X bufidx += have; X idx += have; X total += have; X } X} X X X/* passdata - copy data to one file X * X * DESCRIPTION X * X * Copies a file from one place to another. Doesn't believe in input X * file descriptor zero (see description of kludge in openi() comments). X * Closes the provided output file descriptor. X * X * PARAMETERS X * X * char *from - input file name (old file) X * int ifd - input file descriptor X * char *to - output file name (new file) X * int ofd - output file descriptor X */ X X#ifdef __STDC__ X Xvoid passdata(char *from, int ifd, char *to, int ofd) X X#else X Xvoid passdata(from, ifd, to, ofd) Xchar *from; Xint ifd; Xchar *to; Xint ofd; X X#endif X{ X int got; X int sparse; X char block[BUFSIZ]; X X if (ifd) { X lseek(ifd, (OFFSET) 0, 0); X sparse = 0; X while ((got = read(ifd, block, sizeof(block))) > 0 X && (sparse = ar_write(ofd, block, (uint) got)) >= 0) { X total += got; X } X if (got) { X warn(got < 0 ? from : to, syserr()); X } else if (sparse > 0 X && (lseek(ofd, (OFFSET)(-sparse), 1) < 0 X || write(ofd, block, (uint) sparse) != sparse)) { X warn(to, syserr()); X } X } X close(ofd); X} X X X/* buf_allocate - get space for the I/O buffer X * X * DESCRIPTION X * X * buf_allocate allocates an I/O buffer using malloc. The resulting X * buffer is used for all data buffering throughout the program. X * Buf_allocate must be called prior to any use of the buffer or any X * of the buffering calls. X * X * PARAMETERS X * X * int size - size of the I/O buffer to request X * X * ERRORS X * X * If an invalid size is given for a buffer or if a buffer of the X * required size cannot be allocated, then the function prints out an X * error message and returns a non-zero exit status to the calling X * process, terminating the program. X * X */ X X#ifdef __STDC__ X Xvoid buf_allocate(OFFSET size) X X#else X Xvoid buf_allocate(size) XOFFSET size; X X#endif X{ X extern char *malloc(); X X if (size <= 0) { X fatal("invalid value for blocksize"); X } X if ((bufstart = malloc((unsigned) size)) == NULL) { X fatal("Cannot allocate I/O buffer"); X } X bufend = bufidx = bufstart; X bufend += size; X} X X X/* buf_skip - skip input archive data X * X * DESCRIPTION X * X * Buf_skip skips past archive data. It is used when the length of X * the archive data is known, and we do not wish to process the data. X * X * PARAMETERS X * X * OFFSET len - number of bytes to skip X * X * RETURNS X * X * Returns zero under normal circumstances, -1 if unreadable data is X * encountered. X */ X X#ifdef __STDC__ X Xint buf_skip(OFFSET len) X X#else X Xint buf_skip(len) XOFFSET len; X X#endif X{ X uint chunk; X int corrupt = 0; X X while (len) { X if (bufend - bufidx < 0) { X fatal("Buffer overlow in buf_skip\n"); X } X while ((chunk = bufend - bufidx) == 0) { X corrupt |= ar_read(); X } X if (chunk > len) { X chunk = len; X } X bufidx += chunk; X len -= chunk; X total += chunk; X } X return (corrupt); X} X X X/* buf_read - read a given number of characters from the input archive X * X * DESCRIPTION X * X * Reads len number of characters from the input archive and X * stores them in the buffer pointed at by dst. X * X * PARAMETERS X * X * char *dst - pointer to buffer to store data into X * uint len - length of data to read X * X * RETURNS X * X * Returns zero with valid data, -1 if unreadable portions were X * replaced by null characters. X */ X X#ifdef __STDC__ X Xint buf_read(char *dst, uint len) X X#else X Xint buf_read(dst, len) Xchar *dst; Xuint len; X X#endif X{ X int have; X int want; X int corrupt = 0; X char *endx = dst + len; X X while (want = endx - dst) { X if (bufend - bufidx < 0) { X fatal("Buffer overlow in buf_read\n"); X } X while ((have = bufend - bufidx) == 0) { X have = 0; X corrupt |= ar_read(); X } X if (have > want) { X have = want; X } X memcpy(dst, bufidx, have); X bufidx += have; X dst += have; X total += have; X } X return (corrupt); X} X X X/* indata - install data from an archive X * X * DESCRIPTION X * X * Indata writes size bytes of data from the archive buffer to the output X * file specified by fd. The filename which is being written, pointed X * to by name is provided only for diagnostics. X * X * PARAMETERS X * X * int fd - output file descriptor X * OFFSET size - number of bytes to write to output file X * char *name - name of file which corresponds to fd X * X * RETURNS X * X * Returns given file descriptor. X */ X X#ifdef __STDC__ X Xstatic int indata(int fd, OFFSET size, char *name) X X#else X Xstatic int indata(fd, size, name) Xint fd; XOFFSET size; Xchar *name; X X#endif X{ X uint chunk; X char *oops; X int sparse; X int corrupt; X char *buf; X uint avail; X X corrupt = sparse = 0; X oops = NULL; X while (size) { X corrupt |= buf_in_avail(&buf, &avail); X size -= (chunk = size < avail ? (uint) size : avail); X if (oops == NULL && (sparse = ar_write(fd, buf, chunk)) < 0) { X oops = syserr(); X } X buf_use(chunk); X } X if (corrupt) { X warn(name, "Corrupt archive data"); X } X if (oops) { X warn(name, oops); X } else if (sparse > 0 && (lseek(fd, (OFFSET) - 1, 1) < 0 X || write(fd, "", 1) != 1)) { X warn(name, syserr()); X } X return (fd); X} X X X/* outflush - flush the output buffer X * X * DESCRIPTION X * X * The output buffer is written, if there is anything in it, to the X * archive file. X */ X X#ifdef __STDC__ X Xstatic void outflush(void) X X#else X Xstatic void outflush() X X#endif X{ X char *buf; X int got; X uint len; X X /* if (bufidx - buf > 0) */ X for (buf = bufstart; len = bufidx - buf;) { X if ((got = write(archivefd, buf, MIN(len, blocksize))) > 0) { X buf += got; X } else if (got < 0) { X next(AR_WRITE); X } X } X bufend = (bufidx = bufstart) + blocksize; X} X X X/* ar_read - fill the archive buffer X * X * DESCRIPTION X * X * Remembers mid-buffer read failures and reports them the next time X * through. Replaces unreadable data with null characters. Resets X * the buffer pointers as appropriate. X * X * RETURNS X * X * Returns zero with valid data, -1 otherwise. X */ X X#ifdef __STDC__ X Xint ar_read(void) X X#else X Xint ar_read() X X#endif X{ X int got; X static int failed; X X bufend = bufidx = bufstart; X if (!failed) { X if (areof) { X if (total == 0) { X fatal("No input"); X } else { X next(AR_READ); X } X } X while (!failed && !areof && bufstart + blocksize - bufend >= blocksize) { X if ((got = read(archivefd, bufend, (unsigned int) blocksize)) > 0) { X bufend += got; X } else if (got < 0) { X failed = -1; X warnarch(syserr(), (OFFSET) 0 - (bufend - bufidx)); X } else { X ++areof; X } X } X } X if (failed && bufend == bufstart) { X failed = 0; X for (got = 0; got < blocksize; ++got) { X *bufend++ = '\0'; X } X return (-1); X } X return (0); X} X X X/* ar_write - write a filesystem block X * X * DESCRIPTION X * X * Writes len bytes of data data from the specified buffer to the X * specified file. Seeks past sparse blocks. X * X * PARAMETERS X * X * int fd - file to write to X * char *buf - buffer to get data from X * uint len - number of bytes to transfer X * X * RETURNS X * X * Returns 0 if the block was written, the given length for a sparse X * block or -1 if unsuccessful. X */ X X#ifdef __STDC__ X Xstatic int ar_write(int fd, char *buf, uint len) X X#else X Xstatic int ar_write(fd, buf, len) Xint fd; Xchar *buf; Xuint len; X X#endif X{ X char *bidx; X char *bend; X X bend = (bidx = buf) + len; X while (bidx < bend) { X if (*bidx++) { X return (write(fd, buf, len) == len ? 0 : -1); X } X } X return (lseek(fd, (OFFSET) len, 1) < 0 ? -1 : len); X} X X X/* buf_pad - pad the archive buffer X * X * DESCRIPTION X * X * Buf_pad writes len zero bytes to the archive buffer in order to X * pad it. X * X * PARAMETERS X * X * OFFSET pad - number of zero bytes to pad X * X */ X X#ifdef __STDC__ X Xstatic void buf_pad(OFFSET pad) X X#else X Xstatic void buf_pad(pad) XOFFSET pad; X X#endif X{ X int idx; X int have; X X while (pad) { X if ((have = bufend - bufidx) > pad) { X have = pad; X } X for (idx = 0; idx < have; ++idx) { X *bufidx++ = '\0'; X } X total += have; X pad -= have; X if (bufend - bufidx == 0) { X outflush(); X } X } X} X X X/* buf_use - allocate buffer space X * X * DESCRIPTION X * X * Buf_use marks space in the buffer as being used; advancing both the X * buffer index (bufidx) and the total byte count (total). X * X * PARAMETERS X * X * uint len - Amount of space to allocate in the buffer X */ X X#ifdef __STDC__ X Xstatic void buf_use(uint len) X X#else X Xstatic void buf_use(len) Xuint len; X X#endif X{ X bufidx += len; X total += len; X} X X X/* buf_in_avail - index available input data within the buffer X * X * DESCRIPTION X * X * Buf_in_avail fills the archive buffer, and points the bufp X * parameter at the start of the data. The lenp parameter is X * modified to contain the number of bytes which were read. X * X * PARAMETERS X * X * char **bufp - pointer to the buffer to read data into X * uint *lenp - pointer to the number of bytes which were read X * (returned to the caller) X * X * RETURNS X * X * Stores a pointer to the data and its length in given locations. X * Returns zero with valid data, -1 if unreadable portions were X * replaced with nulls. X * X * ERRORS X * X * If an error occurs in ar_read, the error code is returned to the X * calling function. X * X */ X X#ifdef __STDC__ X Xstatic int buf_in_avail(char **bufp, uint *lenp) X X#else X Xstatic int buf_in_avail(bufp, lenp) Xchar **bufp; Xuint *lenp; X X#endif X{ X uint have; X int corrupt = 0; X X while ((have = bufend - bufidx) == 0) { X corrupt |= ar_read(); X } X *bufp = bufidx; X *lenp = have; X return (corrupt); X} X X X/* buf_out_avail - index buffer space for archive output X * X * DESCRIPTION X * X * Stores a buffer pointer at a given location. Returns the number X * of bytes available. X * X * PARAMETERS X * X * char **bufp - pointer to the buffer which is to be stored X * X * RETURNS X * X * The number of bytes which are available in the buffer. X * X */ X X#ifdef __STDC__ X Xstatic uint buf_out_avail(char **bufp) X X#else X Xstatic uint buf_out_avail(bufp) Xchar **bufp; X X#endif X{ X int have; X X if (bufend - bufidx < 0) { X fatal("Buffer overlow in buf_out_avail\n"); X } X if ((have = bufend - bufidx) == 0) { X outflush(); X } X *bufp = bufidx; X return (have); X} END_OF_buffer.c if test 17360 -ne `wc -c <buffer.c`; then echo shar: \"buffer.c\" unpacked with wrong size! fi # end of overwriting check fi if test -f paxdir.c -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"paxdir.c\" else echo shar: Extracting \"paxdir.c\" \(16936 characters\) sed "s/^X//" >paxdir.c <<'END_OF_paxdir.c' X/* X opendir -- open a directory stream X X last edit: 16-Jun-1987 D A Gwyn X*/ X X#include <sys/errno.h> X#include <sys/types.h> X#include <sys/stat.h> X#include "paxdir.h" X X#ifdef BSD_SYSV X/* X <sys/_dir.h> -- definitions for 4.2,4.3BSD directories X X last edit: 25-Apr-1987 D A Gwyn X X A directory consists of some number of blocks of DIRBLKSIZ bytes each, X where DIRBLKSIZ is chosen such that it can be transferred to disk in a X single atomic operation (e.g., 512 bytes on most machines). X X Each DIRBLKSIZ-byte block contains some number of directory entry X structures, which are of variable length. Each directory entry has the X beginning of a (struct direct) at the front of it, containing its X filesystem-unique ident number, the length of the entry, and the length X of the name contained in the entry. These are followed by the NUL- X terminated name padded to a (long) boundary with 0 bytes. The maximum X length of a name in a directory is MAXNAMELEN. X X The macro DIRSIZ(dp) gives the amount of space required to represent a X directory entry. Free space in a directory is represented by entries X that have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes in a X directory block are claimed by the directory entries; this usually X results in the last entry in a directory having a large dp->d_reclen. X When entries are deleted from a directory, the space is returned to the X previous entry in the same directory block by increasing its X dp->d_reclen. If the first entry of a directory block is free, then X its dp->d_fileno is set to 0; entries other than the first in a X directory do not normally have dp->d_fileno set to 0. X X prerequisite: <sys/types.h> X*/ X X#if defined(accel) || defined(sun) || defined(vax) X#define DIRBLKSIZ 512 /* size of directory block */ X#else X#ifdef alliant X#define DIRBLKSIZ 4096 /* size of directory block */ X#else X#ifdef gould X#define DIRBLKSIZ 1024 /* size of directory block */ X#else X#ifdef ns32000 /* Dynix System V */ X#define DIRBLKSIZ 2600 /* size of directory block */ X#else /* be conservative; multiple blocks are okay X * but fractions are not */ X#define DIRBLKSIZ 4096 /* size of directory block */ X#endif X#endif X#endif X#endif X X#define MAXNAMELEN 255 /* maximum filename length */ X/* NOTE: not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */ X Xstruct direct { /* data from read()/_getdirentries() */ X unsigned long d_fileno; /* unique ident of entry */ X unsigned short d_reclen; /* length of this record */ X unsigned short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMELEN + 1]; /* NUL-terminated filename */ X}; X X/* X The DIRSIZ macro gives the minimum record length which will hold the X directory entry. This requires the amount of space in a (struct X direct) without the d_name field, plus enough space for the name with a X terminating NUL character, rounded up to a (long) boundary. X X (Note that Berkeley didn't properly compensate for struct padding, X but we nevertheless have to use the same size as the actual system.) X*/ X X#define DIRSIZ( dp ) ((sizeof(struct direct) - (MAXNAMELEN+1) \ X + sizeof(long) + (dp)->d_namlen) \ X / sizeof(long) * sizeof(long)) X X#else X#include <sys/dir.h> X#ifdef SYSV3 X#undef MAXNAMLEN /* avoid conflict with SVR3 */ X#endif X /* Good thing we don't need to use the DIRSIZ() macro! */ X#ifdef d_ino /* 4.3BSD/NFS using d_fileno */ X#undef d_ino /* (not absolutely necessary) */ X#else X#define d_fileno d_ino /* (struct direct) member */ X#endif X#endif X#ifdef UNK X#ifndef UFS X#include "***** ERROR ***** UNK applies only to UFS" X/* One could do something similar for getdirentries(), but I didn't bother. */ X#endif X#include <signal.h> X#endif X X#if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */ X#include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined" X#endif X X#ifdef UFS X#define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */ X#else /* BFS || NFS */ X#define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */ X#endif X X#ifdef NFS X#ifdef BSD_SYSV X#define getdirentries _getdirentries /* package hides this system call */ X#endif Xextern int getdirentries(); Xstatic long dummy; /* getdirentries() needs basep */ X#define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy ) X#else /* UFS || BFS */ X#ifdef BSD_SYSV X#define read _read /* avoid emulation overhead */ X#endif Xextern int read(); X#define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n ) X#endif X X#ifdef UNK Xextern int _getdents(); /* actual system call */ X#endif X Xextern char *strncpy(); Xextern int fstat(); Xextern OFFSET lseek(); X Xextern int errno; X X#ifndef DIRBLKSIZ X#define DIRBLKSIZ 4096 /* directory file read buffer size */ X#endif X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef SEEK_CUR X#define SEEK_CUR 1 X#endif X X#ifndef S_ISDIR /* macro to test for directory file */ X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X X X#ifndef SEEK_CUR X#define SEEK_CUR 1 X#endif X X#ifdef BSD_SYSV X#define open _open /* avoid emulation overhead */ X#endif X Xextern int getdents(); /* SVR3 system call, or emulation */ X Xtypedef char *pointer; /* (void *) if you have it */ X Xextern void free(); Xextern pointer malloc(); Xextern int Xopen(), close(), fstat(); X Xextern int errno; Xextern OFFSET lseek(); X X#ifndef SEEK_SET X#define SEEK_SET 0 X#endif X Xtypedef int bool; /* Boolean data type */ X#define false 0 X#define true 1 X X X#ifndef NULL X#define NULL 0 X#endif X X#ifndef O_RDONLY X#define O_RDONLY 0 X#endif X X#ifndef S_ISDIR /* macro to test for directory file */ X#define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR) X#endif X X#ifdef __STDC__ X XDIR *opendir(char *dirname) X X#else X XDIR *opendir(dirname) Xchar *dirname; /* name of directory */ X X#endif X{ X register DIR *dirp; /* -> malloc'ed storage */ X register int fd; /* file descriptor for read */ X struct stat sbuf; /* result of fstat() */ X X if ((fd = open(dirname, O_RDONLY)) < 0) X return NULL; /* errno set by open() */ X X if (fstat(fd, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) { X close(fd); X errno = ENOTDIR; X return NULL; /* not a directory */ X } X if ((dirp = (DIR *) malloc(sizeof(DIR))) == NULL X || (dirp->dd_buf = (char *) malloc((unsigned) DIRBUF)) == NULL X ) { X register int serrno = errno; X /* errno set to ENOMEM by sbrk() */ X X if (dirp != NULL) X free((pointer) dirp); X X close(fd); X errno = serrno; X return NULL; /* not enough memory */ X } X dirp->dd_fd = fd; X dirp->dd_loc = dirp->dd_size = 0; /* refill needed */ X X return dirp; X} X X X/* X * closedir -- close a directory stream X * X * last edit: 11-Nov-1988 D A Gwyn X */ X X#ifdef __STDC__ X Xint closedir(register DIR *dirp) X X#else X Xint closedir(dirp) Xregister DIR *dirp; /* stream from opendir() */ X X#endif X{ X register int fd; X X if ( dirp == NULL || dirp->dd_buf == NULL ) { X errno = EFAULT; X return -1; /* invalid pointer */ X } X X fd = dirp->dd_fd; /* bug fix thanks to R. Salz */ X free( (pointer)dirp->dd_buf ); X free( (pointer)dirp ); X return close( fd ); X} X X X/* X readdir -- read next entry from a directory stream X X last edit: 25-Apr-1987 D A Gwyn X*/ X X#ifdef __STDC__ X Xstruct dirent *readdir(register DIR *dirp) X X#else X Xstruct dirent *readdir(dirp) Xregister DIR *dirp; /* stream from opendir() */ X X#endif X{ X register struct dirent *dp; /* -> directory data */ X X if (dirp == NULL || dirp->dd_buf == NULL) { X errno = EFAULT; X return NULL; /* invalid pointer */ X } X do { X if (dirp->dd_loc >= dirp->dd_size) /* empty or obsolete */ X dirp->dd_loc = dirp->dd_size = 0; X X if (dirp->dd_size == 0 /* need to refill buffer */ X && (dirp->dd_size = X getdents(dirp->dd_fd, dirp->dd_buf, (unsigned) DIRBUF) X ) <= 0 X ) X return NULL; /* EOF or error */ X X dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc]; X dirp->dd_loc += dp->d_reclen; X } X while (dp->d_ino == 0L); /* don't rely on getdents() */ X X return dp; X} X X X/* X seekdir -- reposition a directory stream X X last edit: 24-May-1987 D A Gwyn X X An unsuccessful seekdir() will in general alter the current X directory position; beware. X X NOTE: 4.nBSD directory compaction makes seekdir() & telldir() X practically impossible to do right. Avoid using them! X*/ X X#ifdef __STDC__ X Xvoid seekdir(register DIR *dirp, register OFFSET loc) X X#else X Xvoid seekdir(dirp, loc) Xregister DIR *dirp; /* stream from opendir() */ Xregister OFFSET loc; /* position from telldir() */ X X#endif X{ X register bool rewind; /* "start over when stymied" flag */ X X if (dirp == NULL || dirp->dd_buf == NULL) { X errno = EFAULT; X return; /* invalid pointer */ X } X /* X * A (struct dirent)'s d_off is an invented quantity on 4.nBSD X * NFS-supporting systems, so it is not safe to lseek() to it. X */ X X /* Monotonicity of d_off is heavily exploited in the following. */ X X /* X * This algorithm is tuned for modest directory sizes. For huge X * directories, it might be more efficient to read blocks until the first X * d_off is too large, then back up one block, or even to use binary X * search on the directory blocks. I doubt that the extra code for that X * would be worthwhile. X */ X X if (dirp->dd_loc >= dirp->dd_size /* invalid index */ X || ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc X /* too far along in buffer */ X ) X dirp->dd_loc = 0; /* reset to beginning of buffer */ X /* else save time by starting at current dirp->dd_loc */ X X for (rewind = true;;) { X register struct dirent *dp; X X /* See whether the matching entry is in the current buffer. */ X X if ((dirp->dd_loc < dirp->dd_size /* valid index */ X || readdir(dirp) != NULL /* next buffer read */ X && (dirp->dd_loc = 0, true) /* beginning of buffer set */ X ) X && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off X <= loc /* match possible in this buffer */ X ) { X for ( /* dp initialized above */ ; X (char *) dp < &dirp->dd_buf[dirp->dd_size]; X dp = (struct dirent *) ((char *) dp + dp->d_reclen) X ) X if (dp->d_off == loc) { /* found it! */ X dirp->dd_loc = X (char *) dp - dirp->dd_buf; X return; X } X rewind = false; /* no point in backing up later */ X dirp->dd_loc = dirp->dd_size; /* set end of buffer */ X } else X /* whole buffer past matching entry */ if (!rewind) { /* no point in searching X * further */ X errno = EINVAL; X return; /* no entry at specified loc */ X } else { /* rewind directory and start over */ X rewind = false; /* but only once! */ X X dirp->dd_loc = dirp->dd_size = 0; X X if (lseek(dirp->dd_fd, (OFFSET) 0, SEEK_SET) X != 0 X ) X return; /* errno already set (EBADF) */ X X if (loc == 0) X return; /* save time */ X } X } X} X X X/* telldir - report directory stream position X * X * DESCRIPTION X * X * Returns the offset of the next directory entry in the X * directory associated with dirp. X * X * NOTE: 4.nBSD directory compaction makes seekdir() & telldir() X * practically impossible to do right. Avoid using them! X * X * PARAMETERS X * X * DIR *dirp - stream from opendir() X * X * RETURNS X * X * Return offset of next entry X */ X X X#ifdef __STDC__ X XOFFSET telldir(DIR *dirp) X X#else X XOFFSET telldir(dirp) XDIR *dirp; /* stream from opendir() */ X X#endif X{ X if (dirp == NULL || dirp->dd_buf == NULL) { X errno = EFAULT; X return -1; /* invalid pointer */ X } X if (dirp->dd_loc < dirp->dd_size) /* valid index */ X return ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off; X else /* beginning of next directory block */ X return lseek(dirp->dd_fd, (OFFSET) 0, SEEK_CUR); X} X X X#ifdef UFS X X/* X The following routine is necessary to handle DIRSIZ-long entry names. X Thanks to Richard Todd for pointing this out. X*/ X X X/* return # chars in embedded name */ X X#ifdef __STDC__ X Xstatic int NameLen(char *name) X X#else X Xstatic int NameLen(name) Xchar *name; /* -> name embedded in struct direct */ X X#endif X{ X register char *s; /* -> name[.] */ X register char *stop = &name[DIRSIZ]; /* -> past end of name field */ X X for (s = &name[1]; /* (empty names are impossible) */ X *s != '\0' /* not NUL terminator */ X && ++s < stop; /* < DIRSIZ characters scanned */ X ); X X return s - name; /* # valid characters in name */ X} X X#else /* BFS || NFS */ X Xextern int strlen(); X X#define NameLen( name ) strlen( name ) /* names are always NUL-terminated */ X X#endif X X#ifdef UNK Xstatic enum { X maybe, no, yes X} state = maybe; X X X/* sig_catch - used to catch signals X * X * DESCRIPTION X * X * Used to catch signals. X */ X X/*ARGSUSED*/ X X#ifdef __STDC__ X Xstatic void sig_catch(int sig) X X#else X Xstatic void sig_catch(sig) Xint sig; /* must be SIGSYS */ X X#endif X{ X state = no; /* attempted _getdents() faulted */ X} X#endif X X X/* getdents - get directory entries X * X * DESCRIPTION X * X * Gets directory entries from the filesystem in an implemenation X * defined way. X * X * PARAMETERS X * X * int fildes - directory file descriptor X * char *buf - where to put the (struct dirent)s X * unsigned nbyte - size of buf[] X * X * RETURNS X * X * Returns number of bytes read; 0 on EOF, -1 on error X */ X X#ifdef __STDC__ X Xint getdents(int fildes, char *buf, unsigned nbyte) X X#else X Xint getdents(fildes, buf, nbyte) Xint fildes; /* directory file descriptor */ Xchar *buf; /* where to put the (struct dirent)s */ Xunsigned nbyte; /* size of buf[] */ X X#endif X{ X int serrno; /* entry errno */ X OFFSET offset; /* initial directory file offset */ X struct stat statb; /* fstat() info */ X union { X /* directory file block buffer */ X#ifdef UFS X char dblk[DIRBLKSIZ + 1]; X#else X char dblk[DIRBLKSIZ]; X#endif X struct direct dummy; /* just for alignment */ X } u; /* (avoids having to malloc()) */ X register struct direct *dp; /* -> u.dblk[.] */ X register struct dirent *bp; /* -> buf[.] */ X X#ifdef UNK X switch (state) { X SIG_T (*shdlr)(); /* entry SIGSYS handler */ X register int retval; /* return from _getdents() if any */ X X case yes: /* _getdents() is known to work */ X return _getdents(fildes, buf, nbyte); X X case maybe: /* first time only */ X shdlr = signal(SIGSYS, sig_catch); X retval = _getdents(fildes, buf, nbyte); /* try it */ X signal(SIGSYS, shdlr); X X if (state == maybe) { /* SIGSYS did not occur */ X state = yes; /* so _getdents() must have worked */ X return retval; X } X /* else fall through into emulation */ X X/* case no: /* fall through into emulation */ X } X#endif X X if (buf == NULL X#ifdef ATT_SPEC X || (unsigned long) buf % sizeof(long) != 0 /* ugh */ X#endif X ) { X errno = EFAULT; /* invalid pointer */ X return -1; X } X if (fstat(fildes, &statb) != 0) { X return -1; /* errno set by fstat() */ X } X X if (!S_ISDIR(statb.st_mode)) { X errno = ENOTDIR; /* not a directory */ X return -1; X } X if ((offset = lseek(fildes, (OFFSET) 0, SEEK_CUR)) < 0) { X return -1; /* errno set by lseek() */ X } X X#ifdef BFS /* no telling what remote hosts do */ X if ((unsigned long) offset % DIRBLKSIZ != 0) { X errno = ENOENT; /* file pointer probably misaligned */ X return -1; X } X#endif X X serrno = errno; /* save entry errno */ X X for (bp = (struct dirent *) buf; bp == (struct dirent *) buf;) { X X /* convert next directory block */ X int size; X X do { X size = GetBlock(fildes, u.dblk, DIRBLKSIZ); X } while (size == -1 && errno == EINTR); X X if (size <= 0) { X return size; /* EOF or error (EBADF) */ X } X X for (dp = (struct direct *) u.dblk; X (char *) dp < &u.dblk[size]; X dp = (struct direct *) ((char *) dp + RecLen(dp)) X ) { X#ifndef UFS X if (dp->d_reclen <= 0) { X errno = EIO; /* corrupted directory */ X return -1; X } X#endif X X if (dp->d_fileno != 0) { /* non-empty; copy to user buffer */ X register int reclen = X DIRENTSIZ(NameLen(dp->d_name)); X X if ((char *) bp + reclen > &buf[nbyte]) { X errno = EINVAL; X return -1; /* buf too small */ X } X bp->d_ino = dp->d_fileno; X bp->d_off = offset + ((char *) dp - u.dblk); X bp->d_reclen = reclen; X X { X#ifdef UFS X /* Is the following kludge ugly? You bet. */ X X register char save = dp->d_name[DIRSIZ]; X /* save original data */ X X dp->d_name[DIRSIZ] = '\0'; X /* ensure NUL termination */ X#endif X /* adds NUL padding */ X strncpy(bp->d_name, dp->d_name, reclen - DIRENTBASESIZ); X#ifdef UFS X dp->d_name[DIRSIZ] = save; X /* restore original data */ X#endif X } X X bp = (struct dirent *) ((char *) bp + reclen); X } X } X X#ifndef BFS /* 4.2BSD screwed up; fixed in 4.3BSD */ X if ((char *) dp > &u.dblk[size]) { X errno = EIO; /* corrupted directory */ X return -1; X } X#endif X } X X errno = serrno; /* restore entry errno */ X return (char *) bp - buf; /* return # bytes read */ X} END_OF_paxdir.c if test 16936 -ne `wc -c <paxdir.c`; then echo shar: \"paxdir.c\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 5 \(of 6\). cp /dev/null ark5isdone MISSING="" for I in 1 2 3 4 5 6 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 6 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.