1*a7b9eedcSflorian /* $OpenBSD: inode.c,v 1.31 2024/05/09 08:35:40 florian Exp $ */
20190393fSart /* $NetBSD: inode.c,v 1.8 2000/01/28 16:01:46 bouyer Exp $ */
38c424e8eSdownsj
48c424e8eSdownsj /*
55ff4e0c8Sdownsj * Copyright (c) 1997 Manuel Bouyer.
68c424e8eSdownsj * Copyright (c) 1980, 1986, 1993
78c424e8eSdownsj * The Regents of the University of California. All rights reserved.
88c424e8eSdownsj *
98c424e8eSdownsj * Redistribution and use in source and binary forms, with or without
108c424e8eSdownsj * modification, are permitted provided that the following conditions
118c424e8eSdownsj * are met:
128c424e8eSdownsj * 1. Redistributions of source code must retain the above copyright
138c424e8eSdownsj * notice, this list of conditions and the following disclaimer.
148c424e8eSdownsj * 2. Redistributions in binary form must reproduce the above copyright
158c424e8eSdownsj * notice, this list of conditions and the following disclaimer in the
168c424e8eSdownsj * documentation and/or other materials provided with the distribution.
171ef0d710Smillert * 3. Neither the name of the University nor the names of its contributors
188c424e8eSdownsj * may be used to endorse or promote products derived from this software
198c424e8eSdownsj * without specific prior written permission.
208c424e8eSdownsj *
218c424e8eSdownsj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
228c424e8eSdownsj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238c424e8eSdownsj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248c424e8eSdownsj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
258c424e8eSdownsj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
268c424e8eSdownsj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278c424e8eSdownsj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
288c424e8eSdownsj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
298c424e8eSdownsj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
308c424e8eSdownsj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318c424e8eSdownsj * SUCH DAMAGE.
328c424e8eSdownsj */
338c424e8eSdownsj
34b9fc9a72Sderaadt #include <sys/param.h> /* btodb */
358c424e8eSdownsj #include <sys/time.h>
368c424e8eSdownsj #include <ufs/ext2fs/ext2fs_dinode.h>
378c424e8eSdownsj #include <ufs/ext2fs/ext2fs_dir.h>
388c424e8eSdownsj #include <ufs/ext2fs/ext2fs.h>
398c424e8eSdownsj
408c424e8eSdownsj #include <ufs/ufs/dinode.h> /* for IFMT & friends */
418c424e8eSdownsj #ifndef SMALL
428c424e8eSdownsj #include <pwd.h>
438c424e8eSdownsj #endif
448c424e8eSdownsj #include <stdio.h>
458c424e8eSdownsj #include <stdlib.h>
468c424e8eSdownsj #include <string.h>
470190393fSart #include <time.h>
48b9fc9a72Sderaadt #include <limits.h>
498c424e8eSdownsj
508c424e8eSdownsj #include "fsck.h"
518c424e8eSdownsj #include "fsutil.h"
528c424e8eSdownsj #include "extern.h"
538c424e8eSdownsj
5465348f21Sjasoni /*
5565348f21Sjasoni * CG is stored in fs byte order in memory, so we can't use ino_to_fsba
5665348f21Sjasoni * here.
5765348f21Sjasoni */
5865348f21Sjasoni
5965348f21Sjasoni #define fsck_ino_to_fsba(fs, x) \
6060a51e06Spelikan (letoh32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \
6165348f21Sjasoni (((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
6265348f21Sjasoni
638c424e8eSdownsj static ino_t startinum;
648c424e8eSdownsj
65c72b5b24Smillert static int iblock(struct inodesc *, long, u_int64_t);
66935730fbSniallo static int setlarge(void);
67935730fbSniallo
68935730fbSniallo static int
setlarge(void)69935730fbSniallo setlarge(void)
70935730fbSniallo {
71935730fbSniallo if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
72935730fbSniallo pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
73935730fbSniallo return 0;
74935730fbSniallo }
75bf2afe82Skevlo if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGE_FILE)) {
76935730fbSniallo if (preen)
77935730fbSniallo pwarn("SETTING LARGE FILE INDICATOR\n");
78935730fbSniallo else if (!reply("SET LARGE FILE INDICATOR"))
79935730fbSniallo return 0;
80bf2afe82Skevlo sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGE_FILE;
81935730fbSniallo sbdirty();
82935730fbSniallo }
83935730fbSniallo return 1;
84935730fbSniallo }
85935730fbSniallo
86935730fbSniallo u_int64_t
inosize(struct ext2fs_dinode * dp)87935730fbSniallo inosize(struct ext2fs_dinode *dp)
88935730fbSniallo {
8960a51e06Spelikan u_int64_t size = letoh32(dp->e2di_size);
90935730fbSniallo
9160a51e06Spelikan if ((letoh16(dp->e2di_mode) & IFMT) == IFREG)
9260a51e06Spelikan size |= (u_int64_t)letoh32(dp->e2di_size_hi) << 32;
93935730fbSniallo if (size >= 0x80000000U)
94935730fbSniallo (void)setlarge();
95935730fbSniallo return size;
96935730fbSniallo }
97935730fbSniallo
98935730fbSniallo void
inossize(struct ext2fs_dinode * dp,u_int64_t size)99935730fbSniallo inossize(struct ext2fs_dinode *dp, u_int64_t size)
100935730fbSniallo {
10160a51e06Spelikan if ((letoh16(dp->e2di_mode) & IFMT) == IFREG) {
10260a51e06Spelikan dp->e2di_size_hi = htole32(size >> 32);
103935730fbSniallo if (size >= 0x80000000U)
104935730fbSniallo if (!setlarge())
105935730fbSniallo return;
106935730fbSniallo } else if (size >= 0x80000000U) {
107935730fbSniallo pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n",
10860a51e06Spelikan (unsigned long long)size, letoh16(dp->e2di_mode) & IFMT);
109935730fbSniallo return;
110935730fbSniallo }
11160a51e06Spelikan dp->e2di_size = htole32(size);
112935730fbSniallo }
1138c424e8eSdownsj
1148c424e8eSdownsj int
ckinode(struct ext2fs_dinode * dp,struct inodesc * idesc)1158809fabbSderaadt ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc)
1168c424e8eSdownsj {
1170190393fSart u_int32_t *ap;
11865348f21Sjasoni long ret, n, ndb;
1198c424e8eSdownsj struct ext2fs_dinode dino;
1208c424e8eSdownsj u_int64_t remsize, sizepb;
1218c424e8eSdownsj mode_t mode;
122b9fc9a72Sderaadt char pathbuf[PATH_MAX + 1];
1238c424e8eSdownsj
1248c424e8eSdownsj if (idesc->id_fix != IGNORE)
1258c424e8eSdownsj idesc->id_fix = DONTKNOW;
1268c424e8eSdownsj idesc->id_entryno = 0;
127935730fbSniallo idesc->id_filesize = inosize(dp);
12860a51e06Spelikan mode = letoh16(dp->e2di_mode) & IFMT;
12965348f21Sjasoni if (mode == IFBLK || mode == IFCHR || mode == IFIFO ||
130935730fbSniallo (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN)))
1318c424e8eSdownsj return (KEEPON);
1328c424e8eSdownsj dino = *dp;
133935730fbSniallo ndb = howmany(inosize(&dino), sblock.e2fs_bsize);
1348c424e8eSdownsj for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR];
1358c424e8eSdownsj ap++,ndb--) {
1368c424e8eSdownsj idesc->id_numfrags = 1;
1378c424e8eSdownsj if (*ap == 0) {
1388c424e8eSdownsj if (idesc->id_type == DATA && ndb > 0) {
1398c424e8eSdownsj /* An empty block in a directory XXX */
140487a1948Stedu getpathname(pathbuf, sizeof pathbuf,
141487a1948Stedu idesc->id_number, idesc->id_number);
1428c424e8eSdownsj pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
1438c424e8eSdownsj pathbuf);
1448c424e8eSdownsj if (reply("ADJUST LENGTH") == 1) {
1458c424e8eSdownsj dp = ginode(idesc->id_number);
146935730fbSniallo inossize(dp,
147935730fbSniallo (ap - &dino.e2di_blocks[0]) *
14865348f21Sjasoni sblock.e2fs_bsize);
1498c424e8eSdownsj printf(
1508c424e8eSdownsj "YOU MUST RERUN FSCK AFTERWARDS\n");
1518c424e8eSdownsj rerun = 1;
1528c424e8eSdownsj inodirty();
1538c424e8eSdownsj }
1548c424e8eSdownsj }
1558c424e8eSdownsj continue;
1568c424e8eSdownsj }
15760a51e06Spelikan idesc->id_blkno = letoh32(*ap);
1588c424e8eSdownsj if (idesc->id_type == ADDR)
1598c424e8eSdownsj ret = (*idesc->id_func)(idesc);
1608c424e8eSdownsj else
1618c424e8eSdownsj ret = dirscan(idesc);
1628c424e8eSdownsj if (ret & STOP)
1638c424e8eSdownsj return (ret);
1648c424e8eSdownsj }
1658c424e8eSdownsj idesc->id_numfrags = 1;
166935730fbSniallo remsize = inosize(&dino) - sblock.e2fs_bsize * NDADDR;
1678c424e8eSdownsj sizepb = sblock.e2fs_bsize;
1688c424e8eSdownsj for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) {
1698c424e8eSdownsj if (*ap) {
17060a51e06Spelikan idesc->id_blkno = letoh32(*ap);
1718c424e8eSdownsj ret = iblock(idesc, n, remsize);
1728c424e8eSdownsj if (ret & STOP)
1738c424e8eSdownsj return (ret);
1748c424e8eSdownsj } else {
1758c424e8eSdownsj if (idesc->id_type == DATA && remsize > 0) {
1768c424e8eSdownsj /* An empty block in a directory XXX */
177487a1948Stedu getpathname(pathbuf, sizeof pathbuf,
178487a1948Stedu idesc->id_number, idesc->id_number);
1798c424e8eSdownsj pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
1808c424e8eSdownsj pathbuf);
1818c424e8eSdownsj if (reply("ADJUST LENGTH") == 1) {
1828c424e8eSdownsj dp = ginode(idesc->id_number);
183935730fbSniallo inossize(dp, inosize(dp) - remsize);
1848c424e8eSdownsj remsize = 0;
1858c424e8eSdownsj printf(
1868c424e8eSdownsj "YOU MUST RERUN FSCK AFTERWARDS\n");
1878c424e8eSdownsj rerun = 1;
1888c424e8eSdownsj inodirty();
1898c424e8eSdownsj break;
1908c424e8eSdownsj }
1918c424e8eSdownsj }
1928c424e8eSdownsj }
1938c424e8eSdownsj sizepb *= NINDIR(&sblock);
1948c424e8eSdownsj remsize -= sizepb;
1958c424e8eSdownsj }
1968c424e8eSdownsj return (KEEPON);
1978c424e8eSdownsj }
1988c424e8eSdownsj
1998c424e8eSdownsj static int
iblock(struct inodesc * idesc,long ilevel,u_int64_t isize)2008809fabbSderaadt iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
2018c424e8eSdownsj {
202b6d2e2d5Sderaadt daddr32_t *ap;
203b6d2e2d5Sderaadt daddr32_t *aplim;
2040190393fSart struct bufarea *bp;
205c72b5b24Smillert int i, n, (*func)(struct inodesc *), nif;
2068c424e8eSdownsj u_int64_t sizepb;
2078c424e8eSdownsj char buf[BUFSIZ];
208b9fc9a72Sderaadt char pathbuf[PATH_MAX + 1];
2098c424e8eSdownsj struct ext2fs_dinode *dp;
2108c424e8eSdownsj
2118c424e8eSdownsj if (idesc->id_type == ADDR) {
2128c424e8eSdownsj func = idesc->id_func;
2138c424e8eSdownsj if (((n = (*func)(idesc)) & KEEPON) == 0)
2148c424e8eSdownsj return (n);
2158c424e8eSdownsj } else
2168c424e8eSdownsj func = dirscan;
2178c424e8eSdownsj if (chkrange(idesc->id_blkno, idesc->id_numfrags))
2188c424e8eSdownsj return (SKIP);
2198c424e8eSdownsj bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize);
2208c424e8eSdownsj ilevel--;
2218c424e8eSdownsj for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++)
2228c424e8eSdownsj sizepb *= NINDIR(&sblock);
2238c424e8eSdownsj if (isize > sizepb * NINDIR(&sblock))
2248c424e8eSdownsj nif = NINDIR(&sblock);
2258c424e8eSdownsj else
2268c424e8eSdownsj nif = howmany(isize, sizepb);
2278c424e8eSdownsj if (idesc->id_func == pass1check &&
2288c424e8eSdownsj nif < NINDIR(&sblock)) {
2298c424e8eSdownsj aplim = &bp->b_un.b_indir[NINDIR(&sblock)];
2308c424e8eSdownsj for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
2318c424e8eSdownsj if (*ap == 0)
2328c424e8eSdownsj continue;
23365348f21Sjasoni (void)snprintf(buf, sizeof(buf),
2343b92bd08Sderaadt "PARTIALLY TRUNCATED INODE I=%llu",
2353b92bd08Sderaadt (unsigned long long)idesc->id_number);
2368c424e8eSdownsj if (dofix(idesc, buf)) {
2378c424e8eSdownsj *ap = 0;
2388c424e8eSdownsj dirty(bp);
2398c424e8eSdownsj }
2408c424e8eSdownsj }
2418c424e8eSdownsj flush(fswritefd, bp);
2428c424e8eSdownsj }
2438c424e8eSdownsj aplim = &bp->b_un.b_indir[nif];
2448c424e8eSdownsj for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
2458c424e8eSdownsj if (*ap) {
24660a51e06Spelikan idesc->id_blkno = letoh32(*ap);
2478c424e8eSdownsj if (ilevel == 0)
2488c424e8eSdownsj n = (*func)(idesc);
2498c424e8eSdownsj else
2508c424e8eSdownsj n = iblock(idesc, ilevel, isize);
2518c424e8eSdownsj if (n & STOP) {
2528c424e8eSdownsj bp->b_flags &= ~B_INUSE;
2538c424e8eSdownsj return (n);
2548c424e8eSdownsj }
2558c424e8eSdownsj } else {
2568c424e8eSdownsj if (idesc->id_type == DATA && isize > 0) {
2578c424e8eSdownsj /* An empty block in a directory XXX */
258487a1948Stedu getpathname(pathbuf, sizeof pathbuf,
259487a1948Stedu idesc->id_number, idesc->id_number);
2608c424e8eSdownsj pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
2618c424e8eSdownsj pathbuf);
2628c424e8eSdownsj if (reply("ADJUST LENGTH") == 1) {
2638c424e8eSdownsj dp = ginode(idesc->id_number);
264935730fbSniallo inossize(dp, inosize(dp) - isize);
2658c424e8eSdownsj isize = 0;
2668c424e8eSdownsj printf(
2678c424e8eSdownsj "YOU MUST RERUN FSCK AFTERWARDS\n");
2688c424e8eSdownsj rerun = 1;
2698c424e8eSdownsj inodirty();
2708c424e8eSdownsj bp->b_flags &= ~B_INUSE;
2718c424e8eSdownsj return(STOP);
2728c424e8eSdownsj }
2738c424e8eSdownsj }
2748c424e8eSdownsj }
2758c424e8eSdownsj isize -= sizepb;
2768c424e8eSdownsj }
2778c424e8eSdownsj bp->b_flags &= ~B_INUSE;
2788c424e8eSdownsj return (KEEPON);
2798c424e8eSdownsj }
2808c424e8eSdownsj
2818c424e8eSdownsj /*
2828c424e8eSdownsj * Check that a block in a legal block number.
2838c424e8eSdownsj * Return 0 if in range, 1 if out of range.
2848c424e8eSdownsj */
2858c424e8eSdownsj int
chkrange(daddr32_t blk,int cnt)286b6d2e2d5Sderaadt chkrange(daddr32_t blk, int cnt)
2878c424e8eSdownsj {
2880190393fSart int c, overh;
2898c424e8eSdownsj
2908c424e8eSdownsj if ((unsigned)(blk + cnt) > maxfsblock)
2918c424e8eSdownsj return (1);
2928c424e8eSdownsj c = dtog(&sblock, blk);
29365348f21Sjasoni overh = cgoverhead(c);
29465348f21Sjasoni if (blk < sblock.e2fs.e2fs_bpg * c + overh +
2958c424e8eSdownsj sblock.e2fs.e2fs_first_dblock) {
29665348f21Sjasoni if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh +
2978c424e8eSdownsj sblock.e2fs.e2fs_first_dblock) {
2988c424e8eSdownsj if (debug) {
2998c424e8eSdownsj printf("blk %d < cgdmin %d;",
30065348f21Sjasoni blk, sblock.e2fs.e2fs_bpg * c + overh +
3018c424e8eSdownsj sblock.e2fs.e2fs_first_dblock);
3028c424e8eSdownsj printf(" blk + cnt %d > cgsbase %d\n",
30365348f21Sjasoni blk + cnt, sblock.e2fs.e2fs_bpg * c +
30465348f21Sjasoni overh + sblock.e2fs.e2fs_first_dblock);
3058c424e8eSdownsj }
3068c424e8eSdownsj return (1);
3078c424e8eSdownsj }
3088c424e8eSdownsj } else {
30965348f21Sjasoni if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh +
3108c424e8eSdownsj sblock.e2fs.e2fs_first_dblock) {
3118c424e8eSdownsj if (debug) {
3128c424e8eSdownsj printf("blk %d >= cgdmin %d;",
31365348f21Sjasoni blk, sblock.e2fs.e2fs_bpg * c + overh +
3148c424e8eSdownsj sblock.e2fs.e2fs_first_dblock);
3158c424e8eSdownsj printf(" blk + cnt %d > cgdmax %d\n",
31665348f21Sjasoni blk+cnt, sblock.e2fs.e2fs_bpg * (c + 1) +
31765348f21Sjasoni overh + sblock.e2fs.e2fs_first_dblock);
3188c424e8eSdownsj }
3198c424e8eSdownsj return (1);
3208c424e8eSdownsj }
3218c424e8eSdownsj }
3228c424e8eSdownsj return (0);
3238c424e8eSdownsj }
3248c424e8eSdownsj
3258c424e8eSdownsj /*
3268c424e8eSdownsj * General purpose interface for reading inodes.
3278c424e8eSdownsj */
3288c424e8eSdownsj struct ext2fs_dinode *
ginode(ino_t inumber)3298809fabbSderaadt ginode(ino_t inumber)
3308c424e8eSdownsj {
331b6d2e2d5Sderaadt daddr32_t iblk;
3328c424e8eSdownsj
3338c424e8eSdownsj if ((inumber < EXT2_FIRSTINO && inumber != EXT2_ROOTINO)
3348c424e8eSdownsj || inumber > maxino)
3353b92bd08Sderaadt errexit("bad inode number %llu to ginode\n",
3363b92bd08Sderaadt (unsigned long long)inumber);
3378c424e8eSdownsj if (startinum == 0 ||
3388c424e8eSdownsj inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) {
3390190393fSart iblk = fsck_ino_to_fsba(&sblock, inumber);
3408c424e8eSdownsj if (pbp != 0)
3418c424e8eSdownsj pbp->b_flags &= ~B_INUSE;
3428c424e8eSdownsj pbp = getdatablk(iblk, sblock.e2fs_bsize);
3438c424e8eSdownsj startinum = ((inumber -1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1;
3448c424e8eSdownsj }
3458c424e8eSdownsj return (&pbp->b_un.b_dinode[(inumber-1) % sblock.e2fs_ipb]);
3468c424e8eSdownsj }
3478c424e8eSdownsj
3488c424e8eSdownsj /*
3498c424e8eSdownsj * Special purpose version of ginode used to optimize first pass
3508c424e8eSdownsj * over all the inodes in numerical order.
3518c424e8eSdownsj */
3528c424e8eSdownsj ino_t nextino, lastinum;
3538c424e8eSdownsj long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
3548c424e8eSdownsj struct ext2fs_dinode *inodebuf;
3558c424e8eSdownsj
3568c424e8eSdownsj struct ext2fs_dinode *
getnextinode(ino_t inumber)3578809fabbSderaadt getnextinode(ino_t inumber)
3588c424e8eSdownsj {
3598c424e8eSdownsj long size;
360b6d2e2d5Sderaadt daddr32_t dblk;
36150e48d67Skrw struct ext2fs_dinode *dp;
36250e48d67Skrw static char *bp;
3638c424e8eSdownsj
3648c424e8eSdownsj if (inumber != nextino++ || inumber > maxino)
3653b92bd08Sderaadt errexit("bad inode number %llu to nextinode\n",
3663b92bd08Sderaadt (unsigned long long)inumber);
3678c424e8eSdownsj if (inumber >= lastinum) {
3688c424e8eSdownsj readcnt++;
3690190393fSart dblk = fsbtodb(&sblock, fsck_ino_to_fsba(&sblock, lastinum));
3708c424e8eSdownsj if (readcnt % readpercg == 0) {
3718c424e8eSdownsj size = partialsize;
3728c424e8eSdownsj lastinum += partialcnt;
3738c424e8eSdownsj } else {
3748c424e8eSdownsj size = inobufsize;
3758c424e8eSdownsj lastinum += fullcnt;
3768c424e8eSdownsj }
3778c424e8eSdownsj (void)bread(fsreadfd, (char *)inodebuf, dblk, size);
37850e48d67Skrw bp = (char *)inodebuf;
3798c424e8eSdownsj }
38050e48d67Skrw
38150e48d67Skrw dp = (struct ext2fs_dinode *)bp;
38250e48d67Skrw bp += EXT2_DINODE_SIZE(&sblock);
38350e48d67Skrw
38450e48d67Skrw return (dp);
3858c424e8eSdownsj }
3868c424e8eSdownsj
3878c424e8eSdownsj void
resetinodebuf(void)3888809fabbSderaadt resetinodebuf(void)
3898c424e8eSdownsj {
3908c424e8eSdownsj
3918c424e8eSdownsj startinum = 0;
3928c424e8eSdownsj nextino = 1;
3938c424e8eSdownsj lastinum = 1;
3948c424e8eSdownsj readcnt = 0;
3958c424e8eSdownsj inobufsize = blkroundup(&sblock, INOBUFSIZE);
39650e48d67Skrw fullcnt = inobufsize / EXT2_DINODE_SIZE(&sblock);
3978c424e8eSdownsj readpercg = sblock.e2fs.e2fs_ipg / fullcnt;
3988c424e8eSdownsj partialcnt = sblock.e2fs.e2fs_ipg % fullcnt;
39950e48d67Skrw partialsize = partialcnt * EXT2_DINODE_SIZE(&sblock);
4008c424e8eSdownsj if (partialcnt != 0) {
4018c424e8eSdownsj readpercg++;
4028c424e8eSdownsj } else {
4038c424e8eSdownsj partialcnt = fullcnt;
4048c424e8eSdownsj partialsize = inobufsize;
4058c424e8eSdownsj }
4068c424e8eSdownsj if (inodebuf == NULL &&
407f87ea3b6Sderaadt (inodebuf = malloc((unsigned)inobufsize)) == NULL)
4088c424e8eSdownsj errexit("Cannot allocate space for inode buffer\n");
4098c424e8eSdownsj while (nextino < EXT2_ROOTINO)
4108c424e8eSdownsj (void)getnextinode(nextino);
4118c424e8eSdownsj }
4128c424e8eSdownsj
4138c424e8eSdownsj void
freeinodebuf(void)4148809fabbSderaadt freeinodebuf(void)
4158c424e8eSdownsj {
4168c424e8eSdownsj
4178c424e8eSdownsj if (inodebuf != NULL)
4188c424e8eSdownsj free((char *)inodebuf);
4198c424e8eSdownsj inodebuf = NULL;
4208c424e8eSdownsj }
4218c424e8eSdownsj
4228c424e8eSdownsj /*
4238c424e8eSdownsj * Routines to maintain information about directory inodes.
4248c424e8eSdownsj * This is built during the first pass and used during the
4258c424e8eSdownsj * second and third passes.
4268c424e8eSdownsj *
4278c424e8eSdownsj * Enter inodes into the cache.
4288c424e8eSdownsj */
4298c424e8eSdownsj void
cacheino(struct ext2fs_dinode * dp,ino_t inumber)4308809fabbSderaadt cacheino(struct ext2fs_dinode *dp, ino_t inumber)
4318c424e8eSdownsj {
4320190393fSart struct inoinfo *inp;
4338c424e8eSdownsj struct inoinfo **inpp;
4348c424e8eSdownsj unsigned int blks;
4358c424e8eSdownsj
436935730fbSniallo blks = howmany(inosize(dp), sblock.e2fs_bsize);
4378c424e8eSdownsj if (blks > NDADDR)
4388c424e8eSdownsj blks = NDADDR + NIADDR;
439f87ea3b6Sderaadt inp = malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr32_t));
4400190393fSart if (inp == NULL)
4418c424e8eSdownsj return;
4428c424e8eSdownsj inpp = &inphead[inumber % numdirs];
4438c424e8eSdownsj inp->i_nexthash = *inpp;
4448c424e8eSdownsj *inpp = inp;
4458c424e8eSdownsj inp->i_child = inp->i_sibling = inp->i_parentp = 0;
4468c424e8eSdownsj if (inumber == EXT2_ROOTINO)
4478c424e8eSdownsj inp->i_parent = EXT2_ROOTINO;
4488c424e8eSdownsj else
4498c424e8eSdownsj inp->i_parent = (ino_t)0;
4508c424e8eSdownsj inp->i_dotdot = (ino_t)0;
4518c424e8eSdownsj inp->i_number = inumber;
452935730fbSniallo inp->i_isize = inosize(dp);
453b6d2e2d5Sderaadt inp->i_numblks = blks * sizeof(daddr32_t);
4548c424e8eSdownsj memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks);
4558c424e8eSdownsj if (inplast == listmax) {
4568c424e8eSdownsj listmax += 100;
45724dc2196Sderaadt inpsort = reallocarray(inpsort, listmax,
45824dc2196Sderaadt sizeof(struct inoinfo *));
4598c424e8eSdownsj if (inpsort == NULL)
4608c424e8eSdownsj errexit("cannot increase directory list\n");
4618c424e8eSdownsj }
4628c424e8eSdownsj inpsort[inplast++] = inp;
4638c424e8eSdownsj }
4648c424e8eSdownsj
4658c424e8eSdownsj /*
4668c424e8eSdownsj * Look up an inode cache structure.
4678c424e8eSdownsj */
4688c424e8eSdownsj struct inoinfo *
getinoinfo(ino_t inumber)4698809fabbSderaadt getinoinfo(ino_t inumber)
4708c424e8eSdownsj {
4710190393fSart struct inoinfo *inp;
4728c424e8eSdownsj
4738c424e8eSdownsj for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
4748c424e8eSdownsj if (inp->i_number != inumber)
4758c424e8eSdownsj continue;
4768c424e8eSdownsj return (inp);
4778c424e8eSdownsj }
4783b92bd08Sderaadt errexit("cannot find inode %llu\n", (unsigned long long)inumber);
47992dc8f3cSkstailey return (NULL);
4808c424e8eSdownsj }
4818c424e8eSdownsj
4828c424e8eSdownsj /*
4838c424e8eSdownsj * Clean up all the inode cache structure.
4848c424e8eSdownsj */
4858c424e8eSdownsj void
inocleanup(void)4868809fabbSderaadt inocleanup(void)
4878c424e8eSdownsj {
4880190393fSart struct inoinfo **inpp;
4898c424e8eSdownsj
4908c424e8eSdownsj if (inphead == NULL)
4918c424e8eSdownsj return;
4928c424e8eSdownsj for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
4938c424e8eSdownsj free((char *)(*inpp));
4948c424e8eSdownsj free((char *)inphead);
4958c424e8eSdownsj free((char *)inpsort);
4968c424e8eSdownsj inphead = inpsort = NULL;
4978c424e8eSdownsj }
4988c424e8eSdownsj
4998c424e8eSdownsj void
inodirty(void)5008809fabbSderaadt inodirty(void)
5018c424e8eSdownsj {
5028c424e8eSdownsj
5038c424e8eSdownsj dirty(pbp);
5048c424e8eSdownsj }
5058c424e8eSdownsj
5068c424e8eSdownsj void
clri(struct inodesc * idesc,char * type,int flag)5078809fabbSderaadt clri(struct inodesc *idesc, char *type, int flag)
5088c424e8eSdownsj {
5090190393fSart struct ext2fs_dinode *dp;
5108c424e8eSdownsj
5118c424e8eSdownsj dp = ginode(idesc->id_number);
5128c424e8eSdownsj if (flag == 1) {
5138c424e8eSdownsj pwarn("%s %s", type,
5148c424e8eSdownsj (dp->e2di_mode & IFMT) == IFDIR ? "DIR" : "FILE");
5158c424e8eSdownsj pinode(idesc->id_number);
5168c424e8eSdownsj }
5178c424e8eSdownsj if (preen || reply("CLEAR") == 1) {
5188c424e8eSdownsj if (preen)
5198c424e8eSdownsj printf(" (CLEARED)\n");
5208c424e8eSdownsj n_files--;
5218c424e8eSdownsj (void)ckinode(dp, idesc);
5228c424e8eSdownsj clearinode(dp);
5238c424e8eSdownsj statemap[idesc->id_number] = USTATE;
5248c424e8eSdownsj inodirty();
5258c424e8eSdownsj }
5268c424e8eSdownsj }
5278c424e8eSdownsj
5288c424e8eSdownsj int
findname(struct inodesc * idesc)5298809fabbSderaadt findname(struct inodesc *idesc)
5308c424e8eSdownsj {
5310190393fSart struct ext2fs_direct *dirp = idesc->id_dirp;
5320190393fSart u_int16_t namlen = dirp->e2d_namlen;
5338c424e8eSdownsj
53460a51e06Spelikan if (letoh32(dirp->e2d_ino) != idesc->id_parent)
5358c424e8eSdownsj return (KEEPON);
5360190393fSart memcpy(idesc->id_name, dirp->e2d_name, (size_t)namlen);
5370190393fSart idesc->id_name[namlen] = '\0';
5388c424e8eSdownsj return (STOP|FOUND);
5398c424e8eSdownsj }
5408c424e8eSdownsj
5418c424e8eSdownsj int
findino(struct inodesc * idesc)5428809fabbSderaadt findino(struct inodesc *idesc)
5438c424e8eSdownsj {
5440190393fSart struct ext2fs_direct *dirp = idesc->id_dirp;
54560a51e06Spelikan u_int32_t ino = letoh32(dirp->e2d_ino);
5468c424e8eSdownsj
5470190393fSart if (ino == 0)
5488c424e8eSdownsj return (KEEPON);
5498c424e8eSdownsj if (strcmp(dirp->e2d_name, idesc->id_name) == 0 &&
5500190393fSart (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO)
5510190393fSart && ino <= maxino) {
5520190393fSart idesc->id_parent = ino;
5538c424e8eSdownsj return (STOP|FOUND);
5548c424e8eSdownsj }
5558c424e8eSdownsj return (KEEPON);
5568c424e8eSdownsj }
5578c424e8eSdownsj
5588c424e8eSdownsj void
pinode(ino_t ino)5598809fabbSderaadt pinode(ino_t ino)
5608c424e8eSdownsj {
5610190393fSart struct ext2fs_dinode *dp;
562dee31871Smillert const char *p;
5638c424e8eSdownsj time_t t;
564d23196ecSpedro u_int32_t uid;
5658c424e8eSdownsj
5663b92bd08Sderaadt printf(" I=%llu ", (unsigned long long)ino);
5678c424e8eSdownsj if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino)
5688c424e8eSdownsj return;
5698c424e8eSdownsj dp = ginode(ino);
5708c424e8eSdownsj printf(" OWNER=");
57160a51e06Spelikan uid = letoh16(dp->e2di_uid_low) | (letoh16(dp->e2di_uid_high) << 16);
5728c424e8eSdownsj #ifndef SMALL
573dee31871Smillert if ((p = user_from_uid(uid, 1)) != NULL)
574dee31871Smillert printf("%s ", p);
5758c424e8eSdownsj else
5768c424e8eSdownsj #endif
577dee31871Smillert printf("%u ", uid);
57860a51e06Spelikan printf("MODE=%o\n", letoh16(dp->e2di_mode));
5798c424e8eSdownsj if (preen)
5808c424e8eSdownsj printf("%s: ", cdevname());
581935730fbSniallo printf("SIZE=%llu ", (long long)inosize(dp));
58260a51e06Spelikan t = (time_t) letoh32(dp->e2di_mtime);
5838c424e8eSdownsj p = ctime(&t);
584*a7b9eedcSflorian if (p)
5858c424e8eSdownsj printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]);
586*a7b9eedcSflorian else
587*a7b9eedcSflorian printf("MTIME=%lld ", t);
5888c424e8eSdownsj }
5898c424e8eSdownsj
5908c424e8eSdownsj void
blkerror(ino_t ino,char * type,daddr32_t blk)591b6d2e2d5Sderaadt blkerror(ino_t ino, char *type, daddr32_t blk)
5928c424e8eSdownsj {
5938c424e8eSdownsj
5943b92bd08Sderaadt pfatal("%d %s I=%llu", blk, type, (unsigned long long)ino);
5958c424e8eSdownsj printf("\n");
5968c424e8eSdownsj switch (statemap[ino]) {
5978c424e8eSdownsj
5988c424e8eSdownsj case FSTATE:
5998c424e8eSdownsj statemap[ino] = FCLEAR;
6008c424e8eSdownsj return;
6018c424e8eSdownsj
6028c424e8eSdownsj case DSTATE:
6038c424e8eSdownsj statemap[ino] = DCLEAR;
6048c424e8eSdownsj return;
6058c424e8eSdownsj
6068c424e8eSdownsj case FCLEAR:
6078c424e8eSdownsj case DCLEAR:
6088c424e8eSdownsj return;
6098c424e8eSdownsj
6108c424e8eSdownsj default:
6118c424e8eSdownsj errexit("BAD STATE %d TO BLKERR\n", statemap[ino]);
6128c424e8eSdownsj /* NOTREACHED */
6138c424e8eSdownsj }
6148c424e8eSdownsj }
6158c424e8eSdownsj
6168c424e8eSdownsj /*
6178c424e8eSdownsj * allocate an unused inode
6188c424e8eSdownsj */
6198c424e8eSdownsj ino_t
allocino(ino_t request,int type)6208809fabbSderaadt allocino(ino_t request, int type)
6218c424e8eSdownsj {
6220190393fSart ino_t ino;
6230190393fSart struct ext2fs_dinode *dp;
6248c424e8eSdownsj time_t t;
6258c424e8eSdownsj
6268c424e8eSdownsj if (request == 0)
6278c424e8eSdownsj request = EXT2_ROOTINO;
6288c424e8eSdownsj else if (statemap[request] != USTATE)
6298c424e8eSdownsj return (0);
6308c424e8eSdownsj for (ino = request; ino < maxino; ino++) {
6318c424e8eSdownsj if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO))
6328c424e8eSdownsj continue;
6338c424e8eSdownsj if (statemap[ino] == USTATE)
6348c424e8eSdownsj break;
6358c424e8eSdownsj }
6368c424e8eSdownsj if (ino == maxino)
6378c424e8eSdownsj return (0);
6388c424e8eSdownsj switch (type & IFMT) {
6398c424e8eSdownsj case IFDIR:
6408c424e8eSdownsj statemap[ino] = DSTATE;
6418c424e8eSdownsj break;
6428c424e8eSdownsj case IFREG:
6438c424e8eSdownsj case IFLNK:
6448c424e8eSdownsj statemap[ino] = FSTATE;
6458c424e8eSdownsj break;
6468c424e8eSdownsj default:
6478c424e8eSdownsj return (0);
6488c424e8eSdownsj }
6498c424e8eSdownsj dp = ginode(ino);
65060a51e06Spelikan dp->e2di_blocks[0] = htole32(allocblk());
6518c424e8eSdownsj if (dp->e2di_blocks[0] == 0) {
6528c424e8eSdownsj statemap[ino] = USTATE;
6538c424e8eSdownsj return (0);
6548c424e8eSdownsj }
65560a51e06Spelikan dp->e2di_mode = htole16(type);
6568c424e8eSdownsj (void)time(&t);
65760a51e06Spelikan dp->e2di_atime = (u_int32_t)htole32(t);
6588c424e8eSdownsj dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime;
6598c424e8eSdownsj dp->e2di_dtime = 0;
660935730fbSniallo inossize(dp, sblock.e2fs_bsize);
66160a51e06Spelikan dp->e2di_nblock = htole32(btodb(sblock.e2fs_bsize));
6628c424e8eSdownsj n_files++;
6638c424e8eSdownsj inodirty();
6640190393fSart typemap[ino] = E2IFTODT(type);
6658c424e8eSdownsj return (ino);
6668c424e8eSdownsj }
6678c424e8eSdownsj
6688c424e8eSdownsj /*
6698c424e8eSdownsj * deallocate an inode
6708c424e8eSdownsj */
6718c424e8eSdownsj void
freeino(ino_t ino)6728809fabbSderaadt freeino(ino_t ino)
6738c424e8eSdownsj {
6748c424e8eSdownsj struct inodesc idesc;
6758c424e8eSdownsj struct ext2fs_dinode *dp;
6768c424e8eSdownsj
6778c424e8eSdownsj memset(&idesc, 0, sizeof(struct inodesc));
6788c424e8eSdownsj idesc.id_type = ADDR;
6798c424e8eSdownsj idesc.id_func = pass4check;
6808c424e8eSdownsj idesc.id_number = ino;
6818c424e8eSdownsj dp = ginode(ino);
6828c424e8eSdownsj (void)ckinode(dp, &idesc);
6838c424e8eSdownsj clearinode(dp);
6848c424e8eSdownsj inodirty();
6858c424e8eSdownsj statemap[ino] = USTATE;
6868c424e8eSdownsj n_files--;
6878c424e8eSdownsj }
688