Commit | Line | Data |
---|---|---|
76797561 DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | */ | |
6 | ||
ba8f3d8f | 7 | #ifndef lint |
c689da7b | 8 | static char sccsid[] = "@(#)pass2.c 5.4 (Berkeley) %G%"; |
76797561 | 9 | #endif not lint |
ba8f3d8f KM |
10 | |
11 | #include <sys/param.h> | |
12 | #include <sys/inode.h> | |
13 | #include <sys/fs.h> | |
14 | #include <sys/dir.h> | |
15 | #include <strings.h> | |
16 | #include "fsck.h" | |
17 | ||
18 | int pass2check(); | |
19 | ||
20 | pass2() | |
21 | { | |
22 | register DINODE *dp; | |
23 | struct inodesc rootdesc; | |
24 | ||
25 | bzero((char *)&rootdesc, sizeof(struct inodesc)); | |
26 | rootdesc.id_type = ADDR; | |
27 | rootdesc.id_func = pass2check; | |
28 | rootdesc.id_number = ROOTINO; | |
29 | pathp = pathname; | |
30 | switch (statemap[ROOTINO]) { | |
31 | ||
32 | case USTATE: | |
7e1e49f2 KM |
33 | pfatal("ROOT INODE UNALLOCATED"); |
34 | if (reply("ALLOCATE") == 0) | |
35 | errexit(""); | |
c689da7b | 36 | if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) |
7e1e49f2 KM |
37 | errexit("CANNOT ALLOCATE ROOT INODE\n"); |
38 | descend(&rootdesc, ROOTINO); | |
39 | break; | |
40 | ||
41 | case DCLEAR: | |
42 | pfatal("DUPS/BAD IN ROOT INODE"); | |
43 | if (reply("REALLOCATE")) { | |
44 | freeino(ROOTINO); | |
c689da7b | 45 | if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) |
7e1e49f2 KM |
46 | errexit("CANNOT ALLOCATE ROOT INODE\n"); |
47 | descend(&rootdesc, ROOTINO); | |
48 | break; | |
49 | } | |
50 | if (reply("CONTINUE") == 0) | |
51 | errexit(""); | |
52 | statemap[ROOTINO] = DSTATE; | |
53 | descend(&rootdesc, ROOTINO); | |
54 | break; | |
ba8f3d8f KM |
55 | |
56 | case FSTATE: | |
993a756c | 57 | case FCLEAR: |
ba8f3d8f | 58 | pfatal("ROOT INODE NOT DIRECTORY"); |
7e1e49f2 KM |
59 | if (reply("REALLOCATE")) { |
60 | freeino(ROOTINO); | |
c689da7b | 61 | if (allocdir(ROOTINO, ROOTINO, 0755) != ROOTINO) |
7e1e49f2 KM |
62 | errexit("CANNOT ALLOCATE ROOT INODE\n"); |
63 | descend(&rootdesc, ROOTINO); | |
64 | break; | |
65 | } | |
39c18287 | 66 | if (reply("FIX") == 0) |
ba8f3d8f | 67 | errexit(""); |
39c18287 | 68 | dp = ginode(ROOTINO); |
ba8f3d8f KM |
69 | dp->di_mode &= ~IFMT; |
70 | dp->di_mode |= IFDIR; | |
71 | inodirty(); | |
ba8f3d8f KM |
72 | statemap[ROOTINO] = DSTATE; |
73 | /* fall into ... */ | |
74 | ||
75 | case DSTATE: | |
76 | descend(&rootdesc, ROOTINO); | |
77 | break; | |
78 | ||
993a756c KM |
79 | default: |
80 | errexit("BAD STATE %d FOR ROOT INODE", statemap[ROOTINO]); | |
ba8f3d8f KM |
81 | } |
82 | } | |
83 | ||
84 | pass2check(idesc) | |
85 | struct inodesc *idesc; | |
86 | { | |
87 | register DIRECT *dirp = idesc->id_dirp; | |
88 | char *curpathloc; | |
89 | int n, entrysize, ret = 0; | |
90 | DINODE *dp; | |
91 | DIRECT proto; | |
3ad2f081 | 92 | char namebuf[BUFSIZ]; |
ba8f3d8f KM |
93 | |
94 | /* | |
95 | * check for "." | |
96 | */ | |
97 | if (idesc->id_entryno != 0) | |
98 | goto chk1; | |
99 | if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") == 0) { | |
100 | if (dirp->d_ino != idesc->id_number) { | |
101 | direrr(idesc->id_number, "BAD INODE NUMBER FOR '.'"); | |
102 | dirp->d_ino = idesc->id_number; | |
103 | if (reply("FIX") == 1) | |
104 | ret |= ALTERED; | |
105 | } | |
106 | goto chk1; | |
107 | } | |
108 | direrr(idesc->id_number, "MISSING '.'"); | |
109 | proto.d_ino = idesc->id_number; | |
110 | proto.d_namlen = 1; | |
111 | (void)strcpy(proto.d_name, "."); | |
112 | entrysize = DIRSIZ(&proto); | |
113 | if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") != 0) { | |
114 | pfatal("CANNOT FIX, FIRST ENTRY IN DIRECTORY CONTAINS %s\n", | |
115 | dirp->d_name); | |
116 | } else if (dirp->d_reclen < entrysize) { | |
117 | pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '.'\n"); | |
118 | } else if (dirp->d_reclen < 2 * entrysize) { | |
119 | proto.d_reclen = dirp->d_reclen; | |
120 | bcopy((char *)&proto, (char *)dirp, entrysize); | |
121 | if (reply("FIX") == 1) | |
122 | ret |= ALTERED; | |
123 | } else { | |
124 | n = dirp->d_reclen - entrysize; | |
125 | proto.d_reclen = entrysize; | |
126 | bcopy((char *)&proto, (char *)dirp, entrysize); | |
127 | idesc->id_entryno++; | |
128 | lncntp[dirp->d_ino]--; | |
129 | dirp = (DIRECT *)((char *)(dirp) + entrysize); | |
130 | bzero((char *)dirp, n); | |
131 | dirp->d_reclen = n; | |
132 | if (reply("FIX") == 1) | |
133 | ret |= ALTERED; | |
134 | } | |
135 | chk1: | |
136 | if (idesc->id_entryno > 1) | |
137 | goto chk2; | |
138 | proto.d_ino = idesc->id_parent; | |
139 | proto.d_namlen = 2; | |
140 | (void)strcpy(proto.d_name, ".."); | |
141 | entrysize = DIRSIZ(&proto); | |
142 | if (idesc->id_entryno == 0) { | |
143 | n = DIRSIZ(dirp); | |
144 | if (dirp->d_reclen < n + entrysize) | |
145 | goto chk2; | |
146 | proto.d_reclen = dirp->d_reclen - n; | |
147 | dirp->d_reclen = n; | |
148 | idesc->id_entryno++; | |
149 | lncntp[dirp->d_ino]--; | |
150 | dirp = (DIRECT *)((char *)(dirp) + n); | |
151 | bzero((char *)dirp, n); | |
152 | dirp->d_reclen = n; | |
153 | } | |
154 | if (dirp->d_ino != 0 && strcmp(dirp->d_name, "..") == 0) { | |
155 | if (dirp->d_ino != idesc->id_parent) { | |
156 | direrr(idesc->id_number, "BAD INODE NUMBER FOR '..'"); | |
157 | dirp->d_ino = idesc->id_parent; | |
158 | if (reply("FIX") == 1) | |
159 | ret |= ALTERED; | |
160 | } | |
161 | goto chk2; | |
162 | } | |
163 | direrr(idesc->id_number, "MISSING '..'"); | |
164 | if (dirp->d_ino != 0 && strcmp(dirp->d_name, ".") != 0) { | |
165 | pfatal("CANNOT FIX, SECOND ENTRY IN DIRECTORY CONTAINS %s\n", | |
166 | dirp->d_name); | |
167 | } else if (dirp->d_reclen < entrysize) { | |
168 | pfatal("CANNOT FIX, INSUFFICIENT SPACE TO ADD '..'\n"); | |
169 | } else { | |
170 | proto.d_reclen = dirp->d_reclen; | |
171 | bcopy((char *)&proto, (char *)dirp, entrysize); | |
172 | if (reply("FIX") == 1) | |
173 | ret |= ALTERED; | |
174 | } | |
175 | chk2: | |
176 | if (dirp->d_ino == 0) | |
177 | return (ret|KEEPON); | |
178 | if (dirp->d_namlen <= 2 && | |
179 | dirp->d_name[0] == '.' && | |
180 | idesc->id_entryno >= 2) { | |
181 | if (dirp->d_namlen == 1) { | |
182 | direrr(idesc->id_number, "EXTRA '.' ENTRY"); | |
183 | dirp->d_ino = 0; | |
184 | if (reply("FIX") == 1) | |
185 | ret |= ALTERED; | |
186 | return (KEEPON | ret); | |
187 | } | |
188 | if (dirp->d_name[1] == '.') { | |
189 | direrr(idesc->id_number, "EXTRA '..' ENTRY"); | |
190 | dirp->d_ino = 0; | |
191 | if (reply("FIX") == 1) | |
192 | ret |= ALTERED; | |
193 | return (KEEPON | ret); | |
194 | } | |
195 | } | |
196 | curpathloc = pathp; | |
197 | *pathp++ = '/'; | |
198 | if (pathp + dirp->d_namlen >= endpathname) { | |
199 | *pathp = '\0'; | |
200 | errexit("NAME TOO LONG %s%s\n", pathname, dirp->d_name); | |
201 | } | |
202 | bcopy(dirp->d_name, pathp, dirp->d_namlen + 1); | |
203 | pathp += dirp->d_namlen; | |
204 | idesc->id_entryno++; | |
205 | n = 0; | |
206 | if (dirp->d_ino > imax || dirp->d_ino <= 0) { | |
207 | direrr(dirp->d_ino, "I OUT OF RANGE"); | |
208 | n = reply("REMOVE"); | |
209 | } else { | |
210 | again: | |
211 | switch (statemap[dirp->d_ino]) { | |
212 | case USTATE: | |
213 | direrr(dirp->d_ino, "UNALLOCATED"); | |
214 | n = reply("REMOVE"); | |
215 | break; | |
216 | ||
993a756c KM |
217 | case DCLEAR: |
218 | case FCLEAR: | |
ba8f3d8f KM |
219 | direrr(dirp->d_ino, "DUP/BAD"); |
220 | if ((n = reply("REMOVE")) == 1) | |
221 | break; | |
39c18287 | 222 | dp = ginode(dirp->d_ino); |
7718c0e6 | 223 | statemap[dirp->d_ino] = DIRCT(dp) ? DSTATE : FSTATE; |
77d16a71 | 224 | lncntp[dirp->d_ino] = dp->di_nlink; |
ba8f3d8f KM |
225 | goto again; |
226 | ||
993a756c | 227 | case DFOUND: |
3ad2f081 KM |
228 | if (idesc->id_entryno > 2) { |
229 | getpathname(namebuf, dirp->d_ino, dirp->d_ino); | |
230 | pwarn("%s %s %s\n", pathname, | |
231 | "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", | |
232 | namebuf); | |
233 | if (preen) | |
234 | printf(" (IGNORED)\n"); | |
235 | else if ((n = reply("REMOVE")) == 1) | |
236 | break; | |
237 | } | |
993a756c KM |
238 | /* fall through */ |
239 | ||
ba8f3d8f KM |
240 | case FSTATE: |
241 | lncntp[dirp->d_ino]--; | |
242 | break; | |
243 | ||
244 | case DSTATE: | |
245 | descend(idesc, dirp->d_ino); | |
993a756c | 246 | if (statemap[dirp->d_ino] == DFOUND) { |
ba8f3d8f | 247 | lncntp[dirp->d_ino]--; |
993a756c | 248 | } else if (statemap[dirp->d_ino] == DCLEAR) { |
ba8f3d8f KM |
249 | dirp->d_ino = 0; |
250 | ret |= ALTERED; | |
993a756c KM |
251 | } else |
252 | errexit("BAD RETURN STATE %d FROM DESCEND", | |
253 | statemap[dirp->d_ino]); | |
ba8f3d8f | 254 | break; |
ea4448dc KM |
255 | |
256 | default: | |
257 | errexit("BAD STATE %d FOR INODE I=%d", | |
258 | statemap[dirp->d_ino], dirp->d_ino); | |
ba8f3d8f KM |
259 | } |
260 | } | |
261 | pathp = curpathloc; | |
262 | *pathp = '\0'; | |
263 | if (n == 0) | |
264 | return (ret|KEEPON); | |
265 | dirp->d_ino = 0; | |
266 | return (ret|KEEPON|ALTERED); | |
267 | } |