summaryrefslogtreecommitdiff
path: root/ufs-fsck/inode.c
blob: e8924e1ab153bfcfe2a4c7263423f26fda98843a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/* Inode allocation, deallocation, etc.
   Copyright (C) 1994 Free Software Foundation, Inc.
   Written by Michael I. Bushnell.

   This file is part of the GNU Hurd.

   The GNU Hurd is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   The GNU Hurd is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

static void
inode_iterate (struct dinode *dp, 
	       int (*fn) (daddr_t, int),
	       int doaddrblocks)
{
  mode_t mode = dp->di_model & IFMT;
  int nb, maxb;
  
  /* Call FN for iblock IBLOCK of level LEVEL and recurse down
     the indirect block pointers. */
  int
  scaniblock (daddr_t iblock, int level)
    {
      int cont;
      daddr_t ptrs[NIADDR(sblock)];
      int i;

      if (doaddrblocks)
	{
	  cont = (*fn)(iblock, sblock->fs_frag);
	  if (cont == RET_STOP)
	    return RET_STOP;
	  else if (cont == RET_BAD)
	    return RET_GOOD;
	}
      
      readblock (fsbtodb (iblock), buf, sblock->fs_bsize);
      for (i = 0; i < NIADDR (sblock); i++)
	{
	  if (level == 0)
	    cont = (*fn)(ptrs[i], sblock->fs_frag);
	  else 
	    cont = scaniblock (ptrs[i], level - 1);
	  if (cont == RET_STOP)
	    return RET_STOP;
	}
      return RET_GOOD;
    }

  if (mode == IFBLK || mode == IFCHR
      || (mode == IFLNK && sblock->fs_maxsymlinklen != -1
	  && (dp->di_size < sblock->fs_maxsymlinklen
	      || (sblock->fs_maxsymlinklen == 0 && dp->di_blocks == 0))))
    return;

  maxb = howmany (dp->di_size, sblock->fs_bsize);
  for (nb = 0; nb < NDADDR; nb++)
    {
      int offset;
      int nfrags;
      int cont;
      
      if (nb == maxb && (offset = blkoff (sblock, dp->di_size)))
	nfrags = numfrags (sblock, fragroundup (sblock, offset));
      else
	nfrags = sblock->fs_frag;
      
      if (dp->di_db[nb] && (*fn)(dp->di_db[nb], nfrags) != RET_GOOD)
	return;
    }
  
  for (nb = 0; nb < NIADDR; nb++)
    if (dp->di_ib[nb] && scaniblock (dp->di_ib[nb], nb) != RET_GOOD)
      return;

  if (doaddrblocks && dp->di_trans)
    (*fn)(dp->di_trans, sblock->fs_frag);
}

void
datablocks_iterate (struct dinode *dp, 
		    int (*fn) (daddr_t, int))
{
  inode_iterate (dp, fn, 0);
}

void
allblock_iterate (struct dinode *dp,
		  int (*fn) (daddr_t, int))
{
  inode_iterate (dp, fn, 1);
}