align buffers used for I/O to DEV_BSIZE so it's executed more optimally when run for xbd(4) raw (character) devicediff -r1.72 -r1.73 src/sbin/fsck_ffs/inode.c
(jdolecek)
--- src/sbin/fsck_ffs/inode.c 2017/02/08 16:11:40 1.72
+++ src/sbin/fsck_ffs/inode.c 2020/04/17 09:42:27 1.73
@@ -1,1051 +1,1051 @@ | @@ -1,1051 +1,1051 @@ | |||
1 | /* $NetBSD: inode.c,v 1.72 2017/02/08 16:11:40 rin Exp $ */ | 1 | /* $NetBSD: inode.c,v 1.73 2020/04/17 09:42:27 jdolecek Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1980, 1986, 1993 | 4 | * Copyright (c) 1980, 1986, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; | 35 | static char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: inode.c,v 1.72 2017/02/08 16:11:40 rin Exp $"); | 37 | __RCSID("$NetBSD: inode.c,v 1.73 2020/04/17 09:42:27 jdolecek Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | #include <sys/time.h> | 42 | #include <sys/time.h> | |
43 | #include <sys/stat.h> | 43 | #include <sys/stat.h> | |
44 | 44 | |||
45 | #include <ufs/ufs/dinode.h> | 45 | #include <ufs/ufs/dinode.h> | |
46 | #include <ufs/ufs/dir.h> | 46 | #include <ufs/ufs/dir.h> | |
47 | #include <ufs/ffs/fs.h> | 47 | #include <ufs/ffs/fs.h> | |
48 | #include <ufs/ffs/ffs_extern.h> | 48 | #include <ufs/ffs/ffs_extern.h> | |
49 | #include <ufs/ufs/ufs_bswap.h> | 49 | #include <ufs/ufs/ufs_bswap.h> | |
50 | 50 | |||
51 | #ifndef SMALL | 51 | #ifndef SMALL | |
52 | #include <err.h> | 52 | #include <err.h> | |
53 | #include <pwd.h> | 53 | #include <pwd.h> | |
54 | #endif | 54 | #endif | |
55 | #include <stdio.h> | 55 | #include <stdio.h> | |
56 | #include <stdlib.h> | 56 | #include <stdlib.h> | |
57 | #include <string.h> | 57 | #include <string.h> | |
58 | #include <time.h> | 58 | #include <time.h> | |
59 | 59 | |||
60 | #include "fsck.h" | 60 | #include "fsck.h" | |
61 | #include "fsutil.h" | 61 | #include "fsutil.h" | |
62 | #include "extern.h" | 62 | #include "extern.h" | |
63 | 63 | |||
64 | static ino_t startinum; | 64 | static ino_t startinum; | |
65 | 65 | |||
66 | static int iblock(struct inodesc *, long, u_int64_t); | 66 | static int iblock(struct inodesc *, long, u_int64_t); | |
67 | #ifndef NO_FFS_EI | 67 | #ifndef NO_FFS_EI | |
68 | static void swap_dinode1(union dinode *, int); | 68 | static void swap_dinode1(union dinode *, int); | |
69 | static void swap_dinode2(union dinode *, int); | 69 | static void swap_dinode2(union dinode *, int); | |
70 | #endif | 70 | #endif | |
71 | 71 | |||
72 | int | 72 | int | |
73 | ckinode(union dinode *dp, struct inodesc *idesc) | 73 | ckinode(union dinode *dp, struct inodesc *idesc) | |
74 | { | 74 | { | |
75 | int ret, offset, i; | 75 | int ret, offset, i; | |
76 | union dinode dino; | 76 | union dinode dino; | |
77 | u_int64_t sizepb; | 77 | u_int64_t sizepb; | |
78 | int64_t remsize; | 78 | int64_t remsize; | |
79 | daddr_t ndb; | 79 | daddr_t ndb; | |
80 | mode_t mode; | 80 | mode_t mode; | |
81 | char pathbuf[MAXPATHLEN + 1]; | 81 | char pathbuf[MAXPATHLEN + 1]; | |
82 | 82 | |||
83 | if (idesc->id_fix != IGNORE) | 83 | if (idesc->id_fix != IGNORE) | |
84 | idesc->id_fix = DONTKNOW; | 84 | idesc->id_fix = DONTKNOW; | |
85 | idesc->id_entryno = 0; | 85 | idesc->id_entryno = 0; | |
86 | idesc->id_filesize = iswap64(DIP(dp, size)); | 86 | idesc->id_filesize = iswap64(DIP(dp, size)); | |
87 | mode = iswap16(DIP(dp, mode)) & IFMT; | 87 | mode = iswap16(DIP(dp, mode)) & IFMT; | |
88 | if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && | 88 | if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && | |
89 | (idesc->id_filesize < sblock->fs_maxsymlinklen || | 89 | (idesc->id_filesize < sblock->fs_maxsymlinklen || | |
90 | (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) || | 90 | (isappleufs && (idesc->id_filesize < APPLEUFS_MAXSYMLINKLEN)) || | |
91 | (sblock->fs_maxsymlinklen == 0 && DIP(dp, blocks) == 0)))) | 91 | (sblock->fs_maxsymlinklen == 0 && DIP(dp, blocks) == 0)))) | |
92 | return (KEEPON); | 92 | return (KEEPON); | |
93 | if (is_ufs2) | 93 | if (is_ufs2) | |
94 | dino.dp2 = dp->dp2; | 94 | dino.dp2 = dp->dp2; | |
95 | else | 95 | else | |
96 | dino.dp1 = dp->dp1; | 96 | dino.dp1 = dp->dp1; | |
97 | ndb = howmany(iswap64(DIP(&dino, size)), sblock->fs_bsize); | 97 | ndb = howmany(iswap64(DIP(&dino, size)), sblock->fs_bsize); | |
98 | for (i = 0; i < UFS_NDADDR; i++) { | 98 | for (i = 0; i < UFS_NDADDR; i++) { | |
99 | if (--ndb == 0 && | 99 | if (--ndb == 0 && | |
100 | (offset = ffs_blkoff(sblock, iswap64(DIP(&dino, size)))) != 0) | 100 | (offset = ffs_blkoff(sblock, iswap64(DIP(&dino, size)))) != 0) | |
101 | idesc->id_numfrags = | 101 | idesc->id_numfrags = | |
102 | ffs_numfrags(sblock, ffs_fragroundup(sblock, offset)); | 102 | ffs_numfrags(sblock, ffs_fragroundup(sblock, offset)); | |
103 | else | 103 | else | |
104 | idesc->id_numfrags = sblock->fs_frag; | 104 | idesc->id_numfrags = sblock->fs_frag; | |
105 | if (DIP(&dino, db[i]) == 0) { | 105 | if (DIP(&dino, db[i]) == 0) { | |
106 | if (idesc->id_type == DATA && ndb >= 0) { | 106 | if (idesc->id_type == DATA && ndb >= 0) { | |
107 | /* An empty block in a directory XXX */ | 107 | /* An empty block in a directory XXX */ | |
108 | markclean = 0; | 108 | markclean = 0; | |
109 | getpathname(pathbuf, sizeof(pathbuf), | 109 | getpathname(pathbuf, sizeof(pathbuf), | |
110 | idesc->id_number, idesc->id_number); | 110 | idesc->id_number, idesc->id_number); | |
111 | pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | 111 | pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | |
112 | pathbuf); | 112 | pathbuf); | |
113 | if (reply("ADJUST LENGTH") == 1) { | 113 | if (reply("ADJUST LENGTH") == 1) { | |
114 | dp = ginode(idesc->id_number); | 114 | dp = ginode(idesc->id_number); | |
115 | DIP_SET(dp, size, iswap64(i * | 115 | DIP_SET(dp, size, iswap64(i * | |
116 | sblock->fs_bsize)); | 116 | sblock->fs_bsize)); | |
117 | printf( | 117 | printf( | |
118 | "YOU MUST RERUN FSCK AFTERWARDS\n"); | 118 | "YOU MUST RERUN FSCK AFTERWARDS\n"); | |
119 | rerun = 1; | 119 | rerun = 1; | |
120 | inodirty(); | 120 | inodirty(); | |
121 | } | 121 | } | |
122 | } | 122 | } | |
123 | continue; | 123 | continue; | |
124 | } | 124 | } | |
125 | if (is_ufs2) | 125 | if (is_ufs2) | |
126 | idesc->id_blkno = iswap64(dino.dp2.di_db[i]); | 126 | idesc->id_blkno = iswap64(dino.dp2.di_db[i]); | |
127 | else | 127 | else | |
128 | idesc->id_blkno = iswap32(dino.dp1.di_db[i]); | 128 | idesc->id_blkno = iswap32(dino.dp1.di_db[i]); | |
129 | if (idesc->id_type != DATA) | 129 | if (idesc->id_type != DATA) | |
130 | ret = (*idesc->id_func)(idesc); | 130 | ret = (*idesc->id_func)(idesc); | |
131 | else | 131 | else | |
132 | ret = dirscan(idesc); | 132 | ret = dirscan(idesc); | |
133 | if (ret & STOP) | 133 | if (ret & STOP) | |
134 | return (ret); | 134 | return (ret); | |
135 | } | 135 | } | |
136 | idesc->id_numfrags = sblock->fs_frag; | 136 | idesc->id_numfrags = sblock->fs_frag; | |
137 | remsize = iswap64(DIP(&dino, size)) - sblock->fs_bsize * UFS_NDADDR; | 137 | remsize = iswap64(DIP(&dino, size)) - sblock->fs_bsize * UFS_NDADDR; | |
138 | sizepb = sblock->fs_bsize; | 138 | sizepb = sblock->fs_bsize; | |
139 | for (i = 0; i < UFS_NIADDR; i++) { | 139 | for (i = 0; i < UFS_NIADDR; i++) { | |
140 | if (DIP(&dino, ib[i])) { | 140 | if (DIP(&dino, ib[i])) { | |
141 | if (is_ufs2) | 141 | if (is_ufs2) | |
142 | idesc->id_blkno = iswap64(dino.dp2.di_ib[i]); | 142 | idesc->id_blkno = iswap64(dino.dp2.di_ib[i]); | |
143 | else | 143 | else | |
144 | idesc->id_blkno = iswap32(dino.dp1.di_ib[i]); | 144 | idesc->id_blkno = iswap32(dino.dp1.di_ib[i]); | |
145 | ret = iblock(idesc, i + 1, remsize); | 145 | ret = iblock(idesc, i + 1, remsize); | |
146 | if (ret & STOP) | 146 | if (ret & STOP) | |
147 | return (ret); | 147 | return (ret); | |
148 | } else { | 148 | } else { | |
149 | if (idesc->id_type == DATA && remsize > 0) { | 149 | if (idesc->id_type == DATA && remsize > 0) { | |
150 | /* An empty block in a directory XXX */ | 150 | /* An empty block in a directory XXX */ | |
151 | markclean = 0; | 151 | markclean = 0; | |
152 | getpathname(pathbuf, sizeof(pathbuf), | 152 | getpathname(pathbuf, sizeof(pathbuf), | |
153 | idesc->id_number, idesc->id_number); | 153 | idesc->id_number, idesc->id_number); | |
154 | pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | 154 | pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | |
155 | pathbuf); | 155 | pathbuf); | |
156 | if (reply("ADJUST LENGTH") == 1) { | 156 | if (reply("ADJUST LENGTH") == 1) { | |
157 | dp = ginode(idesc->id_number); | 157 | dp = ginode(idesc->id_number); | |
158 | DIP_SET(dp, size, | 158 | DIP_SET(dp, size, | |
159 | iswap64(iswap64(DIP(dp, size)) | 159 | iswap64(iswap64(DIP(dp, size)) | |
160 | - remsize)); | 160 | - remsize)); | |
161 | remsize = 0; | 161 | remsize = 0; | |
162 | printf( | 162 | printf( | |
163 | "YOU MUST RERUN FSCK AFTERWARDS\n"); | 163 | "YOU MUST RERUN FSCK AFTERWARDS\n"); | |
164 | rerun = 1; | 164 | rerun = 1; | |
165 | inodirty(); | 165 | inodirty(); | |
166 | break; | 166 | break; | |
167 | } | 167 | } | |
168 | } | 168 | } | |
169 | } | 169 | } | |
170 | sizepb *= FFS_NINDIR(sblock); | 170 | sizepb *= FFS_NINDIR(sblock); | |
171 | remsize -= sizepb; | 171 | remsize -= sizepb; | |
172 | } | 172 | } | |
173 | return (KEEPON); | 173 | return (KEEPON); | |
174 | } | 174 | } | |
175 | 175 | |||
176 | static int | 176 | static int | |
177 | iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) | 177 | iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) | |
178 | { | 178 | { | |
179 | struct bufarea *bp; | 179 | struct bufarea *bp; | |
180 | int i, n, (*func) (struct inodesc *), nif; | 180 | int i, n, (*func) (struct inodesc *), nif; | |
181 | u_int64_t sizepb; | 181 | u_int64_t sizepb; | |
182 | char buf[BUFSIZ]; | 182 | char buf[BUFSIZ]; | |
183 | char pathbuf[MAXPATHLEN + 1]; | 183 | char pathbuf[MAXPATHLEN + 1]; | |
184 | union dinode *dp; | 184 | union dinode *dp; | |
185 | 185 | |||
186 | if (idesc->id_type != DATA) { | 186 | if (idesc->id_type != DATA) { | |
187 | func = idesc->id_func; | 187 | func = idesc->id_func; | |
188 | if (((n = (*func)(idesc)) & KEEPON) == 0) | 188 | if (((n = (*func)(idesc)) & KEEPON) == 0) | |
189 | return (n); | 189 | return (n); | |
190 | } else | 190 | } else | |
191 | func = dirscan; | 191 | func = dirscan; | |
192 | if (chkrange(idesc->id_blkno, idesc->id_numfrags)) | 192 | if (chkrange(idesc->id_blkno, idesc->id_numfrags)) | |
193 | return (SKIP); | 193 | return (SKIP); | |
194 | bp = getdatablk(idesc->id_blkno, sblock->fs_bsize); | 194 | bp = getdatablk(idesc->id_blkno, sblock->fs_bsize); | |
195 | ilevel--; | 195 | ilevel--; | |
196 | for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++) | 196 | for (sizepb = sblock->fs_bsize, i = 0; i < ilevel; i++) | |
197 | sizepb *= FFS_NINDIR(sblock); | 197 | sizepb *= FFS_NINDIR(sblock); | |
198 | if (howmany(isize, sizepb) > (size_t)FFS_NINDIR(sblock)) | 198 | if (howmany(isize, sizepb) > (size_t)FFS_NINDIR(sblock)) | |
199 | nif = FFS_NINDIR(sblock); | 199 | nif = FFS_NINDIR(sblock); | |
200 | else | 200 | else | |
201 | nif = howmany(isize, sizepb); | 201 | nif = howmany(isize, sizepb); | |
202 | if (do_blkswap) { /* swap byte order of the whole blk */ | 202 | if (do_blkswap) { /* swap byte order of the whole blk */ | |
203 | if (is_ufs2) { | 203 | if (is_ufs2) { | |
204 | for (i = 0; i < nif; i++) | 204 | for (i = 0; i < nif; i++) | |
205 | bp->b_un.b_indir2[i] = | 205 | bp->b_un.b_indir2[i] = | |
206 | bswap64(bp->b_un.b_indir2[i]); | 206 | bswap64(bp->b_un.b_indir2[i]); | |
207 | } else { | 207 | } else { | |
208 | for (i = 0; i < nif; i++) | 208 | for (i = 0; i < nif; i++) | |
209 | bp->b_un.b_indir1[i] = | 209 | bp->b_un.b_indir1[i] = | |
210 | bswap32(bp->b_un.b_indir1[i]); | 210 | bswap32(bp->b_un.b_indir1[i]); | |
211 | } | 211 | } | |
212 | dirty(bp); | 212 | dirty(bp); | |
213 | flush(fswritefd, bp); | 213 | flush(fswritefd, bp); | |
214 | } | 214 | } | |
215 | if (idesc->id_func == pass1check && nif < FFS_NINDIR(sblock)) { | 215 | if (idesc->id_func == pass1check && nif < FFS_NINDIR(sblock)) { | |
216 | for (i = nif; i < FFS_NINDIR(sblock); i++) { | 216 | for (i = nif; i < FFS_NINDIR(sblock); i++) { | |
217 | if (IBLK(bp, i) == 0) | 217 | if (IBLK(bp, i) == 0) | |
218 | continue; | 218 | continue; | |
219 | (void)snprintf(buf, sizeof(buf), | 219 | (void)snprintf(buf, sizeof(buf), | |
220 | "PARTIALLY TRUNCATED INODE I=%llu", | 220 | "PARTIALLY TRUNCATED INODE I=%llu", | |
221 | (unsigned long long)idesc->id_number); | 221 | (unsigned long long)idesc->id_number); | |
222 | if (dofix(idesc, buf)) { | 222 | if (dofix(idesc, buf)) { | |
223 | IBLK_SET(bp, i, 0); | 223 | IBLK_SET(bp, i, 0); | |
224 | dirty(bp); | 224 | dirty(bp); | |
225 | } else | 225 | } else | |
226 | markclean = 0; | 226 | markclean = 0; | |
227 | } | 227 | } | |
228 | flush(fswritefd, bp); | 228 | flush(fswritefd, bp); | |
229 | } | 229 | } | |
230 | for (i = 0; i < nif; i++) { | 230 | for (i = 0; i < nif; i++) { | |
231 | if (IBLK(bp, i)) { | 231 | if (IBLK(bp, i)) { | |
232 | if (is_ufs2) | 232 | if (is_ufs2) | |
233 | idesc->id_blkno = iswap64(bp->b_un.b_indir2[i]); | 233 | idesc->id_blkno = iswap64(bp->b_un.b_indir2[i]); | |
234 | else | 234 | else | |
235 | idesc->id_blkno = iswap32(bp->b_un.b_indir1[i]); | 235 | idesc->id_blkno = iswap32(bp->b_un.b_indir1[i]); | |
236 | if (ilevel == 0) | 236 | if (ilevel == 0) | |
237 | n = (*func)(idesc); | 237 | n = (*func)(idesc); | |
238 | else | 238 | else | |
239 | n = iblock(idesc, ilevel, isize); | 239 | n = iblock(idesc, ilevel, isize); | |
240 | if (n & STOP) { | 240 | if (n & STOP) { | |
241 | bp->b_flags &= ~B_INUSE; | 241 | bp->b_flags &= ~B_INUSE; | |
242 | return (n); | 242 | return (n); | |
243 | } | 243 | } | |
244 | } else { | 244 | } else { | |
245 | if (idesc->id_type == DATA && isize > 0) { | 245 | if (idesc->id_type == DATA && isize > 0) { | |
246 | /* An empty block in a directory XXX */ | 246 | /* An empty block in a directory XXX */ | |
247 | markclean = 0; | 247 | markclean = 0; | |
248 | getpathname(pathbuf, sizeof(pathbuf), | 248 | getpathname(pathbuf, sizeof(pathbuf), | |
249 | idesc->id_number, idesc->id_number); | 249 | idesc->id_number, idesc->id_number); | |
250 | pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | 250 | pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", | |
251 | pathbuf); | 251 | pathbuf); | |
252 | if (reply("ADJUST LENGTH") == 1) { | 252 | if (reply("ADJUST LENGTH") == 1) { | |
253 | dp = ginode(idesc->id_number); | 253 | dp = ginode(idesc->id_number); | |
254 | DIP_SET(dp, size, | 254 | DIP_SET(dp, size, | |
255 | iswap64(iswap64(DIP(dp, size)) | 255 | iswap64(iswap64(DIP(dp, size)) | |
256 | - isize)); | 256 | - isize)); | |
257 | isize = 0; | 257 | isize = 0; | |
258 | printf( | 258 | printf( | |
259 | "YOU MUST RERUN FSCK AFTERWARDS\n"); | 259 | "YOU MUST RERUN FSCK AFTERWARDS\n"); | |
260 | rerun = 1; | 260 | rerun = 1; | |
261 | inodirty(); | 261 | inodirty(); | |
262 | bp->b_flags &= ~B_INUSE; | 262 | bp->b_flags &= ~B_INUSE; | |
263 | return(STOP); | 263 | return(STOP); | |
264 | } | 264 | } | |
265 | } | 265 | } | |
266 | } | 266 | } | |
267 | isize -= sizepb; | 267 | isize -= sizepb; | |
268 | } | 268 | } | |
269 | bp->b_flags &= ~B_INUSE; | 269 | bp->b_flags &= ~B_INUSE; | |
270 | return (KEEPON); | 270 | return (KEEPON); | |
271 | } | 271 | } | |
272 | 272 | |||
273 | /* | 273 | /* | |
274 | * Check that a block in a legal block number. | 274 | * Check that a block in a legal block number. | |
275 | * Return 0 if in range, 1 if out of range. | 275 | * Return 0 if in range, 1 if out of range. | |
276 | */ | 276 | */ | |
277 | int | 277 | int | |
278 | chkrange(daddr_t blk, int cnt) | 278 | chkrange(daddr_t blk, int cnt) | |
279 | { | 279 | { | |
280 | int c; | 280 | int c; | |
281 | 281 | |||
282 | if (cnt <= 0 || blk <= 0 || blk > maxfsblock || | 282 | if (cnt <= 0 || blk <= 0 || blk > maxfsblock || | |
283 | cnt - 1 > maxfsblock - blk) | 283 | cnt - 1 > maxfsblock - blk) | |
284 | return (1); | 284 | return (1); | |
285 | if (cnt > sblock->fs_frag || | 285 | if (cnt > sblock->fs_frag || | |
286 | ffs_fragnum(sblock, blk) + cnt > sblock->fs_frag) { | 286 | ffs_fragnum(sblock, blk) + cnt > sblock->fs_frag) { | |
287 | if (debug) | 287 | if (debug) | |
288 | printf("bad size: blk %lld, offset %d, size %d\n", | 288 | printf("bad size: blk %lld, offset %d, size %d\n", | |
289 | (long long)blk, (int)ffs_fragnum(sblock, blk), cnt); | 289 | (long long)blk, (int)ffs_fragnum(sblock, blk), cnt); | |
290 | } | 290 | } | |
291 | c = dtog(sblock, blk); | 291 | c = dtog(sblock, blk); | |
292 | if (blk < cgdmin(sblock, c)) { | 292 | if (blk < cgdmin(sblock, c)) { | |
293 | if ((blk + cnt) > cgsblock(sblock, c)) { | 293 | if ((blk + cnt) > cgsblock(sblock, c)) { | |
294 | if (debug) { | 294 | if (debug) { | |
295 | printf("blk %lld < cgdmin %lld;", | 295 | printf("blk %lld < cgdmin %lld;", | |
296 | (long long)blk, | 296 | (long long)blk, | |
297 | (long long)cgdmin(sblock, c)); | 297 | (long long)cgdmin(sblock, c)); | |
298 | printf(" blk + cnt %lld > cgsbase %lld\n", | 298 | printf(" blk + cnt %lld > cgsbase %lld\n", | |
299 | (long long)(blk + cnt), | 299 | (long long)(blk + cnt), | |
300 | (long long)cgsblock(sblock, c)); | 300 | (long long)cgsblock(sblock, c)); | |
301 | } | 301 | } | |
302 | return (1); | 302 | return (1); | |
303 | } | 303 | } | |
304 | } else { | 304 | } else { | |
305 | if ((blk + cnt) > cgbase(sblock, c+1)) { | 305 | if ((blk + cnt) > cgbase(sblock, c+1)) { | |
306 | if (debug) { | 306 | if (debug) { | |
307 | printf("blk %lld >= cgdmin %lld;", | 307 | printf("blk %lld >= cgdmin %lld;", | |
308 | (long long)blk, | 308 | (long long)blk, | |
309 | (long long)cgdmin(sblock, c)); | 309 | (long long)cgdmin(sblock, c)); | |
310 | printf(" blk + cnt %lld > sblock->fs_fpg %d\n", | 310 | printf(" blk + cnt %lld > sblock->fs_fpg %d\n", | |
311 | (long long)(blk+cnt), sblock->fs_fpg); | 311 | (long long)(blk+cnt), sblock->fs_fpg); | |
312 | } | 312 | } | |
313 | return (1); | 313 | return (1); | |
314 | } | 314 | } | |
315 | } | 315 | } | |
316 | return (0); | 316 | return (0); | |
317 | } | 317 | } | |
318 | 318 | |||
319 | /* | 319 | /* | |
320 | * General purpose interface for reading inodes. | 320 | * General purpose interface for reading inodes. | |
321 | */ | 321 | */ | |
322 | union dinode * | 322 | union dinode * | |
323 | ginode(ino_t inumber) | 323 | ginode(ino_t inumber) | |
324 | { | 324 | { | |
325 | daddr_t iblk; | 325 | daddr_t iblk; | |
326 | int blkoff; | 326 | int blkoff; | |
327 | 327 | |||
328 | if (inumber < UFS_ROOTINO || inumber > maxino) | 328 | if (inumber < UFS_ROOTINO || inumber > maxino) | |
329 | errexit("bad inode number %llu to ginode", | 329 | errexit("bad inode number %llu to ginode", | |
330 | (unsigned long long)inumber); | 330 | (unsigned long long)inumber); | |
331 | if (startinum == 0 || | 331 | if (startinum == 0 || | |
332 | inumber < startinum || inumber >= startinum + FFS_INOPB(sblock)) { | 332 | inumber < startinum || inumber >= startinum + FFS_INOPB(sblock)) { | |
333 | iblk = ino_to_fsba(sblock, inumber); | 333 | iblk = ino_to_fsba(sblock, inumber); | |
334 | if (pbp != 0) | 334 | if (pbp != 0) | |
335 | pbp->b_flags &= ~B_INUSE; | 335 | pbp->b_flags &= ~B_INUSE; | |
336 | pbp = getdatablk(iblk, sblock->fs_bsize); | 336 | pbp = getdatablk(iblk, sblock->fs_bsize); | |
337 | startinum = (inumber / FFS_INOPB(sblock)) * FFS_INOPB(sblock); | 337 | startinum = (inumber / FFS_INOPB(sblock)) * FFS_INOPB(sblock); | |
338 | } | 338 | } | |
339 | if (is_ufs2) { | 339 | if (is_ufs2) { | |
340 | blkoff = (inumber % FFS_INOPB(sblock)) * DINODE2_SIZE; | 340 | blkoff = (inumber % FFS_INOPB(sblock)) * DINODE2_SIZE; | |
341 | return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); | 341 | return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); | |
342 | } | 342 | } | |
343 | blkoff = (inumber % FFS_INOPB(sblock)) * DINODE1_SIZE; | 343 | blkoff = (inumber % FFS_INOPB(sblock)) * DINODE1_SIZE; | |
344 | return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); | 344 | return ((union dinode *)((caddr_t)pbp->b_un.b_buf + blkoff)); | |
345 | } | 345 | } | |
346 | 346 | |||
347 | #ifndef NO_FFS_EI | 347 | #ifndef NO_FFS_EI | |
348 | static void | 348 | static void | |
349 | swap_dinode1(union dinode *dp, int n) | 349 | swap_dinode1(union dinode *dp, int n) | |
350 | { | 350 | { | |
351 | int i, j; | 351 | int i, j; | |
352 | struct ufs1_dinode *dp1; | 352 | struct ufs1_dinode *dp1; | |
353 | int32_t maxsymlinklen = sblock->fs_maxsymlinklen; | 353 | int32_t maxsymlinklen = sblock->fs_maxsymlinklen; | |
354 | if (isappleufs) | 354 | if (isappleufs) | |
355 | maxsymlinklen = APPLEUFS_MAXSYMLINKLEN; | 355 | maxsymlinklen = APPLEUFS_MAXSYMLINKLEN; | |
356 | 356 | |||
357 | dp1 = (struct ufs1_dinode *)&dp->dp1; | 357 | dp1 = (struct ufs1_dinode *)&dp->dp1; | |
358 | for (i = 0; i < n; i++, dp1++) { | 358 | for (i = 0; i < n; i++, dp1++) { | |
359 | ffs_dinode1_swap(dp1, dp1); | 359 | ffs_dinode1_swap(dp1, dp1); | |
360 | if (((iswap16(dp1->di_mode) & IFMT) != IFLNK) || | 360 | if (((iswap16(dp1->di_mode) & IFMT) != IFLNK) || | |
361 | doinglevel2 || | 361 | doinglevel2 || | |
362 | (maxsymlinklen < 0) || | 362 | (maxsymlinklen < 0) || | |
363 | (iswap64(dp1->di_size) > (uint64_t)maxsymlinklen)) { | 363 | (iswap64(dp1->di_size) > (uint64_t)maxsymlinklen)) { | |
364 | for (j = 0; j < UFS_NDADDR; j++) | 364 | for (j = 0; j < UFS_NDADDR; j++) | |
365 | dp1->di_db[j] = bswap32(dp1->di_db[j]); | 365 | dp1->di_db[j] = bswap32(dp1->di_db[j]); | |
366 | for (j = 0; j < UFS_NIADDR; j++) | 366 | for (j = 0; j < UFS_NIADDR; j++) | |
367 | dp1->di_ib[j] = bswap32(dp1->di_ib[j]); | 367 | dp1->di_ib[j] = bswap32(dp1->di_ib[j]); | |
368 | } | 368 | } | |
369 | } | 369 | } | |
370 | } | 370 | } | |
371 | 371 | |||
372 | static void | 372 | static void | |
373 | swap_dinode2(union dinode *dp, int n) | 373 | swap_dinode2(union dinode *dp, int n) | |
374 | { | 374 | { | |
375 | int i, j; | 375 | int i, j; | |
376 | struct ufs2_dinode *dp2; | 376 | struct ufs2_dinode *dp2; | |
377 | 377 | |||
378 | dp2 = (struct ufs2_dinode *)&dp->dp2; | 378 | dp2 = (struct ufs2_dinode *)&dp->dp2; | |
379 | for (i = 0; i < n; i++, dp2++) { | 379 | for (i = 0; i < n; i++, dp2++) { | |
380 | ffs_dinode2_swap(dp2, dp2); | 380 | ffs_dinode2_swap(dp2, dp2); | |
381 | if ((iswap16(dp2->di_mode) & IFMT) != IFLNK) { | 381 | if ((iswap16(dp2->di_mode) & IFMT) != IFLNK) { | |
382 | for (j = 0; j < UFS_NXADDR; j++) | 382 | for (j = 0; j < UFS_NXADDR; j++) | |
383 | dp2->di_extb[j] = bswap64(dp2->di_extb[j]); | 383 | dp2->di_extb[j] = bswap64(dp2->di_extb[j]); | |
384 | for (j = 0; j < UFS_NDADDR; j++) | 384 | for (j = 0; j < UFS_NDADDR; j++) | |
385 | dp2->di_db[j] = bswap64(dp2->di_db[j]); | 385 | dp2->di_db[j] = bswap64(dp2->di_db[j]); | |
386 | for (j = 0; j < UFS_NIADDR; j++) | 386 | for (j = 0; j < UFS_NIADDR; j++) | |
387 | dp2->di_ib[j] = bswap64(dp2->di_ib[j]); | 387 | dp2->di_ib[j] = bswap64(dp2->di_ib[j]); | |
388 | } | 388 | } | |
389 | } | 389 | } | |
390 | } | 390 | } | |
391 | #endif /* !NO_FFS_EI */ | 391 | #endif /* !NO_FFS_EI */ | |
392 | 392 | |||
393 | /* | 393 | /* | |
394 | * Special purpose version of ginode used to optimize first pass | 394 | * Special purpose version of ginode used to optimize first pass | |
395 | * over all the inodes in numerical order. | 395 | * over all the inodes in numerical order. | |
396 | */ | 396 | */ | |
397 | ino_t nextino, lastinum, lastvalidinum; | 397 | ino_t nextino, lastinum, lastvalidinum; | |
398 | long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; | 398 | long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; | |
399 | union dinode *inodebuf; | 399 | union dinode *inodebuf; | |
400 | 400 | |||
401 | union dinode * | 401 | union dinode * | |
402 | getnextinode(ino_t inumber) | 402 | getnextinode(ino_t inumber) | |
403 | { | 403 | { | |
404 | long size; | 404 | long size; | |
405 | daddr_t dblk; | 405 | daddr_t dblk; | |
406 | static union dinode *dp; | 406 | static union dinode *dp; | |
407 | union dinode *ret; | 407 | union dinode *ret; | |
408 | 408 | |||
409 | if (inumber != nextino++ || inumber > lastvalidinum) | 409 | if (inumber != nextino++ || inumber > lastvalidinum) | |
410 | errexit("bad inode number %llu to nextinode", | 410 | errexit("bad inode number %llu to nextinode", | |
411 | (unsigned long long)inumber); | 411 | (unsigned long long)inumber); | |
412 | 412 | |||
413 | if (inumber >= lastinum) { | 413 | if (inumber >= lastinum) { | |
414 | readcnt++; | 414 | readcnt++; | |
415 | dblk = FFS_FSBTODB(sblock, ino_to_fsba(sblock, lastinum)); | 415 | dblk = FFS_FSBTODB(sblock, ino_to_fsba(sblock, lastinum)); | |
416 | if (readcnt % readpercg == 0) { | 416 | if (readcnt % readpercg == 0) { | |
417 | size = partialsize; | 417 | size = partialsize; | |
418 | lastinum += partialcnt; | 418 | lastinum += partialcnt; | |
419 | } else { | 419 | } else { | |
420 | size = inobufsize; | 420 | size = inobufsize; | |
421 | lastinum += fullcnt; | 421 | lastinum += fullcnt; | |
422 | } | 422 | } | |
423 | (void)bread(fsreadfd, (caddr_t)inodebuf, dblk, size); | 423 | (void)bread(fsreadfd, (caddr_t)inodebuf, dblk, size); | |
424 | if (doswap) { | 424 | if (doswap) { | |
425 | if (is_ufs2) | 425 | if (is_ufs2) | |
426 | swap_dinode2(inodebuf, lastinum - inumber); | 426 | swap_dinode2(inodebuf, lastinum - inumber); | |
427 | else | 427 | else | |
428 | swap_dinode1(inodebuf, lastinum - inumber); | 428 | swap_dinode1(inodebuf, lastinum - inumber); | |
429 | bwrite(fswritefd, (char *)inodebuf, dblk, size); | 429 | bwrite(fswritefd, (char *)inodebuf, dblk, size); | |
430 | } | 430 | } | |
431 | dp = (union dinode *)inodebuf; | 431 | dp = (union dinode *)inodebuf; | |
432 | } | 432 | } | |
433 | ret = dp; | 433 | ret = dp; | |
434 | dp = (union dinode *) | 434 | dp = (union dinode *) | |
435 | ((char *)dp + (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE)); | 435 | ((char *)dp + (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE)); | |
436 | return ret; | 436 | return ret; | |
437 | } | 437 | } | |
438 | 438 | |||
439 | void | 439 | void | |
440 | setinodebuf(ino_t inum) | 440 | setinodebuf(ino_t inum) | |
441 | { | 441 | { | |
442 | 442 | |||
443 | if (inum % sblock->fs_ipg != 0) | 443 | if (inum % sblock->fs_ipg != 0) | |
444 | errexit("bad inode number %llu to setinodebuf", | 444 | errexit("bad inode number %llu to setinodebuf", | |
445 | (unsigned long long)inum); | 445 | (unsigned long long)inum); | |
446 | 446 | |||
447 | lastvalidinum = inum + sblock->fs_ipg - 1; | 447 | lastvalidinum = inum + sblock->fs_ipg - 1; | |
448 | startinum = 0; | 448 | startinum = 0; | |
449 | nextino = inum; | 449 | nextino = inum; | |
450 | lastinum = inum; | 450 | lastinum = inum; | |
451 | readcnt = 0; | 451 | readcnt = 0; | |
452 | if (inodebuf != NULL) | 452 | if (inodebuf != NULL) | |
453 | return; | 453 | return; | |
454 | inobufsize = ffs_blkroundup(sblock, INOBUFSIZE); | 454 | inobufsize = ffs_blkroundup(sblock, INOBUFSIZE); | |
455 | fullcnt = inobufsize / (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); | 455 | fullcnt = inobufsize / (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); | |
456 | readpercg = sblock->fs_ipg / fullcnt; | 456 | readpercg = sblock->fs_ipg / fullcnt; | |
457 | partialcnt = sblock->fs_ipg % fullcnt; | 457 | partialcnt = sblock->fs_ipg % fullcnt; | |
458 | partialsize = partialcnt * (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); | 458 | partialsize = partialcnt * (is_ufs2 ? DINODE2_SIZE : DINODE1_SIZE); | |
459 | if (partialcnt != 0) { | 459 | if (partialcnt != 0) { | |
460 | readpercg++; | 460 | readpercg++; | |
461 | } else { | 461 | } else { | |
462 | partialcnt = fullcnt; | 462 | partialcnt = fullcnt; | |
463 | partialsize = inobufsize; | 463 | partialsize = inobufsize; | |
464 | } | 464 | } | |
465 | if (inodebuf == NULL && | 465 | if (inodebuf == NULL && | |
466 | (inodebuf = malloc((unsigned)inobufsize)) == NULL) | 466 | (inodebuf = aligned_alloc(DEV_BSIZE, (unsigned)inobufsize)) == NULL) | |
467 | errexit("Cannot allocate space for inode buffer"); | 467 | errexit("Cannot allocate space for inode buffer"); | |
468 | } | 468 | } | |
469 | 469 | |||
470 | void | 470 | void | |
471 | freeinodebuf(void) | 471 | freeinodebuf(void) | |
472 | { | 472 | { | |
473 | 473 | |||
474 | if (inodebuf != NULL) | 474 | if (inodebuf != NULL) | |
475 | free((char *)inodebuf); | 475 | free((char *)inodebuf); | |
476 | inodebuf = NULL; | 476 | inodebuf = NULL; | |
477 | } | 477 | } | |
478 | 478 | |||
479 | /* | 479 | /* | |
480 | * Routines to maintain information about directory inodes. | 480 | * Routines to maintain information about directory inodes. | |
481 | * This is built during the first pass and used during the | 481 | * This is built during the first pass and used during the | |
482 | * second and third passes. | 482 | * second and third passes. | |
483 | * | 483 | * | |
484 | * Enter inodes into the cache. | 484 | * Enter inodes into the cache. | |
485 | */ | 485 | */ | |
486 | void | 486 | void | |
487 | cacheino(union dinode *dp, ino_t inumber) | 487 | cacheino(union dinode *dp, ino_t inumber) | |
488 | { | 488 | { | |
489 | struct inoinfo *inp; | 489 | struct inoinfo *inp; | |
490 | struct inoinfo **inpp, **ninpsort; | 490 | struct inoinfo **inpp, **ninpsort; | |
491 | unsigned int i, blks, extra; | 491 | unsigned int i, blks, extra; | |
492 | int64_t size; | 492 | int64_t size; | |
493 | 493 | |||
494 | size = iswap64(DIP(dp, size)); | 494 | size = iswap64(DIP(dp, size)); | |
495 | blks = howmany(size, sblock->fs_bsize); | 495 | blks = howmany(size, sblock->fs_bsize); | |
496 | if (blks > UFS_NDADDR) | 496 | if (blks > UFS_NDADDR) | |
497 | blks = UFS_NDADDR + UFS_NIADDR; | 497 | blks = UFS_NDADDR + UFS_NIADDR; | |
498 | if (blks > 0) | 498 | if (blks > 0) | |
499 | extra = (blks - 1) * sizeof (int64_t); | 499 | extra = (blks - 1) * sizeof (int64_t); | |
500 | else | 500 | else | |
501 | extra = 0; | 501 | extra = 0; | |
502 | inp = malloc(sizeof(*inp) + extra); | 502 | inp = malloc(sizeof(*inp) + extra); | |
503 | if (inp == NULL) | 503 | if (inp == NULL) | |
504 | return; | 504 | return; | |
505 | inpp = &inphead[inumber % dirhash]; | 505 | inpp = &inphead[inumber % dirhash]; | |
506 | inp->i_nexthash = *inpp; | 506 | inp->i_nexthash = *inpp; | |
507 | *inpp = inp; | 507 | *inpp = inp; | |
508 | inp->i_child = inp->i_sibling = 0; | 508 | inp->i_child = inp->i_sibling = 0; | |
509 | if (inumber == UFS_ROOTINO) | 509 | if (inumber == UFS_ROOTINO) | |
510 | inp->i_parent = UFS_ROOTINO; | 510 | inp->i_parent = UFS_ROOTINO; | |
511 | else | 511 | else | |
512 | inp->i_parent = (ino_t)0; | 512 | inp->i_parent = (ino_t)0; | |
513 | inp->i_dotdot = (ino_t)0; | 513 | inp->i_dotdot = (ino_t)0; | |
514 | inp->i_number = inumber; | 514 | inp->i_number = inumber; | |
515 | inp->i_isize = size; | 515 | inp->i_isize = size; | |
516 | inp->i_numblks = blks; | 516 | inp->i_numblks = blks; | |
517 | for (i = 0; i < (blks < UFS_NDADDR ? blks : UFS_NDADDR); i++) | 517 | for (i = 0; i < (blks < UFS_NDADDR ? blks : UFS_NDADDR); i++) | |
518 | inp->i_blks[i] = DIP(dp, db[i]); | 518 | inp->i_blks[i] = DIP(dp, db[i]); | |
519 | if (blks > UFS_NDADDR) | 519 | if (blks > UFS_NDADDR) | |
520 | for (i = 0; i < UFS_NIADDR; i++) | 520 | for (i = 0; i < UFS_NIADDR; i++) | |
521 | inp->i_blks[UFS_NDADDR + i] = DIP(dp, ib[i]); | 521 | inp->i_blks[UFS_NDADDR + i] = DIP(dp, ib[i]); | |
522 | if (inplast == listmax) { | 522 | if (inplast == listmax) { | |
523 | ninpsort = (struct inoinfo **)realloc((char *)inpsort, | 523 | ninpsort = (struct inoinfo **)realloc((char *)inpsort, | |
524 | (unsigned)(listmax + 100) * sizeof(struct inoinfo *)); | 524 | (unsigned)(listmax + 100) * sizeof(struct inoinfo *)); | |
525 | if (inpsort == NULL) | 525 | if (inpsort == NULL) | |
526 | errexit("cannot increase directory list"); | 526 | errexit("cannot increase directory list"); | |
527 | inpsort = ninpsort; | 527 | inpsort = ninpsort; | |
528 | listmax += 100; | 528 | listmax += 100; | |
529 | } | 529 | } | |
530 | inpsort[inplast++] = inp; | 530 | inpsort[inplast++] = inp; | |
531 | } | 531 | } | |
532 | 532 | |||
533 | /* | 533 | /* | |
534 | * Look up an inode cache structure. | 534 | * Look up an inode cache structure. | |
535 | */ | 535 | */ | |
536 | struct inoinfo * | 536 | struct inoinfo * | |
537 | getinoinfo(ino_t inumber) | 537 | getinoinfo(ino_t inumber) | |
538 | { | 538 | { | |
539 | struct inoinfo *inp; | 539 | struct inoinfo *inp; | |
540 | 540 | |||
541 | for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { | 541 | for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { | |
542 | if (inp->i_number != inumber) | 542 | if (inp->i_number != inumber) | |
543 | continue; | 543 | continue; | |
544 | return (inp); | 544 | return (inp); | |
545 | } | 545 | } | |
546 | errexit("cannot find inode %llu", (unsigned long long)inumber); | 546 | errexit("cannot find inode %llu", (unsigned long long)inumber); | |
547 | return ((struct inoinfo *)0); | 547 | return ((struct inoinfo *)0); | |
548 | } | 548 | } | |
549 | 549 | |||
550 | /* | 550 | /* | |
551 | * Clean up all the inode cache structure. | 551 | * Clean up all the inode cache structure. | |
552 | */ | 552 | */ | |
553 | void | 553 | void | |
554 | inocleanup(void) | 554 | inocleanup(void) | |
555 | { | 555 | { | |
556 | struct inoinfo **inpp; | 556 | struct inoinfo **inpp; | |
557 | 557 | |||
558 | if (inphead == NULL) | 558 | if (inphead == NULL) | |
559 | return; | 559 | return; | |
560 | for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) | 560 | for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) | |
561 | free((char *)(*inpp)); | 561 | free((char *)(*inpp)); | |
562 | free((char *)inphead); | 562 | free((char *)inphead); | |
563 | free((char *)inpsort); | 563 | free((char *)inpsort); | |
564 | inphead = inpsort = NULL; | 564 | inphead = inpsort = NULL; | |
565 | } | 565 | } | |
566 | 566 | |||
567 | void | 567 | void | |
568 | inodirty(void) | 568 | inodirty(void) | |
569 | { | 569 | { | |
570 | 570 | |||
571 | dirty(pbp); | 571 | dirty(pbp); | |
572 | } | 572 | } | |
573 | 573 | |||
574 | void | 574 | void | |
575 | clri(struct inodesc *idesc, const char *type, int flag) | 575 | clri(struct inodesc *idesc, const char *type, int flag) | |
576 | { | 576 | { | |
577 | union dinode *dp; | 577 | union dinode *dp; | |
578 | 578 | |||
579 | dp = ginode(idesc->id_number); | 579 | dp = ginode(idesc->id_number); | |
580 | if (flag == 1) { | 580 | if (flag == 1) { | |
581 | pwarn("%s %s", type, | 581 | pwarn("%s %s", type, | |
582 | (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE"); | 582 | (iswap16(DIP(dp, mode)) & IFMT) == IFDIR ? "DIR" : "FILE"); | |
583 | pinode(idesc->id_number); | 583 | pinode(idesc->id_number); | |
584 | } | 584 | } | |
585 | if (preen || reply("CLEAR") == 1) { | 585 | if (preen || reply("CLEAR") == 1) { | |
586 | if (preen) | 586 | if (preen) | |
587 | printf(" (CLEARED)\n"); | 587 | printf(" (CLEARED)\n"); | |
588 | n_files--; | 588 | n_files--; | |
589 | /* | 589 | /* | |
590 | * ckinode will call id_func (actually always pass4check) | 590 | * ckinode will call id_func (actually always pass4check) | |
591 | * which will update the block count | 591 | * which will update the block count | |
592 | */ | 592 | */ | |
593 | if (idesc->id_type != SNAP) | 593 | if (idesc->id_type != SNAP) | |
594 | update_uquot(idesc->id_number, | 594 | update_uquot(idesc->id_number, | |
595 | idesc->id_uid, idesc->id_gid, 0, -1); | 595 | idesc->id_uid, idesc->id_gid, 0, -1); | |
596 | (void)ckinode(dp, idesc); | 596 | (void)ckinode(dp, idesc); | |
597 | clearinode(dp); | 597 | clearinode(dp); | |
598 | inoinfo(idesc->id_number)->ino_state = USTATE; | 598 | inoinfo(idesc->id_number)->ino_state = USTATE; | |
599 | inodirty(); | 599 | inodirty(); | |
600 | } else | 600 | } else | |
601 | markclean = 0; | 601 | markclean = 0; | |
602 | } | 602 | } | |
603 | 603 | |||
604 | int | 604 | int | |
605 | findname(struct inodesc *idesc) | 605 | findname(struct inodesc *idesc) | |
606 | { | 606 | { | |
607 | struct direct *dirp = idesc->id_dirp; | 607 | struct direct *dirp = idesc->id_dirp; | |
608 | size_t len; | 608 | size_t len; | |
609 | char *buf; | 609 | char *buf; | |
610 | 610 | |||
611 | if (iswap32(dirp->d_ino) != idesc->id_parent || idesc->id_entryno < 2) { | 611 | if (iswap32(dirp->d_ino) != idesc->id_parent || idesc->id_entryno < 2) { | |
612 | idesc->id_entryno++; | 612 | idesc->id_entryno++; | |
613 | return (KEEPON); | 613 | return (KEEPON); | |
614 | } | 614 | } | |
615 | if ((len = dirp->d_namlen + 1) > MAXPATHLEN) { | 615 | if ((len = dirp->d_namlen + 1) > MAXPATHLEN) { | |
616 | /* XXX: We don't fix but we ignore */ | 616 | /* XXX: We don't fix but we ignore */ | |
617 | len = MAXPATHLEN; | 617 | len = MAXPATHLEN; | |
618 | } | 618 | } | |
619 | /* this is namebuf from utilities.c */ | 619 | /* this is namebuf from utilities.c */ | |
620 | buf = __UNCONST(idesc->id_name); | 620 | buf = __UNCONST(idesc->id_name); | |
621 | (void)memcpy(buf, dirp->d_name, (size_t)dirp->d_namlen + 1); | 621 | (void)memcpy(buf, dirp->d_name, (size_t)dirp->d_namlen + 1); | |
622 | return (STOP|FOUND); | 622 | return (STOP|FOUND); | |
623 | } | 623 | } | |
624 | 624 | |||
625 | int | 625 | int | |
626 | findino(struct inodesc *idesc) | 626 | findino(struct inodesc *idesc) | |
627 | { | 627 | { | |
628 | struct direct *dirp = idesc->id_dirp; | 628 | struct direct *dirp = idesc->id_dirp; | |
629 | 629 | |||
630 | if (dirp->d_ino == 0) | 630 | if (dirp->d_ino == 0) | |
631 | return (KEEPON); | 631 | return (KEEPON); | |
632 | if (strcmp(dirp->d_name, idesc->id_name) == 0 && | 632 | if (strcmp(dirp->d_name, idesc->id_name) == 0 && | |
633 | iswap32(dirp->d_ino) >= UFS_ROOTINO && iswap32(dirp->d_ino) <= maxino) { | 633 | iswap32(dirp->d_ino) >= UFS_ROOTINO && iswap32(dirp->d_ino) <= maxino) { | |
634 | idesc->id_parent = iswap32(dirp->d_ino); | 634 | idesc->id_parent = iswap32(dirp->d_ino); | |
635 | return (STOP|FOUND); | 635 | return (STOP|FOUND); | |
636 | } | 636 | } | |
637 | return (KEEPON); | 637 | return (KEEPON); | |
638 | } | 638 | } | |
639 | 639 | |||
640 | int | 640 | int | |
641 | clearentry(struct inodesc *idesc) | 641 | clearentry(struct inodesc *idesc) | |
642 | { | 642 | { | |
643 | struct direct *dirp = idesc->id_dirp; | 643 | struct direct *dirp = idesc->id_dirp; | |
644 | 644 | |||
645 | if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { | 645 | if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { | |
646 | idesc->id_entryno++; | 646 | idesc->id_entryno++; | |
647 | return (KEEPON); | 647 | return (KEEPON); | |
648 | } | 648 | } | |
649 | dirp->d_ino = 0; | 649 | dirp->d_ino = 0; | |
650 | return (STOP|FOUND|ALTERED); | 650 | return (STOP|FOUND|ALTERED); | |
651 | } | 651 | } | |
652 | 652 | |||
653 | void | 653 | void | |
654 | pinode(ino_t ino) | 654 | pinode(ino_t ino) | |
655 | { | 655 | { | |
656 | union dinode *dp; | 656 | union dinode *dp; | |
657 | struct passwd *pw; | 657 | struct passwd *pw; | |
658 | 658 | |||
659 | printf(" I=%llu ", (unsigned long long)ino); | 659 | printf(" I=%llu ", (unsigned long long)ino); | |
660 | if (ino < UFS_ROOTINO || ino > maxino) | 660 | if (ino < UFS_ROOTINO || ino > maxino) | |
661 | return; | 661 | return; | |
662 | dp = ginode(ino); | 662 | dp = ginode(ino); | |
663 | printf(" OWNER="); | 663 | printf(" OWNER="); | |
664 | #ifndef SMALL | 664 | #ifndef SMALL | |
665 | if (Uflag && (pw = getpwuid((int)iswap32(DIP(dp, uid)))) != 0) | 665 | if (Uflag && (pw = getpwuid((int)iswap32(DIP(dp, uid)))) != 0) | |
666 | printf("%s ", pw->pw_name); | 666 | printf("%s ", pw->pw_name); | |
667 | else | 667 | else | |
668 | #endif | 668 | #endif | |
669 | printf("%u ", (unsigned)iswap32(DIP(dp, uid))); | 669 | printf("%u ", (unsigned)iswap32(DIP(dp, uid))); | |
670 | printf("MODE=%o\n", iswap16(DIP(dp, mode))); | 670 | printf("MODE=%o\n", iswap16(DIP(dp, mode))); | |
671 | if (preen) | 671 | if (preen) | |
672 | printf("%s: ", cdevname()); | 672 | printf("%s: ", cdevname()); | |
673 | printf("SIZE=%llu ", (unsigned long long)iswap64(DIP(dp, size))); | 673 | printf("SIZE=%llu ", (unsigned long long)iswap64(DIP(dp, size))); | |
674 | printf("MTIME=%s ", print_mtime(iswap32(DIP(dp, mtime)))); | 674 | printf("MTIME=%s ", print_mtime(iswap32(DIP(dp, mtime)))); | |
675 | } | 675 | } | |
676 | 676 | |||
677 | void | 677 | void | |
678 | blkerror(ino_t ino, const char *type, daddr_t blk) | 678 | blkerror(ino_t ino, const char *type, daddr_t blk) | |
679 | { | 679 | { | |
680 | struct inostat *info; | 680 | struct inostat *info; | |
681 | 681 | |||
682 | pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino); | 682 | pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino); | |
683 | printf("\n"); | 683 | printf("\n"); | |
684 | info = inoinfo(ino); | 684 | info = inoinfo(ino); | |
685 | switch (info->ino_state) { | 685 | switch (info->ino_state) { | |
686 | 686 | |||
687 | case FSTATE: | 687 | case FSTATE: | |
688 | info->ino_state = FCLEAR; | 688 | info->ino_state = FCLEAR; | |
689 | return; | 689 | return; | |
690 | 690 | |||
691 | case DSTATE: | 691 | case DSTATE: | |
692 | info->ino_state = DCLEAR; | 692 | info->ino_state = DCLEAR; | |
693 | return; | 693 | return; | |
694 | 694 | |||
695 | case FCLEAR: | 695 | case FCLEAR: | |
696 | case DCLEAR: | 696 | case DCLEAR: | |
697 | return; | 697 | return; | |
698 | 698 | |||
699 | default: | 699 | default: | |
700 | errexit("BAD STATE %d TO BLKERR", info->ino_state); | 700 | errexit("BAD STATE %d TO BLKERR", info->ino_state); | |
701 | /* NOTREACHED */ | 701 | /* NOTREACHED */ | |
702 | } | 702 | } | |
703 | } | 703 | } | |
704 | 704 | |||
705 | /* | 705 | /* | |
706 | * allocate an unused inode | 706 | * allocate an unused inode | |
707 | */ | 707 | */ | |
708 | ino_t | 708 | ino_t | |
709 | allocino(ino_t request, int type) | 709 | allocino(ino_t request, int type) | |
710 | { | 710 | { | |
711 | ino_t ino; | 711 | ino_t ino; | |
712 | union dinode *dp; | 712 | union dinode *dp; | |
713 | struct ufs1_dinode *dp1; | 713 | struct ufs1_dinode *dp1; | |
714 | struct ufs2_dinode *dp2; | 714 | struct ufs2_dinode *dp2; | |
715 | time_t t; | 715 | time_t t; | |
716 | struct cg *cgp = cgrp; | 716 | struct cg *cgp = cgrp; | |
717 | int cg; | 717 | int cg; | |
718 | struct inostat *info = NULL; | 718 | struct inostat *info = NULL; | |
719 | int nfrags; | 719 | int nfrags; | |
720 | 720 | |||
721 | if (request == 0) | 721 | if (request == 0) | |
722 | request = UFS_ROOTINO; | 722 | request = UFS_ROOTINO; | |
723 | else if (inoinfo(request)->ino_state != USTATE) | 723 | else if (inoinfo(request)->ino_state != USTATE) | |
724 | return (0); | 724 | return (0); | |
725 | for (ino = request; ino < maxino; ino++) { | 725 | for (ino = request; ino < maxino; ino++) { | |
726 | info = inoinfo(ino); | 726 | info = inoinfo(ino); | |
727 | if (info->ino_state == USTATE) | 727 | if (info->ino_state == USTATE) | |
728 | break; | 728 | break; | |
729 | } | 729 | } | |
730 | if (ino == maxino) | 730 | if (ino == maxino) | |
731 | return (0); | 731 | return (0); | |
732 | cg = ino_to_cg(sblock, ino); | 732 | cg = ino_to_cg(sblock, ino); | |
733 | /* If necessary, extend the inoinfo array. grow exponentially */ | 733 | /* If necessary, extend the inoinfo array. grow exponentially */ | |
734 | if ((ino % sblock->fs_ipg) >= (uint64_t)inostathead[cg].il_numalloced) { | 734 | if ((ino % sblock->fs_ipg) >= (uint64_t)inostathead[cg].il_numalloced) { | |
735 | unsigned long newalloced, i; | 735 | unsigned long newalloced, i; | |
736 | newalloced = MIN(sblock->fs_ipg, | 736 | newalloced = MIN(sblock->fs_ipg, | |
737 | MAX(2 * inostathead[cg].il_numalloced, 10)); | 737 | MAX(2 * inostathead[cg].il_numalloced, 10)); | |
738 | info = calloc(newalloced, sizeof(struct inostat)); | 738 | info = calloc(newalloced, sizeof(struct inostat)); | |
739 | if (info == NULL) { | 739 | if (info == NULL) { | |
740 | pwarn("cannot alloc %lu bytes to extend inoinfo\n", | 740 | pwarn("cannot alloc %lu bytes to extend inoinfo\n", | |
741 | sizeof(struct inostat) * newalloced); | 741 | sizeof(struct inostat) * newalloced); | |
742 | return 0; | 742 | return 0; | |
743 | } | 743 | } | |
744 | memmove(info, inostathead[cg].il_stat, | 744 | memmove(info, inostathead[cg].il_stat, | |
745 | inostathead[cg].il_numalloced * sizeof(*info)); | 745 | inostathead[cg].il_numalloced * sizeof(*info)); | |
746 | for (i = inostathead[cg].il_numalloced; i < newalloced; i++) { | 746 | for (i = inostathead[cg].il_numalloced; i < newalloced; i++) { | |
747 | info[i].ino_state = USTATE; | 747 | info[i].ino_state = USTATE; | |
748 | } | 748 | } | |
749 | if (inostathead[cg].il_numalloced) | 749 | if (inostathead[cg].il_numalloced) | |
750 | free(inostathead[cg].il_stat); | 750 | free(inostathead[cg].il_stat); | |
751 | inostathead[cg].il_stat = info; | 751 | inostathead[cg].il_stat = info; | |
752 | inostathead[cg].il_numalloced = newalloced; | 752 | inostathead[cg].il_numalloced = newalloced; | |
753 | info = inoinfo(ino); | 753 | info = inoinfo(ino); | |
754 | } | 754 | } | |
755 | getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); | 755 | getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); | |
756 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | 756 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | |
757 | if ((doswap && !needswap) || (!doswap && needswap)) | 757 | if ((doswap && !needswap) || (!doswap && needswap)) | |
758 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | 758 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | |
759 | if (!cg_chkmagic(cgp, 0)) | 759 | if (!cg_chkmagic(cgp, 0)) | |
760 | pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg); | 760 | pfatal("CG %d: ALLOCINO: BAD MAGIC NUMBER\n", cg); | |
761 | if (doswap) | 761 | if (doswap) | |
762 | cgdirty(); | 762 | cgdirty(); | |
763 | setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); | 763 | setbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); | |
764 | cgp->cg_cs.cs_nifree--; | 764 | cgp->cg_cs.cs_nifree--; | |
765 | sblock->fs_cstotal.cs_nifree--; | 765 | sblock->fs_cstotal.cs_nifree--; | |
766 | sblock->fs_cs(fs, cg).cs_nifree--; | 766 | sblock->fs_cs(fs, cg).cs_nifree--; | |
767 | sbdirty(); | 767 | sbdirty(); | |
768 | switch (type & IFMT) { | 768 | switch (type & IFMT) { | |
769 | case IFDIR: | 769 | case IFDIR: | |
770 | info->ino_state = DSTATE; | 770 | info->ino_state = DSTATE; | |
771 | cgp->cg_cs.cs_ndir++; | 771 | cgp->cg_cs.cs_ndir++; | |
772 | nfrags = 1; | 772 | nfrags = 1; | |
773 | break; | 773 | break; | |
774 | case IFREG: | 774 | case IFREG: | |
775 | info->ino_state = FSTATE; | 775 | info->ino_state = FSTATE; | |
776 | nfrags = sblock->fs_frag; | 776 | nfrags = sblock->fs_frag; | |
777 | break; | 777 | break; | |
778 | case IFLNK: | 778 | case IFLNK: | |
779 | info->ino_state = FSTATE; | 779 | info->ino_state = FSTATE; | |
780 | nfrags = 1; | 780 | nfrags = 1; | |
781 | break; | 781 | break; | |
782 | default: | 782 | default: | |
783 | return (0); | 783 | return (0); | |
784 | } | 784 | } | |
785 | cgdirty(); | 785 | cgdirty(); | |
786 | dp = ginode(ino); | 786 | dp = ginode(ino); | |
787 | if (is_ufs2) { | 787 | if (is_ufs2) { | |
788 | dp2 = &dp->dp2; | 788 | dp2 = &dp->dp2; | |
789 | dp2->di_db[0] = iswap64(allocblk(nfrags)); | 789 | dp2->di_db[0] = iswap64(allocblk(nfrags)); | |
790 | if (dp2->di_db[0] == 0) { | 790 | if (dp2->di_db[0] == 0) { | |
791 | info->ino_state = USTATE; | 791 | info->ino_state = USTATE; | |
792 | return (0); | 792 | return (0); | |
793 | } | 793 | } | |
794 | dp2->di_mode = iswap16(type); | 794 | dp2->di_mode = iswap16(type); | |
795 | dp2->di_flags = 0; | 795 | dp2->di_flags = 0; | |
796 | (void)time(&t); | 796 | (void)time(&t); | |
797 | dp2->di_atime = iswap64(t); | 797 | dp2->di_atime = iswap64(t); | |
798 | dp2->di_mtime = dp2->di_ctime = dp2->di_atime; | 798 | dp2->di_mtime = dp2->di_ctime = dp2->di_atime; | |
799 | dp2->di_size = iswap64(ffs_lfragtosize(sblock, nfrags)); | 799 | dp2->di_size = iswap64(ffs_lfragtosize(sblock, nfrags)); | |
800 | dp2->di_blocks = iswap64(btodb(ffs_lfragtosize(sblock, nfrags))); | 800 | dp2->di_blocks = iswap64(btodb(ffs_lfragtosize(sblock, nfrags))); | |
801 | } else { | 801 | } else { | |
802 | dp1 = &dp->dp1; | 802 | dp1 = &dp->dp1; | |
803 | dp1->di_db[0] = iswap32(allocblk(nfrags)); | 803 | dp1->di_db[0] = iswap32(allocblk(nfrags)); | |
804 | if (dp1->di_db[0] == 0) { | 804 | if (dp1->di_db[0] == 0) { | |
805 | info->ino_state = USTATE; | 805 | info->ino_state = USTATE; | |
806 | return (0); | 806 | return (0); | |
807 | } | 807 | } | |
808 | dp1->di_mode = iswap16(type); | 808 | dp1->di_mode = iswap16(type); | |
809 | dp1->di_flags = 0; | 809 | dp1->di_flags = 0; | |
810 | (void)time(&t); | 810 | (void)time(&t); | |
811 | dp1->di_atime = iswap32(t); | 811 | dp1->di_atime = iswap32(t); | |
812 | dp1->di_mtime = dp1->di_ctime = dp1->di_atime; | 812 | dp1->di_mtime = dp1->di_ctime = dp1->di_atime; | |
813 | dp1->di_size = iswap64(ffs_lfragtosize(sblock, nfrags)); | 813 | dp1->di_size = iswap64(ffs_lfragtosize(sblock, nfrags)); | |
814 | dp1->di_blocks = iswap32(btodb(ffs_lfragtosize(sblock, nfrags))); | 814 | dp1->di_blocks = iswap32(btodb(ffs_lfragtosize(sblock, nfrags))); | |
815 | } | 815 | } | |
816 | n_files++; | 816 | n_files++; | |
817 | inodirty(); | 817 | inodirty(); | |
818 | if (newinofmt) | 818 | if (newinofmt) | |
819 | info->ino_type = IFTODT(type); | 819 | info->ino_type = IFTODT(type); | |
820 | return (ino); | 820 | return (ino); | |
821 | } | 821 | } | |
822 | 822 | |||
823 | /* | 823 | /* | |
824 | * deallocate an inode | 824 | * deallocate an inode | |
825 | */ | 825 | */ | |
826 | void | 826 | void | |
827 | freeino(ino_t ino) | 827 | freeino(ino_t ino) | |
828 | { | 828 | { | |
829 | struct inodesc idesc; | 829 | struct inodesc idesc; | |
830 | union dinode *dp; | 830 | union dinode *dp; | |
831 | struct cg *cgp = cgrp; | 831 | struct cg *cgp = cgrp; | |
832 | int cg; | 832 | int cg; | |
833 | 833 | |||
834 | cg = ino_to_cg(sblock, ino); | 834 | cg = ino_to_cg(sblock, ino); | |
835 | getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); | 835 | getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); | |
836 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | 836 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | |
837 | if ((doswap && !needswap) || (!doswap && needswap)) | 837 | if ((doswap && !needswap) || (!doswap && needswap)) | |
838 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | 838 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | |
839 | if (!cg_chkmagic(cgp, 0)) { | 839 | if (!cg_chkmagic(cgp, 0)) { | |
840 | pwarn("CG %d: FREEINO: BAD MAGIC NUMBER\n", cg); | 840 | pwarn("CG %d: FREEINO: BAD MAGIC NUMBER\n", cg); | |
841 | cgp = NULL; | 841 | cgp = NULL; | |
842 | } | 842 | } | |
843 | 843 | |||
844 | memset(&idesc, 0, sizeof(struct inodesc)); | 844 | memset(&idesc, 0, sizeof(struct inodesc)); | |
845 | idesc.id_func = pass4check; | 845 | idesc.id_func = pass4check; | |
846 | idesc.id_number = ino; | 846 | idesc.id_number = ino; | |
847 | dp = ginode(ino); | 847 | dp = ginode(ino); | |
848 | idesc.id_uid = iswap32(DIP(dp, uid)); | 848 | idesc.id_uid = iswap32(DIP(dp, uid)); | |
849 | idesc.id_gid = iswap32(DIP(dp, gid)); | 849 | idesc.id_gid = iswap32(DIP(dp, gid)); | |
850 | if (iswap32(DIP(dp, flags)) & SF_SNAPSHOT) | 850 | if (iswap32(DIP(dp, flags)) & SF_SNAPSHOT) | |
851 | idesc.id_type = SNAP; | 851 | idesc.id_type = SNAP; | |
852 | else | 852 | else | |
853 | idesc.id_type = ADDR; | 853 | idesc.id_type = ADDR; | |
854 | (void)ckinode(dp, &idesc); | 854 | (void)ckinode(dp, &idesc); | |
855 | clearinode(dp); | 855 | clearinode(dp); | |
856 | inodirty(); | 856 | inodirty(); | |
857 | inoinfo(ino)->ino_state = USTATE; | 857 | inoinfo(ino)->ino_state = USTATE; | |
858 | if (idesc.id_type != SNAP) | 858 | if (idesc.id_type != SNAP) | |
859 | update_uquot(idesc.id_number, | 859 | update_uquot(idesc.id_number, | |
860 | idesc.id_uid, idesc.id_gid, 0, -1); | 860 | idesc.id_uid, idesc.id_gid, 0, -1); | |
861 | n_files--; | 861 | n_files--; | |
862 | if (cgp) { | 862 | if (cgp) { | |
863 | clrbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); | 863 | clrbit(cg_inosused(cgp, 0), ino % sblock->fs_ipg); | |
864 | cgp->cg_cs.cs_nifree++; | 864 | cgp->cg_cs.cs_nifree++; | |
865 | sblock->fs_cstotal.cs_nifree++; | 865 | sblock->fs_cstotal.cs_nifree++; | |
866 | sblock->fs_cs(fs, cg).cs_nifree++; | 866 | sblock->fs_cs(fs, cg).cs_nifree++; | |
867 | sbdirty(); | 867 | sbdirty(); | |
868 | cgdirty(); | 868 | cgdirty(); | |
869 | } | 869 | } | |
870 | } | 870 | } | |
871 | 871 | |||
872 | /* read a data block from inode */ | 872 | /* read a data block from inode */ | |
873 | ssize_t | 873 | ssize_t | |
874 | readblk(union dinode *dp, off_t offset, struct bufarea **bp) | 874 | readblk(union dinode *dp, off_t offset, struct bufarea **bp) | |
875 | { | 875 | { | |
876 | daddr_t blkno = ffs_lblkno(sblock, offset); | 876 | daddr_t blkno = ffs_lblkno(sblock, offset); | |
877 | daddr_t iblkno; | 877 | daddr_t iblkno; | |
878 | int type = IFMT & iswap16(DIP(dp, mode)); | 878 | int type = IFMT & iswap16(DIP(dp, mode)); | |
879 | ssize_t filesize = iswap64(DIP(dp, size)); | 879 | ssize_t filesize = iswap64(DIP(dp, size)); | |
880 | int ilevel; | 880 | int ilevel; | |
881 | daddr_t nblks; | 881 | daddr_t nblks; | |
882 | const daddr_t naddrperblk = sblock->fs_bsize / | 882 | const daddr_t naddrperblk = sblock->fs_bsize / | |
883 | (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t)); | 883 | (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t)); | |
884 | struct bufarea *ibp; | 884 | struct bufarea *ibp; | |
885 | 885 | |||
886 | *bp = NULL; | 886 | *bp = NULL; | |
887 | offset &= ~(sblock->fs_bsize - 1); | 887 | offset &= ~(sblock->fs_bsize - 1); | |
888 | 888 | |||
889 | if (type != IFREG) | 889 | if (type != IFREG) | |
890 | return 0; | 890 | return 0; | |
891 | if (offset >= filesize) | 891 | if (offset >= filesize) | |
892 | return 0; /* short read */ | 892 | return 0; /* short read */ | |
893 | if (blkno < UFS_NDADDR) { | 893 | if (blkno < UFS_NDADDR) { | |
894 | blkno = is_ufs2 ? iswap64(dp->dp2.di_db[blkno]) : | 894 | blkno = is_ufs2 ? iswap64(dp->dp2.di_db[blkno]) : | |
895 | iswap32(dp->dp1.di_db[blkno]); | 895 | iswap32(dp->dp1.di_db[blkno]); | |
896 | if (blkno == 0) | 896 | if (blkno == 0) | |
897 | return 0; | 897 | return 0; | |
898 | *bp = getdatablk(blkno, sblock->fs_bsize); | 898 | *bp = getdatablk(blkno, sblock->fs_bsize); | |
899 | return (bp != NULL) ? sblock->fs_bsize : 0; | 899 | return (bp != NULL) ? sblock->fs_bsize : 0; | |
900 | } | 900 | } | |
901 | blkno -= UFS_NDADDR; | 901 | blkno -= UFS_NDADDR; | |
902 | /* find indir level */ | 902 | /* find indir level */ | |
903 | for (ilevel = 1, nblks = naddrperblk; | 903 | for (ilevel = 1, nblks = naddrperblk; | |
904 | ilevel <= UFS_NIADDR; | 904 | ilevel <= UFS_NIADDR; | |
905 | ilevel++, nblks *= naddrperblk) { | 905 | ilevel++, nblks *= naddrperblk) { | |
906 | if (blkno < nblks) | 906 | if (blkno < nblks) | |
907 | break; | 907 | break; | |
908 | else | 908 | else | |
909 | blkno -= nblks; | 909 | blkno -= nblks; | |
910 | } | 910 | } | |
911 | if (ilevel > UFS_NIADDR) | 911 | if (ilevel > UFS_NIADDR) | |
912 | errexit("bad ofsset %" PRIu64 " to readblk", offset); | 912 | errexit("bad ofsset %" PRIu64 " to readblk", offset); | |
913 | 913 | |||
914 | /* get the first indirect block */ | 914 | /* get the first indirect block */ | |
915 | iblkno = is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : | 915 | iblkno = is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : | |
916 | iswap32(dp->dp1.di_ib[ilevel - 1]); | 916 | iswap32(dp->dp1.di_ib[ilevel - 1]); | |
917 | if (iblkno == 0) | 917 | if (iblkno == 0) | |
918 | return 0; | 918 | return 0; | |
919 | ibp = getdatablk(iblkno, sblock->fs_bsize); | 919 | ibp = getdatablk(iblkno, sblock->fs_bsize); | |
920 | /* walk indirect blocks up to the data block */ | 920 | /* walk indirect blocks up to the data block */ | |
921 | for (; ilevel >0 ; ilevel--) { | 921 | for (; ilevel >0 ; ilevel--) { | |
922 | nblks = nblks / naddrperblk; | 922 | nblks = nblks / naddrperblk; | |
923 | if (is_ufs2) | 923 | if (is_ufs2) | |
924 | iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]); | 924 | iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]); | |
925 | else | 925 | else | |
926 | iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]); | 926 | iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]); | |
927 | if (iblkno == 0) | 927 | if (iblkno == 0) | |
928 | return 0; | 928 | return 0; | |
929 | blkno = blkno % nblks; | 929 | blkno = blkno % nblks; | |
930 | ibp->b_flags &= ~B_INUSE; | 930 | ibp->b_flags &= ~B_INUSE; | |
931 | ibp = getdatablk(iblkno, sblock->fs_bsize); | 931 | ibp = getdatablk(iblkno, sblock->fs_bsize); | |
932 | } | 932 | } | |
933 | *bp = ibp; | 933 | *bp = ibp; | |
934 | return sblock->fs_bsize; | 934 | return sblock->fs_bsize; | |
935 | } | 935 | } | |
936 | 936 | |||
937 | static struct bufarea * getnewblk(daddr_t *); | 937 | static struct bufarea * getnewblk(daddr_t *); | |
938 | static struct bufarea * | 938 | static struct bufarea * | |
939 | getnewblk(daddr_t *blkno) | 939 | getnewblk(daddr_t *blkno) | |
940 | { | 940 | { | |
941 | struct bufarea *bp; | 941 | struct bufarea *bp; | |
942 | *blkno = allocblk(sblock->fs_frag); | 942 | *blkno = allocblk(sblock->fs_frag); | |
943 | if (*blkno == 0) | 943 | if (*blkno == 0) | |
944 | return NULL; | 944 | return NULL; | |
945 | bp = getdatablk(*blkno, sblock->fs_bsize); | 945 | bp = getdatablk(*blkno, sblock->fs_bsize); | |
946 | memset(bp->b_un.b_buf, 0, sblock->fs_bsize); | 946 | memset(bp->b_un.b_buf, 0, sblock->fs_bsize); | |
947 | return bp; | 947 | return bp; | |
948 | } | 948 | } | |
949 | 949 | |||
950 | /* expand given inode by one full fs block */ | 950 | /* expand given inode by one full fs block */ | |
951 | struct bufarea * | 951 | struct bufarea * | |
952 | expandfile(union dinode *dp) | 952 | expandfile(union dinode *dp) | |
953 | { | 953 | { | |
954 | uint64_t filesize = iswap64(DIP(dp, size)); | 954 | uint64_t filesize = iswap64(DIP(dp, size)); | |
955 | daddr_t newblk, blkno, iblkno, nblks; | 955 | daddr_t newblk, blkno, iblkno, nblks; | |
956 | daddr_t di_blocks; | 956 | daddr_t di_blocks; | |
957 | int ilevel; | 957 | int ilevel; | |
958 | const daddr_t naddrperblk = sblock->fs_bsize / | 958 | const daddr_t naddrperblk = sblock->fs_bsize / | |
959 | (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t)); | 959 | (is_ufs2 ? sizeof(uint64_t) : sizeof(uint32_t)); | |
960 | struct bufarea *ibp, *bp = NULL; | 960 | struct bufarea *ibp, *bp = NULL; | |
961 | 961 | |||
962 | di_blocks = is_ufs2 ? iswap64(dp->dp2.di_blocks) : | 962 | di_blocks = is_ufs2 ? iswap64(dp->dp2.di_blocks) : | |
963 | iswap32(dp->dp1.di_blocks); | 963 | iswap32(dp->dp1.di_blocks); | |
964 | /* compute location of new block */ | 964 | /* compute location of new block */ | |
965 | blkno = ffs_lblkno(sblock, filesize); | 965 | blkno = ffs_lblkno(sblock, filesize); | |
966 | 966 | |||
967 | if (blkno < UFS_NDADDR) { | 967 | if (blkno < UFS_NDADDR) { | |
968 | /* easy way: allocate a direct block */ | 968 | /* easy way: allocate a direct block */ | |
969 | if ((bp = getnewblk(&newblk)) == NULL) { | 969 | if ((bp = getnewblk(&newblk)) == NULL) { | |
970 | return NULL; | 970 | return NULL; | |
971 | } | 971 | } | |
972 | di_blocks += btodb(sblock->fs_bsize); | 972 | di_blocks += btodb(sblock->fs_bsize); | |
973 | 973 | |||
974 | if (is_ufs2) { | 974 | if (is_ufs2) { | |
975 | dp->dp2.di_db[blkno] = iswap64(newblk); | 975 | dp->dp2.di_db[blkno] = iswap64(newblk); | |
976 | } else { | 976 | } else { | |
977 | dp->dp1.di_db[blkno] = iswap32(newblk); | 977 | dp->dp1.di_db[blkno] = iswap32(newblk); | |
978 | } | 978 | } | |
979 | goto out; | 979 | goto out; | |
980 | } | 980 | } | |
981 | blkno -= UFS_NDADDR; | 981 | blkno -= UFS_NDADDR; | |
982 | /* find indir level */ | 982 | /* find indir level */ | |
983 | for (ilevel = 1, nblks = naddrperblk; | 983 | for (ilevel = 1, nblks = naddrperblk; | |
984 | ilevel <= UFS_NIADDR; | 984 | ilevel <= UFS_NIADDR; | |
985 | ilevel++, nblks *= naddrperblk) { | 985 | ilevel++, nblks *= naddrperblk) { | |
986 | if (blkno < nblks) | 986 | if (blkno < nblks) | |
987 | break; | 987 | break; | |
988 | else | 988 | else | |
989 | blkno -= nblks; | 989 | blkno -= nblks; | |
990 | } | 990 | } | |
991 | if (ilevel > UFS_NIADDR) | 991 | if (ilevel > UFS_NIADDR) | |
992 | errexit("bad filesize %" PRIu64 " to expandfile", filesize); | 992 | errexit("bad filesize %" PRIu64 " to expandfile", filesize); | |
993 | 993 | |||
994 | /* get the first indirect block, allocating if needed */ | 994 | /* get the first indirect block, allocating if needed */ | |
995 | if ((is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : | 995 | if ((is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : | |
996 | iswap32(dp->dp1.di_ib[ilevel - 1])) == 0) { | 996 | iswap32(dp->dp1.di_ib[ilevel - 1])) == 0) { | |
997 | if ((ibp = getnewblk(&newblk)) == NULL) | 997 | if ((ibp = getnewblk(&newblk)) == NULL) | |
998 | return 0; | 998 | return 0; | |
999 | di_blocks += btodb(sblock->fs_bsize); | 999 | di_blocks += btodb(sblock->fs_bsize); | |
1000 | if (is_ufs2) | 1000 | if (is_ufs2) | |
1001 | dp->dp2.di_ib[ilevel - 1] = iswap64(newblk); | 1001 | dp->dp2.di_ib[ilevel - 1] = iswap64(newblk); | |
1002 | else | 1002 | else | |
1003 | dp->dp1.di_ib[ilevel - 1] = iswap32(newblk); | 1003 | dp->dp1.di_ib[ilevel - 1] = iswap32(newblk); | |
1004 | } else { | 1004 | } else { | |
1005 | ibp = getdatablk(is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : | 1005 | ibp = getdatablk(is_ufs2 ? iswap64(dp->dp2.di_ib[ilevel - 1]) : | |
1006 | iswap32(dp->dp1.di_ib[ilevel - 1]), sblock->fs_bsize); | 1006 | iswap32(dp->dp1.di_ib[ilevel - 1]), sblock->fs_bsize); | |
1007 | } | 1007 | } | |
1008 | /* walk indirect blocks up to the data block */ | 1008 | /* walk indirect blocks up to the data block */ | |
1009 | for (; ilevel >0 ; ilevel--) { | 1009 | for (; ilevel >0 ; ilevel--) { | |
1010 | nblks = nblks / naddrperblk; | 1010 | nblks = nblks / naddrperblk; | |
1011 | if (is_ufs2) | 1011 | if (is_ufs2) | |
1012 | iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]); | 1012 | iblkno = iswap64(ibp->b_un.b_indir2[blkno / nblks]); | |
1013 | else | 1013 | else | |
1014 | iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]); | 1014 | iblkno = iswap32(ibp->b_un.b_indir1[blkno / nblks]); | |
1015 | if (iblkno == 0) { | 1015 | if (iblkno == 0) { | |
1016 | if ((bp = getnewblk(&newblk)) == NULL) | 1016 | if ((bp = getnewblk(&newblk)) == NULL) | |
1017 | return NULL; | 1017 | return NULL; | |
1018 | di_blocks += btodb(sblock->fs_bsize); | 1018 | di_blocks += btodb(sblock->fs_bsize); | |
1019 | if (is_ufs2) | 1019 | if (is_ufs2) | |
1020 | ibp->b_un.b_indir2[blkno / nblks] = | 1020 | ibp->b_un.b_indir2[blkno / nblks] = | |
1021 | iswap64(newblk); | 1021 | iswap64(newblk); | |
1022 | else | 1022 | else | |
1023 | ibp->b_un.b_indir1[blkno / nblks] = | 1023 | ibp->b_un.b_indir1[blkno / nblks] = | |
1024 | iswap32(newblk); | 1024 | iswap32(newblk); | |
1025 | dirty(ibp); | 1025 | dirty(ibp); | |
1026 | ibp->b_flags &= ~B_INUSE; | 1026 | ibp->b_flags &= ~B_INUSE; | |
1027 | ibp = bp; | 1027 | ibp = bp; | |
1028 | } else { | 1028 | } else { | |
1029 | ibp->b_flags &= ~B_INUSE; | 1029 | ibp->b_flags &= ~B_INUSE; | |
1030 | ibp = getdatablk(iblkno, sblock->fs_bsize); | 1030 | ibp = getdatablk(iblkno, sblock->fs_bsize); | |
1031 | bp = NULL; | 1031 | bp = NULL; | |
1032 | } | 1032 | } | |
1033 | blkno = blkno % nblks; | 1033 | blkno = blkno % nblks; | |
1034 | } | 1034 | } | |
1035 | if (bp == NULL) { | 1035 | if (bp == NULL) { | |
1036 | errexit("INTERNAL ERROR: " | 1036 | errexit("INTERNAL ERROR: " | |
1037 | "expandfile() failed to allocate a new block\n"); | 1037 | "expandfile() failed to allocate a new block\n"); | |
1038 | } | 1038 | } | |
1039 | 1039 | |||
1040 | out: | 1040 | out: | |
1041 | filesize += sblock->fs_bsize; | 1041 | filesize += sblock->fs_bsize; | |
1042 | if (is_ufs2) { | 1042 | if (is_ufs2) { | |
1043 | dp->dp2.di_size = iswap64(filesize); | 1043 | dp->dp2.di_size = iswap64(filesize); | |
1044 | dp->dp2.di_blocks = iswap64(di_blocks); | 1044 | dp->dp2.di_blocks = iswap64(di_blocks); | |
1045 | } else { | 1045 | } else { | |
1046 | dp->dp1.di_size = iswap64(filesize); | 1046 | dp->dp1.di_size = iswap64(filesize); | |
1047 | dp->dp1.di_blocks = iswap32(di_blocks); | 1047 | dp->dp1.di_blocks = iswap32(di_blocks); | |
1048 | } | 1048 | } | |
1049 | inodirty(); | 1049 | inodirty(); | |
1050 | return bp; | 1050 | return bp; | |
1051 | } | 1051 | } |
--- src/sbin/fsck_ffs/setup.c 2018/10/05 09:49:23 1.102
+++ src/sbin/fsck_ffs/setup.c 2020/04/17 09:42:27 1.103
@@ -1,1144 +1,1147 @@ | @@ -1,1144 +1,1147 @@ | |||
1 | /* $NetBSD: setup.c,v 1.102 2018/10/05 09:49:23 hannken Exp $ */ | 1 | /* $NetBSD: setup.c,v 1.103 2020/04/17 09:42:27 jdolecek Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1980, 1986, 1993 | 4 | * Copyright (c) 1980, 1986, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; | 35 | static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: setup.c,v 1.102 2018/10/05 09:49:23 hannken Exp $"); | 37 | __RCSID("$NetBSD: setup.c,v 1.103 2020/04/17 09:42:27 jdolecek Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | #include <sys/time.h> | 42 | #include <sys/time.h> | |
43 | #include <sys/stat.h> | 43 | #include <sys/stat.h> | |
44 | #include <sys/ioctl.h> | 44 | #include <sys/ioctl.h> | |
45 | #include <sys/file.h> | 45 | #include <sys/file.h> | |
46 | #include <sys/disk.h> | 46 | #include <sys/disk.h> | |
47 | 47 | |||
48 | #include <ufs/ufs/dinode.h> | 48 | #include <ufs/ufs/dinode.h> | |
49 | #include <ufs/ufs/dir.h> | 49 | #include <ufs/ufs/dir.h> | |
50 | #include <ufs/ufs/ufs_bswap.h> | 50 | #include <ufs/ufs/ufs_bswap.h> | |
51 | #include <ufs/ufs/quota2.h> | 51 | #include <ufs/ufs/quota2.h> | |
52 | #include <ufs/ffs/fs.h> | 52 | #include <ufs/ffs/fs.h> | |
53 | #include <ufs/ffs/ffs_extern.h> | 53 | #include <ufs/ffs/ffs_extern.h> | |
54 | 54 | |||
55 | #include <ctype.h> | 55 | #include <ctype.h> | |
56 | #include <err.h> | 56 | #include <err.h> | |
57 | #include <errno.h> | 57 | #include <errno.h> | |
58 | #include <stdio.h> | 58 | #include <stdio.h> | |
59 | #include <stdlib.h> | 59 | #include <stdlib.h> | |
60 | #include <string.h> | 60 | #include <string.h> | |
61 | 61 | |||
62 | #include "fsck.h" | 62 | #include "fsck.h" | |
63 | #include "extern.h" | 63 | #include "extern.h" | |
64 | #include "fsutil.h" | 64 | #include "fsutil.h" | |
65 | #include "partutil.h" | 65 | #include "partutil.h" | |
66 | #include "exitvalues.h" | 66 | #include "exitvalues.h" | |
67 | 67 | |||
68 | #define POWEROF2(num) (((num) & ((num) - 1)) == 0) | 68 | #define POWEROF2(num) (((num) & ((num) - 1)) == 0) | |
69 | 69 | |||
70 | static void badsb(int, const char *); | 70 | static void badsb(int, const char *); | |
71 | static int calcsb(const char *, int, struct fs *); | 71 | static int calcsb(const char *, int, struct fs *); | |
72 | static int readsb(int); | 72 | static int readsb(int); | |
73 | #ifndef NO_APPLE_UFS | 73 | #ifndef NO_APPLE_UFS | |
74 | static int readappleufs(void); | 74 | static int readappleufs(void); | |
75 | #endif | 75 | #endif | |
76 | static int check_snapinum(void); | 76 | static int check_snapinum(void); | |
77 | 77 | |||
78 | int16_t sblkpostbl[256]; | 78 | int16_t sblkpostbl[256]; | |
79 | 79 | |||
80 | /* | 80 | /* | |
81 | * Read in a superblock finding an alternate if necessary. | 81 | * Read in a superblock finding an alternate if necessary. | |
82 | * Return 1 if successful, 0 if unsuccessful, -1 if filesystem | 82 | * Return 1 if successful, 0 if unsuccessful, -1 if filesystem | |
83 | * is already clean (preen mode only). | 83 | * is already clean (preen mode only). | |
84 | */ | 84 | */ | |
85 | int | 85 | int | |
86 | setup(const char *dev, const char *origdev) | 86 | setup(const char *dev, const char *origdev) | |
87 | { | 87 | { | |
88 | long cg, size, asked, i, j; | 88 | long cg, size, asked, i, j; | |
89 | long bmapsize; | 89 | long bmapsize; | |
90 | struct disk_geom geo; | 90 | struct disk_geom geo; | |
91 | struct dkwedge_info dkw; | 91 | struct dkwedge_info dkw; | |
92 | off_t sizepb; | 92 | off_t sizepb; | |
93 | struct stat statb; | 93 | struct stat statb; | |
94 | struct fs proto; | 94 | struct fs proto; | |
95 | int doskipclean; | 95 | int doskipclean; | |
96 | u_int64_t maxfilesize; | 96 | u_int64_t maxfilesize; | |
97 | struct csum *ccsp; | 97 | struct csum *ccsp; | |
98 | int fd; | 98 | int fd; | |
99 | 99 | |||
100 | havesb = 0; | 100 | havesb = 0; | |
101 | fswritefd = -1; | 101 | fswritefd = -1; | |
102 | doskipclean = skipclean; | 102 | doskipclean = skipclean; | |
103 | if (stat(dev, &statb) < 0) { | 103 | if (stat(dev, &statb) < 0) { | |
104 | printf("Can't stat %s: %s\n", dev, strerror(errno)); | 104 | printf("Can't stat %s: %s\n", dev, strerror(errno)); | |
105 | return (0); | 105 | return (0); | |
106 | } | 106 | } | |
107 | if (!forceimage && !S_ISCHR(statb.st_mode)) { | 107 | if (!forceimage && !S_ISCHR(statb.st_mode)) { | |
108 | pfatal("%s is not a character device", dev); | 108 | pfatal("%s is not a character device", dev); | |
109 | if (reply("CONTINUE") == 0) | 109 | if (reply("CONTINUE") == 0) | |
110 | return (0); | 110 | return (0); | |
111 | } | 111 | } | |
112 | if ((fsreadfd = open(dev, O_RDONLY)) < 0) { | 112 | if ((fsreadfd = open(dev, O_RDONLY)) < 0) { | |
113 | printf("Can't open %s: %s\n", dev, strerror(errno)); | 113 | printf("Can't open %s: %s\n", dev, strerror(errno)); | |
114 | return (0); | 114 | return (0); | |
115 | } | 115 | } | |
116 | if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { | 116 | if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { | |
117 | fswritefd = -1; | 117 | fswritefd = -1; | |
118 | if (preen) | 118 | if (preen) | |
119 | pfatal("NO WRITE ACCESS"); | 119 | pfatal("NO WRITE ACCESS"); | |
120 | printf("** %s (NO WRITE)\n", dev); | 120 | printf("** %s (NO WRITE)\n", dev); | |
121 | quiet = 0; | 121 | quiet = 0; | |
122 | } else | 122 | } else | |
123 | if (!preen && !quiet) | 123 | if (!preen && !quiet) | |
124 | printf("** %s\n", dev); | 124 | printf("** %s\n", dev); | |
125 | fsmodified = 0; | 125 | fsmodified = 0; | |
126 | lfdir = 0; | 126 | lfdir = 0; | |
127 | initbarea(&sblk); | 127 | initbarea(&sblk); | |
128 | initbarea(&asblk); | 128 | initbarea(&asblk); | |
129 | sblk.b_un.b_buf = malloc(SBLOCKSIZE); | 129 | sblk.b_un.b_buf = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); | |
130 | sblock = malloc(SBLOCKSIZE); | 130 | sblock = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); | |
131 | asblk.b_un.b_buf = malloc(SBLOCKSIZE); | 131 | asblk.b_un.b_buf = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); | |
132 | altsblock = malloc(SBLOCKSIZE); | 132 | altsblock = aligned_alloc(DEV_BSIZE, SBLOCKSIZE); | |
133 | if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL || | 133 | if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL || | |
134 | sblock == NULL || altsblock == NULL) | 134 | sblock == NULL || altsblock == NULL) | |
135 | errexit("Cannot allocate space for superblock"); | 135 | errexit("Cannot allocate space for superblock"); | |
136 | if (strcmp(dev, origdev) && !forceimage) { | 136 | if (strcmp(dev, origdev) && !forceimage) { | |
137 | /* | 137 | /* | |
138 | * dev isn't the original fs (for example it's a snapshot) | 138 | * dev isn't the original fs (for example it's a snapshot) | |
139 | * do getdiskinfo on the original device | 139 | * do getdiskinfo on the original device | |
140 | */ | 140 | */ | |
141 | fd = open(origdev, O_RDONLY); | 141 | fd = open(origdev, O_RDONLY); | |
142 | if (fd < 0) { | 142 | if (fd < 0) { | |
143 | warn("Can't open %s", origdev); | 143 | warn("Can't open %s", origdev); | |
144 | return (0); | 144 | return (0); | |
145 | } | 145 | } | |
146 | } else { | 146 | } else { | |
147 | fd = fsreadfd; | 147 | fd = fsreadfd; | |
148 | } | 148 | } | |
149 | if (!forceimage && getdiskinfo(origdev, fd, NULL, &geo, &dkw) != -1) | 149 | if (!forceimage && getdiskinfo(origdev, fd, NULL, &geo, &dkw) != -1) | |
150 | dev_bsize = secsize = geo.dg_secsize; | 150 | dev_bsize = secsize = geo.dg_secsize; | |
151 | else | 151 | else | |
152 | dev_bsize = secsize = DEV_BSIZE; | 152 | dev_bsize = secsize = DEV_BSIZE; | |
153 | /* | 153 | /* | |
154 | * Read in the superblock, looking for alternates if necessary | 154 | * Read in the superblock, looking for alternates if necessary | |
155 | */ | 155 | */ | |
156 | if (readsb(1) == 0) { | 156 | if (readsb(1) == 0) { | |
157 | if (bflag || preen || forceimage || | 157 | if (bflag || preen || forceimage || | |
158 | calcsb(dev, fsreadfd, &proto) == 0) | 158 | calcsb(dev, fsreadfd, &proto) == 0) | |
159 | return(0); | 159 | return(0); | |
160 | if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) | 160 | if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) | |
161 | return (0); | 161 | return (0); | |
162 | for (cg = 0; cg < proto.fs_ncg; cg++) { | 162 | for (cg = 0; cg < proto.fs_ncg; cg++) { | |
163 | bflag = FFS_FSBTODB(&proto, cgsblock(&proto, cg)); | 163 | bflag = FFS_FSBTODB(&proto, cgsblock(&proto, cg)); | |
164 | if (readsb(0) != 0) | 164 | if (readsb(0) != 0) | |
165 | break; | 165 | break; | |
166 | } | 166 | } | |
167 | if (cg >= proto.fs_ncg) { | 167 | if (cg >= proto.fs_ncg) { | |
168 | printf("%s %s\n%s %s\n%s %s\n", | 168 | printf("%s %s\n%s %s\n%s %s\n", | |
169 | "SEARCH FOR ALTERNATE SUPER-BLOCK", | 169 | "SEARCH FOR ALTERNATE SUPER-BLOCK", | |
170 | "FAILED. YOU MUST USE THE", | 170 | "FAILED. YOU MUST USE THE", | |
171 | "-b OPTION TO fsck_ffs TO SPECIFY THE", | 171 | "-b OPTION TO fsck_ffs TO SPECIFY THE", | |
172 | "LOCATION OF AN ALTERNATE", | 172 | "LOCATION OF AN ALTERNATE", | |
173 | "SUPER-BLOCK TO SUPPLY NEEDED", | 173 | "SUPER-BLOCK TO SUPPLY NEEDED", | |
174 | "INFORMATION; SEE fsck_ffs(8)."); | 174 | "INFORMATION; SEE fsck_ffs(8)."); | |
175 | return(0); | 175 | return(0); | |
176 | } | 176 | } | |
177 | doskipclean = 0; | 177 | doskipclean = 0; | |
178 | pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); | 178 | pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); | |
179 | } | 179 | } | |
180 | 180 | |||
181 | if (!quota2_check_doquota()) | 181 | if (!quota2_check_doquota()) | |
182 | doskipclean = 0; | 182 | doskipclean = 0; | |
183 | 183 | |||
184 | /* ffs_superblock_layout() == 2 */ | 184 | /* ffs_superblock_layout() == 2 */ | |
185 | if (sblock->fs_magic != FS_UFS1_MAGIC || | 185 | if (sblock->fs_magic != FS_UFS1_MAGIC || | |
186 | (sblock->fs_old_flags & FS_FLAGS_UPDATED) != 0) { | 186 | (sblock->fs_old_flags & FS_FLAGS_UPDATED) != 0) { | |
187 | /* can have WAPBL */ | 187 | /* can have WAPBL */ | |
188 | if (check_wapbl() != 0) { | 188 | if (check_wapbl() != 0) { | |
189 | doskipclean = 0; | 189 | doskipclean = 0; | |
190 | } | 190 | } | |
191 | if (sblock->fs_flags & FS_DOWAPBL) { | 191 | if (sblock->fs_flags & FS_DOWAPBL) { | |
192 | if (preen && doskipclean) { | 192 | if (preen && doskipclean) { | |
193 | if (!quiet) | 193 | if (!quiet) | |
194 | pwarn("file system is journaled; " | 194 | pwarn("file system is journaled; " | |
195 | "not checking\n"); | 195 | "not checking\n"); | |
196 | return (-1); | 196 | return (-1); | |
197 | } | 197 | } | |
198 | if (!quiet) | 198 | if (!quiet) | |
199 | pwarn("** File system is journaled; " | 199 | pwarn("** File system is journaled; " | |
200 | "replaying journal\n"); | 200 | "replaying journal\n"); | |
201 | replay_wapbl(); | 201 | replay_wapbl(); | |
202 | doskipclean = 0; | 202 | doskipclean = 0; | |
203 | sblock->fs_flags &= ~FS_DOWAPBL; | 203 | sblock->fs_flags &= ~FS_DOWAPBL; | |
204 | sbdirty(); | 204 | sbdirty(); | |
205 | /* Although we may have updated the superblock from | 205 | /* Although we may have updated the superblock from | |
206 | * the journal, we are still going to do a full check, | 206 | * the journal, we are still going to do a full check, | |
207 | * so we don't bother to re-read the superblock from | 207 | * so we don't bother to re-read the superblock from | |
208 | * the journal. | 208 | * the journal. | |
209 | * XXX, instead we could re-read the superblock and | 209 | * XXX, instead we could re-read the superblock and | |
210 | * then not force doskipclean = 0 | 210 | * then not force doskipclean = 0 | |
211 | */ | 211 | */ | |
212 | } | 212 | } | |
213 | } | 213 | } | |
214 | if (debug) | 214 | if (debug) | |
215 | printf("clean = %d\n", sblock->fs_clean); | 215 | printf("clean = %d\n", sblock->fs_clean); | |
216 | 216 | |||
217 | if (doswap) | 217 | if (doswap) | |
218 | doskipclean = 0; | 218 | doskipclean = 0; | |
219 | 219 | |||
220 | if (sblock->fs_clean & FS_ISCLEAN) { | 220 | if (sblock->fs_clean & FS_ISCLEAN) { | |
221 | if (doskipclean) { | 221 | if (doskipclean) { | |
222 | if (!quiet) | 222 | if (!quiet) | |
223 | pwarn("%sile system is clean; not checking\n", | 223 | pwarn("%sile system is clean; not checking\n", | |
224 | preen ? "f" : "** F"); | 224 | preen ? "f" : "** F"); | |
225 | return (-1); | 225 | return (-1); | |
226 | } | 226 | } | |
227 | if (!preen && !doswap) | 227 | if (!preen && !doswap) | |
228 | pwarn("** File system is already clean\n"); | 228 | pwarn("** File system is already clean\n"); | |
229 | } | 229 | } | |
230 | maxfsblock = sblock->fs_size; | 230 | maxfsblock = sblock->fs_size; | |
231 | maxino = sblock->fs_ncg * sblock->fs_ipg; | 231 | maxino = sblock->fs_ncg * sblock->fs_ipg; | |
232 | sizepb = sblock->fs_bsize; | 232 | sizepb = sblock->fs_bsize; | |
233 | maxfilesize = sblock->fs_bsize * UFS_NDADDR - 1; | 233 | maxfilesize = sblock->fs_bsize * UFS_NDADDR - 1; | |
234 | for (i = 0; i < UFS_NIADDR; i++) { | 234 | for (i = 0; i < UFS_NIADDR; i++) { | |
235 | sizepb *= FFS_NINDIR(sblock); | 235 | sizepb *= FFS_NINDIR(sblock); | |
236 | maxfilesize += sizepb; | 236 | maxfilesize += sizepb; | |
237 | } | 237 | } | |
238 | if ((!is_ufs2 && cvtlevel >= 4) && | 238 | if ((!is_ufs2 && cvtlevel >= 4) && | |
239 | (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) { | 239 | (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) { | |
240 | if (preen) | 240 | if (preen) | |
241 | pwarn("CONVERTING TO NEW SUPERBLOCK LAYOUT\n"); | 241 | pwarn("CONVERTING TO NEW SUPERBLOCK LAYOUT\n"); | |
242 | else if (!reply("CONVERT TO NEW SUPERBLOCK LAYOUT")) | 242 | else if (!reply("CONVERT TO NEW SUPERBLOCK LAYOUT")) | |
243 | return(0); | 243 | return(0); | |
244 | sblock->fs_old_flags |= FS_FLAGS_UPDATED; | 244 | sblock->fs_old_flags |= FS_FLAGS_UPDATED; | |
245 | /* Disable the postbl tables */ | 245 | /* Disable the postbl tables */ | |
246 | sblock->fs_old_cpc = 0; | 246 | sblock->fs_old_cpc = 0; | |
247 | sblock->fs_old_nrpos = 1; | 247 | sblock->fs_old_nrpos = 1; | |
248 | sblock->fs_old_trackskew = 0; | 248 | sblock->fs_old_trackskew = 0; | |
249 | /* The other fields have already been updated by | 249 | /* The other fields have already been updated by | |
250 | * sb_oldfscompat_read | 250 | * sb_oldfscompat_read | |
251 | */ | 251 | */ | |
252 | sbdirty(); | 252 | sbdirty(); | |
253 | } | 253 | } | |
254 | if (!is_ufs2 && cvtlevel == 3 && | 254 | if (!is_ufs2 && cvtlevel == 3 && | |
255 | (sblock->fs_old_flags & FS_FLAGS_UPDATED)) { | 255 | (sblock->fs_old_flags & FS_FLAGS_UPDATED)) { | |
256 | if (preen) | 256 | if (preen) | |
257 | pwarn("DOWNGRADING TO OLD SUPERBLOCK LAYOUT\n"); | 257 | pwarn("DOWNGRADING TO OLD SUPERBLOCK LAYOUT\n"); | |
258 | else if (!reply("DOWNGRADE TO OLD SUPERBLOCK LAYOUT")) | 258 | else if (!reply("DOWNGRADE TO OLD SUPERBLOCK LAYOUT")) | |
259 | return(0); | 259 | return(0); | |
260 | sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; | 260 | sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; | |
261 | sb_oldfscompat_write(sblock, sblock); | 261 | sb_oldfscompat_write(sblock, sblock); | |
262 | sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; /* just in case */ | 262 | sblock->fs_old_flags &= ~FS_FLAGS_UPDATED; /* just in case */ | |
263 | /* Leave postbl tables disabled, but blank its superblock region anyway */ | 263 | /* Leave postbl tables disabled, but blank its superblock region anyway */ | |
264 | sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT; | 264 | sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT; | |
265 | sblock->fs_old_cpc = 0; | 265 | sblock->fs_old_cpc = 0; | |
266 | sblock->fs_old_nrpos = 1; | 266 | sblock->fs_old_nrpos = 1; | |
267 | sblock->fs_old_trackskew = 0; | 267 | sblock->fs_old_trackskew = 0; | |
268 | memset(&sblock->fs_old_postbl_start, 0xff, 256); | 268 | memset(&sblock->fs_old_postbl_start, 0xff, 256); | |
269 | sb_oldfscompat_read(sblock, &sblocksave); | 269 | sb_oldfscompat_read(sblock, &sblocksave); | |
270 | sbdirty(); | 270 | sbdirty(); | |
271 | } | 271 | } | |
272 | /* | 272 | /* | |
273 | * Check and potentially fix certain fields in the super block. | 273 | * Check and potentially fix certain fields in the super block. | |
274 | */ | 274 | */ | |
275 | if (sblock->fs_flags & ~(FS_KNOWN_FLAGS)) { | 275 | if (sblock->fs_flags & ~(FS_KNOWN_FLAGS)) { | |
276 | pfatal("UNKNOWN FLAGS=0x%08x IN SUPERBLOCK", sblock->fs_flags); | 276 | pfatal("UNKNOWN FLAGS=0x%08x IN SUPERBLOCK", sblock->fs_flags); | |
277 | if (reply("CLEAR") == 1) { | 277 | if (reply("CLEAR") == 1) { | |
278 | sblock->fs_flags &= FS_KNOWN_FLAGS; | 278 | sblock->fs_flags &= FS_KNOWN_FLAGS; | |
279 | sbdirty(); | 279 | sbdirty(); | |
280 | } | 280 | } | |
281 | } | 281 | } | |
282 | if (sblock->fs_optim != FS_OPTTIME && sblock->fs_optim != FS_OPTSPACE) { | 282 | if (sblock->fs_optim != FS_OPTTIME && sblock->fs_optim != FS_OPTSPACE) { | |
283 | pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); | 283 | pfatal("UNDEFINED OPTIMIZATION IN SUPERBLOCK"); | |
284 | if (reply("SET TO DEFAULT") == 1) { | 284 | if (reply("SET TO DEFAULT") == 1) { | |
285 | sblock->fs_optim = FS_OPTTIME; | 285 | sblock->fs_optim = FS_OPTTIME; | |
286 | sbdirty(); | 286 | sbdirty(); | |
287 | } | 287 | } | |
288 | } | 288 | } | |
289 | if ((sblock->fs_minfree < 0 || sblock->fs_minfree > 99)) { | 289 | if ((sblock->fs_minfree < 0 || sblock->fs_minfree > 99)) { | |
290 | pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", | 290 | pfatal("IMPOSSIBLE MINFREE=%d IN SUPERBLOCK", | |
291 | sblock->fs_minfree); | 291 | sblock->fs_minfree); | |
292 | if (reply("SET TO DEFAULT") == 1) { | 292 | if (reply("SET TO DEFAULT") == 1) { | |
293 | sblock->fs_minfree = 10; | 293 | sblock->fs_minfree = 10; | |
294 | sbdirty(); | 294 | sbdirty(); | |
295 | } | 295 | } | |
296 | } | 296 | } | |
297 | if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT && | 297 | if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT && | |
298 | (sblock->fs_old_interleave < 1 || | 298 | (sblock->fs_old_interleave < 1 || | |
299 | sblock->fs_old_interleave > sblock->fs_old_nsect)) { | 299 | sblock->fs_old_interleave > sblock->fs_old_nsect)) { | |
300 | pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", | 300 | pwarn("IMPOSSIBLE INTERLEAVE=%d IN SUPERBLOCK", | |
301 | sblock->fs_old_interleave); | 301 | sblock->fs_old_interleave); | |
302 | sblock->fs_old_interleave = 1; | 302 | sblock->fs_old_interleave = 1; | |
303 | if (preen) | 303 | if (preen) | |
304 | printf(" (FIXED)\n"); | 304 | printf(" (FIXED)\n"); | |
305 | if (preen || reply("SET TO DEFAULT") == 1) { | 305 | if (preen || reply("SET TO DEFAULT") == 1) { | |
306 | sbdirty(); | 306 | sbdirty(); | |
307 | dirty(&asblk); | 307 | dirty(&asblk); | |
308 | } | 308 | } | |
309 | } | 309 | } | |
310 | if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT && | 310 | if (!is_ufs2 && sblock->fs_old_postblformat != FS_42POSTBLFMT && | |
311 | (sblock->fs_old_npsect < sblock->fs_old_nsect || | 311 | (sblock->fs_old_npsect < sblock->fs_old_nsect || | |
312 | sblock->fs_old_npsect > sblock->fs_old_nsect*2)) { | 312 | sblock->fs_old_npsect > sblock->fs_old_nsect*2)) { | |
313 | pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", | 313 | pwarn("IMPOSSIBLE NPSECT=%d IN SUPERBLOCK", | |
314 | sblock->fs_old_npsect); | 314 | sblock->fs_old_npsect); | |
315 | sblock->fs_old_npsect = sblock->fs_old_nsect; | 315 | sblock->fs_old_npsect = sblock->fs_old_nsect; | |
316 | if (preen) | 316 | if (preen) | |
317 | printf(" (FIXED)\n"); | 317 | printf(" (FIXED)\n"); | |
318 | if (preen || reply("SET TO DEFAULT") == 1) { | 318 | if (preen || reply("SET TO DEFAULT") == 1) { | |
319 | sbdirty(); | 319 | sbdirty(); | |
320 | dirty(&asblk); | 320 | dirty(&asblk); | |
321 | } | 321 | } | |
322 | } | 322 | } | |
323 | if (sblock->fs_bmask != ~(sblock->fs_bsize - 1)) { | 323 | if (sblock->fs_bmask != ~(sblock->fs_bsize - 1)) { | |
324 | pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK", | 324 | pwarn("INCORRECT BMASK=0x%x IN SUPERBLOCK", | |
325 | sblock->fs_bmask); | 325 | sblock->fs_bmask); | |
326 | sblock->fs_bmask = ~(sblock->fs_bsize - 1); | 326 | sblock->fs_bmask = ~(sblock->fs_bsize - 1); | |
327 | if (preen) | 327 | if (preen) | |
328 | printf(" (FIXED)\n"); | 328 | printf(" (FIXED)\n"); | |
329 | if (preen || reply("FIX") == 1) { | 329 | if (preen || reply("FIX") == 1) { | |
330 | sbdirty(); | 330 | sbdirty(); | |
331 | dirty(&asblk); | 331 | dirty(&asblk); | |
332 | } | 332 | } | |
333 | } | 333 | } | |
334 | if (sblock->fs_fmask != ~(sblock->fs_fsize - 1)) { | 334 | if (sblock->fs_fmask != ~(sblock->fs_fsize - 1)) { | |
335 | pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK", | 335 | pwarn("INCORRECT FMASK=0x%x IN SUPERBLOCK", | |
336 | sblock->fs_fmask); | 336 | sblock->fs_fmask); | |
337 | sblock->fs_fmask = ~(sblock->fs_fsize - 1); | 337 | sblock->fs_fmask = ~(sblock->fs_fsize - 1); | |
338 | if (preen) | 338 | if (preen) | |
339 | printf(" (FIXED)\n"); | 339 | printf(" (FIXED)\n"); | |
340 | if (preen || reply("FIX") == 1) { | 340 | if (preen || reply("FIX") == 1) { | |
341 | sbdirty(); | 341 | sbdirty(); | |
342 | dirty(&asblk); | 342 | dirty(&asblk); | |
343 | } | 343 | } | |
344 | } | 344 | } | |
345 | if (check_snapinum()) { | 345 | if (check_snapinum()) { | |
346 | if (preen) | 346 | if (preen) | |
347 | printf(" (FIXED)\n"); | 347 | printf(" (FIXED)\n"); | |
348 | if (preen || reply("FIX") == 1) { | 348 | if (preen || reply("FIX") == 1) { | |
349 | sbdirty(); | 349 | sbdirty(); | |
350 | dirty(&asblk); | 350 | dirty(&asblk); | |
351 | } | 351 | } | |
352 | } | 352 | } | |
353 | if (is_ufs2 || sblock->fs_old_inodefmt >= FS_44INODEFMT) { | 353 | if (is_ufs2 || sblock->fs_old_inodefmt >= FS_44INODEFMT) { | |
354 | if (sblock->fs_maxfilesize != maxfilesize) { | 354 | if (sblock->fs_maxfilesize != maxfilesize) { | |
355 | pwarn("INCORRECT MAXFILESIZE=%lld IN SUPERBLOCK", | 355 | pwarn("INCORRECT MAXFILESIZE=%lld IN SUPERBLOCK", | |
356 | (unsigned long long)sblock->fs_maxfilesize); | 356 | (unsigned long long)sblock->fs_maxfilesize); | |
357 | sblock->fs_maxfilesize = maxfilesize; | 357 | sblock->fs_maxfilesize = maxfilesize; | |
358 | if (preen) | 358 | if (preen) | |
359 | printf(" (FIXED)\n"); | 359 | printf(" (FIXED)\n"); | |
360 | if (preen || reply("FIX") == 1) { | 360 | if (preen || reply("FIX") == 1) { | |
361 | sbdirty(); | 361 | sbdirty(); | |
362 | dirty(&asblk); | 362 | dirty(&asblk); | |
363 | } | 363 | } | |
364 | } | 364 | } | |
365 | if ((is_ufs2 && sblock->fs_maxsymlinklen != UFS2_MAXSYMLINKLEN) | 365 | if ((is_ufs2 && sblock->fs_maxsymlinklen != UFS2_MAXSYMLINKLEN) | |
366 | || | 366 | || | |
367 | (!is_ufs2 && sblock->fs_maxsymlinklen != UFS1_MAXSYMLINKLEN)) | 367 | (!is_ufs2 && sblock->fs_maxsymlinklen != UFS1_MAXSYMLINKLEN)) | |
368 | { | 368 | { | |
369 | pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", | 369 | pwarn("INCORRECT MAXSYMLINKLEN=%d IN SUPERBLOCK", | |
370 | sblock->fs_maxsymlinklen); | 370 | sblock->fs_maxsymlinklen); | |
371 | sblock->fs_maxsymlinklen = is_ufs2 ? | 371 | sblock->fs_maxsymlinklen = is_ufs2 ? | |
372 | UFS2_MAXSYMLINKLEN : UFS1_MAXSYMLINKLEN; | 372 | UFS2_MAXSYMLINKLEN : UFS1_MAXSYMLINKLEN; | |
373 | if (preen) | 373 | if (preen) | |
374 | printf(" (FIXED)\n"); | 374 | printf(" (FIXED)\n"); | |
375 | if (preen || reply("FIX") == 1) { | 375 | if (preen || reply("FIX") == 1) { | |
376 | sbdirty(); | 376 | sbdirty(); | |
377 | dirty(&asblk); | 377 | dirty(&asblk); | |
378 | } | 378 | } | |
379 | } | 379 | } | |
380 | if (sblock->fs_qbmask != ~sblock->fs_bmask) { | 380 | if (sblock->fs_qbmask != ~sblock->fs_bmask) { | |
381 | pwarn("INCORRECT QBMASK=%#llx IN SUPERBLOCK", | 381 | pwarn("INCORRECT QBMASK=%#llx IN SUPERBLOCK", | |
382 | (unsigned long long)sblock->fs_qbmask); | 382 | (unsigned long long)sblock->fs_qbmask); | |
383 | sblock->fs_qbmask = ~sblock->fs_bmask; | 383 | sblock->fs_qbmask = ~sblock->fs_bmask; | |
384 | if (preen) | 384 | if (preen) | |
385 | printf(" (FIXED)\n"); | 385 | printf(" (FIXED)\n"); | |
386 | if (preen || reply("FIX") == 1) { | 386 | if (preen || reply("FIX") == 1) { | |
387 | sbdirty(); | 387 | sbdirty(); | |
388 | dirty(&asblk); | 388 | dirty(&asblk); | |
389 | } | 389 | } | |
390 | } | 390 | } | |
391 | if (sblock->fs_qfmask != ~sblock->fs_fmask) { | 391 | if (sblock->fs_qfmask != ~sblock->fs_fmask) { | |
392 | pwarn("INCORRECT QFMASK=%#llx IN SUPERBLOCK", | 392 | pwarn("INCORRECT QFMASK=%#llx IN SUPERBLOCK", | |
393 | (unsigned long long)sblock->fs_qfmask); | 393 | (unsigned long long)sblock->fs_qfmask); | |
394 | sblock->fs_qfmask = ~sblock->fs_fmask; | 394 | sblock->fs_qfmask = ~sblock->fs_fmask; | |
395 | if (preen) | 395 | if (preen) | |
396 | printf(" (FIXED)\n"); | 396 | printf(" (FIXED)\n"); | |
397 | if (preen || reply("FIX") == 1) { | 397 | if (preen || reply("FIX") == 1) { | |
398 | sbdirty(); | 398 | sbdirty(); | |
399 | dirty(&asblk); | 399 | dirty(&asblk); | |
400 | } | 400 | } | |
401 | } | 401 | } | |
402 | newinofmt = 1; | 402 | newinofmt = 1; | |
403 | } else { | 403 | } else { | |
404 | sblock->fs_qbmask = ~sblock->fs_bmask; | 404 | sblock->fs_qbmask = ~sblock->fs_bmask; | |
405 | sblock->fs_qfmask = ~sblock->fs_fmask; | 405 | sblock->fs_qfmask = ~sblock->fs_fmask; | |
406 | newinofmt = 0; | 406 | newinofmt = 0; | |
407 | } | 407 | } | |
408 | /* | 408 | /* | |
409 | * Convert to new inode format. | 409 | * Convert to new inode format. | |
410 | */ | 410 | */ | |
411 | if (!is_ufs2 && cvtlevel >= 2 && | 411 | if (!is_ufs2 && cvtlevel >= 2 && | |
412 | sblock->fs_old_inodefmt < FS_44INODEFMT) { | 412 | sblock->fs_old_inodefmt < FS_44INODEFMT) { | |
413 | if (preen) | 413 | if (preen) | |
414 | pwarn("CONVERTING TO NEW INODE FORMAT\n"); | 414 | pwarn("CONVERTING TO NEW INODE FORMAT\n"); | |
415 | else if (!reply("CONVERT TO NEW INODE FORMAT")) | 415 | else if (!reply("CONVERT TO NEW INODE FORMAT")) | |
416 | return(0); | 416 | return(0); | |
417 | doinglevel2++; | 417 | doinglevel2++; | |
418 | sblock->fs_old_inodefmt = FS_44INODEFMT; | 418 | sblock->fs_old_inodefmt = FS_44INODEFMT; | |
419 | sblock->fs_maxfilesize = maxfilesize; | 419 | sblock->fs_maxfilesize = maxfilesize; | |
420 | sblock->fs_maxsymlinklen = UFS1_MAXSYMLINKLEN; | 420 | sblock->fs_maxsymlinklen = UFS1_MAXSYMLINKLEN; | |
421 | sblock->fs_qbmask = ~sblock->fs_bmask; | 421 | sblock->fs_qbmask = ~sblock->fs_bmask; | |
422 | sblock->fs_qfmask = ~sblock->fs_fmask; | 422 | sblock->fs_qfmask = ~sblock->fs_fmask; | |
423 | sbdirty(); | 423 | sbdirty(); | |
424 | dirty(&asblk); | 424 | dirty(&asblk); | |
425 | } | 425 | } | |
426 | /* | 426 | /* | |
427 | * Convert to new cylinder group format. | 427 | * Convert to new cylinder group format. | |
428 | */ | 428 | */ | |
429 | if (!is_ufs2 && cvtlevel >= 1 && | 429 | if (!is_ufs2 && cvtlevel >= 1 && | |
430 | sblock->fs_old_postblformat == FS_42POSTBLFMT) { | 430 | sblock->fs_old_postblformat == FS_42POSTBLFMT) { | |
431 | if (preen) | 431 | if (preen) | |
432 | pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n"); | 432 | pwarn("CONVERTING TO NEW CYLINDER GROUP FORMAT\n"); | |
433 | else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT")) | 433 | else if (!reply("CONVERT TO NEW CYLINDER GROUP FORMAT")) | |
434 | return(0); | 434 | return(0); | |
435 | doinglevel1++; | 435 | doinglevel1++; | |
436 | sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT; | 436 | sblock->fs_old_postblformat = FS_DYNAMICPOSTBLFMT; | |
437 | sblock->fs_old_nrpos = 8; | 437 | sblock->fs_old_nrpos = 8; | |
438 | sblock->fs_old_postbloff = | 438 | sblock->fs_old_postbloff = | |
439 | (char *)(&sblock->fs_old_postbl_start) - | 439 | (char *)(&sblock->fs_old_postbl_start) - | |
440 | (char *)(&sblock->fs_firstfield); | 440 | (char *)(&sblock->fs_firstfield); | |
441 | sblock->fs_old_rotbloff = | 441 | sblock->fs_old_rotbloff = | |
442 | (char *)(&sblock->fs_magic+1) - | 442 | (char *)(&sblock->fs_magic+1) - | |
443 | (char *)(&sblock->fs_firstfield); | 443 | (char *)(&sblock->fs_firstfield); | |
444 | sblock->fs_cgsize = | 444 | sblock->fs_cgsize = | |
445 | ffs_fragroundup(sblock, CGSIZE(sblock)); | 445 | ffs_fragroundup(sblock, CGSIZE(sblock)); | |
446 | sbdirty(); | 446 | sbdirty(); | |
447 | dirty(&asblk); | 447 | dirty(&asblk); | |
448 | } | 448 | } | |
449 | if (asblk.b_dirty && !bflag) { | 449 | if (asblk.b_dirty && !bflag) { | |
450 | memmove(sblk.b_un.b_fs, sblock, SBLOCKSIZE); | 450 | memmove(sblk.b_un.b_fs, sblock, SBLOCKSIZE); | |
451 | sb_oldfscompat_write(sblk.b_un.b_fs, sblocksave); | 451 | sb_oldfscompat_write(sblk.b_un.b_fs, sblocksave); | |
452 | if (needswap) | 452 | if (needswap) | |
453 | ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); | 453 | ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); | |
454 | memmove(asblk.b_un.b_fs, sblk.b_un.b_fs, (size_t)sblock->fs_sbsize); | 454 | memmove(asblk.b_un.b_fs, sblk.b_un.b_fs, (size_t)sblock->fs_sbsize); | |
455 | flush(fswritefd, &asblk); | 455 | flush(fswritefd, &asblk); | |
456 | } | 456 | } | |
457 | /* | 457 | /* | |
458 | * read in the summary info. | 458 | * read in the summary info. | |
459 | */ | 459 | */ | |
460 | asked = 0; | 460 | asked = 0; | |
461 | sblock->fs_csp = (struct csum *)calloc(1, sblock->fs_cssize); | 461 | sblock->fs_csp = (struct csum *)aligned_alloc(DEV_BSIZE, | |
462 | sblock->fs_cssize); | |||
462 | if (sblock->fs_csp == NULL) { | 463 | if (sblock->fs_csp == NULL) { | |
463 | pwarn("cannot alloc %u bytes for summary info\n", | 464 | pwarn("cannot alloc %u bytes for summary info\n", | |
464 | sblock->fs_cssize); | 465 | sblock->fs_cssize); | |
465 | goto badsblabel; | 466 | goto badsblabel; | |
466 | } | 467 | } | |
468 | memset(sblock->fs_csp, 0, sblock->fs_cssize); | |||
467 | for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { | 469 | for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { | |
468 | size = sblock->fs_cssize - i < sblock->fs_bsize ? | 470 | size = sblock->fs_cssize - i < sblock->fs_bsize ? | |
469 | sblock->fs_cssize - i : sblock->fs_bsize; | 471 | sblock->fs_cssize - i : sblock->fs_bsize; | |
470 | ccsp = (struct csum *)((char *)sblock->fs_csp + i); | 472 | ccsp = (struct csum *)((char *)sblock->fs_csp + i); | |
471 | if (bread(fsreadfd, (char *)ccsp, | 473 | if (bread(fsreadfd, (char *)ccsp, | |
472 | FFS_FSBTODB(sblock, sblock->fs_csaddr + j * sblock->fs_frag), | 474 | FFS_FSBTODB(sblock, sblock->fs_csaddr + j * sblock->fs_frag), | |
473 | size) != 0 && !asked) { | 475 | size) != 0 && !asked) { | |
474 | pfatal("BAD SUMMARY INFORMATION"); | 476 | pfatal("BAD SUMMARY INFORMATION"); | |
475 | if (reply("CONTINUE") == 0) { | 477 | if (reply("CONTINUE") == 0) { | |
476 | markclean = 0; | 478 | markclean = 0; | |
477 | exit(FSCK_EXIT_CHECK_FAILED); | 479 | exit(FSCK_EXIT_CHECK_FAILED); | |
478 | } | 480 | } | |
479 | asked++; | 481 | asked++; | |
480 | } | 482 | } | |
481 | if (doswap) { | 483 | if (doswap) { | |
482 | ffs_csum_swap(ccsp, ccsp, size); | 484 | ffs_csum_swap(ccsp, ccsp, size); | |
483 | bwrite(fswritefd, (char *)ccsp, | 485 | bwrite(fswritefd, (char *)ccsp, | |
484 | FFS_FSBTODB(sblock, | 486 | FFS_FSBTODB(sblock, | |
485 | sblock->fs_csaddr + j * sblock->fs_frag), | 487 | sblock->fs_csaddr + j * sblock->fs_frag), | |
486 | size); | 488 | size); | |
487 | } | 489 | } | |
488 | if (needswap) | 490 | if (needswap) | |
489 | ffs_csum_swap(ccsp, ccsp, size); | 491 | ffs_csum_swap(ccsp, ccsp, size); | |
490 | } | 492 | } | |
491 | /* | 493 | /* | |
492 | * allocate and initialize the necessary maps | 494 | * allocate and initialize the necessary maps | |
493 | */ | 495 | */ | |
494 | bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); | 496 | bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); | |
495 | blockmap = calloc((unsigned)bmapsize, sizeof (char)); | 497 | blockmap = aligned_alloc(DEV_BSIZE, (unsigned)bmapsize); | |
496 | if (blockmap == NULL) { | 498 | if (blockmap == NULL) { | |
497 | pwarn("cannot alloc %u bytes for blockmap\n", | 499 | pwarn("cannot alloc %u bytes for blockmap\n", | |
498 | (unsigned)bmapsize); | 500 | (unsigned)bmapsize); | |
499 | goto badsblabel; | 501 | goto badsblabel; | |
500 | } | 502 | } | |
503 | memset(blockmap, 0, bmapsize); | |||
501 | inostathead = calloc((unsigned)(sblock->fs_ncg), | 504 | inostathead = calloc((unsigned)(sblock->fs_ncg), | |
502 | sizeof(struct inostatlist)); | 505 | sizeof(struct inostatlist)); | |
503 | if (inostathead == NULL) { | 506 | if (inostathead == NULL) { | |
504 | pwarn("cannot alloc %u bytes for inostathead\n", | 507 | pwarn("cannot alloc %u bytes for inostathead\n", | |
505 | (unsigned)(sizeof(struct inostatlist) * (sblock->fs_ncg))); | 508 | (unsigned)(sizeof(struct inostatlist) * (sblock->fs_ncg))); | |
506 | goto badsblabel; | 509 | goto badsblabel; | |
507 | } | 510 | } | |
508 | /* | 511 | /* | |
509 | * cs_ndir may be inaccurate, particularly if we're using the -b | 512 | * cs_ndir may be inaccurate, particularly if we're using the -b | |
510 | * option, so set a minimum to prevent bogus subdirectory reconnects | 513 | * option, so set a minimum to prevent bogus subdirectory reconnects | |
511 | * and really inefficient directory scans. | 514 | * and really inefficient directory scans. | |
512 | * Also set a maximum in case the value is too large. | 515 | * Also set a maximum in case the value is too large. | |
513 | */ | 516 | */ | |
514 | numdirs = sblock->fs_cstotal.cs_ndir; | 517 | numdirs = sblock->fs_cstotal.cs_ndir; | |
515 | if (numdirs < 1024) | 518 | if (numdirs < 1024) | |
516 | numdirs = 1024; | 519 | numdirs = 1024; | |
517 | if ((ino_t)numdirs > maxino + 1) | 520 | if ((ino_t)numdirs > maxino + 1) | |
518 | numdirs = maxino + 1; | 521 | numdirs = maxino + 1; | |
519 | dirhash = numdirs; | 522 | dirhash = numdirs; | |
520 | inplast = 0; | 523 | inplast = 0; | |
521 | listmax = numdirs + 10; | 524 | listmax = numdirs + 10; | |
522 | inpsort = calloc((unsigned)listmax, sizeof(*inpsort)); | 525 | inpsort = calloc((unsigned)listmax, sizeof(*inpsort)); | |
523 | inphead = calloc((unsigned)numdirs, sizeof(*inphead)); | 526 | inphead = calloc((unsigned)numdirs, sizeof(*inphead)); | |
524 | if (inpsort == NULL || inphead == NULL) { | 527 | if (inpsort == NULL || inphead == NULL) { | |
525 | pwarn("cannot alloc %u bytes for inphead\n", | 528 | pwarn("cannot alloc %u bytes for inphead\n", | |
526 | (unsigned)(numdirs * sizeof(struct inoinfo *))); | 529 | (unsigned)(numdirs * sizeof(struct inoinfo *))); | |
527 | goto badsblabel; | 530 | goto badsblabel; | |
528 | } | 531 | } | |
529 | cgrp = malloc(sblock->fs_cgsize); | 532 | cgrp = aligned_alloc(DEV_BSIZE, sblock->fs_cgsize); | |
530 | if (cgrp == NULL) { | 533 | if (cgrp == NULL) { | |
531 | pwarn("cannot alloc %u bytes for cylinder group\n", | 534 | pwarn("cannot alloc %u bytes for cylinder group\n", | |
532 | sblock->fs_cgsize); | 535 | sblock->fs_cgsize); | |
533 | goto badsblabel; | 536 | goto badsblabel; | |
534 | } | 537 | } | |
535 | bufinit(); | 538 | bufinit(); | |
536 | if (sblock->fs_flags & FS_DOSOFTDEP) | 539 | if (sblock->fs_flags & FS_DOSOFTDEP) | |
537 | usedsoftdep = 1; | 540 | usedsoftdep = 1; | |
538 | else | 541 | else | |
539 | usedsoftdep = 0; | 542 | usedsoftdep = 0; | |
540 | 543 | |||
541 | #ifndef NO_APPLE_UFS | 544 | #ifndef NO_APPLE_UFS | |
542 | if (!forceimage && dkw.dkw_parent[0]) | 545 | if (!forceimage && dkw.dkw_parent[0]) | |
543 | if (strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0) | 546 | if (strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0) | |
544 | isappleufs = 1; | 547 | isappleufs = 1; | |
545 | 548 | |||
546 | if (readappleufs()) | 549 | if (readappleufs()) | |
547 | isappleufs = 1; | 550 | isappleufs = 1; | |
548 | #endif | 551 | #endif | |
549 | 552 | |||
550 | if (isappleufs) | 553 | if (isappleufs) | |
551 | dirblksiz = APPLEUFS_DIRBLKSIZ; | 554 | dirblksiz = APPLEUFS_DIRBLKSIZ; | |
552 | else | 555 | else | |
553 | dirblksiz = UFS_DIRBLKSIZ; | 556 | dirblksiz = UFS_DIRBLKSIZ; | |
554 | 557 | |||
555 | if (debug) | 558 | if (debug) | |
556 | #ifndef NO_APPLE_UFS | 559 | #ifndef NO_APPLE_UFS | |
557 | printf("isappleufs = %d, dirblksiz = %d\n", isappleufs, dirblksiz); | 560 | printf("isappleufs = %d, dirblksiz = %d\n", isappleufs, dirblksiz); | |
558 | #else | 561 | #else | |
559 | printf("dirblksiz = %d\n", dirblksiz); | 562 | printf("dirblksiz = %d\n", dirblksiz); | |
560 | #endif | 563 | #endif | |
561 | 564 | |||
562 | if (sblock->fs_flags & FS_DOQUOTA2) { | 565 | if (sblock->fs_flags & FS_DOQUOTA2) { | |
563 | /* allocate the quota hash table */ | 566 | /* allocate the quota hash table */ | |
564 | /* | 567 | /* | |
565 | * first compute the size of the hash table | 568 | * first compute the size of the hash table | |
566 | * We know the smallest block size is 4k, so we can use 2k | 569 | * We know the smallest block size is 4k, so we can use 2k | |
567 | * for the hash table; as an entry is 8 bytes we can store | 570 | * for the hash table; as an entry is 8 bytes we can store | |
568 | * 256 entries. So let start q2h_hash_shift at 8 | 571 | * 256 entries. So let start q2h_hash_shift at 8 | |
569 | */ | 572 | */ | |
570 | for (q2h_hash_shift = 8; | 573 | for (q2h_hash_shift = 8; | |
571 | q2h_hash_shift < 15; | 574 | q2h_hash_shift < 15; | |
572 | q2h_hash_shift++) { | 575 | q2h_hash_shift++) { | |
573 | if ((sizeof(uint64_t) << (q2h_hash_shift + 1)) + | 576 | if ((sizeof(uint64_t) << (q2h_hash_shift + 1)) + | |
574 | sizeof(struct quota2_header) > | 577 | sizeof(struct quota2_header) > | |
575 | (size_t)sblock->fs_bsize) | 578 | (size_t)sblock->fs_bsize) | |
576 | break; | 579 | break; | |
577 | } | 580 | } | |
578 | q2h_hash_mask = (1 << q2h_hash_shift) - 1; | 581 | q2h_hash_mask = (1 << q2h_hash_shift) - 1; | |
579 | if (debug) { | 582 | if (debug) { | |
580 | printf("quota hash shift %d, %d entries, mask 0x%x\n", | 583 | printf("quota hash shift %d, %d entries, mask 0x%x\n", | |
581 | q2h_hash_shift, (1 << q2h_hash_shift), | 584 | q2h_hash_shift, (1 << q2h_hash_shift), | |
582 | q2h_hash_mask); | 585 | q2h_hash_mask); | |
583 | } | 586 | } | |
584 | uquot_user_hash = | 587 | uquot_user_hash = | |
585 | calloc((1 << q2h_hash_shift), sizeof(struct uquot_hash)); | 588 | calloc((1 << q2h_hash_shift), sizeof(struct uquot_hash)); | |
586 | uquot_group_hash = | 589 | uquot_group_hash = | |
587 | calloc((1 << q2h_hash_shift), sizeof(struct uquot_hash)); | 590 | calloc((1 << q2h_hash_shift), sizeof(struct uquot_hash)); | |
588 | if (uquot_user_hash == NULL || uquot_group_hash == NULL) | 591 | if (uquot_user_hash == NULL || uquot_group_hash == NULL) | |
589 | errexit("Cannot allocate space for quotas hash\n"); | 592 | errexit("Cannot allocate space for quotas hash\n"); | |
590 | } else { | 593 | } else { | |
591 | uquot_user_hash = uquot_group_hash = NULL; | 594 | uquot_user_hash = uquot_group_hash = NULL; | |
592 | q2h_hash_shift = q2h_hash_mask = 0; | 595 | q2h_hash_shift = q2h_hash_mask = 0; | |
593 | } | 596 | } | |
594 | return (1); | 597 | return (1); | |
595 | badsblabel: | 598 | badsblabel: | |
596 | markclean=0; | 599 | markclean=0; | |
597 | ckfini(1); | 600 | ckfini(1); | |
598 | return (0); | 601 | return (0); | |
599 | } | 602 | } | |
600 | 603 | |||
601 | #ifndef NO_APPLE_UFS | 604 | #ifndef NO_APPLE_UFS | |
602 | static int | 605 | static int | |
603 | readappleufs(void) | 606 | readappleufs(void) | |
604 | { | 607 | { | |
605 | daddr_t label = APPLEUFS_LABEL_OFFSET / dev_bsize; | 608 | daddr_t label = APPLEUFS_LABEL_OFFSET / dev_bsize; | |
606 | struct appleufslabel *appleufs; | 609 | struct appleufslabel *appleufs; | |
607 | int i; | 610 | int i; | |
608 | 611 | |||
609 | /* XXX do we have to deal with APPLEUFS_LABEL_OFFSET not | 612 | /* XXX do we have to deal with APPLEUFS_LABEL_OFFSET not | |
610 | * being block aligned (CD's?) | 613 | * being block aligned (CD's?) | |
611 | */ | 614 | */ | |
612 | if (APPLEUFS_LABEL_SIZE % dev_bsize != 0) | 615 | if (APPLEUFS_LABEL_SIZE % dev_bsize != 0) | |
613 | return 0; | 616 | return 0; | |
614 | if (bread(fsreadfd, (char *)appleufsblk.b_un.b_fs, label, | 617 | if (bread(fsreadfd, (char *)appleufsblk.b_un.b_fs, label, | |
615 | (long)APPLEUFS_LABEL_SIZE) != 0) | 618 | (long)APPLEUFS_LABEL_SIZE) != 0) | |
616 | return 0; | 619 | return 0; | |
617 | appleufsblk.b_bno = label; | 620 | appleufsblk.b_bno = label; | |
618 | appleufsblk.b_size = APPLEUFS_LABEL_SIZE; | 621 | appleufsblk.b_size = APPLEUFS_LABEL_SIZE; | |
619 | 622 | |||
620 | appleufs = appleufsblk.b_un.b_appleufs; | 623 | appleufs = appleufsblk.b_un.b_appleufs; | |
621 | 624 | |||
622 | if (ntohl(appleufs->ul_magic) != APPLEUFS_LABEL_MAGIC) { | 625 | if (ntohl(appleufs->ul_magic) != APPLEUFS_LABEL_MAGIC) { | |
623 | if (!isappleufs) { | 626 | if (!isappleufs) { | |
624 | return 0; | 627 | return 0; | |
625 | } else { | 628 | } else { | |
626 | pfatal("MISSING APPLEUFS VOLUME LABEL\n"); | 629 | pfatal("MISSING APPLEUFS VOLUME LABEL\n"); | |
627 | if (reply("FIX") == 0) { | 630 | if (reply("FIX") == 0) { | |
628 | return 1; | 631 | return 1; | |
629 | } | 632 | } | |
630 | ffs_appleufs_set(appleufs, NULL, -1, 0); | 633 | ffs_appleufs_set(appleufs, NULL, -1, 0); | |
631 | appleufsdirty(); | 634 | appleufsdirty(); | |
632 | } | 635 | } | |
633 | } | 636 | } | |
634 | 637 | |||
635 | if (ntohl(appleufs->ul_version) != APPLEUFS_LABEL_VERSION) { | 638 | if (ntohl(appleufs->ul_version) != APPLEUFS_LABEL_VERSION) { | |
636 | pwarn("INCORRECT APPLE UFS VERSION NUMBER (%d should be %d)", | 639 | pwarn("INCORRECT APPLE UFS VERSION NUMBER (%d should be %d)", | |
637 | ntohl(appleufs->ul_version),APPLEUFS_LABEL_VERSION); | 640 | ntohl(appleufs->ul_version),APPLEUFS_LABEL_VERSION); | |
638 | if (preen) { | 641 | if (preen) { | |
639 | printf(" (CORRECTED)\n"); | 642 | printf(" (CORRECTED)\n"); | |
640 | } | 643 | } | |
641 | if (preen || reply("CORRECT")) { | 644 | if (preen || reply("CORRECT")) { | |
642 | appleufs->ul_version = htonl(APPLEUFS_LABEL_VERSION); | 645 | appleufs->ul_version = htonl(APPLEUFS_LABEL_VERSION); | |
643 | appleufsdirty(); | 646 | appleufsdirty(); | |
644 | } | 647 | } | |
645 | } | 648 | } | |
646 | 649 | |||
647 | if (ntohs(appleufs->ul_namelen) > APPLEUFS_MAX_LABEL_NAME) { | 650 | if (ntohs(appleufs->ul_namelen) > APPLEUFS_MAX_LABEL_NAME) { | |
648 | pwarn("APPLE UFS LABEL NAME TOO LONG"); | 651 | pwarn("APPLE UFS LABEL NAME TOO LONG"); | |
649 | if (preen) { | 652 | if (preen) { | |
650 | printf(" (TRUNCATED)\n"); | 653 | printf(" (TRUNCATED)\n"); | |
651 | } | 654 | } | |
652 | if (preen || reply("TRUNCATE")) { | 655 | if (preen || reply("TRUNCATE")) { | |
653 | appleufs->ul_namelen = htons(APPLEUFS_MAX_LABEL_NAME); | 656 | appleufs->ul_namelen = htons(APPLEUFS_MAX_LABEL_NAME); | |
654 | appleufsdirty(); | 657 | appleufsdirty(); | |
655 | } | 658 | } | |
656 | } | 659 | } | |
657 | 660 | |||
658 | if (ntohs(appleufs->ul_namelen) == 0) { | 661 | if (ntohs(appleufs->ul_namelen) == 0) { | |
659 | pwarn("MISSING APPLE UFS LABEL NAME"); | 662 | pwarn("MISSING APPLE UFS LABEL NAME"); | |
660 | if (preen) { | 663 | if (preen) { | |
661 | printf(" (FIXED)\n"); | 664 | printf(" (FIXED)\n"); | |
662 | } | 665 | } | |
663 | if (preen || reply("FIX")) { | 666 | if (preen || reply("FIX")) { | |
664 | ffs_appleufs_set(appleufs, NULL, -1, 0); | 667 | ffs_appleufs_set(appleufs, NULL, -1, 0); | |
665 | appleufsdirty(); | 668 | appleufsdirty(); | |
666 | } | 669 | } | |
667 | } | 670 | } | |
668 | 671 | |||
669 | /* Scan name for first illegal character */ | 672 | /* Scan name for first illegal character */ | |
670 | for (i=0;i<ntohs(appleufs->ul_namelen);i++) { | 673 | for (i=0;i<ntohs(appleufs->ul_namelen);i++) { | |
671 | if ((appleufs->ul_name[i] == '\0') || | 674 | if ((appleufs->ul_name[i] == '\0') || | |
672 | (appleufs->ul_name[i] == ':') || | 675 | (appleufs->ul_name[i] == ':') || | |
673 | (appleufs->ul_name[i] == '/')) { | 676 | (appleufs->ul_name[i] == '/')) { | |
674 | pwarn("APPLE UFS LABEL NAME CONTAINS ILLEGAL CHARACTER"); | 677 | pwarn("APPLE UFS LABEL NAME CONTAINS ILLEGAL CHARACTER"); | |
675 | if (preen) { | 678 | if (preen) { | |
676 | printf(" (TRUNCATED)\n"); | 679 | printf(" (TRUNCATED)\n"); | |
677 | } | 680 | } | |
678 | if (preen || reply("TRUNCATE")) { | 681 | if (preen || reply("TRUNCATE")) { | |
679 | appleufs->ul_namelen = i+1; | 682 | appleufs->ul_namelen = i+1; | |
680 | appleufsdirty(); | 683 | appleufsdirty(); | |
681 | } | 684 | } | |
682 | break; | 685 | break; | |
683 | } | 686 | } | |
684 | } | 687 | } | |
685 | 688 | |||
686 | /* Check the checksum last, because if anything else was wrong, | 689 | /* Check the checksum last, because if anything else was wrong, | |
687 | * then the checksum gets reset anyway. | 690 | * then the checksum gets reset anyway. | |
688 | */ | 691 | */ | |
689 | appleufs->ul_checksum = 0; | 692 | appleufs->ul_checksum = 0; | |
690 | appleufs->ul_checksum = ffs_appleufs_cksum(appleufs); | 693 | appleufs->ul_checksum = ffs_appleufs_cksum(appleufs); | |
691 | if (appleufsblk.b_un.b_appleufs->ul_checksum != appleufs->ul_checksum) { | 694 | if (appleufsblk.b_un.b_appleufs->ul_checksum != appleufs->ul_checksum) { | |
692 | pwarn("INVALID APPLE UFS CHECKSUM (%#04x should be %#04x)", | 695 | pwarn("INVALID APPLE UFS CHECKSUM (%#04x should be %#04x)", | |
693 | appleufsblk.b_un.b_appleufs->ul_checksum, appleufs->ul_checksum); | 696 | appleufsblk.b_un.b_appleufs->ul_checksum, appleufs->ul_checksum); | |
694 | if (preen) { | 697 | if (preen) { | |
695 | printf(" (CORRECTED)\n"); | 698 | printf(" (CORRECTED)\n"); | |
696 | } | 699 | } | |
697 | if (preen || reply("CORRECT")) { | 700 | if (preen || reply("CORRECT")) { | |
698 | appleufsdirty(); | 701 | appleufsdirty(); | |
699 | } else { | 702 | } else { | |
700 | /* put the incorrect checksum back in place */ | 703 | /* put the incorrect checksum back in place */ | |
701 | appleufs->ul_checksum = appleufsblk.b_un.b_appleufs->ul_checksum; | 704 | appleufs->ul_checksum = appleufsblk.b_un.b_appleufs->ul_checksum; | |
702 | } | 705 | } | |
703 | } | 706 | } | |
704 | return 1; | 707 | return 1; | |
705 | } | 708 | } | |
706 | #endif /* !NO_APPLE_UFS */ | 709 | #endif /* !NO_APPLE_UFS */ | |
707 | 710 | |||
708 | /* | 711 | /* | |
709 | * Detect byte order. Return 0 if valid magic found, -1 otherwise. | 712 | * Detect byte order. Return 0 if valid magic found, -1 otherwise. | |
710 | */ | 713 | */ | |
711 | static int | 714 | static int | |
712 | detect_byteorder(struct fs *fs, int sblockoff) | 715 | detect_byteorder(struct fs *fs, int sblockoff) | |
713 | { | 716 | { | |
714 | if (sblockoff == SBLOCK_UFS2 && (fs->fs_magic == FS_UFS1_MAGIC || | 717 | if (sblockoff == SBLOCK_UFS2 && (fs->fs_magic == FS_UFS1_MAGIC || | |
715 | fs->fs_magic == FS_UFS1_MAGIC_SWAPPED)) | 718 | fs->fs_magic == FS_UFS1_MAGIC_SWAPPED)) | |
716 | /* Likely to be the first alternate of a fs with 64k blocks */ | 719 | /* Likely to be the first alternate of a fs with 64k blocks */ | |
717 | return -1; | 720 | return -1; | |
718 | if (fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC) { | 721 | if (fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC) { | |
719 | #ifndef NO_FFS_EI | 722 | #ifndef NO_FFS_EI | |
720 | if (endian == 0 || BYTE_ORDER == endian) { | 723 | if (endian == 0 || BYTE_ORDER == endian) { | |
721 | needswap = 0; | 724 | needswap = 0; | |
722 | doswap = do_blkswap = do_dirswap = 0; | 725 | doswap = do_blkswap = do_dirswap = 0; | |
723 | } else { | 726 | } else { | |
724 | needswap = 1; | 727 | needswap = 1; | |
725 | doswap = do_blkswap = do_dirswap = 1; | 728 | doswap = do_blkswap = do_dirswap = 1; | |
726 | } | 729 | } | |
727 | #endif | 730 | #endif | |
728 | return 0; | 731 | return 0; | |
729 | } | 732 | } | |
730 | #ifndef NO_FFS_EI | 733 | #ifndef NO_FFS_EI | |
731 | else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED || | 734 | else if (fs->fs_magic == FS_UFS1_MAGIC_SWAPPED || | |
732 | fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) { | 735 | fs->fs_magic == FS_UFS2_MAGIC_SWAPPED) { | |
733 | if (endian == 0 || BYTE_ORDER != endian) { | 736 | if (endian == 0 || BYTE_ORDER != endian) { | |
734 | needswap = 1; | 737 | needswap = 1; | |
735 | doswap = do_blkswap = do_dirswap = 0; | 738 | doswap = do_blkswap = do_dirswap = 0; | |
736 | } else { | 739 | } else { | |
737 | needswap = 0; | 740 | needswap = 0; | |
738 | doswap = do_blkswap = do_dirswap = 1; | 741 | doswap = do_blkswap = do_dirswap = 1; | |
739 | } | 742 | } | |
740 | return 0; | 743 | return 0; | |
741 | } | 744 | } | |
742 | #endif | 745 | #endif | |
743 | return -1; | 746 | return -1; | |
744 | } | 747 | } | |
745 | 748 | |||
746 | /* | 749 | /* | |
747 | * Possible superblock locations ordered from most to least likely. | 750 | * Possible superblock locations ordered from most to least likely. | |
748 | */ | 751 | */ | |
749 | static off_t sblock_try[] = SBLOCKSEARCH; | 752 | static off_t sblock_try[] = SBLOCKSEARCH; | |
750 | 753 | |||
751 | /* | 754 | /* | |
752 | * Read in the super block and its summary info. | 755 | * Read in the super block and its summary info. | |
753 | */ | 756 | */ | |
754 | static int | 757 | static int | |
755 | readsb(int listerr) | 758 | readsb(int listerr) | |
756 | { | 759 | { | |
757 | daddr_t super = 0; | 760 | daddr_t super = 0; | |
758 | struct fs *fs; | 761 | struct fs *fs; | |
759 | int i; | 762 | int i; | |
760 | 763 | |||
761 | if (bflag) { | 764 | if (bflag) { | |
762 | super = bflag; | 765 | super = bflag; | |
763 | if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, | 766 | if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, | |
764 | (long)SBLOCKSIZE) != 0) | 767 | (long)SBLOCKSIZE) != 0) | |
765 | return (0); | 768 | return (0); | |
766 | fs = sblk.b_un.b_fs; | 769 | fs = sblk.b_un.b_fs; | |
767 | if (detect_byteorder(fs, -1) < 0) { | 770 | if (detect_byteorder(fs, -1) < 0) { | |
768 | badsb(listerr, "MAGIC NUMBER WRONG"); | 771 | badsb(listerr, "MAGIC NUMBER WRONG"); | |
769 | return (0); | 772 | return (0); | |
770 | } | 773 | } | |
771 | } else { | 774 | } else { | |
772 | for (i = 0; sblock_try[i] != -1; i++) { | 775 | for (i = 0; sblock_try[i] != -1; i++) { | |
773 | super = sblock_try[i] / dev_bsize; | 776 | super = sblock_try[i] / dev_bsize; | |
774 | if (bread(fsreadfd, (char *)sblk.b_un.b_fs, | 777 | if (bread(fsreadfd, (char *)sblk.b_un.b_fs, | |
775 | super, (long)SBLOCKSIZE) != 0) | 778 | super, (long)SBLOCKSIZE) != 0) | |
776 | continue; | 779 | continue; | |
777 | fs = sblk.b_un.b_fs; | 780 | fs = sblk.b_un.b_fs; | |
778 | if (detect_byteorder(fs, sblock_try[i]) == 0) | 781 | if (detect_byteorder(fs, sblock_try[i]) == 0) | |
779 | break; | 782 | break; | |
780 | } | 783 | } | |
781 | if (sblock_try[i] == -1) { | 784 | if (sblock_try[i] == -1) { | |
782 | badsb(listerr, "CAN'T FIND SUPERBLOCK"); | 785 | badsb(listerr, "CAN'T FIND SUPERBLOCK"); | |
783 | return (0); | 786 | return (0); | |
784 | } | 787 | } | |
785 | } | 788 | } | |
786 | if (doswap) { | 789 | if (doswap) { | |
787 | if (preen) | 790 | if (preen) | |
788 | errx(FSCK_EXIT_USAGE, | 791 | errx(FSCK_EXIT_USAGE, | |
789 | "Incompatible options -B and -p"); | 792 | "Incompatible options -B and -p"); | |
790 | if (nflag) | 793 | if (nflag) | |
791 | errx(FSCK_EXIT_USAGE, | 794 | errx(FSCK_EXIT_USAGE, | |
792 | "Incompatible options -B and -n"); | 795 | "Incompatible options -B and -n"); | |
793 | if (endian == LITTLE_ENDIAN) { | 796 | if (endian == LITTLE_ENDIAN) { | |
794 | if (!reply("CONVERT TO LITTLE ENDIAN")) | 797 | if (!reply("CONVERT TO LITTLE ENDIAN")) | |
795 | return 0; | 798 | return 0; | |
796 | } else if (endian == BIG_ENDIAN) { | 799 | } else if (endian == BIG_ENDIAN) { | |
797 | if (!reply("CONVERT TO BIG ENDIAN")) | 800 | if (!reply("CONVERT TO BIG ENDIAN")) | |
798 | return 0; | 801 | return 0; | |
799 | } else | 802 | } else | |
800 | pfatal("INTERNAL ERROR: unknown endian"); | 803 | pfatal("INTERNAL ERROR: unknown endian"); | |
801 | } | 804 | } | |
802 | if (needswap) | 805 | if (needswap) | |
803 | pwarn("** Swapped byte order\n"); | 806 | pwarn("** Swapped byte order\n"); | |
804 | /* swap SB byte order if asked */ | 807 | /* swap SB byte order if asked */ | |
805 | if (doswap) | 808 | if (doswap) | |
806 | ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); | 809 | ffs_sb_swap(sblk.b_un.b_fs, sblk.b_un.b_fs); | |
807 | 810 | |||
808 | memmove(sblock, sblk.b_un.b_fs, SBLOCKSIZE); | 811 | memmove(sblock, sblk.b_un.b_fs, SBLOCKSIZE); | |
809 | if (needswap) | 812 | if (needswap) | |
810 | ffs_sb_swap(sblk.b_un.b_fs, sblock); | 813 | ffs_sb_swap(sblk.b_un.b_fs, sblock); | |
811 | 814 | |||
812 | is_ufs2 = sblock->fs_magic == FS_UFS2_MAGIC; | 815 | is_ufs2 = sblock->fs_magic == FS_UFS2_MAGIC; | |
813 | 816 | |||
814 | /* | 817 | /* | |
815 | * run a few consistency checks of the super block | 818 | * run a few consistency checks of the super block | |
816 | */ | 819 | */ | |
817 | if (sblock->fs_sbsize > SBLOCKSIZE) | 820 | if (sblock->fs_sbsize > SBLOCKSIZE) | |
818 | { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } | 821 | { badsb(listerr, "SIZE PREPOSTEROUSLY LARGE"); return (0); } | |
819 | /* | 822 | /* | |
820 | * Compute block size that the filesystem is based on, | 823 | * Compute block size that the filesystem is based on, | |
821 | * according to FFS_FSBTODB, and adjust superblock block number | 824 | * according to FFS_FSBTODB, and adjust superblock block number | |
822 | * so we can tell if this is an alternate later. | 825 | * so we can tell if this is an alternate later. | |
823 | */ | 826 | */ | |
824 | super *= dev_bsize; | 827 | super *= dev_bsize; | |
825 | dev_bsize = sblock->fs_fsize / FFS_FSBTODB(sblock, 1); | 828 | dev_bsize = sblock->fs_fsize / FFS_FSBTODB(sblock, 1); | |
826 | sblk.b_bno = super / dev_bsize; | 829 | sblk.b_bno = super / dev_bsize; | |
827 | sblk.b_size = SBLOCKSIZE; | 830 | sblk.b_size = SBLOCKSIZE; | |
828 | if (bflag) | 831 | if (bflag) | |
829 | goto out; | 832 | goto out; | |
830 | /* | 833 | /* | |
831 | * Set all possible fields that could differ, then do check | 834 | * Set all possible fields that could differ, then do check | |
832 | * of whole super block against an alternate super block-> | 835 | * of whole super block against an alternate super block-> | |
833 | * When an alternate super-block is specified this check is skipped. | 836 | * When an alternate super-block is specified this check is skipped. | |
834 | */ | 837 | */ | |
835 | getblk(&asblk, cgsblock(sblock, sblock->fs_ncg - 1), sblock->fs_sbsize); | 838 | getblk(&asblk, cgsblock(sblock, sblock->fs_ncg - 1), sblock->fs_sbsize); | |
836 | if (asblk.b_errs) | 839 | if (asblk.b_errs) | |
837 | return (0); | 840 | return (0); | |
838 | /* swap SB byte order if asked */ | 841 | /* swap SB byte order if asked */ | |
839 | if (doswap) | 842 | if (doswap) | |
840 | ffs_sb_swap(asblk.b_un.b_fs, asblk.b_un.b_fs); | 843 | ffs_sb_swap(asblk.b_un.b_fs, asblk.b_un.b_fs); | |
841 | 844 | |||
842 | memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize); | 845 | memmove(altsblock, asblk.b_un.b_fs, sblock->fs_sbsize); | |
843 | if (needswap) | 846 | if (needswap) | |
844 | ffs_sb_swap(asblk.b_un.b_fs, altsblock); | 847 | ffs_sb_swap(asblk.b_un.b_fs, altsblock); | |
845 | if (cmpsblks(sblock, altsblock)) { | 848 | if (cmpsblks(sblock, altsblock)) { | |
846 | if (debug) { | 849 | if (debug) { | |
847 | uint32_t *nlp, *olp, *endlp; | 850 | uint32_t *nlp, *olp, *endlp; | |
848 | 851 | |||
849 | printf("superblock mismatches\n"); | 852 | printf("superblock mismatches\n"); | |
850 | nlp = (uint32_t *)altsblock; | 853 | nlp = (uint32_t *)altsblock; | |
851 | olp = (uint32_t *)sblock; | 854 | olp = (uint32_t *)sblock; | |
852 | endlp = olp + (sblock->fs_sbsize / sizeof *olp); | 855 | endlp = olp + (sblock->fs_sbsize / sizeof *olp); | |
853 | for ( ; olp < endlp; olp++, nlp++) { | 856 | for ( ; olp < endlp; olp++, nlp++) { | |
854 | if (*olp == *nlp) | 857 | if (*olp == *nlp) | |
855 | continue; | 858 | continue; | |
856 | printf("offset %#x, original 0x%08x, alternate " | 859 | printf("offset %#x, original 0x%08x, alternate " | |
857 | "0x%08x\n", | 860 | "0x%08x\n", | |
858 | (int)((uint8_t *)olp-(uint8_t *)sblock), | 861 | (int)((uint8_t *)olp-(uint8_t *)sblock), | |
859 | *olp, *nlp); | 862 | *olp, *nlp); | |
860 | } | 863 | } | |
861 | } | 864 | } | |
862 | badsb(listerr, | 865 | badsb(listerr, | |
863 | "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); | 866 | "VALUES IN SUPER BLOCK DISAGREE WITH THOSE IN FIRST ALTERNATE"); | |
864 | /* | 867 | /* | |
865 | return (0); | 868 | return (0); | |
866 | */ | 869 | */ | |
867 | } | 870 | } | |
868 | out: | 871 | out: | |
869 | 872 | |||
870 | sb_oldfscompat_read(sblock, &sblocksave); | 873 | sb_oldfscompat_read(sblock, &sblocksave); | |
871 | 874 | |||
872 | /* Now we know the SB is valid, we can write it back if needed */ | 875 | /* Now we know the SB is valid, we can write it back if needed */ | |
873 | if (doswap) { | 876 | if (doswap) { | |
874 | sbdirty(); | 877 | sbdirty(); | |
875 | dirty(&asblk); | 878 | dirty(&asblk); | |
876 | } | 879 | } | |
877 | havesb = 1; | 880 | havesb = 1; | |
878 | return (1); | 881 | return (1); | |
879 | } | 882 | } | |
880 | 883 | |||
881 | int | 884 | int | |
882 | cmpsblks(const struct fs *sb, struct fs *asb) | 885 | cmpsblks(const struct fs *sb, struct fs *asb) | |
883 | { | 886 | { | |
884 | if (!is_ufs2 && ((sb->fs_old_flags & FS_FLAGS_UPDATED) == 0)) { | 887 | if (!is_ufs2 && ((sb->fs_old_flags & FS_FLAGS_UPDATED) == 0)) { | |
885 | if (sb->fs_old_postblformat < FS_DYNAMICPOSTBLFMT) | 888 | if (sb->fs_old_postblformat < FS_DYNAMICPOSTBLFMT) | |
886 | return cmpsblks42(sb, asb); | 889 | return cmpsblks42(sb, asb); | |
887 | else | 890 | else | |
888 | return cmpsblks44(sb, asb); | 891 | return cmpsblks44(sb, asb); | |
889 | } | 892 | } | |
890 | if (asb->fs_sblkno != sb->fs_sblkno || | 893 | if (asb->fs_sblkno != sb->fs_sblkno || | |
891 | asb->fs_cblkno != sb->fs_cblkno || | 894 | asb->fs_cblkno != sb->fs_cblkno || | |
892 | asb->fs_iblkno != sb->fs_iblkno || | 895 | asb->fs_iblkno != sb->fs_iblkno || | |
893 | asb->fs_dblkno != sb->fs_dblkno || | 896 | asb->fs_dblkno != sb->fs_dblkno || | |
894 | asb->fs_ncg != sb->fs_ncg || | 897 | asb->fs_ncg != sb->fs_ncg || | |
895 | asb->fs_bsize != sb->fs_bsize || | 898 | asb->fs_bsize != sb->fs_bsize || | |
896 | asb->fs_fsize != sb->fs_fsize || | 899 | asb->fs_fsize != sb->fs_fsize || | |
897 | asb->fs_frag != sb->fs_frag || | 900 | asb->fs_frag != sb->fs_frag || | |
898 | asb->fs_bmask != sb->fs_bmask || | 901 | asb->fs_bmask != sb->fs_bmask || | |
899 | asb->fs_fmask != sb->fs_fmask || | 902 | asb->fs_fmask != sb->fs_fmask || | |
900 | asb->fs_bshift != sb->fs_bshift || | 903 | asb->fs_bshift != sb->fs_bshift || | |
901 | asb->fs_fshift != sb->fs_fshift || | 904 | asb->fs_fshift != sb->fs_fshift || | |
902 | asb->fs_fragshift != sb->fs_fragshift || | 905 | asb->fs_fragshift != sb->fs_fragshift || | |
903 | asb->fs_fsbtodb != sb->fs_fsbtodb || | 906 | asb->fs_fsbtodb != sb->fs_fsbtodb || | |
904 | asb->fs_sbsize != sb->fs_sbsize || | 907 | asb->fs_sbsize != sb->fs_sbsize || | |
905 | asb->fs_nindir != sb->fs_nindir || | 908 | asb->fs_nindir != sb->fs_nindir || | |
906 | asb->fs_inopb != sb->fs_inopb || | 909 | asb->fs_inopb != sb->fs_inopb || | |
907 | asb->fs_cssize != sb->fs_cssize || | 910 | asb->fs_cssize != sb->fs_cssize || | |
908 | asb->fs_ipg != sb->fs_ipg || | 911 | asb->fs_ipg != sb->fs_ipg || | |
909 | asb->fs_fpg != sb->fs_fpg || | 912 | asb->fs_fpg != sb->fs_fpg || | |
910 | asb->fs_magic != sb->fs_magic) | 913 | asb->fs_magic != sb->fs_magic) | |
911 | return 1; | 914 | return 1; | |
912 | return 0; | 915 | return 0; | |
913 | } | 916 | } | |
914 | 917 | |||
915 | /* BSD 4.2 performed the following superblock comparison | 918 | /* BSD 4.2 performed the following superblock comparison | |
916 | * It should correspond to FS_42POSTBLFMT | 919 | * It should correspond to FS_42POSTBLFMT | |
917 | * (although note that in 4.2, the fs_old_postblformat | 920 | * (although note that in 4.2, the fs_old_postblformat | |
918 | * field didn't exist and the corresponding bits are | 921 | * field didn't exist and the corresponding bits are | |
919 | * located near the end of the postbl itself, where they | 922 | * located near the end of the postbl itself, where they | |
920 | * are not likely to be used.) | 923 | * are not likely to be used.) | |
921 | */ | 924 | */ | |
922 | int | 925 | int | |
923 | cmpsblks42(const struct fs *sb, struct fs *asb) | 926 | cmpsblks42(const struct fs *sb, struct fs *asb) | |
924 | { | 927 | { | |
925 | asb->fs_firstfield = sb->fs_firstfield; /* fs_link */ | 928 | asb->fs_firstfield = sb->fs_firstfield; /* fs_link */ | |
926 | asb->fs_unused_1 = sb->fs_unused_1; /* fs_rlink */ | 929 | asb->fs_unused_1 = sb->fs_unused_1; /* fs_rlink */ | |
927 | asb->fs_old_time = sb->fs_old_time; /* fs_time */ | 930 | asb->fs_old_time = sb->fs_old_time; /* fs_time */ | |
928 | asb->fs_old_cstotal = sb->fs_old_cstotal; /* fs_cstotal */ | 931 | asb->fs_old_cstotal = sb->fs_old_cstotal; /* fs_cstotal */ | |
929 | asb->fs_cgrotor = sb->fs_cgrotor; | 932 | asb->fs_cgrotor = sb->fs_cgrotor; | |
930 | asb->fs_fmod = sb->fs_fmod; | 933 | asb->fs_fmod = sb->fs_fmod; | |
931 | asb->fs_clean = sb->fs_clean; | 934 | asb->fs_clean = sb->fs_clean; | |
932 | asb->fs_ronly = sb->fs_ronly; | 935 | asb->fs_ronly = sb->fs_ronly; | |
933 | asb->fs_old_flags = sb->fs_old_flags; | 936 | asb->fs_old_flags = sb->fs_old_flags; | |
934 | asb->fs_maxcontig = sb->fs_maxcontig; | 937 | asb->fs_maxcontig = sb->fs_maxcontig; | |
935 | asb->fs_minfree = sb->fs_minfree; | 938 | asb->fs_minfree = sb->fs_minfree; | |
936 | asb->fs_old_rotdelay = sb->fs_old_rotdelay; | 939 | asb->fs_old_rotdelay = sb->fs_old_rotdelay; | |
937 | asb->fs_maxbpg = sb->fs_maxbpg; | 940 | asb->fs_maxbpg = sb->fs_maxbpg; | |
938 | 941 | |||
939 | /* The former fs_csp, totaling 128 bytes */ | 942 | /* The former fs_csp, totaling 128 bytes */ | |
940 | memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); | 943 | memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); | |
941 | asb->fs_contigdirs = sb->fs_contigdirs; | 944 | asb->fs_contigdirs = sb->fs_contigdirs; | |
942 | asb->fs_csp = sb->fs_csp; | 945 | asb->fs_csp = sb->fs_csp; | |
943 | asb->fs_maxcluster = sb->fs_maxcluster; | 946 | asb->fs_maxcluster = sb->fs_maxcluster; | |
944 | asb->fs_active = sb->fs_active; | 947 | asb->fs_active = sb->fs_active; | |
945 | 948 | |||
946 | /* The former fs_fsmnt, totaling 512 bytes */ | 949 | /* The former fs_fsmnt, totaling 512 bytes */ | |
947 | memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); | 950 | memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); | |
948 | memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname); | 951 | memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname); | |
949 | 952 | |||
950 | return memcmp(sb, asb, sb->fs_sbsize); | 953 | return memcmp(sb, asb, sb->fs_sbsize); | |
951 | } | 954 | } | |
952 | 955 | |||
953 | /* BSD 4.4 performed the following superblock comparison | 956 | /* BSD 4.4 performed the following superblock comparison | |
954 | * This was used in NetBSD through 1.6.1 | 957 | * This was used in NetBSD through 1.6.1 | |
955 | * | 958 | * | |
956 | * Note that this implementation is destructive to asb. | 959 | * Note that this implementation is destructive to asb. | |
957 | */ | 960 | */ | |
958 | int | 961 | int | |
959 | cmpsblks44(const struct fs *sb, struct fs *asb) | 962 | cmpsblks44(const struct fs *sb, struct fs *asb) | |
960 | { | 963 | { | |
961 | /* | 964 | /* | |
962 | * "Copy fields which we don't care if they're different in the | 965 | * "Copy fields which we don't care if they're different in the | |
963 | * alternate superblocks, as they're either likely to be | 966 | * alternate superblocks, as they're either likely to be | |
964 | * different because they're per-cylinder-group specific, or | 967 | * different because they're per-cylinder-group specific, or | |
965 | * because they're transient details which are only maintained | 968 | * because they're transient details which are only maintained | |
966 | * in the primary superblock." | 969 | * in the primary superblock." | |
967 | */ | 970 | */ | |
968 | asb->fs_firstfield = sb->fs_firstfield; | 971 | asb->fs_firstfield = sb->fs_firstfield; | |
969 | asb->fs_unused_1 = sb->fs_unused_1; | 972 | asb->fs_unused_1 = sb->fs_unused_1; | |
970 | asb->fs_old_time = sb->fs_old_time; | 973 | asb->fs_old_time = sb->fs_old_time; | |
971 | asb->fs_old_cstotal = sb->fs_old_cstotal; | 974 | asb->fs_old_cstotal = sb->fs_old_cstotal; | |
972 | asb->fs_cgrotor = sb->fs_cgrotor; | 975 | asb->fs_cgrotor = sb->fs_cgrotor; | |
973 | asb->fs_fmod = sb->fs_fmod; | 976 | asb->fs_fmod = sb->fs_fmod; | |
974 | asb->fs_clean = sb->fs_clean; | 977 | asb->fs_clean = sb->fs_clean; | |
975 | asb->fs_ronly = sb->fs_ronly; | 978 | asb->fs_ronly = sb->fs_ronly; | |
976 | asb->fs_old_flags = sb->fs_old_flags; | 979 | asb->fs_old_flags = sb->fs_old_flags; | |
977 | asb->fs_maxcontig = sb->fs_maxcontig; | 980 | asb->fs_maxcontig = sb->fs_maxcontig; | |
978 | asb->fs_minfree = sb->fs_minfree; | 981 | asb->fs_minfree = sb->fs_minfree; | |
979 | asb->fs_optim = sb->fs_optim; | 982 | asb->fs_optim = sb->fs_optim; | |
980 | asb->fs_old_rotdelay = sb->fs_old_rotdelay; | 983 | asb->fs_old_rotdelay = sb->fs_old_rotdelay; | |
981 | asb->fs_maxbpg = sb->fs_maxbpg; | 984 | asb->fs_maxbpg = sb->fs_maxbpg; | |
982 | 985 | |||
983 | /* The former fs_csp and fs_maxcluster, totaling 128 bytes */ | 986 | /* The former fs_csp and fs_maxcluster, totaling 128 bytes */ | |
984 | memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); | 987 | memmove(asb->fs_ocsp, sb->fs_ocsp, sizeof sb->fs_ocsp); | |
985 | asb->fs_contigdirs = sb->fs_contigdirs; | 988 | asb->fs_contigdirs = sb->fs_contigdirs; | |
986 | asb->fs_csp = sb->fs_csp; | 989 | asb->fs_csp = sb->fs_csp; | |
987 | asb->fs_maxcluster = sb->fs_maxcluster; | 990 | asb->fs_maxcluster = sb->fs_maxcluster; | |
988 | asb->fs_active = sb->fs_active; | 991 | asb->fs_active = sb->fs_active; | |
989 | 992 | |||
990 | /* The former fs_fsmnt, totaling 512 bytes */ | 993 | /* The former fs_fsmnt, totaling 512 bytes */ | |
991 | memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); | 994 | memmove(asb->fs_fsmnt, sb->fs_fsmnt, sizeof sb->fs_fsmnt); | |
992 | memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname); | 995 | memmove(asb->fs_volname, sb->fs_volname, sizeof sb->fs_volname); | |
993 | 996 | |||
994 | /* The former fs_sparecon, totaling 200 bytes */ | 997 | /* The former fs_sparecon, totaling 200 bytes */ | |
995 | memmove(asb->fs_snapinum, | 998 | memmove(asb->fs_snapinum, | |
996 | sb->fs_snapinum, sizeof sb->fs_snapinum); | 999 | sb->fs_snapinum, sizeof sb->fs_snapinum); | |
997 | asb->fs_avgfilesize = sb->fs_avgfilesize; | 1000 | asb->fs_avgfilesize = sb->fs_avgfilesize; | |
998 | asb->fs_avgfpdir = sb->fs_avgfpdir; | 1001 | asb->fs_avgfpdir = sb->fs_avgfpdir; | |
999 | asb->fs_save_cgsize = sb->fs_save_cgsize; | 1002 | asb->fs_save_cgsize = sb->fs_save_cgsize; | |
1000 | memmove(asb->fs_sparecon32, | 1003 | memmove(asb->fs_sparecon32, | |
1001 | sb->fs_sparecon32, sizeof sb->fs_sparecon32); | 1004 | sb->fs_sparecon32, sizeof sb->fs_sparecon32); | |
1002 | asb->fs_flags = sb->fs_flags; | 1005 | asb->fs_flags = sb->fs_flags; | |
1003 | 1006 | |||
1004 | /* Original comment: | 1007 | /* Original comment: | |
1005 | * "The following should not have to be copied, but need to be." | 1008 | * "The following should not have to be copied, but need to be." | |
1006 | */ | 1009 | */ | |
1007 | asb->fs_fsbtodb = sb->fs_fsbtodb; | 1010 | asb->fs_fsbtodb = sb->fs_fsbtodb; | |
1008 | asb->fs_old_interleave = sb->fs_old_interleave; | 1011 | asb->fs_old_interleave = sb->fs_old_interleave; | |
1009 | asb->fs_old_npsect = sb->fs_old_npsect; | 1012 | asb->fs_old_npsect = sb->fs_old_npsect; | |
1010 | asb->fs_old_nrpos = sb->fs_old_nrpos; | 1013 | asb->fs_old_nrpos = sb->fs_old_nrpos; | |
1011 | asb->fs_state = sb->fs_state; | 1014 | asb->fs_state = sb->fs_state; | |
1012 | asb->fs_qbmask = sb->fs_qbmask; | 1015 | asb->fs_qbmask = sb->fs_qbmask; | |
1013 | asb->fs_qfmask = sb->fs_qfmask; | 1016 | asb->fs_qfmask = sb->fs_qfmask; | |
1014 | asb->fs_state = sb->fs_state; | 1017 | asb->fs_state = sb->fs_state; | |
1015 | asb->fs_maxfilesize = sb->fs_maxfilesize; | 1018 | asb->fs_maxfilesize = sb->fs_maxfilesize; | |
1016 | 1019 | |||
1017 | /* | 1020 | /* | |
1018 | * "Compare the superblocks, effectively checking every other | 1021 | * "Compare the superblocks, effectively checking every other | |
1019 | * field to see if they differ." | 1022 | * field to see if they differ." | |
1020 | */ | 1023 | */ | |
1021 | return memcmp(sb, asb, sb->fs_sbsize); | 1024 | return memcmp(sb, asb, sb->fs_sbsize); | |
1022 | } | 1025 | } | |
1023 | 1026 | |||
1024 | 1027 | |||
1025 | static void | 1028 | static void | |
1026 | badsb(int listerr, const char *s) | 1029 | badsb(int listerr, const char *s) | |
1027 | { | 1030 | { | |
1028 | 1031 | |||
1029 | if (!listerr) | 1032 | if (!listerr) | |
1030 | return; | 1033 | return; | |
1031 | if (preen) | 1034 | if (preen) | |
1032 | printf("%s: ", cdevname()); | 1035 | printf("%s: ", cdevname()); | |
1033 | pfatal("BAD SUPER BLOCK: %s\n", s); | 1036 | pfatal("BAD SUPER BLOCK: %s\n", s); | |
1034 | } | 1037 | } | |
1035 | 1038 | |||
1036 | /* | 1039 | /* | |
1037 | * Calculate a prototype superblock based on information in the disk label. | 1040 | * Calculate a prototype superblock based on information in the disk label. | |
1038 | * When done the cgsblock macro can be calculated and the fs_ncg field | 1041 | * When done the cgsblock macro can be calculated and the fs_ncg field | |
1039 | * can be used. Do NOT attempt to use other macros without verifying that | 1042 | * can be used. Do NOT attempt to use other macros without verifying that | |
1040 | * their needed information is available! | 1043 | * their needed information is available! | |
1041 | */ | 1044 | */ | |
1042 | static int | 1045 | static int | |
1043 | calcsb(const char *dev, int devfd, struct fs *fs) | 1046 | calcsb(const char *dev, int devfd, struct fs *fs) | |
1044 | { | 1047 | { | |
1045 | struct dkwedge_info dkw; | 1048 | struct dkwedge_info dkw; | |
1046 | struct disk_geom geo; | 1049 | struct disk_geom geo; | |
1047 | int i, nspf; | 1050 | int i, nspf; | |
1048 | 1051 | |||
1049 | if (getdiskinfo(dev, fsreadfd, NULL, &geo, &dkw) == -1) | 1052 | if (getdiskinfo(dev, fsreadfd, NULL, &geo, &dkw) == -1) | |
1050 | pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); | 1053 | pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); | |
1051 | if (dkw.dkw_parent[0] == '\0') { | 1054 | if (dkw.dkw_parent[0] == '\0') { | |
1052 | pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); | 1055 | pfatal("%s: CANNOT FIGURE OUT FILE SYSTEM PARTITION\n", dev); | |
1053 | return (0); | 1056 | return (0); | |
1054 | } | 1057 | } | |
1055 | if (strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) | 1058 | if (strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) | |
1056 | #ifndef NO_APPLE_UFS | 1059 | #ifndef NO_APPLE_UFS | |
1057 | && strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) | 1060 | && strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) | |
1058 | #endif | 1061 | #endif | |
1059 | ) { | 1062 | ) { | |
1060 | pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", | 1063 | pfatal("%s: NOT LABELED AS A BSD FILE SYSTEM (%s)\n", | |
1061 | dev, dkw.dkw_ptype); | 1064 | dev, dkw.dkw_ptype); | |
1062 | return (0); | 1065 | return (0); | |
1063 | } | 1066 | } | |
1064 | if (geo.dg_secsize == 0) { | 1067 | if (geo.dg_secsize == 0) { | |
1065 | pfatal("%s: CANNOT FIGURE OUT SECTOR SIZE\n", dev); | 1068 | pfatal("%s: CANNOT FIGURE OUT SECTOR SIZE\n", dev); | |
1066 | return 0; | 1069 | return 0; | |
1067 | } | 1070 | } | |
1068 | if (geo.dg_secpercyl == 0) { | 1071 | if (geo.dg_secpercyl == 0) { | |
1069 | pfatal("%s: CANNOT FIGURE OUT SECTORS PER CYLINDER\n", dev); | 1072 | pfatal("%s: CANNOT FIGURE OUT SECTORS PER CYLINDER\n", dev); | |
1070 | return 0; | 1073 | return 0; | |
1071 | } | 1074 | } | |
1072 | if (sblk.b_un.b_fs->fs_fsize == 0) { | 1075 | if (sblk.b_un.b_fs->fs_fsize == 0) { | |
1073 | pfatal("%s: CANNOT FIGURE OUT FRAG BLOCK SIZE\n", dev); | 1076 | pfatal("%s: CANNOT FIGURE OUT FRAG BLOCK SIZE\n", dev); | |
1074 | return 0; | 1077 | return 0; | |
1075 | } | 1078 | } | |
1076 | if (sblk.b_un.b_fs->fs_fpg == 0) { | 1079 | if (sblk.b_un.b_fs->fs_fpg == 0) { | |
1077 | pfatal("%s: CANNOT FIGURE OUT FRAGS PER GROUP\n", dev); | 1080 | pfatal("%s: CANNOT FIGURE OUT FRAGS PER GROUP\n", dev); | |
1078 | return 0; | 1081 | return 0; | |
1079 | } | 1082 | } | |
1080 | if (sblk.b_un.b_fs->fs_old_cpg == 0) { | 1083 | if (sblk.b_un.b_fs->fs_old_cpg == 0) { | |
1081 | pfatal("%s: CANNOT FIGURE OUT OLD CYLINDERS PER GROUP\n", dev); | 1084 | pfatal("%s: CANNOT FIGURE OUT OLD CYLINDERS PER GROUP\n", dev); | |
1082 | return 0; | 1085 | return 0; | |
1083 | } | 1086 | } | |
1084 | memcpy(fs, sblk.b_un.b_fs, sizeof(struct fs)); | 1087 | memcpy(fs, sblk.b_un.b_fs, sizeof(struct fs)); | |
1085 | nspf = fs->fs_fsize / geo.dg_secsize; | 1088 | nspf = fs->fs_fsize / geo.dg_secsize; | |
1086 | fs->fs_old_nspf = nspf; | 1089 | fs->fs_old_nspf = nspf; | |
1087 | for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1) | 1090 | for (fs->fs_fsbtodb = 0, i = nspf; i > 1; i >>= 1) | |
1088 | fs->fs_fsbtodb++; | 1091 | fs->fs_fsbtodb++; | |
1089 | dev_bsize = geo.dg_secsize; | 1092 | dev_bsize = geo.dg_secsize; | |
1090 | if (fs->fs_magic == FS_UFS2_MAGIC) { | 1093 | if (fs->fs_magic == FS_UFS2_MAGIC) { | |
1091 | fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg); | 1094 | fs->fs_ncg = howmany(fs->fs_size, fs->fs_fpg); | |
1092 | } else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ { | 1095 | } else /* if (fs->fs_magic == FS_UFS1_MAGIC) */ { | |
1093 | fs->fs_old_cgmask = 0xffffffff; | 1096 | fs->fs_old_cgmask = 0xffffffff; | |
1094 | for (i = geo.dg_ntracks; i > 1; i >>= 1) | 1097 | for (i = geo.dg_ntracks; i > 1; i >>= 1) | |
1095 | fs->fs_old_cgmask <<= 1; | 1098 | fs->fs_old_cgmask <<= 1; | |
1096 | if (!POWEROF2(geo.dg_ntracks)) | 1099 | if (!POWEROF2(geo.dg_ntracks)) | |
1097 | fs->fs_old_cgmask <<= 1; | 1100 | fs->fs_old_cgmask <<= 1; | |
1098 | fs->fs_old_cgoffset = roundup( | 1101 | fs->fs_old_cgoffset = roundup( | |
1099 | howmany(geo.dg_nsectors, nspf), fs->fs_frag); | 1102 | howmany(geo.dg_nsectors, nspf), fs->fs_frag); | |
1100 | fs->fs_fpg = (fs->fs_old_cpg * geo.dg_secpercyl) / nspf; | 1103 | fs->fs_fpg = (fs->fs_old_cpg * geo.dg_secpercyl) / nspf; | |
1101 | fs->fs_ncg = howmany(fs->fs_size / geo.dg_secpercyl, | 1104 | fs->fs_ncg = howmany(fs->fs_size / geo.dg_secpercyl, | |
1102 | fs->fs_old_cpg); | 1105 | fs->fs_old_cpg); | |
1103 | } | 1106 | } | |
1104 | return (1); | 1107 | return (1); | |
1105 | } | 1108 | } | |
1106 | 1109 | |||
1107 | /* | 1110 | /* | |
1108 | * Test the list of snapshot inode numbers for duplicates and repair. | 1111 | * Test the list of snapshot inode numbers for duplicates and repair. | |
1109 | */ | 1112 | */ | |
1110 | static int | 1113 | static int | |
1111 | check_snapinum(void) | 1114 | check_snapinum(void) | |
1112 | { | 1115 | { | |
1113 | int loc, loc2, res; | 1116 | int loc, loc2, res; | |
1114 | int *snapinum = &sblock->fs_snapinum[0]; | 1117 | int *snapinum = &sblock->fs_snapinum[0]; | |
1115 | 1118 | |||
1116 | res = 0; | 1119 | res = 0; | |
1117 | 1120 | |||
1118 | if (isappleufs) | 1121 | if (isappleufs) | |
1119 | return 0; | 1122 | return 0; | |
1120 | 1123 | |||
1121 | for (loc = 0; loc < FSMAXSNAP; loc++) { | 1124 | for (loc = 0; loc < FSMAXSNAP; loc++) { | |
1122 | if (snapinum[loc] == 0) | 1125 | if (snapinum[loc] == 0) | |
1123 | break; | 1126 | break; | |
1124 | for (loc2 = loc + 1; loc2 < FSMAXSNAP; loc2++) { | 1127 | for (loc2 = loc + 1; loc2 < FSMAXSNAP; loc2++) { | |
1125 | if (snapinum[loc2] == 0 || | 1128 | if (snapinum[loc2] == 0 || | |
1126 | snapinum[loc2] == snapinum[loc]) | 1129 | snapinum[loc2] == snapinum[loc]) | |
1127 | break; | 1130 | break; | |
1128 | } | 1131 | } | |
1129 | if (loc2 >= FSMAXSNAP || snapinum[loc2] == 0) | 1132 | if (loc2 >= FSMAXSNAP || snapinum[loc2] == 0) | |
1130 | continue; | 1133 | continue; | |
1131 | pwarn("SNAPSHOT INODE %u ALREADY ON LIST%s", snapinum[loc2], | 1134 | pwarn("SNAPSHOT INODE %u ALREADY ON LIST%s", snapinum[loc2], | |
1132 | (res ? "" : "\n")); | 1135 | (res ? "" : "\n")); | |
1133 | res = 1; | 1136 | res = 1; | |
1134 | for (loc2 = loc + 1; loc2 < FSMAXSNAP; loc2++) { | 1137 | for (loc2 = loc + 1; loc2 < FSMAXSNAP; loc2++) { | |
1135 | if (snapinum[loc2] == 0) | 1138 | if (snapinum[loc2] == 0) | |
1136 | break; | 1139 | break; | |
1137 | snapinum[loc2 - 1] = snapinum[loc2]; | 1140 | snapinum[loc2 - 1] = snapinum[loc2]; | |
1138 | } | 1141 | } | |
1139 | snapinum[loc2 - 1] = 0; | 1142 | snapinum[loc2 - 1] = 0; | |
1140 | loc--; | 1143 | loc--; | |
1141 | } | 1144 | } | |
1142 | 1145 | |||
1143 | return res; | 1146 | return res; | |
1144 | } | 1147 | } |
--- src/sbin/fsck_ffs/utilities.c 2017/02/08 16:11:40 1.65
+++ src/sbin/fsck_ffs/utilities.c 2020/04/17 09:42:27 1.66
@@ -1,773 +1,773 @@ | @@ -1,773 +1,773 @@ | |||
1 | /* $NetBSD: utilities.c,v 1.65 2017/02/08 16:11:40 rin Exp $ */ | 1 | /* $NetBSD: utilities.c,v 1.66 2020/04/17 09:42:27 jdolecek Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1980, 1986, 1993 | 4 | * Copyright (c) 1980, 1986, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * Redistribution and use in source and binary forms, with or without | 7 | * Redistribution and use in source and binary forms, with or without | |
8 | * modification, are permitted provided that the following conditions | 8 | * modification, are permitted provided that the following conditions | |
9 | * are met: | 9 | * are met: | |
10 | * 1. Redistributions of source code must retain the above copyright | 10 | * 1. Redistributions of source code must retain the above copyright | |
11 | * notice, this list of conditions and the following disclaimer. | 11 | * notice, this list of conditions and the following disclaimer. | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | 12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | 13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | 14 | * documentation and/or other materials provided with the distribution. | |
15 | * 3. Neither the name of the University nor the names of its contributors | 15 | * 3. Neither the name of the University nor the names of its contributors | |
16 | * may be used to endorse or promote products derived from this software | 16 | * may be used to endorse or promote products derived from this software | |
17 | * without specific prior written permission. | 17 | * without specific prior written permission. | |
18 | * | 18 | * | |
19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | 19 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
29 | * SUCH DAMAGE. | 29 | * SUCH DAMAGE. | |
30 | */ | 30 | */ | |
31 | 31 | |||
32 | #include <sys/cdefs.h> | 32 | #include <sys/cdefs.h> | |
33 | #ifndef lint | 33 | #ifndef lint | |
34 | #if 0 | 34 | #if 0 | |
35 | static char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; | 35 | static char sccsid[] = "@(#)utilities.c 8.6 (Berkeley) 5/19/95"; | |
36 | #else | 36 | #else | |
37 | __RCSID("$NetBSD: utilities.c,v 1.65 2017/02/08 16:11:40 rin Exp $"); | 37 | __RCSID("$NetBSD: utilities.c,v 1.66 2020/04/17 09:42:27 jdolecek Exp $"); | |
38 | #endif | 38 | #endif | |
39 | #endif /* not lint */ | 39 | #endif /* not lint */ | |
40 | 40 | |||
41 | #include <sys/param.h> | 41 | #include <sys/param.h> | |
42 | #include <sys/time.h> | 42 | #include <sys/time.h> | |
43 | 43 | |||
44 | #include <ufs/ufs/dinode.h> | 44 | #include <ufs/ufs/dinode.h> | |
45 | #include <ufs/ufs/dir.h> | 45 | #include <ufs/ufs/dir.h> | |
46 | #include <ufs/ffs/fs.h> | 46 | #include <ufs/ffs/fs.h> | |
47 | #include <ufs/ffs/ffs_extern.h> | 47 | #include <ufs/ffs/ffs_extern.h> | |
48 | #include <ufs/ufs/ufs_bswap.h> | 48 | #include <ufs/ufs/ufs_bswap.h> | |
49 | #include <ufs/ufs/quota2.h> | 49 | #include <ufs/ufs/quota2.h> | |
50 | 50 | |||
51 | #include <ctype.h> | 51 | #include <ctype.h> | |
52 | #include <err.h> | 52 | #include <err.h> | |
53 | #include <errno.h> | 53 | #include <errno.h> | |
54 | #include <stdio.h> | 54 | #include <stdio.h> | |
55 | #include <stdlib.h> | 55 | #include <stdlib.h> | |
56 | #include <string.h> | 56 | #include <string.h> | |
57 | #include <unistd.h> | 57 | #include <unistd.h> | |
58 | #include <signal.h> | 58 | #include <signal.h> | |
59 | 59 | |||
60 | #include "fsutil.h" | 60 | #include "fsutil.h" | |
61 | #include "fsck.h" | 61 | #include "fsck.h" | |
62 | #include "extern.h" | 62 | #include "extern.h" | |
63 | #include "exitvalues.h" | 63 | #include "exitvalues.h" | |
64 | 64 | |||
65 | long diskreads, totalreads; /* Disk cache statistics */ | 65 | long diskreads, totalreads; /* Disk cache statistics */ | |
66 | 66 | |||
67 | static void rwerror(const char *, daddr_t); | 67 | static void rwerror(const char *, daddr_t); | |
68 | 68 | |||
69 | int | 69 | int | |
70 | ftypeok(union dinode *dp) | 70 | ftypeok(union dinode *dp) | |
71 | { | 71 | { | |
72 | switch (iswap16(DIP(dp, mode)) & IFMT) { | 72 | switch (iswap16(DIP(dp, mode)) & IFMT) { | |
73 | 73 | |||
74 | case IFDIR: | 74 | case IFDIR: | |
75 | case IFREG: | 75 | case IFREG: | |
76 | case IFBLK: | 76 | case IFBLK: | |
77 | case IFCHR: | 77 | case IFCHR: | |
78 | case IFLNK: | 78 | case IFLNK: | |
79 | case IFSOCK: | 79 | case IFSOCK: | |
80 | case IFIFO: | 80 | case IFIFO: | |
81 | return (1); | 81 | return (1); | |
82 | 82 | |||
83 | default: | 83 | default: | |
84 | if (debug) | 84 | if (debug) | |
85 | printf("bad file type 0%o\n", iswap16(DIP(dp, mode))); | 85 | printf("bad file type 0%o\n", iswap16(DIP(dp, mode))); | |
86 | return (0); | 86 | return (0); | |
87 | } | 87 | } | |
88 | } | 88 | } | |
89 | 89 | |||
90 | int | 90 | int | |
91 | reply(const char *question) | 91 | reply(const char *question) | |
92 | { | 92 | { | |
93 | int persevere; | 93 | int persevere; | |
94 | char c; | 94 | char c; | |
95 | 95 | |||
96 | if (preen) | 96 | if (preen) | |
97 | pfatal("INTERNAL ERROR: GOT TO reply()"); | 97 | pfatal("INTERNAL ERROR: GOT TO reply()"); | |
98 | persevere = !strcmp(question, "CONTINUE"); | 98 | persevere = !strcmp(question, "CONTINUE"); | |
99 | printf("\n"); | 99 | printf("\n"); | |
100 | if (!persevere && (nflag || fswritefd < 0)) { | 100 | if (!persevere && (nflag || fswritefd < 0)) { | |
101 | printf("%s? no\n\n", question); | 101 | printf("%s? no\n\n", question); | |
102 | resolved = 0; | 102 | resolved = 0; | |
103 | return (0); | 103 | return (0); | |
104 | } | 104 | } | |
105 | if (yflag || (persevere && nflag)) { | 105 | if (yflag || (persevere && nflag)) { | |
106 | printf("%s? yes\n\n", question); | 106 | printf("%s? yes\n\n", question); | |
107 | return (1); | 107 | return (1); | |
108 | } | 108 | } | |
109 | do { | 109 | do { | |
110 | printf("%s? [yn] ", question); | 110 | printf("%s? [yn] ", question); | |
111 | (void) fflush(stdout); | 111 | (void) fflush(stdout); | |
112 | c = getc(stdin); | 112 | c = getc(stdin); | |
113 | while (c != '\n' && getc(stdin) != '\n') { | 113 | while (c != '\n' && getc(stdin) != '\n') { | |
114 | if (feof(stdin)) { | 114 | if (feof(stdin)) { | |
115 | resolved = 0; | 115 | resolved = 0; | |
116 | return (0); | 116 | return (0); | |
117 | } | 117 | } | |
118 | } | 118 | } | |
119 | } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); | 119 | } while (c != 'y' && c != 'Y' && c != 'n' && c != 'N'); | |
120 | printf("\n"); | 120 | printf("\n"); | |
121 | if (c == 'y' || c == 'Y') | 121 | if (c == 'y' || c == 'Y') | |
122 | return (1); | 122 | return (1); | |
123 | resolved = 0; | 123 | resolved = 0; | |
124 | return (0); | 124 | return (0); | |
125 | } | 125 | } | |
126 | 126 | |||
127 | /* | 127 | /* | |
128 | * Malloc buffers and set up cache. | 128 | * Malloc buffers and set up cache. | |
129 | */ | 129 | */ | |
130 | void | 130 | void | |
131 | bufinit(void) | 131 | bufinit(void) | |
132 | { | 132 | { | |
133 | struct bufarea *bp; | 133 | struct bufarea *bp; | |
134 | long bufcnt, i; | 134 | long bufcnt, i; | |
135 | char *bufp; | 135 | char *bufp; | |
136 | 136 | |||
137 | pbp = pdirbp = (struct bufarea *)0; | 137 | pbp = pdirbp = (struct bufarea *)0; | |
138 | bufp = malloc((unsigned int)sblock->fs_bsize); | 138 | bufp = aligned_alloc(DEV_BSIZE, (unsigned int)sblock->fs_bsize); | |
139 | if (bufp == 0) | 139 | if (bufp == 0) | |
140 | errexit("cannot allocate buffer pool"); | 140 | errexit("cannot allocate buffer pool"); | |
141 | cgblk.b_un.b_buf = bufp; | 141 | cgblk.b_un.b_buf = bufp; | |
142 | initbarea(&cgblk); | 142 | initbarea(&cgblk); | |
143 | #ifndef NO_APPLE_UFS | 143 | #ifndef NO_APPLE_UFS | |
144 | bufp = malloc((unsigned int)APPLEUFS_LABEL_SIZE); | 144 | bufp = aligned_alloc(DEV_BSIZE, (unsigned int)APPLEUFS_LABEL_SIZE); | |
145 | if (bufp == 0) | 145 | if (bufp == 0) | |
146 | errexit("cannot allocate buffer pool"); | 146 | errexit("cannot allocate buffer pool"); | |
147 | appleufsblk.b_un.b_buf = bufp; | 147 | appleufsblk.b_un.b_buf = bufp; | |
148 | initbarea(&appleufsblk); | 148 | initbarea(&appleufsblk); | |
149 | #endif | 149 | #endif | |
150 | bufhead.b_next = bufhead.b_prev = &bufhead; | 150 | bufhead.b_next = bufhead.b_prev = &bufhead; | |
151 | bufcnt = MAXBUFSPACE / sblock->fs_bsize; | 151 | bufcnt = MAXBUFSPACE / sblock->fs_bsize; | |
152 | if (bufcnt < MINBUFS) | 152 | if (bufcnt < MINBUFS) | |
153 | bufcnt = MINBUFS; | 153 | bufcnt = MINBUFS; | |
154 | for (i = 0; i < bufcnt; i++) { | 154 | for (i = 0; i < bufcnt; i++) { | |
155 | bp = malloc(sizeof(struct bufarea)); | 155 | bp = malloc(sizeof(struct bufarea)); | |
156 | bufp = malloc((unsigned int)sblock->fs_bsize); | 156 | bufp = aligned_alloc(DEV_BSIZE, (unsigned int)sblock->fs_bsize); | |
157 | if (bp == NULL || bufp == NULL) { | 157 | if (bp == NULL || bufp == NULL) { | |
158 | if (i >= MINBUFS) { | 158 | if (i >= MINBUFS) { | |
159 | if (bp) | 159 | if (bp) | |
160 | free(bp); | 160 | free(bp); | |
161 | if (bufp) | 161 | if (bufp) | |
162 | free(bufp); | 162 | free(bufp); | |
163 | break; | 163 | break; | |
164 | } | 164 | } | |
165 | errexit("cannot allocate buffer pool"); | 165 | errexit("cannot allocate buffer pool"); | |
166 | } | 166 | } | |
167 | bp->b_un.b_buf = bufp; | 167 | bp->b_un.b_buf = bufp; | |
168 | bp->b_prev = &bufhead; | 168 | bp->b_prev = &bufhead; | |
169 | bp->b_next = bufhead.b_next; | 169 | bp->b_next = bufhead.b_next; | |
170 | bufhead.b_next->b_prev = bp; | 170 | bufhead.b_next->b_prev = bp; | |
171 | bufhead.b_next = bp; | 171 | bufhead.b_next = bp; | |
172 | initbarea(bp); | 172 | initbarea(bp); | |
173 | } | 173 | } | |
174 | bufhead.b_size = i; /* save number of buffers */ | 174 | bufhead.b_size = i; /* save number of buffers */ | |
175 | } | 175 | } | |
176 | 176 | |||
177 | /* | 177 | /* | |
178 | * Manage a cache of directory blocks. | 178 | * Manage a cache of directory blocks. | |
179 | */ | 179 | */ | |
180 | struct bufarea * | 180 | struct bufarea * | |
181 | getdatablk(daddr_t blkno, long size) | 181 | getdatablk(daddr_t blkno, long size) | |
182 | { | 182 | { | |
183 | struct bufarea *bp; | 183 | struct bufarea *bp; | |
184 | 184 | |||
185 | for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) | 185 | for (bp = bufhead.b_next; bp != &bufhead; bp = bp->b_next) | |
186 | if (bp->b_bno == FFS_FSBTODB(sblock, blkno)) | 186 | if (bp->b_bno == FFS_FSBTODB(sblock, blkno)) | |
187 | goto foundit; | 187 | goto foundit; | |
188 | for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) | 188 | for (bp = bufhead.b_prev; bp != &bufhead; bp = bp->b_prev) | |
189 | if ((bp->b_flags & B_INUSE) == 0) | 189 | if ((bp->b_flags & B_INUSE) == 0) | |
190 | break; | 190 | break; | |
191 | if (bp == &bufhead) | 191 | if (bp == &bufhead) | |
192 | errexit("deadlocked buffer pool"); | 192 | errexit("deadlocked buffer pool"); | |
193 | /* fall through */ | 193 | /* fall through */ | |
194 | foundit: | 194 | foundit: | |
195 | getblk(bp, blkno, size); | 195 | getblk(bp, blkno, size); | |
196 | bp->b_prev->b_next = bp->b_next; | 196 | bp->b_prev->b_next = bp->b_next; | |
197 | bp->b_next->b_prev = bp->b_prev; | 197 | bp->b_next->b_prev = bp->b_prev; | |
198 | bp->b_prev = &bufhead; | 198 | bp->b_prev = &bufhead; | |
199 | bp->b_next = bufhead.b_next; | 199 | bp->b_next = bufhead.b_next; | |
200 | bufhead.b_next->b_prev = bp; | 200 | bufhead.b_next->b_prev = bp; | |
201 | bufhead.b_next = bp; | 201 | bufhead.b_next = bp; | |
202 | bp->b_flags |= B_INUSE; | 202 | bp->b_flags |= B_INUSE; | |
203 | return (bp); | 203 | return (bp); | |
204 | } | 204 | } | |
205 | 205 | |||
206 | void | 206 | void | |
207 | getblk(struct bufarea *bp, daddr_t blk, long size) | 207 | getblk(struct bufarea *bp, daddr_t blk, long size) | |
208 | { | 208 | { | |
209 | daddr_t dblk; | 209 | daddr_t dblk; | |
210 | 210 | |||
211 | dblk = FFS_FSBTODB(sblock, blk); | 211 | dblk = FFS_FSBTODB(sblock, blk); | |
212 | totalreads++; | 212 | totalreads++; | |
213 | if (bp->b_bno != dblk) { | 213 | if (bp->b_bno != dblk) { | |
214 | flush(fswritefd, bp); | 214 | flush(fswritefd, bp); | |
215 | diskreads++; | 215 | diskreads++; | |
216 | bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); | 216 | bp->b_errs = bread(fsreadfd, bp->b_un.b_buf, dblk, size); | |
217 | bp->b_bno = dblk; | 217 | bp->b_bno = dblk; | |
218 | bp->b_size = size; | 218 | bp->b_size = size; | |
219 | } | 219 | } | |
220 | } | 220 | } | |
221 | 221 | |||
222 | void | 222 | void | |
223 | flush(int fd, struct bufarea *bp) | 223 | flush(int fd, struct bufarea *bp) | |
224 | { | 224 | { | |
225 | int i, j; | 225 | int i, j; | |
226 | struct csum *ccsp; | 226 | struct csum *ccsp; | |
227 | 227 | |||
228 | if (!bp->b_dirty) | 228 | if (!bp->b_dirty) | |
229 | return; | 229 | return; | |
230 | if (bp->b_errs != 0) | 230 | if (bp->b_errs != 0) | |
231 | pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", | 231 | pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n", | |
232 | (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", | 232 | (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ", | |
233 | (long long)bp->b_bno); | 233 | (long long)bp->b_bno); | |
234 | bp->b_dirty = 0; | 234 | bp->b_dirty = 0; | |
235 | bp->b_errs = 0; | 235 | bp->b_errs = 0; | |
236 | bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); | 236 | bwrite(fd, bp->b_un.b_buf, bp->b_bno, (long)bp->b_size); | |
237 | if (bp != &sblk) | 237 | if (bp != &sblk) | |
238 | return; | 238 | return; | |
239 | for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { | 239 | for (i = 0, j = 0; i < sblock->fs_cssize; i += sblock->fs_bsize, j++) { | |
240 | int size = sblock->fs_cssize - i < sblock->fs_bsize ? | 240 | int size = sblock->fs_cssize - i < sblock->fs_bsize ? | |
241 | sblock->fs_cssize - i : sblock->fs_bsize; | 241 | sblock->fs_cssize - i : sblock->fs_bsize; | |
242 | ccsp = (struct csum *)((char *)sblock->fs_csp + i); | 242 | ccsp = (struct csum *)((char *)sblock->fs_csp + i); | |
243 | if (needswap) | 243 | if (needswap) | |
244 | ffs_csum_swap(ccsp, ccsp, size); | 244 | ffs_csum_swap(ccsp, ccsp, size); | |
245 | bwrite(fswritefd, (char *)ccsp, | 245 | bwrite(fswritefd, (char *)ccsp, | |
246 | FFS_FSBTODB(sblock, sblock->fs_csaddr + j * sblock->fs_frag), | 246 | FFS_FSBTODB(sblock, sblock->fs_csaddr + j * sblock->fs_frag), | |
247 | size); | 247 | size); | |
248 | if (needswap) | 248 | if (needswap) | |
249 | ffs_csum_swap(ccsp, ccsp, size); | 249 | ffs_csum_swap(ccsp, ccsp, size); | |
250 | } | 250 | } | |
251 | } | 251 | } | |
252 | 252 | |||
253 | static void | 253 | static void | |
254 | rwerror(const char *mesg, daddr_t blk) | 254 | rwerror(const char *mesg, daddr_t blk) | |
255 | { | 255 | { | |
256 | 256 | |||
257 | if (preen == 0) | 257 | if (preen == 0) | |
258 | printf("\n"); | 258 | printf("\n"); | |
259 | pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk); | 259 | pfatal("CANNOT %s: BLK %lld", mesg, (long long)blk); | |
260 | if (reply("CONTINUE") == 0) | 260 | if (reply("CONTINUE") == 0) | |
261 | exit(FSCK_EXIT_CHECK_FAILED); | 261 | exit(FSCK_EXIT_CHECK_FAILED); | |
262 | } | 262 | } | |
263 | 263 | |||
264 | void | 264 | void | |
265 | ckfini(int noint) | 265 | ckfini(int noint) | |
266 | { | 266 | { | |
267 | struct bufarea *bp, *nbp; | 267 | struct bufarea *bp, *nbp; | |
268 | int cnt = 0; | 268 | int cnt = 0; | |
269 | 269 | |||
270 | if (!noint) { | 270 | if (!noint) { | |
271 | if (doinglevel2) | 271 | if (doinglevel2) | |
272 | return; | 272 | return; | |
273 | markclean = 0; | 273 | markclean = 0; | |
274 | } | 274 | } | |
275 | 275 | |||
276 | if (fswritefd < 0) { | 276 | if (fswritefd < 0) { | |
277 | (void)close(fsreadfd); | 277 | (void)close(fsreadfd); | |
278 | return; | 278 | return; | |
279 | } | 279 | } | |
280 | flush(fswritefd, &sblk); | 280 | flush(fswritefd, &sblk); | |
281 | if (havesb && bflag != 0 && | 281 | if (havesb && bflag != 0 && | |
282 | (preen || reply("UPDATE STANDARD SUPERBLOCK"))) { | 282 | (preen || reply("UPDATE STANDARD SUPERBLOCK"))) { | |
283 | if (preen) | 283 | if (preen) | |
284 | pwarn("UPDATING STANDARD SUPERBLOCK\n"); | 284 | pwarn("UPDATING STANDARD SUPERBLOCK\n"); | |
285 | if (!is_ufs2 && (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) | 285 | if (!is_ufs2 && (sblock->fs_old_flags & FS_FLAGS_UPDATED) == 0) | |
286 | sblk.b_bno = SBLOCK_UFS1 / dev_bsize; | 286 | sblk.b_bno = SBLOCK_UFS1 / dev_bsize; | |
287 | else | 287 | else | |
288 | sblk.b_bno = sblock->fs_sblockloc / dev_bsize; | 288 | sblk.b_bno = sblock->fs_sblockloc / dev_bsize; | |
289 | sbdirty(); | 289 | sbdirty(); | |
290 | flush(fswritefd, &sblk); | 290 | flush(fswritefd, &sblk); | |
291 | } | 291 | } | |
292 | #ifndef NO_APPLE_UFS | 292 | #ifndef NO_APPLE_UFS | |
293 | flush(fswritefd, &appleufsblk); | 293 | flush(fswritefd, &appleufsblk); | |
294 | free(appleufsblk.b_un.b_buf); | 294 | free(appleufsblk.b_un.b_buf); | |
295 | #endif | 295 | #endif | |
296 | flush(fswritefd, &cgblk); | 296 | flush(fswritefd, &cgblk); | |
297 | free(cgblk.b_un.b_buf); | 297 | free(cgblk.b_un.b_buf); | |
298 | for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { | 298 | for (bp = bufhead.b_prev; bp && bp != &bufhead; bp = nbp) { | |
299 | cnt++; | 299 | cnt++; | |
300 | flush(fswritefd, bp); | 300 | flush(fswritefd, bp); | |
301 | nbp = bp->b_prev; | 301 | nbp = bp->b_prev; | |
302 | free(bp->b_un.b_buf); | 302 | free(bp->b_un.b_buf); | |
303 | free((char *)bp); | 303 | free((char *)bp); | |
304 | } | 304 | } | |
305 | if (bufhead.b_size != cnt) | 305 | if (bufhead.b_size != cnt) | |
306 | errexit("Panic: lost %d buffers", bufhead.b_size - cnt); | 306 | errexit("Panic: lost %d buffers", bufhead.b_size - cnt); | |
307 | pbp = pdirbp = (struct bufarea *)0; | 307 | pbp = pdirbp = (struct bufarea *)0; | |
308 | if (markclean && (sblock->fs_clean & FS_ISCLEAN) == 0) { | 308 | if (markclean && (sblock->fs_clean & FS_ISCLEAN) == 0) { | |
309 | /* | 309 | /* | |
310 | * Mark the file system as clean, and sync the superblock. | 310 | * Mark the file system as clean, and sync the superblock. | |
311 | */ | 311 | */ | |
312 | if (preen) | 312 | if (preen) | |
313 | pwarn("MARKING FILE SYSTEM CLEAN\n"); | 313 | pwarn("MARKING FILE SYSTEM CLEAN\n"); | |
314 | else if (!reply("MARK FILE SYSTEM CLEAN")) | 314 | else if (!reply("MARK FILE SYSTEM CLEAN")) | |
315 | markclean = 0; | 315 | markclean = 0; | |
316 | if (markclean) { | 316 | if (markclean) { | |
317 | sblock->fs_clean = FS_ISCLEAN; | 317 | sblock->fs_clean = FS_ISCLEAN; | |
318 | sblock->fs_pendingblocks = 0; | 318 | sblock->fs_pendingblocks = 0; | |
319 | sblock->fs_pendinginodes = 0; | 319 | sblock->fs_pendinginodes = 0; | |
320 | sbdirty(); | 320 | sbdirty(); | |
321 | flush(fswritefd, &sblk); | 321 | flush(fswritefd, &sblk); | |
322 | if (!preen) | 322 | if (!preen) | |
323 | printf( | 323 | printf( | |
324 | "\n***** FILE SYSTEM MARKED CLEAN *****\n"); | 324 | "\n***** FILE SYSTEM MARKED CLEAN *****\n"); | |
325 | } | 325 | } | |
326 | } | 326 | } | |
327 | if (debug) | 327 | if (debug) | |
328 | printf("cache missed %ld of %ld (%d%%)\n", diskreads, | 328 | printf("cache missed %ld of %ld (%d%%)\n", diskreads, | |
329 | totalreads, (int)(diskreads * 100 / totalreads)); | 329 | totalreads, (int)(diskreads * 100 / totalreads)); | |
330 | cleanup_wapbl(); | 330 | cleanup_wapbl(); | |
331 | (void)close(fsreadfd); | 331 | (void)close(fsreadfd); | |
332 | (void)close(fswritefd); | 332 | (void)close(fswritefd); | |
333 | } | 333 | } | |
334 | 334 | |||
335 | int | 335 | int | |
336 | bread(int fd, char *buf, daddr_t blk, long size) | 336 | bread(int fd, char *buf, daddr_t blk, long size) | |
337 | { | 337 | { | |
338 | char *cp; | 338 | char *cp; | |
339 | int i, errs; | 339 | int i, errs; | |
340 | off_t offset; | 340 | off_t offset; | |
341 | 341 | |||
342 | offset = blk; | 342 | offset = blk; | |
343 | offset *= dev_bsize; | 343 | offset *= dev_bsize; | |
344 | if ((pread(fd, buf, (int)size, offset) == size) && | 344 | if ((pread(fd, buf, (int)size, offset) == size) && | |
345 | read_wapbl(buf, size, blk) == 0) | 345 | read_wapbl(buf, size, blk) == 0) | |
346 | return (0); | 346 | return (0); | |
347 | rwerror("READ", blk); | 347 | rwerror("READ", blk); | |
348 | errs = 0; | 348 | errs = 0; | |
349 | memset(buf, 0, (size_t)size); | 349 | memset(buf, 0, (size_t)size); | |
350 | printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); | 350 | printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:"); | |
351 | for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { | 351 | for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) { | |
352 | if (pread(fd, cp, (int)secsize, offset + i) != secsize) { | 352 | if (pread(fd, cp, (int)secsize, offset + i) != secsize) { | |
353 | if (secsize != dev_bsize && dev_bsize != 1) | 353 | if (secsize != dev_bsize && dev_bsize != 1) | |
354 | printf(" %lld (%lld),", | 354 | printf(" %lld (%lld),", | |
355 | (long long)((blk*dev_bsize + i) / secsize), | 355 | (long long)((blk*dev_bsize + i) / secsize), | |
356 | (long long)(blk + i / dev_bsize)); | 356 | (long long)(blk + i / dev_bsize)); | |
357 | else | 357 | else | |
358 | printf(" %lld,", | 358 | printf(" %lld,", | |
359 | (long long)(blk + i / dev_bsize)); | 359 | (long long)(blk + i / dev_bsize)); | |
360 | errs++; | 360 | errs++; | |
361 | } | 361 | } | |
362 | } | 362 | } | |
363 | printf("\n"); | 363 | printf("\n"); | |
364 | return (errs); | 364 | return (errs); | |
365 | } | 365 | } | |
366 | 366 | |||
367 | void | 367 | void | |
368 | bwrite(int fd, char *buf, daddr_t blk, long size) | 368 | bwrite(int fd, char *buf, daddr_t blk, long size) | |
369 | { | 369 | { | |
370 | int i; | 370 | int i; | |
371 | char *cp; | 371 | char *cp; | |
372 | off_t offset; | 372 | off_t offset; | |
373 | 373 | |||
374 | if (fd < 0) | 374 | if (fd < 0) | |
375 | return; | 375 | return; | |
376 | offset = blk; | 376 | offset = blk; | |
377 | offset *= dev_bsize; | 377 | offset *= dev_bsize; | |
378 | if (pwrite(fd, buf, (int)size, offset) == size) { | 378 | if (pwrite(fd, buf, (int)size, offset) == size) { | |
379 | fsmodified = 1; | 379 | fsmodified = 1; | |
380 | return; | 380 | return; | |
381 | } | 381 | } | |
382 | rwerror("WRITE", blk); | 382 | rwerror("WRITE", blk); | |
383 | printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); | 383 | printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:"); | |
384 | for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) | 384 | for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize) | |
385 | if (pwrite(fd, cp, (int)dev_bsize, offset + i) != dev_bsize) | 385 | if (pwrite(fd, cp, (int)dev_bsize, offset + i) != dev_bsize) | |
386 | printf(" %lld,", (long long)(blk + i / dev_bsize)); | 386 | printf(" %lld,", (long long)(blk + i / dev_bsize)); | |
387 | printf("\n"); | 387 | printf("\n"); | |
388 | return; | 388 | return; | |
389 | } | 389 | } | |
390 | 390 | |||
391 | /* | 391 | /* | |
392 | * allocate a data block with the specified number of fragments | 392 | * allocate a data block with the specified number of fragments | |
393 | */ | 393 | */ | |
394 | daddr_t | 394 | daddr_t | |
395 | allocblk(long frags) | 395 | allocblk(long frags) | |
396 | { | 396 | { | |
397 | int i, j, k, cg, baseblk; | 397 | int i, j, k, cg, baseblk; | |
398 | struct cg *cgp = cgrp; | 398 | struct cg *cgp = cgrp; | |
399 | 399 | |||
400 | if (frags <= 0 || frags > sblock->fs_frag) | 400 | if (frags <= 0 || frags > sblock->fs_frag) | |
401 | return (0); | 401 | return (0); | |
402 | for (i = 0; i < maxfsblock - sblock->fs_frag; i += sblock->fs_frag) { | 402 | for (i = 0; i < maxfsblock - sblock->fs_frag; i += sblock->fs_frag) { | |
403 | for (j = 0; j <= sblock->fs_frag - frags; j++) { | 403 | for (j = 0; j <= sblock->fs_frag - frags; j++) { | |
404 | if (testbmap(i + j)) | 404 | if (testbmap(i + j)) | |
405 | continue; | 405 | continue; | |
406 | for (k = 1; k < frags; k++) | 406 | for (k = 1; k < frags; k++) | |
407 | if (testbmap(i + j + k)) | 407 | if (testbmap(i + j + k)) | |
408 | break; | 408 | break; | |
409 | if (k < frags) { | 409 | if (k < frags) { | |
410 | j += k; | 410 | j += k; | |
411 | continue; | 411 | continue; | |
412 | } | 412 | } | |
413 | cg = dtog(sblock, i + j); | 413 | cg = dtog(sblock, i + j); | |
414 | getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); | 414 | getblk(&cgblk, cgtod(sblock, cg), sblock->fs_cgsize); | |
415 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | 415 | memcpy(cgp, cgblk.b_un.b_cg, sblock->fs_cgsize); | |
416 | if ((doswap && !needswap) || (!doswap && needswap)) | 416 | if ((doswap && !needswap) || (!doswap && needswap)) | |
417 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | 417 | ffs_cg_swap(cgblk.b_un.b_cg, cgp, sblock); | |
418 | if (!cg_chkmagic(cgp, 0)) | 418 | if (!cg_chkmagic(cgp, 0)) | |
419 | pfatal("CG %d: ALLOCBLK: BAD MAGIC NUMBER\n", | 419 | pfatal("CG %d: ALLOCBLK: BAD MAGIC NUMBER\n", | |
420 | cg); | 420 | cg); | |
421 | baseblk = dtogd(sblock, i + j); | 421 | baseblk = dtogd(sblock, i + j); | |
422 | for (k = 0; k < frags; k++) { | 422 | for (k = 0; k < frags; k++) { | |
423 | setbmap(i + j + k); | 423 | setbmap(i + j + k); | |
424 | clrbit(cg_blksfree(cgp, 0), baseblk + k); | 424 | clrbit(cg_blksfree(cgp, 0), baseblk + k); | |
425 | } | 425 | } | |
426 | n_blks += frags; | 426 | n_blks += frags; | |
427 | if (frags == sblock->fs_frag) { | 427 | if (frags == sblock->fs_frag) { | |
428 | cgp->cg_cs.cs_nbfree--; | 428 | cgp->cg_cs.cs_nbfree--; | |
429 | sblock->fs_cstotal.cs_nbfree--; | 429 | sblock->fs_cstotal.cs_nbfree--; | |
430 | sblock->fs_cs(fs, cg).cs_nbfree--; | 430 | sblock->fs_cs(fs, cg).cs_nbfree--; | |
431 | ffs_clusteracct(sblock, cgp, | 431 | ffs_clusteracct(sblock, cgp, | |
432 | ffs_fragstoblks(sblock, baseblk), -1); | 432 | ffs_fragstoblks(sblock, baseblk), -1); | |
433 | } else { | 433 | } else { | |
434 | cgp->cg_cs.cs_nffree -= frags; | 434 | cgp->cg_cs.cs_nffree -= frags; | |
435 | sblock->fs_cstotal.cs_nffree -= frags; | 435 | sblock->fs_cstotal.cs_nffree -= frags; | |
436 | sblock->fs_cs(fs, cg).cs_nffree -= frags; | 436 | sblock->fs_cs(fs, cg).cs_nffree -= frags; | |
437 | } | 437 | } | |
438 | sbdirty(); | 438 | sbdirty(); | |
439 | cgdirty(); | 439 | cgdirty(); | |
440 | return (i + j); | 440 | return (i + j); | |
441 | } | 441 | } | |
442 | } | 442 | } | |
443 | return (0); | 443 | return (0); | |
444 | } | 444 | } | |
445 | 445 | |||
446 | /* | 446 | /* | |
447 | * Free a previously allocated block | 447 | * Free a previously allocated block | |
448 | */ | 448 | */ | |
449 | void | 449 | void | |
450 | freeblk(daddr_t blkno, long frags) | 450 | freeblk(daddr_t blkno, long frags) | |
451 | { | 451 | { | |
452 | struct inodesc idesc; | 452 | struct inodesc idesc; | |
453 | 453 | |||
454 | memset(&idesc, 0, sizeof(idesc)); | 454 | memset(&idesc, 0, sizeof(idesc)); | |
455 | idesc.id_blkno = blkno; | 455 | idesc.id_blkno = blkno; | |
456 | idesc.id_numfrags = frags; | 456 | idesc.id_numfrags = frags; | |
457 | (void)pass4check(&idesc); | 457 | (void)pass4check(&idesc); | |
458 | } | 458 | } | |
459 | 459 | |||
460 | /* | 460 | /* | |
461 | * Find a pathname | 461 | * Find a pathname | |
462 | */ | 462 | */ | |
463 | void | 463 | void | |
464 | getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) | 464 | getpathname(char *namebuf, size_t namebuflen, ino_t curdir, ino_t ino) | |
465 | { | 465 | { | |
466 | int len; | 466 | int len; | |
467 | char *cp; | 467 | char *cp; | |
468 | struct inodesc idesc; | 468 | struct inodesc idesc; | |
469 | static int busy = 0; | 469 | static int busy = 0; | |
470 | struct inostat *info; | 470 | struct inostat *info; | |
471 | 471 | |||
472 | if (curdir == ino && ino == UFS_ROOTINO) { | 472 | if (curdir == ino && ino == UFS_ROOTINO) { | |
473 | (void)strlcpy(namebuf, "/", namebuflen); | 473 | (void)strlcpy(namebuf, "/", namebuflen); | |
474 | return; | 474 | return; | |
475 | } | 475 | } | |
476 | info = inoinfo(curdir); | 476 | info = inoinfo(curdir); | |
477 | if (busy || (info->ino_state != DSTATE && info->ino_state != DFOUND)) { | 477 | if (busy || (info->ino_state != DSTATE && info->ino_state != DFOUND)) { | |
478 | (void)strlcpy(namebuf, "?", namebuflen); | 478 | (void)strlcpy(namebuf, "?", namebuflen); | |
479 | return; | 479 | return; | |
480 | } | 480 | } | |
481 | busy = 1; | 481 | busy = 1; | |
482 | memset(&idesc, 0, sizeof(struct inodesc)); | 482 | memset(&idesc, 0, sizeof(struct inodesc)); | |
483 | idesc.id_type = DATA; | 483 | idesc.id_type = DATA; | |
484 | idesc.id_fix = IGNORE; | 484 | idesc.id_fix = IGNORE; | |
485 | cp = &namebuf[MAXPATHLEN - 1]; | 485 | cp = &namebuf[MAXPATHLEN - 1]; | |
486 | *cp = '\0'; | 486 | *cp = '\0'; | |
487 | if (curdir != ino) { | 487 | if (curdir != ino) { | |
488 | idesc.id_parent = curdir; | 488 | idesc.id_parent = curdir; | |
489 | goto namelookup; | 489 | goto namelookup; | |
490 | } | 490 | } | |
491 | while (ino != UFS_ROOTINO) { | 491 | while (ino != UFS_ROOTINO) { | |
492 | idesc.id_number = ino; | 492 | idesc.id_number = ino; | |
493 | idesc.id_func = findino; | 493 | idesc.id_func = findino; | |
494 | idesc.id_name = ".."; | 494 | idesc.id_name = ".."; | |
495 | if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) | 495 | if ((ckinode(ginode(ino), &idesc) & FOUND) == 0) | |
496 | break; | 496 | break; | |
497 | namelookup: | 497 | namelookup: | |
498 | idesc.id_number = idesc.id_parent; | 498 | idesc.id_number = idesc.id_parent; | |
499 | idesc.id_parent = ino; | 499 | idesc.id_parent = ino; | |
500 | idesc.id_func = findname; | 500 | idesc.id_func = findname; | |
501 | idesc.id_name = namebuf; | 501 | idesc.id_name = namebuf; | |
502 | if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) | 502 | if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0) | |
503 | break; | 503 | break; | |
504 | len = strlen(namebuf); | 504 | len = strlen(namebuf); | |
505 | cp -= len; | 505 | cp -= len; | |
506 | memmove(cp, namebuf, (size_t)len); | 506 | memmove(cp, namebuf, (size_t)len); | |
507 | *--cp = '/'; | 507 | *--cp = '/'; | |
508 | if (cp < &namebuf[FFS_MAXNAMLEN]) | 508 | if (cp < &namebuf[FFS_MAXNAMLEN]) | |
509 | break; | 509 | break; | |
510 | ino = idesc.id_number; | 510 | ino = idesc.id_number; | |
511 | } | 511 | } | |
512 | busy = 0; | 512 | busy = 0; | |
513 | if (ino != UFS_ROOTINO) | 513 | if (ino != UFS_ROOTINO) | |
514 | *--cp = '?'; | 514 | *--cp = '?'; | |
515 | memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); | 515 | memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp)); | |
516 | } | 516 | } | |
517 | 517 | |||
518 | /* | 518 | /* | |
519 | * determine whether an inode should be fixed. | 519 | * determine whether an inode should be fixed. | |
520 | */ | 520 | */ | |
521 | int | 521 | int | |
522 | dofix(struct inodesc *idesc, const char *msg) | 522 | dofix(struct inodesc *idesc, const char *msg) | |
523 | { | 523 | { | |
524 | 524 | |||
525 | switch (idesc->id_fix) { | 525 | switch (idesc->id_fix) { | |
526 | 526 | |||
527 | case DONTKNOW: | 527 | case DONTKNOW: | |
528 | if (idesc->id_type == DATA) | 528 | if (idesc->id_type == DATA) | |
529 | direrror(idesc->id_number, msg); | 529 | direrror(idesc->id_number, msg); | |
530 | else | 530 | else | |
531 | pwarn("%s", msg); | 531 | pwarn("%s", msg); | |
532 | if (preen) { | 532 | if (preen) { | |
533 | printf(" (SALVAGED)\n"); | 533 | printf(" (SALVAGED)\n"); | |
534 | idesc->id_fix = FIX; | 534 | idesc->id_fix = FIX; | |
535 | return (ALTERED); | 535 | return (ALTERED); | |
536 | } | 536 | } | |
537 | if (reply("SALVAGE") == 0) { | 537 | if (reply("SALVAGE") == 0) { | |
538 | idesc->id_fix = NOFIX; | 538 | idesc->id_fix = NOFIX; | |
539 | return (0); | 539 | return (0); | |
540 | } | 540 | } | |
541 | idesc->id_fix = FIX; | 541 | idesc->id_fix = FIX; | |
542 | return (ALTERED); | 542 | return (ALTERED); | |
543 | 543 | |||
544 | case FIX: | 544 | case FIX: | |
545 | return (ALTERED); | 545 | return (ALTERED); | |
546 | 546 | |||
547 | case NOFIX: | 547 | case NOFIX: | |
548 | case IGNORE: | 548 | case IGNORE: | |
549 | return (0); | 549 | return (0); | |
550 | 550 | |||
551 | default: | 551 | default: | |
552 | errexit("UNKNOWN INODESC FIX MODE %d", idesc->id_fix); | 552 | errexit("UNKNOWN INODESC FIX MODE %d", idesc->id_fix); | |
553 | } | 553 | } | |
554 | /* NOTREACHED */ | 554 | /* NOTREACHED */ | |
555 | return (0); | 555 | return (0); | |
556 | } | 556 | } | |
557 | 557 | |||
558 | void | 558 | void | |
559 | copyback_cg(struct bufarea *blk) | 559 | copyback_cg(struct bufarea *blk) | |
560 | { | 560 | { | |
561 | 561 | |||
562 | memcpy(blk->b_un.b_cg, cgrp, sblock->fs_cgsize); | 562 | memcpy(blk->b_un.b_cg, cgrp, sblock->fs_cgsize); | |
563 | if (needswap) | 563 | if (needswap) | |
564 | ffs_cg_swap(cgrp, blk->b_un.b_cg, sblock); | 564 | ffs_cg_swap(cgrp, blk->b_un.b_cg, sblock); | |
565 | } | 565 | } | |
566 | 566 | |||
567 | void | 567 | void | |
568 | infohandler(int sig) | 568 | infohandler(int sig) | |
569 | { | 569 | { | |
570 | got_siginfo = 1; | 570 | got_siginfo = 1; | |
571 | } | 571 | } | |
572 | 572 | |||
573 | /* | 573 | /* | |
574 | * Look up state information for an inode. | 574 | * Look up state information for an inode. | |
575 | */ | 575 | */ | |
576 | struct inostat * | 576 | struct inostat * | |
577 | inoinfo(ino_t inum) | 577 | inoinfo(ino_t inum) | |
578 | { | 578 | { | |
579 | static struct inostat unallocated = { USTATE, 0, 0 }; | 579 | static struct inostat unallocated = { USTATE, 0, 0 }; | |
580 | struct inostatlist *ilp; | 580 | struct inostatlist *ilp; | |
581 | int iloff; | 581 | int iloff; | |
582 | 582 | |||
583 | if (inum > maxino) | 583 | if (inum > maxino) | |
584 | errexit("inoinfo: inumber %llu out of range", | 584 | errexit("inoinfo: inumber %llu out of range", | |
585 | (unsigned long long)inum); | 585 | (unsigned long long)inum); | |
586 | ilp = &inostathead[inum / sblock->fs_ipg]; | 586 | ilp = &inostathead[inum / sblock->fs_ipg]; | |
587 | iloff = inum % sblock->fs_ipg; | 587 | iloff = inum % sblock->fs_ipg; | |
588 | if (iloff >= ilp->il_numalloced) | 588 | if (iloff >= ilp->il_numalloced) | |
589 | return (&unallocated); | 589 | return (&unallocated); | |
590 | return (&ilp->il_stat[iloff]); | 590 | return (&ilp->il_stat[iloff]); | |
591 | } | 591 | } | |
592 | 592 | |||
593 | void | 593 | void | |
594 | sb_oldfscompat_read(struct fs *fs, struct fs **fssave) | 594 | sb_oldfscompat_read(struct fs *fs, struct fs **fssave) | |
595 | { | 595 | { | |
596 | if ((fs->fs_magic != FS_UFS1_MAGIC) || | 596 | if ((fs->fs_magic != FS_UFS1_MAGIC) || | |
597 | (fs->fs_old_flags & FS_FLAGS_UPDATED)) | 597 | (fs->fs_old_flags & FS_FLAGS_UPDATED)) | |
598 | return; | 598 | return; | |
599 | 599 | |||
600 | /* Save a copy of fields that may be modified for compatibility */ | 600 | /* Save a copy of fields that may be modified for compatibility */ | |
601 | if (fssave) { | 601 | if (fssave) { | |
602 | if (!*fssave) | 602 | if (!*fssave) | |
603 | *fssave = malloc(sizeof(struct fs)); | 603 | *fssave = malloc(sizeof(struct fs)); | |
604 | if (!*fssave) | 604 | if (!*fssave) | |
605 | errexit("cannot allocate space for compat store"); | 605 | errexit("cannot allocate space for compat store"); | |
606 | memmove(*fssave, fs, sizeof(struct fs)); | 606 | memmove(*fssave, fs, sizeof(struct fs)); | |
607 | 607 | |||
608 | if (debug) | 608 | if (debug) | |
609 | printf("detected ufs1 superblock not yet updated for ufs2 kernels\n"); | 609 | printf("detected ufs1 superblock not yet updated for ufs2 kernels\n"); | |
610 | 610 | |||
611 | if (doswap) { | 611 | if (doswap) { | |
612 | uint16_t postbl[256]; | 612 | uint16_t postbl[256]; | |
613 | int i, n; | 613 | int i, n; | |
614 | 614 | |||
615 | if (fs->fs_old_postblformat == FS_42POSTBLFMT) | 615 | if (fs->fs_old_postblformat == FS_42POSTBLFMT) | |
616 | n = 256; | 616 | n = 256; | |
617 | else | 617 | else | |
618 | n = 128; | 618 | n = 128; | |
619 | 619 | |||
620 | /* extract the postbl from the unswapped superblock */ | 620 | /* extract the postbl from the unswapped superblock */ | |
621 | if (!needswap) | 621 | if (!needswap) | |
622 | ffs_sb_swap(*fssave, *fssave); | 622 | ffs_sb_swap(*fssave, *fssave); | |
623 | memmove(postbl, (&(*fssave)->fs_old_postbl_start), | 623 | memmove(postbl, (&(*fssave)->fs_old_postbl_start), | |
624 | n * sizeof(postbl[0])); | 624 | n * sizeof(postbl[0])); | |
625 | if (!needswap) | 625 | if (!needswap) | |
626 | ffs_sb_swap(*fssave, *fssave); | 626 | ffs_sb_swap(*fssave, *fssave); | |
627 | 627 | |||
628 | /* Now swap it */ | 628 | /* Now swap it */ | |
629 | for (i=0; i < n; i++) | 629 | for (i=0; i < n; i++) | |
630 | postbl[i] = bswap16(postbl[i]); | 630 | postbl[i] = bswap16(postbl[i]); | |
631 | 631 | |||
632 | /* And put it back such that it will get correctly | 632 | /* And put it back such that it will get correctly | |
633 | * unscrambled if it is swapped again on the way out | 633 | * unscrambled if it is swapped again on the way out | |
634 | */ | 634 | */ | |
635 | if (needswap) | 635 | if (needswap) | |
636 | ffs_sb_swap(*fssave, *fssave); | 636 | ffs_sb_swap(*fssave, *fssave); | |
637 | memmove((&(*fssave)->fs_old_postbl_start), postbl, | 637 | memmove((&(*fssave)->fs_old_postbl_start), postbl, | |
638 | n * sizeof(postbl[0])); | 638 | n * sizeof(postbl[0])); | |
639 | if (needswap) | 639 | if (needswap) | |
640 | ffs_sb_swap(*fssave, *fssave); | 640 | ffs_sb_swap(*fssave, *fssave); | |
641 | } | 641 | } | |
642 | 642 | |||
643 | } | 643 | } | |
644 | 644 | |||
645 | /* These fields will be overwritten by their | 645 | /* These fields will be overwritten by their | |
646 | * original values in fs_oldfscompat_write, so it is harmless | 646 | * original values in fs_oldfscompat_write, so it is harmless | |
647 | * to modify them here. | 647 | * to modify them here. | |
648 | */ | 648 | */ | |
649 | fs->fs_cstotal.cs_ndir = | 649 | fs->fs_cstotal.cs_ndir = | |
650 | fs->fs_old_cstotal.cs_ndir; | 650 | fs->fs_old_cstotal.cs_ndir; | |
651 | fs->fs_cstotal.cs_nbfree = | 651 | fs->fs_cstotal.cs_nbfree = | |
652 | fs->fs_old_cstotal.cs_nbfree; | 652 | fs->fs_old_cstotal.cs_nbfree; | |
653 | fs->fs_cstotal.cs_nifree = | 653 | fs->fs_cstotal.cs_nifree = | |
654 | fs->fs_old_cstotal.cs_nifree; | 654 | fs->fs_old_cstotal.cs_nifree; | |
655 | fs->fs_cstotal.cs_nffree = | 655 | fs->fs_cstotal.cs_nffree = | |
656 | fs->fs_old_cstotal.cs_nffree; | 656 | fs->fs_old_cstotal.cs_nffree; | |
657 | 657 | |||
658 | fs->fs_maxbsize = fs->fs_bsize; | 658 | fs->fs_maxbsize = fs->fs_bsize; | |
659 | fs->fs_time = fs->fs_old_time; | 659 | fs->fs_time = fs->fs_old_time; | |
660 | fs->fs_size = fs->fs_old_size; | 660 | fs->fs_size = fs->fs_old_size; | |
661 | fs->fs_dsize = fs->fs_old_dsize; | 661 | fs->fs_dsize = fs->fs_old_dsize; | |
662 | fs->fs_csaddr = fs->fs_old_csaddr; | 662 | fs->fs_csaddr = fs->fs_old_csaddr; | |
663 | fs->fs_sblockloc = SBLOCK_UFS1; | 663 | fs->fs_sblockloc = SBLOCK_UFS1; | |
664 | 664 | |||
665 | fs->fs_flags = fs->fs_old_flags; | 665 | fs->fs_flags = fs->fs_old_flags; | |
666 | 666 | |||
667 | if (fs->fs_old_postblformat == FS_42POSTBLFMT) { | 667 | if (fs->fs_old_postblformat == FS_42POSTBLFMT) { | |
668 | fs->fs_old_nrpos = 8; | 668 | fs->fs_old_nrpos = 8; | |
669 | fs->fs_old_npsect = fs->fs_old_nsect; | 669 | fs->fs_old_npsect = fs->fs_old_nsect; | |
670 | fs->fs_old_interleave = 1; | 670 | fs->fs_old_interleave = 1; | |
671 | fs->fs_old_trackskew = 0; | 671 | fs->fs_old_trackskew = 0; | |
672 | } | 672 | } | |
673 | } | 673 | } | |
674 | 674 | |||
675 | void | 675 | void | |
676 | sb_oldfscompat_write(struct fs *fs, struct fs *fssave) | 676 | sb_oldfscompat_write(struct fs *fs, struct fs *fssave) | |
677 | { | 677 | { | |
678 | if ((fs->fs_magic != FS_UFS1_MAGIC) || | 678 | if ((fs->fs_magic != FS_UFS1_MAGIC) || | |
679 | (fs->fs_old_flags & FS_FLAGS_UPDATED)) | 679 | (fs->fs_old_flags & FS_FLAGS_UPDATED)) | |
680 | return; | 680 | return; | |
681 | 681 | |||
682 | fs->fs_old_flags = fs->fs_flags; | 682 | fs->fs_old_flags = fs->fs_flags; | |
683 | fs->fs_old_time = fs->fs_time; | 683 | fs->fs_old_time = fs->fs_time; | |
684 | fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir; | 684 | fs->fs_old_cstotal.cs_ndir = fs->fs_cstotal.cs_ndir; | |
685 | fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree; | 685 | fs->fs_old_cstotal.cs_nbfree = fs->fs_cstotal.cs_nbfree; | |
686 | fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree; | 686 | fs->fs_old_cstotal.cs_nifree = fs->fs_cstotal.cs_nifree; | |
687 | fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree; | 687 | fs->fs_old_cstotal.cs_nffree = fs->fs_cstotal.cs_nffree; | |
688 | 688 | |||
689 | fs->fs_flags = fssave->fs_flags; | 689 | fs->fs_flags = fssave->fs_flags; | |
690 | 690 | |||
691 | if (fs->fs_old_postblformat == FS_42POSTBLFMT) { | 691 | if (fs->fs_old_postblformat == FS_42POSTBLFMT) { | |
692 | fs->fs_old_nrpos = fssave->fs_old_nrpos; | 692 | fs->fs_old_nrpos = fssave->fs_old_nrpos; | |
693 | fs->fs_old_npsect = fssave->fs_old_npsect; | 693 | fs->fs_old_npsect = fssave->fs_old_npsect; | |
694 | fs->fs_old_interleave = fssave->fs_old_interleave; | 694 | fs->fs_old_interleave = fssave->fs_old_interleave; | |
695 | fs->fs_old_trackskew = fssave->fs_old_trackskew; | 695 | fs->fs_old_trackskew = fssave->fs_old_trackskew; | |
696 | } | 696 | } | |
697 | 697 | |||
698 | memmove(&fs->fs_old_postbl_start, &fssave->fs_old_postbl_start, | 698 | memmove(&fs->fs_old_postbl_start, &fssave->fs_old_postbl_start, | |
699 | ((fs->fs_old_postblformat == FS_42POSTBLFMT) ? | 699 | ((fs->fs_old_postblformat == FS_42POSTBLFMT) ? | |
700 | 512 : 256)); | 700 | 512 : 256)); | |
701 | } | 701 | } | |
702 | 702 | |||
703 | struct uquot * | 703 | struct uquot * | |
704 | find_uquot(struct uquot_hash *uq_hash, uint32_t uid, int alloc) | 704 | find_uquot(struct uquot_hash *uq_hash, uint32_t uid, int alloc) | |
705 | { | 705 | { | |
706 | struct uquot *uq; | 706 | struct uquot *uq; | |
707 | SLIST_FOREACH(uq, &uq_hash[uid & q2h_hash_mask], uq_entries) { | 707 | SLIST_FOREACH(uq, &uq_hash[uid & q2h_hash_mask], uq_entries) { | |
708 | if (uq->uq_uid == uid) | 708 | if (uq->uq_uid == uid) | |
709 | return uq; | 709 | return uq; | |
710 | } | 710 | } | |
711 | if (!alloc) | 711 | if (!alloc) | |
712 | return NULL; | 712 | return NULL; | |
713 | uq = malloc(sizeof(struct uquot)); | 713 | uq = malloc(sizeof(struct uquot)); | |
714 | if (uq == NULL) | 714 | if (uq == NULL) | |
715 | errexit("cannot allocate quota entry"); | 715 | errexit("cannot allocate quota entry"); | |
716 | memset(uq, 0, sizeof(struct uquot)); | 716 | memset(uq, 0, sizeof(struct uquot)); | |
717 | uq->uq_uid = uid; | 717 | uq->uq_uid = uid; | |
718 | SLIST_INSERT_HEAD(&uq_hash[uid & q2h_hash_mask], uq, uq_entries); | 718 | SLIST_INSERT_HEAD(&uq_hash[uid & q2h_hash_mask], uq, uq_entries); | |
719 | return uq; | 719 | return uq; | |
720 | } | 720 | } | |
721 | 721 | |||
722 | void | 722 | void | |
723 | remove_uquot(struct uquot_hash *uq_hash, struct uquot *uq) | 723 | remove_uquot(struct uquot_hash *uq_hash, struct uquot *uq) | |
724 | { | 724 | { | |
725 | SLIST_REMOVE(&uq_hash[uq->uq_uid & q2h_hash_mask], | 725 | SLIST_REMOVE(&uq_hash[uq->uq_uid & q2h_hash_mask], | |
726 | uq, uquot, uq_entries); | 726 | uq, uquot, uq_entries); | |
727 | } | 727 | } | |
728 | 728 | |||
729 | void | 729 | void | |
730 | update_uquot(ino_t inum, uid_t uid, gid_t gid, int64_t bchange, int64_t ichange) | 730 | update_uquot(ino_t inum, uid_t uid, gid_t gid, int64_t bchange, int64_t ichange) | |
731 | { | 731 | { | |
732 | /* simple uquot cache: remember the last used */ | 732 | /* simple uquot cache: remember the last used */ | |
733 | static struct uquot *uq_u = NULL; | 733 | static struct uquot *uq_u = NULL; | |
734 | static struct uquot *uq_g = NULL; | 734 | static struct uquot *uq_g = NULL; | |
735 | 735 | |||
736 | if (inum < UFS_ROOTINO) | 736 | if (inum < UFS_ROOTINO) | |
737 | return; | 737 | return; | |
738 | if (is_journal_inode(inum)) | 738 | if (is_journal_inode(inum)) | |
739 | return; | 739 | return; | |
740 | if (is_quota_inode(inum)) | 740 | if (is_quota_inode(inum)) | |
741 | return; | 741 | return; | |
742 | 742 | |||
743 | if (uquot_user_hash == NULL) | 743 | if (uquot_user_hash == NULL) | |
744 | return; | 744 | return; | |
745 | 745 | |||
746 | if (uq_u == NULL || uq_u->uq_uid != uid) | 746 | if (uq_u == NULL || uq_u->uq_uid != uid) | |
747 | uq_u = find_uquot(uquot_user_hash, uid, 1); | 747 | uq_u = find_uquot(uquot_user_hash, uid, 1); | |
748 | uq_u->uq_b += bchange; | 748 | uq_u->uq_b += bchange; | |
749 | uq_u->uq_i += ichange; | 749 | uq_u->uq_i += ichange; | |
750 | if (uq_g == NULL || uq_g->uq_uid != gid) | 750 | if (uq_g == NULL || uq_g->uq_uid != gid) | |
751 | uq_g = find_uquot(uquot_group_hash, gid, 1); | 751 | uq_g = find_uquot(uquot_group_hash, gid, 1); | |
752 | uq_g->uq_b += bchange; | 752 | uq_g->uq_b += bchange; | |
753 | uq_g->uq_i += ichange; | 753 | uq_g->uq_i += ichange; | |
754 | } | 754 | } | |
755 | 755 | |||
756 | int | 756 | int | |
757 | is_quota_inode(ino_t inum) | 757 | is_quota_inode(ino_t inum) | |
758 | { | 758 | { | |
759 | 759 | |||
760 | if ((sblock->fs_flags & FS_DOQUOTA2) == 0) | 760 | if ((sblock->fs_flags & FS_DOQUOTA2) == 0) | |
761 | return 0; | 761 | return 0; | |
762 | 762 | |||
763 | if (sblock->fs_quota_magic != Q2_HEAD_MAGIC) | 763 | if (sblock->fs_quota_magic != Q2_HEAD_MAGIC) | |
764 | return 0; | 764 | return 0; | |
765 | 765 | |||
766 | if (sblock->fs_quotafile[USRQUOTA] == inum) | 766 | if (sblock->fs_quotafile[USRQUOTA] == inum) | |
767 | return 1; | 767 | return 1; | |
768 | 768 | |||
769 | if (sblock->fs_quotafile[GRPQUOTA] == inum) | 769 | if (sblock->fs_quotafile[GRPQUOTA] == inum) | |
770 | return 1; | 770 | return 1; | |
771 | 771 | |||
772 | return 0; | 772 | return 0; | |
773 | } | 773 | } |