diff --git a/src/tests/directory.c b/src/tests/directory.c index eed269f136..7db1e46046 100644 --- a/src/tests/directory.c +++ b/src/tests/directory.c @@ -2,7 +2,7 @@ * CMUCS AFStools * dumpscan - routines for scanning and manipulating AFS volume dumps * - * Copyright (c) 1998 Carnegie Mellon University + * Copyright (c) 1998, 2001, 2004 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its @@ -26,11 +26,13 @@ * the rights to redistribute these changes. */ -/* directory.c - Parse an AFS directory */ +/* directory.c - AFS directory parsing and generation */ /* See the end of this file for a description of the directory format */ #include #include +#include +#include #include #include "dumpscan.h" @@ -41,140 +43,151 @@ #include +struct dir_state { + unsigned char **dirpages; + int npages; + + afs_dir_header *dh; /* Directory header */ + afs_dir_page *page; /* Current page */ + int pageno; /* Current page # */ + int entno; /* Current (next avail) entry # */ + int used; /* # entries used in this page */ +}; + static afs_dir_page page; -#define allocbit(x) (page.header.freebitmap[(x)>>3] & (1 << ((x) & 7))) -#define DPHE (DHE + 1) -#if 0 -static void -fixup(char *name, int l) -{ - name += 16; - l -= 15; +#define bmbyte(bm,x) bm[(x)>>3] +#define bmbit(x) (1 << ((x) & 7)) - while (l-- > 0) { - name[0] = name[4]; - name++; - } +#define allocbit(x) (bmbyte(page.header.freebitmap,x) & bmbit(x)) +#define setallocbit(bm,x) (bmbyte(bm,x) |= bmbit(x)) + +#define DPHE (DHE + 1) + +/* Hash function used in AFS directories. */ +static int namehash(char *name, int buckets, int seed) +{ + int hval = seed, tval; + + while (*name) hval = (hval * 173) + *name++; + tval = hval & (buckets - 1); + return tval ? hval < 0 ? buckets - tval : tval : 0; +} + +#if 0 +static void fixup(char *name, int l) +{ + name += 16; + l -= 15; + + while (l-- > 0) { + name[0] = name[4]; + name++; + } } #endif -afs_uint32 -parse_directory(XFILE * X, dump_parser * p, afs_vnode * v, afs_uint32 size, - int toeof) -{ - afs_dir_entry de; - int pgno, i, l, n; - afs_int32 r; - u_int64 where; - if (p->print_flags & DSPRINT_DIR) { - printf(" VNode Uniqifier Name\n"); - printf(" ========== ========== ==============================\n"); +afs_uint32 parse_directory(XFILE *X, dump_parser *p, afs_vnode *v, + afs_uint32 size, int toeof) +{ + afs_dir_entry de; + int pgno, i, l, n; + afs_int32 r; + u_int64 where; + + if (p->print_flags & DSPRINT_DIR) { + printf(" VNode Uniqifier Name\n"); + printf(" ========== ========== ==============================\n"); + } + if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r; + for (pgno = 0; toeof || size; pgno++, size -= (toeof ? 0 : AFS_PAGESIZE)) { + if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r; + if ((r = xfread(X, &page, AFS_PAGESIZE))) { + if (toeof && r == ERROR_XFILE_EOF) break; + return r; } - if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) - return r; - for (pgno = 0; toeof || size; pgno++, size -= (toeof ? 0 : AFS_PAGESIZE)) { - if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) - return r; - if ((r = xfread(X, &page, AFS_PAGESIZE))) { - if (toeof && (r == ERROR_XFILE_EOF)) - break; - return r; - } - if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) - return r; - if (page.header.tag != htons(1234)) { - if (p->cb_error) - (p->cb_error) (DSERR_MAGIC, 1, p->err_refcon, - "Invalid page tag (%d) in page %d", - ntohs(page.header.tag), pgno); - return DSERR_MAGIC; - } - for (i = (pgno ? 1 : DPHE); i < EPP; i++) { - if (!allocbit(i)) - continue; - if (page.entry[i].flag != FFIRST) { - if (p->cb_error) - (p->cb_error) (DSERR_MAGIC, 0, p->err_refcon, - "Invalid entry flag %d in entry %d/%d; skipping...", - page.entry[i].flag, pgno, i); - continue; - } - n = (EPP - i - 1) * 32 + 16; - for (l = 0; n && page.entry[i].name[l]; l++, n--); - if (page.entry[i].name[l]) { - if (p->cb_error) - (p->cb_error) (DSERR_FMT, 0, p->err_refcon, - "Filename too long in entry %d/%d; skipping page", - pgno, i); - break; - } + if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r; + if (page.header.tag != htons(1234)) { + if (p->cb_error) + (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon, + "Invalid page tag (%d) in page %d", + ntohs(page.header.tag), pgno); + return DSERR_MAGIC; + } + for (i = (pgno ? 1 : DPHE); i < EPP; i++) { + if (!allocbit(i)) continue; + if (page.entry[i].flag != FFIRST) { + if (p->cb_error) + (p->cb_error)(DSERR_MAGIC, 0, p->err_refcon, + "Invalid entry flag %d in entry %d/%d; skipping...", + page.entry[i].flag, pgno, i); + continue; + } + n = (EPP - i - 1) * 32 + 16; + for (l = 0; n && page.entry[i].name[l]; l++, n--); + if (page.entry[i].name[l]) { + if (p->cb_error) + (p->cb_error)(DSERR_FMT, 0, p->err_refcon, + "Filename too long in entry %d/%d; skipping page", + pgno, i); + break; + } /* fixup(page.entry[i].name, l); */ - if (pgno) - de.slot = i - 1 + (pgno - 1) * (EPP - 1) + (EPP - DPHE); - else - de.slot = i - DPHE; - de.name = page.entry[i].name; - de.vnode = ntohl(page.entry[i].vnode); - de.uniq = ntohl(page.entry[i].vunique); - if (p->print_flags & DSPRINT_DIR) - printf(" %10d %10d %s\n", de.vnode, de.uniq, de.name); - if (p->cb_dirent) { - r = (p->cb_dirent) (v, &de, X, p->refcon); - } - if (p->cb_dirent && (r = (p->cb_dirent) (v, &de, X, p->refcon))) - return r; - i += ((l + 16) >> 5); - } + if (pgno) de.slot = i - 1 + (pgno - 1) * (EPP - 1) + (EPP - DPHE); + else de.slot = i - DPHE; + de.name = page.entry[i].name; + de.vnode = ntohl(page.entry[i].vnode); + de.uniq = ntohl(page.entry[i].vunique); + if (p->print_flags & DSPRINT_DIR) + printf(" %10d %10d %s\n", de.vnode, de.uniq, de.name); + if (p->cb_dirent) { + r = (p->cb_dirent)(v, &de, X, p->refcon); + } + if (p->cb_dirent && (r = (p->cb_dirent)(v, &de, X, p->refcon))) + return r; + i += ((l + 16) >> 5); } - if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) - return r; - return 0; + } + if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r; + return 0; } -afs_uint32 -ParseDirectory(XFILE * X, dump_parser * p, afs_uint32 size, int toeof) +afs_uint32 ParseDirectory(XFILE *X, dump_parser *p, afs_uint32 size, int toeof) { - afs_uint32 r; + afs_uint32 r; - r = parse_directory(X, p, 0, size, toeof); - return r; + r = parse_directory(X, p, 0, size, toeof); + return r; } typedef struct { - char **name; - afs_uint32 *vnode; - afs_uint32 *vuniq; + char **name; + afs_uint32 *vnode; + afs_uint32 *vuniq; } dirlookup_stat; -static afs_uint32 -dirlookup_cb(afs_vnode * v, afs_dir_entry * de, XFILE * X, void *refcon) +static afs_uint32 dirlookup_cb(afs_vnode *v, afs_dir_entry *de, + XFILE *X, void *refcon) { - dirlookup_stat *s = (dirlookup_stat *) refcon; + dirlookup_stat *s = (dirlookup_stat *)refcon; - if (s->name && s->name[0]) { /* Search by filename */ - if (strcmp(de->name, s->name[0])) - return 0; /* Not it! */ - if (s->vnode) - s->vnode[0] = de->vnode; - if (s->vuniq) - s->vuniq[0] = de->uniq; - } else if (s->vnode) { /* Search by vnode */ - if (de->vnode != s->vnode[0]) - return 0; /* Not it! */ - if (s->name) { - s->name[0] = (char *)malloc(strlen(de->name) + 1); - if (!s->name[0]) - return ENOMEM; - strcpy(s->name[0], de->name); - } - if (s->vuniq) - s->vuniq[0] = de->uniq; + if (s->name && s->name[0]) { /* Search by filename */ + if (strcmp(de->name, s->name[0])) return 0; /* Not it! */ + if (s->vnode) s->vnode[0] = de->vnode; + if (s->vuniq) s->vuniq[0] = de->uniq; + } else if (s->vnode) { /* Search by vnode */ + if (de->vnode != s->vnode[0]) return 0; /* Not it! */ + if (s->name) { + s->name[0] = (char *)malloc(strlen(de->name) + 1); + if (!s->name[0]) return ENOMEM; + strcpy(s->name[0], de->name); } - return DSERR_DONE; + if (s->vuniq) s->vuniq[0] = de->uniq; + } + return DSERR_DONE; } @@ -189,29 +202,131 @@ dirlookup_cb(afs_vnode * v, afs_dir_entry * de, XFILE * X, void *refcon) * and size set to the length of the directory. * Returns 0 on success, whether or not the entry is found. */ -afs_uint32 -DirectoryLookup(XFILE * X, dump_parser * p, afs_uint32 size, char **name, - afs_uint32 * vnode, afs_uint32 * vuniq) +afs_uint32 DirectoryLookup(XFILE *X, dump_parser *p, afs_uint32 size, + char **name, afs_uint32 *vnode, afs_uint32 *vuniq) { - dump_parser my_p; - dirlookup_stat my_s; - afs_uint32 r; + dump_parser my_p; + dirlookup_stat my_s; + afs_uint32 r; - memset(&my_s, 0, sizeof(my_s)); - my_s.name = name; - my_s.vnode = vnode; - my_s.vuniq = vuniq; + memset(&my_s, 0, sizeof(my_s)); + my_s.name = name; + my_s.vnode = vnode; + my_s.vuniq = vuniq; - memset(&my_p, 0, sizeof(my_p)); - my_p.refcon = (void *)&my_s; - my_p.err_refcon = p->err_refcon; - my_p.cb_error = p->cb_error; - my_p.cb_dirent = dirlookup_cb; + memset(&my_p, 0, sizeof(my_p)); + my_p.refcon = (void *)&my_s; + my_p.err_refcon = p->err_refcon; + my_p.cb_error = p->cb_error; + my_p.cb_dirent = dirlookup_cb; - r = parse_directory(X, &my_p, 0, size, 0); - if (!r) - r = DSERR_DONE; - return handle_return(r, X, 0, p); + r = parse_directory(X, &my_p, 0, size, 0); + if (!r) r = DSERR_DONE; + return handle_return(r, X, 0, p); +} + + +static int allocpage(struct dir_state *ds, int reserve) +{ + unsigned char **dirpages; + int i; + + dirpages = malloc((ds->npages + 1) * sizeof(unsigned char *)); + if (!dirpages) return ENOMEM; + if (ds->dirpages) { + memcpy(dirpages, ds->dirpages, ds->npages * sizeof(unsigned char *)); + free(ds->dirpages); + } + ds->dirpages = dirpages; + + ds->dirpages[ds->npages] = malloc(AFS_PAGESIZE); + if (!ds->dirpages[ds->npages]) return ENOMEM; + ds->pageno = ds->npages++; + + ds->page = (afs_dir_page *)(ds->dirpages[ds->pageno]); + memset(ds->page, 0, AFS_PAGESIZE); + ds->page->header.tag = htons(AFS_DIR_MAGIC); + ds->entno = ds->used = reserve; + for (i = 0; i < reserve; i++) + setallocbit(ds->page->header.freebitmap, i); + return 0; +} + + +afs_uint32 Dir_Init(struct dir_state **dsp) +{ + afs_uint32 r; + + *dsp = malloc(sizeof(struct dir_state)); + if (!*dsp) return ENOMEM; + memset(*dsp, 0, sizeof(struct dir_state)); + if ((r = allocpage(*dsp, DPHE))) return r; + (*dsp)->dh = (afs_dir_header *)((*dsp)->page); + return 0; +} + + +afs_uint32 Dir_AddEntry(struct dir_state *ds, char *name, + afs_uint32 vnode, afs_uint32 unique) +{ + afs_uint32 r; + int l = strlen(name) + 1; + int ne = l > 16 ? 1 + ((l - 16) / 32) + !!((l - 16) % 32) : 1; + int hash = namehash(name, NHASHENT, 0); + + if (ne > EPP - 1) return ENAMETOOLONG; + if (ds->entno + ne > EPP) { + if (ds->pageno < 128) ds->dh->allomap[ds->pageno] = ds->used; + if ((r = allocpage(ds, 1))) return r; + } + ds->page->entry[ds->entno].flag = FFIRST; + ds->page->entry[ds->entno].next = ds->dh->hash[hash]; + ds->page->entry[ds->entno].vnode = htonl(vnode); + ds->page->entry[ds->entno].vunique = htonl(unique); + strcpy(ds->page->entry[ds->entno].name, name); + ds->dh->hash[hash] = htons((ds->pageno * EPP) + ds->entno); + while (ne--) { + setallocbit(ds->page->header.freebitmap, ds->entno); + ds->used++; + ds->entno++; + } + return 0; +} + + +afs_uint32 Dir_Finalize(struct dir_state *ds) +{ + int pages = ds->pageno + 1; + + if (ds->pageno < 128) ds->dh->allomap[ds->pageno] = ds->used; + ds->dh->pagehdr.pgcount = htons(pages); + return 0; +} + + +afs_uint32 Dir_EmitData(struct dir_state *ds, XFILE *X, int dotag) +{ + afs_uint32 r, size; + int i; + + size = ds->npages * AFS_PAGESIZE; + if (dotag && (r = WriteTagInt32(X, VTAG_DATA, size))) return r; + for (i = 0; i < ds->npages; i++) { + if ((r = xfwrite(X, ds->dirpages[i], AFS_PAGESIZE))) return r; + } + return 0; +} + + +afs_uint32 Dir_Free(struct dir_state *ds) +{ + int i; + + for (i = 0; i < ds->npages; i++) + free(ds->dirpages[i]); + free(ds->dirpages); + free(ds); + return 0; } diff --git a/src/tests/dumpfmt.h b/src/tests/dumpfmt.h index 184d98c2bc..74d49de35d 100644 --- a/src/tests/dumpfmt.h +++ b/src/tests/dumpfmt.h @@ -2,7 +2,7 @@ * CMUCS AFStools * dumpscan - routines for scanning and manipulating AFS volume dumps * - * Copyright (c) 1998 Carnegie Mellon University + * Copyright (c) 1998, 2001 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its @@ -122,29 +122,38 @@ #define VTAG_DATA 'f' -#define AFS_DIR_EPP 64 +#define AFS_DIR_MAGIC 1234 +#define AFS_DIR_EPP 64 +#define AFS_DIR_MAXPAGES 128 +#define AFS_DIR_NHASH 128 typedef struct { - afs_uint16 pgcount; - afs_uint16 tag; - char freecount; - char freebitmap[AFS_DIR_EPP / 8]; - char padding[32 - (5 + AFS_DIR_EPP / 8)]; + afs_uint16 pgcount; + afs_uint16 tag; + char freecount; + char freebitmap[AFS_DIR_EPP/8]; + char padding[32 - (5 + AFS_DIR_EPP/8)]; } afs_dir_pagehdr; typedef struct { - char flag; - char length; - afs_uint16 next; - afs_uint32 vnode; - afs_uint32 vunique; - char name[16]; - char padding[4]; + afs_dir_pagehdr pagehdr; + char allomap[AFS_DIR_MAXPAGES]; + afs_uint16 hash[AFS_DIR_NHASH]; +} afs_dir_header; + +typedef struct { + char flag; + char length; + afs_uint16 next; + afs_uint32 vnode; + afs_uint32 vunique; + char name[16]; + char padding[4]; } afs_dir_direntry; typedef union { - afs_dir_pagehdr header; - afs_dir_direntry entry[AFS_DIR_EPP]; + afs_dir_pagehdr header; + afs_dir_direntry entry[AFS_DIR_EPP]; } afs_dir_page; #endif /* _DUMPFMT_H_ */ diff --git a/src/tests/dumpscan.h b/src/tests/dumpscan.h index b3e077b970..ba1c4ddd20 100644 --- a/src/tests/dumpscan.h +++ b/src/tests/dumpscan.h @@ -2,7 +2,7 @@ * CMUCS AFStools * dumpscan - routines for scanning and manipulating AFS volume dumps * - * Copyright (c) 1998 Carnegie Mellon University + * Copyright (c) 1998, 2001, 2003 Carnegie Mellon University * All Rights Reserved. * * Permission to use, copy, modify and distribute this software and its @@ -39,21 +39,13 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include /* Random useful types */ typedef struct tagged_field tagged_field; typedef struct tag_parse_info tag_parse_info; -typedef afs_uint32(*tag_parser) (XFILE *, unsigned char *, tagged_field *, - afs_uint32, tag_parse_info *, void *, - void *); +typedef afs_uint32 (*tag_parser)(XFILE *, unsigned char *, tagged_field *, + afs_uint32, tag_parse_info *, void *, void *); +typedef struct dir_state dir_state; /* Error codes used within dumpscan. * Any of the routines declared below, or callbacks used by them, @@ -77,20 +69,20 @@ typedef afs_uint32(*tag_parser) (XFILE *, unsigned char *, tagged_field *, * functions should extract as much data as possible from the actual file * to fill this in. */ typedef struct { - afs_uint32 version; - afs_uint32 from_date; - afs_uint32 to_date; - afs_uint32 dump_date; - afs_uint32 filenum; - unsigned char *server; - unsigned char *part; - unsigned char *volname; - afs_uint32 volid; - afs_uint32 dumplen; - afs_uint32 level; - afs_uint32 magic; - afs_uint32 cksum; - afs_uint32 flags; + afs_uint32 version; + afs_uint32 from_date; + afs_uint32 to_date; + afs_uint32 dump_date; + afs_uint32 filenum; + unsigned char *server; + unsigned char *part; + unsigned char *volname; + afs_uint32 volid; + u_int64 dumplen; + afs_uint32 level; + afs_uint32 magic; + afs_uint32 cksum; + afs_uint32 flags; } backup_system_header; @@ -100,14 +92,14 @@ typedef struct { #define F_DUMPHDR_FROM 0x00000004 #define F_DUMPHDR_TO 0x00000008 typedef struct { - u_int64 offset; /* Where in the file is it? */ - afs_uint32 field_mask; /* What fields are present? */ - afs_uint32 magic; /* Magic number */ - afs_uint32 version; /* Dump format version */ - afs_uint32 volid; /* VolID of volume in dump */ - unsigned char *volname; /* Name of volume in dump */ - afs_uint32 from_date; /* Reference date */ - afs_uint32 to_date; /* Date of dump */ + u_int64 offset; /* Where in the input stream is it? */ + afs_uint32 field_mask; /* What fields are present? */ + afs_uint32 magic; /* Magic number */ + afs_uint32 version; /* Dump format version */ + afs_uint32 volid; /* VolID of volume in dump */ + unsigned char *volname; /* Name of volume in dump */ + afs_uint32 from_date; /* Reference date */ + afs_uint32 to_date; /* Date of dump */ } afs_dump_header; @@ -138,33 +130,33 @@ typedef struct { #define F_VOLHDR_DAYUSE 0x00800000 #define F_VOLHDR_DAYUSE_DATE 0x01000000 typedef struct { - u_int64 offset; /* Where in the file is it? */ - afs_uint32 field_mask; /* What fields are present? */ - afs_uint32 volid; /* Volume ID */ - afs_uint32 volvers; /* ?? */ - unsigned char *volname; /* Volume Name */ - int flag_inservice; /* Inservice flag (0 or not) */ - int flag_blessed; /* Blessed to come online (0 or not) */ - afs_uint32 voluniq; /* Volume uniquifier */ - int voltype; /* Volume type */ - afs_uint32 parent_volid; /* Parent volume ID */ - afs_uint32 clone_volid; /* Clone volume ID */ - afs_uint32 maxquota; /* Max quota */ - afs_uint32 minquota; /* Min quota (obsolete) */ - afs_uint32 diskused; /* Disk blocks used */ - afs_uint32 nfiles; /* Number of files in volume */ - afs_uint32 account_no; /* Account number (unused) */ - afs_uint32 owner; /* Volume owner */ - afs_uint32 create_date; /* Creation date of this copy */ - afs_uint32 access_date; /* Last access */ - afs_uint32 update_date; /* Last modification */ - afs_uint32 expire_date; /* Expiration (unused) */ - afs_uint32 backup_date; /* Last backup clone */ - unsigned char *offline_msg; /* Offline message */ - unsigned char *motd_msg; /* Volume MOTD */ - afs_uint32 weekuse[7]; /* Weekuse data */ - afs_uint32 dayuse; /* # accesses in last day */ - afs_uint32 dayuse_date; /* Date for which dayuse is valid */ + u_int64 offset; /* Where in the input stream is it? */ + afs_uint32 field_mask; /* What fields are present? */ + afs_uint32 volid; /* Volume ID */ + afs_uint32 volvers; /* ?? */ + unsigned char *volname; /* Volume Name */ + int flag_inservice; /* Inservice flag (0 or not) */ + int flag_blessed; /* Blessed to come online (0 or not) */ + afs_uint32 voluniq; /* Volume uniquifier */ + int voltype; /* Volume type */ + afs_uint32 parent_volid; /* Parent volume ID */ + afs_uint32 clone_volid; /* Clone volume ID */ + afs_uint32 maxquota; /* Max quota */ + afs_uint32 minquota; /* Min quota (obsolete) */ + afs_uint32 diskused; /* Disk blocks used */ + afs_uint32 nfiles; /* Number of files in volume */ + afs_uint32 account_no; /* Account number (unused) */ + afs_uint32 owner; /* Volume owner */ + afs_uint32 create_date; /* Creation date of this copy */ + afs_uint32 access_date; /* Last access */ + afs_uint32 update_date; /* Last modification */ + afs_uint32 expire_date; /* Expiration (unused) */ + afs_uint32 backup_date; /* Last backup clone */ + unsigned char *offline_msg; /* Offline message */ + unsigned char *motd_msg; /* Volume MOTD */ + afs_uint32 weekuse[7]; /* Weekuse data */ + afs_uint32 dayuse; /* # accesses in last day */ + afs_uint32 dayuse_date; /* Date for which dayuse is valid */ } afs_vol_header; @@ -179,146 +171,154 @@ typedef struct { #define F_VNODE_MODE 0x00000080 #define F_VNODE_CDATE 0x00000100 #define F_VNODE_SDATE 0x00000200 -#define F_VNODE_SIZE 0x00000800 -#define F_VNODE_DATA 0x00001000 #define F_VNODE_ACL 0x00000400 +#define F_VNODE_SIZE 0x00000800 /* Set if size is present */ +#define F_VNODE_DATA 0x00001000 /* Set if size nonzero and data present */ +#define F_VNODE_PARTIAL 0x00002000 /* Partial vnode continuation (no header) */ +#define F_VNODE_LINK_TARGET 0x00004000 /* Symlink target present */ typedef struct { - u_int64 offset; /* Where in the file is it? */ - afs_uint32 field_mask; /* What fields are present? */ - afs_uint32 vnode; /* Vnode number */ - afs_uint32 vuniq; /* Uniquifier */ - int type; /* Vnode type */ - afs_uint16 nlinks; /* Number of links (should be in 1 dir!) */ - afs_uint32 parent; /* Parent vnode */ - afs_uint32 datavers; /* Data version */ - afs_uint32 author; /* Last writer */ - afs_uint32 owner; /* Owner UID */ - afs_uint32 group; /* Owning group */ - afs_uint16 mode; /* UNIX mode bits */ - afs_uint32 client_date; /* Last modified date from client */ - afs_uint32 server_date; /* Last modified date on server */ - afs_uint32 size; /* Size of data */ - u_int64 d_offset; /* Where in the file is the data? */ - unsigned char acl[SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE]; + u_int64 offset; /* Where in the input stream is it? */ + afs_uint32 field_mask; /* What fields are present? */ + afs_uint32 vnode; /* Vnode number */ + afs_uint32 vuniq; /* Uniquifier */ + int type; /* Vnode type */ + afs_uint16 nlinks; /* Number of links (should be in 1 dir!) */ + afs_uint32 parent; /* Parent vnode */ + afs_uint32 datavers; /* Data version */ + afs_uint32 author; /* Last writer */ + afs_uint32 owner; /* Owner UID */ + afs_uint32 group; /* Owning group */ + afs_uint16 mode; /* UNIX mode bits */ + afs_uint32 client_date; /* Last modified date from client */ + afs_uint32 server_date; /* Last modified date on server */ + afs_uint32 size; /* Size of data */ + u_int64 d_offset; /* Where in the input stream is the data? */ + char *link_target; /* Target of symbolic link */ + unsigned char acl[SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE]; } afs_vnode; /** AFS directory entry **/ typedef struct { - int slot; /* Directory slot # (info only) */ - char *name; /* Name of entry */ - afs_uint32 vnode; /* Vnode number */ - afs_uint32 uniq; /* Uniquifier */ + int slot; /* Directory slot # (info only) */ + char *name; /* Name of entry */ + afs_uint32 vnode; /* Vnode number */ + afs_uint32 uniq; /* Uniquifier */ } afs_dir_entry; /** Tagged field definitions **/ -#define DKIND_NOOP 0x00 /* No data */ -#define DKIND_BYTE 0x10 /* 1 byte - decimal */ -#define DKIND_HEX8 0x11 /* 1 byte - hex */ -#define DKIND_CHAR 0x12 /* 1 byte - character */ -#define DKIND_FLAG 0x13 /* 1 byte - true/false */ -#define DKIND_INT16 0x20 /* 2 bytes - decimal */ -#define DKIND_HEX16 0x21 /* 2 bytes - hex */ -#define DKIND_INT32 0x30 /* 4 bytes - decimal */ -#define DKIND_HEX32 0x31 /* 4 bytes - hex */ -#define DKIND_TIME 0x32 /* 4 bytes - time */ -#define DKIND_STRING 0x40 /* ASCIIZ string */ -#define DKIND_SPECIAL 0x50 /* Custom parser */ +#define DKIND_NOOP 0x00 /* No data */ +#define DKIND_BYTE 0x10 /* 1 byte - decimal */ +#define DKIND_HEX8 0x11 /* 1 byte - hex */ +#define DKIND_CHAR 0x12 /* 1 byte - character */ +#define DKIND_FLAG 0x13 /* 1 byte - true/false */ +#define DKIND_INT16 0x20 /* 2 bytes - decimal */ +#define DKIND_HEX16 0x21 /* 2 bytes - hex */ +#define DKIND_OCT16 0x28 /* 2 bytes - octal */ +#define DKIND_INT32 0x30 /* 4 bytes - decimal */ +#define DKIND_HEX32 0x31 /* 4 bytes - hex */ +#define DKIND_TIME 0x32 /* 4 bytes - time */ +#define DKIND_OCT32 0x38 /* 4 bytes - octal */ +#define DKIND_STRING 0x40 /* ASCIIZ string */ +#define DKIND_SPECIAL 0x50 /* Custom parser */ #define DKIND_MASK (~0x0f) struct tag_parse_info { - void *err_refcon; - afs_uint32(*cb_error) (afs_uint32, int, void *, char *, ...); - afs_uint32 flags; + void *err_refcon; + afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...); + afs_uint32 flags; #define TPFLAG_SKIP 0x0001 #define TPFLAG_RSKIP 0x0002 - int shift_offset; - u_int64 shift_start; + int shift_offset; + u_int64 shift_start; }; struct tagged_field { - char tag; /* Tag character */ - int kind; /* Kind of object */ - char *label; /* Label to use (for debugging) */ - tag_parser func; /* Parser function (for DKIND_SPECIAL) */ - void *refptr; /* Reference pointer (for parser's use) */ - int refarg; /* Reference argument (for parser's use) */ + char tag; /* Tag character */ + int kind; /* Kind of object */ + char *label; /* Label to use (for debugging) */ + tag_parser func; /* Parser function (for DKIND_SPECIAL) */ + void *refptr; /* Reference pointer (for parser's use) */ + int refarg; /* Reference argument (for parser's use) */ }; /** Control structure for parsing volume dumps **/ typedef struct { - /* Callback functions: - * Whenever a "complex" object is parsed, we call a callback function. - * The callback gets a pointer to the complex object, the file pointer - * for the dump we're parsing, and the value of refcon in this structure. - * Callbacks should return 0 if all is well, non-0 to abort the dump. - * By convention, positive numbers should be errno values, and negative - * numbers can be used for other things. It is OK to _try_ to seek anywhere - * in the file. Beware, though, that the input is not always seekable. - * Also, note that the structures passed to these callbacks are going to - * go away after the callback returns. There is no way to prevent this; - * make a copy if you want one. - */ - void *refcon; - afs_uint32(*cb_bckhdr) (backup_system_header *, XFILE *, void *); /* Backup */ - afs_uint32(*cb_dumphdr) (afs_dump_header *, XFILE *, void *); /* Dump hdr */ - afs_uint32(*cb_volhdr) (afs_vol_header *, XFILE *, void *); /* Volume hdr */ - afs_uint32(*cb_vnode_dir) (afs_vnode *, XFILE *, void *); /* Directory */ - afs_uint32(*cb_vnode_file) (afs_vnode *, XFILE *, void *); /* File */ - afs_uint32(*cb_vnode_link) (afs_vnode *, XFILE *, void *); /* Symlink */ - afs_uint32(*cb_vnode_empty) (afs_vnode *, XFILE *, void *); /* vnode+uniq */ - afs_uint32(*cb_vnode_wierd) (afs_vnode *, XFILE *, void *); /* Unknown type */ + /* Callback functions: + * Whenever a "complex" object is parsed, we call a callback function. + * The callback gets a pointer to the complex object, the file pointer + * for the dump we're parsing, and the value of refcon in this structure. + * Callbacks should return 0 if all is well, non-0 to abort the dump. + * By convention, positive numbers should be errno values, and negative + * numbers can be used for other things. It is OK to _try_ to seek anywhere + * in the file. Beware, though, that the input is not always seekable. + * Also, note that the structures passed to these callbacks are going to + * go away after the callback returns. There is no way to prevent this; + * make a copy if you want one. + */ + void *refcon; + afs_uint32 (*cb_bckhdr)(backup_system_header *, XFILE *, void *); /* Backup Header */ + afs_uint32 (*cb_dumphdr)(afs_dump_header *, XFILE *, void *); /* Dump Header */ + afs_uint32 (*cb_volhdr)(afs_vol_header *, XFILE *, void *); /* Volume Header */ + afs_uint32 (*cb_vnode_dir)(afs_vnode *, XFILE *, void *); /* Directory Vnode */ + afs_uint32 (*cb_vnode_file)(afs_vnode *, XFILE *, void *); /* File Vnode */ + afs_uint32 (*cb_vnode_link)(afs_vnode *, XFILE *, void *); /* Symlink Vnode */ + afs_uint32 (*cb_vnode_empty)(afs_vnode *, XFILE *, void *); /* vnode+uniq only */ + afs_uint32 (*cb_vnode_wierd)(afs_vnode *, XFILE *, void *); /* Unknown type */ + afs_uint32 (*cb_file_data)(afs_vnode *, XFILE *, void *); /* File Data */ + afs_uint32 (*cb_dir_data)(afs_vnode *, XFILE *, void *); /* Directory Data */ + afs_uint32 (*cb_link_data)(afs_vnode *, XFILE *, void *); /* Symlink Data */ - /* This function is called when there is an error in the dump. */ - /* (cb_error)(errno, fatal, refcon, msg_fmt, msg_args...) */ - void *err_refcon; /* If set, use instead of refcon for dir entries */ - afs_uint32(*cb_error) (afs_uint32, int, void *, char *, ...); + /* This function is called when there is an error in the dump. */ + /* (cb_error)(errno, fatal, refcon, msg_fmt, msg_args...) */ + void *err_refcon; /* If set, use instead of refcon for dir entries */ + afs_uint32 (*cb_error)(afs_uint32, int, void *, char *, ...); - /* This function is called for each directory entry, if set */ - afs_uint32(*cb_dirent) (afs_vnode *, afs_dir_entry *, XFILE *, void *); + /* This function is called for each directory entry, if set */ + afs_uint32 (*cb_dirent)(afs_vnode *, afs_dir_entry *, XFILE *, void *); - int flags; /* Flags and options */ -#define DSFLAG_SEEK 0x0001 /* Input file is seekable */ + int flags; /* Flags and options */ +#define DSFLAG_SEEK 0x0001 /* Input file is seekable */ - int print_flags; /* Flags to control what is printed */ -#define DSPRINT_BCKHDR 0x0001 /* Print backup system header */ -#define DSPRINT_DUMPHDR 0x0002 /* Print AFS dump header */ -#define DSPRINT_VOLHDR 0x0004 /* Print AFS volume header */ -#define DSPRINT_ITEM 0x0010 /* Print top-level tags */ -#define DSPRINT_VNODE 0x0020 /* Print vnode attributes */ -#define DSPRINT_ACL 0x0040 /* Print directory ACL's */ -#define DSPRINT_DIR 0x0080 /* Print directory contents */ -#define DSPRINT_DEBUG 0x0100 /* Print debugging info */ -#define DSPRINT_PATH 0x0200 /* Print vnode paths */ + int print_flags; /* Flags to control what is printed */ +#define DSPRINT_BCKHDR 0x0001 /* Print backup system header */ +#define DSPRINT_DUMPHDR 0x0002 /* Print AFS dump header */ +#define DSPRINT_VOLHDR 0x0004 /* Print AFS volume header */ +#define DSPRINT_ITEM 0x0010 /* Print top-level tags */ +#define DSPRINT_VNODE 0x0020 /* Print vnode attributes */ +#define DSPRINT_ACL 0x0040 /* Print directory ACL's */ +#define DSPRINT_DIR 0x0080 /* Print directory contents */ +#define DSPRINT_DEBUG 0x0100 /* Print debugging info */ +#define DSPRINT_PATH 0x0200 /* Print vnode paths */ - int repair_flags; /* Flags to control what is repaired. - * Most of these _require_ DSFLAG_SEEK */ -#define DSFIX_SKIP 0x0001 /* Try to skip null tags */ -#define DSFIX_RSKIP 0x0002 /* Seek back to fing skipped tags */ -#define DSFIX_VDSYNC 0x0004 /* Resync location after vnode data */ -#define DSFIX_VFSYNC 0x0008 /* Try to resync after bad vnode */ + int repair_flags; /* Flags to control what is repaired. + * Most of these _require_ DSFLAG_SEEK */ +#define DSFIX_SKIP 0x0001 /* Try to skip null tags */ +#define DSFIX_RSKIP 0x0002 /* Seek back to fing skipped tags */ +#define DSFIX_VDSYNC 0x0004 /* Resync location after vnode data */ +#define DSFIX_VFSYNC 0x0008 /* Try to resync after bad vnode */ /** Things below this point for internal use only **/ - afs_uint32 vol_uniquifier; + afs_uint32 vol_uniquifier; } dump_parser; /** Hash table and control info for pathname manipulation **/ typedef struct vhash_ent { - struct vhash_ent *next; /* Pointer to next entry */ - afs_uint32 vnode; /* VNode number */ - afs_uint32 parent; /* Parent VNode number */ - u_int64 v_offset; /* Offset to start of vnode */ - u_int64 d_offset; /* Offset to data (0 if none) */ - afs_uint32 d_size; /* Size of data */ + struct vhash_ent *next; /* Pointer to next entry */ + afs_uint32 vnode; /* VNode number */ + afs_uint32 parent; /* Parent VNode number */ + u_int64 v_offset; /* Offset to start of vnode */ + u_int64 d_offset; /* Offset to data (0 if none) */ + afs_uint32 d_size; /* Size of data */ } vhash_ent; typedef struct { - afs_uint32 n_vnodes; /* Number of vnodes in volume */ - afs_uint32 n_dirs; /* Number of file vnodes */ - afs_uint32 n_files; /* Number of directory vnodes */ - int hash_size; /* Hash table size (bits) */ - vhash_ent **hash_table; /* Hash table */ - dump_parser *p; /* Dump parser to use */ + afs_uint32 n_vnodes; /* Number of vnodes in volume */ + afs_uint32 n_dirs; /* Number of file vnodes */ + afs_uint32 n_files; /* Number of directory vnodes */ + int hash_size; /* Hash table size (bits) */ + vhash_ent **hash_table; /* Hash table */ + dump_parser *p; /* Dump parser to use */ } path_hashinfo; @@ -338,17 +338,17 @@ extern afs_uint32 WriteString(XFILE *, unsigned char *); extern afs_uint32 WriteTagByte(XFILE *, unsigned char, unsigned char); extern afs_uint32 WriteTagInt16(XFILE *, unsigned char, afs_uint16); extern afs_uint32 WriteTagInt32(XFILE *, unsigned char, afs_uint32); -extern afs_uint32 WriteTagInt32Pair(XFILE *, unsigned char, afs_uint32, - afs_uint32); +extern afs_uint32 WriteTagInt32Pair(XFILE *, unsigned char, afs_uint32, afs_uint32); +extern afs_uint32 WriteTagString(XFILE *, unsigned char, unsigned char *); /* parsetag.c - Parse tagged data */ extern afs_uint32 ParseTaggedData(XFILE *, tagged_field *, unsigned char *, - tag_parse_info *, void *, void *); + tag_parse_info *, void *, void *); /* stagehdr.c - Parse and dump Stage dump headers */ -extern afs_uint32 ParseStageHdr(XFILE *, unsigned char *, - backup_system_header *); -extern afs_uint32 DumpStagehdr(XFILE *, backup_system_header *); +extern afs_uint32 ParseStageHdr(XFILE *, unsigned char *, backup_system_header *); +extern afs_uint32 ParseStageV20Hdr(XFILE *, unsigned char *, backup_system_header *); +extern afs_uint32 DumpStageV20Hdr(XFILE *, backup_system_header *); /* backuphdr.c - Parse and print backup system headers */ extern void PrintBackupHdr(backup_system_header *); @@ -360,10 +360,16 @@ extern afs_uint32 ParseVolumeHeader(XFILE *, dump_parser *); extern afs_uint32 ParseVNode(XFILE *, dump_parser *); -/* directory.c - Directory parsing and lookup */ +/* directory.c - Directory parsing, lookup, and generation */ extern afs_uint32 ParseDirectory(XFILE *, dump_parser *, afs_uint32, int); -extern afs_uint32 DirectoryLookup(XFILE *, dump_parser *, afs_uint32, char **, - afs_uint32 *, afs_uint32 *); +extern afs_uint32 DirectoryLookup(XFILE *, dump_parser *, afs_uint32, + char **, afs_uint32 *, afs_uint32 *); +extern afs_uint32 Dir_Init(dir_state **); +extern afs_uint32 Dir_AddEntry(dir_state *, char *, afs_uint32, afs_uint32); +extern afs_uint32 Dir_Finalize(dir_state *); +extern afs_uint32 Dir_EmitData(dir_state *, XFILE *, int); +extern afs_uint32 Dir_Free(dir_state *ds); + /* dump.c - Dump parts of a volume dump */ extern afs_uint32 DumpDumpHeader(XFILE *, afs_dump_header *); @@ -371,12 +377,13 @@ extern afs_uint32 DumpVolumeHeader(XFILE *, afs_vol_header *); extern afs_uint32 DumpVNode(XFILE *, afs_vnode *); extern afs_uint32 DumpVnodeData(XFILE *, char *, afs_uint32); extern afs_uint32 CopyVnodeData(XFILE *, XFILE *, afs_uint32); +extern afs_uint32 DumpVNodeData(XFILE *OX, char *buf, afs_uint32 size); +extern afs_uint32 DumpDumpEnd(XFILE *OX); /* pathname.c - Follow and construct pathnames */ extern afs_uint32 Path_PreScan(XFILE *, path_hashinfo *, int); extern void Path_FreeHashTable(path_hashinfo *); extern afs_uint32 Path_Follow(XFILE *, path_hashinfo *, char *, vhash_ent *); -extern afs_uint32 Path_Build(XFILE *, path_hashinfo *, afs_uint32, char **, - int); +extern afs_uint32 Path_Build(XFILE *, path_hashinfo *, afs_uint32, char **, int); #endif