3 * dumpscan - routines for scanning and manipulating AFS volume dumps
5 * Copyright (c) 1998 Carnegie Mellon University
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.
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.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software_Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie Mellon
26 * the rights to redistribute these changes.
29 /* pathname.c - Pathname lookup and traversal */
35 #include "dumpscan_errs.h"
37 /* Hash function for a vnode */
38 #define BUCKET_SIZE 32
39 #define vnode_hash(phi,vnode) ((vnode) & ((1 << (phi)->hash_size) - 1))
43 get_vhash_ent(path_hashinfo
* phi
, afs_uint32 vnode
, int make
)
45 int key
= vnode_hash(phi
, vnode
);
48 for (vhe
= phi
->hash_table
[key
]; vhe
&& vhe
->vnode
!= vnode
;
51 vhe
= calloc(1, sizeof(vhash_ent
));
54 vhe
->next
= phi
->hash_table
[key
];
55 phi
->hash_table
[key
] = vhe
;
63 volhdr_cb(afs_vol_header
* hdr
, XFILE
* X
, void *refcon
)
65 path_hashinfo
*phi
= (path_hashinfo
*) refcon
;
68 if (hdr
->field_mask
& F_VOLHDR_NFILES
) {
69 nfiles
= phi
->n_vnodes
= hdr
->nfiles
;
70 for (phi
->hash_size
= 1; nfiles
> BUCKET_SIZE
;
71 phi
->hash_size
++, nfiles
>>= 1);
72 hsize
= (1 << phi
->hash_size
);
73 phi
->hash_table
= calloc(hsize
,sizeof(vhash_ent
*));
79 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
80 "File count missing from volume header");
87 vnode_keep(afs_vnode
* v
, XFILE
* X
, void *refcon
)
89 path_hashinfo
*phi
= (path_hashinfo
*) refcon
;
92 if (!phi
->hash_table
) {
94 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->refcon
,
95 "No volume header in dump???");
98 vhe
= get_vhash_ent(phi
, v
->vnode
, 1);
101 cp64(vhe
->v_offset
, v
->offset
);
102 if (v
->field_mask
& F_VNODE_PARENT
)
103 vhe
->parent
= v
->parent
;
104 if (v
->field_mask
& F_VNODE_DATA
) {
105 cp64(vhe
->d_offset
, v
->d_offset
);
106 vhe
->d_size
= v
->size
;
108 if ((v
->field_mask
& F_VNODE_TYPE
) && v
->type
== vDirectory
)
117 vnode_stop(afs_vnode
* v
, XFILE
* X
, void *refcon
)
119 path_hashinfo
*phi
= (path_hashinfo
*) refcon
;
122 /* If the file is seekable, try to position so we can pick up later... */
123 if (phi
->p
->flags
& DSFLAG_SEEK
)
124 if ((r
= xfseek(X
, &v
->offset
)))
131 dirent_cb(afs_vnode
* v
, afs_dir_entry
* de
, XFILE
* X
, void *refcon
)
133 path_hashinfo
*phi
= (path_hashinfo
*) refcon
;
136 if (!phi
->hash_table
) {
137 if (phi
->p
->cb_error
)
138 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->refcon
,
139 "No volume header in dump???");
142 if (!strcmp(de
->name
, ".") || !strcmp(de
->name
, ".."))
144 vhe
= get_vhash_ent(phi
, de
->vnode
, 1);
147 vhe
->parent
= v
->vnode
;
152 /* Prescan the vnodes in a dump file, collecting information that will
153 * be useful in generating and following pathnames.
156 Path_PreScan(XFILE
* X
, path_hashinfo
* phi
, int full
)
158 dump_parser my_p
, *p
= phi
->p
;
160 memset(phi
, 0, sizeof(path_hashinfo
));
162 memset(&my_p
, 0, sizeof(my_p
));
163 my_p
.refcon
= (void *)phi
;
164 my_p
.cb_volhdr
= volhdr_cb
;
165 my_p
.cb_vnode_dir
= vnode_keep
;
167 my_p
.cb_vnode_file
= vnode_keep
;
168 my_p
.cb_vnode_link
= vnode_keep
;
169 my_p
.cb_vnode_empty
= vnode_keep
;
170 my_p
.cb_vnode_wierd
= vnode_keep
;
172 my_p
.cb_vnode_file
= vnode_stop
;
173 my_p
.cb_vnode_link
= vnode_stop
;
174 my_p
.cb_vnode_empty
= vnode_stop
;
175 my_p
.cb_vnode_wierd
= vnode_stop
;
177 my_p
.err_refcon
= p
->err_refcon
;
178 my_p
.cb_error
= p
->cb_error
;
179 my_p
.cb_dirent
= dirent_cb
;
180 my_p
.flags
= p
->flags
;
181 my_p
.print_flags
= p
->print_flags
;
182 my_p
.repair_flags
= p
->repair_flags
;
184 return ParseDumpFile(X
, &my_p
);
188 /* Free the hash table in a path_hashinfo */
190 Path_FreeHashTable(path_hashinfo
* phi
)
193 vhash_ent
*vhe
, *next_vhe
;
195 if (phi
->hash_table
) {
196 size
= (1 << phi
->hash_size
);
197 for (i
= 0; i
< size
; i
++)
198 for (vhe
= phi
->hash_table
[i
]; vhe
; vhe
= next_vhe
) {
199 next_vhe
= vhe
->next
;
202 free(phi
->hash_table
);
207 /* Follow a pathname to the vnode it represents */
209 Path_Follow(XFILE
* X
, path_hashinfo
* phi
, char *path
, vhash_ent
* his_vhe
)
213 afs_uint32 r
, vnum
= 1;
217 name
= strtok(path
, "/");
219 for (name
= strtok(path
, "/"); name
; name
= strtok(0, "/")) {
221 if (phi
->p
->cb_error
)
222 (phi
->p
->cb_error
) (ENOTDIR
, 1, phi
->p
->err_refcon
,
223 "Not a directory vnode");
226 vhe
= get_vhash_ent(phi
, vnum
, 0);
228 if (phi
->p
->cb_error
)
229 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
230 "Vnode %d not found in hash table", vnum
);
233 if (zero64(vhe
->d_offset
)) {
234 if (phi
->p
->cb_error
)
235 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
236 "Directory vnode %d is incomplete", vnum
);
239 if ((r
= xfseek(X
, &vhe
->d_offset
))) {
240 if (phi
->p
->cb_error
)
241 (phi
->p
->cb_error
) (r
, 1, phi
->p
->err_refcon
,
242 "Unable to seek to directory %d", vnum
);
246 r
= DirectoryLookup(X
, phi
->p
, vhe
->d_size
, &name
, &vnum
, 0);
250 if (phi
->p
->cb_error
)
251 (phi
->p
->cb_error
) (ENOENT
, 1, phi
->p
->err_refcon
,
256 vhe
= get_vhash_ent(phi
, vnum
, 0);
258 if (phi
->p
->cb_error
)
259 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
260 "Vnode %d not found in hash table", vnum
);
270 Path_Build(XFILE
* X
, path_hashinfo
* phi
, afs_uint32 vnode
, char **his_path
,
274 char *name
, *path
= 0, fastbuf
[12];
276 afs_uint32 parent
, r
;
280 *his_path
= strdup("/");
282 if (phi
->p
->cb_error
)
283 (phi
->p
->cb_error
) (ENOMEM
, 1, phi
->p
->err_refcon
,
284 "No memory for pathname of vnode 1");
291 vhe
= get_vhash_ent(phi
, vnode
, 0);
293 if (phi
->p
->cb_error
)
294 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
295 "Vnode %d not found in hash table", vnode
);
299 /* Find the parent */
301 if (phi
->p
->cb_error
)
302 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
303 "Vnode %d has no parent?", vnode
);
308 parent
= vhe
->parent
;
309 vhe
= get_vhash_ent(phi
, parent
, 0);
310 if (phi
->p
->print_flags
& DSPRINT_DEBUG
)
311 fprintf(stderr
, "Searching for vnode %d in parent %d\n", vnode
,
314 if (phi
->p
->cb_error
)
315 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
316 "Vnode %d not found in hash table",
324 /* Make up a path component from the vnode number */
325 sprintf(fastbuf
, "%d", vnode
);
328 /* Do a reverse-lookup in the parent directory */
329 if (zero64(vhe
->d_offset
)) {
330 if (phi
->p
->cb_error
)
331 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
332 "Directory vnode %d is incomplete",
338 if ((r
= xfseek(X
, &vhe
->d_offset
))) {
339 if (phi
->p
->cb_error
)
340 (phi
->p
->cb_error
) (errno
, 1, phi
->p
->err_refcon
,
341 "Unable to seek to directory %d",
349 r
= DirectoryLookup(X
, phi
->p
, vhe
->d_size
, &name
, &vnode
, 0);
353 if (phi
->p
->cb_error
)
354 (phi
->p
->cb_error
) (DSERR_FMT
, 1, phi
->p
->err_refcon
,
355 "No entry for vnode %d in directory %d",
365 path
= realloc(path
, nl
+ pl
+ 2);
367 if (phi
->p
->cb_error
)
368 (phi
->p
->cb_error
) (ENOMEM
, 1, phi
->p
->err_refcon
,
369 "No memory for pathname of vnode 1");
377 for (x
= name
, y
= path
+ 1; *x
;)
381 path
= (char *)malloc(nl
+ 2);
383 if (phi
->p
->cb_error
)
384 (phi
->p
->cb_error
) (ENOMEM
, 1, phi
->p
->err_refcon
,
385 "No memory for pathname of vnode 1");
389 strcpy(path
+ 1, name
);