📄 archive.c
字号:
/* archive.c - archive support Author: Kees J. Bot * 13 Nov 1993 */#include "h.h"#ifdef unix#include <unistd.h>#include <fcntl.h>#define arraysize(a) (sizeof(a) / sizeof((a)[0]))#define arraylimit(a) ((a) + arraysize(a))/* ASCII ar header. */#define ASCII_ARMAG "!<arch>\n"#define ASCII_SARMAG 8#define ASCII_ARFMAG "`\n"struct ascii_ar_hdr { char ar_name[16]; char ar_date[12]; char ar_uid[6]; char ar_gid[6]; char ar_mode[8]; char ar_size[10]; char ar_fmag[2];};/* ACK ar header. */#define ACK_ARMAG 0177545#define ACK_AALMAG 0177454struct ack_ar_hdr { char ar_name[14]; unsigned long ar_date; unsigned char ar_uid; unsigned char ar_gid; unsigned short ar_mode; unsigned long ar_size;};typedef struct archname { struct archname *next; /* Next on the hash chain. */ char name[16]; /* One archive entry. */ time_t date; /* The timestamp. */ /* (no need for other attibutes) */} archname_t;static size_t namelen; /* Max name length, 14 or 16. */#define HASHSIZE (64 << sizeof(int))static archname_t *nametab[HASHSIZE];_PROTOTYPE( static int hash, (char *name) );_PROTOTYPE( static int searchtab, (char *name, time_t *date, int scan) );_PROTOTYPE( static void deltab, (void) );_PROTOTYPE( static long ar_atol, (char *s, size_t n) );_PROTOTYPE( static int read_ascii_archive, (int afd) );_PROTOTYPE( static int read_ack_archive, (int afd) );static char *lpar, *rpar; /* Leave these at '(' and ')'. */int is_archive_ref(name) char *name;/* True if name is of the form "archive(file)". */{ char *p = name; while (*p != 0 && *p != '(' && *p != ')') p++; lpar = p; if (*p++ != '(') return 0; while (*p != 0 && *p != '(' && *p != ')') p++; rpar = p; if (*p++ != ')') return 0; return *p == 0;}static int hash(name) char *name;/* Compute a hash value out of a name. */{ unsigned h = 0; unsigned char *p = (unsigned char *) name; int n = namelen; while (*p != 0) { h = h * 0x1111 + *p++; if (--n == 0) break; } return h % arraysize(nametab);}static int searchtab(name, date, scan) char *name; time_t *date; int scan;/* Enter a name to the table, or return the date of one already there. */{ archname_t **pnp, *np; int cmp = 1; pnp = &nametab[hash(name)]; while ((np = *pnp) != NULL && (cmp = strncmp(name, np->name, namelen)) > 0) { pnp= &np->next; } if (cmp != 0) { if (scan) { errno = ENOENT; return -1; } if ((np = (archname_t *) malloc(sizeof(*np))) == NULL) fatal("No memory for archive name cache",(char *)0,0); strncpy(np->name, name, namelen); np->date = *date; np->next = *pnp; *pnp = np; } if (scan) *date = np->date; return 0;}static void deltab()/* Delete the name cache, a different library is to be read. */{ archname_t **pnp, *np, *junk; for (pnp = nametab; pnp < arraylimit(nametab); pnp++) { for (np = *pnp; np != NULL; ) { junk = np; np = np->next; free(junk); } *pnp = NULL; }}static long ar_atol(s, n) char *s; size_t n;/* Transform a string into a number. Ignore the space padding. */{ long l= 0; while (n > 0) { if (*s != ' ') l= l * 10 + (*s - '0'); s++; n--; } return l;}static int read_ascii_archive(afd)int afd;/* Read a modern ASCII type archive. */{ struct ascii_ar_hdr hdr; off_t pos= 8; char *p; time_t date; namelen = 16; for (;;) { if (lseek(afd, pos, SEEK_SET) == -1) return -1; switch (read(afd, &hdr, sizeof(hdr))) { case sizeof(hdr): break; case -1: return -1; default: return 0; } if (strncmp(hdr.ar_fmag, ASCII_ARFMAG, sizeof(hdr.ar_fmag)) != 0) { errno= EINVAL; return -1; } /* Strings are space padded! */ for (p= hdr.ar_name; p < hdr.ar_name + sizeof(hdr.ar_name); p++) { if (*p == ' ') { *p= 0; break; } } /* Add a file to the cache. */ date = ar_atol(hdr.ar_date, sizeof(hdr.ar_date)); searchtab(hdr.ar_name, &date, 0); pos+= sizeof(hdr) + ar_atol(hdr.ar_size, sizeof(hdr.ar_size)); pos= (pos + 1) & (~ (off_t) 1); }}static int read_ack_archive(afd)int afd;/* Read an ACK type archive. */{ unsigned char raw_hdr[14 + 4 + 1 + 1 + 2 + 4]; struct ack_ar_hdr hdr; off_t pos= 2; time_t date; namelen = 14; for (;;) { if (lseek(afd, pos, SEEK_SET) == -1) return -1; switch (read(afd, raw_hdr, sizeof(raw_hdr))) { case sizeof(raw_hdr): break; case -1: return -1; default: return 0; } /* Copy the useful fields from the raw bytes transforming PDP-11 * style numbers to native format. */ memcpy(hdr.ar_name, raw_hdr + 0, 14); hdr.ar_date= (long) raw_hdr[14 + 1] << 24 | (long) raw_hdr[14 + 0] << 16 | (long) raw_hdr[14 + 3] << 8 | (long) raw_hdr[14 + 2] << 0; hdr.ar_size= (long) raw_hdr[22 + 1] << 24 | (long) raw_hdr[22 + 0] << 16 | (long) raw_hdr[22 + 3] << 8 | (long) raw_hdr[22 + 2] << 0; /* Add a file to the cache. */ date = hdr.ar_date; searchtab(hdr.ar_name, &date, 0); pos= (pos + 26 + hdr.ar_size + 1) & (~ (off_t) 1); }}int archive_stat(name, stp) char *name; struct stat *stp;/* Search an archive for a file and return that file's stat info. */{ int afd; int r= -1; char magic[8]; char *file; static dev_t ardev; static ino_t arino = 0; if (!is_archive_ref(name)) { errno = EINVAL; return -1; } *lpar= 0; *rpar= 0; file= lpar + 1; if (stat(name, stp) < 0) goto bail_out; if (stp->st_ino != arino || stp->st_dev != ardev) { /* Either the first (and probably only) library, or a different * library. */ arino = stp->st_ino; ardev = stp->st_dev; deltab(); if ((afd= open(name, O_RDONLY)) < 0) goto bail_out; switch (read(afd, magic, sizeof(magic))) { case 8: if (strncmp(magic, ASCII_ARMAG, 8) == 0) { r= read_ascii_archive(afd); break; } if ((magic[0] & 0xFF) == ((ACK_AALMAG >> 0) & 0xFF) && (magic[1] & 0xFF) == ((ACK_AALMAG >> 8) & 0xFF) ) { r= read_ack_archive(afd); break; } /*FALL THROUGH*/ default: errno = EINVAL; /*FALL THROUGH*/ case -1: /* r= -1 */; } { int e= errno; close(afd); errno= e; } } else { /* Library is cached. */ r = 0; } if (r == 0) { /* Search the cache. */ r = searchtab(file, &stp->st_mtime, 1); }bail_out: /* Repair the name(file) thing. */ *lpar= '('; *rpar= ')'; return r;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -