test-suite-pull-tools-directly-in-20020114
[openafs.git] / src / tests / directory.c
1 /*
2  * CMUCS AFStools
3  * dumpscan - routines for scanning and manipulating AFS volume dumps
4  *
5  * Copyright (c) 1998 Carnegie Mellon University
6  * All Rights Reserved.
7  * 
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software_Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie Mellon
26  * the rights to redistribute these changes.
27  */
28
29 /* directory.c - Parse an AFS directory */
30 /* See the end of this file for a description of the directory format */
31
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <netinet/in.h>
35
36 #include "dumpscan.h"
37 #include "dumpscan_errs.h"
38 #include "xf_errs.h"
39 #include "dumpfmt.h"
40 #include "internal.h"
41
42 #include <afs/dir.h>
43
44 static afs_dir_page page;
45
46 #define allocbit(x) (page.header.freebitmap[(x)>>3] & (1 << ((x) & 7)))
47 #define DPHE (DHE + 1)
48
49 static void fixup(char *name, int l)
50 {
51   name += 16;
52   l -= 15;
53
54   while (l-- > 0) {
55     name[0] = name[4];
56     name++;
57   }
58 }
59
60 afs_uint32 parse_directory(XFILE *X, dump_parser *p, afs_vnode *v,
61                         afs_uint32 size, int toeof)
62 {
63   afs_dir_entry de;
64   int pgno, i, j, l, n;
65   afs_uint32 r;
66   u_int64 where;
67
68   if (p->print_flags & DSPRINT_DIR) {
69     printf("  VNode      Uniqifier   Name\n");
70     printf("  ========== ==========  ==============================\n");
71   }
72   if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
73   for (pgno = 0; toeof || size; pgno++, size -= (toeof ? 0 : AFS_PAGESIZE)) {
74     if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
75     if (r = xfread(X, &page, AFS_PAGESIZE)) {
76       if (toeof && r == ERROR_XFILE_EOF) break;
77       return r;
78     }
79     if ((p->flags & DSFLAG_SEEK) && (r = xftell(X, &where))) return r;
80     if (page.header.tag != htons(1234)) {
81       if (p->cb_error)
82         (p->cb_error)(DSERR_MAGIC, 1, p->err_refcon,
83                       "Invalid page tag (%d) in page %d",
84                       ntohs(page.header.tag), pgno);
85       return DSERR_MAGIC;
86     }
87     for (i = (pgno ? 1 : DPHE); i < EPP; i++) {
88       if (!allocbit(i)) continue;
89       if (page.entry[i].flag != FFIRST) {
90         if (p->cb_error)
91           (p->cb_error)(DSERR_MAGIC, 0, p->err_refcon,
92                         "Invalid entry flag %d in entry %d/%d; skipping...",
93                         page.entry[i].flag, pgno, i);
94         continue;
95       }
96       n = (EPP - i - 1) * 32 + 16;
97       for (l = 0; n && page.entry[i].name[l]; l++, n--);
98       if (page.entry[i].name[l]) {
99         if (p->cb_error)
100           (p->cb_error)(DSERR_FMT, 0, p->err_refcon,
101                         "Filename too long in entry %d/%d; skipping page",
102                         pgno, i);
103         break;
104       }
105 /*    fixup(page.entry[i].name, l); */
106       if (pgno) de.slot = i - 1 + (pgno - 1) * (EPP - 1) + (EPP - DPHE);
107       else de.slot = i - DPHE;
108       de.name  = page.entry[i].name;
109       de.vnode = ntohl(page.entry[i].vnode);
110       de.uniq  = ntohl(page.entry[i].vunique);
111       if (p->print_flags & DSPRINT_DIR)
112         printf("  %10d %10d  %s\n", de.vnode, de.uniq, de.name);
113       if (p->cb_dirent) {
114         r = (p->cb_dirent)(v, &de, X, p->refcon);
115       }
116       if (p->cb_dirent && (r = (p->cb_dirent)(v, &de, X, p->refcon)))
117         return r;
118       i += ((l + 16) >> 5);
119     }
120   }
121   if ((p->flags & DSFLAG_SEEK) && (r = xfseek(X, &where))) return r;
122   return 0;
123 }
124
125
126 afs_uint32 ParseDirectory(XFILE *X, dump_parser *p, afs_uint32 size, int toeof)
127 {
128   afs_uint32 r;
129
130   r = parse_directory(X, p, 0, size, toeof);
131 }
132
133
134 typedef struct {
135   char **name;
136   afs_uint32 *vnode;
137   afs_uint32 *vuniq;
138 } dirlookup_stat;
139
140
141 static afs_uint32 dirlookup_cb(afs_vnode *v, afs_dir_entry *de,
142                             XFILE *X, void *refcon)
143 {
144   dirlookup_stat *s = (dirlookup_stat *)refcon;
145
146   if (s->name && s->name[0]) {                  /* Search by filename */
147     if (strcmp(de->name, s->name[0])) return 0; /* Not it! */
148     if (s->vnode) s->vnode[0] = de->vnode;
149     if (s->vuniq) s->vuniq[0] = de->uniq;
150   } else if (s->vnode) {                        /* Search by vnode */
151     if (de->vnode != s->vnode[0]) return 0;     /* Not it! */
152     if (s->name) {
153       s->name[0] = (char *)malloc(strlen(de->name) + 1);
154       if (!s->name[0]) return ENOMEM;
155       strcpy(s->name[0], de->name);
156     }
157     if (s->vuniq) s->vuniq[0] = de->uniq;
158   }
159   return DSERR_DONE;
160 }
161
162
163 /* Look up an entry in a directory, by name or vnode.
164  * If *name is NULL, we are looking up by vnode.
165  * Otherwise, we are looking for a filename.
166  * In any event, any of name, vnode, vuniq that are
167  * neither NULL nor the search key are filled in on
168  * success.
169  *
170  * Call this with X pointing to the start of the directory,
171  * and size set to the length of the directory.
172  * Returns 0 on success, whether or not the entry is found.
173  */
174 afs_uint32 DirectoryLookup(XFILE *X, dump_parser *p, afs_uint32 size,
175                     char **name, afs_uint32 *vnode, afs_uint32 *vuniq)
176 {
177   dump_parser my_p;
178   dirlookup_stat my_s;
179   afs_uint32 r;
180
181   memset(&my_s, 0, sizeof(my_s));
182   my_s.name  = name;
183   my_s.vnode = vnode;
184   my_s.vuniq = vuniq;
185
186   memset(&my_p, 0, sizeof(my_p));
187   my_p.refcon = (void *)&my_s;
188   my_p.err_refcon = p->err_refcon;
189   my_p.cb_error = p->cb_error;
190   my_p.cb_dirent  = dirlookup_cb;
191
192   r = parse_directory(X, &my_p, 0, size, 0);
193   if (!r) r = DSERR_DONE;
194   return handle_return(r, X, 0, p);
195 }
196
197
198 /* AFS directory format:
199  * AFS directories are stored in volume dumps in exactly the same format
200  * that is used on disk, which makes them relatively easy to dump and restore,
201  * but means we have to do some work to interpret them.
202  *
203  * The ACL for a directory is stored on disk in the last part of a "large"
204  * (directory) vnode.  This part of the vnode, which has fixed size
205  * SIZEOF_LARGEDISKVNODE - SIZEOF_SMALLDISKVNODE, is copied directly into
206  * the dump file with a tag of 'A' (VTAG_ACL).  The structure of this
207  * section is described in <afs/acl.h>.
208  *
209  * The name-to-vnode mappings are also stored exactly as they appear on
210  * disk, using the file data ('f') attribute.  As usual, this attribute
211  * consists of a 32-bit number containing the size, immediately followed
212  * by the data itself.  The interesting structures and constants are
213  * defined in <afs/dir.h>
214  * 
215  * A directory consists of one or more 'pages', each of which is 2K
216  * (AFS_PAGESIZE).  Each page contains EPP (currently 64) 'entries', each
217  * of which is 32 bytes.  The first page begins with a DirHeader, which
218  * is DHE entries long, and includes a PageHeader.  All other pages begin
219  * with just a PageHeader, which is 1 entry long.  Every other entry is
220  * a DirEntry, a DirXEntry (name extension), or unused.
221  *
222  * A Page Header contains the following elements:
223  * - pgcount    contains a count of the number of pages in the directory,
224  *              if the directory is new-style (>128 pages), or 0 if it is
225  *              old-style.  This field is meaningful only in the Dir Header.
226  * - tag        a magic number, which must be 1234
227  * - freecount  apparently unused
228  * - freebitmap A bitmap of free entries.  Each byte corresponds to 8
229  *              entries, with the least significant bit referring to the
230  *              first of those.  Each bit is set iff the corresponding
231  *              entry is allocated.  Entries used by the page and dir
232  *              headers are considered allocated.
233  *
234  * A Dir Header consists of a Page Header, followed by an allocation map
235  * and hash table.  The allocation map contains one byte for each of the
236  * first 128 pages; that byte contains the number of entries in that page
237  * that are allocated.  Every page that actually exists has at peast one
238  * entry allocated (the Page Header); if a byte in this map is 0, it means
239  * that the page does not yet exist.
240  *
241  * Each bucket in the hash table is a linked list, using 'blob numbers'
242  * as pointers.  A blob number is defined as (page# * EPP) + entry#.
243  * The head of each chain is kept in the hash table, and the next pointers
244  * are kept in the 'next' entry of each directory.
245  *
246  * Directory entries themselves contain the following elements:
247  * - flag    Set to FFIRST iff this is the first blob in an entry
248  *           (otherwise it will be a name continuation).  This is
249  *           probably not reliable.
250  * - length  Unused
251  * - next    Pointer to the next element in this hash chain
252  * - fid     FileID (vnode and uniquifier)
253  * - name    Filename (null-terminated)
254  */