1*913768d6Sjoerg /* $NetBSD: inode.c,v 1.70 2020/04/03 19:36:33 joerg Exp $ */
25aaab72dSperseant
35aaab72dSperseant /*-
45aaab72dSperseant * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
55aaab72dSperseant * All rights reserved.
65aaab72dSperseant *
75aaab72dSperseant * This code is derived from software contributed to The NetBSD Foundation
85aaab72dSperseant * by Konrad E. Schroder <perseant@hhhh.org>.
95aaab72dSperseant *
105aaab72dSperseant * Redistribution and use in source and binary forms, with or without
115aaab72dSperseant * modification, are permitted provided that the following conditions
125aaab72dSperseant * are met:
135aaab72dSperseant * 1. Redistributions of source code must retain the above copyright
145aaab72dSperseant * notice, this list of conditions and the following disclaimer.
155aaab72dSperseant * 2. Redistributions in binary form must reproduce the above copyright
165aaab72dSperseant * notice, this list of conditions and the following disclaimer in the
175aaab72dSperseant * documentation and/or other materials provided with the distribution.
185aaab72dSperseant *
195aaab72dSperseant * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
205aaab72dSperseant * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
215aaab72dSperseant * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
225aaab72dSperseant * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
235aaab72dSperseant * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
245aaab72dSperseant * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
255aaab72dSperseant * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
265aaab72dSperseant * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
275aaab72dSperseant * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
285aaab72dSperseant * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
295aaab72dSperseant * POSSIBILITY OF SUCH DAMAGE.
305aaab72dSperseant */
31276d62f6Sagc
32276d62f6Sagc /*
33276d62f6Sagc * Copyright (c) 1980, 1986, 1993
34276d62f6Sagc * The Regents of the University of California. All rights reserved.
35276d62f6Sagc *
36276d62f6Sagc * Redistribution and use in source and binary forms, with or without
37276d62f6Sagc * modification, are permitted provided that the following conditions
38276d62f6Sagc * are met:
39276d62f6Sagc * 1. Redistributions of source code must retain the above copyright
40276d62f6Sagc * notice, this list of conditions and the following disclaimer.
41276d62f6Sagc * 2. Redistributions in binary form must reproduce the above copyright
42276d62f6Sagc * notice, this list of conditions and the following disclaimer in the
43276d62f6Sagc * documentation and/or other materials provided with the distribution.
44276d62f6Sagc * 3. Neither the name of the University nor the names of its contributors
45276d62f6Sagc * may be used to endorse or promote products derived from this software
46276d62f6Sagc * without specific prior written permission.
47276d62f6Sagc *
48276d62f6Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49276d62f6Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50276d62f6Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51276d62f6Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52276d62f6Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53276d62f6Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54276d62f6Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55276d62f6Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56276d62f6Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57276d62f6Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58276d62f6Sagc * SUCH DAMAGE.
59276d62f6Sagc */
60369e9cadSperseant
61ba10361aSperseant #include <sys/types.h>
62369e9cadSperseant #include <sys/param.h>
63369e9cadSperseant #include <sys/time.h>
64ba10361aSperseant #include <sys/buf.h>
65ba10361aSperseant #include <sys/mount.h>
66ba10361aSperseant
67f5ac0b5fSdholland #define vnode uvnode
68369e9cadSperseant #include <ufs/lfs/lfs.h>
69835d1242Sdholland #include <ufs/lfs/lfs_accessors.h>
7079e35bebSdholland #include <ufs/lfs/lfs_inode.h>
71ba10361aSperseant #undef vnode
72ba10361aSperseant
73ba10361aSperseant #include <err.h>
74369e9cadSperseant #ifndef SMALL
75369e9cadSperseant #include <pwd.h>
76369e9cadSperseant #endif
77369e9cadSperseant #include <stdio.h>
78369e9cadSperseant #include <stdlib.h>
79369e9cadSperseant #include <string.h>
80b6479e9fSchristos #include <util.h>
81369e9cadSperseant
82ba10361aSperseant #include "bufcache.h"
83100801edSchristos #include "lfs_user.h"
84ba10361aSperseant
85369e9cadSperseant #include "fsck.h"
86369e9cadSperseant #include "fsutil.h"
87369e9cadSperseant #include "extern.h"
88369e9cadSperseant
891d259671Sperseant static int iblock(struct inodesc *, long, u_int64_t);
90369e9cadSperseant int blksreqd(struct lfs *, int);
91369e9cadSperseant int lfs_maxino(void);
92369e9cadSperseant
93ba10361aSperseant /*
94ba10361aSperseant * Get a dinode of a given inum.
95ba10361aSperseant * XXX combine this function with vget.
96ba10361aSperseant */
9708d0c37fSdholland union lfs_dinode *
ginode(ino_t ino)98ba10361aSperseant ginode(ino_t ino)
99369e9cadSperseant {
100ba10361aSperseant struct uvnode *vp;
101ba10361aSperseant struct ubuf *bp;
1024e3fced9Sperseant IFILE *ifp;
103daf91f9bSdholland daddr_t daddr;
104daf91f9bSdholland unsigned segno;
105369e9cadSperseant
106ba10361aSperseant vp = vget(fs, ino);
107ba10361aSperseant if (vp == NULL)
108e6c70652Sperseant return NULL;
109e6c70652Sperseant
110ba10361aSperseant if (din_table[ino] == 0x0) {
111ba10361aSperseant LFS_IENTRY(ifp, fs, ino, bp);
112daf91f9bSdholland daddr = lfs_if_getdaddr(fs, ifp);
113daf91f9bSdholland segno = lfs_dtosn(fs, daddr);
114daf91f9bSdholland din_table[ino] = daddr;
11508d0c37fSdholland seg_table[segno].su_nbytes += DINOSIZE(fs);
116fe44973fSad brelse(bp, 0);
117e6c70652Sperseant }
11840401aa6Sdholland return VTOI(vp)->i_din;
119369e9cadSperseant }
120369e9cadSperseant
121369e9cadSperseant /*
122ba10361aSperseant * Check validity of held blocks in an inode, recursing through all blocks.
123369e9cadSperseant */
124369e9cadSperseant int
ckinode(union lfs_dinode * dp,struct inodesc * idesc)12508d0c37fSdholland ckinode(union lfs_dinode *dp, struct inodesc *idesc)
126369e9cadSperseant {
127639239a1Sdholland daddr_t lbn, pbn;
128369e9cadSperseant long ret, n, ndb, offset;
12908d0c37fSdholland union lfs_dinode dino;
130369e9cadSperseant u_int64_t remsize, sizepb;
131369e9cadSperseant mode_t mode;
132369e9cadSperseant char pathbuf[MAXPATHLEN + 1];
133ba10361aSperseant struct uvnode *vp, *thisvp;
134369e9cadSperseant
135369e9cadSperseant if (idesc->id_fix != IGNORE)
136369e9cadSperseant idesc->id_fix = DONTKNOW;
137369e9cadSperseant idesc->id_entryno = 0;
13808d0c37fSdholland idesc->id_filesize = lfs_dino_getsize(fs, dp);
13908d0c37fSdholland mode = lfs_dino_getmode(fs, dp) & LFS_IFMT;
14055fd1169Sdholland if (mode == LFS_IFBLK || mode == LFS_IFCHR ||
14108d0c37fSdholland (mode == LFS_IFLNK && (lfs_dino_getsize(fs, dp) < lfs_sb_getmaxsymlinklen(fs) ||
142958ff91fSdholland (lfs_sb_getmaxsymlinklen(fs) == 0 &&
14308d0c37fSdholland lfs_dino_getblocks(fs, dp) == 0))))
144369e9cadSperseant return (KEEPON);
14508d0c37fSdholland /* XXX is this safe if we're 32-bit? */
146369e9cadSperseant dino = *dp;
14708d0c37fSdholland ndb = howmany(lfs_dino_getsize(fs, &dino), lfs_sb_getbsize(fs));
148369e9cadSperseant
149884f970fSyamt thisvp = vget(fs, idesc->id_number);
1504f8bc7f7Sdholland for (lbn = 0; lbn < ULFS_NDADDR; lbn++) {
15108d0c37fSdholland pbn = lfs_dino_getdb(fs, &dino, lbn);
152ba10361aSperseant if (thisvp)
153369e9cadSperseant idesc->id_numfrags =
1549ae6af71Schristos lfs_numfrags(fs, VTOI(thisvp)->i_lfs_fragsize[lbn]);
155ba10361aSperseant else {
15608d0c37fSdholland if (--ndb == 0 && (offset = lfs_blkoff(fs, lfs_dino_getsize(fs, &dino))) != 0) {
157ba10361aSperseant idesc->id_numfrags =
1589ae6af71Schristos lfs_numfrags(fs, lfs_fragroundup(fs, offset));
159369e9cadSperseant } else
160576195d5Sdholland idesc->id_numfrags = lfs_sb_getfrag(fs);
161ba10361aSperseant }
16208d0c37fSdholland if (pbn == 0) {
163369e9cadSperseant if (idesc->id_type == DATA && ndb >= 0) {
164369e9cadSperseant /* An empty block in a directory XXX */
1658883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf),
1668883e1fbSitojun idesc->id_number, idesc->id_number);
16729f1062bSperseant pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [1]",
16829f1062bSperseant pathbuf, (long long)idesc->id_number);
169369e9cadSperseant if (reply("ADJUST LENGTH") == 1) {
170ba10361aSperseant vp = vget(fs, idesc->id_number);
171ba10361aSperseant dp = VTOD(vp);
17208d0c37fSdholland lfs_dino_setsize(fs, dp,
17308d0c37fSdholland lbn * lfs_sb_getbsize(fs));
174369e9cadSperseant printf(
175369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n");
176369e9cadSperseant rerun = 1;
177ba10361aSperseant inodirty(VTOI(vp));
17829f1062bSperseant } else
17929f1062bSperseant break;
180369e9cadSperseant }
181369e9cadSperseant continue;
182369e9cadSperseant }
18308d0c37fSdholland idesc->id_blkno = pbn;
18408d0c37fSdholland idesc->id_lblkno = lbn;
185369e9cadSperseant if (idesc->id_type == ADDR) {
186369e9cadSperseant ret = (*idesc->id_func) (idesc);
1871d259671Sperseant } else
188369e9cadSperseant ret = dirscan(idesc);
189369e9cadSperseant if (ret & STOP)
190369e9cadSperseant return (ret);
191369e9cadSperseant }
192576195d5Sdholland idesc->id_numfrags = lfs_sb_getfrag(fs);
19308d0c37fSdholland remsize = lfs_dino_getsize(fs, &dino) - lfs_sb_getbsize(fs) * ULFS_NDADDR;
194576195d5Sdholland sizepb = lfs_sb_getbsize(fs);
19508d0c37fSdholland for (n = 1; n <= ULFS_NIADDR; n++) {
19608d0c37fSdholland pbn = lfs_dino_getib(fs, &dino, n-1);
19708d0c37fSdholland if (pbn) {
19808d0c37fSdholland idesc->id_blkno = pbn;
199369e9cadSperseant ret = iblock(idesc, n, remsize);
200369e9cadSperseant if (ret & STOP)
201369e9cadSperseant return (ret);
202369e9cadSperseant } else {
203369e9cadSperseant if (idesc->id_type == DATA && remsize > 0) {
204369e9cadSperseant /* An empty block in a directory XXX */
2058883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf),
2068883e1fbSitojun idesc->id_number, idesc->id_number);
20729f1062bSperseant pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [2]",
20829f1062bSperseant pathbuf, (long long)idesc->id_number);
209369e9cadSperseant if (reply("ADJUST LENGTH") == 1) {
210ba10361aSperseant vp = vget(fs, idesc->id_number);
211ba10361aSperseant dp = VTOD(vp);
21208d0c37fSdholland lfs_dino_setsize(fs, dp,
21308d0c37fSdholland lfs_dino_getsize(fs, dp) - remsize);
214369e9cadSperseant remsize = 0;
215369e9cadSperseant printf(
216369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n");
217369e9cadSperseant rerun = 1;
218ba10361aSperseant inodirty(VTOI(vp));
219369e9cadSperseant break;
22029f1062bSperseant } else
22129f1062bSperseant break;
222369e9cadSperseant }
223369e9cadSperseant }
2249ae6af71Schristos sizepb *= LFS_NINDIR(fs);
225369e9cadSperseant remsize -= sizepb;
226369e9cadSperseant }
227369e9cadSperseant return (KEEPON);
228369e9cadSperseant }
229369e9cadSperseant
230369e9cadSperseant static int
iblock(struct inodesc * idesc,long ilevel,u_int64_t isize)2311d259671Sperseant iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
232369e9cadSperseant {
233639239a1Sdholland unsigned j, maxindir;
234639239a1Sdholland daddr_t found;
235ba10361aSperseant struct ubuf *bp;
2361d259671Sperseant int i, n, (*func) (struct inodesc *), nif;
237369e9cadSperseant u_int64_t sizepb;
238369e9cadSperseant char pathbuf[MAXPATHLEN + 1], buf[BUFSIZ];
239ba10361aSperseant struct uvnode *devvp, *vp;
240ba10361aSperseant int diddirty = 0;
241369e9cadSperseant
242369e9cadSperseant if (idesc->id_type == ADDR) {
243369e9cadSperseant func = idesc->id_func;
244369e9cadSperseant n = (*func) (idesc);
245369e9cadSperseant if ((n & KEEPON) == 0)
246369e9cadSperseant return (n);
247369e9cadSperseant } else
248369e9cadSperseant func = dirscan;
24979748725Smlelstv if (chkrange(idesc->id_blkno, idesc->id_numfrags))
250369e9cadSperseant return (SKIP);
251ba10361aSperseant
252dcba0206Sperseant devvp = fs->lfs_devvp;
253576195d5Sdholland bread(devvp, LFS_FSBTODB(fs, idesc->id_blkno), lfs_sb_getbsize(fs),
2544ec44e9dSchopps 0, &bp);
255369e9cadSperseant ilevel--;
256576195d5Sdholland for (sizepb = lfs_sb_getbsize(fs), i = 0; i < ilevel; i++)
2579ae6af71Schristos sizepb *= LFS_NINDIR(fs);
2589ae6af71Schristos if (isize > sizepb * LFS_NINDIR(fs))
2599ae6af71Schristos nif = LFS_NINDIR(fs);
260369e9cadSperseant else
261369e9cadSperseant nif = howmany(isize, sizepb);
2629ae6af71Schristos if (idesc->id_func == pass1check && nif < LFS_NINDIR(fs)) {
263639239a1Sdholland maxindir = LFS_NINDIR(fs);
264639239a1Sdholland for (j = nif; j < maxindir; j++) {
265639239a1Sdholland found = lfs_iblock_get(fs, bp->b_data, j);
266639239a1Sdholland if (found == 0)
267369e9cadSperseant continue;
26877c21aedSdholland (void)snprintf(buf, sizeof(buf),
26977c21aedSdholland "PARTIALLY TRUNCATED INODE I=%llu",
270c4ee9f6dSchristos (unsigned long long)idesc->id_number);
271369e9cadSperseant if (dofix(idesc, buf)) {
272639239a1Sdholland lfs_iblock_set(fs, bp->b_data, j, 0);
273ba10361aSperseant ++diddirty;
274369e9cadSperseant }
275369e9cadSperseant }
276369e9cadSperseant }
277639239a1Sdholland maxindir = nif;
278639239a1Sdholland for (j = 0; j < maxindir; j++) {
279639239a1Sdholland found = lfs_iblock_get(fs, bp->b_data, j);
280639239a1Sdholland if (found) {
281639239a1Sdholland idesc->id_blkno = found;
2826e547a61Syamt if (ilevel == 0) {
2836e547a61Syamt /*
2849ae6af71Schristos * dirscan needs lfs_lblkno.
2856e547a61Syamt */
2866e547a61Syamt idesc->id_lblkno++;
287369e9cadSperseant n = (*func) (idesc);
2886e547a61Syamt } else {
289369e9cadSperseant n = iblock(idesc, ilevel, isize);
2906e547a61Syamt }
291369e9cadSperseant if (n & STOP) {
292ba10361aSperseant if (diddirty)
293ba10361aSperseant VOP_BWRITE(bp);
294ba10361aSperseant else
295fe44973fSad brelse(bp, 0);
296369e9cadSperseant return (n);
297369e9cadSperseant }
298369e9cadSperseant } else {
299369e9cadSperseant if (idesc->id_type == DATA && isize > 0) {
300369e9cadSperseant /* An empty block in a directory XXX */
3018883e1fbSitojun getpathname(pathbuf, sizeof(pathbuf),
3028883e1fbSitojun idesc->id_number, idesc->id_number);
30329f1062bSperseant pfatal("DIRECTORY %s INO %lld: CONTAINS EMPTY BLOCKS [3]",
30429f1062bSperseant pathbuf, (long long)idesc->id_number);
305369e9cadSperseant if (reply("ADJUST LENGTH") == 1) {
306ba10361aSperseant vp = vget(fs, idesc->id_number);
307f4c19b7cSdholland lfs_dino_setsize(fs, VTOI(vp)->i_din,
308f4c19b7cSdholland lfs_dino_getsize(fs,
309f4c19b7cSdholland VTOI(vp)->i_din)
310f4c19b7cSdholland - isize);
311369e9cadSperseant isize = 0;
312369e9cadSperseant printf(
313369e9cadSperseant "YOU MUST RERUN FSCK AFTERWARDS\n");
314369e9cadSperseant rerun = 1;
315ba10361aSperseant inodirty(VTOI(vp));
316ba10361aSperseant if (diddirty)
317ba10361aSperseant VOP_BWRITE(bp);
318ba10361aSperseant else
319fe44973fSad brelse(bp, 0);
320369e9cadSperseant return (STOP);
321369e9cadSperseant }
322369e9cadSperseant }
323369e9cadSperseant }
324369e9cadSperseant isize -= sizepb;
325369e9cadSperseant }
326ba10361aSperseant if (diddirty)
327ba10361aSperseant VOP_BWRITE(bp);
328ba10361aSperseant else
329fe44973fSad brelse(bp, 0);
330369e9cadSperseant return (KEEPON);
331369e9cadSperseant }
3324b8db838Sperseant
333369e9cadSperseant /*
334369e9cadSperseant * Check that a block in a legal block number.
335369e9cadSperseant * Return 0 if in range, 1 if out of range.
336369e9cadSperseant */
337369e9cadSperseant int
chkrange(daddr_t blk,int cnt)3381d259671Sperseant chkrange(daddr_t blk, int cnt)
339369e9cadSperseant {
3409ae6af71Schristos if (blk < lfs_sntod(fs, 0)) {
34175453f28Sperseant return (1);
34275453f28Sperseant }
3434e3fced9Sperseant if (blk > maxfsblock) {
3444e3fced9Sperseant return (1);
3454e3fced9Sperseant }
3469ae6af71Schristos if (blk + cnt < lfs_sntod(fs, 0)) {
3474e3fced9Sperseant return (1);
3484e3fced9Sperseant }
3494e3fced9Sperseant if (blk + cnt > maxfsblock) {
350369e9cadSperseant return (1);
351369e9cadSperseant }
352369e9cadSperseant return (0);
353369e9cadSperseant }
3544b8db838Sperseant
355369e9cadSperseant /*
356369e9cadSperseant * Routines to maintain information about directory inodes.
357369e9cadSperseant * This is built during the first pass and used during the
358369e9cadSperseant * second and third passes.
359369e9cadSperseant *
360369e9cadSperseant * Enter inodes into the cache.
361369e9cadSperseant */
362369e9cadSperseant void
cacheino(union lfs_dinode * dp,ino_t inumber)36308d0c37fSdholland cacheino(union lfs_dinode *dp, ino_t inumber)
364369e9cadSperseant {
365ba10361aSperseant struct inoinfo *inp;
3666379e111Sitojun struct inoinfo **inpp, **ninpsort;
36708d0c37fSdholland unsigned int blks, i;
368369e9cadSperseant
36908d0c37fSdholland blks = howmany(lfs_dino_getsize(fs, dp), lfs_sb_getbsize(fs));
3704f8bc7f7Sdholland if (blks > ULFS_NDADDR)
3714f8bc7f7Sdholland blks = ULFS_NDADDR + ULFS_NIADDR;
372639239a1Sdholland inp = emalloc(sizeof(*inp) + (blks - 1) * sizeof(inp->i_blks[0]));
373369e9cadSperseant inpp = &inphead[inumber % numdirs];
374369e9cadSperseant inp->i_nexthash = *inpp;
375369e9cadSperseant *inpp = inp;
376369e9cadSperseant inp->i_child = inp->i_sibling = inp->i_parentp = 0;
3774f8bc7f7Sdholland if (inumber == ULFS_ROOTINO)
3784f8bc7f7Sdholland inp->i_parent = ULFS_ROOTINO;
379369e9cadSperseant else
380369e9cadSperseant inp->i_parent = (ino_t) 0;
381369e9cadSperseant inp->i_dotdot = (ino_t) 0;
382369e9cadSperseant inp->i_number = inumber;
38308d0c37fSdholland inp->i_isize = lfs_dino_getsize(fs, dp);
384ba10361aSperseant
385639239a1Sdholland inp->i_numblks = blks * sizeof(inp->i_blks[0]);
38608d0c37fSdholland for (i=0; i<blks && i<ULFS_NDADDR; i++) {
38708d0c37fSdholland inp->i_blks[i] = lfs_dino_getdb(fs, dp, i);
38808d0c37fSdholland }
38908d0c37fSdholland for (; i<blks; i++) {
39008d0c37fSdholland inp->i_blks[i] = lfs_dino_getib(fs, dp, i - ULFS_NDADDR);
39108d0c37fSdholland }
392369e9cadSperseant if (inplast == listmax) {
393b6479e9fSchristos ninpsort = erealloc(inpsort,
394b6479e9fSchristos (listmax + 100) * sizeof(struct inoinfo *));
3956379e111Sitojun inpsort = ninpsort;
3966379e111Sitojun listmax += 100;
397369e9cadSperseant }
398369e9cadSperseant inpsort[inplast++] = inp;
399369e9cadSperseant }
400369e9cadSperseant
401369e9cadSperseant /*
402369e9cadSperseant * Look up an inode cache structure.
403369e9cadSperseant */
404369e9cadSperseant struct inoinfo *
getinoinfo(ino_t inumber)4051d259671Sperseant getinoinfo(ino_t inumber)
406369e9cadSperseant {
407251f7f59Sperry struct inoinfo *inp;
408369e9cadSperseant
409369e9cadSperseant for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
410369e9cadSperseant if (inp->i_number != inumber)
411369e9cadSperseant continue;
412369e9cadSperseant return (inp);
413369e9cadSperseant }
4144ff9f6f7Schristos err(EEXIT, "cannot find inode %llu", (unsigned long long)inumber);
415369e9cadSperseant return ((struct inoinfo *) 0);
416369e9cadSperseant }
417369e9cadSperseant
418369e9cadSperseant /*
419369e9cadSperseant * Clean up all the inode cache structure.
420369e9cadSperseant */
421369e9cadSperseant void
inocleanup(void)422251f7f59Sperry inocleanup(void)
423369e9cadSperseant {
424251f7f59Sperry struct inoinfo **inpp;
425369e9cadSperseant
426369e9cadSperseant if (inphead == NULL)
427369e9cadSperseant return;
428369e9cadSperseant for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
429369e9cadSperseant free((char *) (*inpp));
430369e9cadSperseant free((char *) inphead);
431369e9cadSperseant free((char *) inpsort);
432369e9cadSperseant inphead = inpsort = NULL;
433369e9cadSperseant }
434369e9cadSperseant
435369e9cadSperseant void
inodirty(struct inode * ip)436ba10361aSperseant inodirty(struct inode *ip)
437369e9cadSperseant {
438f2b481f7Spgoyette ip->i_state |= IN_MODIFIED;
439369e9cadSperseant }
440369e9cadSperseant
441369e9cadSperseant void
clri(struct inodesc * idesc,const char * type,int flag)442e0dd0ca2Schristos clri(struct inodesc * idesc, const char *type, int flag)
443369e9cadSperseant {
444ba10361aSperseant struct uvnode *vp;
445369e9cadSperseant
446ba10361aSperseant vp = vget(fs, idesc->id_number);
447cb2499acSperseant if (flag & 0x1) {
448369e9cadSperseant pwarn("%s %s", type,
449f4c19b7cSdholland (lfs_dino_getmode(fs, VTOI(vp)->i_din) & LFS_IFMT) == LFS_IFDIR ? "DIR" : "FILE");
450369e9cadSperseant pinode(idesc->id_number);
451369e9cadSperseant }
452cb2499acSperseant if ((flag & 0x2) || preen || reply("CLEAR") == 1) {
453ba10361aSperseant if (preen && flag != 2)
454369e9cadSperseant printf(" (CLEARED)\n");
455369e9cadSperseant n_files--;
456ba10361aSperseant (void) ckinode(VTOD(vp), idesc);
45717d264b6Syamt clearinode(idesc->id_number);
458369e9cadSperseant statemap[idesc->id_number] = USTATE;
45917d264b6Syamt vnode_destroy(vp);
460cb2499acSperseant return;
46117d264b6Syamt }
462cb2499acSperseant return;
46317d264b6Syamt }
46417d264b6Syamt
46517d264b6Syamt void
clearinode(ino_t inumber)46617d264b6Syamt clearinode(ino_t inumber)
46717d264b6Syamt {
46817d264b6Syamt struct ubuf *bp;
46917d264b6Syamt IFILE *ifp;
47017d264b6Syamt daddr_t daddr;
471e6c70652Sperseant
472e6c70652Sperseant /* Send cleared inode to the free list */
473e6c70652Sperseant
47417d264b6Syamt LFS_IENTRY(ifp, fs, inumber, bp);
475daf91f9bSdholland daddr = lfs_if_getdaddr(fs, ifp);
476a37f15f0Sperseant if (daddr == LFS_UNUSED_DADDR) {
477fe44973fSad brelse(bp, 0);
478a37f15f0Sperseant return;
479a37f15f0Sperseant }
480daf91f9bSdholland lfs_if_setdaddr(fs, ifp, LFS_UNUSED_DADDR);
481daf91f9bSdholland lfs_if_setnextfree(fs, ifp, lfs_sb_getfreehd(fs));
482576195d5Sdholland lfs_sb_setfreehd(fs, inumber);
483e6c70652Sperseant sbdirty();
484ba10361aSperseant VOP_BWRITE(bp);
48517d264b6Syamt
48617d264b6Syamt /*
48717d264b6Syamt * update segment usage.
48817d264b6Syamt */
48917d264b6Syamt if (daddr != LFS_UNUSED_DADDR) {
49017d264b6Syamt SEGUSE *sup;
4919ae6af71Schristos u_int32_t oldsn = lfs_dtosn(fs, daddr);
49217d264b6Syamt
49308d0c37fSdholland seg_table[oldsn].su_nbytes -= DINOSIZE(fs);
49417d264b6Syamt LFS_SEGENTRY(sup, fs, oldsn, bp);
49508d0c37fSdholland sup->su_nbytes -= DINOSIZE(fs);
49617d264b6Syamt LFS_WRITESEGENTRY(sup, fs, oldsn, bp); /* Ifile */
497369e9cadSperseant }
498369e9cadSperseant }
499369e9cadSperseant
500369e9cadSperseant int
findname(struct inodesc * idesc)5011d259671Sperseant findname(struct inodesc * idesc)
502369e9cadSperseant {
503d01ce2a2Sdholland LFS_DIRHEADER *dirp = idesc->id_dirp;
504e0dd0ca2Schristos size_t len;
505e0dd0ca2Schristos char *buf;
506369e9cadSperseant
507e9e7bd33Sdholland if (lfs_dir_getino(fs, dirp) != idesc->id_parent)
508369e9cadSperseant return (KEEPON);
5093da39f1cSdholland len = lfs_dir_getnamlen(fs, dirp) + 1;
5103da39f1cSdholland if (len > MAXPATHLEN) {
511e0dd0ca2Schristos /* Truncate it but don't overflow the buffer */
5123da39f1cSdholland /* XXX: this case doesn't null-terminate the result */
513e0dd0ca2Schristos len = MAXPATHLEN;
514e0dd0ca2Schristos }
515e0dd0ca2Schristos /* this is namebuf with utils.h */
516e0dd0ca2Schristos buf = __UNCONST(idesc->id_name);
517d033ca8cSdholland (void)memcpy(buf, lfs_dir_nameptr(fs, dirp), len);
518369e9cadSperseant return (STOP | FOUND);
519369e9cadSperseant }
520369e9cadSperseant
521369e9cadSperseant int
findino(struct inodesc * idesc)5221d259671Sperseant findino(struct inodesc * idesc)
523369e9cadSperseant {
524d01ce2a2Sdholland LFS_DIRHEADER *dirp = idesc->id_dirp;
525e9e7bd33Sdholland ino_t ino;
526369e9cadSperseant
527e9e7bd33Sdholland ino = lfs_dir_getino(fs, dirp);
528e9e7bd33Sdholland if (ino == 0)
529369e9cadSperseant return (KEEPON);
530d033ca8cSdholland if (strcmp(lfs_dir_nameptr(fs, dirp), idesc->id_name) == 0 &&
531e9e7bd33Sdholland ino >= ULFS_ROOTINO && ino < maxino) {
532e9e7bd33Sdholland idesc->id_parent = ino;
533369e9cadSperseant return (STOP | FOUND);
534369e9cadSperseant }
535369e9cadSperseant return (KEEPON);
536369e9cadSperseant }
537369e9cadSperseant
538369e9cadSperseant void
pinode(ino_t ino)5391d259671Sperseant pinode(ino_t ino)
540369e9cadSperseant {
54108d0c37fSdholland union lfs_dinode *dp;
542369e9cadSperseant struct passwd *pw;
543369e9cadSperseant
544c4ee9f6dSchristos printf(" I=%llu ", (unsigned long long)ino);
5454f8bc7f7Sdholland if (ino < ULFS_ROOTINO || ino >= maxino)
546369e9cadSperseant return;
547369e9cadSperseant dp = ginode(ino);
548369e9cadSperseant if (dp) {
549369e9cadSperseant printf(" OWNER=");
550369e9cadSperseant #ifndef SMALL
55108d0c37fSdholland if (Uflag && (pw = getpwuid(lfs_dino_getuid(fs, dp))) != 0)
552369e9cadSperseant printf("%s ", pw->pw_name);
553369e9cadSperseant else
554369e9cadSperseant #endif
55508d0c37fSdholland printf("%u ", (unsigned)lfs_dino_getuid(fs, dp));
55608d0c37fSdholland printf("MODE=%o\n", lfs_dino_getmode(fs, dp));
557369e9cadSperseant if (preen)
558369e9cadSperseant printf("%s: ", cdevname());
55908d0c37fSdholland printf("SIZE=%ju ", (uintmax_t) lfs_dino_getsize(fs, dp));
56008d0c37fSdholland printf("MTIME=%s ", print_mtime(lfs_dino_getmtime(fs, dp)));
561369e9cadSperseant }
562369e9cadSperseant }
563369e9cadSperseant
564369e9cadSperseant void
blkerror(ino_t ino,const char * type,daddr_t blk)5659be35a63Schristos blkerror(ino_t ino, const char *type, daddr_t blk)
566369e9cadSperseant {
567369e9cadSperseant
568c4ee9f6dSchristos pfatal("%lld %s I=%llu", (long long) blk, type,
569c4ee9f6dSchristos (unsigned long long)ino);
570369e9cadSperseant printf("\n");
571369e9cadSperseant if (exitonfail)
572369e9cadSperseant exit(1);
573369e9cadSperseant switch (statemap[ino]) {
574369e9cadSperseant
575369e9cadSperseant case FSTATE:
576369e9cadSperseant statemap[ino] = FCLEAR;
577369e9cadSperseant return;
578369e9cadSperseant
579369e9cadSperseant case DSTATE:
580369e9cadSperseant statemap[ino] = DCLEAR;
581369e9cadSperseant return;
582369e9cadSperseant
583369e9cadSperseant case FCLEAR:
584369e9cadSperseant case DCLEAR:
585369e9cadSperseant return;
586369e9cadSperseant
587369e9cadSperseant default:
5884ff9f6f7Schristos err(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]);
589369e9cadSperseant /* NOTREACHED */
590369e9cadSperseant }
591369e9cadSperseant }
5924b8db838Sperseant
593369e9cadSperseant /*
594369e9cadSperseant * allocate an unused inode
595369e9cadSperseant */
596369e9cadSperseant ino_t
allocino(ino_t request,int type)5971d259671Sperseant allocino(ino_t request, int type)
598369e9cadSperseant {
599ba10361aSperseant ino_t ino;
60008d0c37fSdholland union lfs_dinode *dp;
601369e9cadSperseant time_t t;
602ba10361aSperseant struct uvnode *vp;
603ba10361aSperseant struct ubuf *bp;
604369e9cadSperseant
605369e9cadSperseant if (request == 0)
6064f8bc7f7Sdholland request = ULFS_ROOTINO;
607369e9cadSperseant else if (statemap[request] != USTATE)
608369e9cadSperseant return (0);
609369e9cadSperseant for (ino = request; ino < maxino; ino++)
610369e9cadSperseant if (statemap[ino] == USTATE)
611369e9cadSperseant break;
612369e9cadSperseant if (ino == maxino)
61329f1062bSperseant extend_ifile(fs);
61429f1062bSperseant
61555fd1169Sdholland switch (type & LFS_IFMT) {
61655fd1169Sdholland case LFS_IFDIR:
617369e9cadSperseant statemap[ino] = DSTATE;
618369e9cadSperseant break;
61955fd1169Sdholland case LFS_IFREG:
62055fd1169Sdholland case LFS_IFLNK:
621369e9cadSperseant statemap[ino] = FSTATE;
622369e9cadSperseant break;
623369e9cadSperseant default:
624369e9cadSperseant return (0);
625369e9cadSperseant }
6264b8db838Sperseant vp = lfs_valloc(fs, ino);
6274b8db838Sperseant if (vp == NULL)
6284b8db838Sperseant return (0);
62940401aa6Sdholland dp = VTOI(vp)->i_din;
630576195d5Sdholland bp = getblk(vp, 0, lfs_sb_getfsize(fs));
631ba10361aSperseant VOP_BWRITE(bp);
63208d0c37fSdholland lfs_dino_setmode(fs, dp, type);
633369e9cadSperseant (void) time(&t);
63408d0c37fSdholland lfs_dino_setatime(fs, dp, t);
63508d0c37fSdholland lfs_dino_setctime(fs, dp, t);
63608d0c37fSdholland lfs_dino_setmtime(fs, dp, t);
63708d0c37fSdholland lfs_dino_setsize(fs, dp, lfs_sb_getfsize(fs));
63808d0c37fSdholland lfs_dino_setblocks(fs, dp, lfs_btofsb(fs, lfs_sb_getfsize(fs)));
639369e9cadSperseant n_files++;
640ba10361aSperseant inodirty(VTOI(vp));
641caf768dcSdholland typemap[ino] = LFS_IFTODT(type);
642369e9cadSperseant return (ino);
643369e9cadSperseant }
6444b8db838Sperseant
645369e9cadSperseant /*
646369e9cadSperseant * deallocate an inode
647369e9cadSperseant */
648369e9cadSperseant void
freeino(ino_t ino)6491d259671Sperseant freeino(ino_t ino)
650369e9cadSperseant {
651369e9cadSperseant struct inodesc idesc;
652ba10361aSperseant struct uvnode *vp;
653369e9cadSperseant
654369e9cadSperseant memset(&idesc, 0, sizeof(struct inodesc));
655369e9cadSperseant idesc.id_type = ADDR;
656369e9cadSperseant idesc.id_func = pass4check;
657369e9cadSperseant idesc.id_number = ino;
658ba10361aSperseant vp = vget(fs, ino);
659ba10361aSperseant (void) ckinode(VTOD(vp), &idesc);
66017d264b6Syamt clearinode(ino);
661369e9cadSperseant statemap[ino] = USTATE;
66217d264b6Syamt vnode_destroy(vp);
663e6c70652Sperseant
664369e9cadSperseant n_files--;
665369e9cadSperseant }
666