2 * Copyright (c) 1980, 1986 The Regents of the University of California.
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 #include <afsconfig.h>
19 #include <afs/param.h>
22 /* We need the old directory type headers (included below), so don't include
23 * the normal dirent.h, or it will conflict. */
25 # include <sys/inode.h>
26 # define LONGFILENAMES 1
27 # include <sys/sysmacros.h>
30 # ifdef HAVE_USR_OLD_USR_INCLUDE_NDIR_H
31 # include </usr/old/usr/include/ndir.h>
41 #define VICE /* control whether AFS changes are present */
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <ufs/inode.h>
53 #else /* AFS_OSF_ENV */
54 #ifdef AFS_VFSINCL_ENV
56 #include <sys/vnode.h>
58 #include <sys/fs/ufs_inode.h>
59 #include <sys/fs/ufs_fs.h>
61 #include <sys/fs/ufs_fsdir.h>
64 #include <ufs/inode.h>
66 #include <ufs/fsdir.h>
70 #else /* AFS_VFSINCL_ENV */
71 #include <sys/inode.h>
76 #endif /* AFS_VFSINCL_ENV */
77 #endif /* AFS_OSF_ENV */
79 #include <afs/osi_inode.h>
84 #include <sys/mnttab.h>
85 #include <sys/mntent.h>
89 #endif /* AFS_SUN_ENV */
91 struct bufarea
*pbp
= 0;
95 struct inodesc
*idesc
;
98 long ret
, n
, ndb
, offset
;
100 UOFF_T indir_data_blks
;
101 extern int pass1check();
107 idesc
->id_fix
= DONTKNOW
;
108 idesc
->id_entryno
= 0;
109 idesc
->id_filesize
= dp
->di_size
;
110 if ((dp
->di_mode
& IFMT
) == IFBLK
|| (dp
->di_mode
& IFMT
) == IFCHR
)
113 if ((dp
->di_flags
& IC_FASTLINK
) != 0) {
116 #endif /* AFS_OSF_ENV */
118 ndb
= howmany(dino
.di_size
, (UOFF_T
) sblock
.fs_bsize
);
122 * Check property lists on pass1
124 if (idesc
->id_func
== pass1check
&& dino
.di_flags
& IC_PROPLIST
&& *ap
) {
125 ret
= proplist_scan(dp
, idesc
);
129 #endif /* AFS_OSF_ENV */
130 for (; ap
< &dino
.di_db
[NDADDR
]; ap
++) {
131 if (--ndb
== 0 && (offset
= blkoff(&sblock
, dino
.di_size
)) != 0)
133 numfrags(&sblock
, fragroundup(&sblock
, offset
));
135 idesc
->id_numfrags
= sblock
.fs_frag
;
138 idesc
->id_blkno
= *ap
;
139 if (idesc
->id_type
== ADDR
)
140 ret
= (*idesc
->id_func
) (idesc
);
142 ret
= dirscan(idesc
);
146 idesc
->id_numfrags
= sblock
.fs_frag
;
147 #if defined(AFS_SUN5_ENV)
149 * indir_data_blks determine the no. of data blocks
150 * in the previous levels. ie., at level 3 it
151 * is the number of data blocks at level 2, 1, and 0.
153 for (ap
= &dino
.di_ib
[0], n
= 1; n
<= NIADDR
; ap
++, n
++) {
156 indir_data_blks
= NDADDR
;
159 indir_data_blks
= NDADDR
+ NINDIR(&sblock
);
163 NDADDR
+ NINDIR(&sblock
) +
164 (NINDIR(&sblock
) * NINDIR(&sblock
));
167 idesc
->id_blkno
= *ap
;
170 (u_offset_t
) howmany(dino
.di_size
,
171 (u_offset_t
) sblock
.fs_bsize
) -
178 for (ap
= &dino
.di_ib
[0], n
= 1; n
<= NIADDR
; ap
++, n
++) {
180 idesc
->id_blkno
= *ap
;
181 ret
= iblock(idesc
, n
, dino
.di_size
- sblock
.fs_bsize
* NDADDR
);
190 iblock(idesc
, ilevel
, isize
)
191 struct inodesc
*idesc
;
197 int i
, n
, (*func
) ();
202 extern int dirscan(), pass1check();
204 if (idesc
->id_type
== ADDR
) {
205 func
= idesc
->id_func
;
206 if (((n
= (*func
) (idesc
)) & KEEPON
) == 0)
210 if (chkrange(idesc
->id_blkno
, idesc
->id_numfrags
))
212 bp
= getdatablk(idesc
->id_blkno
, sblock
.fs_bsize
);
214 #if defined(AFS_SUN5_ENV)
215 for (sizepb
= 1, i
= 0; i
< ilevel
; i
++) {
216 sizepb
*= (u_offset_t
) NINDIR(&sblock
);
220 * nif indicates the next "free" pointer (as an array index) in this
221 * indirect block, based on counting the blocks remaining in the
222 * file after subtracting all previously processed blocks.
223 * This figure is based on the size field of the inode.
225 * Note that in normal operation, nif may initially calculated to
226 * be larger than the number of pointers in this block; if that is
227 * the case, nif is limited to the max number of pointers per
230 * Also note that if an inode is inconsistant (has more blocks
231 * allocated to it than the size field would indicate), the sweep
232 * through any indirect blocks directly pointed at by the inode
233 * continues. Since the block offset of any data blocks referenced
234 * by these indirect blocks is greater than the size of the file,
235 * the index nif may be computed as a negative value.
236 * In this case, we reset nif to indicate that all pointers in
237 * this retrieval block should be zeroed and the resulting
238 * unreferenced data and/or retrieval blocks be recovered
239 * through garbage collection later.
241 nif
= (offset_t
) howmany(isize
, sizepb
);
242 if (nif
> NINDIR(&sblock
))
243 nif
= NINDIR(&sblock
);
247 for (sizepb
= sblock
.fs_bsize
, i
= 0; i
< ilevel
; i
++)
248 sizepb
*= (UOFF_T
) NINDIR(&sblock
);
249 nif
= isize
/ sizepb
+ 1;
250 if (nif
> NINDIR(&sblock
))
251 nif
= NINDIR(&sblock
);
253 if (idesc
->id_func
== pass1check
&& nif
< NINDIR(&sblock
)) {
254 aplim
= &bp
->b_un
.b_indir
[NINDIR(&sblock
)];
255 for (ap
= &bp
->b_un
.b_indir
[nif
]; ap
< aplim
; ap
++) {
258 (void)sprintf(buf
, "PARTIALLY TRUNCATED INODE I=%d",
260 if (dofix(idesc
, buf
)) {
265 flush(fswritefd
, bp
);
267 aplim
= &bp
->b_un
.b_indir
[nif
];
268 for (ap
= bp
->b_un
.b_indir
, i
= 1; ap
< aplim
; ap
++, i
++) {
270 idesc
->id_blkno
= *ap
;
272 #if defined(AFS_SUN5_ENV)
273 n
= iblock(idesc
, ilevel
, isize
);
275 * each iteration decrease "remaining block
276 * count" by however many blocks were accessible
277 * by a pointer at this indirect block level.
281 n
= iblock(idesc
, ilevel
, isize
- i
* sizepb
);
286 bp
->b_flags
&= ~B_INUSE
;
291 bp
->b_flags
&= ~B_INUSE
;
296 * Check that a block in a legal block number.
297 * Return 0 if in range, 1 if out of range.
305 if ((unsigned)(blk
+ cnt
) > maxfsblock
)
307 c
= dtog(&sblock
, blk
);
308 if (blk
< cgdmin(&sblock
, c
)) {
309 if ((blk
+ cnt
) > cgsblock(&sblock
, c
)) {
311 printf("blk %d < cgdmin %d;", blk
, cgdmin(&sblock
, c
));
312 printf(" blk + cnt %d > cgsbase %d\n", blk
+ cnt
,
313 cgsblock(&sblock
, c
));
318 if ((blk
+ cnt
) > cgbase(&sblock
, c
+ 1)) {
320 printf("blk %d >= cgdmin %d;", blk
, cgdmin(&sblock
, c
));
321 printf(" blk + cnt %d > sblock.fs_fpg %d\n", blk
+ cnt
,
336 if (inumber
< ROOTINO
|| inumber
> maxino
)
337 errexit("bad inode number %d to ginode\n", inumber
);
338 if (mlk_startinum
== 0 || inumber
< mlk_startinum
339 || inumber
>= mlk_startinum
+ INOPB(&sblock
)) {
340 iblk
= itod(&sblock
, inumber
);
342 pbp
->b_flags
&= ~B_INUSE
;
343 pbp
= getdatablk(iblk
, sblock
.fs_bsize
);
344 mlk_startinum
= (inumber
/ INOPB(&sblock
)) * INOPB(&sblock
);
346 return (&pbp
->b_un
.b_dinode
[inumber
% INOPB(&sblock
)]);
352 struct inoinfo
**inpp
;
356 for (inpp
= &inpsort
[inplast
- 1]; inpp
>= inpsort
; inpp
--)
360 inphead
= inpsort
= NULL
;
370 clri(idesc
, type
, flag
)
371 struct inodesc
*idesc
;
376 #if defined(ACLS) && defined(AFS_HPUX_ENV)
377 struct inodesc cidesc
;
380 dp
= ginode(idesc
->id_number
);
382 pwarn("%s %s", type
, (dp
->di_mode
& IFMT
) == IFDIR
? "DIR" : "FILE");
383 pinode(idesc
->id_number
);
384 #if defined(ACLS) && defined(AFS_HPUX_ENV)
385 } else if (flag
== 2) {
386 pwarn("%s %s", type
, "CONTINUATION INODE ");
387 printf(" I=%u ", idesc
->id_number
);
390 if (preen
|| reply("CLEAR") == 1) {
392 printf(" (CLEARED)\n");
393 #if defined(ACLS) && defined(AFS_HPUX_ENV)
400 * If there is a CI associated with this inode, we must
403 if (statemap
[idesc
->id_number
] & HASCINODE
) {
404 if (!(dp
->di_contin
< ROOTINO
|| dp
->di_contin
> maxino
))
405 cidesc
.id_number
= dp
->di_contin
;
406 clri(&cidesc
, "UNREF", 2);
411 (void)ckinode(dp
, idesc
);
417 statemap
[idesc
->id_number
] = USTATE
;
423 struct inodesc
*idesc
;
425 struct direct
*dirp
= idesc
->id_dirp
;
427 if (dirp
->d_ino
!= idesc
->id_parent
)
429 memcpy(idesc
->id_name
, dirp
->d_name
, (int)dirp
->d_namlen
+ 1);
430 return (STOP
| FOUND
);
434 struct inodesc
*idesc
;
436 struct direct
*dirp
= idesc
->id_dirp
;
438 if (dirp
->d_ino
== 0)
440 if (strcmp(dirp
->d_name
, idesc
->id_name
) == 0 && dirp
->d_ino
>= ROOTINO
441 && dirp
->d_ino
<= maxino
) {
442 idesc
->id_parent
= dirp
->d_ino
;
443 return (STOP
| FOUND
);
457 printf(" I=%u ", ino
);
458 if (ino
< ROOTINO
|| ino
> maxino
)
462 #if defined(AFS_HPUX110_ENV)
468 pwarn("Could not getinode(%d) in pinode.", ino
);
471 uid
= _GET_D_UID(dp
);
472 if (getpw(uid
, uidbuf
) == 0) {
473 for (p
= uidbuf
; *p
!= ':'; p
++);
475 printf("%s ", uidbuf
);
480 #else /* AFS_HPUX110_ENV */
481 #if defined(AFS_HPUX102_ENV)
482 if ((pw
= getpwuid(_GET_D_UID(dp
))) != 0)
483 printf("%s ", pw
->pw_name
);
485 printf("%d ", _GET_D_UID(dp
));
486 #else /* AFS_HPUX102_ENV */
487 if ((pw
= getpwuid((int)dp
->di_uid
)) != 0)
488 printf("%s ", pw
->pw_name
);
490 printf("%d ", dp
->di_uid
);
491 #endif /* else AFS_HPUX102_ENV */
492 #endif /* else AFS_HPUX110_ENV */
493 printf("MODE=%o\n", dp
->di_mode
);
495 printf("%s: ", devname
);
496 #if defined(AFS_SUN5_ENV)
497 printf("SIZE=%" AFS_INT64_FMT
" ", dp
->di_size
);
499 printf("SIZE=%ld ", dp
->di_size
);
503 printf("MTIME=%12.12s %4.4s ", p
+ 4, p
+ 20);
506 blkerror(ino
, type
, blk
)
512 pfatal("%ld %s I=%u", blk
, type
, ino
);
514 switch (statemap
[ino
]) {
520 #if defined(ACLS) && defined(AFS_HPUX_ENV)
522 * Keep the continuation inode info
524 if (statemap
[ino
] & HASCINODE
)
525 statemap
[ino
] = FCLEAR
| HASCINODE
;
527 statemap
[ino
] = FCLEAR
;
529 statemap
[ino
] = FCLEAR
;
534 #if defined(ACLS) && defined(AFS_HPUX_ENV)
536 * Keep the continuation inode info
538 if (statemap
[ino
] & HASCINODE
)
539 statemap
[ino
] = DCLEAR
| HASCINODE
;
541 statemap
[ino
] = DCLEAR
;
543 statemap
[ino
] = DCLEAR
;
552 errexit("BAD STATE %d TO BLKERR", statemap
[ino
]);
558 * allocate an unused inode
561 allocino(request
, type
)
570 else if (statemap
[request
] != USTATE
)
572 for (ino
= request
; ino
< maxino
; ino
++)
573 if (statemap
[ino
] == USTATE
)
577 switch (type
& IFMT
) {
579 statemap
[ino
] = DSTATE
;
583 statemap
[ino
] = FSTATE
;
589 dp
->di_db
[0] = allocblk((long)1);
590 if (dp
->di_db
[0] == 0) {
591 statemap
[ino
] = USTATE
;
596 dp
->di_mtime
= dp
->di_ctime
= dp
->di_atime
;
597 dp
->di_size
= sblock
.fs_fsize
;
598 dp
->di_blocks
= btodb(sblock
.fs_fsize
);
606 * deallocate an inode
611 struct inodesc idesc
;
612 extern int pass4check();
615 memset(&idesc
, 0, sizeof(struct inodesc
));
616 idesc
.id_type
= ADDR
;
617 idesc
.id_func
= pass4check
;
618 idesc
.id_number
= ino
;
620 (void)ckinode(dp
, &idesc
);
627 statemap
[ino
] = USTATE
;