📄 ar.c
字号:
if(strcmp(p->name, name) == 0) return 1; p = (Hashchain*) armalloc(sizeof(Hashchain)); p->next = hash[h]; p->name = name; hash[h] = p; return 0;}/* * open an archive and validate its header */intopenar(char *arname, int mode, int errok){ int fd; char mbuf[SARMAG]; fd = open(arname, mode); if(fd >= 0){ if(read(fd, mbuf, SARMAG) != SARMAG || strncmp(mbuf, ARMAG, SARMAG)) { fprint(2, "ar: %s not in archive format\n", arname); exits("error"); } }else if(!errok){ fprint(2, "ar: cannot open %s: %r\n", arname); exits("error"); } return fd;}/* * create an archive and set its header */intarcreate(char *arname){ int fd; fd = create(arname, OWRITE, 0664); if(fd < 0){ fprint(2, "ar: cannot create %s: %r\n", arname); exits("error"); } if(write(fd, ARMAG, SARMAG) != SARMAG) wrerr(); return fd;}/* * error handling */voidwrerr(void){ perror("ar: write error"); exits("error");}voidrderr(void){ perror("ar: read error"); exits("error");}voidphaseerr(int offset){ fprint(2, "ar: phase error at offset %d\n", offset); exits("error");}voidusage(void){ fprint(2, "usage: ar [%s][%s] archive files ...\n", opt, man); exits("error");}/* * read the header for the next archive member */Armember *getdir(Biobuf *b){ Armember *bp; char *cp; static char name[ARNAMESIZE+1]; bp = newmember(); if(HEADER_IO(Bread, b, bp->hdr)) { free(bp); return 0; } if(strncmp(bp->hdr.fmag, ARFMAG, sizeof(bp->hdr.fmag))) phaseerr(Boffset(b)); strncpy(name, bp->hdr.name, sizeof(bp->hdr.name)); cp = name+sizeof(name)-1; while(*--cp==' ') ; cp[1] = '\0'; file = name; bp->date = strtol(bp->hdr.date, 0, 0); bp->size = strtol(bp->hdr.size, 0, 0); return bp;}/* * Copy the file referenced by fd to the temp file */voidarmove(Biobuf *b, Arfile *ap, Armember *bp){ char *cp; Dir *d; d = dirfstat(Bfildes(b)); if (d == nil) { fprint(2, "ar: cannot stat %s\n", file); return; } trim(file, bp->hdr.name, sizeof(bp->hdr.name)); for (cp = strchr(bp->hdr.name, 0); /* blank pad on right */ cp < bp->hdr.name+sizeof(bp->hdr.name); cp++) *cp = ' '; sprint(bp->hdr.date, "%-12ld", d->mtime); sprint(bp->hdr.uid, "%-6d", 0); sprint(bp->hdr.gid, "%-6d", 0); sprint(bp->hdr.mode, "%-8lo", d->mode); sprint(bp->hdr.size, "%-10lld", d->length); strncpy(bp->hdr.fmag, ARFMAG, 2); bp->size = d->length; arread(b, bp, bp->size); if (d->length&0x01) d->length++; if (ap) { arinsert(ap, bp); ap->size += d->length+SAR_HDR; } free(d);}/* * Copy the archive member at the current offset into the temp file. */voidarcopy(Biobuf *b, Arfile *ap, Armember *bp){ long n; n = bp->size; if (n & 01) n++; arread(b, bp, n); if (ap) { arinsert(ap, bp); ap->size += n+SAR_HDR; }}/* * Skip an archive member */voidskip(Biobuf *bp, vlong len){ if (len & 01) len++; Bseek(bp, len, 1);}/* * Stream the three temp files to an archive */voidinstall(char *arname, Arfile *astart, Arfile *amiddle, Arfile *aend, int createflag){ int fd; if(allobj && dupfound) { fprint(2, "%s not changed\n", arname); return; } /* leave note group behind when copying back; i.e. sidestep interrupts */ rfork(RFNOTEG); if(createflag) fprint(2, "ar: creating %s\n", arname); fd = arcreate(arname); if(allobj) rl(fd); if (astart) { arstream(fd, astart); arfree(astart); } if (amiddle) { arstream(fd, amiddle); arfree(amiddle); } if (aend) { arstream(fd, aend); arfree(aend); } close(fd);}voidrl(int fd){ Biobuf b; char *cp; struct ar_hdr a; long len; Binit(&b, fd, OWRITE); Bseek(&b,seek(fd,0,1), 0); len = symdefsize; if(len&01) len++; sprint(a.date, "%-12ld", time(0)); sprint(a.uid, "%-6d", 0); sprint(a.gid, "%-6d", 0); sprint(a.mode, "%-8lo", 0644L); sprint(a.size, "%-10ld", len); strncpy(a.fmag, ARFMAG, 2); strcpy(a.name, symdef); for (cp = strchr(a.name, 0); /* blank pad on right */ cp < a.name+sizeof(a.name); cp++) *cp = ' '; if(HEADER_IO(Bwrite, &b, a)) wrerr(); len += Boffset(&b); if (astart) { wrsym(&b, len, astart->sym); len += astart->size; } if(amiddle) { wrsym(&b, len, amiddle->sym); len += amiddle->size; } if(aend) wrsym(&b, len, aend->sym); if(symdefsize&0x01) Bputc(&b, 0); Bterm(&b);}/* * Write the defined symbols to the symdef file */voidwrsym(Biobuf *bp, long offset, Arsymref *as){ int off; while(as) { Bputc(bp, as->type); off = as->offset+offset; Bputc(bp, off); Bputc(bp, off>>8); Bputc(bp, off>>16); Bputc(bp, off>>24); if (Bwrite(bp, as->name, as->len+1) != as->len+1) wrerr(); as = as->next; }}/* * Check if the archive member matches an entry on the command line. */intmatch(int count, char **files){ int i; char name[ARNAMESIZE+1]; for(i=0; i<count; i++) { if(files[i] == 0) continue; trim(files[i], name, ARNAMESIZE); if(strncmp(name, file, ARNAMESIZE) == 0) { file = files[i]; files[i] = 0; return 1; } } return 0;}/* * compare the current member to the name of the pivot member */intbamatch(char *file, char *pivot){ static int state = 0; switch(state) { case 0: /* looking for position file */ if (aflag) { if (strncmp(file, pivot, ARNAMESIZE) == 0) state = 1; } else if (bflag) { if (strncmp(file, pivot, ARNAMESIZE) == 0) { state = 2; /* found */ return 1; } } break; case 1: /* found - after previous file */ state = 2; return 1; case 2: /* already found position file */ break; } return 0;}/* * output a message, if 'v' option was specified */voidmesg(int c, char *file){ if(vflag) Bprint(&bout, "%c - %s\n", c, file);}/* * isolate file name by stripping leading directories and trailing slashes */voidtrim(char *s, char *buf, int n){ char *p; for(;;) { p = strrchr(s, '/'); if (!p) { /* no slash in name */ strncpy(buf, s, n); return; } if (p[1] != 0) { /* p+1 is first char of file name */ strncpy(buf, p+1, n); return; } *p = 0; /* strip trailing slash */ }}/* * utilities for printing long form of 't' command */#define SUID 04000#define SGID 02000#define ROWN 0400#define WOWN 0200#define XOWN 0100#define RGRP 040#define WGRP 020#define XGRP 010#define ROTH 04#define WOTH 02#define XOTH 01#define STXT 01000voidlongt(Armember *bp){ char *cp; pmode(strtoul(bp->hdr.mode, 0, 8)); Bprint(&bout, "%3ld/%1ld", strtol(bp->hdr.uid, 0, 0), strtol(bp->hdr.gid, 0, 0)); Bprint(&bout, "%7ld", bp->size); cp = ctime(bp->date); Bprint(&bout, " %-12.12s %-4.4s ", cp+4, cp+24);}int m1[] = { 1, ROWN, 'r', '-' };int m2[] = { 1, WOWN, 'w', '-' };int m3[] = { 2, SUID, 's', XOWN, 'x', '-' };int m4[] = { 1, RGRP, 'r', '-' };int m5[] = { 1, WGRP, 'w', '-' };int m6[] = { 2, SGID, 's', XGRP, 'x', '-' };int m7[] = { 1, ROTH, 'r', '-' };int m8[] = { 1, WOTH, 'w', '-' };int m9[] = { 2, STXT, 't', XOTH, 'x', '-' };int *m[] = { m1, m2, m3, m4, m5, m6, m7, m8, m9};voidpmode(long mode){ int **mp; for(mp = &m[0]; mp < &m[9];) select(*mp++, mode);}voidselect(int *ap, long mode){ int n; n = *ap++; while(--n>=0 && (mode&*ap++)==0) ap++; Bputc(&bout, *ap);}/* * Temp file I/O subsystem. We attempt to cache all three temp files in * core. When we run out of memory we spill to disk. * The I/O model assumes that temp files: * 1) are only written on the end * 2) are only read from the beginning * 3) are only read after all writing is complete. * The architecture uses one control block per temp file. Each control * block anchors a chain of buffers, each containing an archive member. */Arfile *newtempfile(char *name) /* allocate a file control block */{ Arfile *ap; ap = (Arfile *) armalloc(sizeof(Arfile)); ap->fname = name; return ap;}Armember *newmember(void) /* allocate a member buffer */{ return (Armember *)armalloc(sizeof(Armember));}voidarread(Biobuf *b, Armember *bp, int n) /* read an image into a member buffer */{ int i; bp->member = armalloc(n); i = Bread(b, bp->member, n); if (i < 0) { free(bp->member); bp->member = 0; rderr(); }}/* * insert a member buffer into the member chain */voidarinsert(Arfile *ap, Armember *bp){ bp->next = 0; if (!ap->tail) ap->head = bp; else ap->tail->next = bp; ap->tail = bp;}/* * stream the members in a temp file to the file referenced by 'fd'. */voidarstream(int fd, Arfile *ap){ Armember *bp; int i; char buf[8192]; if (ap->paged) { /* copy from disk */ seek(ap->fd, 0, 0); for (;;) { i = read(ap->fd, buf, sizeof(buf)); if (i < 0) rderr(); if (i == 0) break; if (write(fd, buf, i) != i) wrerr(); } close(ap->fd); ap->paged = 0; } /* dump the in-core buffers */ for (bp = ap->head; bp; bp = bp->next) { if (!arwrite(fd, bp)) wrerr(); }}/* * write a member to 'fd'. */intarwrite(int fd, Armember *bp){ int len; if(HEADER_IO(write, fd, bp->hdr)) return 0; len = bp->size; if (len & 01) len++; if (write(fd, bp->member, len) != len) return 0; return 1;}/* * Spill a member to a disk copy of a temp file */intpage(Arfile *ap){ Armember *bp; bp = ap->head; if (!ap->paged) { /* not yet paged - create file */ ap->fname = mktemp(ap->fname); ap->fd = create(ap->fname, ORDWR|ORCLOSE, 0600); if (ap->fd < 0) { fprint(2,"ar: can't create temp file\n"); return 0; } ap->paged = 1; } if (!arwrite(ap->fd, bp)) /* write member and free buffer block */ return 0; ap->head = bp->next; if (ap->tail == bp) ap->tail = bp->next; free(bp->member); free(bp); return 1;}/* * try to reclaim space by paging. we try to spill the start, middle, * and end files, in that order. there is no particular reason for the * ordering. */intgetspace(void){ if (astart && astart->head && page(astart)) return 1; if (amiddle && amiddle->head && page(amiddle)) return 1; if (aend && aend->head && page(aend)) return 1; return 0;}voidarfree(Arfile *ap) /* free a member buffer */{ Armember *bp, *next; for (bp = ap->head; bp; bp = next) { next = bp->next; if (bp->member) free(bp->member); free(bp); } free(ap);}/* * allocate space for a control block or member buffer. if the malloc * fails we try to reclaim space by spilling previously allocated * member buffers. */char *armalloc(int n){ char *cp; do { cp = malloc(n); if (cp) { memset(cp, 0, n); return cp; } } while (getspace()); fprint(2, "ar: out of memory\n"); exits("malloc"); return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -