2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afs/param.h>
13 #include "../h/types.h"
14 #include "../h/param.h"
18 #include "../h/sysmacros.h"
19 #include "../h/signal.h"
20 #include "../h/errno.h"
22 #include "../h/time.h"
23 #if defined(AFS_AIX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_FBSD_ENV)
24 #include "../h/errno.h"
26 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV)
27 #include "../h/kernel.h"
30 #if defined(AFS_SUN56_ENV) || defined(AFS_HPUX_ENV)
31 #include "../afs/sysincludes.h"
34 #if defined(AFS_FBSD_ENV)
35 #include "../h/lock.h"
37 #include "../vm/vm_extern.h"
38 #include "../vm/pmap.h"
39 #include "../vm/vm_map.h"
40 #endif /* AFS_FBSD_ENV */
41 #include "../h/user.h"
42 #endif /* AFS_SGI64_ENV */
45 #include "../afs/gfs_vfs.h"
46 #include "../afs/gfs_vnode.h"
51 #include <sys/vnode.h>
52 #include <ufs/inode.h>
55 #include <vfs/vnode.h>
56 #include <sys/inode.h>
58 #else /* AFS_MACH_ENV */
60 #include <sys/mount.h>
61 #include <sys/vnode.h>
62 #include <ufs/inode.h>
63 #else /* AFS_OSF_ENV */
66 #if !defined(AFS_SGI_ENV)
68 #endif /* AFS_OSF_ENV */
69 #endif /* AFS_MACH_ENV */
72 #ifndef AFS_LINUX20_ENV
73 #include "../netinet/in.h"
75 #if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV)
76 #include "../h/mbuf.h"
78 #else /* !defined(UKERNEL) */
79 #include "../afs/sysincludes.h"
80 #endif /* !defined(UKERNEL) */
81 #include "../afs/afs_osi.h"
83 #include "../afs/dir.h"
85 #include "../afs/longc_procs.h"
86 #ifdef AFS_LINUX20_ENV
87 #include "../h/string.h"
90 /* generic renaming */
91 #define NameBlobs afs_dir_NameBlobs
92 #define GetBlob afs_dir_GetBlob
93 #define Create afs_dir_Create
94 #define Length afs_dir_Length
95 #define Delete afs_dir_Delete
96 #define MakeDir afs_dir_MakeDir
97 #define Lookup afs_dir_Lookup
98 #define LookupOffset afs_dir_LookupOffset
99 #define EnumerateDir afs_dir_EnumerateDir
100 #define IsEmpty afs_dir_IsEmpty
103 # include <sys/types.h>
107 #include <winsock2.h>
109 #include <netinet/in.h>
115 static struct DirEntry *FindItem();
116 struct DirEntry *GetBlob();
117 struct DirEntry *DRead();
118 struct DirEntry *DNew();
124 char * name; {/* Find out how many entries are required to store a name. */
127 return 1+((i+15)>>5);
130 int Create (dir, entry, vfid)
134 /* Create an entry in a file. Dir is a file representation, while entry is a string name. */
137 register struct DirEntry *ep;
139 register struct DirHeader *dhp;
141 /* check name quality */
142 if (*entry == 0) return EINVAL;
143 /* First check if file already exists. */
144 ep = FindItem(dir,entry,&pp);
150 blobs = NameBlobs(entry); /* number of entries required */
151 firstelt = FindBlobs(dir,blobs);
152 if (firstelt < 0) return EFBIG; /* directory is full */
153 /* First, we fill in the directory entry. */
154 ep = GetBlob(dir,firstelt);
155 if (ep == 0) return EIO;
157 ep->fid.vnode = htonl(vfid[1]);
158 ep->fid.vunique = htonl(vfid[2]);
159 strcpy(ep->name,entry);
160 /* Now we just have to thread it on the hash table list. */
161 dhp = (struct DirHeader *) DRead(dir,0);
167 ep->next = dhp->hashTable[i];
168 dhp->hashTable[i] = htons(firstelt);
177 struct DirHeader *dhp;
178 dhp = (struct DirHeader *) DRead(dir,0);
180 if (dhp->header.pgcount != 0) ctr = ntohs(dhp->header.pgcount);
182 /* old style, count the pages */
184 for(i=0;i<MAXPAGES;i++)
185 if (dhp->alloMap[i] != EPP) ctr++;
188 return ctr*AFS_PAGESIZE;
194 /* Delete an entry from a directory, including update of all free entry descriptors. */
196 register struct DirEntry *firstitem;
197 unsigned short *previtem;
198 firstitem = FindItem(dir,entry,&previtem);
199 if (firstitem == 0) return ENOENT;
200 *previtem = firstitem->next;
201 DRelease(previtem,1);
202 index = DVOffset(firstitem)/32;
203 nitems = NameBlobs(firstitem->name);
204 DRelease(firstitem,0);
205 FreeBlobs(dir,index,nitems);
209 FindBlobs (dir,nblobs)
212 /* Find a bunch of contiguous entries; at least nblobs in a row. */
213 register int i, j, k;
215 register struct DirHeader *dhp;
216 struct PageHeader *pp;
219 dhp = (struct DirHeader *) DRead(dir,0); /* read the dir header in first. */
221 for(i=0;i<BIGMAXPAGES;i++) {
222 if (i >= MAXPAGES || dhp->alloMap[i] >= nblobs) {
223 /* if page could contain enough entries */
224 /* If there are EPP free entries, then the page is not even allocated. */
226 /* this pages exists past the end of the old-style dir */
227 pgcount = ntohs(dhp->header.pgcount);
230 dhp->header.pgcount = htons(pgcount);
232 if (i > pgcount - 1) {
233 /* this page is bigger than last allocated page */
235 dhp->header.pgcount = htons(i+1);
238 else if (dhp->alloMap[i] == EPP) {
239 /* Add the page to the directory. */
241 dhp->alloMap[i] = EPP-1;
242 dhp->header.pgcount = htons(i+1);
244 pp = (struct PageHeader *) DRead(dir,i); /* read the page in. */
249 for(j=0;j<=EPP-nblobs;j++) {
251 for(k=0;k<nblobs;k++)
252 if ((pp->freebitmap[(j+k)>>3]>>((j+k)&7)) & 1) {
260 /* Here we have the first index in j. We update the allocation maps
261 and free up any resources we've got allocated. */
262 if (i < MAXPAGES) dhp->alloMap[i] -= nblobs;
264 for (k=0;k<nblobs;k++)
265 pp->freebitmap[(j+k)>>3] |= 1<<((j+k)&7);
269 DRelease(pp, 0); /* This dir page is unchanged. */
272 /* If we make it here, the directory is full. */
277 void AddPage (dir,pageno)
279 int pageno; {/* Add a page to a directory. */
281 register struct PageHeader *pp;
283 pp = (struct PageHeader *) DNew(dir,pageno); /* Get a new buffer labelled dir,pageno */
284 pp->tag = htons(1234);
285 if (pageno > 0) pp->pgcount = 0;
286 pp->freecount = EPP-1; /* The first dude is already allocated */
287 pp->freebitmap[0] = 0x01;
288 for (i=1;i<EPP/8;i++) /* It's a constant */
289 pp->freebitmap[i] = 0;
293 void FreeBlobs(dir,firstblob,nblobs)
295 register int firstblob;
297 /* Free a whole bunch of directory entries. */
300 struct DirHeader *dhp;
301 struct PageHeader *pp;
302 page = firstblob/EPP;
303 firstblob -= EPP*page; /* convert to page-relative entry */
304 dhp = (struct DirHeader *) DRead(dir,0);
306 if (page < MAXPAGES) dhp->alloMap[page] += nblobs;
308 pp = (struct PageHeader *) DRead(dir,page);
309 if (pp) for (i=0;i<nblobs;i++)
310 pp->freebitmap[(firstblob+i)>>3] &= ~(1<<((firstblob+i)&7));
314 MakeDir (dir,me,parent)
318 /* Format an empty directory properly. Note that the first 13 entries in a directory header
319 page are allocated, 1 to the page header, 4 to the allocation map and 8 to the hash table. */
321 register struct DirHeader *dhp;
322 dhp = (struct DirHeader *) DNew(dir,0);
323 dhp->header.pgcount = htons(1);
324 dhp->header.tag = htons(1234);
325 dhp->header.freecount = (EPP-DHE-1);
326 dhp->header.freebitmap[0] = 0xff;
327 dhp->header.freebitmap[1] = 0x1f;
328 for(i=2;i<EPP/8;i++) dhp->header.freebitmap[i] = 0;
329 dhp->alloMap[0]=(EPP-DHE-1);
330 for(i=1;i<MAXPAGES;i++)dhp->alloMap[i] = EPP;
331 for(i=0;i<NHASHENT;i++)dhp->hashTable[i] = 0;
334 Create(dir,"..",parent); /* Virtue is its own .. */
338 Lookup (dir, entry, fid)
341 register afs_int32 *fid; {
342 /* Look up a file name in directory. */
343 register struct DirEntry *firstitem;
344 unsigned short *previtem;
346 firstitem = FindItem(dir,entry,&previtem);
347 if (firstitem == 0) return ENOENT;
348 DRelease(previtem,0);
349 fid[1] = ntohl(firstitem->fid.vnode);
350 fid[2] = ntohl(firstitem->fid.vunique);
351 DRelease(firstitem,0);
355 LookupOffset (dir, entry, fid, offsetp)
359 register afs_int32 *fid; {
360 /* Look up a file name in directory. */
361 register struct DirEntry *firstitem;
362 unsigned short *previtem;
364 firstitem = FindItem(dir,entry,&previtem);
365 if (firstitem == 0) return ENOENT;
366 DRelease(previtem,0);
367 fid[1] = ntohl(firstitem->fid.vnode);
368 fid[2] = ntohl(firstitem->fid.vunique);
370 *offsetp = DVOffset(firstitem);
371 DRelease(firstitem,0);
375 EnumerateDir (dir,hookproc,hook)
379 /* Enumerate the contents of a directory. */
382 register struct DirHeader *dhp;
383 register struct DirEntry *ep;
385 dhp = (struct DirHeader *) DRead(dir,0);
386 if (!dhp) return EIO; /* first page should be there */
387 for(i=0; i<NHASHENT; i++) {
388 /* For each hash chain, enumerate everyone on the list. */
389 num = ntohs(dhp->hashTable[i]);
391 /* Walk down the hash table list. */
393 ep = GetBlob(dir,num);
396 /* we failed, return why */
402 num = ntohs(ep->next);
403 (*hookproc) (hook, ep->name, ntohl(ep->fid.vnode), ntohl(ep->fid.vunique));
413 /* Enumerate the contents of a directory. */
416 register struct DirHeader *dhp;
417 register struct DirEntry *ep;
418 dhp = (struct DirHeader *) DRead(dir,0);
420 for(i=0;i<NHASHENT;i++) {
421 /* For each hash chain, enumerate everyone on the list. */
422 num = ntohs(dhp->hashTable[i]);
424 /* Walk down the hash table list. */
425 ep = GetBlob(dir,num);
427 if (strcmp(ep->name,"..") && strcmp(ep->name,".")) {
432 num = ntohs(ep->next);
440 struct DirEntry *GetBlob (dir, blobno)
443 /* Return a pointer to an entry, given its number. */
445 ep=DRead(dir,blobno>>LEPP);
447 return (struct DirEntry *) (((long)ep)+32*(blobno&(EPP-1)));
451 register char *string; {
452 /* Hash a string to a number between 0 and NHASHENT. */
453 register unsigned char tc;
457 while(tc=(*string++)) {
461 tval = hval & (NHASHENT-1);
462 if (tval == 0) return tval;
463 else if (hval < 0) tval = NHASHENT-tval;
467 static struct DirEntry *FindItem (dir,ename,previtem)
470 unsigned short **previtem; {
471 /* Find a directory entry, given its name. This entry returns a pointer to a locked buffer, and a pointer to a locked buffer (in previtem) referencing the found item (to aid the delete code). If no entry is found, however, no items are left locked, and a null pointer is returned instead. */
473 register struct DirHeader *dhp;
474 register unsigned short *lp;
475 register struct DirEntry *tp;
477 dhp = (struct DirHeader *) DRead(dir,0);
479 if (dhp->hashTable[i] == 0) {
484 tp = GetBlob(dir,(u_short)ntohs(dhp->hashTable[i]));
489 lp = &(dhp->hashTable[i]);
491 /* Look at each hash conflict entry. */
492 if (!strcmp(ename,tp->name)) {
493 /* Found our entry. */
500 /* The end of the line */
501 DRelease(lp,0); /* Release all locks. */
504 tp = GetBlob(dir,(u_short)ntohs(tp->next));