diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/hpfs |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/hpfs')
-rw-r--r-- | fs/hpfs/Makefile | 8 | ||||
-rw-r--r-- | fs/hpfs/alloc.c | 456 | ||||
-rw-r--r-- | fs/hpfs/anode.c | 491 | ||||
-rw-r--r-- | fs/hpfs/buffer.c | 175 | ||||
-rw-r--r-- | fs/hpfs/dentry.c | 60 | ||||
-rw-r--r-- | fs/hpfs/dir.c | 320 | ||||
-rw-r--r-- | fs/hpfs/dnode.c | 1080 | ||||
-rw-r--r-- | fs/hpfs/ea.c | 363 | ||||
-rw-r--r-- | fs/hpfs/file.c | 140 | ||||
-rw-r--r-- | fs/hpfs/hpfs.h | 493 | ||||
-rw-r--r-- | fs/hpfs/hpfs_fn.h | 338 | ||||
-rw-r--r-- | fs/hpfs/inode.c | 291 | ||||
-rw-r--r-- | fs/hpfs/map.c | 275 | ||||
-rw-r--r-- | fs/hpfs/name.c | 144 | ||||
-rw-r--r-- | fs/hpfs/namei.c | 673 | ||||
-rw-r--r-- | fs/hpfs/super.c | 701 |
16 files changed, 6008 insertions, 0 deletions
diff --git a/fs/hpfs/Makefile b/fs/hpfs/Makefile new file mode 100644 index 000000000000..57b786fb9827 --- /dev/null +++ b/fs/hpfs/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | # | ||
2 | # Makefile for the Linux hpfs filesystem routines. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_HPFS_FS) += hpfs.o | ||
6 | |||
7 | hpfs-objs := alloc.o anode.o buffer.o dentry.o dir.o dnode.o ea.o file.o \ | ||
8 | inode.o map.o name.o namei.o super.o | ||
diff --git a/fs/hpfs/alloc.c b/fs/hpfs/alloc.c new file mode 100644 index 000000000000..5503e2c28910 --- /dev/null +++ b/fs/hpfs/alloc.c | |||
@@ -0,0 +1,456 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/alloc.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * HPFS bitmap operations | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec); | ||
12 | |||
13 | /* | ||
14 | * Check if a sector is allocated in bitmap | ||
15 | * This is really slow. Turned on only if chk==2 | ||
16 | */ | ||
17 | |||
18 | static int chk_if_allocated(struct super_block *s, secno sec, char *msg) | ||
19 | { | ||
20 | struct quad_buffer_head qbh; | ||
21 | unsigned *bmp; | ||
22 | if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "chk"))) goto fail; | ||
23 | if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f)) & 1) { | ||
24 | hpfs_error(s, "sector '%s' - %08x not allocated in bitmap", msg, sec); | ||
25 | goto fail1; | ||
26 | } | ||
27 | hpfs_brelse4(&qbh); | ||
28 | if (sec >= hpfs_sb(s)->sb_dirband_start && sec < hpfs_sb(s)->sb_dirband_start + hpfs_sb(s)->sb_dirband_size) { | ||
29 | unsigned ssec = (sec - hpfs_sb(s)->sb_dirband_start) / 4; | ||
30 | if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto fail; | ||
31 | if ((bmp[ssec >> 5] >> (ssec & 0x1f)) & 1) { | ||
32 | hpfs_error(s, "sector '%s' - %08x not allocated in directory bitmap", msg, sec); | ||
33 | goto fail1; | ||
34 | } | ||
35 | hpfs_brelse4(&qbh); | ||
36 | } | ||
37 | return 0; | ||
38 | fail1: | ||
39 | hpfs_brelse4(&qbh); | ||
40 | fail: | ||
41 | return 1; | ||
42 | } | ||
43 | |||
44 | /* | ||
45 | * Check if sector(s) have proper number and additionally check if they're | ||
46 | * allocated in bitmap. | ||
47 | */ | ||
48 | |||
49 | int hpfs_chk_sectors(struct super_block *s, secno start, int len, char *msg) | ||
50 | { | ||
51 | if (start + len < start || start < 0x12 || | ||
52 | start + len > hpfs_sb(s)->sb_fs_size) { | ||
53 | hpfs_error(s, "sector(s) '%s' badly placed at %08x", msg, start); | ||
54 | return 1; | ||
55 | } | ||
56 | if (hpfs_sb(s)->sb_chk>=2) { | ||
57 | int i; | ||
58 | for (i = 0; i < len; i++) | ||
59 | if (chk_if_allocated(s, start + i, msg)) return 1; | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | static secno alloc_in_bmp(struct super_block *s, secno near, unsigned n, unsigned forward) | ||
65 | { | ||
66 | struct quad_buffer_head qbh; | ||
67 | unsigned *bmp; | ||
68 | unsigned bs = near & ~0x3fff; | ||
69 | unsigned nr = (near & 0x3fff) & ~(n - 1); | ||
70 | /*unsigned mnr;*/ | ||
71 | unsigned i, q; | ||
72 | int a, b; | ||
73 | secno ret = 0; | ||
74 | if (n != 1 && n != 4) { | ||
75 | hpfs_error(s, "Bad allocation size: %d", n); | ||
76 | return 0; | ||
77 | } | ||
78 | lock_super(s); | ||
79 | if (bs != ~0x3fff) { | ||
80 | if (!(bmp = hpfs_map_bitmap(s, near >> 14, &qbh, "aib"))) goto uls; | ||
81 | } else { | ||
82 | if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) goto uls; | ||
83 | } | ||
84 | if (!tstbits(bmp, nr, n + forward)) { | ||
85 | ret = bs + nr; | ||
86 | goto rt; | ||
87 | } | ||
88 | /*if (!tstbits(bmp, nr + n, n + forward)) { | ||
89 | ret = bs + nr + n; | ||
90 | goto rt; | ||
91 | }*/ | ||
92 | q = nr + n; b = 0; | ||
93 | while ((a = tstbits(bmp, q, n + forward)) != 0) { | ||
94 | q += a; | ||
95 | if (n != 1) q = ((q-1)&~(n-1))+n; | ||
96 | if (!b) { | ||
97 | if (q>>5 != nr>>5) { | ||
98 | b = 1; | ||
99 | q = nr & 0x1f; | ||
100 | } | ||
101 | } else if (q > nr) break; | ||
102 | } | ||
103 | if (!a) { | ||
104 | ret = bs + q; | ||
105 | goto rt; | ||
106 | } | ||
107 | nr >>= 5; | ||
108 | /*for (i = nr + 1; i != nr; i++, i &= 0x1ff) {*/ | ||
109 | i = nr; | ||
110 | do { | ||
111 | if (!bmp[i]) goto cont; | ||
112 | if (n + forward >= 0x3f && bmp[i] != -1) goto cont; | ||
113 | q = i<<5; | ||
114 | if (i > 0) { | ||
115 | unsigned k = bmp[i-1]; | ||
116 | while (k & 0x80000000) { | ||
117 | q--; k <<= 1; | ||
118 | } | ||
119 | } | ||
120 | if (n != 1) q = ((q-1)&~(n-1))+n; | ||
121 | while ((a = tstbits(bmp, q, n + forward)) != 0) { | ||
122 | q += a; | ||
123 | if (n != 1) q = ((q-1)&~(n-1))+n; | ||
124 | if (q>>5 > i) break; | ||
125 | } | ||
126 | if (!a) { | ||
127 | ret = bs + q; | ||
128 | goto rt; | ||
129 | } | ||
130 | cont: | ||
131 | i++, i &= 0x1ff; | ||
132 | } while (i != nr); | ||
133 | rt: | ||
134 | if (ret) { | ||
135 | if (hpfs_sb(s)->sb_chk && ((ret >> 14) != (bs >> 14) || (bmp[(ret & 0x3fff) >> 5] | ~(((1 << n) - 1) << (ret & 0x1f))) != 0xffffffff)) { | ||
136 | hpfs_error(s, "Allocation doesn't work! Wanted %d, allocated at %08x", n, ret); | ||
137 | ret = 0; | ||
138 | goto b; | ||
139 | } | ||
140 | bmp[(ret & 0x3fff) >> 5] &= ~(((1 << n) - 1) << (ret & 0x1f)); | ||
141 | hpfs_mark_4buffers_dirty(&qbh); | ||
142 | } | ||
143 | b: | ||
144 | hpfs_brelse4(&qbh); | ||
145 | uls: | ||
146 | unlock_super(s); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * Allocation strategy: 1) search place near the sector specified | ||
152 | * 2) search bitmap where free sectors last found | ||
153 | * 3) search all bitmaps | ||
154 | * 4) search all bitmaps ignoring number of pre-allocated | ||
155 | * sectors | ||
156 | */ | ||
157 | |||
158 | secno hpfs_alloc_sector(struct super_block *s, secno near, unsigned n, int forward, int lock) | ||
159 | { | ||
160 | secno sec; | ||
161 | int i; | ||
162 | unsigned n_bmps; | ||
163 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
164 | int f_p = 0; | ||
165 | int near_bmp; | ||
166 | if (forward < 0) { | ||
167 | forward = -forward; | ||
168 | f_p = 1; | ||
169 | } | ||
170 | if (lock) hpfs_lock_creation(s); | ||
171 | n_bmps = (sbi->sb_fs_size + 0x4000 - 1) >> 14; | ||
172 | if (near && near < sbi->sb_fs_size) { | ||
173 | if ((sec = alloc_in_bmp(s, near, n, f_p ? forward : forward/4))) goto ret; | ||
174 | near_bmp = near >> 14; | ||
175 | } else near_bmp = n_bmps / 2; | ||
176 | /* | ||
177 | if (b != -1) { | ||
178 | if ((sec = alloc_in_bmp(s, b<<14, n, f_p ? forward : forward/2))) { | ||
179 | b &= 0x0fffffff; | ||
180 | goto ret; | ||
181 | } | ||
182 | if (b > 0x10000000) if ((sec = alloc_in_bmp(s, (b&0xfffffff)<<14, n, f_p ? forward : 0))) goto ret; | ||
183 | */ | ||
184 | if (!f_p) if (forward > sbi->sb_max_fwd_alloc) forward = sbi->sb_max_fwd_alloc; | ||
185 | less_fwd: | ||
186 | for (i = 0; i < n_bmps; i++) { | ||
187 | if (near_bmp+i < n_bmps && ((sec = alloc_in_bmp(s, (near_bmp+i) << 14, n, forward)))) { | ||
188 | sbi->sb_c_bitmap = near_bmp+i; | ||
189 | goto ret; | ||
190 | } | ||
191 | if (!forward) { | ||
192 | if (near_bmp-i-1 >= 0 && ((sec = alloc_in_bmp(s, (near_bmp-i-1) << 14, n, forward)))) { | ||
193 | sbi->sb_c_bitmap = near_bmp-i-1; | ||
194 | goto ret; | ||
195 | } | ||
196 | } else { | ||
197 | if (near_bmp+i >= n_bmps && ((sec = alloc_in_bmp(s, (near_bmp+i-n_bmps) << 14, n, forward)))) { | ||
198 | sbi->sb_c_bitmap = near_bmp+i-n_bmps; | ||
199 | goto ret; | ||
200 | } | ||
201 | } | ||
202 | if (i == 1 && sbi->sb_c_bitmap != -1 && ((sec = alloc_in_bmp(s, (sbi->sb_c_bitmap) << 14, n, forward)))) { | ||
203 | goto ret; | ||
204 | } | ||
205 | } | ||
206 | if (!f_p) { | ||
207 | if (forward) { | ||
208 | sbi->sb_max_fwd_alloc = forward * 3 / 4; | ||
209 | forward /= 2; | ||
210 | goto less_fwd; | ||
211 | } | ||
212 | } | ||
213 | sec = 0; | ||
214 | ret: | ||
215 | if (sec && f_p) { | ||
216 | for (i = 0; i < forward; i++) { | ||
217 | if (!hpfs_alloc_if_possible_nolock(s, sec + i + 1)) { | ||
218 | hpfs_error(s, "Prealloc doesn't work! Wanted %d, allocated at %08x, can't allocate %d", forward, sec, i); | ||
219 | sec = 0; | ||
220 | break; | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | if (lock) hpfs_unlock_creation(s); | ||
225 | return sec; | ||
226 | } | ||
227 | |||
228 | static secno alloc_in_dirband(struct super_block *s, secno near, int lock) | ||
229 | { | ||
230 | unsigned nr = near; | ||
231 | secno sec; | ||
232 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
233 | if (nr < sbi->sb_dirband_start) | ||
234 | nr = sbi->sb_dirband_start; | ||
235 | if (nr >= sbi->sb_dirband_start + sbi->sb_dirband_size) | ||
236 | nr = sbi->sb_dirband_start + sbi->sb_dirband_size - 4; | ||
237 | nr -= sbi->sb_dirband_start; | ||
238 | nr >>= 2; | ||
239 | if (lock) hpfs_lock_creation(s); | ||
240 | sec = alloc_in_bmp(s, (~0x3fff) | nr, 1, 0); | ||
241 | if (lock) hpfs_unlock_creation(s); | ||
242 | if (!sec) return 0; | ||
243 | return ((sec & 0x3fff) << 2) + sbi->sb_dirband_start; | ||
244 | } | ||
245 | |||
246 | /* Alloc sector if it's free */ | ||
247 | |||
248 | static int hpfs_alloc_if_possible_nolock(struct super_block *s, secno sec) | ||
249 | { | ||
250 | struct quad_buffer_head qbh; | ||
251 | unsigned *bmp; | ||
252 | lock_super(s); | ||
253 | if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "aip"))) goto end; | ||
254 | if (bmp[(sec & 0x3fff) >> 5] & (1 << (sec & 0x1f))) { | ||
255 | bmp[(sec & 0x3fff) >> 5] &= ~(1 << (sec & 0x1f)); | ||
256 | hpfs_mark_4buffers_dirty(&qbh); | ||
257 | hpfs_brelse4(&qbh); | ||
258 | unlock_super(s); | ||
259 | return 1; | ||
260 | } | ||
261 | hpfs_brelse4(&qbh); | ||
262 | end: | ||
263 | unlock_super(s); | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | int hpfs_alloc_if_possible(struct super_block *s, secno sec) | ||
268 | { | ||
269 | int r; | ||
270 | hpfs_lock_creation(s); | ||
271 | r = hpfs_alloc_if_possible_nolock(s, sec); | ||
272 | hpfs_unlock_creation(s); | ||
273 | return r; | ||
274 | } | ||
275 | |||
276 | /* Free sectors in bitmaps */ | ||
277 | |||
278 | void hpfs_free_sectors(struct super_block *s, secno sec, unsigned n) | ||
279 | { | ||
280 | struct quad_buffer_head qbh; | ||
281 | unsigned *bmp; | ||
282 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
283 | /*printk("2 - ");*/ | ||
284 | if (!n) return; | ||
285 | if (sec < 0x12) { | ||
286 | hpfs_error(s, "Trying to free reserved sector %08x", sec); | ||
287 | return; | ||
288 | } | ||
289 | lock_super(s); | ||
290 | sbi->sb_max_fwd_alloc += n > 0xffff ? 0xffff : n; | ||
291 | if (sbi->sb_max_fwd_alloc > 0xffffff) sbi->sb_max_fwd_alloc = 0xffffff; | ||
292 | new_map: | ||
293 | if (!(bmp = hpfs_map_bitmap(s, sec >> 14, &qbh, "free"))) { | ||
294 | unlock_super(s); | ||
295 | return; | ||
296 | } | ||
297 | new_tst: | ||
298 | if ((bmp[(sec & 0x3fff) >> 5] >> (sec & 0x1f) & 1)) { | ||
299 | hpfs_error(s, "sector %08x not allocated", sec); | ||
300 | hpfs_brelse4(&qbh); | ||
301 | unlock_super(s); | ||
302 | return; | ||
303 | } | ||
304 | bmp[(sec & 0x3fff) >> 5] |= 1 << (sec & 0x1f); | ||
305 | if (!--n) { | ||
306 | hpfs_mark_4buffers_dirty(&qbh); | ||
307 | hpfs_brelse4(&qbh); | ||
308 | unlock_super(s); | ||
309 | return; | ||
310 | } | ||
311 | if (!(++sec & 0x3fff)) { | ||
312 | hpfs_mark_4buffers_dirty(&qbh); | ||
313 | hpfs_brelse4(&qbh); | ||
314 | goto new_map; | ||
315 | } | ||
316 | goto new_tst; | ||
317 | } | ||
318 | |||
319 | /* | ||
320 | * Check if there are at least n free dnodes on the filesystem. | ||
321 | * Called before adding to dnode. If we run out of space while | ||
322 | * splitting dnodes, it would corrupt dnode tree. | ||
323 | */ | ||
324 | |||
325 | int hpfs_check_free_dnodes(struct super_block *s, int n) | ||
326 | { | ||
327 | int n_bmps = (hpfs_sb(s)->sb_fs_size + 0x4000 - 1) >> 14; | ||
328 | int b = hpfs_sb(s)->sb_c_bitmap & 0x0fffffff; | ||
329 | int i, j; | ||
330 | unsigned *bmp; | ||
331 | struct quad_buffer_head qbh; | ||
332 | if ((bmp = hpfs_map_dnode_bitmap(s, &qbh))) { | ||
333 | for (j = 0; j < 512; j++) { | ||
334 | unsigned k; | ||
335 | if (!bmp[j]) continue; | ||
336 | for (k = bmp[j]; k; k >>= 1) if (k & 1) if (!--n) { | ||
337 | hpfs_brelse4(&qbh); | ||
338 | return 0; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | hpfs_brelse4(&qbh); | ||
343 | i = 0; | ||
344 | if (hpfs_sb(s)->sb_c_bitmap != -1) { | ||
345 | bmp = hpfs_map_bitmap(s, b, &qbh, "chkdn1"); | ||
346 | goto chk_bmp; | ||
347 | } | ||
348 | chk_next: | ||
349 | if (i == b) i++; | ||
350 | if (i >= n_bmps) return 1; | ||
351 | bmp = hpfs_map_bitmap(s, i, &qbh, "chkdn2"); | ||
352 | chk_bmp: | ||
353 | if (bmp) { | ||
354 | for (j = 0; j < 512; j++) { | ||
355 | unsigned k; | ||
356 | if (!bmp[j]) continue; | ||
357 | for (k = 0xf; k; k <<= 4) | ||
358 | if ((bmp[j] & k) == k) { | ||
359 | if (!--n) { | ||
360 | hpfs_brelse4(&qbh); | ||
361 | return 0; | ||
362 | } | ||
363 | } | ||
364 | } | ||
365 | hpfs_brelse4(&qbh); | ||
366 | } | ||
367 | i++; | ||
368 | goto chk_next; | ||
369 | } | ||
370 | |||
371 | void hpfs_free_dnode(struct super_block *s, dnode_secno dno) | ||
372 | { | ||
373 | if (hpfs_sb(s)->sb_chk) if (dno & 3) { | ||
374 | hpfs_error(s, "hpfs_free_dnode: dnode %08x not aligned", dno); | ||
375 | return; | ||
376 | } | ||
377 | if (dno < hpfs_sb(s)->sb_dirband_start || | ||
378 | dno >= hpfs_sb(s)->sb_dirband_start + hpfs_sb(s)->sb_dirband_size) { | ||
379 | hpfs_free_sectors(s, dno, 4); | ||
380 | } else { | ||
381 | struct quad_buffer_head qbh; | ||
382 | unsigned *bmp; | ||
383 | unsigned ssec = (dno - hpfs_sb(s)->sb_dirband_start) / 4; | ||
384 | lock_super(s); | ||
385 | if (!(bmp = hpfs_map_dnode_bitmap(s, &qbh))) { | ||
386 | unlock_super(s); | ||
387 | return; | ||
388 | } | ||
389 | bmp[ssec >> 5] |= 1 << (ssec & 0x1f); | ||
390 | hpfs_mark_4buffers_dirty(&qbh); | ||
391 | hpfs_brelse4(&qbh); | ||
392 | unlock_super(s); | ||
393 | } | ||
394 | } | ||
395 | |||
396 | struct dnode *hpfs_alloc_dnode(struct super_block *s, secno near, | ||
397 | dnode_secno *dno, struct quad_buffer_head *qbh, | ||
398 | int lock) | ||
399 | { | ||
400 | struct dnode *d; | ||
401 | if (hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_dmap) > FREE_DNODES_ADD) { | ||
402 | if (!(*dno = alloc_in_dirband(s, near, lock))) | ||
403 | if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) return NULL; | ||
404 | } else { | ||
405 | if (!(*dno = hpfs_alloc_sector(s, near, 4, 0, lock))) | ||
406 | if (!(*dno = alloc_in_dirband(s, near, lock))) return NULL; | ||
407 | } | ||
408 | if (!(d = hpfs_get_4sectors(s, *dno, qbh))) { | ||
409 | hpfs_free_dnode(s, *dno); | ||
410 | return NULL; | ||
411 | } | ||
412 | memset(d, 0, 2048); | ||
413 | d->magic = DNODE_MAGIC; | ||
414 | d->first_free = 52; | ||
415 | d->dirent[0] = 32; | ||
416 | d->dirent[2] = 8; | ||
417 | d->dirent[30] = 1; | ||
418 | d->dirent[31] = 255; | ||
419 | d->self = *dno; | ||
420 | return d; | ||
421 | } | ||
422 | |||
423 | struct fnode *hpfs_alloc_fnode(struct super_block *s, secno near, fnode_secno *fno, | ||
424 | struct buffer_head **bh) | ||
425 | { | ||
426 | struct fnode *f; | ||
427 | if (!(*fno = hpfs_alloc_sector(s, near, 1, FNODE_ALLOC_FWD, 1))) return NULL; | ||
428 | if (!(f = hpfs_get_sector(s, *fno, bh))) { | ||
429 | hpfs_free_sectors(s, *fno, 1); | ||
430 | return NULL; | ||
431 | } | ||
432 | memset(f, 0, 512); | ||
433 | f->magic = FNODE_MAGIC; | ||
434 | f->ea_offs = 0xc4; | ||
435 | f->btree.n_free_nodes = 8; | ||
436 | f->btree.first_free = 8; | ||
437 | return f; | ||
438 | } | ||
439 | |||
440 | struct anode *hpfs_alloc_anode(struct super_block *s, secno near, anode_secno *ano, | ||
441 | struct buffer_head **bh) | ||
442 | { | ||
443 | struct anode *a; | ||
444 | if (!(*ano = hpfs_alloc_sector(s, near, 1, ANODE_ALLOC_FWD, 1))) return NULL; | ||
445 | if (!(a = hpfs_get_sector(s, *ano, bh))) { | ||
446 | hpfs_free_sectors(s, *ano, 1); | ||
447 | return NULL; | ||
448 | } | ||
449 | memset(a, 0, 512); | ||
450 | a->magic = ANODE_MAGIC; | ||
451 | a->self = *ano; | ||
452 | a->btree.n_free_nodes = 40; | ||
453 | a->btree.n_used_nodes = 0; | ||
454 | a->btree.first_free = 8; | ||
455 | return a; | ||
456 | } | ||
diff --git a/fs/hpfs/anode.c b/fs/hpfs/anode.c new file mode 100644 index 000000000000..1aa88c4e0964 --- /dev/null +++ b/fs/hpfs/anode.c | |||
@@ -0,0 +1,491 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/anode.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * handling HPFS anode tree that contains file allocation info | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | /* Find a sector in allocation tree */ | ||
12 | |||
13 | secno hpfs_bplus_lookup(struct super_block *s, struct inode *inode, | ||
14 | struct bplus_header *btree, unsigned sec, | ||
15 | struct buffer_head *bh) | ||
16 | { | ||
17 | anode_secno a = -1; | ||
18 | struct anode *anode; | ||
19 | int i; | ||
20 | int c1, c2 = 0; | ||
21 | go_down: | ||
22 | if (hpfs_sb(s)->sb_chk) if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_bplus_lookup")) return -1; | ||
23 | if (btree->internal) { | ||
24 | for (i = 0; i < btree->n_used_nodes; i++) | ||
25 | if (btree->u.internal[i].file_secno > sec) { | ||
26 | a = btree->u.internal[i].down; | ||
27 | brelse(bh); | ||
28 | if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; | ||
29 | btree = &anode->btree; | ||
30 | goto go_down; | ||
31 | } | ||
32 | hpfs_error(s, "sector %08x not found in internal anode %08x", sec, a); | ||
33 | brelse(bh); | ||
34 | return -1; | ||
35 | } | ||
36 | for (i = 0; i < btree->n_used_nodes; i++) | ||
37 | if (btree->u.external[i].file_secno <= sec && | ||
38 | btree->u.external[i].file_secno + btree->u.external[i].length > sec) { | ||
39 | a = btree->u.external[i].disk_secno + sec - btree->u.external[i].file_secno; | ||
40 | if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, a, 1, "data")) { | ||
41 | brelse(bh); | ||
42 | return -1; | ||
43 | } | ||
44 | if (inode) { | ||
45 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
46 | hpfs_inode->i_file_sec = btree->u.external[i].file_secno; | ||
47 | hpfs_inode->i_disk_sec = btree->u.external[i].disk_secno; | ||
48 | hpfs_inode->i_n_secs = btree->u.external[i].length; | ||
49 | } | ||
50 | brelse(bh); | ||
51 | return a; | ||
52 | } | ||
53 | hpfs_error(s, "sector %08x not found in external anode %08x", sec, a); | ||
54 | brelse(bh); | ||
55 | return -1; | ||
56 | } | ||
57 | |||
58 | /* Add a sector to tree */ | ||
59 | |||
60 | secno hpfs_add_sector_to_btree(struct super_block *s, secno node, int fnod, unsigned fsecno) | ||
61 | { | ||
62 | struct bplus_header *btree; | ||
63 | struct anode *anode = NULL, *ranode = NULL; | ||
64 | struct fnode *fnode; | ||
65 | anode_secno a, na = -1, ra, up = -1; | ||
66 | secno se; | ||
67 | struct buffer_head *bh, *bh1, *bh2; | ||
68 | int n; | ||
69 | unsigned fs; | ||
70 | int c1, c2 = 0; | ||
71 | if (fnod) { | ||
72 | if (!(fnode = hpfs_map_fnode(s, node, &bh))) return -1; | ||
73 | btree = &fnode->btree; | ||
74 | } else { | ||
75 | if (!(anode = hpfs_map_anode(s, node, &bh))) return -1; | ||
76 | btree = &anode->btree; | ||
77 | } | ||
78 | a = node; | ||
79 | go_down: | ||
80 | if ((n = btree->n_used_nodes - 1) < -!!fnod) { | ||
81 | hpfs_error(s, "anode %08x has no entries", a); | ||
82 | brelse(bh); | ||
83 | return -1; | ||
84 | } | ||
85 | if (btree->internal) { | ||
86 | a = btree->u.internal[n].down; | ||
87 | btree->u.internal[n].file_secno = -1; | ||
88 | mark_buffer_dirty(bh); | ||
89 | brelse(bh); | ||
90 | if (hpfs_sb(s)->sb_chk) | ||
91 | if (hpfs_stop_cycles(s, a, &c1, &c2, "hpfs_add_sector_to_btree #1")) return -1; | ||
92 | if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; | ||
93 | btree = &anode->btree; | ||
94 | goto go_down; | ||
95 | } | ||
96 | if (n >= 0) { | ||
97 | if (btree->u.external[n].file_secno + btree->u.external[n].length != fsecno) { | ||
98 | hpfs_error(s, "allocated size %08x, trying to add sector %08x, %cnode %08x", | ||
99 | btree->u.external[n].file_secno + btree->u.external[n].length, fsecno, | ||
100 | fnod?'f':'a', node); | ||
101 | brelse(bh); | ||
102 | return -1; | ||
103 | } | ||
104 | if (hpfs_alloc_if_possible(s, se = btree->u.external[n].disk_secno + btree->u.external[n].length)) { | ||
105 | btree->u.external[n].length++; | ||
106 | mark_buffer_dirty(bh); | ||
107 | brelse(bh); | ||
108 | return se; | ||
109 | } | ||
110 | } else { | ||
111 | if (fsecno) { | ||
112 | hpfs_error(s, "empty file %08x, trying to add sector %08x", node, fsecno); | ||
113 | brelse(bh); | ||
114 | return -1; | ||
115 | } | ||
116 | se = !fnod ? node : (node + 16384) & ~16383; | ||
117 | } | ||
118 | if (!(se = hpfs_alloc_sector(s, se, 1, fsecno*ALLOC_M>ALLOC_FWD_MAX ? ALLOC_FWD_MAX : fsecno*ALLOC_M<ALLOC_FWD_MIN ? ALLOC_FWD_MIN : fsecno*ALLOC_M, 1))) { | ||
119 | brelse(bh); | ||
120 | return -1; | ||
121 | } | ||
122 | fs = n < 0 ? 0 : btree->u.external[n].file_secno + btree->u.external[n].length; | ||
123 | if (!btree->n_free_nodes) { | ||
124 | up = a != node ? anode->up : -1; | ||
125 | if (!(anode = hpfs_alloc_anode(s, a, &na, &bh1))) { | ||
126 | brelse(bh); | ||
127 | hpfs_free_sectors(s, se, 1); | ||
128 | return -1; | ||
129 | } | ||
130 | if (a == node && fnod) { | ||
131 | anode->up = node; | ||
132 | anode->btree.fnode_parent = 1; | ||
133 | anode->btree.n_used_nodes = btree->n_used_nodes; | ||
134 | anode->btree.first_free = btree->first_free; | ||
135 | anode->btree.n_free_nodes = 40 - anode->btree.n_used_nodes; | ||
136 | memcpy(&anode->u, &btree->u, btree->n_used_nodes * 12); | ||
137 | btree->internal = 1; | ||
138 | btree->n_free_nodes = 11; | ||
139 | btree->n_used_nodes = 1; | ||
140 | btree->first_free = (char *)&(btree->u.internal[1]) - (char *)btree; | ||
141 | btree->u.internal[0].file_secno = -1; | ||
142 | btree->u.internal[0].down = na; | ||
143 | mark_buffer_dirty(bh); | ||
144 | } else if (!(ranode = hpfs_alloc_anode(s, /*a*/0, &ra, &bh2))) { | ||
145 | brelse(bh); | ||
146 | brelse(bh1); | ||
147 | hpfs_free_sectors(s, se, 1); | ||
148 | hpfs_free_sectors(s, na, 1); | ||
149 | return -1; | ||
150 | } | ||
151 | brelse(bh); | ||
152 | bh = bh1; | ||
153 | btree = &anode->btree; | ||
154 | } | ||
155 | btree->n_free_nodes--; n = btree->n_used_nodes++; | ||
156 | btree->first_free += 12; | ||
157 | btree->u.external[n].disk_secno = se; | ||
158 | btree->u.external[n].file_secno = fs; | ||
159 | btree->u.external[n].length = 1; | ||
160 | mark_buffer_dirty(bh); | ||
161 | brelse(bh); | ||
162 | if ((a == node && fnod) || na == -1) return se; | ||
163 | c2 = 0; | ||
164 | while (up != -1) { | ||
165 | struct anode *new_anode; | ||
166 | if (hpfs_sb(s)->sb_chk) | ||
167 | if (hpfs_stop_cycles(s, up, &c1, &c2, "hpfs_add_sector_to_btree #2")) return -1; | ||
168 | if (up != node || !fnod) { | ||
169 | if (!(anode = hpfs_map_anode(s, up, &bh))) return -1; | ||
170 | btree = &anode->btree; | ||
171 | } else { | ||
172 | if (!(fnode = hpfs_map_fnode(s, up, &bh))) return -1; | ||
173 | btree = &fnode->btree; | ||
174 | } | ||
175 | if (btree->n_free_nodes) { | ||
176 | btree->n_free_nodes--; n = btree->n_used_nodes++; | ||
177 | btree->first_free += 8; | ||
178 | btree->u.internal[n].file_secno = -1; | ||
179 | btree->u.internal[n].down = na; | ||
180 | btree->u.internal[n-1].file_secno = fs; | ||
181 | mark_buffer_dirty(bh); | ||
182 | brelse(bh); | ||
183 | brelse(bh2); | ||
184 | hpfs_free_sectors(s, ra, 1); | ||
185 | if ((anode = hpfs_map_anode(s, na, &bh))) { | ||
186 | anode->up = up; | ||
187 | anode->btree.fnode_parent = up == node && fnod; | ||
188 | mark_buffer_dirty(bh); | ||
189 | brelse(bh); | ||
190 | } | ||
191 | return se; | ||
192 | } | ||
193 | up = up != node ? anode->up : -1; | ||
194 | btree->u.internal[btree->n_used_nodes - 1].file_secno = /*fs*/-1; | ||
195 | mark_buffer_dirty(bh); | ||
196 | brelse(bh); | ||
197 | a = na; | ||
198 | if ((new_anode = hpfs_alloc_anode(s, a, &na, &bh))) { | ||
199 | anode = new_anode; | ||
200 | /*anode->up = up != -1 ? up : ra;*/ | ||
201 | anode->btree.internal = 1; | ||
202 | anode->btree.n_used_nodes = 1; | ||
203 | anode->btree.n_free_nodes = 59; | ||
204 | anode->btree.first_free = 16; | ||
205 | anode->btree.u.internal[0].down = a; | ||
206 | anode->btree.u.internal[0].file_secno = -1; | ||
207 | mark_buffer_dirty(bh); | ||
208 | brelse(bh); | ||
209 | if ((anode = hpfs_map_anode(s, a, &bh))) { | ||
210 | anode->up = na; | ||
211 | mark_buffer_dirty(bh); | ||
212 | brelse(bh); | ||
213 | } | ||
214 | } else na = a; | ||
215 | } | ||
216 | if ((anode = hpfs_map_anode(s, na, &bh))) { | ||
217 | anode->up = node; | ||
218 | if (fnod) anode->btree.fnode_parent = 1; | ||
219 | mark_buffer_dirty(bh); | ||
220 | brelse(bh); | ||
221 | } | ||
222 | if (!fnod) { | ||
223 | if (!(anode = hpfs_map_anode(s, node, &bh))) { | ||
224 | brelse(bh2); | ||
225 | return -1; | ||
226 | } | ||
227 | btree = &anode->btree; | ||
228 | } else { | ||
229 | if (!(fnode = hpfs_map_fnode(s, node, &bh))) { | ||
230 | brelse(bh2); | ||
231 | return -1; | ||
232 | } | ||
233 | btree = &fnode->btree; | ||
234 | } | ||
235 | ranode->up = node; | ||
236 | memcpy(&ranode->btree, btree, btree->first_free); | ||
237 | if (fnod) ranode->btree.fnode_parent = 1; | ||
238 | ranode->btree.n_free_nodes = (ranode->btree.internal ? 60 : 40) - ranode->btree.n_used_nodes; | ||
239 | if (ranode->btree.internal) for (n = 0; n < ranode->btree.n_used_nodes; n++) { | ||
240 | struct anode *unode; | ||
241 | if ((unode = hpfs_map_anode(s, ranode->u.internal[n].down, &bh1))) { | ||
242 | unode->up = ra; | ||
243 | unode->btree.fnode_parent = 0; | ||
244 | mark_buffer_dirty(bh1); | ||
245 | brelse(bh1); | ||
246 | } | ||
247 | } | ||
248 | btree->internal = 1; | ||
249 | btree->n_free_nodes = fnod ? 10 : 58; | ||
250 | btree->n_used_nodes = 2; | ||
251 | btree->first_free = (char *)&btree->u.internal[2] - (char *)btree; | ||
252 | btree->u.internal[0].file_secno = fs; | ||
253 | btree->u.internal[0].down = ra; | ||
254 | btree->u.internal[1].file_secno = -1; | ||
255 | btree->u.internal[1].down = na; | ||
256 | mark_buffer_dirty(bh); | ||
257 | brelse(bh); | ||
258 | mark_buffer_dirty(bh2); | ||
259 | brelse(bh2); | ||
260 | return se; | ||
261 | } | ||
262 | |||
263 | /* | ||
264 | * Remove allocation tree. Recursion would look much nicer but | ||
265 | * I want to avoid it because it can cause stack overflow. | ||
266 | */ | ||
267 | |||
268 | void hpfs_remove_btree(struct super_block *s, struct bplus_header *btree) | ||
269 | { | ||
270 | struct bplus_header *btree1 = btree; | ||
271 | struct anode *anode = NULL; | ||
272 | anode_secno ano = 0, oano; | ||
273 | struct buffer_head *bh; | ||
274 | int level = 0; | ||
275 | int pos = 0; | ||
276 | int i; | ||
277 | int c1, c2 = 0; | ||
278 | int d1, d2; | ||
279 | go_down: | ||
280 | d2 = 0; | ||
281 | while (btree1->internal) { | ||
282 | ano = btree1->u.internal[pos].down; | ||
283 | if (level) brelse(bh); | ||
284 | if (hpfs_sb(s)->sb_chk) | ||
285 | if (hpfs_stop_cycles(s, ano, &d1, &d2, "hpfs_remove_btree #1")) | ||
286 | return; | ||
287 | if (!(anode = hpfs_map_anode(s, ano, &bh))) return; | ||
288 | btree1 = &anode->btree; | ||
289 | level++; | ||
290 | pos = 0; | ||
291 | } | ||
292 | for (i = 0; i < btree1->n_used_nodes; i++) | ||
293 | hpfs_free_sectors(s, btree1->u.external[i].disk_secno, btree1->u.external[i].length); | ||
294 | go_up: | ||
295 | if (!level) return; | ||
296 | brelse(bh); | ||
297 | if (hpfs_sb(s)->sb_chk) | ||
298 | if (hpfs_stop_cycles(s, ano, &c1, &c2, "hpfs_remove_btree #2")) return; | ||
299 | hpfs_free_sectors(s, ano, 1); | ||
300 | oano = ano; | ||
301 | ano = anode->up; | ||
302 | if (--level) { | ||
303 | if (!(anode = hpfs_map_anode(s, ano, &bh))) return; | ||
304 | btree1 = &anode->btree; | ||
305 | } else btree1 = btree; | ||
306 | for (i = 0; i < btree1->n_used_nodes; i++) { | ||
307 | if (btree1->u.internal[i].down == oano) { | ||
308 | if ((pos = i + 1) < btree1->n_used_nodes) | ||
309 | goto go_down; | ||
310 | else | ||
311 | goto go_up; | ||
312 | } | ||
313 | } | ||
314 | hpfs_error(s, | ||
315 | "reference to anode %08x not found in anode %08x " | ||
316 | "(probably bad up pointer)", | ||
317 | oano, level ? ano : -1); | ||
318 | if (level) | ||
319 | brelse(bh); | ||
320 | } | ||
321 | |||
322 | /* Just a wrapper around hpfs_bplus_lookup .. used for reading eas */ | ||
323 | |||
324 | static secno anode_lookup(struct super_block *s, anode_secno a, unsigned sec) | ||
325 | { | ||
326 | struct anode *anode; | ||
327 | struct buffer_head *bh; | ||
328 | if (!(anode = hpfs_map_anode(s, a, &bh))) return -1; | ||
329 | return hpfs_bplus_lookup(s, NULL, &anode->btree, sec, bh); | ||
330 | } | ||
331 | |||
332 | int hpfs_ea_read(struct super_block *s, secno a, int ano, unsigned pos, | ||
333 | unsigned len, char *buf) | ||
334 | { | ||
335 | struct buffer_head *bh; | ||
336 | char *data; | ||
337 | secno sec; | ||
338 | unsigned l; | ||
339 | while (len) { | ||
340 | if (ano) { | ||
341 | if ((sec = anode_lookup(s, a, pos >> 9)) == -1) | ||
342 | return -1; | ||
343 | } else sec = a + (pos >> 9); | ||
344 | if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, sec, 1, "ea #1")) return -1; | ||
345 | if (!(data = hpfs_map_sector(s, sec, &bh, (len - 1) >> 9))) | ||
346 | return -1; | ||
347 | l = 0x200 - (pos & 0x1ff); if (l > len) l = len; | ||
348 | memcpy(buf, data + (pos & 0x1ff), l); | ||
349 | brelse(bh); | ||
350 | buf += l; pos += l; len -= l; | ||
351 | } | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | int hpfs_ea_write(struct super_block *s, secno a, int ano, unsigned pos, | ||
356 | unsigned len, char *buf) | ||
357 | { | ||
358 | struct buffer_head *bh; | ||
359 | char *data; | ||
360 | secno sec; | ||
361 | unsigned l; | ||
362 | while (len) { | ||
363 | if (ano) { | ||
364 | if ((sec = anode_lookup(s, a, pos >> 9)) == -1) | ||
365 | return -1; | ||
366 | } else sec = a + (pos >> 9); | ||
367 | if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, sec, 1, "ea #2")) return -1; | ||
368 | if (!(data = hpfs_map_sector(s, sec, &bh, (len - 1) >> 9))) | ||
369 | return -1; | ||
370 | l = 0x200 - (pos & 0x1ff); if (l > len) l = len; | ||
371 | memcpy(data + (pos & 0x1ff), buf, l); | ||
372 | mark_buffer_dirty(bh); | ||
373 | brelse(bh); | ||
374 | buf += l; pos += l; len -= l; | ||
375 | } | ||
376 | return 0; | ||
377 | } | ||
378 | |||
379 | void hpfs_ea_remove(struct super_block *s, secno a, int ano, unsigned len) | ||
380 | { | ||
381 | struct anode *anode; | ||
382 | struct buffer_head *bh; | ||
383 | if (ano) { | ||
384 | if (!(anode = hpfs_map_anode(s, a, &bh))) return; | ||
385 | hpfs_remove_btree(s, &anode->btree); | ||
386 | brelse(bh); | ||
387 | hpfs_free_sectors(s, a, 1); | ||
388 | } else hpfs_free_sectors(s, a, (len + 511) >> 9); | ||
389 | } | ||
390 | |||
391 | /* Truncate allocation tree. Doesn't join anodes - I hope it doesn't matter */ | ||
392 | |||
393 | void hpfs_truncate_btree(struct super_block *s, secno f, int fno, unsigned secs) | ||
394 | { | ||
395 | struct fnode *fnode; | ||
396 | struct anode *anode; | ||
397 | struct buffer_head *bh; | ||
398 | struct bplus_header *btree; | ||
399 | anode_secno node = f; | ||
400 | int i, j, nodes; | ||
401 | int c1, c2 = 0; | ||
402 | if (fno) { | ||
403 | if (!(fnode = hpfs_map_fnode(s, f, &bh))) return; | ||
404 | btree = &fnode->btree; | ||
405 | } else { | ||
406 | if (!(anode = hpfs_map_anode(s, f, &bh))) return; | ||
407 | btree = &anode->btree; | ||
408 | } | ||
409 | if (!secs) { | ||
410 | hpfs_remove_btree(s, btree); | ||
411 | if (fno) { | ||
412 | btree->n_free_nodes = 8; | ||
413 | btree->n_used_nodes = 0; | ||
414 | btree->first_free = 8; | ||
415 | btree->internal = 0; | ||
416 | mark_buffer_dirty(bh); | ||
417 | } else hpfs_free_sectors(s, f, 1); | ||
418 | brelse(bh); | ||
419 | return; | ||
420 | } | ||
421 | while (btree->internal) { | ||
422 | nodes = btree->n_used_nodes + btree->n_free_nodes; | ||
423 | for (i = 0; i < btree->n_used_nodes; i++) | ||
424 | if (btree->u.internal[i].file_secno >= secs) goto f; | ||
425 | brelse(bh); | ||
426 | hpfs_error(s, "internal btree %08x doesn't end with -1", node); | ||
427 | return; | ||
428 | f: | ||
429 | for (j = i + 1; j < btree->n_used_nodes; j++) | ||
430 | hpfs_ea_remove(s, btree->u.internal[j].down, 1, 0); | ||
431 | btree->n_used_nodes = i + 1; | ||
432 | btree->n_free_nodes = nodes - btree->n_used_nodes; | ||
433 | btree->first_free = 8 + 8 * btree->n_used_nodes; | ||
434 | mark_buffer_dirty(bh); | ||
435 | if (btree->u.internal[i].file_secno == secs) { | ||
436 | brelse(bh); | ||
437 | return; | ||
438 | } | ||
439 | node = btree->u.internal[i].down; | ||
440 | brelse(bh); | ||
441 | if (hpfs_sb(s)->sb_chk) | ||
442 | if (hpfs_stop_cycles(s, node, &c1, &c2, "hpfs_truncate_btree")) | ||
443 | return; | ||
444 | if (!(anode = hpfs_map_anode(s, node, &bh))) return; | ||
445 | btree = &anode->btree; | ||
446 | } | ||
447 | nodes = btree->n_used_nodes + btree->n_free_nodes; | ||
448 | for (i = 0; i < btree->n_used_nodes; i++) | ||
449 | if (btree->u.external[i].file_secno + btree->u.external[i].length >= secs) goto ff; | ||
450 | brelse(bh); | ||
451 | return; | ||
452 | ff: | ||
453 | if (secs <= btree->u.external[i].file_secno) { | ||
454 | hpfs_error(s, "there is an allocation error in file %08x, sector %08x", f, secs); | ||
455 | if (i) i--; | ||
456 | } | ||
457 | else if (btree->u.external[i].file_secno + btree->u.external[i].length > secs) { | ||
458 | hpfs_free_sectors(s, btree->u.external[i].disk_secno + secs - | ||
459 | btree->u.external[i].file_secno, btree->u.external[i].length | ||
460 | - secs + btree->u.external[i].file_secno); /* I hope gcc optimizes this :-) */ | ||
461 | btree->u.external[i].length = secs - btree->u.external[i].file_secno; | ||
462 | } | ||
463 | for (j = i + 1; j < btree->n_used_nodes; j++) | ||
464 | hpfs_free_sectors(s, btree->u.external[j].disk_secno, btree->u.external[j].length); | ||
465 | btree->n_used_nodes = i + 1; | ||
466 | btree->n_free_nodes = nodes - btree->n_used_nodes; | ||
467 | btree->first_free = 8 + 12 * btree->n_used_nodes; | ||
468 | mark_buffer_dirty(bh); | ||
469 | brelse(bh); | ||
470 | } | ||
471 | |||
472 | /* Remove file or directory and it's eas - note that directory must | ||
473 | be empty when this is called. */ | ||
474 | |||
475 | void hpfs_remove_fnode(struct super_block *s, fnode_secno fno) | ||
476 | { | ||
477 | struct buffer_head *bh; | ||
478 | struct fnode *fnode; | ||
479 | struct extended_attribute *ea; | ||
480 | struct extended_attribute *ea_end; | ||
481 | if (!(fnode = hpfs_map_fnode(s, fno, &bh))) return; | ||
482 | if (!fnode->dirflag) hpfs_remove_btree(s, &fnode->btree); | ||
483 | else hpfs_remove_dtree(s, fnode->u.external[0].disk_secno); | ||
484 | ea_end = fnode_end_ea(fnode); | ||
485 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | ||
486 | if (ea->indirect) | ||
487 | hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); | ||
488 | hpfs_ea_ext_remove(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l); | ||
489 | brelse(bh); | ||
490 | hpfs_free_sectors(s, fno, 1); | ||
491 | } | ||
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c new file mode 100644 index 000000000000..2807aa833e62 --- /dev/null +++ b/fs/hpfs/buffer.c | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/buffer.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * general buffer i/o | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | void hpfs_lock_creation(struct super_block *s) | ||
12 | { | ||
13 | #ifdef DEBUG_LOCKS | ||
14 | printk("lock creation\n"); | ||
15 | #endif | ||
16 | down(&hpfs_sb(s)->hpfs_creation_de); | ||
17 | } | ||
18 | |||
19 | void hpfs_unlock_creation(struct super_block *s) | ||
20 | { | ||
21 | #ifdef DEBUG_LOCKS | ||
22 | printk("unlock creation\n"); | ||
23 | #endif | ||
24 | up(&hpfs_sb(s)->hpfs_creation_de); | ||
25 | } | ||
26 | |||
27 | /* Map a sector into a buffer and return pointers to it and to the buffer. */ | ||
28 | |||
29 | void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp, | ||
30 | int ahead) | ||
31 | { | ||
32 | struct buffer_head *bh; | ||
33 | |||
34 | cond_resched(); | ||
35 | |||
36 | *bhp = bh = sb_bread(s, secno); | ||
37 | if (bh != NULL) | ||
38 | return bh->b_data; | ||
39 | else { | ||
40 | printk("HPFS: hpfs_map_sector: read error\n"); | ||
41 | return NULL; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | /* Like hpfs_map_sector but don't read anything */ | ||
46 | |||
47 | void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head **bhp) | ||
48 | { | ||
49 | struct buffer_head *bh; | ||
50 | /*return hpfs_map_sector(s, secno, bhp, 0);*/ | ||
51 | |||
52 | cond_resched(); | ||
53 | |||
54 | if ((*bhp = bh = sb_getblk(s, secno)) != NULL) { | ||
55 | if (!buffer_uptodate(bh)) wait_on_buffer(bh); | ||
56 | set_buffer_uptodate(bh); | ||
57 | return bh->b_data; | ||
58 | } else { | ||
59 | printk("HPFS: hpfs_get_sector: getblk failed\n"); | ||
60 | return NULL; | ||
61 | } | ||
62 | } | ||
63 | |||
64 | /* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */ | ||
65 | |||
66 | void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffer_head *qbh, | ||
67 | int ahead) | ||
68 | { | ||
69 | struct buffer_head *bh; | ||
70 | char *data; | ||
71 | |||
72 | cond_resched(); | ||
73 | |||
74 | if (secno & 3) { | ||
75 | printk("HPFS: hpfs_map_4sectors: unaligned read\n"); | ||
76 | return NULL; | ||
77 | } | ||
78 | |||
79 | qbh->data = data = (char *)kmalloc(2048, GFP_NOFS); | ||
80 | if (!data) { | ||
81 | printk("HPFS: hpfs_map_4sectors: out of memory\n"); | ||
82 | goto bail; | ||
83 | } | ||
84 | |||
85 | qbh->bh[0] = bh = sb_bread(s, secno); | ||
86 | if (!bh) | ||
87 | goto bail0; | ||
88 | memcpy(data, bh->b_data, 512); | ||
89 | |||
90 | qbh->bh[1] = bh = sb_bread(s, secno + 1); | ||
91 | if (!bh) | ||
92 | goto bail1; | ||
93 | memcpy(data + 512, bh->b_data, 512); | ||
94 | |||
95 | qbh->bh[2] = bh = sb_bread(s, secno + 2); | ||
96 | if (!bh) | ||
97 | goto bail2; | ||
98 | memcpy(data + 2 * 512, bh->b_data, 512); | ||
99 | |||
100 | qbh->bh[3] = bh = sb_bread(s, secno + 3); | ||
101 | if (!bh) | ||
102 | goto bail3; | ||
103 | memcpy(data + 3 * 512, bh->b_data, 512); | ||
104 | |||
105 | return data; | ||
106 | |||
107 | bail3: | ||
108 | brelse(qbh->bh[2]); | ||
109 | bail2: | ||
110 | brelse(qbh->bh[1]); | ||
111 | bail1: | ||
112 | brelse(qbh->bh[0]); | ||
113 | bail0: | ||
114 | kfree(data); | ||
115 | printk("HPFS: hpfs_map_4sectors: read error\n"); | ||
116 | bail: | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | /* Don't read sectors */ | ||
121 | |||
122 | void *hpfs_get_4sectors(struct super_block *s, unsigned secno, | ||
123 | struct quad_buffer_head *qbh) | ||
124 | { | ||
125 | cond_resched(); | ||
126 | |||
127 | if (secno & 3) { | ||
128 | printk("HPFS: hpfs_get_4sectors: unaligned read\n"); | ||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | /*return hpfs_map_4sectors(s, secno, qbh, 0);*/ | ||
133 | if (!(qbh->data = kmalloc(2048, GFP_NOFS))) { | ||
134 | printk("HPFS: hpfs_get_4sectors: out of memory\n"); | ||
135 | return NULL; | ||
136 | } | ||
137 | if (!(hpfs_get_sector(s, secno, &qbh->bh[0]))) goto bail0; | ||
138 | if (!(hpfs_get_sector(s, secno + 1, &qbh->bh[1]))) goto bail1; | ||
139 | if (!(hpfs_get_sector(s, secno + 2, &qbh->bh[2]))) goto bail2; | ||
140 | if (!(hpfs_get_sector(s, secno + 3, &qbh->bh[3]))) goto bail3; | ||
141 | memcpy(qbh->data, qbh->bh[0]->b_data, 512); | ||
142 | memcpy(qbh->data + 512, qbh->bh[1]->b_data, 512); | ||
143 | memcpy(qbh->data + 2*512, qbh->bh[2]->b_data, 512); | ||
144 | memcpy(qbh->data + 3*512, qbh->bh[3]->b_data, 512); | ||
145 | return qbh->data; | ||
146 | |||
147 | bail3: brelse(qbh->bh[2]); | ||
148 | bail2: brelse(qbh->bh[1]); | ||
149 | bail1: brelse(qbh->bh[0]); | ||
150 | bail0: | ||
151 | return NULL; | ||
152 | } | ||
153 | |||
154 | |||
155 | void hpfs_brelse4(struct quad_buffer_head *qbh) | ||
156 | { | ||
157 | brelse(qbh->bh[3]); | ||
158 | brelse(qbh->bh[2]); | ||
159 | brelse(qbh->bh[1]); | ||
160 | brelse(qbh->bh[0]); | ||
161 | kfree(qbh->data); | ||
162 | } | ||
163 | |||
164 | void hpfs_mark_4buffers_dirty(struct quad_buffer_head *qbh) | ||
165 | { | ||
166 | PRINTK(("hpfs_mark_4buffers_dirty\n")); | ||
167 | memcpy(qbh->bh[0]->b_data, qbh->data, 512); | ||
168 | memcpy(qbh->bh[1]->b_data, qbh->data + 512, 512); | ||
169 | memcpy(qbh->bh[2]->b_data, qbh->data + 2 * 512, 512); | ||
170 | memcpy(qbh->bh[3]->b_data, qbh->data + 3 * 512, 512); | ||
171 | mark_buffer_dirty(qbh->bh[0]); | ||
172 | mark_buffer_dirty(qbh->bh[1]); | ||
173 | mark_buffer_dirty(qbh->bh[2]); | ||
174 | mark_buffer_dirty(qbh->bh[3]); | ||
175 | } | ||
diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c new file mode 100644 index 000000000000..08319126b2af --- /dev/null +++ b/fs/hpfs/dentry.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/dentry.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * dcache operations | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | /* | ||
12 | * Note: the dentry argument is the parent dentry. | ||
13 | */ | ||
14 | |||
15 | static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr) | ||
16 | { | ||
17 | unsigned long hash; | ||
18 | int i; | ||
19 | unsigned l = qstr->len; | ||
20 | |||
21 | if (l == 1) if (qstr->name[0]=='.') goto x; | ||
22 | if (l == 2) if (qstr->name[0]=='.' || qstr->name[1]=='.') goto x; | ||
23 | hpfs_adjust_length((char *)qstr->name, &l); | ||
24 | /*if (hpfs_chk_name((char *)qstr->name,&l))*/ | ||
25 | /*return -ENAMETOOLONG;*/ | ||
26 | /*return -ENOENT;*/ | ||
27 | x: | ||
28 | |||
29 | hash = init_name_hash(); | ||
30 | for (i = 0; i < l; i++) | ||
31 | hash = partial_name_hash(hpfs_upcase(hpfs_sb(dentry->d_sb)->sb_cp_table,qstr->name[i]), hash); | ||
32 | qstr->hash = end_name_hash(hash); | ||
33 | |||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | ||
38 | { | ||
39 | unsigned al=a->len; | ||
40 | unsigned bl=b->len; | ||
41 | hpfs_adjust_length((char *)a->name, &al); | ||
42 | /*hpfs_adjust_length((char *)b->name, &bl);*/ | ||
43 | /* 'a' is the qstr of an already existing dentry, so the name | ||
44 | * must be valid. 'b' must be validated first. | ||
45 | */ | ||
46 | |||
47 | if (hpfs_chk_name((char *)b->name, &bl)) return 1; | ||
48 | if (hpfs_compare_names(dentry->d_sb, (char *)a->name, al, (char *)b->name, bl, 0)) return 1; | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static struct dentry_operations hpfs_dentry_operations = { | ||
53 | .d_hash = hpfs_hash_dentry, | ||
54 | .d_compare = hpfs_compare_dentry, | ||
55 | }; | ||
56 | |||
57 | void hpfs_set_dentry_operations(struct dentry *dentry) | ||
58 | { | ||
59 | dentry->d_op = &hpfs_dentry_operations; | ||
60 | } | ||
diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c new file mode 100644 index 000000000000..0217c3a04441 --- /dev/null +++ b/fs/hpfs/dir.c | |||
@@ -0,0 +1,320 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/dir.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * directory VFS functions | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | static int hpfs_dir_release(struct inode *inode, struct file *filp) | ||
12 | { | ||
13 | lock_kernel(); | ||
14 | hpfs_del_pos(inode, &filp->f_pos); | ||
15 | /*hpfs_write_if_changed(inode);*/ | ||
16 | unlock_kernel(); | ||
17 | return 0; | ||
18 | } | ||
19 | |||
20 | /* This is slow, but it's not used often */ | ||
21 | |||
22 | static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence) | ||
23 | { | ||
24 | loff_t new_off = off + (whence == 1 ? filp->f_pos : 0); | ||
25 | loff_t pos; | ||
26 | struct quad_buffer_head qbh; | ||
27 | struct inode *i = filp->f_dentry->d_inode; | ||
28 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
29 | struct super_block *s = i->i_sb; | ||
30 | |||
31 | lock_kernel(); | ||
32 | |||
33 | /*printk("dir lseek\n");*/ | ||
34 | if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok; | ||
35 | down(&i->i_sem); | ||
36 | pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1; | ||
37 | while (pos != new_off) { | ||
38 | if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh); | ||
39 | else goto fail; | ||
40 | if (pos == 12) goto fail; | ||
41 | } | ||
42 | up(&i->i_sem); | ||
43 | ok: | ||
44 | unlock_kernel(); | ||
45 | return filp->f_pos = new_off; | ||
46 | fail: | ||
47 | up(&i->i_sem); | ||
48 | /*printk("illegal lseek: %016llx\n", new_off);*/ | ||
49 | unlock_kernel(); | ||
50 | return -ESPIPE; | ||
51 | } | ||
52 | |||
53 | static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
54 | { | ||
55 | struct inode *inode = filp->f_dentry->d_inode; | ||
56 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
57 | struct quad_buffer_head qbh; | ||
58 | struct hpfs_dirent *de; | ||
59 | int lc; | ||
60 | long old_pos; | ||
61 | char *tempname; | ||
62 | int c1, c2 = 0; | ||
63 | int ret = 0; | ||
64 | |||
65 | lock_kernel(); | ||
66 | |||
67 | if (hpfs_sb(inode->i_sb)->sb_chk) { | ||
68 | if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode")) { | ||
69 | ret = -EFSERROR; | ||
70 | goto out; | ||
71 | } | ||
72 | if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode")) { | ||
73 | ret = -EFSERROR; | ||
74 | goto out; | ||
75 | } | ||
76 | } | ||
77 | if (hpfs_sb(inode->i_sb)->sb_chk >= 2) { | ||
78 | struct buffer_head *bh; | ||
79 | struct fnode *fno; | ||
80 | int e = 0; | ||
81 | if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) { | ||
82 | ret = -EIOERROR; | ||
83 | goto out; | ||
84 | } | ||
85 | if (!fno->dirflag) { | ||
86 | e = 1; | ||
87 | hpfs_error(inode->i_sb, "not a directory, fnode %08x",inode->i_ino); | ||
88 | } | ||
89 | if (hpfs_inode->i_dno != fno->u.external[0].disk_secno) { | ||
90 | e = 1; | ||
91 | hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, fno->u.external[0].disk_secno); | ||
92 | } | ||
93 | brelse(bh); | ||
94 | if (e) { | ||
95 | ret = -EFSERROR; | ||
96 | goto out; | ||
97 | } | ||
98 | } | ||
99 | lc = hpfs_sb(inode->i_sb)->sb_lowercase; | ||
100 | if (filp->f_pos == 12) { /* diff -r requires this (note, that diff -r */ | ||
101 | filp->f_pos = 13; /* also fails on msdos filesystem in 2.0) */ | ||
102 | goto out; | ||
103 | } | ||
104 | if (filp->f_pos == 13) { | ||
105 | ret = -ENOENT; | ||
106 | goto out; | ||
107 | } | ||
108 | |||
109 | while (1) { | ||
110 | again: | ||
111 | /* This won't work when cycle is longer than number of dirents | ||
112 | accepted by filldir, but what can I do? | ||
113 | maybe killall -9 ls helps */ | ||
114 | if (hpfs_sb(inode->i_sb)->sb_chk) | ||
115 | if (hpfs_stop_cycles(inode->i_sb, filp->f_pos, &c1, &c2, "hpfs_readdir")) { | ||
116 | ret = -EFSERROR; | ||
117 | goto out; | ||
118 | } | ||
119 | if (filp->f_pos == 12) | ||
120 | goto out; | ||
121 | if (filp->f_pos == 3 || filp->f_pos == 4 || filp->f_pos == 5) { | ||
122 | printk("HPFS: warning: pos==%d\n",(int)filp->f_pos); | ||
123 | goto out; | ||
124 | } | ||
125 | if (filp->f_pos == 0) { | ||
126 | if (filldir(dirent, ".", 1, filp->f_pos, inode->i_ino, DT_DIR) < 0) | ||
127 | goto out; | ||
128 | filp->f_pos = 11; | ||
129 | } | ||
130 | if (filp->f_pos == 11) { | ||
131 | if (filldir(dirent, "..", 2, filp->f_pos, hpfs_inode->i_parent_dir, DT_DIR) < 0) | ||
132 | goto out; | ||
133 | filp->f_pos = 1; | ||
134 | } | ||
135 | if (filp->f_pos == 1) { | ||
136 | filp->f_pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1; | ||
137 | hpfs_add_pos(inode, &filp->f_pos); | ||
138 | filp->f_version = inode->i_version; | ||
139 | } | ||
140 | old_pos = filp->f_pos; | ||
141 | if (!(de = map_pos_dirent(inode, &filp->f_pos, &qbh))) { | ||
142 | ret = -EIOERROR; | ||
143 | goto out; | ||
144 | } | ||
145 | if (de->first || de->last) { | ||
146 | if (hpfs_sb(inode->i_sb)->sb_chk) { | ||
147 | if (de->first && !de->last && (de->namelen != 2 || de ->name[0] != 1 || de->name[1] != 1)) hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08x", old_pos); | ||
148 | if (de->last && (de->namelen != 1 || de ->name[0] != 255)) hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08x", old_pos); | ||
149 | } | ||
150 | hpfs_brelse4(&qbh); | ||
151 | goto again; | ||
152 | } | ||
153 | tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3); | ||
154 | if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) { | ||
155 | filp->f_pos = old_pos; | ||
156 | if (tempname != (char *)de->name) kfree(tempname); | ||
157 | hpfs_brelse4(&qbh); | ||
158 | goto out; | ||
159 | } | ||
160 | if (tempname != (char *)de->name) kfree(tempname); | ||
161 | hpfs_brelse4(&qbh); | ||
162 | } | ||
163 | out: | ||
164 | unlock_kernel(); | ||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | /* | ||
169 | * lookup. Search the specified directory for the specified name, set | ||
170 | * *result to the corresponding inode. | ||
171 | * | ||
172 | * lookup uses the inode number to tell read_inode whether it is reading | ||
173 | * the inode of a directory or a file -- file ino's are odd, directory | ||
174 | * ino's are even. read_inode avoids i/o for file inodes; everything | ||
175 | * needed is up here in the directory. (And file fnodes are out in | ||
176 | * the boondocks.) | ||
177 | * | ||
178 | * - M.P.: this is over, sometimes we've got to read file's fnode for eas | ||
179 | * inode numbers are just fnode sector numbers; iget lock is used | ||
180 | * to tell read_inode to read fnode or not. | ||
181 | */ | ||
182 | |||
183 | struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
184 | { | ||
185 | const char *name = dentry->d_name.name; | ||
186 | unsigned len = dentry->d_name.len; | ||
187 | struct quad_buffer_head qbh; | ||
188 | struct hpfs_dirent *de; | ||
189 | ino_t ino; | ||
190 | int err; | ||
191 | struct inode *result = NULL; | ||
192 | struct hpfs_inode_info *hpfs_result; | ||
193 | |||
194 | lock_kernel(); | ||
195 | if ((err = hpfs_chk_name((char *)name, &len))) { | ||
196 | if (err == -ENAMETOOLONG) { | ||
197 | unlock_kernel(); | ||
198 | return ERR_PTR(-ENAMETOOLONG); | ||
199 | } | ||
200 | goto end_add; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * '.' and '..' will never be passed here. | ||
205 | */ | ||
206 | |||
207 | de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *) name, len, NULL, &qbh); | ||
208 | |||
209 | /* | ||
210 | * This is not really a bailout, just means file not found. | ||
211 | */ | ||
212 | |||
213 | if (!de) goto end; | ||
214 | |||
215 | /* | ||
216 | * Get inode number, what we're after. | ||
217 | */ | ||
218 | |||
219 | ino = de->fnode; | ||
220 | |||
221 | /* | ||
222 | * Go find or make an inode. | ||
223 | */ | ||
224 | |||
225 | result = iget_locked(dir->i_sb, ino); | ||
226 | if (!result) { | ||
227 | hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode"); | ||
228 | goto bail1; | ||
229 | } | ||
230 | if (result->i_state & I_NEW) { | ||
231 | hpfs_init_inode(result); | ||
232 | if (de->directory) | ||
233 | hpfs_read_inode(result); | ||
234 | else if (de->ea_size && hpfs_sb(dir->i_sb)->sb_eas) | ||
235 | hpfs_read_inode(result); | ||
236 | else { | ||
237 | result->i_mode |= S_IFREG; | ||
238 | result->i_mode &= ~0111; | ||
239 | result->i_op = &hpfs_file_iops; | ||
240 | result->i_fop = &hpfs_file_ops; | ||
241 | result->i_nlink = 1; | ||
242 | } | ||
243 | unlock_new_inode(result); | ||
244 | } | ||
245 | hpfs_result = hpfs_i(result); | ||
246 | if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino; | ||
247 | |||
248 | hpfs_decide_conv(result, (char *)name, len); | ||
249 | |||
250 | if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) { | ||
251 | hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); | ||
252 | goto bail1; | ||
253 | } | ||
254 | |||
255 | /* | ||
256 | * Fill in the info from the directory if this is a newly created | ||
257 | * inode. | ||
258 | */ | ||
259 | |||
260 | if (!result->i_ctime.tv_sec) { | ||
261 | if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, de->creation_date))) | ||
262 | result->i_ctime.tv_sec = 1; | ||
263 | result->i_ctime.tv_nsec = 0; | ||
264 | result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, de->write_date); | ||
265 | result->i_mtime.tv_nsec = 0; | ||
266 | result->i_atime.tv_sec = local_to_gmt(dir->i_sb, de->read_date); | ||
267 | result->i_atime.tv_nsec = 0; | ||
268 | hpfs_result->i_ea_size = de->ea_size; | ||
269 | if (!hpfs_result->i_ea_mode && de->read_only) | ||
270 | result->i_mode &= ~0222; | ||
271 | if (!de->directory) { | ||
272 | if (result->i_size == -1) { | ||
273 | result->i_size = de->file_size; | ||
274 | result->i_data.a_ops = &hpfs_aops; | ||
275 | hpfs_i(result)->mmu_private = result->i_size; | ||
276 | /* | ||
277 | * i_blocks should count the fnode and any anodes. | ||
278 | * We count 1 for the fnode and don't bother about | ||
279 | * anodes -- the disk heads are on the directory band | ||
280 | * and we want them to stay there. | ||
281 | */ | ||
282 | result->i_blocks = 1 + ((result->i_size + 511) >> 9); | ||
283 | } | ||
284 | } | ||
285 | } | ||
286 | |||
287 | hpfs_brelse4(&qbh); | ||
288 | |||
289 | /* | ||
290 | * Made it. | ||
291 | */ | ||
292 | |||
293 | end: | ||
294 | end_add: | ||
295 | hpfs_set_dentry_operations(dentry); | ||
296 | unlock_kernel(); | ||
297 | d_add(dentry, result); | ||
298 | return NULL; | ||
299 | |||
300 | /* | ||
301 | * Didn't. | ||
302 | */ | ||
303 | bail1: | ||
304 | |||
305 | hpfs_brelse4(&qbh); | ||
306 | |||
307 | /*bail:*/ | ||
308 | |||
309 | unlock_kernel(); | ||
310 | return ERR_PTR(-ENOENT); | ||
311 | } | ||
312 | |||
313 | struct file_operations hpfs_dir_ops = | ||
314 | { | ||
315 | .llseek = hpfs_dir_lseek, | ||
316 | .read = generic_read_dir, | ||
317 | .readdir = hpfs_readdir, | ||
318 | .release = hpfs_dir_release, | ||
319 | .fsync = hpfs_file_fsync, | ||
320 | }; | ||
diff --git a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c new file mode 100644 index 000000000000..1d21307730a8 --- /dev/null +++ b/fs/hpfs/dnode.c | |||
@@ -0,0 +1,1080 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/dnode.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * handling directory dnode tree - adding, deleteing & searching for dirents | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | static loff_t get_pos(struct dnode *d, struct hpfs_dirent *fde) | ||
12 | { | ||
13 | struct hpfs_dirent *de; | ||
14 | struct hpfs_dirent *de_end = dnode_end_de(d); | ||
15 | int i = 1; | ||
16 | for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { | ||
17 | if (de == fde) return ((loff_t) d->self << 4) | (loff_t)i; | ||
18 | i++; | ||
19 | } | ||
20 | printk("HPFS: get_pos: not_found\n"); | ||
21 | return ((loff_t)d->self << 4) | (loff_t)1; | ||
22 | } | ||
23 | |||
24 | void hpfs_add_pos(struct inode *inode, loff_t *pos) | ||
25 | { | ||
26 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
27 | int i = 0; | ||
28 | loff_t **ppos; | ||
29 | |||
30 | if (hpfs_inode->i_rddir_off) | ||
31 | for (; hpfs_inode->i_rddir_off[i]; i++) | ||
32 | if (hpfs_inode->i_rddir_off[i] == pos) return; | ||
33 | if (!(i&0x0f)) { | ||
34 | if (!(ppos = kmalloc((i+0x11) * sizeof(loff_t*), GFP_NOFS))) { | ||
35 | printk("HPFS: out of memory for position list\n"); | ||
36 | return; | ||
37 | } | ||
38 | if (hpfs_inode->i_rddir_off) { | ||
39 | memcpy(ppos, hpfs_inode->i_rddir_off, i * sizeof(loff_t)); | ||
40 | kfree(hpfs_inode->i_rddir_off); | ||
41 | } | ||
42 | hpfs_inode->i_rddir_off = ppos; | ||
43 | } | ||
44 | hpfs_inode->i_rddir_off[i] = pos; | ||
45 | hpfs_inode->i_rddir_off[i + 1] = NULL; | ||
46 | } | ||
47 | |||
48 | void hpfs_del_pos(struct inode *inode, loff_t *pos) | ||
49 | { | ||
50 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
51 | loff_t **i, **j; | ||
52 | |||
53 | if (!hpfs_inode->i_rddir_off) goto not_f; | ||
54 | for (i = hpfs_inode->i_rddir_off; *i; i++) if (*i == pos) goto fnd; | ||
55 | goto not_f; | ||
56 | fnd: | ||
57 | for (j = i + 1; *j; j++) ; | ||
58 | *i = *(j - 1); | ||
59 | *(j - 1) = NULL; | ||
60 | if (j - 1 == hpfs_inode->i_rddir_off) { | ||
61 | kfree(hpfs_inode->i_rddir_off); | ||
62 | hpfs_inode->i_rddir_off = NULL; | ||
63 | } | ||
64 | return; | ||
65 | not_f: | ||
66 | /*printk("HPFS: warning: position pointer %p->%08x not found\n", pos, (int)*pos);*/ | ||
67 | return; | ||
68 | } | ||
69 | |||
70 | static void for_all_poss(struct inode *inode, void (*f)(loff_t *, loff_t, loff_t), | ||
71 | loff_t p1, loff_t p2) | ||
72 | { | ||
73 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
74 | loff_t **i; | ||
75 | |||
76 | if (!hpfs_inode->i_rddir_off) return; | ||
77 | for (i = hpfs_inode->i_rddir_off; *i; i++) (*f)(*i, p1, p2); | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | static void hpfs_pos_subst(loff_t *p, loff_t f, loff_t t) | ||
82 | { | ||
83 | if (*p == f) *p = t; | ||
84 | } | ||
85 | |||
86 | /*void hpfs_hpfs_pos_substd(loff_t *p, loff_t f, loff_t t) | ||
87 | { | ||
88 | if ((*p & ~0x3f) == (f & ~0x3f)) *p = (t & ~0x3f) | (*p & 0x3f); | ||
89 | }*/ | ||
90 | |||
91 | static void hpfs_pos_ins(loff_t *p, loff_t d, loff_t c) | ||
92 | { | ||
93 | if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) { | ||
94 | int n = (*p & 0x3f) + c; | ||
95 | if (n > 0x3f) printk("HPFS: hpfs_pos_ins: %08x + %d\n", (int)*p, (int)c >> 8); | ||
96 | else *p = (*p & ~0x3f) | n; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static void hpfs_pos_del(loff_t *p, loff_t d, loff_t c) | ||
101 | { | ||
102 | if ((*p & ~0x3f) == (d & ~0x3f) && (*p & 0x3f) >= (d & 0x3f)) { | ||
103 | int n = (*p & 0x3f) - c; | ||
104 | if (n < 1) printk("HPFS: hpfs_pos_ins: %08x - %d\n", (int)*p, (int)c >> 8); | ||
105 | else *p = (*p & ~0x3f) | n; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static struct hpfs_dirent *dnode_pre_last_de(struct dnode *d) | ||
110 | { | ||
111 | struct hpfs_dirent *de, *de_end, *dee = NULL, *deee = NULL; | ||
112 | de_end = dnode_end_de(d); | ||
113 | for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { | ||
114 | deee = dee; dee = de; | ||
115 | } | ||
116 | return deee; | ||
117 | } | ||
118 | |||
119 | static struct hpfs_dirent *dnode_last_de(struct dnode *d) | ||
120 | { | ||
121 | struct hpfs_dirent *de, *de_end, *dee = NULL; | ||
122 | de_end = dnode_end_de(d); | ||
123 | for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { | ||
124 | dee = de; | ||
125 | } | ||
126 | return dee; | ||
127 | } | ||
128 | |||
129 | static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno ptr) | ||
130 | { | ||
131 | struct hpfs_dirent *de; | ||
132 | if (!(de = dnode_last_de(d))) { | ||
133 | hpfs_error(s, "set_last_pointer: empty dnode %08x", d->self); | ||
134 | return; | ||
135 | } | ||
136 | if (hpfs_sb(s)->sb_chk) { | ||
137 | if (de->down) { | ||
138 | hpfs_error(s, "set_last_pointer: dnode %08x has already last pointer %08x", | ||
139 | d->self, de_down_pointer(de)); | ||
140 | return; | ||
141 | } | ||
142 | if (de->length != 32) { | ||
143 | hpfs_error(s, "set_last_pointer: bad last dirent in dnode %08x", d->self); | ||
144 | return; | ||
145 | } | ||
146 | } | ||
147 | if (ptr) { | ||
148 | if ((d->first_free += 4) > 2048) { | ||
149 | hpfs_error(s,"set_last_pointer: too long dnode %08x", d->self); | ||
150 | d->first_free -= 4; | ||
151 | return; | ||
152 | } | ||
153 | de->length = 36; | ||
154 | de->down = 1; | ||
155 | *(dnode_secno *)((char *)de + 32) = ptr; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | /* Add an entry to dnode and don't care if it grows over 2048 bytes */ | ||
160 | |||
161 | struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, unsigned char *name, | ||
162 | unsigned namelen, secno down_ptr) | ||
163 | { | ||
164 | struct hpfs_dirent *de; | ||
165 | struct hpfs_dirent *de_end = dnode_end_de(d); | ||
166 | unsigned d_size = de_size(namelen, down_ptr); | ||
167 | for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { | ||
168 | int c = hpfs_compare_names(s, name, namelen, de->name, de->namelen, de->last); | ||
169 | if (!c) { | ||
170 | hpfs_error(s, "name (%c,%d) already exists in dnode %08x", *name, namelen, d->self); | ||
171 | return NULL; | ||
172 | } | ||
173 | if (c < 0) break; | ||
174 | } | ||
175 | memmove((char *)de + d_size, de, (char *)de_end - (char *)de); | ||
176 | memset(de, 0, d_size); | ||
177 | if (down_ptr) { | ||
178 | *(int *)((char *)de + d_size - 4) = down_ptr; | ||
179 | de->down = 1; | ||
180 | } | ||
181 | de->length = d_size; | ||
182 | if (down_ptr) de->down = 1; | ||
183 | de->not_8x3 = hpfs_is_name_long(name, namelen); | ||
184 | de->namelen = namelen; | ||
185 | memcpy(de->name, name, namelen); | ||
186 | d->first_free += d_size; | ||
187 | return de; | ||
188 | } | ||
189 | |||
190 | /* Delete dirent and don't care about its subtree */ | ||
191 | |||
192 | static void hpfs_delete_de(struct super_block *s, struct dnode *d, | ||
193 | struct hpfs_dirent *de) | ||
194 | { | ||
195 | if (de->last) { | ||
196 | hpfs_error(s, "attempt to delete last dirent in dnode %08x", d->self); | ||
197 | return; | ||
198 | } | ||
199 | d->first_free -= de->length; | ||
200 | memmove(de, de_next_de(de), d->first_free + (char *)d - (char *)de); | ||
201 | } | ||
202 | |||
203 | static void fix_up_ptrs(struct super_block *s, struct dnode *d) | ||
204 | { | ||
205 | struct hpfs_dirent *de; | ||
206 | struct hpfs_dirent *de_end = dnode_end_de(d); | ||
207 | dnode_secno dno = d->self; | ||
208 | for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) | ||
209 | if (de->down) { | ||
210 | struct quad_buffer_head qbh; | ||
211 | struct dnode *dd; | ||
212 | if ((dd = hpfs_map_dnode(s, de_down_pointer(de), &qbh))) { | ||
213 | if (dd->up != dno || dd->root_dnode) { | ||
214 | dd->up = dno; | ||
215 | dd->root_dnode = 0; | ||
216 | hpfs_mark_4buffers_dirty(&qbh); | ||
217 | } | ||
218 | hpfs_brelse4(&qbh); | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | |||
223 | /* Add an entry to dnode and do dnode splitting if required */ | ||
224 | |||
225 | static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, | ||
226 | unsigned char *name, unsigned namelen, | ||
227 | struct hpfs_dirent *new_de, dnode_secno down_ptr) | ||
228 | { | ||
229 | struct quad_buffer_head qbh, qbh1, qbh2; | ||
230 | struct dnode *d, *ad, *rd, *nd = NULL; | ||
231 | dnode_secno adno, rdno; | ||
232 | struct hpfs_dirent *de; | ||
233 | struct hpfs_dirent nde; | ||
234 | char *nname; | ||
235 | int h; | ||
236 | int pos; | ||
237 | struct buffer_head *bh; | ||
238 | struct fnode *fnode; | ||
239 | int c1, c2 = 0; | ||
240 | if (!(nname = kmalloc(256, GFP_NOFS))) { | ||
241 | printk("HPFS: out of memory, can't add to dnode\n"); | ||
242 | return 1; | ||
243 | } | ||
244 | go_up: | ||
245 | if (namelen >= 256) { | ||
246 | hpfs_error(i->i_sb, "hpfs_add_to_dnode: namelen == %d", namelen); | ||
247 | if (nd) kfree(nd); | ||
248 | kfree(nname); | ||
249 | return 1; | ||
250 | } | ||
251 | if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) { | ||
252 | if (nd) kfree(nd); | ||
253 | kfree(nname); | ||
254 | return 1; | ||
255 | } | ||
256 | go_up_a: | ||
257 | if (hpfs_sb(i->i_sb)->sb_chk) | ||
258 | if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_to_dnode")) { | ||
259 | hpfs_brelse4(&qbh); | ||
260 | if (nd) kfree(nd); | ||
261 | kfree(nname); | ||
262 | return 1; | ||
263 | } | ||
264 | if (d->first_free + de_size(namelen, down_ptr) <= 2048) { | ||
265 | loff_t t; | ||
266 | copy_de(de=hpfs_add_de(i->i_sb, d, name, namelen, down_ptr), new_de); | ||
267 | t = get_pos(d, de); | ||
268 | for_all_poss(i, hpfs_pos_ins, t, 1); | ||
269 | for_all_poss(i, hpfs_pos_subst, 4, t); | ||
270 | for_all_poss(i, hpfs_pos_subst, 5, t + 1); | ||
271 | hpfs_mark_4buffers_dirty(&qbh); | ||
272 | hpfs_brelse4(&qbh); | ||
273 | if (nd) kfree(nd); | ||
274 | kfree(nname); | ||
275 | return 0; | ||
276 | } | ||
277 | if (!nd) if (!(nd = kmalloc(0x924, GFP_NOFS))) { | ||
278 | /* 0x924 is a max size of dnode after adding a dirent with | ||
279 | max name length. We alloc this only once. There must | ||
280 | not be any error while splitting dnodes, otherwise the | ||
281 | whole directory, not only file we're adding, would | ||
282 | be lost. */ | ||
283 | printk("HPFS: out of memory for dnode splitting\n"); | ||
284 | hpfs_brelse4(&qbh); | ||
285 | kfree(nname); | ||
286 | return 1; | ||
287 | } | ||
288 | memcpy(nd, d, d->first_free); | ||
289 | copy_de(de = hpfs_add_de(i->i_sb, nd, name, namelen, down_ptr), new_de); | ||
290 | for_all_poss(i, hpfs_pos_ins, get_pos(nd, de), 1); | ||
291 | h = ((char *)dnode_last_de(nd) - (char *)nd) / 2 + 10; | ||
292 | if (!(ad = hpfs_alloc_dnode(i->i_sb, d->up, &adno, &qbh1, 0))) { | ||
293 | hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); | ||
294 | hpfs_brelse4(&qbh); | ||
295 | kfree(nd); | ||
296 | kfree(nname); | ||
297 | return 1; | ||
298 | } | ||
299 | i->i_size += 2048; | ||
300 | i->i_blocks += 4; | ||
301 | pos = 1; | ||
302 | for (de = dnode_first_de(nd); (char *)de_next_de(de) - (char *)nd < h; de = de_next_de(de)) { | ||
303 | copy_de(hpfs_add_de(i->i_sb, ad, de->name, de->namelen, de->down ? de_down_pointer(de) : 0), de); | ||
304 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, ((loff_t)adno << 4) | pos); | ||
305 | pos++; | ||
306 | } | ||
307 | copy_de(new_de = &nde, de); | ||
308 | memcpy(name = nname, de->name, namelen = de->namelen); | ||
309 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4); | ||
310 | down_ptr = adno; | ||
311 | set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); | ||
312 | de = de_next_de(de); | ||
313 | memmove((char *)nd + 20, de, nd->first_free + (char *)nd - (char *)de); | ||
314 | nd->first_free -= (char *)de - (char *)nd - 20; | ||
315 | memcpy(d, nd, nd->first_free); | ||
316 | for_all_poss(i, hpfs_pos_del, (loff_t)dno << 4, pos); | ||
317 | fix_up_ptrs(i->i_sb, ad); | ||
318 | if (!d->root_dnode) { | ||
319 | dno = ad->up = d->up; | ||
320 | hpfs_mark_4buffers_dirty(&qbh); | ||
321 | hpfs_brelse4(&qbh); | ||
322 | hpfs_mark_4buffers_dirty(&qbh1); | ||
323 | hpfs_brelse4(&qbh1); | ||
324 | goto go_up; | ||
325 | } | ||
326 | if (!(rd = hpfs_alloc_dnode(i->i_sb, d->up, &rdno, &qbh2, 0))) { | ||
327 | hpfs_error(i->i_sb, "unable to alloc dnode - dnode tree will be corrupted"); | ||
328 | hpfs_brelse4(&qbh); | ||
329 | hpfs_brelse4(&qbh1); | ||
330 | kfree(nd); | ||
331 | kfree(nname); | ||
332 | return 1; | ||
333 | } | ||
334 | i->i_size += 2048; | ||
335 | i->i_blocks += 4; | ||
336 | rd->root_dnode = 1; | ||
337 | rd->up = d->up; | ||
338 | if (!(fnode = hpfs_map_fnode(i->i_sb, d->up, &bh))) { | ||
339 | hpfs_free_dnode(i->i_sb, rdno); | ||
340 | hpfs_brelse4(&qbh); | ||
341 | hpfs_brelse4(&qbh1); | ||
342 | hpfs_brelse4(&qbh2); | ||
343 | kfree(nd); | ||
344 | kfree(nname); | ||
345 | return 1; | ||
346 | } | ||
347 | fnode->u.external[0].disk_secno = rdno; | ||
348 | mark_buffer_dirty(bh); | ||
349 | brelse(bh); | ||
350 | d->up = ad->up = hpfs_i(i)->i_dno = rdno; | ||
351 | d->root_dnode = ad->root_dnode = 0; | ||
352 | hpfs_mark_4buffers_dirty(&qbh); | ||
353 | hpfs_brelse4(&qbh); | ||
354 | hpfs_mark_4buffers_dirty(&qbh1); | ||
355 | hpfs_brelse4(&qbh1); | ||
356 | qbh = qbh2; | ||
357 | set_last_pointer(i->i_sb, rd, dno); | ||
358 | dno = rdno; | ||
359 | d = rd; | ||
360 | goto go_up_a; | ||
361 | } | ||
362 | |||
363 | /* | ||
364 | * Add an entry to directory btree. | ||
365 | * I hate such crazy directory structure. | ||
366 | * It's easy to read but terrible to write. | ||
367 | * I wrote this directory code 4 times. | ||
368 | * I hope, now it's finally bug-free. | ||
369 | */ | ||
370 | |||
371 | int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen, | ||
372 | struct hpfs_dirent *new_de, int cdepth) | ||
373 | { | ||
374 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
375 | struct dnode *d; | ||
376 | struct hpfs_dirent *de, *de_end; | ||
377 | struct quad_buffer_head qbh; | ||
378 | dnode_secno dno; | ||
379 | int c; | ||
380 | int c1, c2 = 0; | ||
381 | dno = hpfs_inode->i_dno; | ||
382 | down: | ||
383 | if (hpfs_sb(i->i_sb)->sb_chk) | ||
384 | if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "hpfs_add_dirent")) return 1; | ||
385 | if (!(d = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 1; | ||
386 | de_end = dnode_end_de(d); | ||
387 | for (de = dnode_first_de(d); de < de_end; de = de_next_de(de)) { | ||
388 | if (!(c = hpfs_compare_names(i->i_sb, name, namelen, de->name, de->namelen, de->last))) { | ||
389 | hpfs_brelse4(&qbh); | ||
390 | return -1; | ||
391 | } | ||
392 | if (c < 0) { | ||
393 | if (de->down) { | ||
394 | dno = de_down_pointer(de); | ||
395 | hpfs_brelse4(&qbh); | ||
396 | goto down; | ||
397 | } | ||
398 | break; | ||
399 | } | ||
400 | } | ||
401 | hpfs_brelse4(&qbh); | ||
402 | if (!cdepth) hpfs_lock_creation(i->i_sb); | ||
403 | if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_ADD)) { | ||
404 | c = 1; | ||
405 | goto ret; | ||
406 | } | ||
407 | i->i_version++; | ||
408 | c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0); | ||
409 | ret: | ||
410 | if (!cdepth) hpfs_unlock_creation(i->i_sb); | ||
411 | return c; | ||
412 | } | ||
413 | |||
414 | /* | ||
415 | * Find dirent with higher name in 'from' subtree and move it to 'to' dnode. | ||
416 | * Return the dnode we moved from (to be checked later if it's empty) | ||
417 | */ | ||
418 | |||
419 | static secno move_to_top(struct inode *i, dnode_secno from, dnode_secno to) | ||
420 | { | ||
421 | dnode_secno dno, ddno; | ||
422 | dnode_secno chk_up = to; | ||
423 | struct dnode *dnode; | ||
424 | struct quad_buffer_head qbh; | ||
425 | struct hpfs_dirent *de, *nde; | ||
426 | int a; | ||
427 | loff_t t; | ||
428 | int c1, c2 = 0; | ||
429 | dno = from; | ||
430 | while (1) { | ||
431 | if (hpfs_sb(i->i_sb)->sb_chk) | ||
432 | if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "move_to_top")) | ||
433 | return 0; | ||
434 | if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return 0; | ||
435 | if (hpfs_sb(i->i_sb)->sb_chk) { | ||
436 | if (dnode->up != chk_up) { | ||
437 | hpfs_error(i->i_sb, "move_to_top: up pointer from %08x should be %08x, is %08x", | ||
438 | dno, chk_up, dnode->up); | ||
439 | hpfs_brelse4(&qbh); | ||
440 | return 0; | ||
441 | } | ||
442 | chk_up = dno; | ||
443 | } | ||
444 | if (!(de = dnode_last_de(dnode))) { | ||
445 | hpfs_error(i->i_sb, "move_to_top: dnode %08x has no last de", dno); | ||
446 | hpfs_brelse4(&qbh); | ||
447 | return 0; | ||
448 | } | ||
449 | if (!de->down) break; | ||
450 | dno = de_down_pointer(de); | ||
451 | hpfs_brelse4(&qbh); | ||
452 | } | ||
453 | while (!(de = dnode_pre_last_de(dnode))) { | ||
454 | dnode_secno up = dnode->up; | ||
455 | hpfs_brelse4(&qbh); | ||
456 | hpfs_free_dnode(i->i_sb, dno); | ||
457 | i->i_size -= 2048; | ||
458 | i->i_blocks -= 4; | ||
459 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, 5); | ||
460 | if (up == to) return to; | ||
461 | if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return 0; | ||
462 | if (dnode->root_dnode) { | ||
463 | hpfs_error(i->i_sb, "move_to_top: got to root_dnode while moving from %08x to %08x", from, to); | ||
464 | hpfs_brelse4(&qbh); | ||
465 | return 0; | ||
466 | } | ||
467 | de = dnode_last_de(dnode); | ||
468 | if (!de || !de->down) { | ||
469 | hpfs_error(i->i_sb, "move_to_top: dnode %08x doesn't point down to %08x", up, dno); | ||
470 | hpfs_brelse4(&qbh); | ||
471 | return 0; | ||
472 | } | ||
473 | dnode->first_free -= 4; | ||
474 | de->length -= 4; | ||
475 | de->down = 0; | ||
476 | hpfs_mark_4buffers_dirty(&qbh); | ||
477 | dno = up; | ||
478 | } | ||
479 | t = get_pos(dnode, de); | ||
480 | for_all_poss(i, hpfs_pos_subst, t, 4); | ||
481 | for_all_poss(i, hpfs_pos_subst, t + 1, 5); | ||
482 | if (!(nde = kmalloc(de->length, GFP_NOFS))) { | ||
483 | hpfs_error(i->i_sb, "out of memory for dirent - directory will be corrupted"); | ||
484 | hpfs_brelse4(&qbh); | ||
485 | return 0; | ||
486 | } | ||
487 | memcpy(nde, de, de->length); | ||
488 | ddno = de->down ? de_down_pointer(de) : 0; | ||
489 | hpfs_delete_de(i->i_sb, dnode, de); | ||
490 | set_last_pointer(i->i_sb, dnode, ddno); | ||
491 | hpfs_mark_4buffers_dirty(&qbh); | ||
492 | hpfs_brelse4(&qbh); | ||
493 | a = hpfs_add_to_dnode(i, to, nde->name, nde->namelen, nde, from); | ||
494 | kfree(nde); | ||
495 | if (a) return 0; | ||
496 | return dno; | ||
497 | } | ||
498 | |||
499 | /* | ||
500 | * Check if a dnode is empty and delete it from the tree | ||
501 | * (chkdsk doesn't like empty dnodes) | ||
502 | */ | ||
503 | |||
504 | static void delete_empty_dnode(struct inode *i, dnode_secno dno) | ||
505 | { | ||
506 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
507 | struct quad_buffer_head qbh; | ||
508 | struct dnode *dnode; | ||
509 | dnode_secno down, up, ndown; | ||
510 | int p; | ||
511 | struct hpfs_dirent *de; | ||
512 | int c1, c2 = 0; | ||
513 | try_it_again: | ||
514 | if (hpfs_stop_cycles(i->i_sb, dno, &c1, &c2, "delete_empty_dnode")) return; | ||
515 | if (!(dnode = hpfs_map_dnode(i->i_sb, dno, &qbh))) return; | ||
516 | if (dnode->first_free > 56) goto end; | ||
517 | if (dnode->first_free == 52 || dnode->first_free == 56) { | ||
518 | struct hpfs_dirent *de_end; | ||
519 | int root = dnode->root_dnode; | ||
520 | up = dnode->up; | ||
521 | de = dnode_first_de(dnode); | ||
522 | down = de->down ? de_down_pointer(de) : 0; | ||
523 | if (hpfs_sb(i->i_sb)->sb_chk) if (root && !down) { | ||
524 | hpfs_error(i->i_sb, "delete_empty_dnode: root dnode %08x is empty", dno); | ||
525 | goto end; | ||
526 | } | ||
527 | hpfs_brelse4(&qbh); | ||
528 | hpfs_free_dnode(i->i_sb, dno); | ||
529 | i->i_size -= 2048; | ||
530 | i->i_blocks -= 4; | ||
531 | if (root) { | ||
532 | struct fnode *fnode; | ||
533 | struct buffer_head *bh; | ||
534 | struct dnode *d1; | ||
535 | struct quad_buffer_head qbh1; | ||
536 | if (hpfs_sb(i->i_sb)->sb_chk) if (up != i->i_ino) { | ||
537 | hpfs_error(i->i_sb, "bad pointer to fnode, dnode %08x, pointing to %08x, should be %08x", dno, up, i->i_ino); | ||
538 | return; | ||
539 | } | ||
540 | if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { | ||
541 | d1->up = up; | ||
542 | d1->root_dnode = 1; | ||
543 | hpfs_mark_4buffers_dirty(&qbh1); | ||
544 | hpfs_brelse4(&qbh1); | ||
545 | } | ||
546 | if ((fnode = hpfs_map_fnode(i->i_sb, up, &bh))) { | ||
547 | fnode->u.external[0].disk_secno = down; | ||
548 | mark_buffer_dirty(bh); | ||
549 | brelse(bh); | ||
550 | } | ||
551 | hpfs_inode->i_dno = down; | ||
552 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, (loff_t) 12); | ||
553 | return; | ||
554 | } | ||
555 | if (!(dnode = hpfs_map_dnode(i->i_sb, up, &qbh))) return; | ||
556 | p = 1; | ||
557 | de_end = dnode_end_de(dnode); | ||
558 | for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de), p++) | ||
559 | if (de->down) if (de_down_pointer(de) == dno) goto fnd; | ||
560 | hpfs_error(i->i_sb, "delete_empty_dnode: pointer to dnode %08x not found in dnode %08x", dno, up); | ||
561 | goto end; | ||
562 | fnd: | ||
563 | for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | 1, ((loff_t)up << 4) | p); | ||
564 | if (!down) { | ||
565 | de->down = 0; | ||
566 | de->length -= 4; | ||
567 | dnode->first_free -= 4; | ||
568 | memmove(de_next_de(de), (char *)de_next_de(de) + 4, | ||
569 | (char *)dnode + dnode->first_free - (char *)de_next_de(de)); | ||
570 | } else { | ||
571 | struct dnode *d1; | ||
572 | struct quad_buffer_head qbh1; | ||
573 | *(dnode_secno *) ((void *) de + de->length - 4) = down; | ||
574 | if ((d1 = hpfs_map_dnode(i->i_sb, down, &qbh1))) { | ||
575 | d1->up = up; | ||
576 | hpfs_mark_4buffers_dirty(&qbh1); | ||
577 | hpfs_brelse4(&qbh1); | ||
578 | } | ||
579 | } | ||
580 | } else { | ||
581 | hpfs_error(i->i_sb, "delete_empty_dnode: dnode %08x, first_free == %03x", dno, dnode->first_free); | ||
582 | goto end; | ||
583 | } | ||
584 | |||
585 | if (!de->last) { | ||
586 | struct hpfs_dirent *de_next = de_next_de(de); | ||
587 | struct hpfs_dirent *de_cp; | ||
588 | struct dnode *d1; | ||
589 | struct quad_buffer_head qbh1; | ||
590 | if (!de_next->down) goto endm; | ||
591 | ndown = de_down_pointer(de_next); | ||
592 | if (!(de_cp = kmalloc(de->length, GFP_NOFS))) { | ||
593 | printk("HPFS: out of memory for dtree balancing\n"); | ||
594 | goto endm; | ||
595 | } | ||
596 | memcpy(de_cp, de, de->length); | ||
597 | hpfs_delete_de(i->i_sb, dnode, de); | ||
598 | hpfs_mark_4buffers_dirty(&qbh); | ||
599 | hpfs_brelse4(&qbh); | ||
600 | for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, 4); | ||
601 | for_all_poss(i, hpfs_pos_del, ((loff_t)up << 4) | p, 1); | ||
602 | if (de_cp->down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de_cp), &qbh1))) { | ||
603 | d1->up = ndown; | ||
604 | hpfs_mark_4buffers_dirty(&qbh1); | ||
605 | hpfs_brelse4(&qbh1); | ||
606 | } | ||
607 | hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, de_cp->down ? de_down_pointer(de_cp) : 0); | ||
608 | /*printk("UP-TO-DNODE: %08x (ndown = %08x, down = %08x, dno = %08x)\n", up, ndown, down, dno);*/ | ||
609 | dno = up; | ||
610 | kfree(de_cp); | ||
611 | goto try_it_again; | ||
612 | } else { | ||
613 | struct hpfs_dirent *de_prev = dnode_pre_last_de(dnode); | ||
614 | struct hpfs_dirent *de_cp; | ||
615 | struct dnode *d1; | ||
616 | struct quad_buffer_head qbh1; | ||
617 | dnode_secno dlp; | ||
618 | if (!de_prev) { | ||
619 | hpfs_error(i->i_sb, "delete_empty_dnode: empty dnode %08x", up); | ||
620 | hpfs_mark_4buffers_dirty(&qbh); | ||
621 | hpfs_brelse4(&qbh); | ||
622 | dno = up; | ||
623 | goto try_it_again; | ||
624 | } | ||
625 | if (!de_prev->down) goto endm; | ||
626 | ndown = de_down_pointer(de_prev); | ||
627 | if ((d1 = hpfs_map_dnode(i->i_sb, ndown, &qbh1))) { | ||
628 | struct hpfs_dirent *del = dnode_last_de(d1); | ||
629 | dlp = del->down ? de_down_pointer(del) : 0; | ||
630 | if (!dlp && down) { | ||
631 | if (d1->first_free > 2044) { | ||
632 | if (hpfs_sb(i->i_sb)->sb_chk >= 2) { | ||
633 | printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); | ||
634 | printk("HPFS: warning: terminating balancing operation\n"); | ||
635 | } | ||
636 | hpfs_brelse4(&qbh1); | ||
637 | goto endm; | ||
638 | } | ||
639 | if (hpfs_sb(i->i_sb)->sb_chk >= 2) { | ||
640 | printk("HPFS: warning: unbalanced dnode tree, see hpfs.txt 4 more info\n"); | ||
641 | printk("HPFS: warning: goin'on\n"); | ||
642 | } | ||
643 | del->length += 4; | ||
644 | del->down = 1; | ||
645 | d1->first_free += 4; | ||
646 | } | ||
647 | if (dlp && !down) { | ||
648 | del->length -= 4; | ||
649 | del->down = 0; | ||
650 | d1->first_free -= 4; | ||
651 | } else if (down) | ||
652 | *(dnode_secno *) ((void *) del + del->length - 4) = down; | ||
653 | } else goto endm; | ||
654 | if (!(de_cp = kmalloc(de_prev->length, GFP_NOFS))) { | ||
655 | printk("HPFS: out of memory for dtree balancing\n"); | ||
656 | hpfs_brelse4(&qbh1); | ||
657 | goto endm; | ||
658 | } | ||
659 | hpfs_mark_4buffers_dirty(&qbh1); | ||
660 | hpfs_brelse4(&qbh1); | ||
661 | memcpy(de_cp, de_prev, de_prev->length); | ||
662 | hpfs_delete_de(i->i_sb, dnode, de_prev); | ||
663 | if (!de_prev->down) { | ||
664 | de_prev->length += 4; | ||
665 | de_prev->down = 1; | ||
666 | dnode->first_free += 4; | ||
667 | } | ||
668 | *(dnode_secno *) ((void *) de_prev + de_prev->length - 4) = ndown; | ||
669 | hpfs_mark_4buffers_dirty(&qbh); | ||
670 | hpfs_brelse4(&qbh); | ||
671 | for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | (p - 1), 4); | ||
672 | for_all_poss(i, hpfs_pos_subst, ((loff_t)up << 4) | p, ((loff_t)up << 4) | (p - 1)); | ||
673 | if (down) if ((d1 = hpfs_map_dnode(i->i_sb, de_down_pointer(de), &qbh1))) { | ||
674 | d1->up = ndown; | ||
675 | hpfs_mark_4buffers_dirty(&qbh1); | ||
676 | hpfs_brelse4(&qbh1); | ||
677 | } | ||
678 | hpfs_add_to_dnode(i, ndown, de_cp->name, de_cp->namelen, de_cp, dlp); | ||
679 | dno = up; | ||
680 | kfree(de_cp); | ||
681 | goto try_it_again; | ||
682 | } | ||
683 | endm: | ||
684 | hpfs_mark_4buffers_dirty(&qbh); | ||
685 | end: | ||
686 | hpfs_brelse4(&qbh); | ||
687 | } | ||
688 | |||
689 | |||
690 | /* Delete dirent from directory */ | ||
691 | |||
692 | int hpfs_remove_dirent(struct inode *i, dnode_secno dno, struct hpfs_dirent *de, | ||
693 | struct quad_buffer_head *qbh, int depth) | ||
694 | { | ||
695 | struct dnode *dnode = qbh->data; | ||
696 | dnode_secno down = 0; | ||
697 | int lock = 0; | ||
698 | loff_t t; | ||
699 | if (de->first || de->last) { | ||
700 | hpfs_error(i->i_sb, "hpfs_remove_dirent: attempt to delete first or last dirent in dnode %08x", dno); | ||
701 | hpfs_brelse4(qbh); | ||
702 | return 1; | ||
703 | } | ||
704 | if (de->down) down = de_down_pointer(de); | ||
705 | if (depth && (de->down || (de == dnode_first_de(dnode) && de_next_de(de)->last))) { | ||
706 | lock = 1; | ||
707 | hpfs_lock_creation(i->i_sb); | ||
708 | if (hpfs_check_free_dnodes(i->i_sb, FREE_DNODES_DEL)) { | ||
709 | hpfs_brelse4(qbh); | ||
710 | hpfs_unlock_creation(i->i_sb); | ||
711 | return 2; | ||
712 | } | ||
713 | } | ||
714 | i->i_version++; | ||
715 | for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1); | ||
716 | hpfs_delete_de(i->i_sb, dnode, de); | ||
717 | hpfs_mark_4buffers_dirty(qbh); | ||
718 | hpfs_brelse4(qbh); | ||
719 | if (down) { | ||
720 | dnode_secno a = move_to_top(i, down, dno); | ||
721 | for_all_poss(i, hpfs_pos_subst, 5, t); | ||
722 | if (a) delete_empty_dnode(i, a); | ||
723 | if (lock) hpfs_unlock_creation(i->i_sb); | ||
724 | return !a; | ||
725 | } | ||
726 | delete_empty_dnode(i, dno); | ||
727 | if (lock) hpfs_unlock_creation(i->i_sb); | ||
728 | return 0; | ||
729 | } | ||
730 | |||
731 | void hpfs_count_dnodes(struct super_block *s, dnode_secno dno, int *n_dnodes, | ||
732 | int *n_subdirs, int *n_items) | ||
733 | { | ||
734 | struct dnode *dnode; | ||
735 | struct quad_buffer_head qbh; | ||
736 | struct hpfs_dirent *de; | ||
737 | dnode_secno ptr, odno = 0; | ||
738 | int c1, c2 = 0; | ||
739 | int d1, d2 = 0; | ||
740 | go_down: | ||
741 | if (n_dnodes) (*n_dnodes)++; | ||
742 | if (hpfs_sb(s)->sb_chk) | ||
743 | if (hpfs_stop_cycles(s, dno, &c1, &c2, "hpfs_count_dnodes #1")) return; | ||
744 | ptr = 0; | ||
745 | go_up: | ||
746 | if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; | ||
747 | if (hpfs_sb(s)->sb_chk) if (odno && odno != -1 && dnode->up != odno) | ||
748 | hpfs_error(s, "hpfs_count_dnodes: bad up pointer; dnode %08x, down %08x points to %08x", odno, dno, dnode->up); | ||
749 | de = dnode_first_de(dnode); | ||
750 | if (ptr) while(1) { | ||
751 | if (de->down) if (de_down_pointer(de) == ptr) goto process_de; | ||
752 | if (de->last) { | ||
753 | hpfs_brelse4(&qbh); | ||
754 | hpfs_error(s, "hpfs_count_dnodes: pointer to dnode %08x not found in dnode %08x, got here from %08x", | ||
755 | ptr, dno, odno); | ||
756 | return; | ||
757 | } | ||
758 | de = de_next_de(de); | ||
759 | } | ||
760 | next_de: | ||
761 | if (de->down) { | ||
762 | odno = dno; | ||
763 | dno = de_down_pointer(de); | ||
764 | hpfs_brelse4(&qbh); | ||
765 | goto go_down; | ||
766 | } | ||
767 | process_de: | ||
768 | if (!de->first && !de->last && de->directory && n_subdirs) (*n_subdirs)++; | ||
769 | if (!de->first && !de->last && n_items) (*n_items)++; | ||
770 | if ((de = de_next_de(de)) < dnode_end_de(dnode)) goto next_de; | ||
771 | ptr = dno; | ||
772 | dno = dnode->up; | ||
773 | if (dnode->root_dnode) { | ||
774 | hpfs_brelse4(&qbh); | ||
775 | return; | ||
776 | } | ||
777 | hpfs_brelse4(&qbh); | ||
778 | if (hpfs_sb(s)->sb_chk) | ||
779 | if (hpfs_stop_cycles(s, ptr, &d1, &d2, "hpfs_count_dnodes #2")) return; | ||
780 | odno = -1; | ||
781 | goto go_up; | ||
782 | } | ||
783 | |||
784 | static struct hpfs_dirent *map_nth_dirent(struct super_block *s, dnode_secno dno, int n, | ||
785 | struct quad_buffer_head *qbh, struct dnode **dn) | ||
786 | { | ||
787 | int i; | ||
788 | struct hpfs_dirent *de, *de_end; | ||
789 | struct dnode *dnode; | ||
790 | dnode = hpfs_map_dnode(s, dno, qbh); | ||
791 | if (!dnode) return NULL; | ||
792 | if (dn) *dn=dnode; | ||
793 | de = dnode_first_de(dnode); | ||
794 | de_end = dnode_end_de(dnode); | ||
795 | for (i = 1; de < de_end; i++, de = de_next_de(de)) { | ||
796 | if (i == n) { | ||
797 | return de; | ||
798 | } | ||
799 | if (de->last) break; | ||
800 | } | ||
801 | hpfs_brelse4(qbh); | ||
802 | hpfs_error(s, "map_nth_dirent: n too high; dnode = %08x, requested %08x", dno, n); | ||
803 | return NULL; | ||
804 | } | ||
805 | |||
806 | dnode_secno hpfs_de_as_down_as_possible(struct super_block *s, dnode_secno dno) | ||
807 | { | ||
808 | struct quad_buffer_head qbh; | ||
809 | dnode_secno d = dno; | ||
810 | dnode_secno up = 0; | ||
811 | struct hpfs_dirent *de; | ||
812 | int c1, c2 = 0; | ||
813 | |||
814 | again: | ||
815 | if (hpfs_sb(s)->sb_chk) | ||
816 | if (hpfs_stop_cycles(s, d, &c1, &c2, "hpfs_de_as_down_as_possible")) | ||
817 | return d; | ||
818 | if (!(de = map_nth_dirent(s, d, 1, &qbh, NULL))) return dno; | ||
819 | if (hpfs_sb(s)->sb_chk) | ||
820 | if (up && ((struct dnode *)qbh.data)->up != up) | ||
821 | hpfs_error(s, "hpfs_de_as_down_as_possible: bad up pointer; dnode %08x, down %08x points to %08x", up, d, ((struct dnode *)qbh.data)->up); | ||
822 | if (!de->down) { | ||
823 | hpfs_brelse4(&qbh); | ||
824 | return d; | ||
825 | } | ||
826 | up = d; | ||
827 | d = de_down_pointer(de); | ||
828 | hpfs_brelse4(&qbh); | ||
829 | goto again; | ||
830 | } | ||
831 | |||
832 | struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp, | ||
833 | struct quad_buffer_head *qbh) | ||
834 | { | ||
835 | loff_t pos; | ||
836 | unsigned c; | ||
837 | dnode_secno dno; | ||
838 | struct hpfs_dirent *de, *d; | ||
839 | struct hpfs_dirent *up_de; | ||
840 | struct hpfs_dirent *end_up_de; | ||
841 | struct dnode *dnode; | ||
842 | struct dnode *up_dnode; | ||
843 | struct quad_buffer_head qbh0; | ||
844 | |||
845 | pos = *posp; | ||
846 | dno = pos >> 6 << 2; | ||
847 | pos &= 077; | ||
848 | if (!(de = map_nth_dirent(inode->i_sb, dno, pos, qbh, &dnode))) | ||
849 | goto bail; | ||
850 | |||
851 | /* Going to the next dirent */ | ||
852 | if ((d = de_next_de(de)) < dnode_end_de(dnode)) { | ||
853 | if (!(++*posp & 077)) { | ||
854 | hpfs_error(inode->i_sb, "map_pos_dirent: pos crossed dnode boundary; pos = %08x", *posp); | ||
855 | goto bail; | ||
856 | } | ||
857 | /* We're going down the tree */ | ||
858 | if (d->down) { | ||
859 | *posp = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, de_down_pointer(d)) << 4) + 1; | ||
860 | } | ||
861 | |||
862 | return de; | ||
863 | } | ||
864 | |||
865 | /* Going up */ | ||
866 | if (dnode->root_dnode) goto bail; | ||
867 | |||
868 | if (!(up_dnode = hpfs_map_dnode(inode->i_sb, dnode->up, &qbh0))) | ||
869 | goto bail; | ||
870 | |||
871 | end_up_de = dnode_end_de(up_dnode); | ||
872 | c = 0; | ||
873 | for (up_de = dnode_first_de(up_dnode); up_de < end_up_de; | ||
874 | up_de = de_next_de(up_de)) { | ||
875 | if (!(++c & 077)) hpfs_error(inode->i_sb, | ||
876 | "map_pos_dirent: pos crossed dnode boundary; dnode = %08x", dnode->up); | ||
877 | if (up_de->down && de_down_pointer(up_de) == dno) { | ||
878 | *posp = ((loff_t) dnode->up << 4) + c; | ||
879 | hpfs_brelse4(&qbh0); | ||
880 | return de; | ||
881 | } | ||
882 | } | ||
883 | |||
884 | hpfs_error(inode->i_sb, "map_pos_dirent: pointer to dnode %08x not found in parent dnode %08x", | ||
885 | dno, dnode->up); | ||
886 | hpfs_brelse4(&qbh0); | ||
887 | |||
888 | bail: | ||
889 | *posp = 12; | ||
890 | return de; | ||
891 | } | ||
892 | |||
893 | /* Find a dirent in tree */ | ||
894 | |||
895 | struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, char *name, unsigned len, | ||
896 | dnode_secno *dd, struct quad_buffer_head *qbh) | ||
897 | { | ||
898 | struct dnode *dnode; | ||
899 | struct hpfs_dirent *de; | ||
900 | struct hpfs_dirent *de_end; | ||
901 | int c1, c2 = 0; | ||
902 | |||
903 | if (!S_ISDIR(inode->i_mode)) hpfs_error(inode->i_sb, "map_dirent: not a directory\n"); | ||
904 | again: | ||
905 | if (hpfs_sb(inode->i_sb)->sb_chk) | ||
906 | if (hpfs_stop_cycles(inode->i_sb, dno, &c1, &c2, "map_dirent")) return NULL; | ||
907 | if (!(dnode = hpfs_map_dnode(inode->i_sb, dno, qbh))) return NULL; | ||
908 | |||
909 | de_end = dnode_end_de(dnode); | ||
910 | for (de = dnode_first_de(dnode); de < de_end; de = de_next_de(de)) { | ||
911 | int t = hpfs_compare_names(inode->i_sb, name, len, de->name, de->namelen, de->last); | ||
912 | if (!t) { | ||
913 | if (dd) *dd = dno; | ||
914 | return de; | ||
915 | } | ||
916 | if (t < 0) { | ||
917 | if (de->down) { | ||
918 | dno = de_down_pointer(de); | ||
919 | hpfs_brelse4(qbh); | ||
920 | goto again; | ||
921 | } | ||
922 | break; | ||
923 | } | ||
924 | } | ||
925 | hpfs_brelse4(qbh); | ||
926 | return NULL; | ||
927 | } | ||
928 | |||
929 | /* | ||
930 | * Remove empty directory. In normal cases it is only one dnode with two | ||
931 | * entries, but we must handle also such obscure cases when it's a tree | ||
932 | * of empty dnodes. | ||
933 | */ | ||
934 | |||
935 | void hpfs_remove_dtree(struct super_block *s, dnode_secno dno) | ||
936 | { | ||
937 | struct quad_buffer_head qbh; | ||
938 | struct dnode *dnode; | ||
939 | struct hpfs_dirent *de; | ||
940 | dnode_secno d1, d2, rdno = dno; | ||
941 | while (1) { | ||
942 | if (!(dnode = hpfs_map_dnode(s, dno, &qbh))) return; | ||
943 | de = dnode_first_de(dnode); | ||
944 | if (de->last) { | ||
945 | if (de->down) d1 = de_down_pointer(de); | ||
946 | else goto error; | ||
947 | hpfs_brelse4(&qbh); | ||
948 | hpfs_free_dnode(s, dno); | ||
949 | dno = d1; | ||
950 | } else break; | ||
951 | } | ||
952 | if (!de->first) goto error; | ||
953 | d1 = de->down ? de_down_pointer(de) : 0; | ||
954 | de = de_next_de(de); | ||
955 | if (!de->last) goto error; | ||
956 | d2 = de->down ? de_down_pointer(de) : 0; | ||
957 | hpfs_brelse4(&qbh); | ||
958 | hpfs_free_dnode(s, dno); | ||
959 | do { | ||
960 | while (d1) { | ||
961 | if (!(dnode = hpfs_map_dnode(s, dno = d1, &qbh))) return; | ||
962 | de = dnode_first_de(dnode); | ||
963 | if (!de->last) goto error; | ||
964 | d1 = de->down ? de_down_pointer(de) : 0; | ||
965 | hpfs_brelse4(&qbh); | ||
966 | hpfs_free_dnode(s, dno); | ||
967 | } | ||
968 | d1 = d2; | ||
969 | d2 = 0; | ||
970 | } while (d1); | ||
971 | return; | ||
972 | error: | ||
973 | hpfs_brelse4(&qbh); | ||
974 | hpfs_free_dnode(s, dno); | ||
975 | hpfs_error(s, "directory %08x is corrupted or not empty", rdno); | ||
976 | } | ||
977 | |||
978 | /* | ||
979 | * Find dirent for specified fnode. Use truncated 15-char name in fnode as | ||
980 | * a help for searching. | ||
981 | */ | ||
982 | |||
983 | struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, | ||
984 | struct fnode *f, struct quad_buffer_head *qbh) | ||
985 | { | ||
986 | char *name1; | ||
987 | char *name2; | ||
988 | int name1len, name2len; | ||
989 | struct dnode *d; | ||
990 | dnode_secno dno, downd; | ||
991 | struct fnode *upf; | ||
992 | struct buffer_head *bh; | ||
993 | struct hpfs_dirent *de, *de_end; | ||
994 | int c; | ||
995 | int c1, c2 = 0; | ||
996 | int d1, d2 = 0; | ||
997 | name1 = f->name; | ||
998 | if (!(name2 = kmalloc(256, GFP_NOFS))) { | ||
999 | printk("HPFS: out of memory, can't map dirent\n"); | ||
1000 | return NULL; | ||
1001 | } | ||
1002 | if (f->len <= 15) | ||
1003 | memcpy(name2, name1, name1len = name2len = f->len); | ||
1004 | else { | ||
1005 | memcpy(name2, name1, 15); | ||
1006 | memset(name2 + 15, 0xff, 256 - 15); | ||
1007 | /*name2[15] = 0xff;*/ | ||
1008 | name1len = 15; name2len = 256; | ||
1009 | } | ||
1010 | if (!(upf = hpfs_map_fnode(s, f->up, &bh))) { | ||
1011 | kfree(name2); | ||
1012 | return NULL; | ||
1013 | } | ||
1014 | if (!upf->dirflag) { | ||
1015 | brelse(bh); | ||
1016 | hpfs_error(s, "fnode %08x has non-directory parent %08x", fno, f->up); | ||
1017 | kfree(name2); | ||
1018 | return NULL; | ||
1019 | } | ||
1020 | dno = upf->u.external[0].disk_secno; | ||
1021 | brelse(bh); | ||
1022 | go_down: | ||
1023 | downd = 0; | ||
1024 | go_up: | ||
1025 | if (!(d = hpfs_map_dnode(s, dno, qbh))) { | ||
1026 | kfree(name2); | ||
1027 | return NULL; | ||
1028 | } | ||
1029 | de_end = dnode_end_de(d); | ||
1030 | de = dnode_first_de(d); | ||
1031 | if (downd) { | ||
1032 | while (de < de_end) { | ||
1033 | if (de->down) if (de_down_pointer(de) == downd) goto f; | ||
1034 | de = de_next_de(de); | ||
1035 | } | ||
1036 | hpfs_error(s, "pointer to dnode %08x not found in dnode %08x", downd, dno); | ||
1037 | hpfs_brelse4(qbh); | ||
1038 | kfree(name2); | ||
1039 | return NULL; | ||
1040 | } | ||
1041 | next_de: | ||
1042 | if (de->fnode == fno) { | ||
1043 | kfree(name2); | ||
1044 | return de; | ||
1045 | } | ||
1046 | c = hpfs_compare_names(s, name1, name1len, de->name, de->namelen, de->last); | ||
1047 | if (c < 0 && de->down) { | ||
1048 | dno = de_down_pointer(de); | ||
1049 | hpfs_brelse4(qbh); | ||
1050 | if (hpfs_sb(s)->sb_chk) | ||
1051 | if (hpfs_stop_cycles(s, dno, &c1, &c2, "map_fnode_dirent #1")) { | ||
1052 | kfree(name2); | ||
1053 | return NULL; | ||
1054 | } | ||
1055 | goto go_down; | ||
1056 | } | ||
1057 | f: | ||
1058 | if (de->fnode == fno) { | ||
1059 | kfree(name2); | ||
1060 | return de; | ||
1061 | } | ||
1062 | c = hpfs_compare_names(s, name2, name2len, de->name, de->namelen, de->last); | ||
1063 | if (c < 0 && !de->last) goto not_found; | ||
1064 | if ((de = de_next_de(de)) < de_end) goto next_de; | ||
1065 | if (d->root_dnode) goto not_found; | ||
1066 | downd = dno; | ||
1067 | dno = d->up; | ||
1068 | hpfs_brelse4(qbh); | ||
1069 | if (hpfs_sb(s)->sb_chk) | ||
1070 | if (hpfs_stop_cycles(s, downd, &d1, &d2, "map_fnode_dirent #2")) { | ||
1071 | kfree(name2); | ||
1072 | return NULL; | ||
1073 | } | ||
1074 | goto go_up; | ||
1075 | not_found: | ||
1076 | hpfs_brelse4(qbh); | ||
1077 | hpfs_error(s, "dirent for fnode %08x not found", fno); | ||
1078 | kfree(name2); | ||
1079 | return NULL; | ||
1080 | } | ||
diff --git a/fs/hpfs/ea.c b/fs/hpfs/ea.c new file mode 100644 index 000000000000..66339dc030e4 --- /dev/null +++ b/fs/hpfs/ea.c | |||
@@ -0,0 +1,363 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/ea.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * handling extended attributes | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | /* Remove external extended attributes. ano specifies whether a is a | ||
12 | direct sector where eas starts or an anode */ | ||
13 | |||
14 | void hpfs_ea_ext_remove(struct super_block *s, secno a, int ano, unsigned len) | ||
15 | { | ||
16 | unsigned pos = 0; | ||
17 | while (pos < len) { | ||
18 | char ex[4 + 255 + 1 + 8]; | ||
19 | struct extended_attribute *ea = (struct extended_attribute *)ex; | ||
20 | if (pos + 4 > len) { | ||
21 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | ||
22 | ano ? "anode" : "sectors", a, len); | ||
23 | return; | ||
24 | } | ||
25 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; | ||
26 | if (ea->indirect) { | ||
27 | if (ea->valuelen != 8) { | ||
28 | hpfs_error(s, "ea->indirect set while ea->valuelen!=8, %s %08x, pos %08x", | ||
29 | ano ? "anode" : "sectors", a, pos); | ||
30 | return; | ||
31 | } | ||
32 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 9, ex+4)) | ||
33 | return; | ||
34 | hpfs_ea_remove(s, ea_sec(ea), ea->anode, ea_len(ea)); | ||
35 | } | ||
36 | pos += ea->namelen + ea->valuelen + 5; | ||
37 | } | ||
38 | if (!ano) hpfs_free_sectors(s, a, (len+511) >> 9); | ||
39 | else { | ||
40 | struct buffer_head *bh; | ||
41 | struct anode *anode; | ||
42 | if ((anode = hpfs_map_anode(s, a, &bh))) { | ||
43 | hpfs_remove_btree(s, &anode->btree); | ||
44 | brelse(bh); | ||
45 | hpfs_free_sectors(s, a, 1); | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | |||
50 | static char *get_indirect_ea(struct super_block *s, int ano, secno a, int size) | ||
51 | { | ||
52 | char *ret; | ||
53 | if (!(ret = kmalloc(size + 1, GFP_NOFS))) { | ||
54 | printk("HPFS: out of memory for EA\n"); | ||
55 | return NULL; | ||
56 | } | ||
57 | if (hpfs_ea_read(s, a, ano, 0, size, ret)) { | ||
58 | kfree(ret); | ||
59 | return NULL; | ||
60 | } | ||
61 | ret[size] = 0; | ||
62 | return ret; | ||
63 | } | ||
64 | |||
65 | static void set_indirect_ea(struct super_block *s, int ano, secno a, char *data, | ||
66 | int size) | ||
67 | { | ||
68 | hpfs_ea_write(s, a, ano, 0, size, data); | ||
69 | } | ||
70 | |||
71 | /* Read an extended attribute named 'key' into the provided buffer */ | ||
72 | |||
73 | int hpfs_read_ea(struct super_block *s, struct fnode *fnode, char *key, | ||
74 | char *buf, int size) | ||
75 | { | ||
76 | unsigned pos; | ||
77 | int ano, len; | ||
78 | secno a; | ||
79 | struct extended_attribute *ea; | ||
80 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | ||
81 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | ||
82 | if (!strcmp(ea->name, key)) { | ||
83 | if (ea->indirect) | ||
84 | goto indirect; | ||
85 | if (ea->valuelen >= size) | ||
86 | return -EINVAL; | ||
87 | memcpy(buf, ea_data(ea), ea->valuelen); | ||
88 | buf[ea->valuelen] = 0; | ||
89 | return 0; | ||
90 | } | ||
91 | a = fnode->ea_secno; | ||
92 | len = fnode->ea_size_l; | ||
93 | ano = fnode->ea_anode; | ||
94 | pos = 0; | ||
95 | while (pos < len) { | ||
96 | char ex[4 + 255 + 1 + 8]; | ||
97 | ea = (struct extended_attribute *)ex; | ||
98 | if (pos + 4 > len) { | ||
99 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | ||
100 | ano ? "anode" : "sectors", a, len); | ||
101 | return -EIO; | ||
102 | } | ||
103 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return -EIO; | ||
104 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) | ||
105 | return -EIO; | ||
106 | if (!strcmp(ea->name, key)) { | ||
107 | if (ea->indirect) | ||
108 | goto indirect; | ||
109 | if (ea->valuelen >= size) | ||
110 | return -EINVAL; | ||
111 | if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, buf)) | ||
112 | return -EIO; | ||
113 | buf[ea->valuelen] = 0; | ||
114 | return 0; | ||
115 | } | ||
116 | pos += ea->namelen + ea->valuelen + 5; | ||
117 | } | ||
118 | return -ENOENT; | ||
119 | indirect: | ||
120 | if (ea_len(ea) >= size) | ||
121 | return -EINVAL; | ||
122 | if (hpfs_ea_read(s, ea_sec(ea), ea->anode, 0, ea_len(ea), buf)) | ||
123 | return -EIO; | ||
124 | buf[ea_len(ea)] = 0; | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | /* Read an extended attribute named 'key' */ | ||
129 | char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *size) | ||
130 | { | ||
131 | char *ret; | ||
132 | unsigned pos; | ||
133 | int ano, len; | ||
134 | secno a; | ||
135 | struct extended_attribute *ea; | ||
136 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | ||
137 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | ||
138 | if (!strcmp(ea->name, key)) { | ||
139 | if (ea->indirect) | ||
140 | return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); | ||
141 | if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) { | ||
142 | printk("HPFS: out of memory for EA\n"); | ||
143 | return NULL; | ||
144 | } | ||
145 | memcpy(ret, ea_data(ea), ea->valuelen); | ||
146 | ret[ea->valuelen] = 0; | ||
147 | return ret; | ||
148 | } | ||
149 | a = fnode->ea_secno; | ||
150 | len = fnode->ea_size_l; | ||
151 | ano = fnode->ea_anode; | ||
152 | pos = 0; | ||
153 | while (pos < len) { | ||
154 | char ex[4 + 255 + 1 + 8]; | ||
155 | ea = (struct extended_attribute *)ex; | ||
156 | if (pos + 4 > len) { | ||
157 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | ||
158 | ano ? "anode" : "sectors", a, len); | ||
159 | return NULL; | ||
160 | } | ||
161 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return NULL; | ||
162 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) | ||
163 | return NULL; | ||
164 | if (!strcmp(ea->name, key)) { | ||
165 | if (ea->indirect) | ||
166 | return get_indirect_ea(s, ea->anode, ea_sec(ea), *size = ea_len(ea)); | ||
167 | if (!(ret = kmalloc((*size = ea->valuelen) + 1, GFP_NOFS))) { | ||
168 | printk("HPFS: out of memory for EA\n"); | ||
169 | return NULL; | ||
170 | } | ||
171 | if (hpfs_ea_read(s, a, ano, pos + 4 + ea->namelen + 1, ea->valuelen, ret)) { | ||
172 | kfree(ret); | ||
173 | return NULL; | ||
174 | } | ||
175 | ret[ea->valuelen] = 0; | ||
176 | return ret; | ||
177 | } | ||
178 | pos += ea->namelen + ea->valuelen + 5; | ||
179 | } | ||
180 | return NULL; | ||
181 | } | ||
182 | |||
183 | /* | ||
184 | * Update or create extended attribute 'key' with value 'data'. Note that | ||
185 | * when this ea exists, it MUST have the same size as size of data. | ||
186 | * This driver can't change sizes of eas ('cause I just don't need it). | ||
187 | */ | ||
188 | |||
189 | void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data, int size) | ||
190 | { | ||
191 | fnode_secno fno = inode->i_ino; | ||
192 | struct super_block *s = inode->i_sb; | ||
193 | unsigned pos; | ||
194 | int ano, len; | ||
195 | secno a; | ||
196 | unsigned char h[4]; | ||
197 | struct extended_attribute *ea; | ||
198 | struct extended_attribute *ea_end = fnode_end_ea(fnode); | ||
199 | for (ea = fnode_ea(fnode); ea < ea_end; ea = next_ea(ea)) | ||
200 | if (!strcmp(ea->name, key)) { | ||
201 | if (ea->indirect) { | ||
202 | if (ea_len(ea) == size) | ||
203 | set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); | ||
204 | } else if (ea->valuelen == size) { | ||
205 | memcpy(ea_data(ea), data, size); | ||
206 | } | ||
207 | return; | ||
208 | } | ||
209 | a = fnode->ea_secno; | ||
210 | len = fnode->ea_size_l; | ||
211 | ano = fnode->ea_anode; | ||
212 | pos = 0; | ||
213 | while (pos < len) { | ||
214 | char ex[4 + 255 + 1 + 8]; | ||
215 | ea = (struct extended_attribute *)ex; | ||
216 | if (pos + 4 > len) { | ||
217 | hpfs_error(s, "EAs don't end correctly, %s %08x, len %08x", | ||
218 | ano ? "anode" : "sectors", a, len); | ||
219 | return; | ||
220 | } | ||
221 | if (hpfs_ea_read(s, a, ano, pos, 4, ex)) return; | ||
222 | if (hpfs_ea_read(s, a, ano, pos + 4, ea->namelen + 1 + (ea->indirect ? 8 : 0), ex + 4)) | ||
223 | return; | ||
224 | if (!strcmp(ea->name, key)) { | ||
225 | if (ea->indirect) { | ||
226 | if (ea_len(ea) == size) | ||
227 | set_indirect_ea(s, ea->anode, ea_sec(ea), data, size); | ||
228 | } | ||
229 | else { | ||
230 | if (ea->valuelen == size) | ||
231 | hpfs_ea_write(s, a, ano, pos + 4 + ea->namelen + 1, size, data); | ||
232 | } | ||
233 | return; | ||
234 | } | ||
235 | pos += ea->namelen + ea->valuelen + 5; | ||
236 | } | ||
237 | if (!fnode->ea_offs) { | ||
238 | /*if (fnode->ea_size_s) { | ||
239 | hpfs_error(s, "fnode %08x: ea_size_s == %03x, ea_offs == 0", | ||
240 | inode->i_ino, fnode->ea_size_s); | ||
241 | return; | ||
242 | }*/ | ||
243 | fnode->ea_offs = 0xc4; | ||
244 | } | ||
245 | if (fnode->ea_offs < 0xc4 || fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200) { | ||
246 | hpfs_error(s, "fnode %08x: ea_offs == %03x, ea_size_s == %03x", | ||
247 | inode->i_ino, fnode->ea_offs, fnode->ea_size_s); | ||
248 | return; | ||
249 | } | ||
250 | if ((fnode->ea_size_s || !fnode->ea_size_l) && | ||
251 | fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s + strlen(key) + size + 5 <= 0x200) { | ||
252 | ea = fnode_end_ea(fnode); | ||
253 | *(char *)ea = 0; | ||
254 | ea->namelen = strlen(key); | ||
255 | ea->valuelen = size; | ||
256 | strcpy(ea->name, key); | ||
257 | memcpy(ea_data(ea), data, size); | ||
258 | fnode->ea_size_s += strlen(key) + size + 5; | ||
259 | goto ret; | ||
260 | } | ||
261 | /* Most the code here is 99.9993422% unused. I hope there are no bugs. | ||
262 | But what .. HPFS.IFS has also bugs in ea management. */ | ||
263 | if (fnode->ea_size_s && !fnode->ea_size_l) { | ||
264 | secno n; | ||
265 | struct buffer_head *bh; | ||
266 | char *data; | ||
267 | if (!(n = hpfs_alloc_sector(s, fno, 1, 0, 1))) return; | ||
268 | if (!(data = hpfs_get_sector(s, n, &bh))) { | ||
269 | hpfs_free_sectors(s, n, 1); | ||
270 | return; | ||
271 | } | ||
272 | memcpy(data, fnode_ea(fnode), fnode->ea_size_s); | ||
273 | fnode->ea_size_l = fnode->ea_size_s; | ||
274 | fnode->ea_size_s = 0; | ||
275 | fnode->ea_secno = n; | ||
276 | fnode->ea_anode = 0; | ||
277 | mark_buffer_dirty(bh); | ||
278 | brelse(bh); | ||
279 | } | ||
280 | pos = fnode->ea_size_l + 5 + strlen(key) + size; | ||
281 | len = (fnode->ea_size_l + 511) >> 9; | ||
282 | if (pos >= 30000) goto bail; | ||
283 | while (((pos + 511) >> 9) > len) { | ||
284 | if (!len) { | ||
285 | if (!(fnode->ea_secno = hpfs_alloc_sector(s, fno, 1, 0, 1))) | ||
286 | goto bail; | ||
287 | fnode->ea_anode = 0; | ||
288 | len++; | ||
289 | } else if (!fnode->ea_anode) { | ||
290 | if (hpfs_alloc_if_possible(s, fnode->ea_secno + len)) { | ||
291 | len++; | ||
292 | } else { | ||
293 | /* Aargh... don't know how to create ea anodes :-( */ | ||
294 | /*struct buffer_head *bh; | ||
295 | struct anode *anode; | ||
296 | anode_secno a_s; | ||
297 | if (!(anode = hpfs_alloc_anode(s, fno, &a_s, &bh))) | ||
298 | goto bail; | ||
299 | anode->up = fno; | ||
300 | anode->btree.fnode_parent = 1; | ||
301 | anode->btree.n_free_nodes--; | ||
302 | anode->btree.n_used_nodes++; | ||
303 | anode->btree.first_free += 12; | ||
304 | anode->u.external[0].disk_secno = fnode->ea_secno; | ||
305 | anode->u.external[0].file_secno = 0; | ||
306 | anode->u.external[0].length = len; | ||
307 | mark_buffer_dirty(bh); | ||
308 | brelse(bh); | ||
309 | fnode->ea_anode = 1; | ||
310 | fnode->ea_secno = a_s;*/ | ||
311 | secno new_sec; | ||
312 | int i; | ||
313 | if (!(new_sec = hpfs_alloc_sector(s, fno, 1, 1 - ((pos + 511) >> 9), 1))) | ||
314 | goto bail; | ||
315 | for (i = 0; i < len; i++) { | ||
316 | struct buffer_head *bh1, *bh2; | ||
317 | void *b1, *b2; | ||
318 | if (!(b1 = hpfs_map_sector(s, fnode->ea_secno + i, &bh1, len - i - 1))) { | ||
319 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | ||
320 | goto bail; | ||
321 | } | ||
322 | if (!(b2 = hpfs_get_sector(s, new_sec + i, &bh2))) { | ||
323 | brelse(bh1); | ||
324 | hpfs_free_sectors(s, new_sec, (pos + 511) >> 9); | ||
325 | goto bail; | ||
326 | } | ||
327 | memcpy(b2, b1, 512); | ||
328 | brelse(bh1); | ||
329 | mark_buffer_dirty(bh2); | ||
330 | brelse(bh2); | ||
331 | } | ||
332 | hpfs_free_sectors(s, fnode->ea_secno, len); | ||
333 | fnode->ea_secno = new_sec; | ||
334 | len = (pos + 511) >> 9; | ||
335 | } | ||
336 | } | ||
337 | if (fnode->ea_anode) { | ||
338 | if (hpfs_add_sector_to_btree(s, fnode->ea_secno, | ||
339 | 0, len) != -1) { | ||
340 | len++; | ||
341 | } else { | ||
342 | goto bail; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | h[0] = 0; | ||
347 | h[1] = strlen(key); | ||
348 | h[2] = size & 0xff; | ||
349 | h[3] = size >> 8; | ||
350 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l, 4, h)) goto bail; | ||
351 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 4, h[1] + 1, key)) goto bail; | ||
352 | if (hpfs_ea_write(s, fnode->ea_secno, fnode->ea_anode, fnode->ea_size_l + 5 + h[1], size, data)) goto bail; | ||
353 | fnode->ea_size_l = pos; | ||
354 | ret: | ||
355 | hpfs_i(inode)->i_ea_size += 5 + strlen(key) + size; | ||
356 | return; | ||
357 | bail: | ||
358 | if (fnode->ea_secno) | ||
359 | if (fnode->ea_anode) hpfs_truncate_btree(s, fnode->ea_secno, 1, (fnode->ea_size_l + 511) >> 9); | ||
360 | else hpfs_free_sectors(s, fnode->ea_secno + ((fnode->ea_size_l + 511) >> 9), len - ((fnode->ea_size_l + 511) >> 9)); | ||
361 | else fnode->ea_secno = fnode->ea_size_l = 0; | ||
362 | } | ||
363 | |||
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c new file mode 100644 index 000000000000..ab144dabd870 --- /dev/null +++ b/fs/hpfs/file.c | |||
@@ -0,0 +1,140 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/file.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * file VFS functions | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | #define BLOCKS(size) (((size) + 511) >> 9) | ||
12 | |||
13 | static int hpfs_file_release(struct inode *inode, struct file *file) | ||
14 | { | ||
15 | lock_kernel(); | ||
16 | hpfs_write_if_changed(inode); | ||
17 | unlock_kernel(); | ||
18 | return 0; | ||
19 | } | ||
20 | |||
21 | int hpfs_file_fsync(struct file *file, struct dentry *dentry, int datasync) | ||
22 | { | ||
23 | /*return file_fsync(file, dentry);*/ | ||
24 | return 0; /* Don't fsync :-) */ | ||
25 | } | ||
26 | |||
27 | /* | ||
28 | * generic_file_read often calls bmap with non-existing sector, | ||
29 | * so we must ignore such errors. | ||
30 | */ | ||
31 | |||
32 | static secno hpfs_bmap(struct inode *inode, unsigned file_secno) | ||
33 | { | ||
34 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
35 | unsigned n, disk_secno; | ||
36 | struct fnode *fnode; | ||
37 | struct buffer_head *bh; | ||
38 | if (BLOCKS(hpfs_i(inode)->mmu_private) <= file_secno) return 0; | ||
39 | n = file_secno - hpfs_inode->i_file_sec; | ||
40 | if (n < hpfs_inode->i_n_secs) return hpfs_inode->i_disk_sec + n; | ||
41 | if (!(fnode = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) return 0; | ||
42 | disk_secno = hpfs_bplus_lookup(inode->i_sb, inode, &fnode->btree, file_secno, bh); | ||
43 | if (disk_secno == -1) return 0; | ||
44 | if (hpfs_chk_sectors(inode->i_sb, disk_secno, 1, "bmap")) return 0; | ||
45 | return disk_secno; | ||
46 | } | ||
47 | |||
48 | static void hpfs_truncate(struct inode *i) | ||
49 | { | ||
50 | if (IS_IMMUTABLE(i)) return /*-EPERM*/; | ||
51 | lock_kernel(); | ||
52 | hpfs_i(i)->i_n_secs = 0; | ||
53 | i->i_blocks = 1 + ((i->i_size + 511) >> 9); | ||
54 | hpfs_i(i)->mmu_private = i->i_size; | ||
55 | hpfs_truncate_btree(i->i_sb, i->i_ino, 1, ((i->i_size + 511) >> 9)); | ||
56 | hpfs_write_inode(i); | ||
57 | hpfs_i(i)->i_n_secs = 0; | ||
58 | unlock_kernel(); | ||
59 | } | ||
60 | |||
61 | static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) | ||
62 | { | ||
63 | secno s; | ||
64 | s = hpfs_bmap(inode, iblock); | ||
65 | if (s) { | ||
66 | map_bh(bh_result, inode->i_sb, s); | ||
67 | return 0; | ||
68 | } | ||
69 | if (!create) return 0; | ||
70 | if (iblock<<9 != hpfs_i(inode)->mmu_private) { | ||
71 | BUG(); | ||
72 | return -EIO; | ||
73 | } | ||
74 | if ((s = hpfs_add_sector_to_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1)) == -1) { | ||
75 | hpfs_truncate_btree(inode->i_sb, inode->i_ino, 1, inode->i_blocks - 1); | ||
76 | return -ENOSPC; | ||
77 | } | ||
78 | inode->i_blocks++; | ||
79 | hpfs_i(inode)->mmu_private += 512; | ||
80 | set_buffer_new(bh_result); | ||
81 | map_bh(bh_result, inode->i_sb, s); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int hpfs_writepage(struct page *page, struct writeback_control *wbc) | ||
86 | { | ||
87 | return block_write_full_page(page,hpfs_get_block, wbc); | ||
88 | } | ||
89 | static int hpfs_readpage(struct file *file, struct page *page) | ||
90 | { | ||
91 | return block_read_full_page(page,hpfs_get_block); | ||
92 | } | ||
93 | static int hpfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) | ||
94 | { | ||
95 | return cont_prepare_write(page,from,to,hpfs_get_block, | ||
96 | &hpfs_i(page->mapping->host)->mmu_private); | ||
97 | } | ||
98 | static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) | ||
99 | { | ||
100 | return generic_block_bmap(mapping,block,hpfs_get_block); | ||
101 | } | ||
102 | struct address_space_operations hpfs_aops = { | ||
103 | .readpage = hpfs_readpage, | ||
104 | .writepage = hpfs_writepage, | ||
105 | .sync_page = block_sync_page, | ||
106 | .prepare_write = hpfs_prepare_write, | ||
107 | .commit_write = generic_commit_write, | ||
108 | .bmap = _hpfs_bmap | ||
109 | }; | ||
110 | |||
111 | static ssize_t hpfs_file_write(struct file *file, const char __user *buf, | ||
112 | size_t count, loff_t *ppos) | ||
113 | { | ||
114 | ssize_t retval; | ||
115 | |||
116 | retval = generic_file_write(file, buf, count, ppos); | ||
117 | if (retval > 0) { | ||
118 | struct inode *inode = file->f_dentry->d_inode; | ||
119 | inode->i_mtime = CURRENT_TIME_SEC; | ||
120 | hpfs_i(inode)->i_dirty = 1; | ||
121 | } | ||
122 | return retval; | ||
123 | } | ||
124 | |||
125 | struct file_operations hpfs_file_ops = | ||
126 | { | ||
127 | .llseek = generic_file_llseek, | ||
128 | .read = generic_file_read, | ||
129 | .write = hpfs_file_write, | ||
130 | .mmap = generic_file_mmap, | ||
131 | .release = hpfs_file_release, | ||
132 | .fsync = hpfs_file_fsync, | ||
133 | .sendfile = generic_file_sendfile, | ||
134 | }; | ||
135 | |||
136 | struct inode_operations hpfs_file_iops = | ||
137 | { | ||
138 | .truncate = hpfs_truncate, | ||
139 | .setattr = hpfs_notify_change, | ||
140 | }; | ||
diff --git a/fs/hpfs/hpfs.h b/fs/hpfs/hpfs.h new file mode 100644 index 000000000000..0e84c73cd9c4 --- /dev/null +++ b/fs/hpfs/hpfs.h | |||
@@ -0,0 +1,493 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/hpfs.h | ||
3 | * | ||
4 | * HPFS structures by Chris Smith, 1993 | ||
5 | * | ||
6 | * a little bit modified by Mikulas Patocka, 1998-1999 | ||
7 | */ | ||
8 | |||
9 | /* The paper | ||
10 | |||
11 | Duncan, Roy | ||
12 | Design goals and implementation of the new High Performance File System | ||
13 | Microsoft Systems Journal Sept 1989 v4 n5 p1(13) | ||
14 | |||
15 | describes what HPFS looked like when it was new, and it is the source | ||
16 | of most of the information given here. The rest is conjecture. | ||
17 | |||
18 | For definitive information on the Duncan paper, see it, not this file. | ||
19 | For definitive information on HPFS, ask somebody else -- this is guesswork. | ||
20 | There are certain to be many mistakes. */ | ||
21 | |||
22 | /* Notation */ | ||
23 | |||
24 | typedef unsigned secno; /* sector number, partition relative */ | ||
25 | |||
26 | typedef secno dnode_secno; /* sector number of a dnode */ | ||
27 | typedef secno fnode_secno; /* sector number of an fnode */ | ||
28 | typedef secno anode_secno; /* sector number of an anode */ | ||
29 | |||
30 | typedef u32 time32_t; /* 32-bit time_t type */ | ||
31 | |||
32 | /* sector 0 */ | ||
33 | |||
34 | /* The boot block is very like a FAT boot block, except that the | ||
35 | 29h signature byte is 28h instead, and the ID string is "HPFS". */ | ||
36 | |||
37 | #define BB_MAGIC 0xaa55 | ||
38 | |||
39 | struct hpfs_boot_block | ||
40 | { | ||
41 | unsigned char jmp[3]; | ||
42 | unsigned char oem_id[8]; | ||
43 | unsigned char bytes_per_sector[2]; /* 512 */ | ||
44 | unsigned char sectors_per_cluster; | ||
45 | unsigned char n_reserved_sectors[2]; | ||
46 | unsigned char n_fats; | ||
47 | unsigned char n_rootdir_entries[2]; | ||
48 | unsigned char n_sectors_s[2]; | ||
49 | unsigned char media_byte; | ||
50 | unsigned short sectors_per_fat; | ||
51 | unsigned short sectors_per_track; | ||
52 | unsigned short heads_per_cyl; | ||
53 | unsigned int n_hidden_sectors; | ||
54 | unsigned int n_sectors_l; /* size of partition */ | ||
55 | unsigned char drive_number; | ||
56 | unsigned char mbz; | ||
57 | unsigned char sig_28h; /* 28h */ | ||
58 | unsigned char vol_serno[4]; | ||
59 | unsigned char vol_label[11]; | ||
60 | unsigned char sig_hpfs[8]; /* "HPFS " */ | ||
61 | unsigned char pad[448]; | ||
62 | unsigned short magic; /* aa55 */ | ||
63 | }; | ||
64 | |||
65 | |||
66 | /* sector 16 */ | ||
67 | |||
68 | /* The super block has the pointer to the root directory. */ | ||
69 | |||
70 | #define SB_MAGIC 0xf995e849 | ||
71 | |||
72 | struct hpfs_super_block | ||
73 | { | ||
74 | unsigned magic; /* f995 e849 */ | ||
75 | unsigned magic1; /* fa53 e9c5, more magic? */ | ||
76 | /*unsigned huh202;*/ /* ?? 202 = N. of B. in 1.00390625 S.*/ | ||
77 | char version; /* version of a filesystem usually 2 */ | ||
78 | char funcversion; /* functional version - oldest version | ||
79 | of filesystem that can understand | ||
80 | this disk */ | ||
81 | unsigned short int zero; /* 0 */ | ||
82 | fnode_secno root; /* fnode of root directory */ | ||
83 | secno n_sectors; /* size of filesystem */ | ||
84 | unsigned n_badblocks; /* number of bad blocks */ | ||
85 | secno bitmaps; /* pointers to free space bit maps */ | ||
86 | unsigned zero1; /* 0 */ | ||
87 | secno badblocks; /* bad block list */ | ||
88 | unsigned zero3; /* 0 */ | ||
89 | time32_t last_chkdsk; /* date last checked, 0 if never */ | ||
90 | /*unsigned zero4;*/ /* 0 */ | ||
91 | time32_t last_optimize; /* date last optimized, 0 if never */ | ||
92 | secno n_dir_band; /* number of sectors in dir band */ | ||
93 | secno dir_band_start; /* first sector in dir band */ | ||
94 | secno dir_band_end; /* last sector in dir band */ | ||
95 | secno dir_band_bitmap; /* free space map, 1 dnode per bit */ | ||
96 | char volume_name[32]; /* not used */ | ||
97 | secno user_id_table; /* 8 preallocated sectors - user id */ | ||
98 | unsigned zero6[103]; /* 0 */ | ||
99 | }; | ||
100 | |||
101 | |||
102 | /* sector 17 */ | ||
103 | |||
104 | /* The spare block has pointers to spare sectors. */ | ||
105 | |||
106 | #define SP_MAGIC 0xf9911849 | ||
107 | |||
108 | struct hpfs_spare_block | ||
109 | { | ||
110 | unsigned magic; /* f991 1849 */ | ||
111 | unsigned magic1; /* fa52 29c5, more magic? */ | ||
112 | |||
113 | unsigned dirty: 1; /* 0 clean, 1 "improperly stopped" */ | ||
114 | /*unsigned flag1234: 4;*/ /* unknown flags */ | ||
115 | unsigned sparedir_used: 1; /* spare dirblks used */ | ||
116 | unsigned hotfixes_used: 1; /* hotfixes used */ | ||
117 | unsigned bad_sector: 1; /* bad sector, corrupted disk (???) */ | ||
118 | unsigned bad_bitmap: 1; /* bad bitmap */ | ||
119 | unsigned fast: 1; /* partition was fast formatted */ | ||
120 | unsigned old_wrote: 1; /* old version wrote to partion */ | ||
121 | unsigned old_wrote_1: 1; /* old version wrote to partion (?) */ | ||
122 | unsigned install_dasd_limits: 1; /* HPFS386 flags */ | ||
123 | unsigned resynch_dasd_limits: 1; | ||
124 | unsigned dasd_limits_operational: 1; | ||
125 | unsigned multimedia_active: 1; | ||
126 | unsigned dce_acls_active: 1; | ||
127 | unsigned dasd_limits_dirty: 1; | ||
128 | unsigned flag67: 2; | ||
129 | unsigned char mm_contlgulty; | ||
130 | unsigned char unused; | ||
131 | |||
132 | secno hotfix_map; /* info about remapped bad sectors */ | ||
133 | unsigned n_spares_used; /* number of hotfixes */ | ||
134 | unsigned n_spares; /* number of spares in hotfix map */ | ||
135 | unsigned n_dnode_spares_free; /* spare dnodes unused */ | ||
136 | unsigned n_dnode_spares; /* length of spare_dnodes[] list, | ||
137 | follows in this block*/ | ||
138 | secno code_page_dir; /* code page directory block */ | ||
139 | unsigned n_code_pages; /* number of code pages */ | ||
140 | /*unsigned large_numbers[2];*/ /* ?? */ | ||
141 | unsigned super_crc; /* on HPFS386 and LAN Server this is | ||
142 | checksum of superblock, on normal | ||
143 | OS/2 unused */ | ||
144 | unsigned spare_crc; /* on HPFS386 checksum of spareblock */ | ||
145 | unsigned zero1[15]; /* unused */ | ||
146 | dnode_secno spare_dnodes[100]; /* emergency free dnode list */ | ||
147 | unsigned zero2[1]; /* room for more? */ | ||
148 | }; | ||
149 | |||
150 | /* The bad block list is 4 sectors long. The first word must be zero, | ||
151 | the remaining words give n_badblocks bad block numbers. | ||
152 | I bet you can see it coming... */ | ||
153 | |||
154 | #define BAD_MAGIC 0 | ||
155 | |||
156 | /* The hotfix map is 4 sectors long. It looks like | ||
157 | |||
158 | secno from[n_spares]; | ||
159 | secno to[n_spares]; | ||
160 | |||
161 | The to[] list is initialized to point to n_spares preallocated empty | ||
162 | sectors. The from[] list contains the sector numbers of bad blocks | ||
163 | which have been remapped to corresponding sectors in the to[] list. | ||
164 | n_spares_used gives the length of the from[] list. */ | ||
165 | |||
166 | |||
167 | /* Sectors 18 and 19 are preallocated and unused. | ||
168 | Maybe they're spares for 16 and 17, but simple substitution fails. */ | ||
169 | |||
170 | |||
171 | /* The code page info pointed to by the spare block consists of an index | ||
172 | block and blocks containing uppercasing tables. I don't know what | ||
173 | these are for (CHKDSK, maybe?) -- OS/2 does not seem to use them | ||
174 | itself. Linux doesn't use them either. */ | ||
175 | |||
176 | /* block pointed to by spareblock->code_page_dir */ | ||
177 | |||
178 | #define CP_DIR_MAGIC 0x494521f7 | ||
179 | |||
180 | struct code_page_directory | ||
181 | { | ||
182 | unsigned magic; /* 4945 21f7 */ | ||
183 | unsigned n_code_pages; /* number of pointers following */ | ||
184 | unsigned zero1[2]; | ||
185 | struct { | ||
186 | unsigned short ix; /* index */ | ||
187 | unsigned short code_page_number; /* code page number */ | ||
188 | unsigned bounds; /* matches corresponding word | ||
189 | in data block */ | ||
190 | secno code_page_data; /* sector number of a code_page_data | ||
191 | containing c.p. array */ | ||
192 | unsigned short index; /* index in c.p. array in that sector*/ | ||
193 | unsigned short unknown; /* some unknown value; usually 0; | ||
194 | 2 in Japanese version */ | ||
195 | } array[31]; /* unknown length */ | ||
196 | }; | ||
197 | |||
198 | /* blocks pointed to by code_page_directory */ | ||
199 | |||
200 | #define CP_DATA_MAGIC 0x894521f7 | ||
201 | |||
202 | struct code_page_data | ||
203 | { | ||
204 | unsigned magic; /* 8945 21f7 */ | ||
205 | unsigned n_used; /* # elements used in c_p_data[] */ | ||
206 | unsigned bounds[3]; /* looks a bit like | ||
207 | (beg1,end1), (beg2,end2) | ||
208 | one byte each */ | ||
209 | unsigned short offs[3]; /* offsets from start of sector | ||
210 | to start of c_p_data[ix] */ | ||
211 | struct { | ||
212 | unsigned short ix; /* index */ | ||
213 | unsigned short code_page_number; /* code page number */ | ||
214 | unsigned short unknown; /* the same as in cp directory */ | ||
215 | unsigned char map[128]; /* upcase table for chars 80..ff */ | ||
216 | unsigned short zero2; | ||
217 | } code_page[3]; | ||
218 | unsigned char incognita[78]; | ||
219 | }; | ||
220 | |||
221 | |||
222 | /* Free space bitmaps are 4 sectors long, which is 16384 bits. | ||
223 | 16384 sectors is 8 meg, and each 8 meg band has a 4-sector bitmap. | ||
224 | Bit order in the maps is little-endian. 0 means taken, 1 means free. | ||
225 | |||
226 | Bit map sectors are marked allocated in the bit maps, and so are sectors | ||
227 | off the end of the partition. | ||
228 | |||
229 | Band 0 is sectors 0-3fff, its map is in sectors 18-1b. | ||
230 | Band 1 is 4000-7fff, its map is in 7ffc-7fff. | ||
231 | Band 2 is 8000-ffff, its map is in 8000-8003. | ||
232 | The remaining bands have maps in their first (even) or last (odd) 4 sectors | ||
233 | -- if the last, partial, band is odd its map is in its last 4 sectors. | ||
234 | |||
235 | The bitmap locations are given in a table pointed to by the super block. | ||
236 | No doubt they aren't constrained to be at 18, 7ffc, 8000, ...; that is | ||
237 | just where they usually are. | ||
238 | |||
239 | The "directory band" is a bunch of sectors preallocated for dnodes. | ||
240 | It has a 4-sector free space bitmap of its own. Each bit in the map | ||
241 | corresponds to one 4-sector dnode, bit 0 of the map corresponding to | ||
242 | the first 4 sectors of the directory band. The entire band is marked | ||
243 | allocated in the main bitmap. The super block gives the locations | ||
244 | of the directory band and its bitmap. ("band" doesn't mean it is | ||
245 | 8 meg long; it isn't.) */ | ||
246 | |||
247 | |||
248 | /* dnode: directory. 4 sectors long */ | ||
249 | |||
250 | /* A directory is a tree of dnodes. The fnode for a directory | ||
251 | contains one pointer, to the root dnode of the tree. The fnode | ||
252 | never moves, the dnodes do the B-tree thing, splitting and merging | ||
253 | as files are added and removed. */ | ||
254 | |||
255 | #define DNODE_MAGIC 0x77e40aae | ||
256 | |||
257 | struct dnode { | ||
258 | unsigned magic; /* 77e4 0aae */ | ||
259 | unsigned first_free; /* offset from start of dnode to | ||
260 | first free dir entry */ | ||
261 | unsigned root_dnode:1; /* Is it root dnode? */ | ||
262 | unsigned increment_me:31; /* some kind of activity counter? | ||
263 | Neither HPFS.IFS nor CHKDSK cares | ||
264 | if you change this word */ | ||
265 | secno up; /* (root dnode) directory's fnode | ||
266 | (nonroot) parent dnode */ | ||
267 | dnode_secno self; /* pointer to this dnode */ | ||
268 | unsigned char dirent[2028]; /* one or more dirents */ | ||
269 | }; | ||
270 | |||
271 | struct hpfs_dirent { | ||
272 | unsigned short length; /* offset to next dirent */ | ||
273 | unsigned first: 1; /* set on phony ^A^A (".") entry */ | ||
274 | unsigned has_acl: 1; | ||
275 | unsigned down: 1; /* down pointer present (after name) */ | ||
276 | unsigned last: 1; /* set on phony \377 entry */ | ||
277 | unsigned has_ea: 1; /* entry has EA */ | ||
278 | unsigned has_xtd_perm: 1; /* has extended perm list (???) */ | ||
279 | unsigned has_explicit_acl: 1; | ||
280 | unsigned has_needea: 1; /* ?? some EA has NEEDEA set | ||
281 | I have no idea why this is | ||
282 | interesting in a dir entry */ | ||
283 | unsigned read_only: 1; /* dos attrib */ | ||
284 | unsigned hidden: 1; /* dos attrib */ | ||
285 | unsigned system: 1; /* dos attrib */ | ||
286 | unsigned flag11: 1; /* would be volume label dos attrib */ | ||
287 | unsigned directory: 1; /* dos attrib */ | ||
288 | unsigned archive: 1; /* dos attrib */ | ||
289 | unsigned not_8x3: 1; /* name is not 8.3 */ | ||
290 | unsigned flag15: 1; | ||
291 | fnode_secno fnode; /* fnode giving allocation info */ | ||
292 | time32_t write_date; /* mtime */ | ||
293 | unsigned file_size; /* file length, bytes */ | ||
294 | time32_t read_date; /* atime */ | ||
295 | time32_t creation_date; /* ctime */ | ||
296 | unsigned ea_size; /* total EA length, bytes */ | ||
297 | unsigned char no_of_acls : 3; /* number of ACL's */ | ||
298 | unsigned char reserver : 5; | ||
299 | unsigned char ix; /* code page index (of filename), see | ||
300 | struct code_page_data */ | ||
301 | unsigned char namelen, name[1]; /* file name */ | ||
302 | /* dnode_secno down; btree down pointer, if present, | ||
303 | follows name on next word boundary, or maybe it | ||
304 | precedes next dirent, which is on a word boundary. */ | ||
305 | }; | ||
306 | |||
307 | |||
308 | /* B+ tree: allocation info in fnodes and anodes */ | ||
309 | |||
310 | /* dnodes point to fnodes which are responsible for listing the sectors | ||
311 | assigned to the file. This is done with trees of (length,address) | ||
312 | pairs. (Actually triples, of (length, file-address, disk-address) | ||
313 | which can represent holes. Find out if HPFS does that.) | ||
314 | At any rate, fnodes contain a small tree; if subtrees are needed | ||
315 | they occupy essentially a full block in anodes. A leaf-level tree node | ||
316 | has 3-word entries giving sector runs, a non-leaf node has 2-word | ||
317 | entries giving subtree pointers. A flag in the header says which. */ | ||
318 | |||
319 | struct bplus_leaf_node | ||
320 | { | ||
321 | unsigned file_secno; /* first file sector in extent */ | ||
322 | unsigned length; /* length, sectors */ | ||
323 | secno disk_secno; /* first corresponding disk sector */ | ||
324 | }; | ||
325 | |||
326 | struct bplus_internal_node | ||
327 | { | ||
328 | unsigned file_secno; /* subtree maps sectors < this */ | ||
329 | anode_secno down; /* pointer to subtree */ | ||
330 | }; | ||
331 | |||
332 | struct bplus_header | ||
333 | { | ||
334 | unsigned hbff: 1; /* high bit of first free entry offset */ | ||
335 | unsigned flag1: 1; | ||
336 | unsigned flag2: 1; | ||
337 | unsigned flag3: 1; | ||
338 | unsigned flag4: 1; | ||
339 | unsigned fnode_parent: 1; /* ? we're pointed to by an fnode, | ||
340 | the data btree or some ea or the | ||
341 | main ea bootage pointer ea_secno */ | ||
342 | /* also can get set in fnodes, which | ||
343 | may be a chkdsk glitch or may mean | ||
344 | this bit is irrelevant in fnodes, | ||
345 | or this interpretation is all wet */ | ||
346 | unsigned binary_search: 1; /* suggest binary search (unused) */ | ||
347 | unsigned internal: 1; /* 1 -> (internal) tree of anodes | ||
348 | 0 -> (leaf) list of extents */ | ||
349 | unsigned char fill[3]; | ||
350 | unsigned char n_free_nodes; /* free nodes in following array */ | ||
351 | unsigned char n_used_nodes; /* used nodes in following array */ | ||
352 | unsigned short first_free; /* offset from start of header to | ||
353 | first free node in array */ | ||
354 | union { | ||
355 | struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving | ||
356 | subtree pointers */ | ||
357 | struct bplus_leaf_node external[0]; /* (external) 3-word entries giving | ||
358 | sector runs */ | ||
359 | } u; | ||
360 | }; | ||
361 | |||
362 | /* fnode: root of allocation b+ tree, and EA's */ | ||
363 | |||
364 | /* Every file and every directory has one fnode, pointed to by the directory | ||
365 | entry and pointing to the file's sectors or directory's root dnode. EA's | ||
366 | are also stored here, and there are said to be ACL's somewhere here too. */ | ||
367 | |||
368 | #define FNODE_MAGIC 0xf7e40aae | ||
369 | |||
370 | struct fnode | ||
371 | { | ||
372 | unsigned magic; /* f7e4 0aae */ | ||
373 | unsigned zero1[2]; /* read history */ | ||
374 | unsigned char len, name[15]; /* true length, truncated name */ | ||
375 | fnode_secno up; /* pointer to file's directory fnode */ | ||
376 | /*unsigned zero2[3];*/ | ||
377 | secno acl_size_l; | ||
378 | secno acl_secno; | ||
379 | unsigned short acl_size_s; | ||
380 | char acl_anode; | ||
381 | char zero2; /* history bit count */ | ||
382 | unsigned ea_size_l; /* length of disk-resident ea's */ | ||
383 | secno ea_secno; /* first sector of disk-resident ea's*/ | ||
384 | unsigned short ea_size_s; /* length of fnode-resident ea's */ | ||
385 | |||
386 | unsigned flag0: 1; | ||
387 | unsigned ea_anode: 1; /* 1 -> ea_secno is an anode */ | ||
388 | unsigned flag2: 1; | ||
389 | unsigned flag3: 1; | ||
390 | unsigned flag4: 1; | ||
391 | unsigned flag5: 1; | ||
392 | unsigned flag6: 1; | ||
393 | unsigned flag7: 1; | ||
394 | unsigned dirflag: 1; /* 1 -> directory. first & only extent | ||
395 | points to dnode. */ | ||
396 | unsigned flag9: 1; | ||
397 | unsigned flag10: 1; | ||
398 | unsigned flag11: 1; | ||
399 | unsigned flag12: 1; | ||
400 | unsigned flag13: 1; | ||
401 | unsigned flag14: 1; | ||
402 | unsigned flag15: 1; | ||
403 | |||
404 | struct bplus_header btree; /* b+ tree, 8 extents or 12 subtrees */ | ||
405 | union { | ||
406 | struct bplus_leaf_node external[8]; | ||
407 | struct bplus_internal_node internal[12]; | ||
408 | } u; | ||
409 | |||
410 | unsigned file_size; /* file length, bytes */ | ||
411 | unsigned n_needea; /* number of EA's with NEEDEA set */ | ||
412 | char user_id[16]; /* unused */ | ||
413 | unsigned short ea_offs; /* offset from start of fnode | ||
414 | to first fnode-resident ea */ | ||
415 | char dasd_limit_treshhold; | ||
416 | char dasd_limit_delta; | ||
417 | unsigned dasd_limit; | ||
418 | unsigned dasd_usage; | ||
419 | /*unsigned zero5[2];*/ | ||
420 | unsigned char ea[316]; /* zero or more EA's, packed together | ||
421 | with no alignment padding. | ||
422 | (Do not use this name, get here | ||
423 | via fnode + ea_offs. I think.) */ | ||
424 | }; | ||
425 | |||
426 | |||
427 | /* anode: 99.44% pure allocation tree */ | ||
428 | |||
429 | #define ANODE_MAGIC 0x37e40aae | ||
430 | |||
431 | struct anode | ||
432 | { | ||
433 | unsigned magic; /* 37e4 0aae */ | ||
434 | anode_secno self; /* pointer to this anode */ | ||
435 | secno up; /* parent anode or fnode */ | ||
436 | |||
437 | struct bplus_header btree; /* b+tree, 40 extents or 60 subtrees */ | ||
438 | union { | ||
439 | struct bplus_leaf_node external[40]; | ||
440 | struct bplus_internal_node internal[60]; | ||
441 | } u; | ||
442 | |||
443 | unsigned fill[3]; /* unused */ | ||
444 | }; | ||
445 | |||
446 | |||
447 | /* extended attributes. | ||
448 | |||
449 | A file's EA info is stored as a list of (name,value) pairs. It is | ||
450 | usually in the fnode, but (if it's large) it is moved to a single | ||
451 | sector run outside the fnode, or to multiple runs with an anode tree | ||
452 | that points to them. | ||
453 | |||
454 | The value of a single EA is stored along with the name, or (if large) | ||
455 | it is moved to a single sector run, or multiple runs pointed to by an | ||
456 | anode tree, pointed to by the value field of the (name,value) pair. | ||
457 | |||
458 | Flags in the EA tell whether the value is immediate, in a single sector | ||
459 | run, or in multiple runs. Flags in the fnode tell whether the EA list | ||
460 | is immediate, in a single run, or in multiple runs. */ | ||
461 | |||
462 | struct extended_attribute | ||
463 | { | ||
464 | unsigned indirect: 1; /* 1 -> value gives sector number | ||
465 | where real value starts */ | ||
466 | unsigned anode: 1; /* 1 -> sector is an anode | ||
467 | that points to fragmented value */ | ||
468 | unsigned flag2: 1; | ||
469 | unsigned flag3: 1; | ||
470 | unsigned flag4: 1; | ||
471 | unsigned flag5: 1; | ||
472 | unsigned flag6: 1; | ||
473 | unsigned needea: 1; /* required ea */ | ||
474 | unsigned char namelen; /* length of name, bytes */ | ||
475 | unsigned short valuelen; /* length of value, bytes */ | ||
476 | unsigned char name[0]; | ||
477 | /* | ||
478 | unsigned char name[namelen]; ascii attrib name | ||
479 | unsigned char nul; terminating '\0', not counted | ||
480 | unsigned char value[valuelen]; value, arbitrary | ||
481 | if this.indirect, valuelen is 8 and the value is | ||
482 | unsigned length; real length of value, bytes | ||
483 | secno secno; sector address where it starts | ||
484 | if this.anode, the above sector number is the root of an anode tree | ||
485 | which points to the value. | ||
486 | */ | ||
487 | }; | ||
488 | |||
489 | /* | ||
490 | Local Variables: | ||
491 | comment-column: 40 | ||
492 | End: | ||
493 | */ | ||
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h new file mode 100644 index 000000000000..6628c3b352cb --- /dev/null +++ b/fs/hpfs/hpfs_fn.h | |||
@@ -0,0 +1,338 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/hpfs_fn.h | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * function headers | ||
7 | */ | ||
8 | |||
9 | //#define DBG | ||
10 | //#define DEBUG_LOCKS | ||
11 | |||
12 | #include <linux/pagemap.h> | ||
13 | #include <linux/buffer_head.h> | ||
14 | #include <linux/hpfs_fs.h> | ||
15 | #include <linux/slab.h> | ||
16 | #include <linux/smp_lock.h> | ||
17 | |||
18 | #include "hpfs.h" | ||
19 | |||
20 | #define EIOERROR EIO | ||
21 | #define EFSERROR EPERM | ||
22 | #define EMEMERROR ENOMEM | ||
23 | |||
24 | #define ANODE_ALLOC_FWD 512 | ||
25 | #define FNODE_ALLOC_FWD 0 | ||
26 | #define ALLOC_FWD_MIN 16 | ||
27 | #define ALLOC_FWD_MAX 128 | ||
28 | #define ALLOC_M 1 | ||
29 | #define FNODE_RD_AHEAD 16 | ||
30 | #define ANODE_RD_AHEAD 16 | ||
31 | #define DNODE_RD_AHEAD 4 | ||
32 | |||
33 | #define FREE_DNODES_ADD 58 | ||
34 | #define FREE_DNODES_DEL 29 | ||
35 | |||
36 | #define CHKCOND(x,y) if (!(x)) printk y | ||
37 | |||
38 | #ifdef DBG | ||
39 | #define PRINTK(x) printk x | ||
40 | #else | ||
41 | #undef PRINTK | ||
42 | #define PRINTK(x) | ||
43 | #endif | ||
44 | |||
45 | struct hpfs_inode_info { | ||
46 | loff_t mmu_private; | ||
47 | ino_t i_parent_dir; /* (directories) gives fnode of parent dir */ | ||
48 | unsigned i_dno; /* (directories) root dnode */ | ||
49 | unsigned i_dpos; /* (directories) temp for readdir */ | ||
50 | unsigned i_dsubdno; /* (directories) temp for readdir */ | ||
51 | unsigned i_file_sec; /* (files) minimalist cache of alloc info */ | ||
52 | unsigned i_disk_sec; /* (files) minimalist cache of alloc info */ | ||
53 | unsigned i_n_secs; /* (files) minimalist cache of alloc info */ | ||
54 | unsigned i_ea_size; /* size of extended attributes */ | ||
55 | unsigned i_conv : 2; /* (files) crlf->newline hackery */ | ||
56 | unsigned i_ea_mode : 1; /* file's permission is stored in ea */ | ||
57 | unsigned i_ea_uid : 1; /* file's uid is stored in ea */ | ||
58 | unsigned i_ea_gid : 1; /* file's gid is stored in ea */ | ||
59 | unsigned i_dirty : 1; | ||
60 | struct semaphore i_sem; | ||
61 | struct semaphore i_parent; | ||
62 | loff_t **i_rddir_off; | ||
63 | struct inode vfs_inode; | ||
64 | }; | ||
65 | |||
66 | struct hpfs_sb_info { | ||
67 | ino_t sb_root; /* inode number of root dir */ | ||
68 | unsigned sb_fs_size; /* file system size, sectors */ | ||
69 | unsigned sb_bitmaps; /* sector number of bitmap list */ | ||
70 | unsigned sb_dirband_start; /* directory band start sector */ | ||
71 | unsigned sb_dirband_size; /* directory band size, dnodes */ | ||
72 | unsigned sb_dmap; /* sector number of dnode bit map */ | ||
73 | unsigned sb_n_free; /* free blocks for statfs, or -1 */ | ||
74 | unsigned sb_n_free_dnodes; /* free dnodes for statfs, or -1 */ | ||
75 | uid_t sb_uid; /* uid from mount options */ | ||
76 | gid_t sb_gid; /* gid from mount options */ | ||
77 | umode_t sb_mode; /* mode from mount options */ | ||
78 | unsigned sb_conv : 2; /* crlf->newline hackery */ | ||
79 | unsigned sb_eas : 2; /* eas: 0-ignore, 1-ro, 2-rw */ | ||
80 | unsigned sb_err : 2; /* on errs: 0-cont, 1-ro, 2-panic */ | ||
81 | unsigned sb_chk : 2; /* checks: 0-no, 1-normal, 2-strict */ | ||
82 | unsigned sb_lowercase : 1; /* downcase filenames hackery */ | ||
83 | unsigned sb_was_error : 1; /* there was an error, set dirty flag */ | ||
84 | unsigned sb_chkdsk : 2; /* chkdsk: 0-no, 1-on errs, 2-allways */ | ||
85 | unsigned char *sb_cp_table; /* code page tables: */ | ||
86 | /* 128 bytes uppercasing table & */ | ||
87 | /* 128 bytes lowercasing table */ | ||
88 | unsigned *sb_bmp_dir; /* main bitmap directory */ | ||
89 | unsigned sb_c_bitmap; /* current bitmap */ | ||
90 | unsigned sb_max_fwd_alloc; /* max forwad allocation */ | ||
91 | struct semaphore hpfs_creation_de; /* when creating dirents, nobody else | ||
92 | can alloc blocks */ | ||
93 | /*unsigned sb_mounting : 1;*/ | ||
94 | int sb_timeshift; | ||
95 | }; | ||
96 | |||
97 | /* | ||
98 | * conv= options | ||
99 | */ | ||
100 | |||
101 | #define CONV_BINARY 0 /* no conversion */ | ||
102 | #define CONV_TEXT 1 /* crlf->newline */ | ||
103 | #define CONV_AUTO 2 /* decide based on file contents */ | ||
104 | |||
105 | /* Four 512-byte buffers and the 2k block obtained by concatenating them */ | ||
106 | |||
107 | struct quad_buffer_head { | ||
108 | struct buffer_head *bh[4]; | ||
109 | void *data; | ||
110 | }; | ||
111 | |||
112 | /* The b-tree down pointer from a dir entry */ | ||
113 | |||
114 | static inline dnode_secno de_down_pointer (struct hpfs_dirent *de) | ||
115 | { | ||
116 | CHKCOND(de->down,("HPFS: de_down_pointer: !de->down\n")); | ||
117 | return *(dnode_secno *) ((void *) de + de->length - 4); | ||
118 | } | ||
119 | |||
120 | /* The first dir entry in a dnode */ | ||
121 | |||
122 | static inline struct hpfs_dirent *dnode_first_de (struct dnode *dnode) | ||
123 | { | ||
124 | return (void *) dnode->dirent; | ||
125 | } | ||
126 | |||
127 | /* The end+1 of the dir entries */ | ||
128 | |||
129 | static inline struct hpfs_dirent *dnode_end_de (struct dnode *dnode) | ||
130 | { | ||
131 | CHKCOND(dnode->first_free>=0x14 && dnode->first_free<=0xa00,("HPFS: dnode_end_de: dnode->first_free = %d\n",(int)dnode->first_free)); | ||
132 | return (void *) dnode + dnode->first_free; | ||
133 | } | ||
134 | |||
135 | /* The dir entry after dir entry de */ | ||
136 | |||
137 | static inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de) | ||
138 | { | ||
139 | CHKCOND(de->length>=0x20 && de->length<0x800,("HPFS: de_next_de: de->length = %d\n",(int)de->length)); | ||
140 | return (void *) de + de->length; | ||
141 | } | ||
142 | |||
143 | static inline struct extended_attribute *fnode_ea(struct fnode *fnode) | ||
144 | { | ||
145 | return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s); | ||
146 | } | ||
147 | |||
148 | static inline struct extended_attribute *fnode_end_ea(struct fnode *fnode) | ||
149 | { | ||
150 | return (struct extended_attribute *)((char *)fnode + fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s); | ||
151 | } | ||
152 | |||
153 | static inline struct extended_attribute *next_ea(struct extended_attribute *ea) | ||
154 | { | ||
155 | return (struct extended_attribute *)((char *)ea + 5 + ea->namelen + ea->valuelen); | ||
156 | } | ||
157 | |||
158 | static inline secno ea_sec(struct extended_attribute *ea) | ||
159 | { | ||
160 | return *(secno *)((char *)ea + 9 + ea->namelen); | ||
161 | } | ||
162 | |||
163 | static inline secno ea_len(struct extended_attribute *ea) | ||
164 | { | ||
165 | return *(secno *)((char *)ea + 5 + ea->namelen); | ||
166 | } | ||
167 | |||
168 | static inline char *ea_data(struct extended_attribute *ea) | ||
169 | { | ||
170 | return (char *)((char *)ea + 5 + ea->namelen); | ||
171 | } | ||
172 | |||
173 | static inline unsigned de_size(int namelen, secno down_ptr) | ||
174 | { | ||
175 | return ((0x1f + namelen + 3) & ~3) + (down_ptr ? 4 : 0); | ||
176 | } | ||
177 | |||
178 | static inline void copy_de(struct hpfs_dirent *dst, struct hpfs_dirent *src) | ||
179 | { | ||
180 | int a; | ||
181 | int n; | ||
182 | if (!dst || !src) return; | ||
183 | a = dst->down; | ||
184 | n = dst->not_8x3; | ||
185 | memcpy((char *)dst + 2, (char *)src + 2, 28); | ||
186 | dst->down = a; | ||
187 | dst->not_8x3 = n; | ||
188 | } | ||
189 | |||
190 | static inline unsigned tstbits(unsigned *bmp, unsigned b, unsigned n) | ||
191 | { | ||
192 | int i; | ||
193 | if ((b >= 0x4000) || (b + n - 1 >= 0x4000)) return n; | ||
194 | if (!((bmp[(b & 0x3fff) >> 5] >> (b & 0x1f)) & 1)) return 1; | ||
195 | for (i = 1; i < n; i++) | ||
196 | if (/*b+i < 0x4000 &&*/ !((bmp[((b+i) & 0x3fff) >> 5] >> ((b+i) & 0x1f)) & 1)) | ||
197 | return i + 1; | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* alloc.c */ | ||
202 | |||
203 | int hpfs_chk_sectors(struct super_block *, secno, int, char *); | ||
204 | secno hpfs_alloc_sector(struct super_block *, secno, unsigned, int, int); | ||
205 | int hpfs_alloc_if_possible(struct super_block *, secno); | ||
206 | void hpfs_free_sectors(struct super_block *, secno, unsigned); | ||
207 | int hpfs_check_free_dnodes(struct super_block *, int); | ||
208 | void hpfs_free_dnode(struct super_block *, secno); | ||
209 | struct dnode *hpfs_alloc_dnode(struct super_block *, secno, dnode_secno *, struct quad_buffer_head *, int); | ||
210 | struct fnode *hpfs_alloc_fnode(struct super_block *, secno, fnode_secno *, struct buffer_head **); | ||
211 | struct anode *hpfs_alloc_anode(struct super_block *, secno, anode_secno *, struct buffer_head **); | ||
212 | |||
213 | /* anode.c */ | ||
214 | |||
215 | secno hpfs_bplus_lookup(struct super_block *, struct inode *, struct bplus_header *, unsigned, struct buffer_head *); | ||
216 | secno hpfs_add_sector_to_btree(struct super_block *, secno, int, unsigned); | ||
217 | void hpfs_remove_btree(struct super_block *, struct bplus_header *); | ||
218 | int hpfs_ea_read(struct super_block *, secno, int, unsigned, unsigned, char *); | ||
219 | int hpfs_ea_write(struct super_block *, secno, int, unsigned, unsigned, char *); | ||
220 | void hpfs_ea_remove(struct super_block *, secno, int, unsigned); | ||
221 | void hpfs_truncate_btree(struct super_block *, secno, int, unsigned); | ||
222 | void hpfs_remove_fnode(struct super_block *, fnode_secno fno); | ||
223 | |||
224 | /* buffer.c */ | ||
225 | |||
226 | void hpfs_lock_creation(struct super_block *); | ||
227 | void hpfs_unlock_creation(struct super_block *); | ||
228 | void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int); | ||
229 | void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **); | ||
230 | void *hpfs_map_4sectors(struct super_block *, unsigned, struct quad_buffer_head *, int); | ||
231 | void *hpfs_get_4sectors(struct super_block *, unsigned, struct quad_buffer_head *); | ||
232 | void hpfs_brelse4(struct quad_buffer_head *); | ||
233 | void hpfs_mark_4buffers_dirty(struct quad_buffer_head *); | ||
234 | |||
235 | /* dentry.c */ | ||
236 | |||
237 | void hpfs_set_dentry_operations(struct dentry *); | ||
238 | |||
239 | /* dir.c */ | ||
240 | |||
241 | struct dentry *hpfs_lookup(struct inode *, struct dentry *, struct nameidata *); | ||
242 | extern struct file_operations hpfs_dir_ops; | ||
243 | |||
244 | /* dnode.c */ | ||
245 | |||
246 | void hpfs_add_pos(struct inode *, loff_t *); | ||
247 | void hpfs_del_pos(struct inode *, loff_t *); | ||
248 | struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *, unsigned char *, unsigned, secno); | ||
249 | int hpfs_add_dirent(struct inode *, unsigned char *, unsigned, struct hpfs_dirent *, int); | ||
250 | int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int); | ||
251 | void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *); | ||
252 | dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno); | ||
253 | struct hpfs_dirent *map_pos_dirent(struct inode *, loff_t *, struct quad_buffer_head *); | ||
254 | struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *); | ||
255 | void hpfs_remove_dtree(struct super_block *, dnode_secno); | ||
256 | struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct fnode *, struct quad_buffer_head *); | ||
257 | |||
258 | /* ea.c */ | ||
259 | |||
260 | void hpfs_ea_ext_remove(struct super_block *, secno, int, unsigned); | ||
261 | int hpfs_read_ea(struct super_block *, struct fnode *, char *, char *, int); | ||
262 | char *hpfs_get_ea(struct super_block *, struct fnode *, char *, int *); | ||
263 | void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int); | ||
264 | |||
265 | /* file.c */ | ||
266 | |||
267 | int hpfs_file_fsync(struct file *, struct dentry *, int); | ||
268 | extern struct file_operations hpfs_file_ops; | ||
269 | extern struct inode_operations hpfs_file_iops; | ||
270 | extern struct address_space_operations hpfs_aops; | ||
271 | |||
272 | /* inode.c */ | ||
273 | |||
274 | void hpfs_init_inode(struct inode *); | ||
275 | void hpfs_read_inode(struct inode *); | ||
276 | void hpfs_write_inode(struct inode *); | ||
277 | void hpfs_write_inode_nolock(struct inode *); | ||
278 | int hpfs_notify_change(struct dentry *, struct iattr *); | ||
279 | void hpfs_write_if_changed(struct inode *); | ||
280 | void hpfs_delete_inode(struct inode *); | ||
281 | |||
282 | /* map.c */ | ||
283 | |||
284 | unsigned *hpfs_map_dnode_bitmap(struct super_block *, struct quad_buffer_head *); | ||
285 | unsigned *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head *, char *); | ||
286 | char *hpfs_load_code_page(struct super_block *, secno); | ||
287 | secno *hpfs_load_bitmap_directory(struct super_block *, secno bmp); | ||
288 | struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **); | ||
289 | struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **); | ||
290 | struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *); | ||
291 | dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino); | ||
292 | |||
293 | /* name.c */ | ||
294 | |||
295 | unsigned char hpfs_upcase(unsigned char *, unsigned char); | ||
296 | int hpfs_chk_name(unsigned char *, unsigned *); | ||
297 | char *hpfs_translate_name(struct super_block *, unsigned char *, unsigned, int, int); | ||
298 | int hpfs_compare_names(struct super_block *, unsigned char *, unsigned, unsigned char *, unsigned, int); | ||
299 | int hpfs_is_name_long(unsigned char *, unsigned); | ||
300 | void hpfs_adjust_length(unsigned char *, unsigned *); | ||
301 | void hpfs_decide_conv(struct inode *, unsigned char *, unsigned); | ||
302 | |||
303 | /* namei.c */ | ||
304 | |||
305 | extern struct inode_operations hpfs_dir_iops; | ||
306 | extern struct address_space_operations hpfs_symlink_aops; | ||
307 | |||
308 | static inline struct hpfs_inode_info *hpfs_i(struct inode *inode) | ||
309 | { | ||
310 | return list_entry(inode, struct hpfs_inode_info, vfs_inode); | ||
311 | } | ||
312 | |||
313 | static inline struct hpfs_sb_info *hpfs_sb(struct super_block *sb) | ||
314 | { | ||
315 | return sb->s_fs_info; | ||
316 | } | ||
317 | |||
318 | /* super.c */ | ||
319 | |||
320 | void hpfs_error(struct super_block *, char *, ...); | ||
321 | int hpfs_stop_cycles(struct super_block *, int, int *, int *, char *); | ||
322 | unsigned hpfs_count_one_bitmap(struct super_block *, secno); | ||
323 | |||
324 | /* | ||
325 | * local time (HPFS) to GMT (Unix) | ||
326 | */ | ||
327 | |||
328 | static inline time_t local_to_gmt(struct super_block *s, time32_t t) | ||
329 | { | ||
330 | extern struct timezone sys_tz; | ||
331 | return t + sys_tz.tz_minuteswest * 60 + hpfs_sb(s)->sb_timeshift; | ||
332 | } | ||
333 | |||
334 | static inline time32_t gmt_to_local(struct super_block *s, time_t t) | ||
335 | { | ||
336 | extern struct timezone sys_tz; | ||
337 | return t - sys_tz.tz_minuteswest * 60 - hpfs_sb(s)->sb_timeshift; | ||
338 | } | ||
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c new file mode 100644 index 000000000000..38b1741fa539 --- /dev/null +++ b/fs/hpfs/inode.c | |||
@@ -0,0 +1,291 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/inode.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * inode VFS functions | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | void hpfs_init_inode(struct inode *i) | ||
12 | { | ||
13 | struct super_block *sb = i->i_sb; | ||
14 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
15 | |||
16 | i->i_uid = hpfs_sb(sb)->sb_uid; | ||
17 | i->i_gid = hpfs_sb(sb)->sb_gid; | ||
18 | i->i_mode = hpfs_sb(sb)->sb_mode; | ||
19 | hpfs_inode->i_conv = hpfs_sb(sb)->sb_conv; | ||
20 | i->i_blksize = 512; | ||
21 | i->i_size = -1; | ||
22 | i->i_blocks = -1; | ||
23 | |||
24 | hpfs_inode->i_dno = 0; | ||
25 | hpfs_inode->i_n_secs = 0; | ||
26 | hpfs_inode->i_file_sec = 0; | ||
27 | hpfs_inode->i_disk_sec = 0; | ||
28 | hpfs_inode->i_dpos = 0; | ||
29 | hpfs_inode->i_dsubdno = 0; | ||
30 | hpfs_inode->i_ea_mode = 0; | ||
31 | hpfs_inode->i_ea_uid = 0; | ||
32 | hpfs_inode->i_ea_gid = 0; | ||
33 | hpfs_inode->i_ea_size = 0; | ||
34 | |||
35 | hpfs_inode->i_rddir_off = NULL; | ||
36 | hpfs_inode->i_dirty = 0; | ||
37 | |||
38 | i->i_ctime.tv_sec = i->i_ctime.tv_nsec = 0; | ||
39 | i->i_mtime.tv_sec = i->i_mtime.tv_nsec = 0; | ||
40 | i->i_atime.tv_sec = i->i_atime.tv_nsec = 0; | ||
41 | } | ||
42 | |||
43 | void hpfs_read_inode(struct inode *i) | ||
44 | { | ||
45 | struct buffer_head *bh; | ||
46 | struct fnode *fnode; | ||
47 | struct super_block *sb = i->i_sb; | ||
48 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
49 | unsigned char *ea; | ||
50 | int ea_size; | ||
51 | |||
52 | if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) { | ||
53 | /*i->i_mode |= S_IFREG; | ||
54 | i->i_mode &= ~0111; | ||
55 | i->i_op = &hpfs_file_iops; | ||
56 | i->i_fop = &hpfs_file_ops; | ||
57 | i->i_nlink = 0;*/ | ||
58 | make_bad_inode(i); | ||
59 | return; | ||
60 | } | ||
61 | if (hpfs_sb(i->i_sb)->sb_eas) { | ||
62 | if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) { | ||
63 | if (ea_size == 2) { | ||
64 | i->i_uid = le16_to_cpu(*(u16*)ea); | ||
65 | hpfs_inode->i_ea_uid = 1; | ||
66 | } | ||
67 | kfree(ea); | ||
68 | } | ||
69 | if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) { | ||
70 | if (ea_size == 2) { | ||
71 | i->i_gid = le16_to_cpu(*(u16*)ea); | ||
72 | hpfs_inode->i_ea_gid = 1; | ||
73 | } | ||
74 | kfree(ea); | ||
75 | } | ||
76 | if ((ea = hpfs_get_ea(i->i_sb, fnode, "SYMLINK", &ea_size))) { | ||
77 | kfree(ea); | ||
78 | i->i_mode = S_IFLNK | 0777; | ||
79 | i->i_op = &page_symlink_inode_operations; | ||
80 | i->i_data.a_ops = &hpfs_symlink_aops; | ||
81 | i->i_nlink = 1; | ||
82 | i->i_size = ea_size; | ||
83 | i->i_blocks = 1; | ||
84 | brelse(bh); | ||
85 | return; | ||
86 | } | ||
87 | if ((ea = hpfs_get_ea(i->i_sb, fnode, "MODE", &ea_size))) { | ||
88 | int rdev = 0; | ||
89 | umode_t mode = hpfs_sb(sb)->sb_mode; | ||
90 | if (ea_size == 2) { | ||
91 | mode = le16_to_cpu(*(u16*)ea); | ||
92 | hpfs_inode->i_ea_mode = 1; | ||
93 | } | ||
94 | kfree(ea); | ||
95 | i->i_mode = mode; | ||
96 | if (S_ISBLK(mode) || S_ISCHR(mode)) { | ||
97 | if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) { | ||
98 | if (ea_size == 4) | ||
99 | rdev = le32_to_cpu(*(u32*)ea); | ||
100 | kfree(ea); | ||
101 | } | ||
102 | } | ||
103 | if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { | ||
104 | brelse(bh); | ||
105 | i->i_nlink = 1; | ||
106 | i->i_size = 0; | ||
107 | i->i_blocks = 1; | ||
108 | init_special_inode(i, mode, | ||
109 | new_decode_dev(rdev)); | ||
110 | return; | ||
111 | } | ||
112 | } | ||
113 | } | ||
114 | if (fnode->dirflag) { | ||
115 | unsigned n_dnodes, n_subdirs; | ||
116 | i->i_mode |= S_IFDIR; | ||
117 | i->i_op = &hpfs_dir_iops; | ||
118 | i->i_fop = &hpfs_dir_ops; | ||
119 | hpfs_inode->i_parent_dir = fnode->up; | ||
120 | hpfs_inode->i_dno = fnode->u.external[0].disk_secno; | ||
121 | if (hpfs_sb(sb)->sb_chk >= 2) { | ||
122 | struct buffer_head *bh0; | ||
123 | if (hpfs_map_fnode(sb, hpfs_inode->i_parent_dir, &bh0)) brelse(bh0); | ||
124 | } | ||
125 | n_dnodes = 0; n_subdirs = 0; | ||
126 | hpfs_count_dnodes(i->i_sb, hpfs_inode->i_dno, &n_dnodes, &n_subdirs, NULL); | ||
127 | i->i_blocks = 4 * n_dnodes; | ||
128 | i->i_size = 2048 * n_dnodes; | ||
129 | i->i_nlink = 2 + n_subdirs; | ||
130 | } else { | ||
131 | i->i_mode |= S_IFREG; | ||
132 | if (!hpfs_inode->i_ea_mode) i->i_mode &= ~0111; | ||
133 | i->i_op = &hpfs_file_iops; | ||
134 | i->i_fop = &hpfs_file_ops; | ||
135 | i->i_nlink = 1; | ||
136 | i->i_size = fnode->file_size; | ||
137 | i->i_blocks = ((i->i_size + 511) >> 9) + 1; | ||
138 | i->i_data.a_ops = &hpfs_aops; | ||
139 | hpfs_i(i)->mmu_private = i->i_size; | ||
140 | } | ||
141 | brelse(bh); | ||
142 | } | ||
143 | |||
144 | static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode) | ||
145 | { | ||
146 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
147 | /*if (fnode->acl_size_l || fnode->acl_size_s) { | ||
148 | Some unknown structures like ACL may be in fnode, | ||
149 | we'd better not overwrite them | ||
150 | hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino); | ||
151 | } else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) { | ||
152 | u32 ea; | ||
153 | if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) { | ||
154 | ea = cpu_to_le32(i->i_uid); | ||
155 | hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2); | ||
156 | hpfs_inode->i_ea_uid = 1; | ||
157 | } | ||
158 | if ((i->i_gid != hpfs_sb(i->i_sb)->sb_gid) || hpfs_inode->i_ea_gid) { | ||
159 | ea = cpu_to_le32(i->i_gid); | ||
160 | hpfs_set_ea(i, fnode, "GID", (char *)&ea, 2); | ||
161 | hpfs_inode->i_ea_gid = 1; | ||
162 | } | ||
163 | if (!S_ISLNK(i->i_mode)) | ||
164 | if ((i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0 : 0111)) | ||
165 | | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG)) | ||
166 | && i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333)) | ||
167 | | (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) { | ||
168 | ea = cpu_to_le32(i->i_mode); | ||
169 | hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2); | ||
170 | hpfs_inode->i_ea_mode = 1; | ||
171 | } | ||
172 | if (S_ISBLK(i->i_mode) || S_ISCHR(i->i_mode)) { | ||
173 | ea = cpu_to_le32(new_encode_dev(i->i_rdev)); | ||
174 | hpfs_set_ea(i, fnode, "DEV", (char *)&ea, 4); | ||
175 | } | ||
176 | } | ||
177 | } | ||
178 | |||
179 | void hpfs_write_inode(struct inode *i) | ||
180 | { | ||
181 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
182 | struct inode *parent; | ||
183 | if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return; | ||
184 | if (hpfs_inode->i_rddir_off && !atomic_read(&i->i_count)) { | ||
185 | if (*hpfs_inode->i_rddir_off) printk("HPFS: write_inode: some position still there\n"); | ||
186 | kfree(hpfs_inode->i_rddir_off); | ||
187 | hpfs_inode->i_rddir_off = NULL; | ||
188 | } | ||
189 | down(&hpfs_inode->i_parent); | ||
190 | if (!i->i_nlink) { | ||
191 | up(&hpfs_inode->i_parent); | ||
192 | return; | ||
193 | } | ||
194 | parent = iget_locked(i->i_sb, hpfs_inode->i_parent_dir); | ||
195 | if (parent) { | ||
196 | hpfs_inode->i_dirty = 0; | ||
197 | if (parent->i_state & I_NEW) { | ||
198 | hpfs_init_inode(parent); | ||
199 | hpfs_read_inode(parent); | ||
200 | unlock_new_inode(parent); | ||
201 | } | ||
202 | down(&hpfs_inode->i_sem); | ||
203 | hpfs_write_inode_nolock(i); | ||
204 | up(&hpfs_inode->i_sem); | ||
205 | iput(parent); | ||
206 | } else { | ||
207 | mark_inode_dirty(i); | ||
208 | } | ||
209 | up(&hpfs_inode->i_parent); | ||
210 | } | ||
211 | |||
212 | void hpfs_write_inode_nolock(struct inode *i) | ||
213 | { | ||
214 | struct hpfs_inode_info *hpfs_inode = hpfs_i(i); | ||
215 | struct buffer_head *bh; | ||
216 | struct fnode *fnode; | ||
217 | struct quad_buffer_head qbh; | ||
218 | struct hpfs_dirent *de; | ||
219 | if (i->i_ino == hpfs_sb(i->i_sb)->sb_root) return; | ||
220 | if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) return; | ||
221 | if (i->i_ino != hpfs_sb(i->i_sb)->sb_root && i->i_nlink) { | ||
222 | if (!(de = map_fnode_dirent(i->i_sb, i->i_ino, fnode, &qbh))) { | ||
223 | brelse(bh); | ||
224 | return; | ||
225 | } | ||
226 | } else de = NULL; | ||
227 | if (S_ISREG(i->i_mode)) { | ||
228 | fnode->file_size = i->i_size; | ||
229 | if (de) de->file_size = i->i_size; | ||
230 | } else if (S_ISDIR(i->i_mode)) { | ||
231 | fnode->file_size = 0; | ||
232 | if (de) de->file_size = 0; | ||
233 | } | ||
234 | hpfs_write_inode_ea(i, fnode); | ||
235 | if (de) { | ||
236 | de->write_date = gmt_to_local(i->i_sb, i->i_mtime.tv_sec); | ||
237 | de->read_date = gmt_to_local(i->i_sb, i->i_atime.tv_sec); | ||
238 | de->creation_date = gmt_to_local(i->i_sb, i->i_ctime.tv_sec); | ||
239 | de->read_only = !(i->i_mode & 0222); | ||
240 | de->ea_size = hpfs_inode->i_ea_size; | ||
241 | hpfs_mark_4buffers_dirty(&qbh); | ||
242 | hpfs_brelse4(&qbh); | ||
243 | } | ||
244 | if (S_ISDIR(i->i_mode)) { | ||
245 | if ((de = map_dirent(i, hpfs_inode->i_dno, "\001\001", 2, NULL, &qbh))) { | ||
246 | de->write_date = gmt_to_local(i->i_sb, i->i_mtime.tv_sec); | ||
247 | de->read_date = gmt_to_local(i->i_sb, i->i_atime.tv_sec); | ||
248 | de->creation_date = gmt_to_local(i->i_sb, i->i_ctime.tv_sec); | ||
249 | de->read_only = !(i->i_mode & 0222); | ||
250 | de->ea_size = /*hpfs_inode->i_ea_size*/0; | ||
251 | de->file_size = 0; | ||
252 | hpfs_mark_4buffers_dirty(&qbh); | ||
253 | hpfs_brelse4(&qbh); | ||
254 | } else hpfs_error(i->i_sb, "directory %08x doesn't have '.' entry", i->i_ino); | ||
255 | } | ||
256 | mark_buffer_dirty(bh); | ||
257 | brelse(bh); | ||
258 | } | ||
259 | |||
260 | int hpfs_notify_change(struct dentry *dentry, struct iattr *attr) | ||
261 | { | ||
262 | struct inode *inode = dentry->d_inode; | ||
263 | int error=0; | ||
264 | lock_kernel(); | ||
265 | if ( ((attr->ia_valid & ATTR_SIZE) && attr->ia_size > inode->i_size) || | ||
266 | (hpfs_sb(inode->i_sb)->sb_root == inode->i_ino) ) { | ||
267 | error = -EINVAL; | ||
268 | } else if ((error = inode_change_ok(inode, attr))) { | ||
269 | } else if ((error = inode_setattr(inode, attr))) { | ||
270 | } else { | ||
271 | hpfs_write_inode(inode); | ||
272 | } | ||
273 | unlock_kernel(); | ||
274 | return error; | ||
275 | } | ||
276 | |||
277 | void hpfs_write_if_changed(struct inode *inode) | ||
278 | { | ||
279 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
280 | |||
281 | if (hpfs_inode->i_dirty) | ||
282 | hpfs_write_inode(inode); | ||
283 | } | ||
284 | |||
285 | void hpfs_delete_inode(struct inode *inode) | ||
286 | { | ||
287 | lock_kernel(); | ||
288 | hpfs_remove_fnode(inode->i_sb, inode->i_ino); | ||
289 | unlock_kernel(); | ||
290 | clear_inode(inode); | ||
291 | } | ||
diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c new file mode 100644 index 000000000000..0fecdac22e4e --- /dev/null +++ b/fs/hpfs/map.c | |||
@@ -0,0 +1,275 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/map.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * mapping structures to memory with some minimal checks | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | unsigned *hpfs_map_dnode_bitmap(struct super_block *s, struct quad_buffer_head *qbh) | ||
12 | { | ||
13 | return hpfs_map_4sectors(s, hpfs_sb(s)->sb_dmap, qbh, 0); | ||
14 | } | ||
15 | |||
16 | unsigned int *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block, | ||
17 | struct quad_buffer_head *qbh, char *id) | ||
18 | { | ||
19 | secno sec; | ||
20 | if (hpfs_sb(s)->sb_chk) if (bmp_block * 16384 > hpfs_sb(s)->sb_fs_size) { | ||
21 | hpfs_error(s, "hpfs_map_bitmap called with bad parameter: %08x at %s", bmp_block, id); | ||
22 | return NULL; | ||
23 | } | ||
24 | sec = hpfs_sb(s)->sb_bmp_dir[bmp_block]; | ||
25 | if (!sec || sec > hpfs_sb(s)->sb_fs_size-4) { | ||
26 | hpfs_error(s, "invalid bitmap block pointer %08x -> %08x at %s", bmp_block, sec, id); | ||
27 | return NULL; | ||
28 | } | ||
29 | return hpfs_map_4sectors(s, sec, qbh, 4); | ||
30 | } | ||
31 | |||
32 | /* | ||
33 | * Load first code page into kernel memory, return pointer to 256-byte array, | ||
34 | * first 128 bytes are uppercasing table for chars 128-255, next 128 bytes are | ||
35 | * lowercasing table | ||
36 | */ | ||
37 | |||
38 | char *hpfs_load_code_page(struct super_block *s, secno cps) | ||
39 | { | ||
40 | struct buffer_head *bh; | ||
41 | secno cpds; | ||
42 | unsigned cpi; | ||
43 | unsigned char *ptr; | ||
44 | unsigned char *cp_table; | ||
45 | int i; | ||
46 | struct code_page_data *cpd; | ||
47 | struct code_page_directory *cp = hpfs_map_sector(s, cps, &bh, 0); | ||
48 | if (!cp) return NULL; | ||
49 | if (cp->magic != CP_DIR_MAGIC) { | ||
50 | printk("HPFS: Code page directory magic doesn't match (magic = %08x)\n", cp->magic); | ||
51 | brelse(bh); | ||
52 | return NULL; | ||
53 | } | ||
54 | if (!cp->n_code_pages) { | ||
55 | printk("HPFS: n_code_pages == 0\n"); | ||
56 | brelse(bh); | ||
57 | return NULL; | ||
58 | } | ||
59 | cpds = cp->array[0].code_page_data; | ||
60 | cpi = cp->array[0].index; | ||
61 | brelse(bh); | ||
62 | |||
63 | if (cpi >= 3) { | ||
64 | printk("HPFS: Code page index out of array\n"); | ||
65 | return NULL; | ||
66 | } | ||
67 | |||
68 | if (!(cpd = hpfs_map_sector(s, cpds, &bh, 0))) return NULL; | ||
69 | if ((unsigned)cpd->offs[cpi] > 0x178) { | ||
70 | printk("HPFS: Code page index out of sector\n"); | ||
71 | brelse(bh); | ||
72 | return NULL; | ||
73 | } | ||
74 | ptr = (char *)cpd + cpd->offs[cpi] + 6; | ||
75 | if (!(cp_table = kmalloc(256, GFP_KERNEL))) { | ||
76 | printk("HPFS: out of memory for code page table\n"); | ||
77 | brelse(bh); | ||
78 | return NULL; | ||
79 | } | ||
80 | memcpy(cp_table, ptr, 128); | ||
81 | brelse(bh); | ||
82 | |||
83 | /* Try to build lowercasing table from uppercasing one */ | ||
84 | |||
85 | for (i=128; i<256; i++) cp_table[i]=i; | ||
86 | for (i=128; i<256; i++) if (cp_table[i-128]!=i && cp_table[i-128]>=128) | ||
87 | cp_table[cp_table[i-128]] = i; | ||
88 | |||
89 | return cp_table; | ||
90 | } | ||
91 | |||
92 | secno *hpfs_load_bitmap_directory(struct super_block *s, secno bmp) | ||
93 | { | ||
94 | struct buffer_head *bh; | ||
95 | int n = (hpfs_sb(s)->sb_fs_size + 0x200000 - 1) >> 21; | ||
96 | int i; | ||
97 | secno *b; | ||
98 | if (!(b = kmalloc(n * 512, GFP_KERNEL))) { | ||
99 | printk("HPFS: can't allocate memory for bitmap directory\n"); | ||
100 | return NULL; | ||
101 | } | ||
102 | for (i=0;i<n;i++) { | ||
103 | secno *d = hpfs_map_sector(s, bmp+i, &bh, n - i - 1); | ||
104 | if (!d) { | ||
105 | kfree(b); | ||
106 | return NULL; | ||
107 | } | ||
108 | memcpy((char *)b + 512 * i, d, 512); | ||
109 | brelse(bh); | ||
110 | } | ||
111 | return b; | ||
112 | } | ||
113 | |||
114 | /* | ||
115 | * Load fnode to memory | ||
116 | */ | ||
117 | |||
118 | struct fnode *hpfs_map_fnode(struct super_block *s, ino_t ino, struct buffer_head **bhp) | ||
119 | { | ||
120 | struct fnode *fnode; | ||
121 | if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, ino, 1, "fnode")) { | ||
122 | return NULL; | ||
123 | } | ||
124 | if ((fnode = hpfs_map_sector(s, ino, bhp, FNODE_RD_AHEAD))) { | ||
125 | if (hpfs_sb(s)->sb_chk) { | ||
126 | struct extended_attribute *ea; | ||
127 | struct extended_attribute *ea_end; | ||
128 | if (fnode->magic != FNODE_MAGIC) { | ||
129 | hpfs_error(s, "bad magic on fnode %08x", ino); | ||
130 | goto bail; | ||
131 | } | ||
132 | if (!fnode->dirflag) { | ||
133 | if ((unsigned)fnode->btree.n_used_nodes + (unsigned)fnode->btree.n_free_nodes != | ||
134 | (fnode->btree.internal ? 12 : 8)) { | ||
135 | hpfs_error(s, "bad number of nodes in fnode %08x", ino); | ||
136 | goto bail; | ||
137 | } | ||
138 | if (fnode->btree.first_free != | ||
139 | 8 + fnode->btree.n_used_nodes * (fnode->btree.internal ? 8 : 12)) { | ||
140 | hpfs_error(s, "bad first_free pointer in fnode %08x", ino); | ||
141 | goto bail; | ||
142 | } | ||
143 | } | ||
144 | if (fnode->ea_size_s && ((signed int)fnode->ea_offs < 0xc4 || | ||
145 | (signed int)fnode->ea_offs + fnode->acl_size_s + fnode->ea_size_s > 0x200)) { | ||
146 | hpfs_error(s, "bad EA info in fnode %08x: ea_offs == %04x ea_size_s == %04x", | ||
147 | ino, fnode->ea_offs, fnode->ea_size_s); | ||
148 | goto bail; | ||
149 | } | ||
150 | ea = fnode_ea(fnode); | ||
151 | ea_end = fnode_end_ea(fnode); | ||
152 | while (ea != ea_end) { | ||
153 | if (ea > ea_end) { | ||
154 | hpfs_error(s, "bad EA in fnode %08x", ino); | ||
155 | goto bail; | ||
156 | } | ||
157 | ea = next_ea(ea); | ||
158 | } | ||
159 | } | ||
160 | } | ||
161 | return fnode; | ||
162 | bail: | ||
163 | brelse(*bhp); | ||
164 | return NULL; | ||
165 | } | ||
166 | |||
167 | struct anode *hpfs_map_anode(struct super_block *s, anode_secno ano, struct buffer_head **bhp) | ||
168 | { | ||
169 | struct anode *anode; | ||
170 | if (hpfs_sb(s)->sb_chk) if (hpfs_chk_sectors(s, ano, 1, "anode")) return NULL; | ||
171 | if ((anode = hpfs_map_sector(s, ano, bhp, ANODE_RD_AHEAD))) | ||
172 | if (hpfs_sb(s)->sb_chk) { | ||
173 | if (anode->magic != ANODE_MAGIC || anode->self != ano) { | ||
174 | hpfs_error(s, "bad magic on anode %08x", ano); | ||
175 | goto bail; | ||
176 | } | ||
177 | if ((unsigned)anode->btree.n_used_nodes + (unsigned)anode->btree.n_free_nodes != | ||
178 | (anode->btree.internal ? 60 : 40)) { | ||
179 | hpfs_error(s, "bad number of nodes in anode %08x", ano); | ||
180 | goto bail; | ||
181 | } | ||
182 | if (anode->btree.first_free != | ||
183 | 8 + anode->btree.n_used_nodes * (anode->btree.internal ? 8 : 12)) { | ||
184 | hpfs_error(s, "bad first_free pointer in anode %08x", ano); | ||
185 | goto bail; | ||
186 | } | ||
187 | } | ||
188 | return anode; | ||
189 | bail: | ||
190 | brelse(*bhp); | ||
191 | return NULL; | ||
192 | } | ||
193 | |||
194 | /* | ||
195 | * Load dnode to memory and do some checks | ||
196 | */ | ||
197 | |||
198 | struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno, | ||
199 | struct quad_buffer_head *qbh) | ||
200 | { | ||
201 | struct dnode *dnode; | ||
202 | if (hpfs_sb(s)->sb_chk) { | ||
203 | if (hpfs_chk_sectors(s, secno, 4, "dnode")) return NULL; | ||
204 | if (secno & 3) { | ||
205 | hpfs_error(s, "dnode %08x not byte-aligned", secno); | ||
206 | return NULL; | ||
207 | } | ||
208 | } | ||
209 | if ((dnode = hpfs_map_4sectors(s, secno, qbh, DNODE_RD_AHEAD))) | ||
210 | if (hpfs_sb(s)->sb_chk) { | ||
211 | unsigned p, pp = 0; | ||
212 | unsigned char *d = (char *)dnode; | ||
213 | int b = 0; | ||
214 | if (dnode->magic != DNODE_MAGIC) { | ||
215 | hpfs_error(s, "bad magic on dnode %08x", secno); | ||
216 | goto bail; | ||
217 | } | ||
218 | if (dnode->self != secno) | ||
219 | hpfs_error(s, "bad self pointer on dnode %08x self = %08x", secno, dnode->self); | ||
220 | /* Check dirents - bad dirents would cause infinite | ||
221 | loops or shooting to memory */ | ||
222 | if (dnode->first_free > 2048/* || dnode->first_free < 84*/) { | ||
223 | hpfs_error(s, "dnode %08x has first_free == %08x", secno, dnode->first_free); | ||
224 | goto bail; | ||
225 | } | ||
226 | for (p = 20; p < dnode->first_free; p += d[p] + (d[p+1] << 8)) { | ||
227 | struct hpfs_dirent *de = (struct hpfs_dirent *)((char *)dnode + p); | ||
228 | if (de->length > 292 || (de->length < 32) || (de->length & 3) || p + de->length > 2048) { | ||
229 | hpfs_error(s, "bad dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp); | ||
230 | goto bail; | ||
231 | } | ||
232 | if (((31 + de->namelen + de->down*4 + 3) & ~3) != de->length) { | ||
233 | if (((31 + de->namelen + de->down*4 + 3) & ~3) < de->length && s->s_flags & MS_RDONLY) goto ok; | ||
234 | hpfs_error(s, "namelen does not match dirent size in dnode %08x, dirent %03x, last %03x", secno, p, pp); | ||
235 | goto bail; | ||
236 | } | ||
237 | ok: | ||
238 | if (hpfs_sb(s)->sb_chk >= 2) b |= 1 << de->down; | ||
239 | if (de->down) if (de_down_pointer(de) < 0x10) { | ||
240 | hpfs_error(s, "bad down pointer in dnode %08x, dirent %03x, last %03x", secno, p, pp); | ||
241 | goto bail; | ||
242 | } | ||
243 | pp = p; | ||
244 | |||
245 | } | ||
246 | if (p != dnode->first_free) { | ||
247 | hpfs_error(s, "size on last dirent does not match first_free; dnode %08x", secno); | ||
248 | goto bail; | ||
249 | } | ||
250 | if (d[pp + 30] != 1 || d[pp + 31] != 255) { | ||
251 | hpfs_error(s, "dnode %08x does not end with \\377 entry", secno); | ||
252 | goto bail; | ||
253 | } | ||
254 | if (b == 3) printk("HPFS: warning: unbalanced dnode tree, dnode %08x; see hpfs.txt 4 more info\n", secno); | ||
255 | } | ||
256 | return dnode; | ||
257 | bail: | ||
258 | hpfs_brelse4(qbh); | ||
259 | return NULL; | ||
260 | } | ||
261 | |||
262 | dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino) | ||
263 | { | ||
264 | struct buffer_head *bh; | ||
265 | struct fnode *fnode; | ||
266 | dnode_secno dno; | ||
267 | |||
268 | fnode = hpfs_map_fnode(s, ino, &bh); | ||
269 | if (!fnode) | ||
270 | return 0; | ||
271 | |||
272 | dno = fnode->u.external[0].disk_secno; | ||
273 | brelse(bh); | ||
274 | return dno; | ||
275 | } | ||
diff --git a/fs/hpfs/name.c b/fs/hpfs/name.c new file mode 100644 index 000000000000..1f4a964384eb --- /dev/null +++ b/fs/hpfs/name.c | |||
@@ -0,0 +1,144 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/name.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * operations with filenames | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | static char *text_postfix[]={ | ||
12 | ".ASM", ".BAS", ".BAT", ".C", ".CC", ".CFG", ".CMD", ".CON", ".CPP", ".DEF", | ||
13 | ".DOC", ".DPR", ".ERX", ".H", ".HPP", ".HTM", ".HTML", ".JAVA", ".LOG", ".PAS", | ||
14 | ".RC", ".TEX", ".TXT", ".Y", ""}; | ||
15 | |||
16 | static char *text_prefix[]={ | ||
17 | "AUTOEXEC.", "CHANGES", "COPYING", "CONFIG.", "CREDITS", "FAQ", "FILE_ID.DIZ", | ||
18 | "MAKEFILE", "READ.ME", "README", "TERMCAP", ""}; | ||
19 | |||
20 | void hpfs_decide_conv(struct inode *inode, unsigned char *name, unsigned len) | ||
21 | { | ||
22 | struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); | ||
23 | int i; | ||
24 | if (hpfs_inode->i_conv != CONV_AUTO) return; | ||
25 | for (i = 0; *text_postfix[i]; i++) { | ||
26 | int l = strlen(text_postfix[i]); | ||
27 | if (l <= len) | ||
28 | if (!hpfs_compare_names(inode->i_sb, text_postfix[i], l, name + len - l, l, 0)) | ||
29 | goto text; | ||
30 | } | ||
31 | for (i = 0; *text_prefix[i]; i++) { | ||
32 | int l = strlen(text_prefix[i]); | ||
33 | if (l <= len) | ||
34 | if (!hpfs_compare_names(inode->i_sb, text_prefix[i], l, name, l, 0)) | ||
35 | goto text; | ||
36 | } | ||
37 | hpfs_inode->i_conv = CONV_BINARY; | ||
38 | return; | ||
39 | text: | ||
40 | hpfs_inode->i_conv = CONV_TEXT; | ||
41 | return; | ||
42 | } | ||
43 | |||
44 | static inline int not_allowed_char(unsigned char c) | ||
45 | { | ||
46 | return c<' ' || c=='"' || c=='*' || c=='/' || c==':' || c=='<' || | ||
47 | c=='>' || c=='?' || c=='\\' || c=='|'; | ||
48 | } | ||
49 | |||
50 | static inline int no_dos_char(unsigned char c) | ||
51 | { /* Characters that are allowed in HPFS but not in DOS */ | ||
52 | return c=='+' || c==',' || c==';' || c=='=' || c=='[' || c==']'; | ||
53 | } | ||
54 | |||
55 | static inline unsigned char upcase(unsigned char *dir, unsigned char a) | ||
56 | { | ||
57 | if (a<128 || a==255) return a>='a' && a<='z' ? a - 0x20 : a; | ||
58 | if (!dir) return a; | ||
59 | return dir[a-128]; | ||
60 | } | ||
61 | |||
62 | unsigned char hpfs_upcase(unsigned char *dir, unsigned char a) | ||
63 | { | ||
64 | return upcase(dir, a); | ||
65 | } | ||
66 | |||
67 | static inline unsigned char locase(unsigned char *dir, unsigned char a) | ||
68 | { | ||
69 | if (a<128 || a==255) return a>='A' && a<='Z' ? a + 0x20 : a; | ||
70 | if (!dir) return a; | ||
71 | return dir[a]; | ||
72 | } | ||
73 | |||
74 | int hpfs_chk_name(unsigned char *name, unsigned *len) | ||
75 | { | ||
76 | int i; | ||
77 | if (*len > 254) return -ENAMETOOLONG; | ||
78 | hpfs_adjust_length(name, len); | ||
79 | if (!*len) return -EINVAL; | ||
80 | for (i = 0; i < *len; i++) if (not_allowed_char(name[i])) return -EINVAL; | ||
81 | if (*len == 1) if (name[0] == '.') return -EINVAL; | ||
82 | if (*len == 2) if (name[0] == '.' && name[1] == '.') return -EINVAL; | ||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | char *hpfs_translate_name(struct super_block *s, unsigned char *from, | ||
87 | unsigned len, int lc, int lng) | ||
88 | { | ||
89 | char *to; | ||
90 | int i; | ||
91 | if (hpfs_sb(s)->sb_chk >= 2) if (hpfs_is_name_long(from, len) != lng) { | ||
92 | printk("HPFS: Long name flag mismatch - name "); | ||
93 | for (i=0; i<len; i++) printk("%c", from[i]); | ||
94 | printk(" misidentified as %s.\n", lng ? "short" : "long"); | ||
95 | printk("HPFS: It's nothing serious. It could happen because of bug in OS/2.\nHPFS: Set checks=normal to disable this message.\n"); | ||
96 | } | ||
97 | if (!lc) return from; | ||
98 | if (!(to = kmalloc(len, GFP_KERNEL))) { | ||
99 | printk("HPFS: can't allocate memory for name conversion buffer\n"); | ||
100 | return from; | ||
101 | } | ||
102 | for (i = 0; i < len; i++) to[i] = locase(hpfs_sb(s)->sb_cp_table,from[i]); | ||
103 | return to; | ||
104 | } | ||
105 | |||
106 | int hpfs_compare_names(struct super_block *s, unsigned char *n1, unsigned l1, | ||
107 | unsigned char *n2, unsigned l2, int last) | ||
108 | { | ||
109 | unsigned l = l1 < l2 ? l1 : l2; | ||
110 | unsigned i; | ||
111 | if (last) return -1; | ||
112 | for (i = 0; i < l; i++) { | ||
113 | unsigned char c1 = upcase(hpfs_sb(s)->sb_cp_table,n1[i]); | ||
114 | unsigned char c2 = upcase(hpfs_sb(s)->sb_cp_table,n2[i]); | ||
115 | if (c1 < c2) return -1; | ||
116 | if (c1 > c2) return 1; | ||
117 | } | ||
118 | if (l1 < l2) return -1; | ||
119 | if (l1 > l2) return 1; | ||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | int hpfs_is_name_long(unsigned char *name, unsigned len) | ||
124 | { | ||
125 | int i,j; | ||
126 | for (i = 0; i < len && name[i] != '.'; i++) | ||
127 | if (no_dos_char(name[i])) return 1; | ||
128 | if (!i || i > 8) return 1; | ||
129 | if (i == len) return 0; | ||
130 | for (j = i + 1; j < len; j++) | ||
131 | if (name[j] == '.' || no_dos_char(name[i])) return 1; | ||
132 | return j - i > 4; | ||
133 | } | ||
134 | |||
135 | /* OS/2 clears dots and spaces at the end of file name, so we have to */ | ||
136 | |||
137 | void hpfs_adjust_length(unsigned char *name, unsigned *len) | ||
138 | { | ||
139 | if (!*len) return; | ||
140 | if (*len == 1 && name[0] == '.') return; | ||
141 | if (*len == 2 && name[0] == '.' && name[1] == '.') return; | ||
142 | while (*len && (name[*len - 1] == '.' || name[*len - 1] == ' ')) | ||
143 | (*len)--; | ||
144 | } | ||
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c new file mode 100644 index 000000000000..8ff8fc433fc1 --- /dev/null +++ b/fs/hpfs/namei.c | |||
@@ -0,0 +1,673 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/namei.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * adding & removing files & directories | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | |||
11 | static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | ||
12 | { | ||
13 | const char *name = dentry->d_name.name; | ||
14 | unsigned len = dentry->d_name.len; | ||
15 | struct quad_buffer_head qbh0; | ||
16 | struct buffer_head *bh; | ||
17 | struct hpfs_dirent *de; | ||
18 | struct fnode *fnode; | ||
19 | struct dnode *dnode; | ||
20 | struct inode *result; | ||
21 | fnode_secno fno; | ||
22 | dnode_secno dno; | ||
23 | int r; | ||
24 | struct hpfs_dirent dee; | ||
25 | int err; | ||
26 | if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; | ||
27 | lock_kernel(); | ||
28 | err = -ENOSPC; | ||
29 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
30 | if (!fnode) | ||
31 | goto bail; | ||
32 | dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0, 1); | ||
33 | if (!dnode) | ||
34 | goto bail1; | ||
35 | memset(&dee, 0, sizeof dee); | ||
36 | dee.directory = 1; | ||
37 | if (!(mode & 0222)) dee.read_only = 1; | ||
38 | /*dee.archive = 0;*/ | ||
39 | dee.hidden = name[0] == '.'; | ||
40 | dee.fnode = fno; | ||
41 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
42 | result = new_inode(dir->i_sb); | ||
43 | if (!result) | ||
44 | goto bail2; | ||
45 | hpfs_init_inode(result); | ||
46 | result->i_ino = fno; | ||
47 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
48 | hpfs_i(result)->i_dno = dno; | ||
49 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
50 | result->i_ctime.tv_nsec = 0; | ||
51 | result->i_mtime.tv_nsec = 0; | ||
52 | result->i_atime.tv_nsec = 0; | ||
53 | hpfs_i(result)->i_ea_size = 0; | ||
54 | result->i_mode |= S_IFDIR; | ||
55 | result->i_op = &hpfs_dir_iops; | ||
56 | result->i_fop = &hpfs_dir_ops; | ||
57 | result->i_blocks = 4; | ||
58 | result->i_size = 2048; | ||
59 | result->i_nlink = 2; | ||
60 | if (dee.read_only) | ||
61 | result->i_mode &= ~0222; | ||
62 | |||
63 | down(&hpfs_i(dir)->i_sem); | ||
64 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
65 | if (r == 1) | ||
66 | goto bail3; | ||
67 | if (r == -1) { | ||
68 | err = -EEXIST; | ||
69 | goto bail3; | ||
70 | } | ||
71 | fnode->len = len; | ||
72 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
73 | fnode->up = dir->i_ino; | ||
74 | fnode->dirflag = 1; | ||
75 | fnode->btree.n_free_nodes = 7; | ||
76 | fnode->btree.n_used_nodes = 1; | ||
77 | fnode->btree.first_free = 0x14; | ||
78 | fnode->u.external[0].disk_secno = dno; | ||
79 | fnode->u.external[0].file_secno = -1; | ||
80 | dnode->root_dnode = 1; | ||
81 | dnode->up = fno; | ||
82 | de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); | ||
83 | de->creation_date = de->write_date = de->read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
84 | if (!(mode & 0222)) de->read_only = 1; | ||
85 | de->first = de->directory = 1; | ||
86 | /*de->hidden = de->system = 0;*/ | ||
87 | de->fnode = fno; | ||
88 | mark_buffer_dirty(bh); | ||
89 | brelse(bh); | ||
90 | hpfs_mark_4buffers_dirty(&qbh0); | ||
91 | hpfs_brelse4(&qbh0); | ||
92 | dir->i_nlink++; | ||
93 | insert_inode_hash(result); | ||
94 | |||
95 | if (result->i_uid != current->fsuid || | ||
96 | result->i_gid != current->fsgid || | ||
97 | result->i_mode != (mode | S_IFDIR)) { | ||
98 | result->i_uid = current->fsuid; | ||
99 | result->i_gid = current->fsgid; | ||
100 | result->i_mode = mode | S_IFDIR; | ||
101 | hpfs_write_inode_nolock(result); | ||
102 | } | ||
103 | d_instantiate(dentry, result); | ||
104 | up(&hpfs_i(dir)->i_sem); | ||
105 | unlock_kernel(); | ||
106 | return 0; | ||
107 | bail3: | ||
108 | up(&hpfs_i(dir)->i_sem); | ||
109 | iput(result); | ||
110 | bail2: | ||
111 | hpfs_brelse4(&qbh0); | ||
112 | hpfs_free_dnode(dir->i_sb, dno); | ||
113 | bail1: | ||
114 | brelse(bh); | ||
115 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
116 | bail: | ||
117 | unlock_kernel(); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) | ||
122 | { | ||
123 | const char *name = dentry->d_name.name; | ||
124 | unsigned len = dentry->d_name.len; | ||
125 | struct inode *result = NULL; | ||
126 | struct buffer_head *bh; | ||
127 | struct fnode *fnode; | ||
128 | fnode_secno fno; | ||
129 | int r; | ||
130 | struct hpfs_dirent dee; | ||
131 | int err; | ||
132 | if ((err = hpfs_chk_name((char *)name, &len))) | ||
133 | return err==-ENOENT ? -EINVAL : err; | ||
134 | lock_kernel(); | ||
135 | err = -ENOSPC; | ||
136 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
137 | if (!fnode) | ||
138 | goto bail; | ||
139 | memset(&dee, 0, sizeof dee); | ||
140 | if (!(mode & 0222)) dee.read_only = 1; | ||
141 | dee.archive = 1; | ||
142 | dee.hidden = name[0] == '.'; | ||
143 | dee.fnode = fno; | ||
144 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
145 | |||
146 | result = new_inode(dir->i_sb); | ||
147 | if (!result) | ||
148 | goto bail1; | ||
149 | |||
150 | hpfs_init_inode(result); | ||
151 | result->i_ino = fno; | ||
152 | result->i_mode |= S_IFREG; | ||
153 | result->i_mode &= ~0111; | ||
154 | result->i_op = &hpfs_file_iops; | ||
155 | result->i_fop = &hpfs_file_ops; | ||
156 | result->i_nlink = 1; | ||
157 | hpfs_decide_conv(result, (char *)name, len); | ||
158 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
159 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
160 | result->i_ctime.tv_nsec = 0; | ||
161 | result->i_mtime.tv_nsec = 0; | ||
162 | result->i_atime.tv_nsec = 0; | ||
163 | hpfs_i(result)->i_ea_size = 0; | ||
164 | if (dee.read_only) | ||
165 | result->i_mode &= ~0222; | ||
166 | result->i_blocks = 1; | ||
167 | result->i_size = 0; | ||
168 | result->i_data.a_ops = &hpfs_aops; | ||
169 | hpfs_i(result)->mmu_private = 0; | ||
170 | |||
171 | down(&hpfs_i(dir)->i_sem); | ||
172 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
173 | if (r == 1) | ||
174 | goto bail2; | ||
175 | if (r == -1) { | ||
176 | err = -EEXIST; | ||
177 | goto bail2; | ||
178 | } | ||
179 | fnode->len = len; | ||
180 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
181 | fnode->up = dir->i_ino; | ||
182 | mark_buffer_dirty(bh); | ||
183 | brelse(bh); | ||
184 | |||
185 | insert_inode_hash(result); | ||
186 | |||
187 | if (result->i_uid != current->fsuid || | ||
188 | result->i_gid != current->fsgid || | ||
189 | result->i_mode != (mode | S_IFREG)) { | ||
190 | result->i_uid = current->fsuid; | ||
191 | result->i_gid = current->fsgid; | ||
192 | result->i_mode = mode | S_IFREG; | ||
193 | hpfs_write_inode_nolock(result); | ||
194 | } | ||
195 | d_instantiate(dentry, result); | ||
196 | up(&hpfs_i(dir)->i_sem); | ||
197 | unlock_kernel(); | ||
198 | return 0; | ||
199 | |||
200 | bail2: | ||
201 | up(&hpfs_i(dir)->i_sem); | ||
202 | iput(result); | ||
203 | bail1: | ||
204 | brelse(bh); | ||
205 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
206 | bail: | ||
207 | unlock_kernel(); | ||
208 | return err; | ||
209 | } | ||
210 | |||
211 | static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | ||
212 | { | ||
213 | const char *name = dentry->d_name.name; | ||
214 | unsigned len = dentry->d_name.len; | ||
215 | struct buffer_head *bh; | ||
216 | struct fnode *fnode; | ||
217 | fnode_secno fno; | ||
218 | int r; | ||
219 | struct hpfs_dirent dee; | ||
220 | struct inode *result = NULL; | ||
221 | int err; | ||
222 | if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; | ||
223 | if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; | ||
224 | if (!new_valid_dev(rdev)) | ||
225 | return -EINVAL; | ||
226 | lock_kernel(); | ||
227 | err = -ENOSPC; | ||
228 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
229 | if (!fnode) | ||
230 | goto bail; | ||
231 | memset(&dee, 0, sizeof dee); | ||
232 | if (!(mode & 0222)) dee.read_only = 1; | ||
233 | dee.archive = 1; | ||
234 | dee.hidden = name[0] == '.'; | ||
235 | dee.fnode = fno; | ||
236 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
237 | |||
238 | result = new_inode(dir->i_sb); | ||
239 | if (!result) | ||
240 | goto bail1; | ||
241 | |||
242 | hpfs_init_inode(result); | ||
243 | result->i_ino = fno; | ||
244 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
245 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
246 | result->i_ctime.tv_nsec = 0; | ||
247 | result->i_mtime.tv_nsec = 0; | ||
248 | result->i_atime.tv_nsec = 0; | ||
249 | hpfs_i(result)->i_ea_size = 0; | ||
250 | result->i_uid = current->fsuid; | ||
251 | result->i_gid = current->fsgid; | ||
252 | result->i_nlink = 1; | ||
253 | result->i_size = 0; | ||
254 | result->i_blocks = 1; | ||
255 | init_special_inode(result, mode, rdev); | ||
256 | |||
257 | down(&hpfs_i(dir)->i_sem); | ||
258 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
259 | if (r == 1) | ||
260 | goto bail2; | ||
261 | if (r == -1) { | ||
262 | err = -EEXIST; | ||
263 | goto bail2; | ||
264 | } | ||
265 | fnode->len = len; | ||
266 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
267 | fnode->up = dir->i_ino; | ||
268 | mark_buffer_dirty(bh); | ||
269 | |||
270 | insert_inode_hash(result); | ||
271 | |||
272 | hpfs_write_inode_nolock(result); | ||
273 | d_instantiate(dentry, result); | ||
274 | up(&hpfs_i(dir)->i_sem); | ||
275 | brelse(bh); | ||
276 | unlock_kernel(); | ||
277 | return 0; | ||
278 | bail2: | ||
279 | up(&hpfs_i(dir)->i_sem); | ||
280 | iput(result); | ||
281 | bail1: | ||
282 | brelse(bh); | ||
283 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
284 | bail: | ||
285 | unlock_kernel(); | ||
286 | return err; | ||
287 | } | ||
288 | |||
289 | static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) | ||
290 | { | ||
291 | const char *name = dentry->d_name.name; | ||
292 | unsigned len = dentry->d_name.len; | ||
293 | struct buffer_head *bh; | ||
294 | struct fnode *fnode; | ||
295 | fnode_secno fno; | ||
296 | int r; | ||
297 | struct hpfs_dirent dee; | ||
298 | struct inode *result; | ||
299 | int err; | ||
300 | if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; | ||
301 | lock_kernel(); | ||
302 | if (hpfs_sb(dir->i_sb)->sb_eas < 2) { | ||
303 | unlock_kernel(); | ||
304 | return -EPERM; | ||
305 | } | ||
306 | err = -ENOSPC; | ||
307 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | ||
308 | if (!fnode) | ||
309 | goto bail; | ||
310 | memset(&dee, 0, sizeof dee); | ||
311 | dee.archive = 1; | ||
312 | dee.hidden = name[0] == '.'; | ||
313 | dee.fnode = fno; | ||
314 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | ||
315 | |||
316 | result = new_inode(dir->i_sb); | ||
317 | if (!result) | ||
318 | goto bail1; | ||
319 | result->i_ino = fno; | ||
320 | hpfs_init_inode(result); | ||
321 | hpfs_i(result)->i_parent_dir = dir->i_ino; | ||
322 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | ||
323 | result->i_ctime.tv_nsec = 0; | ||
324 | result->i_mtime.tv_nsec = 0; | ||
325 | result->i_atime.tv_nsec = 0; | ||
326 | hpfs_i(result)->i_ea_size = 0; | ||
327 | result->i_mode = S_IFLNK | 0777; | ||
328 | result->i_uid = current->fsuid; | ||
329 | result->i_gid = current->fsgid; | ||
330 | result->i_blocks = 1; | ||
331 | result->i_nlink = 1; | ||
332 | result->i_size = strlen(symlink); | ||
333 | result->i_op = &page_symlink_inode_operations; | ||
334 | result->i_data.a_ops = &hpfs_symlink_aops; | ||
335 | |||
336 | down(&hpfs_i(dir)->i_sem); | ||
337 | r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); | ||
338 | if (r == 1) | ||
339 | goto bail2; | ||
340 | if (r == -1) { | ||
341 | err = -EEXIST; | ||
342 | goto bail2; | ||
343 | } | ||
344 | fnode->len = len; | ||
345 | memcpy(fnode->name, name, len > 15 ? 15 : len); | ||
346 | fnode->up = dir->i_ino; | ||
347 | hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink)); | ||
348 | mark_buffer_dirty(bh); | ||
349 | brelse(bh); | ||
350 | |||
351 | insert_inode_hash(result); | ||
352 | |||
353 | hpfs_write_inode_nolock(result); | ||
354 | d_instantiate(dentry, result); | ||
355 | up(&hpfs_i(dir)->i_sem); | ||
356 | unlock_kernel(); | ||
357 | return 0; | ||
358 | bail2: | ||
359 | up(&hpfs_i(dir)->i_sem); | ||
360 | iput(result); | ||
361 | bail1: | ||
362 | brelse(bh); | ||
363 | hpfs_free_sectors(dir->i_sb, fno, 1); | ||
364 | bail: | ||
365 | unlock_kernel(); | ||
366 | return err; | ||
367 | } | ||
368 | |||
369 | static int hpfs_unlink(struct inode *dir, struct dentry *dentry) | ||
370 | { | ||
371 | const char *name = dentry->d_name.name; | ||
372 | unsigned len = dentry->d_name.len; | ||
373 | struct quad_buffer_head qbh; | ||
374 | struct hpfs_dirent *de; | ||
375 | struct inode *inode = dentry->d_inode; | ||
376 | dnode_secno dno; | ||
377 | fnode_secno fno; | ||
378 | int r; | ||
379 | int rep = 0; | ||
380 | int err; | ||
381 | |||
382 | lock_kernel(); | ||
383 | hpfs_adjust_length((char *)name, &len); | ||
384 | again: | ||
385 | down(&hpfs_i(inode)->i_parent); | ||
386 | down(&hpfs_i(dir)->i_sem); | ||
387 | err = -ENOENT; | ||
388 | de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); | ||
389 | if (!de) | ||
390 | goto out; | ||
391 | |||
392 | err = -EPERM; | ||
393 | if (de->first) | ||
394 | goto out1; | ||
395 | |||
396 | err = -EISDIR; | ||
397 | if (de->directory) | ||
398 | goto out1; | ||
399 | |||
400 | fno = de->fnode; | ||
401 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); | ||
402 | switch (r) { | ||
403 | case 1: | ||
404 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | ||
405 | err = -EFSERROR; | ||
406 | break; | ||
407 | case 2: /* no space for deleting, try to truncate file */ | ||
408 | |||
409 | err = -ENOSPC; | ||
410 | if (rep++) | ||
411 | break; | ||
412 | |||
413 | up(&hpfs_i(dir)->i_sem); | ||
414 | up(&hpfs_i(inode)->i_parent); | ||
415 | d_drop(dentry); | ||
416 | spin_lock(&dentry->d_lock); | ||
417 | if (atomic_read(&dentry->d_count) > 1 || | ||
418 | permission(inode, MAY_WRITE, NULL) || | ||
419 | !S_ISREG(inode->i_mode) || | ||
420 | get_write_access(inode)) { | ||
421 | spin_unlock(&dentry->d_lock); | ||
422 | d_rehash(dentry); | ||
423 | } else { | ||
424 | struct iattr newattrs; | ||
425 | spin_unlock(&dentry->d_lock); | ||
426 | /*printk("HPFS: truncating file before delete.\n");*/ | ||
427 | newattrs.ia_size = 0; | ||
428 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | ||
429 | err = notify_change(dentry, &newattrs); | ||
430 | put_write_access(inode); | ||
431 | if (!err) | ||
432 | goto again; | ||
433 | } | ||
434 | unlock_kernel(); | ||
435 | return -ENOSPC; | ||
436 | default: | ||
437 | inode->i_nlink--; | ||
438 | err = 0; | ||
439 | } | ||
440 | goto out; | ||
441 | |||
442 | out1: | ||
443 | hpfs_brelse4(&qbh); | ||
444 | out: | ||
445 | up(&hpfs_i(dir)->i_sem); | ||
446 | up(&hpfs_i(inode)->i_parent); | ||
447 | unlock_kernel(); | ||
448 | return err; | ||
449 | } | ||
450 | |||
451 | static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) | ||
452 | { | ||
453 | const char *name = dentry->d_name.name; | ||
454 | unsigned len = dentry->d_name.len; | ||
455 | struct quad_buffer_head qbh; | ||
456 | struct hpfs_dirent *de; | ||
457 | struct inode *inode = dentry->d_inode; | ||
458 | dnode_secno dno; | ||
459 | fnode_secno fno; | ||
460 | int n_items = 0; | ||
461 | int err; | ||
462 | int r; | ||
463 | |||
464 | hpfs_adjust_length((char *)name, &len); | ||
465 | lock_kernel(); | ||
466 | down(&hpfs_i(inode)->i_parent); | ||
467 | down(&hpfs_i(dir)->i_sem); | ||
468 | err = -ENOENT; | ||
469 | de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); | ||
470 | if (!de) | ||
471 | goto out; | ||
472 | |||
473 | err = -EPERM; | ||
474 | if (de->first) | ||
475 | goto out1; | ||
476 | |||
477 | err = -ENOTDIR; | ||
478 | if (!de->directory) | ||
479 | goto out1; | ||
480 | |||
481 | hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items); | ||
482 | err = -ENOTEMPTY; | ||
483 | if (n_items) | ||
484 | goto out1; | ||
485 | |||
486 | fno = de->fnode; | ||
487 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); | ||
488 | switch (r) { | ||
489 | case 1: | ||
490 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | ||
491 | err = -EFSERROR; | ||
492 | break; | ||
493 | case 2: | ||
494 | err = -ENOSPC; | ||
495 | break; | ||
496 | default: | ||
497 | dir->i_nlink--; | ||
498 | inode->i_nlink = 0; | ||
499 | err = 0; | ||
500 | } | ||
501 | goto out; | ||
502 | out1: | ||
503 | hpfs_brelse4(&qbh); | ||
504 | out: | ||
505 | up(&hpfs_i(dir)->i_sem); | ||
506 | up(&hpfs_i(inode)->i_parent); | ||
507 | unlock_kernel(); | ||
508 | return err; | ||
509 | } | ||
510 | |||
511 | static int hpfs_symlink_readpage(struct file *file, struct page *page) | ||
512 | { | ||
513 | char *link = kmap(page); | ||
514 | struct inode *i = page->mapping->host; | ||
515 | struct fnode *fnode; | ||
516 | struct buffer_head *bh; | ||
517 | int err; | ||
518 | |||
519 | err = -EIO; | ||
520 | lock_kernel(); | ||
521 | if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) | ||
522 | goto fail; | ||
523 | err = hpfs_read_ea(i->i_sb, fnode, "SYMLINK", link, PAGE_SIZE); | ||
524 | brelse(bh); | ||
525 | if (err) | ||
526 | goto fail; | ||
527 | unlock_kernel(); | ||
528 | SetPageUptodate(page); | ||
529 | kunmap(page); | ||
530 | unlock_page(page); | ||
531 | return 0; | ||
532 | |||
533 | fail: | ||
534 | unlock_kernel(); | ||
535 | SetPageError(page); | ||
536 | kunmap(page); | ||
537 | unlock_page(page); | ||
538 | return err; | ||
539 | } | ||
540 | |||
541 | struct address_space_operations hpfs_symlink_aops = { | ||
542 | .readpage = hpfs_symlink_readpage | ||
543 | }; | ||
544 | |||
545 | static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, | ||
546 | struct inode *new_dir, struct dentry *new_dentry) | ||
547 | { | ||
548 | char *old_name = (char *)old_dentry->d_name.name; | ||
549 | int old_len = old_dentry->d_name.len; | ||
550 | char *new_name = (char *)new_dentry->d_name.name; | ||
551 | int new_len = new_dentry->d_name.len; | ||
552 | struct inode *i = old_dentry->d_inode; | ||
553 | struct inode *new_inode = new_dentry->d_inode; | ||
554 | struct quad_buffer_head qbh, qbh1; | ||
555 | struct hpfs_dirent *dep, *nde; | ||
556 | struct hpfs_dirent de; | ||
557 | dnode_secno dno; | ||
558 | int r; | ||
559 | struct buffer_head *bh; | ||
560 | struct fnode *fnode; | ||
561 | int err; | ||
562 | if ((err = hpfs_chk_name((char *)new_name, &new_len))) return err; | ||
563 | err = 0; | ||
564 | hpfs_adjust_length((char *)old_name, &old_len); | ||
565 | |||
566 | lock_kernel(); | ||
567 | /* order doesn't matter, due to VFS exclusion */ | ||
568 | down(&hpfs_i(i)->i_parent); | ||
569 | if (new_inode) | ||
570 | down(&hpfs_i(new_inode)->i_parent); | ||
571 | down(&hpfs_i(old_dir)->i_sem); | ||
572 | if (new_dir != old_dir) | ||
573 | down(&hpfs_i(new_dir)->i_sem); | ||
574 | |||
575 | /* Erm? Moving over the empty non-busy directory is perfectly legal */ | ||
576 | if (new_inode && S_ISDIR(new_inode->i_mode)) { | ||
577 | err = -EINVAL; | ||
578 | goto end1; | ||
579 | } | ||
580 | |||
581 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { | ||
582 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); | ||
583 | err = -ENOENT; | ||
584 | goto end1; | ||
585 | } | ||
586 | copy_de(&de, dep); | ||
587 | de.hidden = new_name[0] == '.'; | ||
588 | |||
589 | if (new_inode) { | ||
590 | int r; | ||
591 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { | ||
592 | if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) { | ||
593 | new_inode->i_nlink = 0; | ||
594 | copy_de(nde, &de); | ||
595 | memcpy(nde->name, new_name, new_len); | ||
596 | hpfs_mark_4buffers_dirty(&qbh1); | ||
597 | hpfs_brelse4(&qbh1); | ||
598 | goto end; | ||
599 | } | ||
600 | hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent"); | ||
601 | err = -EFSERROR; | ||
602 | goto end1; | ||
603 | } | ||
604 | err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; | ||
605 | goto end1; | ||
606 | } | ||
607 | |||
608 | if (new_dir == old_dir) hpfs_brelse4(&qbh); | ||
609 | |||
610 | hpfs_lock_creation(i->i_sb); | ||
611 | if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de, 1))) { | ||
612 | hpfs_unlock_creation(i->i_sb); | ||
613 | if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); | ||
614 | err = r == 1 ? -ENOSPC : -EFSERROR; | ||
615 | if (new_dir != old_dir) hpfs_brelse4(&qbh); | ||
616 | goto end1; | ||
617 | } | ||
618 | |||
619 | if (new_dir == old_dir) | ||
620 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { | ||
621 | hpfs_unlock_creation(i->i_sb); | ||
622 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); | ||
623 | err = -ENOENT; | ||
624 | goto end1; | ||
625 | } | ||
626 | |||
627 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { | ||
628 | hpfs_unlock_creation(i->i_sb); | ||
629 | hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); | ||
630 | err = r == 2 ? -ENOSPC : -EFSERROR; | ||
631 | goto end1; | ||
632 | } | ||
633 | hpfs_unlock_creation(i->i_sb); | ||
634 | |||
635 | end: | ||
636 | hpfs_i(i)->i_parent_dir = new_dir->i_ino; | ||
637 | if (S_ISDIR(i->i_mode)) { | ||
638 | new_dir->i_nlink++; | ||
639 | old_dir->i_nlink--; | ||
640 | } | ||
641 | if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { | ||
642 | fnode->up = new_dir->i_ino; | ||
643 | fnode->len = new_len; | ||
644 | memcpy(fnode->name, new_name, new_len>15?15:new_len); | ||
645 | if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); | ||
646 | mark_buffer_dirty(bh); | ||
647 | brelse(bh); | ||
648 | } | ||
649 | hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; | ||
650 | hpfs_decide_conv(i, (char *)new_name, new_len); | ||
651 | end1: | ||
652 | if (old_dir != new_dir) | ||
653 | up(&hpfs_i(new_dir)->i_sem); | ||
654 | up(&hpfs_i(old_dir)->i_sem); | ||
655 | up(&hpfs_i(i)->i_parent); | ||
656 | if (new_inode) | ||
657 | up(&hpfs_i(new_inode)->i_parent); | ||
658 | unlock_kernel(); | ||
659 | return err; | ||
660 | } | ||
661 | |||
662 | struct inode_operations hpfs_dir_iops = | ||
663 | { | ||
664 | .create = hpfs_create, | ||
665 | .lookup = hpfs_lookup, | ||
666 | .unlink = hpfs_unlink, | ||
667 | .symlink = hpfs_symlink, | ||
668 | .mkdir = hpfs_mkdir, | ||
669 | .rmdir = hpfs_rmdir, | ||
670 | .mknod = hpfs_mknod, | ||
671 | .rename = hpfs_rename, | ||
672 | .setattr = hpfs_notify_change, | ||
673 | }; | ||
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c new file mode 100644 index 000000000000..8eefa6366db7 --- /dev/null +++ b/fs/hpfs/super.c | |||
@@ -0,0 +1,701 @@ | |||
1 | /* | ||
2 | * linux/fs/hpfs/super.c | ||
3 | * | ||
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | ||
5 | * | ||
6 | * mounting, unmounting, error handling | ||
7 | */ | ||
8 | |||
9 | #include "hpfs_fn.h" | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/parser.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/statfs.h> | ||
14 | |||
15 | /* Mark the filesystem dirty, so that chkdsk checks it when os/2 booted */ | ||
16 | |||
17 | static void mark_dirty(struct super_block *s) | ||
18 | { | ||
19 | if (hpfs_sb(s)->sb_chkdsk && !(s->s_flags & MS_RDONLY)) { | ||
20 | struct buffer_head *bh; | ||
21 | struct hpfs_spare_block *sb; | ||
22 | if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { | ||
23 | sb->dirty = 1; | ||
24 | sb->old_wrote = 0; | ||
25 | mark_buffer_dirty(bh); | ||
26 | brelse(bh); | ||
27 | } | ||
28 | } | ||
29 | } | ||
30 | |||
31 | /* Mark the filesystem clean (mark it dirty for chkdsk if chkdsk==2 or if there | ||
32 | were errors) */ | ||
33 | |||
34 | static void unmark_dirty(struct super_block *s) | ||
35 | { | ||
36 | struct buffer_head *bh; | ||
37 | struct hpfs_spare_block *sb; | ||
38 | if (s->s_flags & MS_RDONLY) return; | ||
39 | if ((sb = hpfs_map_sector(s, 17, &bh, 0))) { | ||
40 | sb->dirty = hpfs_sb(s)->sb_chkdsk > 1 - hpfs_sb(s)->sb_was_error; | ||
41 | sb->old_wrote = hpfs_sb(s)->sb_chkdsk >= 2 && !hpfs_sb(s)->sb_was_error; | ||
42 | mark_buffer_dirty(bh); | ||
43 | brelse(bh); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | /* Filesystem error... */ | ||
48 | |||
49 | #define ERR_BUF_SIZE 1024 | ||
50 | |||
51 | void hpfs_error(struct super_block *s, char *m,...) | ||
52 | { | ||
53 | char *buf; | ||
54 | va_list l; | ||
55 | va_start(l, m); | ||
56 | if (!(buf = kmalloc(ERR_BUF_SIZE, GFP_KERNEL))) | ||
57 | printk("HPFS: No memory for error message '%s'\n",m); | ||
58 | else if (vsprintf(buf, m, l) >= ERR_BUF_SIZE) | ||
59 | printk("HPFS: Grrrr... Kernel memory corrupted ... going on, but it'll crash very soon :-(\n"); | ||
60 | printk("HPFS: filesystem error: "); | ||
61 | if (buf) printk("%s", buf); | ||
62 | else printk("%s\n",m); | ||
63 | if (!hpfs_sb(s)->sb_was_error) { | ||
64 | if (hpfs_sb(s)->sb_err == 2) { | ||
65 | printk("; crashing the system because you wanted it\n"); | ||
66 | mark_dirty(s); | ||
67 | panic("HPFS panic"); | ||
68 | } else if (hpfs_sb(s)->sb_err == 1) { | ||
69 | if (s->s_flags & MS_RDONLY) printk("; already mounted read-only\n"); | ||
70 | else { | ||
71 | printk("; remounting read-only\n"); | ||
72 | mark_dirty(s); | ||
73 | s->s_flags |= MS_RDONLY; | ||
74 | } | ||
75 | } else if (s->s_flags & MS_RDONLY) printk("; going on - but anything won't be destroyed because it's read-only\n"); | ||
76 | else printk("; corrupted filesystem mounted read/write - your computer will explode within 20 seconds ... but you wanted it so!\n"); | ||
77 | } else printk("\n"); | ||
78 | if (buf) kfree(buf); | ||
79 | hpfs_sb(s)->sb_was_error = 1; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * A little trick to detect cycles in many hpfs structures and don't let the | ||
84 | * kernel crash on corrupted filesystem. When first called, set c2 to 0. | ||
85 | * | ||
86 | * BTW. chkdsk doesn't detect cycles correctly. When I had 2 lost directories | ||
87 | * nested each in other, chkdsk locked up happilly. | ||
88 | */ | ||
89 | |||
90 | int hpfs_stop_cycles(struct super_block *s, int key, int *c1, int *c2, | ||
91 | char *msg) | ||
92 | { | ||
93 | if (*c2 && *c1 == key) { | ||
94 | hpfs_error(s, "cycle detected on key %08x in %s", key, msg); | ||
95 | return 1; | ||
96 | } | ||
97 | (*c2)++; | ||
98 | if (!((*c2 - 1) & *c2)) *c1 = key; | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static void hpfs_put_super(struct super_block *s) | ||
103 | { | ||
104 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
105 | if (sbi->sb_cp_table) kfree(sbi->sb_cp_table); | ||
106 | if (sbi->sb_bmp_dir) kfree(sbi->sb_bmp_dir); | ||
107 | unmark_dirty(s); | ||
108 | s->s_fs_info = NULL; | ||
109 | kfree(sbi); | ||
110 | } | ||
111 | |||
112 | unsigned hpfs_count_one_bitmap(struct super_block *s, secno secno) | ||
113 | { | ||
114 | struct quad_buffer_head qbh; | ||
115 | unsigned *bits; | ||
116 | unsigned i, count; | ||
117 | if (!(bits = hpfs_map_4sectors(s, secno, &qbh, 4))) return 0; | ||
118 | count = 0; | ||
119 | for (i = 0; i < 2048 / sizeof(unsigned); i++) { | ||
120 | unsigned b; | ||
121 | if (!bits[i]) continue; | ||
122 | for (b = bits[i]; b; b>>=1) count += b & 1; | ||
123 | } | ||
124 | hpfs_brelse4(&qbh); | ||
125 | return count; | ||
126 | } | ||
127 | |||
128 | static unsigned count_bitmaps(struct super_block *s) | ||
129 | { | ||
130 | unsigned n, count, n_bands; | ||
131 | n_bands = (hpfs_sb(s)->sb_fs_size + 0x3fff) >> 14; | ||
132 | count = 0; | ||
133 | for (n = 0; n < n_bands; n++) | ||
134 | count += hpfs_count_one_bitmap(s, hpfs_sb(s)->sb_bmp_dir[n]); | ||
135 | return count; | ||
136 | } | ||
137 | |||
138 | static int hpfs_statfs(struct super_block *s, struct kstatfs *buf) | ||
139 | { | ||
140 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
141 | lock_kernel(); | ||
142 | |||
143 | /*if (sbi->sb_n_free == -1) {*/ | ||
144 | sbi->sb_n_free = count_bitmaps(s); | ||
145 | sbi->sb_n_free_dnodes = hpfs_count_one_bitmap(s, sbi->sb_dmap); | ||
146 | /*}*/ | ||
147 | buf->f_type = s->s_magic; | ||
148 | buf->f_bsize = 512; | ||
149 | buf->f_blocks = sbi->sb_fs_size; | ||
150 | buf->f_bfree = sbi->sb_n_free; | ||
151 | buf->f_bavail = sbi->sb_n_free; | ||
152 | buf->f_files = sbi->sb_dirband_size / 4; | ||
153 | buf->f_ffree = sbi->sb_n_free_dnodes; | ||
154 | buf->f_namelen = 254; | ||
155 | |||
156 | unlock_kernel(); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static kmem_cache_t * hpfs_inode_cachep; | ||
162 | |||
163 | static struct inode *hpfs_alloc_inode(struct super_block *sb) | ||
164 | { | ||
165 | struct hpfs_inode_info *ei; | ||
166 | ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_NOFS); | ||
167 | if (!ei) | ||
168 | return NULL; | ||
169 | ei->vfs_inode.i_version = 1; | ||
170 | return &ei->vfs_inode; | ||
171 | } | ||
172 | |||
173 | static void hpfs_destroy_inode(struct inode *inode) | ||
174 | { | ||
175 | kmem_cache_free(hpfs_inode_cachep, hpfs_i(inode)); | ||
176 | } | ||
177 | |||
178 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | ||
179 | { | ||
180 | struct hpfs_inode_info *ei = (struct hpfs_inode_info *) foo; | ||
181 | |||
182 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | ||
183 | SLAB_CTOR_CONSTRUCTOR) { | ||
184 | init_MUTEX(&ei->i_sem); | ||
185 | init_MUTEX(&ei->i_parent); | ||
186 | inode_init_once(&ei->vfs_inode); | ||
187 | } | ||
188 | } | ||
189 | |||
190 | static int init_inodecache(void) | ||
191 | { | ||
192 | hpfs_inode_cachep = kmem_cache_create("hpfs_inode_cache", | ||
193 | sizeof(struct hpfs_inode_info), | ||
194 | 0, SLAB_RECLAIM_ACCOUNT, | ||
195 | init_once, NULL); | ||
196 | if (hpfs_inode_cachep == NULL) | ||
197 | return -ENOMEM; | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void destroy_inodecache(void) | ||
202 | { | ||
203 | if (kmem_cache_destroy(hpfs_inode_cachep)) | ||
204 | printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n"); | ||
205 | } | ||
206 | |||
207 | /* | ||
208 | * A tiny parser for option strings, stolen from dosfs. | ||
209 | * Stolen again from read-only hpfs. | ||
210 | * And updated for table-driven option parsing. | ||
211 | */ | ||
212 | |||
213 | enum { | ||
214 | Opt_help, Opt_uid, Opt_gid, Opt_umask, Opt_case_lower, Opt_case_asis, | ||
215 | Opt_conv_binary, Opt_conv_text, Opt_conv_auto, | ||
216 | Opt_check_none, Opt_check_normal, Opt_check_strict, | ||
217 | Opt_err_cont, Opt_err_ro, Opt_err_panic, | ||
218 | Opt_eas_no, Opt_eas_ro, Opt_eas_rw, | ||
219 | Opt_chkdsk_no, Opt_chkdsk_errors, Opt_chkdsk_always, | ||
220 | Opt_timeshift, Opt_err, | ||
221 | }; | ||
222 | |||
223 | static match_table_t tokens = { | ||
224 | {Opt_help, "help"}, | ||
225 | {Opt_uid, "uid=%u"}, | ||
226 | {Opt_gid, "gid=%u"}, | ||
227 | {Opt_umask, "umask=%o"}, | ||
228 | {Opt_case_lower, "case=lower"}, | ||
229 | {Opt_case_asis, "case=asis"}, | ||
230 | {Opt_conv_binary, "conv=binary"}, | ||
231 | {Opt_conv_text, "conv=text"}, | ||
232 | {Opt_conv_auto, "conv=auto"}, | ||
233 | {Opt_check_none, "check=none"}, | ||
234 | {Opt_check_normal, "check=normal"}, | ||
235 | {Opt_check_strict, "check=strict"}, | ||
236 | {Opt_err_cont, "errors=continue"}, | ||
237 | {Opt_err_ro, "errors=remount-ro"}, | ||
238 | {Opt_err_panic, "errors=panic"}, | ||
239 | {Opt_eas_no, "eas=no"}, | ||
240 | {Opt_eas_ro, "eas=ro"}, | ||
241 | {Opt_eas_rw, "eas=rw"}, | ||
242 | {Opt_chkdsk_no, "chkdsk=no"}, | ||
243 | {Opt_chkdsk_errors, "chkdsk=errors"}, | ||
244 | {Opt_chkdsk_always, "chkdsk=always"}, | ||
245 | {Opt_timeshift, "timeshift=%d"}, | ||
246 | {Opt_err, NULL}, | ||
247 | }; | ||
248 | |||
249 | static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, | ||
250 | int *lowercase, int *conv, int *eas, int *chk, int *errs, | ||
251 | int *chkdsk, int *timeshift) | ||
252 | { | ||
253 | char *p; | ||
254 | int option; | ||
255 | |||
256 | if (!opts) | ||
257 | return 1; | ||
258 | |||
259 | /*printk("Parsing opts: '%s'\n",opts);*/ | ||
260 | |||
261 | while ((p = strsep(&opts, ",")) != NULL) { | ||
262 | substring_t args[MAX_OPT_ARGS]; | ||
263 | int token; | ||
264 | if (!*p) | ||
265 | continue; | ||
266 | |||
267 | token = match_token(p, tokens, args); | ||
268 | switch (token) { | ||
269 | case Opt_help: | ||
270 | return 2; | ||
271 | case Opt_uid: | ||
272 | if (match_int(args, &option)) | ||
273 | return 0; | ||
274 | *uid = option; | ||
275 | break; | ||
276 | case Opt_gid: | ||
277 | if (match_int(args, &option)) | ||
278 | return 0; | ||
279 | *gid = option; | ||
280 | break; | ||
281 | case Opt_umask: | ||
282 | if (match_octal(args, &option)) | ||
283 | return 0; | ||
284 | *umask = option; | ||
285 | break; | ||
286 | case Opt_case_lower: | ||
287 | *lowercase = 1; | ||
288 | break; | ||
289 | case Opt_case_asis: | ||
290 | *lowercase = 0; | ||
291 | break; | ||
292 | case Opt_conv_binary: | ||
293 | *conv = CONV_BINARY; | ||
294 | break; | ||
295 | case Opt_conv_text: | ||
296 | *conv = CONV_TEXT; | ||
297 | break; | ||
298 | case Opt_conv_auto: | ||
299 | *conv = CONV_AUTO; | ||
300 | break; | ||
301 | case Opt_check_none: | ||
302 | *chk = 0; | ||
303 | break; | ||
304 | case Opt_check_normal: | ||
305 | *chk = 1; | ||
306 | break; | ||
307 | case Opt_check_strict: | ||
308 | *chk = 2; | ||
309 | break; | ||
310 | case Opt_err_cont: | ||
311 | *errs = 0; | ||
312 | break; | ||
313 | case Opt_err_ro: | ||
314 | *errs = 1; | ||
315 | break; | ||
316 | case Opt_err_panic: | ||
317 | *errs = 2; | ||
318 | break; | ||
319 | case Opt_eas_no: | ||
320 | *eas = 0; | ||
321 | break; | ||
322 | case Opt_eas_ro: | ||
323 | *eas = 1; | ||
324 | break; | ||
325 | case Opt_eas_rw: | ||
326 | *eas = 2; | ||
327 | break; | ||
328 | case Opt_chkdsk_no: | ||
329 | *chkdsk = 0; | ||
330 | break; | ||
331 | case Opt_chkdsk_errors: | ||
332 | *chkdsk = 1; | ||
333 | break; | ||
334 | case Opt_chkdsk_always: | ||
335 | *chkdsk = 2; | ||
336 | break; | ||
337 | case Opt_timeshift: | ||
338 | { | ||
339 | int m = 1; | ||
340 | char *rhs = args[0].from; | ||
341 | if (!rhs || !*rhs) | ||
342 | return 0; | ||
343 | if (*rhs == '-') m = -1; | ||
344 | if (*rhs == '+' || *rhs == '-') rhs++; | ||
345 | *timeshift = simple_strtoul(rhs, &rhs, 0) * m; | ||
346 | if (*rhs) | ||
347 | return 0; | ||
348 | break; | ||
349 | } | ||
350 | default: | ||
351 | return 0; | ||
352 | } | ||
353 | } | ||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | static inline void hpfs_help(void) | ||
358 | { | ||
359 | printk("\n\ | ||
360 | HPFS filesystem options:\n\ | ||
361 | help do not mount and display this text\n\ | ||
362 | uid=xxx set uid of files that don't have uid specified in eas\n\ | ||
363 | gid=xxx set gid of files that don't have gid specified in eas\n\ | ||
364 | umask=xxx set mode of files that don't have mode specified in eas\n\ | ||
365 | case=lower lowercase all files\n\ | ||
366 | case=asis do not lowercase files (default)\n\ | ||
367 | conv=binary do not convert CR/LF -> LF (default)\n\ | ||
368 | conv=auto convert only files with known text extensions\n\ | ||
369 | conv=text convert all files\n\ | ||
370 | check=none no fs checks - kernel may crash on corrupted filesystem\n\ | ||
371 | check=normal do some checks - it should not crash (default)\n\ | ||
372 | check=strict do extra time-consuming checks, used for debugging\n\ | ||
373 | errors=continue continue on errors\n\ | ||
374 | errors=remount-ro remount read-only if errors found (default)\n\ | ||
375 | errors=panic panic on errors\n\ | ||
376 | chkdsk=no do not mark fs for chkdsking even if there were errors\n\ | ||
377 | chkdsk=errors mark fs dirty if errors found (default)\n\ | ||
378 | chkdsk=always always mark fs dirty - used for debugging\n\ | ||
379 | eas=no ignore extended attributes\n\ | ||
380 | eas=ro read but do not write extended attributes\n\ | ||
381 | eas=rw r/w eas => enables chmod, chown, mknod, ln -s (default)\n\ | ||
382 | timeshift=nnn add nnn seconds to file times\n\ | ||
383 | \n"); | ||
384 | } | ||
385 | |||
386 | static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) | ||
387 | { | ||
388 | uid_t uid; | ||
389 | gid_t gid; | ||
390 | umode_t umask; | ||
391 | int lowercase, conv, eas, chk, errs, chkdsk, timeshift; | ||
392 | int o; | ||
393 | struct hpfs_sb_info *sbi = hpfs_sb(s); | ||
394 | |||
395 | *flags |= MS_NOATIME; | ||
396 | |||
397 | uid = sbi->sb_uid; gid = sbi->sb_gid; | ||
398 | umask = 0777 & ~sbi->sb_mode; | ||
399 | lowercase = sbi->sb_lowercase; conv = sbi->sb_conv; | ||
400 | eas = sbi->sb_eas; chk = sbi->sb_chk; chkdsk = sbi->sb_chkdsk; | ||
401 | errs = sbi->sb_err; timeshift = sbi->sb_timeshift; | ||
402 | |||
403 | if (!(o = parse_opts(data, &uid, &gid, &umask, &lowercase, &conv, | ||
404 | &eas, &chk, &errs, &chkdsk, ×hift))) { | ||
405 | printk("HPFS: bad mount options.\n"); | ||
406 | return 1; | ||
407 | } | ||
408 | if (o == 2) { | ||
409 | hpfs_help(); | ||
410 | return 1; | ||
411 | } | ||
412 | if (timeshift != sbi->sb_timeshift) { | ||
413 | printk("HPFS: timeshift can't be changed using remount.\n"); | ||
414 | return 1; | ||
415 | } | ||
416 | |||
417 | unmark_dirty(s); | ||
418 | |||
419 | sbi->sb_uid = uid; sbi->sb_gid = gid; | ||
420 | sbi->sb_mode = 0777 & ~umask; | ||
421 | sbi->sb_lowercase = lowercase; sbi->sb_conv = conv; | ||
422 | sbi->sb_eas = eas; sbi->sb_chk = chk; sbi->sb_chkdsk = chkdsk; | ||
423 | sbi->sb_err = errs; sbi->sb_timeshift = timeshift; | ||
424 | |||
425 | if (!(*flags & MS_RDONLY)) mark_dirty(s); | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | /* Super operations */ | ||
431 | |||
432 | static struct super_operations hpfs_sops = | ||
433 | { | ||
434 | .alloc_inode = hpfs_alloc_inode, | ||
435 | .destroy_inode = hpfs_destroy_inode, | ||
436 | .delete_inode = hpfs_delete_inode, | ||
437 | .put_super = hpfs_put_super, | ||
438 | .statfs = hpfs_statfs, | ||
439 | .remount_fs = hpfs_remount_fs, | ||
440 | }; | ||
441 | |||
442 | static int hpfs_fill_super(struct super_block *s, void *options, int silent) | ||
443 | { | ||
444 | struct buffer_head *bh0, *bh1, *bh2; | ||
445 | struct hpfs_boot_block *bootblock; | ||
446 | struct hpfs_super_block *superblock; | ||
447 | struct hpfs_spare_block *spareblock; | ||
448 | struct hpfs_sb_info *sbi; | ||
449 | struct inode *root; | ||
450 | |||
451 | uid_t uid; | ||
452 | gid_t gid; | ||
453 | umode_t umask; | ||
454 | int lowercase, conv, eas, chk, errs, chkdsk, timeshift; | ||
455 | |||
456 | dnode_secno root_dno; | ||
457 | struct hpfs_dirent *de = NULL; | ||
458 | struct quad_buffer_head qbh; | ||
459 | |||
460 | int o; | ||
461 | |||
462 | sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); | ||
463 | if (!sbi) | ||
464 | return -ENOMEM; | ||
465 | s->s_fs_info = sbi; | ||
466 | memset(sbi, 0, sizeof(*sbi)); | ||
467 | |||
468 | sbi->sb_bmp_dir = NULL; | ||
469 | sbi->sb_cp_table = NULL; | ||
470 | |||
471 | init_MUTEX(&sbi->hpfs_creation_de); | ||
472 | |||
473 | uid = current->uid; | ||
474 | gid = current->gid; | ||
475 | umask = current->fs->umask; | ||
476 | lowercase = 0; | ||
477 | conv = CONV_BINARY; | ||
478 | eas = 2; | ||
479 | chk = 1; | ||
480 | errs = 1; | ||
481 | chkdsk = 1; | ||
482 | timeshift = 0; | ||
483 | |||
484 | if (!(o = parse_opts(options, &uid, &gid, &umask, &lowercase, &conv, | ||
485 | &eas, &chk, &errs, &chkdsk, ×hift))) { | ||
486 | printk("HPFS: bad mount options.\n"); | ||
487 | goto bail0; | ||
488 | } | ||
489 | if (o==2) { | ||
490 | hpfs_help(); | ||
491 | goto bail0; | ||
492 | } | ||
493 | |||
494 | /*sbi->sb_mounting = 1;*/ | ||
495 | sb_set_blocksize(s, 512); | ||
496 | sbi->sb_fs_size = -1; | ||
497 | if (!(bootblock = hpfs_map_sector(s, 0, &bh0, 0))) goto bail1; | ||
498 | if (!(superblock = hpfs_map_sector(s, 16, &bh1, 1))) goto bail2; | ||
499 | if (!(spareblock = hpfs_map_sector(s, 17, &bh2, 0))) goto bail3; | ||
500 | |||
501 | /* Check magics */ | ||
502 | if (/*bootblock->magic != BB_MAGIC | ||
503 | ||*/ superblock->magic != SB_MAGIC | ||
504 | || spareblock->magic != SP_MAGIC) { | ||
505 | if (!silent) printk("HPFS: Bad magic ... probably not HPFS\n"); | ||
506 | goto bail4; | ||
507 | } | ||
508 | |||
509 | /* Check version */ | ||
510 | if (!(s->s_flags & MS_RDONLY) && | ||
511 | superblock->funcversion != 2 && superblock->funcversion != 3) { | ||
512 | printk("HPFS: Bad version %d,%d. Mount readonly to go around\n", | ||
513 | (int)superblock->version, (int)superblock->funcversion); | ||
514 | printk("HPFS: please try recent version of HPFS driver at http://artax.karlin.mff.cuni.cz/~mikulas/vyplody/hpfs/index-e.cgi and if it still can't understand this format, contact author - mikulas@artax.karlin.mff.cuni.cz\n"); | ||
515 | goto bail4; | ||
516 | } | ||
517 | |||
518 | s->s_flags |= MS_NOATIME; | ||
519 | |||
520 | /* Fill superblock stuff */ | ||
521 | s->s_magic = HPFS_SUPER_MAGIC; | ||
522 | s->s_op = &hpfs_sops; | ||
523 | |||
524 | sbi->sb_root = superblock->root; | ||
525 | sbi->sb_fs_size = superblock->n_sectors; | ||
526 | sbi->sb_bitmaps = superblock->bitmaps; | ||
527 | sbi->sb_dirband_start = superblock->dir_band_start; | ||
528 | sbi->sb_dirband_size = superblock->n_dir_band; | ||
529 | sbi->sb_dmap = superblock->dir_band_bitmap; | ||
530 | sbi->sb_uid = uid; | ||
531 | sbi->sb_gid = gid; | ||
532 | sbi->sb_mode = 0777 & ~umask; | ||
533 | sbi->sb_n_free = -1; | ||
534 | sbi->sb_n_free_dnodes = -1; | ||
535 | sbi->sb_lowercase = lowercase; | ||
536 | sbi->sb_conv = conv; | ||
537 | sbi->sb_eas = eas; | ||
538 | sbi->sb_chk = chk; | ||
539 | sbi->sb_chkdsk = chkdsk; | ||
540 | sbi->sb_err = errs; | ||
541 | sbi->sb_timeshift = timeshift; | ||
542 | sbi->sb_was_error = 0; | ||
543 | sbi->sb_cp_table = NULL; | ||
544 | sbi->sb_c_bitmap = -1; | ||
545 | sbi->sb_max_fwd_alloc = 0xffffff; | ||
546 | |||
547 | /* Load bitmap directory */ | ||
548 | if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, superblock->bitmaps))) | ||
549 | goto bail4; | ||
550 | |||
551 | /* Check for general fs errors*/ | ||
552 | if (spareblock->dirty && !spareblock->old_wrote) { | ||
553 | if (errs == 2) { | ||
554 | printk("HPFS: Improperly stopped, not mounted\n"); | ||
555 | goto bail4; | ||
556 | } | ||
557 | hpfs_error(s, "improperly stopped"); | ||
558 | } | ||
559 | |||
560 | if (!(s->s_flags & MS_RDONLY)) { | ||
561 | spareblock->dirty = 1; | ||
562 | spareblock->old_wrote = 0; | ||
563 | mark_buffer_dirty(bh2); | ||
564 | } | ||
565 | |||
566 | if (spareblock->hotfixes_used || spareblock->n_spares_used) { | ||
567 | if (errs >= 2) { | ||
568 | printk("HPFS: Hotfixes not supported here, try chkdsk\n"); | ||
569 | mark_dirty(s); | ||
570 | goto bail4; | ||
571 | } | ||
572 | hpfs_error(s, "hotfixes not supported here, try chkdsk"); | ||
573 | if (errs == 0) printk("HPFS: Proceeding, but your filesystem will be probably corrupted by this driver...\n"); | ||
574 | else printk("HPFS: This driver may read bad files or crash when operating on disk with hotfixes.\n"); | ||
575 | } | ||
576 | if (spareblock->n_dnode_spares != spareblock->n_dnode_spares_free) { | ||
577 | if (errs >= 2) { | ||
578 | printk("HPFS: Spare dnodes used, try chkdsk\n"); | ||
579 | mark_dirty(s); | ||
580 | goto bail4; | ||
581 | } | ||
582 | hpfs_error(s, "warning: spare dnodes used, try chkdsk"); | ||
583 | if (errs == 0) printk("HPFS: Proceeding, but your filesystem could be corrupted if you delete files or directories\n"); | ||
584 | } | ||
585 | if (chk) { | ||
586 | unsigned a; | ||
587 | if (superblock->dir_band_end - superblock->dir_band_start + 1 != superblock->n_dir_band || | ||
588 | superblock->dir_band_end < superblock->dir_band_start || superblock->n_dir_band > 0x4000) { | ||
589 | hpfs_error(s, "dir band size mismatch: dir_band_start==%08x, dir_band_end==%08x, n_dir_band==%08x", | ||
590 | superblock->dir_band_start, superblock->dir_band_end, superblock->n_dir_band); | ||
591 | goto bail4; | ||
592 | } | ||
593 | a = sbi->sb_dirband_size; | ||
594 | sbi->sb_dirband_size = 0; | ||
595 | if (hpfs_chk_sectors(s, superblock->dir_band_start, superblock->n_dir_band, "dir_band") || | ||
596 | hpfs_chk_sectors(s, superblock->dir_band_bitmap, 4, "dir_band_bitmap") || | ||
597 | hpfs_chk_sectors(s, superblock->bitmaps, 4, "bitmaps")) { | ||
598 | mark_dirty(s); | ||
599 | goto bail4; | ||
600 | } | ||
601 | sbi->sb_dirband_size = a; | ||
602 | } else printk("HPFS: You really don't want any checks? You are crazy...\n"); | ||
603 | |||
604 | /* Load code page table */ | ||
605 | if (spareblock->n_code_pages) | ||
606 | if (!(sbi->sb_cp_table = hpfs_load_code_page(s, spareblock->code_page_dir))) | ||
607 | printk("HPFS: Warning: code page support is disabled\n"); | ||
608 | |||
609 | brelse(bh2); | ||
610 | brelse(bh1); | ||
611 | brelse(bh0); | ||
612 | |||
613 | root = iget_locked(s, sbi->sb_root); | ||
614 | if (!root) | ||
615 | goto bail0; | ||
616 | hpfs_init_inode(root); | ||
617 | hpfs_read_inode(root); | ||
618 | unlock_new_inode(root); | ||
619 | s->s_root = d_alloc_root(root); | ||
620 | if (!s->s_root) { | ||
621 | iput(root); | ||
622 | goto bail0; | ||
623 | } | ||
624 | hpfs_set_dentry_operations(s->s_root); | ||
625 | |||
626 | /* | ||
627 | * find the root directory's . pointer & finish filling in the inode | ||
628 | */ | ||
629 | |||
630 | root_dno = hpfs_fnode_dno(s, sbi->sb_root); | ||
631 | if (root_dno) | ||
632 | de = map_dirent(root, root_dno, "\001\001", 2, NULL, &qbh); | ||
633 | if (!de) | ||
634 | hpfs_error(s, "unable to find root dir"); | ||
635 | else { | ||
636 | root->i_atime.tv_sec = local_to_gmt(s, de->read_date); | ||
637 | root->i_atime.tv_nsec = 0; | ||
638 | root->i_mtime.tv_sec = local_to_gmt(s, de->write_date); | ||
639 | root->i_mtime.tv_nsec = 0; | ||
640 | root->i_ctime.tv_sec = local_to_gmt(s, de->creation_date); | ||
641 | root->i_ctime.tv_nsec = 0; | ||
642 | hpfs_i(root)->i_ea_size = de->ea_size; | ||
643 | hpfs_i(root)->i_parent_dir = root->i_ino; | ||
644 | if (root->i_size == -1) | ||
645 | root->i_size = 2048; | ||
646 | if (root->i_blocks == -1) | ||
647 | root->i_blocks = 5; | ||
648 | hpfs_brelse4(&qbh); | ||
649 | } | ||
650 | return 0; | ||
651 | |||
652 | bail4: brelse(bh2); | ||
653 | bail3: brelse(bh1); | ||
654 | bail2: brelse(bh0); | ||
655 | bail1: | ||
656 | bail0: | ||
657 | if (sbi->sb_bmp_dir) kfree(sbi->sb_bmp_dir); | ||
658 | if (sbi->sb_cp_table) kfree(sbi->sb_cp_table); | ||
659 | s->s_fs_info = NULL; | ||
660 | kfree(sbi); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | |||
664 | static struct super_block *hpfs_get_sb(struct file_system_type *fs_type, | ||
665 | int flags, const char *dev_name, void *data) | ||
666 | { | ||
667 | return get_sb_bdev(fs_type, flags, dev_name, data, hpfs_fill_super); | ||
668 | } | ||
669 | |||
670 | static struct file_system_type hpfs_fs_type = { | ||
671 | .owner = THIS_MODULE, | ||
672 | .name = "hpfs", | ||
673 | .get_sb = hpfs_get_sb, | ||
674 | .kill_sb = kill_block_super, | ||
675 | .fs_flags = FS_REQUIRES_DEV, | ||
676 | }; | ||
677 | |||
678 | static int __init init_hpfs_fs(void) | ||
679 | { | ||
680 | int err = init_inodecache(); | ||
681 | if (err) | ||
682 | goto out1; | ||
683 | err = register_filesystem(&hpfs_fs_type); | ||
684 | if (err) | ||
685 | goto out; | ||
686 | return 0; | ||
687 | out: | ||
688 | destroy_inodecache(); | ||
689 | out1: | ||
690 | return err; | ||
691 | } | ||
692 | |||
693 | static void __exit exit_hpfs_fs(void) | ||
694 | { | ||
695 | unregister_filesystem(&hpfs_fs_type); | ||
696 | destroy_inodecache(); | ||
697 | } | ||
698 | |||
699 | module_init(init_hpfs_fs) | ||
700 | module_exit(exit_hpfs_fs) | ||
701 | MODULE_LICENSE("GPL"); | ||