backport to buster
[hcoop/debian/openafs.git] / src / dir / dir.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 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #ifdef KERNEL
14 # if !defined(UKERNEL)
15 # include "h/types.h"
16 # if !defined(AFS_LINUX26_ENV)
17 # include "h/param.h"
18 # endif
19 # ifdef AFS_AUX_ENV
20 # include "h/mmu.h"
21 # include "h/seg.h"
22 # include "h/sysmacros.h"
23 # include "h/signal.h"
24 # include "h/errno.h"
25 # endif
26 # include "h/time.h"
27 # if defined(AFS_AIX_ENV) || defined(AFS_SGI_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_LINUX20_ENV)
28 # include "h/errno.h"
29 # else
30 # if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV)
31 # include "h/kernel.h"
32 # endif
33 # endif
34 # if defined(AFS_SUN5_ENV) || defined(AFS_HPUX_ENV) || defined(AFS_FBSD_ENV) || defined(AFS_DARWIN80_ENV)
35 # include "afs/sysincludes.h"
36 # endif
37 # if !defined(AFS_SGI64_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_OBSD48_ENV) && !defined(AFS_NBSD_ENV)
38 # include "h/user.h"
39 # endif /* AFS_SGI64_ENV */
40 # include "h/uio.h"
41 # ifdef AFS_OSF_ENV
42 # include <sys/mount.h>
43 # include <sys/vnode.h>
44 # include <ufs/inode.h>
45 # endif
46 # if !defined(AFS_SUN5_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_HPUX110_ENV)
47 # include "h/mbuf.h"
48 # endif
49 # ifndef AFS_LINUX20_ENV
50 # include "netinet/in.h"
51 # endif
52 # else /* !defined(UKERNEL) */
53 # include "afs/stds.h"
54 # include "afs/sysincludes.h"
55 # endif /* !defined(UKERNEL) */
56
57 /* afs_buffer.c */
58 /* These are needed because afs_prototypes.h is not included here */
59 struct dcache;
60 struct DirBuffer;
61 extern int DRead(struct dcache *adc, int page, struct DirBuffer *);
62 extern int DNew(struct dcache *adc, int page, struct DirBuffer *);
63
64 # include "afs/afs_osi.h"
65
66 # include "afs/dir.h"
67
68 # ifdef AFS_LINUX20_ENV
69 # include "h/string.h"
70 # endif
71
72 #else /* KERNEL */
73
74 # include <roken.h>
75 # include "dir.h"
76 #endif /* KERNEL */
77
78 afs_int32 DErrno;
79
80 /* Local static prototypes */
81 static int FindBlobs(dir_file_t, int);
82 static void AddPage(dir_file_t, int);
83 static void FreeBlobs(dir_file_t, int, int);
84 static int FindItem(dir_file_t, char *, struct DirBuffer *,
85 struct DirBuffer *);
86
87 /* Find out how many entries are required to store a name. */
88 int
89 afs_dir_NameBlobs(char *name)
90 {
91 int i;
92 i = strlen(name) + 1;
93 return 1 + ((i + 15) >> 5);
94 }
95
96 /* Create an entry in a file. Dir is a file representation, while entry is
97 * a string name. */
98 int
99 afs_dir_Create(dir_file_t dir, char *entry, void *voidfid)
100 {
101 afs_int32 *vfid = (afs_int32 *) voidfid;
102 int blobs, firstelt;
103 int i;
104 struct DirBuffer entrybuf, prevbuf, headerbuf;
105 struct DirEntry *ep;
106 struct DirHeader *dhp;
107 int code;
108
109 /* check name quality */
110 if (*entry == 0)
111 return EINVAL;
112
113 /* First check if file already exists. */
114 code = FindItem(dir, entry, &prevbuf, &entrybuf);
115 if (code && code != ENOENT) {
116 return code;
117 }
118 if (code == 0) {
119 DRelease(&entrybuf, 0);
120 DRelease(&prevbuf, 0);
121 return EEXIST;
122 }
123
124 blobs = afs_dir_NameBlobs(entry); /* number of entries required */
125 firstelt = FindBlobs(dir, blobs);
126 if (firstelt < 0)
127 return EFBIG; /* directory is full */
128
129 /* First, we fill in the directory entry. */
130 if (afs_dir_GetBlob(dir, firstelt, &entrybuf) != 0)
131 return EIO;
132 ep = (struct DirEntry *)entrybuf.data;
133
134 ep->flag = FFIRST;
135 ep->fid.vnode = htonl(vfid[1]);
136 ep->fid.vunique = htonl(vfid[2]);
137 strcpy(ep->name, entry);
138
139 /* Now we just have to thread it on the hash table list. */
140 if (DRead(dir, 0, &headerbuf) != 0) {
141 DRelease(&entrybuf, 1);
142 return EIO;
143 }
144 dhp = (struct DirHeader *)headerbuf.data;
145
146 i = afs_dir_DirHash(entry);
147 ep->next = dhp->hashTable[i];
148 dhp->hashTable[i] = htons(firstelt);
149 DRelease(&headerbuf, 1);
150 DRelease(&entrybuf, 1);
151 return 0;
152 }
153
154 int
155 afs_dir_Length(dir_file_t dir)
156 {
157 int i, ctr;
158 struct DirBuffer headerbuf;
159 struct DirHeader *dhp;
160
161 if (DRead(dir, 0, &headerbuf) != 0)
162 return 0;
163 dhp = (struct DirHeader *)headerbuf.data;
164
165 if (dhp->header.pgcount != 0)
166 ctr = ntohs(dhp->header.pgcount);
167 else {
168 /* old style, count the pages */
169 ctr = 0;
170 for (i = 0; i < MAXPAGES; i++)
171 if (dhp->alloMap[i] != EPP)
172 ctr++;
173 }
174 DRelease(&headerbuf, 0);
175 return ctr * AFS_PAGESIZE;
176 }
177
178 /* Delete an entry from a directory, including update of all free entry
179 * descriptors. */
180 int
181 afs_dir_Delete(dir_file_t dir, char *entry)
182 {
183
184 int nitems, index;
185 struct DirBuffer entrybuf, prevbuf;
186 struct DirEntry *firstitem;
187 unsigned short *previtem;
188 int code;
189
190 code = FindItem(dir, entry, &prevbuf, &entrybuf);
191 if (code) {
192 return code;
193 }
194
195 firstitem = (struct DirEntry *)entrybuf.data;
196 previtem = (unsigned short *)prevbuf.data;
197
198 *previtem = firstitem->next;
199 DRelease(&prevbuf, 1);
200 index = DVOffset(&entrybuf) / 32;
201 nitems = afs_dir_NameBlobs(firstitem->name);
202 /* Clear entire DirEntry and any DirXEntry extensions */
203 memset(firstitem, 0, nitems * sizeof(*firstitem));
204 DRelease(&entrybuf, 1);
205 FreeBlobs(dir, index, nitems);
206 return 0;
207 }
208
209 /* Find a bunch of contiguous entries; at least nblobs in a row. */
210 static int
211 FindBlobs(dir_file_t dir, int nblobs)
212 {
213 int i, j, k;
214 int failed = 0;
215 struct DirBuffer headerbuf, pagebuf;
216 struct DirHeader *dhp;
217 struct PageHeader *pp;
218 int pgcount;
219
220 /* read the dir header in first. */
221 if (DRead(dir, 0, &headerbuf) != 0)
222 return -1;
223 dhp = (struct DirHeader *)headerbuf.data;
224
225 for (i = 0; i < BIGMAXPAGES; i++) {
226 if (i >= MAXPAGES || dhp->alloMap[i] >= nblobs) {
227 /* if page could contain enough entries */
228 /* If there are EPP free entries, then the page is not even allocated. */
229 if (i >= MAXPAGES) {
230 /* this pages exists past the end of the old-style dir */
231 pgcount = ntohs(dhp->header.pgcount);
232 if (pgcount == 0) {
233 pgcount = MAXPAGES;
234 dhp->header.pgcount = htons(pgcount);
235 }
236 if (i > pgcount - 1) {
237 /* this page is bigger than last allocated page */
238 AddPage(dir, i);
239 dhp->header.pgcount = htons(i + 1);
240 }
241 } else if (dhp->alloMap[i] == EPP) {
242 /* Add the page to the directory. */
243 AddPage(dir, i);
244 dhp->alloMap[i] = EPP - 1;
245 dhp->header.pgcount = htons(i + 1);
246 }
247
248 /* read the page in. */
249 if (DRead(dir, i, &pagebuf) != 0) {
250 break;
251 }
252 pp = (struct PageHeader *)pagebuf.data;
253 for (j = 0; j <= EPP - nblobs; j++) {
254 failed = 0;
255 for (k = 0; k < nblobs; k++)
256 if ((pp->freebitmap[(j + k) >> 3] >> ((j + k) & 7)) & 1) {
257 failed = 1;
258 break;
259 }
260 if (!failed)
261 break;
262 failed = 1;
263 }
264 if (!failed) {
265 /* Here we have the first index in j. We update the allocation maps
266 * and free up any resources we've got allocated. */
267 if (i < MAXPAGES)
268 dhp->alloMap[i] -= nblobs;
269 DRelease(&headerbuf, 1);
270 for (k = 0; k < nblobs; k++)
271 pp->freebitmap[(j + k) >> 3] |= 1 << ((j + k) & 7);
272 DRelease(&pagebuf, 1);
273 return j + i * EPP;
274 }
275 DRelease(&pagebuf, 0); /* This dir page is unchanged. */
276 }
277 }
278 /* If we make it here, the directory is full. */
279 DRelease(&headerbuf, 1);
280 return -1;
281 }
282
283 static void
284 AddPage(dir_file_t dir, int pageno)
285 { /* Add a page to a directory. */
286 int i;
287 struct PageHeader *pp;
288 struct DirBuffer pagebuf;
289
290 /* Get a new buffer labelled dir,pageno */
291 DNew(dir, pageno, &pagebuf);
292 pp = (struct PageHeader *)pagebuf.data;
293
294 pp->tag = htons(1234);
295 if (pageno > 0)
296 pp->pgcount = 0;
297 pp->freecount = EPP - 1; /* The first dude is already allocated */
298 pp->freebitmap[0] = 0x01;
299 for (i = 1; i < EPP / 8; i++) /* It's a constant */
300 pp->freebitmap[i] = 0;
301 DRelease(&pagebuf, 1);
302 }
303
304 /* Free a whole bunch of directory entries. */
305
306 static void
307 FreeBlobs(dir_file_t dir, int firstblob, int nblobs)
308 {
309 int i;
310 int page;
311 struct DirBuffer headerbuf, pagehdbuf;
312 struct DirHeader *dhp;
313 struct PageHeader *pp;
314 page = firstblob / EPP;
315 firstblob -= EPP * page; /* convert to page-relative entry */
316
317 if (DRead(dir, 0, &headerbuf) != 0)
318 return;
319 dhp = (struct DirHeader *)headerbuf.data;
320
321 if (page < MAXPAGES)
322 dhp->alloMap[page] += nblobs;
323
324 DRelease(&headerbuf, 1);
325
326 if (DRead(dir, page, &pagehdbuf) != 0)
327 return;
328 pp = (struct PageHeader *)pagehdbuf.data;
329
330 for (i = 0; i < nblobs; i++)
331 pp->freebitmap[(firstblob + i) >> 3] &= ~(1 << ((firstblob + i) & 7));
332
333 DRelease(&pagehdbuf, 1);
334 }
335
336 /*
337 * Format an empty directory properly. Note that the first 13 entries in a
338 * directory header page are allocated, 1 to the page header, 4 to the
339 * allocation map and 8 to the hash table.
340 */
341 int
342 afs_dir_MakeDir(dir_file_t dir, afs_int32 * me, afs_int32 * parent)
343 {
344 int i;
345 struct DirBuffer buffer;
346 struct DirHeader *dhp;
347
348 DNew(dir, 0, &buffer);
349 dhp = (struct DirHeader *)buffer.data;
350
351 dhp->header.pgcount = htons(1);
352 dhp->header.tag = htons(1234);
353 dhp->header.freecount = (EPP - DHE - 1);
354 dhp->header.freebitmap[0] = 0xff;
355 dhp->header.freebitmap[1] = 0x1f;
356 for (i = 2; i < EPP / 8; i++)
357 dhp->header.freebitmap[i] = 0;
358 dhp->alloMap[0] = (EPP - DHE - 1);
359 for (i = 1; i < MAXPAGES; i++)
360 dhp->alloMap[i] = EPP;
361 for (i = 0; i < NHASHENT; i++)
362 dhp->hashTable[i] = 0;
363 DRelease(&buffer, 1);
364 afs_dir_Create(dir, ".", me);
365 afs_dir_Create(dir, "..", parent); /* Virtue is its own .. */
366 return 0;
367 }
368
369 /* Look up a file name in directory. */
370
371 int
372 afs_dir_Lookup(dir_file_t dir, char *entry, void *voidfid)
373 {
374 afs_int32 *fid = (afs_int32 *) voidfid;
375 struct DirBuffer firstbuf, prevbuf;
376 struct DirEntry *firstitem;
377 int code;
378
379 code = FindItem(dir, entry, &prevbuf, &firstbuf);
380 if (code) {
381 return code;
382 }
383 DRelease(&prevbuf, 0);
384 firstitem = (struct DirEntry *)firstbuf.data;
385
386 fid[1] = ntohl(firstitem->fid.vnode);
387 fid[2] = ntohl(firstitem->fid.vunique);
388 DRelease(&firstbuf, 0);
389 return 0;
390 }
391
392 /* Look up a file name in directory. */
393
394 int
395 afs_dir_LookupOffset(dir_file_t dir, char *entry, void *voidfid,
396 long *offsetp)
397 {
398 afs_int32 *fid = (afs_int32 *) voidfid;
399 struct DirBuffer firstbuf, prevbuf;
400 struct DirEntry *firstitem;
401 int code;
402
403 code = FindItem(dir, entry, &prevbuf, &firstbuf);
404 if (code) {
405 return code;
406 }
407 DRelease(&prevbuf, 0);
408 firstitem = (struct DirEntry *)firstbuf.data;
409
410 fid[1] = ntohl(firstitem->fid.vnode);
411 fid[2] = ntohl(firstitem->fid.vunique);
412 if (offsetp)
413 *offsetp = DVOffset(&firstbuf);
414 DRelease(&firstbuf, 0);
415 return 0;
416 }
417
418 /*
419 * Enumerate the contents of a directory. Break when hook function
420 * returns non 0.
421 */
422
423 int
424 afs_dir_EnumerateDir(dir_file_t dir, int (*proc) (void *, char *name,
425 afs_int32 vnode,
426 afs_int32 unique),
427 void *hook)
428 {
429 int i;
430 int num;
431 struct DirBuffer headerbuf, entrybuf;
432 struct DirHeader *dhp;
433 struct DirEntry *ep;
434 int code = 0;
435 int elements;
436
437 if (DRead(dir, 0, &headerbuf) != 0)
438 return EIO;
439 dhp = (struct DirHeader *)headerbuf.data;
440
441 for (i = 0; i < NHASHENT; i++) {
442 /* For each hash chain, enumerate everyone on the list. */
443 num = ntohs(dhp->hashTable[i]);
444 elements = 0;
445 while (num != 0 && elements < BIGMAXPAGES * EPP) {
446 elements++;
447
448 /* Walk down the hash table list. */
449 code = afs_dir_GetVerifiedBlob(dir, num, &entrybuf);
450 if (code)
451 goto out;
452
453 ep = (struct DirEntry *)entrybuf.data;
454 if (!ep) {
455 DRelease(&entrybuf, 0);
456 break;
457 }
458
459 num = ntohs(ep->next);
460 code = (*proc) (hook, ep->name, ntohl(ep->fid.vnode),
461 ntohl(ep->fid.vunique));
462 DRelease(&entrybuf, 0);
463 if (code)
464 goto out;
465 }
466 }
467
468 out:
469 DRelease(&headerbuf, 0);
470 return 0;
471 }
472
473 int
474 afs_dir_IsEmpty(dir_file_t dir)
475 {
476 /* Enumerate the contents of a directory. */
477 int i;
478 int num;
479 struct DirBuffer headerbuf, entrybuf;
480 struct DirHeader *dhp;
481 struct DirEntry *ep;
482 int elements;
483
484 if (DRead(dir, 0, &headerbuf) != 0)
485 return 0;
486 dhp = (struct DirHeader *)headerbuf.data;
487
488 for (i = 0; i < NHASHENT; i++) {
489 /* For each hash chain, enumerate everyone on the list. */
490 num = ntohs(dhp->hashTable[i]);
491 elements = 0;
492 while (num != 0 && elements < BIGMAXPAGES * EPP) {
493 elements++;
494 /* Walk down the hash table list. */
495 if (afs_dir_GetVerifiedBlob(dir, num, &entrybuf) != 0)
496 break;
497 ep = (struct DirEntry *)entrybuf.data;
498 if (strcmp(ep->name, "..") && strcmp(ep->name, ".")) {
499 DRelease(&entrybuf, 0);
500 DRelease(&headerbuf, 0);
501 return 1;
502 }
503 num = ntohs(ep->next);
504 DRelease(&entrybuf, 0);
505 }
506 }
507 DRelease(&headerbuf, 0);
508 return 0;
509 }
510
511 /* Return a pointer to an entry, given its number. Also return the maximum
512 * size of the entry, which is determined by its position within the directory
513 * page.
514 */
515
516 static int
517 GetBlobWithLimit(dir_file_t dir, afs_int32 blobno,
518 struct DirBuffer *buffer, afs_size_t *maxlen)
519 {
520 afs_size_t pos;
521 int code;
522
523 *maxlen = 0;
524 memset(buffer, 0, sizeof(struct DirBuffer));
525
526 code = DRead(dir, blobno >> LEPP, buffer);
527 if (code)
528 return code;
529
530 pos = 32 * (blobno & (EPP - 1));
531
532 *maxlen = AFS_PAGESIZE - pos - 1;
533
534 buffer->data = (void *)(((char *)buffer->data) + pos);
535
536 return 0;
537 }
538
539 /* Given an entries number, return a pointer to that entry */
540 int
541 afs_dir_GetBlob(dir_file_t dir, afs_int32 blobno, struct DirBuffer *buffer)
542 {
543 afs_size_t maxlen = 0;
544 return GetBlobWithLimit(dir, blobno, buffer, &maxlen);
545 }
546
547 /* Return an entry, having verified that the name held within the entry
548 * doesn't overflow off the end of the directory page it is contained
549 * within
550 */
551
552 int
553 afs_dir_GetVerifiedBlob(dir_file_t file, afs_int32 blobno,
554 struct DirBuffer *outbuf)
555 {
556 struct DirEntry *dir;
557 struct DirBuffer buffer;
558 afs_size_t maxlen;
559 int code;
560 char *cp;
561
562 code = GetBlobWithLimit(file, blobno, &buffer, &maxlen);
563 if (code)
564 return code;
565
566 dir = (struct DirEntry *)buffer.data;
567
568 /* A blob is only valid if the name within it is NULL terminated before
569 * the end of the blob's containing page */
570 for (cp = dir->name; *cp != '\0' && cp < ((char *)dir) + maxlen; cp++);
571
572 if (*cp != '\0') {
573 DRelease(&buffer, 0);
574 return EIO;
575 }
576
577 *outbuf = buffer;
578 return 0;
579 }
580
581 int
582 afs_dir_DirHash(char *string)
583 {
584 /* Hash a string to a number between 0 and NHASHENT. */
585 unsigned char tc;
586 unsigned int hval;
587 int tval;
588 hval = 0;
589 while ((tc = (*string++))) {
590 hval *= 173;
591 hval += tc;
592 }
593 tval = hval & (NHASHENT - 1);
594 if (tval == 0)
595 return tval;
596 else if (hval >= 1u<<31)
597 tval = NHASHENT - tval;
598 return tval;
599 }
600
601
602 /* Find a directory entry, given its name. This entry returns a pointer
603 * to a locked buffer, and a pointer to a locked buffer (in previtem)
604 * referencing the found item (to aid the delete code). If no entry is
605 * found, however, no items are left locked, and a null pointer is
606 * returned instead. */
607
608 static int
609 FindItem(dir_file_t dir, char *ename, struct DirBuffer *prevbuf,
610 struct DirBuffer *itembuf )
611 {
612 int i, code;
613 struct DirBuffer curr, prev;
614 struct DirHeader *dhp;
615 struct DirEntry *tp;
616 int elements;
617
618 memset(prevbuf, 0, sizeof(struct DirBuffer));
619 memset(itembuf, 0, sizeof(struct DirBuffer));
620
621 code = DRead(dir, 0, &prev);
622 if (code)
623 return code;
624 dhp = (struct DirHeader *)prev.data;
625
626 i = afs_dir_DirHash(ename);
627 if (dhp->hashTable[i] == 0) {
628 /* no such entry */
629 code = ENOENT;
630 goto out;
631 }
632
633 code = afs_dir_GetVerifiedBlob(dir,
634 (u_short) ntohs(dhp->hashTable[i]),
635 &curr);
636 if (code) {
637 goto out;
638 }
639
640 prev.data = &(dhp->hashTable[i]);
641 elements = 0;
642 /* Detect circular hash chains. Absolute max size of a directory */
643 while (elements < BIGMAXPAGES * EPP) {
644 elements++;
645
646 /* Look at each entry on the hash chain */
647 tp = (struct DirEntry *)curr.data;
648 if (!strcmp(ename, tp->name)) {
649 /* Found it! */
650 *prevbuf = prev;
651 *itembuf = curr;
652 return 0;
653 }
654
655 DRelease(&prev, 0);
656
657 prev = curr;
658 prev.data = &(tp->next);
659
660 if (tp->next == 0) {
661 /* The end of the line */
662 code = ENOENT;
663 goto out;
664 }
665
666 code = afs_dir_GetVerifiedBlob(dir, (u_short) ntohs(tp->next),
667 &curr);
668 if (code)
669 goto out;
670 }
671
672 /* If we've reached here, we've hit our loop limit. Something is weird with
673 * the directory; maybe a circular hash chain? */
674 code = EIO;
675
676 out:
677 DRelease(&prev, 0);
678 return code;
679 }
680
681 static int
682 FindFid (void *dir, afs_uint32 vnode, afs_uint32 unique,
683 struct DirBuffer *itembuf)
684 {
685 /* Find a directory entry, given the vnode and uniquifier of a object.
686 * This entry returns a pointer to a locked buffer. If no entry is found,
687 * however, no items are left locked, and a null pointer is returned
688 * instead.
689 */
690 int i, code;
691 unsigned short next;
692 struct DirBuffer curr, header;
693 struct DirHeader *dhp;
694 struct DirEntry *tp;
695 int elements;
696
697 memset(itembuf, 0, sizeof(struct DirBuffer));
698
699 code = DRead(dir, 0, &header);
700 if (code)
701 return code;
702 dhp = (struct DirHeader *)header.data;
703
704 for (i=0; i<NHASHENT; i++) {
705 if (dhp->hashTable[i] != 0) {
706 code = afs_dir_GetVerifiedBlob(dir,
707 (u_short)ntohs(dhp->hashTable[i]),
708 &curr);
709 if (code) {
710 DRelease(&header, 0);
711 return code;
712 }
713 elements = 0;
714 while(curr.data != NULL && elements < BIGMAXPAGES * EPP) {
715 elements++;
716 tp = (struct DirEntry *)curr.data;
717
718 if (vnode == ntohl(tp->fid.vnode)
719 && unique == ntohl(tp->fid.vunique)) {
720 DRelease(&header, 0);
721 *itembuf = curr;
722 return 0;
723 }
724
725 next = tp->next;
726 DRelease(&curr, 0);
727
728 if (next == 0)
729 break;
730
731 code = afs_dir_GetVerifiedBlob(dir, (u_short)ntohs(next),
732 &curr);
733 if (code) {
734 DRelease(&header, 0);
735 return code;
736 }
737 }
738 }
739 }
740 DRelease(&header, 0);
741 return ENOENT;
742 }
743
744 int
745 afs_dir_InverseLookup(void *dir, afs_uint32 vnode, afs_uint32 unique,
746 char *name, afs_uint32 length)
747 {
748 /* Look for the name pointing to given vnode and unique in a directory */
749 struct DirBuffer entrybuf;
750 struct DirEntry *entry;
751 int code = 0;
752
753 code = FindFid(dir, vnode, unique, &entrybuf);
754 if (code) {
755 return code;
756 }
757 entry = (struct DirEntry *)entrybuf.data;
758
759 if (strlen(entry->name) >= length)
760 code = E2BIG;
761 else
762 strcpy(name, entry->name);
763 DRelease(&entrybuf, 0);
764 return code;
765 }
766
767 /*!
768 * Change an entry fid.
769 *
770 * \param dir
771 * \param entry The entry name.
772 * \param old_fid The old find in MKFid format (host order).
773 * It can be omitted if you don't need a safety check...
774 * \param new_fid The new find in MKFid format (host order).
775 */
776 int
777 afs_dir_ChangeFid(dir_file_t dir, char *entry, afs_uint32 *old_fid,
778 afs_uint32 *new_fid)
779 {
780 struct DirBuffer prevbuf, entrybuf;
781 struct DirEntry *firstitem;
782 struct MKFid *fid_old = (struct MKFid *) old_fid;
783 struct MKFid *fid_new = (struct MKFid *) new_fid;
784 int code;
785
786 /* Find entry. */
787 code = FindItem(dir, entry, &prevbuf, &entrybuf);
788 if (code) {
789 return code;
790 }
791 firstitem = (struct DirEntry *)entrybuf.data;
792 DRelease(&prevbuf, 1);
793
794 /* Replace fid. */
795 if (!old_fid ||
796 ((htonl(fid_old->vnode) == firstitem->fid.vnode) &&
797 (htonl(fid_old->vunique) == firstitem->fid.vunique))) {
798
799 firstitem->fid.vnode = htonl(fid_new->vnode);
800 firstitem->fid.vunique = htonl(fid_new->vunique);
801 }
802
803 DRelease(&entrybuf, 1);
804
805 return 0;
806 }