convert-from-bsd-to-posix-string-and-memory-functions-20010807
[openafs.git] / src / vol / test / listVicepx.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11 **      Lists all files in a /vicepX partition. This started as an
12 **      exercise to know the layout of AFS data in a fileserver
13 **      partition. Later on, it proved useful in debugging problems 
14 **      at customer sites too. 
15 **
16 */
17 #include <afsconfig.h>
18 #include <afs/param.h>
19
20 RCSID("$Header$");
21
22 #include <rx/xdr.h>
23 #include <afs/afsint.h>
24 #include <ctype.h>
25 #include <sys/param.h>
26 #if !defined(AFS_SGI_ENV)
27 #ifdef  AFS_OSF_ENV
28 #include <ufs/fs.h>
29 #else   /* AFS_OSF_ENV */
30 #ifdef AFS_VFSINCL_ENV
31 #define VFS
32 #ifdef  AFS_SUN5_ENV
33 #include <sys/fs/ufs_fs.h>
34 #else
35 #include <ufs/fs.h>
36 #endif
37 #else /* AFS_VFSINCL_ENV */
38 #ifndef AFS_AIX_ENV
39 #include <sys/fs.h>
40 #endif
41 #endif AFS_VFSINCL_ENV
42 #endif  /* AFS_OSF_ENV */
43 #endif /* AFS_SGI_ENV */
44 #include <sys/errno.h>
45 #include <sys/stat.h>
46 #include <stdio.h>
47 #include <sys/file.h>
48 #if defined(AFS_SGI_ENV) || (defined(AFS_SUN_ENV) && !defined(AFS_BSD_ENV))
49 #include <dirent.h>
50 #else
51 #include <sys/dir.h>
52 #endif
53 #ifdef  AFS_AIX_ENV
54 #include <sys/vfs.h>
55 #include <fcntl.h>
56 #else
57 #ifdef  AFS_HPUX_ENV
58 #include <fcntl.h>
59 #include <mntent.h>
60 #else
61 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
62 #ifdef  AFS_SUN5_ENV
63 #include <sys/mnttab.h>
64 #include <sys/mntent.h>
65 #else
66 #include <mntent.h>
67 #endif
68 #else
69 #if defined(AFS_SGI_ENV)
70 #include <fcntl.h>
71 #include <mntent.h>
72
73 /*
74 #include <sys/fs/efs.h>
75 */
76 #include "efs.h" /* until 5.1 release */
77
78 #define ROOTINO EFS_ROOTINO
79 #else
80 #include <fstab.h>
81 #endif
82 #endif /* AFS_SGI_ENV */
83 #endif /* AFS_HPUX_ENV */
84 #endif
85 #include <netdb.h>
86 #include <netinet/in.h>
87 #include <sys/wait.h>
88 #include <setjmp.h>
89 #ifndef ITIMER_REAL
90 #include <sys/time.h>
91 #endif /* ITIMER_REAL */
92
93 #include "nfs.h"
94 #include <afs/errors.h>
95 #include "lock.h"
96 #include "lwp.h"
97 #include "vnode.h"
98 #include "volume.h"
99 #include "vldb.h"
100 #include "partition.h"
101 #include "afs/assert.h"
102 #include "filesignal.h"
103 #include "vutils.h"
104 #include "fssync.h"
105 #include <afs/auxinode.h>
106 #include <afs/dir.h>
107 #include <unistd.h>
108
109 #ifdef  AFS_OSF_ENV
110 extern void *calloc(), *realloc();
111 #endif
112 #include "salvage.h"
113 int volumeId;
114 int VolumeChanged;   /* to satisfy library libdir use */
115
116 #include "listVicepx.h"
117 char*   orphan_NoVnode = "ORPHANED_NoVnode";
118 char*   orphan_NoUnique = "ORPHANED_NoUnique";
119
120 #define allNull         0x00
121 #define allFiles        0x01  /* equivalent to /bin/ls */
122 #define lFlag           0x02  /* equivalent to /bin/ls -l */
123 #define allDirs         0x04  /* equivalent to /bin/ls -ld */
124 #define contentsDInode  0x08  /* list contents of dir inode */
125 #define volInfo         0x10  /* list info from vol header */
126
127 extern DirEnt *lookup();
128 extern char     *getFileName(), *getDirName(), *printStack();
129 extern DirEnt*               hash[];
130
131 int 
132 Usage( name)
133 char*   name;
134 {
135         assert(name);
136         printf("Usage is %s -p <partition name> -v <volume name> [-ls | -lsl | -ld] [-volInfo] [-dir <directory inode>] \n", name);
137         printf("-ls  : lists all files\n");
138         printf("-lsl : lists all files along with its properties\n");
139         printf("-ld :  lists all directories\n");
140         printf("-volInfo : lists volume header \n");
141         printf("-dir <inode number>: prints contents of directory inode\n");
142         exit(1);
143 }
144         
145
146 main(argc, argv)
147 int argc;
148 char*   argv[];
149 {
150         char            fullName[32+VNAMESIZE+sizeof(VHDREXT)+4];
151         char            partition[32], volume[VNAMESIZE];
152         struct stat     statBuf;
153         struct VolumeHeader     volumeHeader;
154         int fd,i, sawPart=0, sawVolume=0, sawDirContents=0;
155         char option = allNull;                  /* no default options */
156         Inode  dirInode;                /* list contents of this dir Inode */
157
158         for (i = 1; i < argc; i++)
159         {
160             if (!strcmp(argv[i], "-p")) 
161             {
162                 if ( (i+1) >= argc )
163                    Usage(argv[0]);
164                 assert(strlen(argv[i+1]) < 32 );
165                 strcpy( partition, argv[++i]);
166                 sawPart = 1;
167             } 
168             else if ( !strcmp(argv[i], "-v"))
169             {
170                 if ( (i+1) >= argc )
171                         Usage(argv[0]);
172                 assert(strlen(argv[i+1]) < VNAMESIZE );
173                 strcpy( volume, argv[++i]);
174                 sawVolume = 1;
175             } 
176             else if ( !strcmp(argv[i], "-dir"))
177             {
178                 if ( (i+1) >= argc )
179                         Usage(argv[0]);
180                 dirInode = atoi(argv[++i]);
181                 option |= contentsDInode;
182                 sawDirContents = 1;
183             }
184             else if ( !strcmp(argv[i], "-ls"))
185                 option |= allFiles;
186             else if ( !strcmp(argv[i], "-lsl"))
187                  option |= ( allFiles | lFlag );
188             else if ( !strcmp(argv[i], "-ld"))
189                  option |=  allDirs;
190             else if ( !strcmp(argv[i], "-volInfo"))
191                  option |=  volInfo;
192             else
193                 Usage(argv[0]);
194         }
195         /* check input parameters */
196         if ( !sawPart || !sawVolume)
197                 Usage(argv[0]);
198
199         /* extract volume id */
200         volumeId = atoi(volume);
201
202         /* construct  unix file name */
203         strcpy(fullName, partition);
204         strcat(fullName,"/V");
205         strcat(fullName,volume);
206         strcat(fullName, VHDREXT);
207
208         /* check to see that volume exists */
209         if ( stat(fullName, &statBuf) < 0 )     
210         {
211                 printf("Error in stat(%s) : %d\n", fullName, errno);
212                 exit(2);
213         }
214
215         /* read volume header */
216         if ( (fd=open(fullName, O_RDONLY)) < 0 ) 
217         {
218                 printf("Error in open(%s) : %d\n", fullName, errno);
219                 exit(3);
220         }
221         if ( read(fd, &volumeHeader, sizeof(struct VolumeHeader)) < sizeof(struct VolumeHeader))
222         {
223                 printf("Error in reading Volume Header : %d\n", errno);
224                 exit(4);
225         }
226
227         switch ( option )
228         {
229             case volInfo:       /* volume header info */
230                 printf("VolId:%d VolInfo:%d mag:%x vers:%d smallVnodeIndex:%d largeVnodeIndex:%d VoAcl:%d volMntTab:%d\n", 
231                 volumeHeader.id, volumeHeader.volumeInfo,
232                 volumeHeader.stamp.magic, volumeHeader.stamp.version, 
233                 volumeHeader.smallVnodeIndex, volumeHeader.largeVnodeIndex, 
234                 volumeHeader.volumeAcl, volumeHeader.volumeMountTable);
235                 break;
236
237             case contentsDInode:        /* list directory entries */
238                 printContentsOfDirInode(statBuf.st_dev, dirInode, 
239                         fullName, option);      
240                 break;
241         }
242
243         scanLargeVnode(statBuf.st_dev, volumeHeader.largeVnodeIndex, fullName, option);
244         if ( option & allDirs )
245                 printDirs(fullName);
246         
247         if ( option & allFiles )
248                 scanSmallVnode(statBuf.st_dev, volumeHeader.smallVnodeIndex, fullName, option);
249         close(fd);
250 }
251
252 int 
253 scanLargeVnode(dev, node, partitionName, option)
254 dev_t   dev;
255 Inode   node;
256 char*   partitionName;
257 char    option;                 /* user options */
258 {
259         afs_int32 diskSize = SIZEOF_LARGEDISKVNODE;
260         int             nVnodes, fdi, vnodeIndex, offset=0;
261         char            buf[SIZEOF_LARGEDISKVNODE];
262         struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
263         FILE*           file;
264         struct stat     statBuf;
265         
266         /* open this largeVodeIndex */
267         if ( (fdi = iopen(dev, node, O_RDONLY)) < 0 )
268         {
269                 printf("Error in reading node : %d\n", errno);
270                 exit(5);
271         }
272
273         /* get a FILE pointer */
274         if ( (file = fdopen(fdi, "r")) == 0 )
275         {
276                 printf("fdopen failed : %d\n", errno);
277                 exit(6);
278         }
279
280         /*find out how many directories are there in this volume */
281         if ( fstat(fdi, &statBuf) < 0 )
282         {
283                 printf("Error in stat(fd=%d): %d\n", fdi, errno);
284                 exit(6);
285         }
286         nVnodes =  (statBuf.st_size / diskSize) - 1;
287         if (nVnodes > 0) 
288                  fseek(file, diskSize, 0);
289         else nVnodes = 0;
290
291         /* scan all entries in this volume */
292         DInit(10);                      /* initialise directory buffer */
293
294         for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
295                         nVnodes--, vnodeIndex++, offset += diskSize)
296         {
297                 /* scan this directory */
298                 int createDirEnt();
299                 if ( (vnode->type == vDirectory ) && (vnode->inodeNumber ) )
300                 {
301                         DirHandle               dir;
302                         DirEnt *        dirEntry;
303
304                         dir.volume =    volumeId;
305                         dir.device =    dev;
306                         dir.cacheCheck = 0;
307                         dir.inode = vnode->inodeNumber; 
308 #ifdef  DEBUG
309                         printf("Directory inode %d (parent vnode = %d) contains the entries :\n", 
310                                                 vnode->inodeNumber, vnode->parent );
311 #endif
312
313                         assert(dirEntry = (DirEnt*) malloc(sizeof(DirEnt)));
314                         dirEntry->inode = vnode->inodeNumber;
315                         dirEntry->numEntries  = 0;
316                         dirEntry->vnodeName   = NULL;
317                         EnumerateDir(&dir, &createDirEnt, dirEntry );
318                         insertHash(dirEntry);           /* insert in hash table */
319                 }
320         }
321         fclose(file);
322 #ifdef DEBUG
323         printHash();
324 #endif
325 }
326
327
328
329 int
330 createDirEnt(dirEntry, fileName, vnode, unique)
331 DirEnt* dirEntry;
332 char*   fileName;
333 afs_int32       vnode;
334 afs_int32       unique;
335 {
336         int     fdi;
337         FILE*   file;
338         struct stat     statBuf;
339
340         /* fil up special fields for itself and parent */
341         if ( strcmp(fileName,".") == 0 ) 
342         {
343                 dirEntry->vnode = vnode;
344                 return;
345         }
346         if ( strcmp(fileName,"..") == 0 ) 
347         {
348                 dirEntry->vnodeParent = vnode;
349                 return;
350         }
351
352         (dirEntry->numEntries)++;
353         assert( dirEntry->vnodeName = (VnodeName *)realloc(dirEntry->vnodeName, 
354                                         dirEntry->numEntries*sizeof(VnodeName)));
355         dirEntry->vnodeName[dirEntry->numEntries-1].vnode = vnode;
356         dirEntry->vnodeName[dirEntry->numEntries-1].vunique = unique;
357         dirEntry->vnodeName[dirEntry->numEntries-1].name  = (char *)malloc(strlen(fileName)+1);
358         assert(dirEntry->vnodeName[dirEntry->numEntries-1].name);
359         strcpy(dirEntry->vnodeName[dirEntry->numEntries-1].name, fileName);
360 }
361
362
363 int 
364 scanSmallVnode(dev, node, partitionName, option )
365 dev_t   dev;
366 Inode   node;
367 char*   partitionName;
368 char    option;                 /* user options */
369 {
370         afs_int32 diskSize = SIZEOF_SMALLDISKVNODE;
371         int             nVnodes, fdi, vnodeIndex, offset=0;
372         char            buf[SIZEOF_LARGEDISKVNODE];
373         struct VnodeDiskObject *vnode = (struct VnodeDiskObject *) buf;
374         FILE*           file;
375         struct stat     statBuf;
376         
377         /* open this smallVodeIndex */
378         if ( (fdi = iopen(dev, node, O_RDONLY)) < 0 )
379         {
380                 printf("Error in reading node : %d\n", errno);
381                 exit(5);
382         }
383
384         /* get a FILE pointer */
385         if ( (file = fdopen(fdi, "r")) == 0 )
386         {
387                 printf("fdopen failed : %d\n", errno);
388                 exit(6);
389         }
390
391         /*find out how many files are there in this volume */
392         if ( fstat(fdi, &statBuf) < 0 )
393         {
394                 printf("Error in stat(fd=%d): %d\n", fdi, errno);
395                 exit(6);
396         }
397         nVnodes =  (statBuf.st_size / diskSize) - 1;
398         if (nVnodes > 0) 
399                  fseek(file, diskSize, 0);
400         else nVnodes = 0;
401
402         /* scan all entries in this volume */
403         for (vnodeIndex = 0; nVnodes && fread(vnode, diskSize, 1, file) == 1;
404                         nVnodes--, vnodeIndex++, offset += 1)
405                 if ( (vnode->type == vFile) || ( vnode->type == vSymlink) )
406                 {
407                         char*   name, *fullPathName;
408                         int pNode, nNode, orphan = 0;
409                         DirEnt* dir;
410 #ifdef FILE_DEBUG
411                         printf(" File Inode = %d parent vnode=%d ", vnode->inodeNumber,
412                                                 vnode->parent);
413 #endif
414                         
415                         if ( (dir = lookup(vnode->parent)) == 0 )/* orphaned*/
416                                 orphan = 1, pushStack ( orphan_NoVnode );
417                         if ( !orphan )
418                         {
419                                 name=getFileName(dir,vnode->uniquifier);
420                                 if ( name == 0 )
421                                     orphan = 1, pushStack(orphan_NoUnique );
422                         }
423                         if ( !orphan )
424                         {
425                                 /* push the file name on stack */
426                                 pushStack ( name );
427                                 pNode = vnode->parent;
428                                 nNode  = dir->vnodeParent;
429                         }
430                         while ( !orphan && (pNode != nNode) )
431                         {
432                                 if( (dir= lookup(nNode)) == 0 )
433                                 {
434                                         orphan = 1, pushStack(orphan_NoVnode); 
435                                         break;  
436                                 }
437                                 if( (name = getDirName(dir, pNode)) == 0 )
438                                 {
439                                         orphan = 1, pushStack(orphan_NoVnode); 
440                                         break;
441                                 }
442                                 pushStack ( name );
443                                 pNode = nNode;
444                                 nNode = dir->vnodeParent;
445                         }       
446                         fullPathName = printStack();    /* full name of file or symLink */
447                         if ( vnode->type == vSymlink )  /* check if mount point */
448                         {
449                                 /* read contents of link */
450                                 struct stat     statLink;
451                                 int             fdLink;
452                                 char*           symLink;
453                                 if ( (fdLink=iopen( dev, vnode->inodeNumber, O_RDONLY)) < 0 )
454                                 {
455                                         printf("Error in opening symbolic link : %d\n", errno);
456                                         exit(10);
457                                 }
458                                 if  ( fstat(fdLink, &statLink) < 0 )
459                                 {
460                                         printf("Error in symLink stat(fd=%d): %d\n", fdLink, errno);
461                                         exit(12);
462                                 }
463                                 assert( symLink = (char*)malloc(statLink.st_size+1) );
464                                 if  (read(fdLink, symLink, statLink.st_size) < 0 )
465                                 {
466                                         printf("Error in reading symbolic link : %d\n", errno);
467                                         exit(11);
468                                 }
469                                 symLink[statLink.st_size] = 0;  /* null termination */
470                                 if  ( symLink[0] == '#' )       /* this is a mount point */
471                                         printf("Volume %s mounted on %s%s\n", 
472                                                 symLink, partitionName, fullPathName);
473                                 free(symLink);
474                                 close(fdLink);
475                         }
476                         if ( option & allFiles) 
477                         {
478                                 if ( option & lFlag )
479                                 {
480                                         switch ( vnode->type )
481                                         {
482                                         case vFile:     printf("F ");
483                                                         break;
484                                         case vDirectory:printf("D ");
485                                                         break;
486                                         case vSymlink:  printf("S ");
487                                                         break;
488                                         default:        printf("U ");
489                                                         break;
490                                         }
491                                         printf("Ind:%d ", vnode->inodeNumber);
492                                         printf("Mod:%x ", vnode->modeBits);
493                                         printf("Lnk:%d ", vnode->linkCount);
494                                         printf("Own:%d ", vnode->owner);
495                                         printf("Grp:%d ", vnode->group);
496                                         printf("Siz:%d ", vnode->length);
497                                 }
498                                 printf("~%s\n", fullPathName);
499                         }
500                 }
501                         
502         fclose(file);
503 }
504
505 /* Lists all directories in the volume */
506 printDirs(partitionName)
507 char*   partitionName;
508 {
509     int i, j, vnode, inode;
510     DirEnt    *ptr, *dir, *tmpDir;
511
512                         /* The root level vnode for this volume */
513     tmpDir = lookup(1); /* root vnode is 1 */
514     if ( tmpDir == 0 )
515         printf("Root vnode(1) does not exists :%s\n", partitionName);
516     else
517         printf("D Ind:%d Vnd:1 ~\n", tmpDir->inode);
518
519     for ( i=0; i < MAX_HASH_SIZE; i++)
520         for ( ptr = (DirEnt*)hash[i]; ptr; ptr = ptr->next)
521             for ( j=0; j < ptr->numEntries; j++)
522             {
523                 int nVnode, pVnode;
524                 char    *fullPathName, *name;
525
526                 pVnode = ptr->vnodeParent;        /* parent vnode */
527                 nVnode = ptr->vnode;              /* this dir vnode */
528                 vnode  = ptr->vnodeName[j].vnode; /* my Vnode */
529
530                 /* directory vnode numbers are odd */
531                 if ( (vnode % 2) == 0 )
532                         continue;
533
534                 tmpDir = lookup(vnode);
535                 if ( !tmpDir )          /* orphaned directory */
536                 {
537                     printf("%s : vnode:%d \n", orphan_NoVnode, vnode);
538                     continue;
539                 }
540                 inode = tmpDir->inode; /* the inode for this vnode */
541                 
542                 pushStack(ptr->vnodeName[j].name);
543
544                 while ( pVnode != 1 )
545                 {
546                     dir = lookup( pVnode );
547                     if ( dir == 0 ) /* orphan */
548                     {
549                         pushStack(orphan_NoVnode);
550                         break;
551                     }
552                     name = getDirName( dir, nVnode );
553                     if ( name == 0 )
554                     {
555                         pushStack(orphan_NoVnode);
556                         break;
557                     }
558                     pushStack(name);
559                     nVnode = pVnode;
560                     pVnode = dir->vnodeParent;
561                 }
562                 fullPathName = printStack();/* full path name of directory*/
563                 printf("D Ind:%d Vnd:%d ~%s\n",
564                                 inode, vnode, fullPathName);
565             }
566 }
567
568 /* figure out how many pages in use in a directory, given ptr to its (locked) he
569 ader */
570 static ComputeUsedPages(dhp)
571 register struct DirHeader *dhp; {
572     register afs_int32 usedPages, i;
573
574     if (dhp->header.pgcount != 0) {
575         /* new style */
576         usedPages = ntohs(dhp->header.pgcount);
577     }
578     else {
579         /* old style */
580         usedPages = 0;
581         for(i=0; i<MAXPAGES; i++) {
582             if (dhp->alloMap[i] == EPP) {
583                 usedPages = i;
584                 break;
585             }
586         }
587         if (usedPages == 0) usedPages = MAXPAGES;
588     }
589     return usedPages;
590 }
591
592 printContentsOfDirInode(device, dirInode, fullName, options)
593 dev_t   device;
594 Inode   dirInode;
595 char*   fullName;
596 char    options;
597 {
598     int              fd, i, j, usedPages, pages;
599     FILE*            file;
600     struct stat      statBuf;
601     char             dirPage[2048];
602     struct DirHeader *dhp= (struct DirHeader*)&dirPage[0];
603     struct DirEntry  *de;
604     struct PageHeader *pg;
605
606     fd = iopen(device, dirInode, O_RDONLY); 
607     if ( fd <= 0 )
608     {
609         printf("Cannot open direcory inode %d\n", dirInode);
610         return -1;
611     }
612     if ( (file = fdopen(fd, "r")) == 0 ) /* for buffered read */
613     {
614         printf("fdopen failed : %d\n", errno);
615         close(fd);
616         return -1;
617     }
618     if ( fstat(fd, &statBuf) < 0 )
619     {
620         printf("Error in stat(fd=%d): %d\n", fd, errno);
621         return -1;
622     }
623     /* read first page */
624     if ( fread(&dirPage, sizeof(dirPage), 1, file ) != 1) 
625     {
626         printf("Cannot read dir header from inode %d(errno %d)\n",
627                         dirInode, errno);
628         fclose(file);
629         return -1;
630     }
631     usedPages = ComputeUsedPages(dhp);
632  
633     printf("Alloc map: ");
634     for ( i=0; i < MAXPAGES; i++)
635     {
636         if ( (i % 16) == 0 )
637                 printf("\n");
638         printf("%.2x ", (unsigned char)dhp->alloMap[i]);
639     }
640     printf("\nHash table:");
641     for ( i=0; i < NHASHENT; i++)
642     {
643         if ( (i % 16) == 0 )
644                 printf("\n");
645         printf("%.2d ", dhp->hashTable[i]);
646     }
647     printf("\n");
648
649     /* print header of first page */
650     printf("--------------- Page 0 ---------------\n");
651     printf("pgcnt      :%d\n", usedPages);
652     printf("tag        :%d\n", dhp->header.tag);
653     printf("freecnt    :%d(not used)\n", dhp->header.freecount);
654     printf("freebitmap :");
655     for ( i=0; i < EPP/8; i++)
656         printf("%.2x ", (unsigned char)(dhp->header.freebitmap[i]));
657     printf("\n");
658
659     /* print slots in the first page of this directory */
660     de = ((struct DirPage0 *)dirPage)->entry;
661     for(i=DHE+1; i<EPP; i++, de = (struct DirEntry*)((char *)de+32))
662         printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n",
663             i, de->flag, de->length, de->next,
664             de->fid.vnode, de->fid.vunique, de->name);
665
666     /* read all succeeding pages of this directory */
667     for ( pages=1; pages < usedPages; pages++)
668     {
669         if ( fread(&dirPage, sizeof(dirPage), 1, file ) != 1) 
670         {
671             printf("Cannot read %s page  from inode %d(errno %d)\n",
672                         pages, dirInode, errno);
673             fclose(file);
674             return -1;
675         }
676         pg = &((struct DirPage1 *)dirPage)->header; /* page header */
677         de = ((struct DirPage1 *)dirPage)->entry;
678
679         /* print page header info */
680         printf("--------------- Page %d ---------------\n", pages);
681         printf("pgcnt      :%d\n", pg->pgcount);
682         printf("tag        :%d\n", pg->tag);
683         printf("freecnt    :%d(not used)\n", pg->freecount);
684         printf("freebitmap :");
685         for ( i=0; i < EPP/8; i++)
686             printf("%.2x ", (unsigned char)(pg->freebitmap[i]));
687         printf("\n");
688         
689         /* print slots in this page */
690         for(i=1; i<EPP; i++, de = (struct DirEntry*)((char *)de+32))
691             printf("ent %d: f=%d l=%d n=%d vn=%d vu=%d name:%s\n",
692                 i, de->flag, de->length, de->next,
693                 de->fid.vnode, de->fid.vunique, de->name);
694     }
695
696     fclose(file);
697     return 0;
698
699         
700
701