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 |
76797561 DF |
8 | static char sccsid[] = "@(#)pass2.c 5.1 (Berkeley) %G%"; |
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(""); | |
36 | if (allocdir(ROOTINO, ROOTINO) != ROOTINO) | |
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); | |
45 | if (allocdir(ROOTINO, ROOTINO) != ROOTINO) | |
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); | |
61 | if (allocdir(ROOTINO, ROOTINO) != ROOTINO) | |
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; |
ba8f3d8f KM |
224 | goto again; |
225 | ||
993a756c | 226 | case DFOUND: |
3ad2f081 KM |
227 | if (idesc->id_entryno > 2) { |
228 | getpathname(namebuf, dirp->d_ino, dirp->d_ino); | |
229 | pwarn("%s %s %s\n", pathname, | |
230 | "IS AN EXTRANEOUS HARD LINK TO DIRECTORY", | |
231 | namebuf); | |
232 | if (preen) | |
233 | printf(" (IGNORED)\n"); | |
234 | else if ((n = reply("REMOVE")) == 1) | |
235 | break; | |
236 | } | |
993a756c KM |
237 | /* fall through */ |
238 | ||
ba8f3d8f KM |
239 | case FSTATE: |
240 | lncntp[dirp->d_ino]--; | |
241 | break; | |
242 | ||
243 | case DSTATE: | |
244 | descend(idesc, dirp->d_ino); | |
993a756c | 245 | if (statemap[dirp->d_ino] == DFOUND) { |
ba8f3d8f | 246 | lncntp[dirp->d_ino]--; |
993a756c | 247 | } else if (statemap[dirp->d_ino] == DCLEAR) { |
ba8f3d8f KM |
248 | dirp->d_ino = 0; |
249 | ret |= ALTERED; | |
993a756c KM |
250 | } else |
251 | errexit("BAD RETURN STATE %d FROM DESCEND", | |
252 | statemap[dirp->d_ino]); | |
ba8f3d8f KM |
253 | break; |
254 | } | |
255 | } | |
256 | pathp = curpathloc; | |
257 | *pathp = '\0'; | |
258 | if (n == 0) | |
259 | return (ret|KEEPON); | |
260 | dirp->d_ino = 0; | |
261 | return (ret|KEEPON|ALTERED); | |
262 | } |