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/udf |
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/udf')
-rw-r--r-- | fs/udf/Makefile | 9 | ||||
-rw-r--r-- | fs/udf/balloc.c | 959 | ||||
-rw-r--r-- | fs/udf/crc.c | 178 | ||||
-rw-r--r-- | fs/udf/dir.c | 268 | ||||
-rw-r--r-- | fs/udf/directory.c | 343 | ||||
-rw-r--r-- | fs/udf/ecma_167.h | 864 | ||||
-rw-r--r-- | fs/udf/file.c | 270 | ||||
-rw-r--r-- | fs/udf/fsync.c | 56 | ||||
-rw-r--r-- | fs/udf/ialloc.c | 170 | ||||
-rw-r--r-- | fs/udf/inode.c | 2010 | ||||
-rw-r--r-- | fs/udf/lowlevel.c | 77 | ||||
-rw-r--r-- | fs/udf/misc.c | 313 | ||||
-rw-r--r-- | fs/udf/namei.c | 1334 | ||||
-rw-r--r-- | fs/udf/osta_udf.h | 296 | ||||
-rw-r--r-- | fs/udf/partition.c | 226 | ||||
-rw-r--r-- | fs/udf/super.c | 1934 | ||||
-rw-r--r-- | fs/udf/symlink.c | 123 | ||||
-rw-r--r-- | fs/udf/truncate.c | 284 | ||||
-rw-r--r-- | fs/udf/udf_i.h | 26 | ||||
-rw-r--r-- | fs/udf/udf_sb.h | 139 | ||||
-rw-r--r-- | fs/udf/udfdecl.h | 167 | ||||
-rw-r--r-- | fs/udf/udfend.h | 81 | ||||
-rw-r--r-- | fs/udf/udftime.c | 174 | ||||
-rw-r--r-- | fs/udf/unicode.c | 516 |
24 files changed, 10817 insertions, 0 deletions
diff --git a/fs/udf/Makefile b/fs/udf/Makefile new file mode 100644 index 000000000000..be845e7540ef --- /dev/null +++ b/fs/udf/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # | ||
2 | # Makefile for the linux udf-filesystem routines. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_UDF_FS) += udf.o | ||
6 | |||
7 | udf-objs := balloc.o dir.o file.o ialloc.o inode.o lowlevel.o namei.o \ | ||
8 | partition.o super.o truncate.o symlink.o fsync.o \ | ||
9 | crc.o directory.o misc.o udftime.o unicode.o | ||
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c new file mode 100644 index 000000000000..b9ded26b10a9 --- /dev/null +++ b/fs/udf/balloc.c | |||
@@ -0,0 +1,959 @@ | |||
1 | /* | ||
2 | * balloc.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Block allocation handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1999-2001 Ben Fennema | ||
19 | * (C) 1999 Stelias Computing Inc | ||
20 | * | ||
21 | * HISTORY | ||
22 | * | ||
23 | * 02/24/99 blf Created. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "udfdecl.h" | ||
28 | |||
29 | #include <linux/quotaops.h> | ||
30 | #include <linux/buffer_head.h> | ||
31 | #include <linux/bitops.h> | ||
32 | |||
33 | #include "udf_i.h" | ||
34 | #include "udf_sb.h" | ||
35 | |||
36 | #define udf_clear_bit(nr,addr) ext2_clear_bit(nr,addr) | ||
37 | #define udf_set_bit(nr,addr) ext2_set_bit(nr,addr) | ||
38 | #define udf_test_bit(nr, addr) ext2_test_bit(nr, addr) | ||
39 | #define udf_find_first_one_bit(addr, size) find_first_one_bit(addr, size) | ||
40 | #define udf_find_next_one_bit(addr, size, offset) find_next_one_bit(addr, size, offset) | ||
41 | |||
42 | #define leBPL_to_cpup(x) leNUM_to_cpup(BITS_PER_LONG, x) | ||
43 | #define leNUM_to_cpup(x,y) xleNUM_to_cpup(x,y) | ||
44 | #define xleNUM_to_cpup(x,y) (le ## x ## _to_cpup(y)) | ||
45 | #define uintBPL_t uint(BITS_PER_LONG) | ||
46 | #define uint(x) xuint(x) | ||
47 | #define xuint(x) __le ## x | ||
48 | |||
49 | extern inline int find_next_one_bit (void * addr, int size, int offset) | ||
50 | { | ||
51 | uintBPL_t * p = ((uintBPL_t *) addr) + (offset / BITS_PER_LONG); | ||
52 | int result = offset & ~(BITS_PER_LONG-1); | ||
53 | unsigned long tmp; | ||
54 | |||
55 | if (offset >= size) | ||
56 | return size; | ||
57 | size -= result; | ||
58 | offset &= (BITS_PER_LONG-1); | ||
59 | if (offset) | ||
60 | { | ||
61 | tmp = leBPL_to_cpup(p++); | ||
62 | tmp &= ~0UL << offset; | ||
63 | if (size < BITS_PER_LONG) | ||
64 | goto found_first; | ||
65 | if (tmp) | ||
66 | goto found_middle; | ||
67 | size -= BITS_PER_LONG; | ||
68 | result += BITS_PER_LONG; | ||
69 | } | ||
70 | while (size & ~(BITS_PER_LONG-1)) | ||
71 | { | ||
72 | if ((tmp = leBPL_to_cpup(p++))) | ||
73 | goto found_middle; | ||
74 | result += BITS_PER_LONG; | ||
75 | size -= BITS_PER_LONG; | ||
76 | } | ||
77 | if (!size) | ||
78 | return result; | ||
79 | tmp = leBPL_to_cpup(p); | ||
80 | found_first: | ||
81 | tmp &= ~0UL >> (BITS_PER_LONG-size); | ||
82 | found_middle: | ||
83 | return result + ffz(~tmp); | ||
84 | } | ||
85 | |||
86 | #define find_first_one_bit(addr, size)\ | ||
87 | find_next_one_bit((addr), (size), 0) | ||
88 | |||
89 | static int read_block_bitmap(struct super_block * sb, | ||
90 | struct udf_bitmap *bitmap, unsigned int block, unsigned long bitmap_nr) | ||
91 | { | ||
92 | struct buffer_head *bh = NULL; | ||
93 | int retval = 0; | ||
94 | kernel_lb_addr loc; | ||
95 | |||
96 | loc.logicalBlockNum = bitmap->s_extPosition; | ||
97 | loc.partitionReferenceNum = UDF_SB_PARTITION(sb); | ||
98 | |||
99 | bh = udf_tread(sb, udf_get_lb_pblock(sb, loc, block)); | ||
100 | if (!bh) | ||
101 | { | ||
102 | retval = -EIO; | ||
103 | } | ||
104 | bitmap->s_block_bitmap[bitmap_nr] = bh; | ||
105 | return retval; | ||
106 | } | ||
107 | |||
108 | static int __load_block_bitmap(struct super_block * sb, | ||
109 | struct udf_bitmap *bitmap, unsigned int block_group) | ||
110 | { | ||
111 | int retval = 0; | ||
112 | int nr_groups = bitmap->s_nr_groups; | ||
113 | |||
114 | if (block_group >= nr_groups) | ||
115 | { | ||
116 | udf_debug("block_group (%d) > nr_groups (%d)\n", block_group, nr_groups); | ||
117 | } | ||
118 | |||
119 | if (bitmap->s_block_bitmap[block_group]) | ||
120 | return block_group; | ||
121 | else | ||
122 | { | ||
123 | retval = read_block_bitmap(sb, bitmap, block_group, block_group); | ||
124 | if (retval < 0) | ||
125 | return retval; | ||
126 | return block_group; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static inline int load_block_bitmap(struct super_block * sb, | ||
131 | struct udf_bitmap *bitmap, unsigned int block_group) | ||
132 | { | ||
133 | int slot; | ||
134 | |||
135 | slot = __load_block_bitmap(sb, bitmap, block_group); | ||
136 | |||
137 | if (slot < 0) | ||
138 | return slot; | ||
139 | |||
140 | if (!bitmap->s_block_bitmap[slot]) | ||
141 | return -EIO; | ||
142 | |||
143 | return slot; | ||
144 | } | ||
145 | |||
146 | static void udf_bitmap_free_blocks(struct super_block * sb, | ||
147 | struct inode * inode, | ||
148 | struct udf_bitmap *bitmap, | ||
149 | kernel_lb_addr bloc, uint32_t offset, uint32_t count) | ||
150 | { | ||
151 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
152 | struct buffer_head * bh = NULL; | ||
153 | unsigned long block; | ||
154 | unsigned long block_group; | ||
155 | unsigned long bit; | ||
156 | unsigned long i; | ||
157 | int bitmap_nr; | ||
158 | unsigned long overflow; | ||
159 | |||
160 | down(&sbi->s_alloc_sem); | ||
161 | if (bloc.logicalBlockNum < 0 || | ||
162 | (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) | ||
163 | { | ||
164 | udf_debug("%d < %d || %d + %d > %d\n", | ||
165 | bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, | ||
166 | UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)); | ||
167 | goto error_return; | ||
168 | } | ||
169 | |||
170 | block = bloc.logicalBlockNum + offset + (sizeof(struct spaceBitmapDesc) << 3); | ||
171 | |||
172 | do_more: | ||
173 | overflow = 0; | ||
174 | block_group = block >> (sb->s_blocksize_bits + 3); | ||
175 | bit = block % (sb->s_blocksize << 3); | ||
176 | |||
177 | /* | ||
178 | * Check to see if we are freeing blocks across a group boundary. | ||
179 | */ | ||
180 | if (bit + count > (sb->s_blocksize << 3)) | ||
181 | { | ||
182 | overflow = bit + count - (sb->s_blocksize << 3); | ||
183 | count -= overflow; | ||
184 | } | ||
185 | bitmap_nr = load_block_bitmap(sb, bitmap, block_group); | ||
186 | if (bitmap_nr < 0) | ||
187 | goto error_return; | ||
188 | |||
189 | bh = bitmap->s_block_bitmap[bitmap_nr]; | ||
190 | for (i=0; i < count; i++) | ||
191 | { | ||
192 | if (udf_set_bit(bit + i, bh->b_data)) | ||
193 | { | ||
194 | udf_debug("bit %ld already set\n", bit + i); | ||
195 | udf_debug("byte=%2x\n", ((char *)bh->b_data)[(bit + i) >> 3]); | ||
196 | } | ||
197 | else | ||
198 | { | ||
199 | if (inode) | ||
200 | DQUOT_FREE_BLOCK(inode, 1); | ||
201 | if (UDF_SB_LVIDBH(sb)) | ||
202 | { | ||
203 | UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = | ||
204 | cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+1); | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | mark_buffer_dirty(bh); | ||
209 | if (overflow) | ||
210 | { | ||
211 | block += count; | ||
212 | count = overflow; | ||
213 | goto do_more; | ||
214 | } | ||
215 | error_return: | ||
216 | sb->s_dirt = 1; | ||
217 | if (UDF_SB_LVIDBH(sb)) | ||
218 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
219 | up(&sbi->s_alloc_sem); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | static int udf_bitmap_prealloc_blocks(struct super_block * sb, | ||
224 | struct inode * inode, | ||
225 | struct udf_bitmap *bitmap, uint16_t partition, uint32_t first_block, | ||
226 | uint32_t block_count) | ||
227 | { | ||
228 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
229 | int alloc_count = 0; | ||
230 | int bit, block, block_group, group_start; | ||
231 | int nr_groups, bitmap_nr; | ||
232 | struct buffer_head *bh; | ||
233 | |||
234 | down(&sbi->s_alloc_sem); | ||
235 | if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition)) | ||
236 | goto out; | ||
237 | |||
238 | if (first_block + block_count > UDF_SB_PARTLEN(sb, partition)) | ||
239 | block_count = UDF_SB_PARTLEN(sb, partition) - first_block; | ||
240 | |||
241 | repeat: | ||
242 | nr_groups = (UDF_SB_PARTLEN(sb, partition) + | ||
243 | (sizeof(struct spaceBitmapDesc) << 3) + (sb->s_blocksize * 8) - 1) / (sb->s_blocksize * 8); | ||
244 | block = first_block + (sizeof(struct spaceBitmapDesc) << 3); | ||
245 | block_group = block >> (sb->s_blocksize_bits + 3); | ||
246 | group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc); | ||
247 | |||
248 | bitmap_nr = load_block_bitmap(sb, bitmap, block_group); | ||
249 | if (bitmap_nr < 0) | ||
250 | goto out; | ||
251 | bh = bitmap->s_block_bitmap[bitmap_nr]; | ||
252 | |||
253 | bit = block % (sb->s_blocksize << 3); | ||
254 | |||
255 | while (bit < (sb->s_blocksize << 3) && block_count > 0) | ||
256 | { | ||
257 | if (!udf_test_bit(bit, bh->b_data)) | ||
258 | goto out; | ||
259 | else if (DQUOT_PREALLOC_BLOCK(inode, 1)) | ||
260 | goto out; | ||
261 | else if (!udf_clear_bit(bit, bh->b_data)) | ||
262 | { | ||
263 | udf_debug("bit already cleared for block %d\n", bit); | ||
264 | DQUOT_FREE_BLOCK(inode, 1); | ||
265 | goto out; | ||
266 | } | ||
267 | block_count --; | ||
268 | alloc_count ++; | ||
269 | bit ++; | ||
270 | block ++; | ||
271 | } | ||
272 | mark_buffer_dirty(bh); | ||
273 | if (block_count > 0) | ||
274 | goto repeat; | ||
275 | out: | ||
276 | if (UDF_SB_LVIDBH(sb)) | ||
277 | { | ||
278 | UDF_SB_LVID(sb)->freeSpaceTable[partition] = | ||
279 | cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count); | ||
280 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
281 | } | ||
282 | sb->s_dirt = 1; | ||
283 | up(&sbi->s_alloc_sem); | ||
284 | return alloc_count; | ||
285 | } | ||
286 | |||
287 | static int udf_bitmap_new_block(struct super_block * sb, | ||
288 | struct inode * inode, | ||
289 | struct udf_bitmap *bitmap, uint16_t partition, uint32_t goal, int *err) | ||
290 | { | ||
291 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
292 | int newbit, bit=0, block, block_group, group_start; | ||
293 | int end_goal, nr_groups, bitmap_nr, i; | ||
294 | struct buffer_head *bh = NULL; | ||
295 | char *ptr; | ||
296 | int newblock = 0; | ||
297 | |||
298 | *err = -ENOSPC; | ||
299 | down(&sbi->s_alloc_sem); | ||
300 | |||
301 | repeat: | ||
302 | if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition)) | ||
303 | goal = 0; | ||
304 | |||
305 | nr_groups = bitmap->s_nr_groups; | ||
306 | block = goal + (sizeof(struct spaceBitmapDesc) << 3); | ||
307 | block_group = block >> (sb->s_blocksize_bits + 3); | ||
308 | group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc); | ||
309 | |||
310 | bitmap_nr = load_block_bitmap(sb, bitmap, block_group); | ||
311 | if (bitmap_nr < 0) | ||
312 | goto error_return; | ||
313 | bh = bitmap->s_block_bitmap[bitmap_nr]; | ||
314 | ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start); | ||
315 | |||
316 | if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) | ||
317 | { | ||
318 | bit = block % (sb->s_blocksize << 3); | ||
319 | |||
320 | if (udf_test_bit(bit, bh->b_data)) | ||
321 | { | ||
322 | goto got_block; | ||
323 | } | ||
324 | end_goal = (bit + 63) & ~63; | ||
325 | bit = udf_find_next_one_bit(bh->b_data, end_goal, bit); | ||
326 | if (bit < end_goal) | ||
327 | goto got_block; | ||
328 | ptr = memscan((char *)bh->b_data + (bit >> 3), 0xFF, sb->s_blocksize - ((bit + 7) >> 3)); | ||
329 | newbit = (ptr - ((char *)bh->b_data)) << 3; | ||
330 | if (newbit < sb->s_blocksize << 3) | ||
331 | { | ||
332 | bit = newbit; | ||
333 | goto search_back; | ||
334 | } | ||
335 | newbit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, bit); | ||
336 | if (newbit < sb->s_blocksize << 3) | ||
337 | { | ||
338 | bit = newbit; | ||
339 | goto got_block; | ||
340 | } | ||
341 | } | ||
342 | |||
343 | for (i=0; i<(nr_groups*2); i++) | ||
344 | { | ||
345 | block_group ++; | ||
346 | if (block_group >= nr_groups) | ||
347 | block_group = 0; | ||
348 | group_start = block_group ? 0 : sizeof(struct spaceBitmapDesc); | ||
349 | |||
350 | bitmap_nr = load_block_bitmap(sb, bitmap, block_group); | ||
351 | if (bitmap_nr < 0) | ||
352 | goto error_return; | ||
353 | bh = bitmap->s_block_bitmap[bitmap_nr]; | ||
354 | if (i < nr_groups) | ||
355 | { | ||
356 | ptr = memscan((char *)bh->b_data + group_start, 0xFF, sb->s_blocksize - group_start); | ||
357 | if ((ptr - ((char *)bh->b_data)) < sb->s_blocksize) | ||
358 | { | ||
359 | bit = (ptr - ((char *)bh->b_data)) << 3; | ||
360 | break; | ||
361 | } | ||
362 | } | ||
363 | else | ||
364 | { | ||
365 | bit = udf_find_next_one_bit((char *)bh->b_data, sb->s_blocksize << 3, group_start << 3); | ||
366 | if (bit < sb->s_blocksize << 3) | ||
367 | break; | ||
368 | } | ||
369 | } | ||
370 | if (i >= (nr_groups*2)) | ||
371 | { | ||
372 | up(&sbi->s_alloc_sem); | ||
373 | return newblock; | ||
374 | } | ||
375 | if (bit < sb->s_blocksize << 3) | ||
376 | goto search_back; | ||
377 | else | ||
378 | bit = udf_find_next_one_bit(bh->b_data, sb->s_blocksize << 3, group_start << 3); | ||
379 | if (bit >= sb->s_blocksize << 3) | ||
380 | { | ||
381 | up(&sbi->s_alloc_sem); | ||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | search_back: | ||
386 | for (i=0; i<7 && bit > (group_start << 3) && udf_test_bit(bit - 1, bh->b_data); i++, bit--); | ||
387 | |||
388 | got_block: | ||
389 | |||
390 | /* | ||
391 | * Check quota for allocation of this block. | ||
392 | */ | ||
393 | if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) | ||
394 | { | ||
395 | up(&sbi->s_alloc_sem); | ||
396 | *err = -EDQUOT; | ||
397 | return 0; | ||
398 | } | ||
399 | |||
400 | newblock = bit + (block_group << (sb->s_blocksize_bits + 3)) - | ||
401 | (sizeof(struct spaceBitmapDesc) << 3); | ||
402 | |||
403 | if (!udf_clear_bit(bit, bh->b_data)) | ||
404 | { | ||
405 | udf_debug("bit already cleared for block %d\n", bit); | ||
406 | goto repeat; | ||
407 | } | ||
408 | |||
409 | mark_buffer_dirty(bh); | ||
410 | |||
411 | if (UDF_SB_LVIDBH(sb)) | ||
412 | { | ||
413 | UDF_SB_LVID(sb)->freeSpaceTable[partition] = | ||
414 | cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1); | ||
415 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
416 | } | ||
417 | sb->s_dirt = 1; | ||
418 | up(&sbi->s_alloc_sem); | ||
419 | *err = 0; | ||
420 | return newblock; | ||
421 | |||
422 | error_return: | ||
423 | *err = -EIO; | ||
424 | up(&sbi->s_alloc_sem); | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static void udf_table_free_blocks(struct super_block * sb, | ||
429 | struct inode * inode, | ||
430 | struct inode * table, | ||
431 | kernel_lb_addr bloc, uint32_t offset, uint32_t count) | ||
432 | { | ||
433 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
434 | uint32_t start, end; | ||
435 | uint32_t nextoffset, oextoffset, elen; | ||
436 | kernel_lb_addr nbloc, obloc, eloc; | ||
437 | struct buffer_head *obh, *nbh; | ||
438 | int8_t etype; | ||
439 | int i; | ||
440 | |||
441 | down(&sbi->s_alloc_sem); | ||
442 | if (bloc.logicalBlockNum < 0 || | ||
443 | (bloc.logicalBlockNum + count) > UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)) | ||
444 | { | ||
445 | udf_debug("%d < %d || %d + %d > %d\n", | ||
446 | bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, | ||
447 | UDF_SB_PARTLEN(sb, bloc.partitionReferenceNum)); | ||
448 | goto error_return; | ||
449 | } | ||
450 | |||
451 | /* We do this up front - There are some error conditions that could occure, | ||
452 | but.. oh well */ | ||
453 | if (inode) | ||
454 | DQUOT_FREE_BLOCK(inode, count); | ||
455 | if (UDF_SB_LVIDBH(sb)) | ||
456 | { | ||
457 | UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)] = | ||
458 | cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)])+count); | ||
459 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
460 | } | ||
461 | |||
462 | start = bloc.logicalBlockNum + offset; | ||
463 | end = bloc.logicalBlockNum + offset + count - 1; | ||
464 | |||
465 | oextoffset = nextoffset = sizeof(struct unallocSpaceEntry); | ||
466 | elen = 0; | ||
467 | obloc = nbloc = UDF_I_LOCATION(table); | ||
468 | |||
469 | obh = nbh = NULL; | ||
470 | |||
471 | while (count && (etype = | ||
472 | udf_next_aext(table, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) | ||
473 | { | ||
474 | if (((eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) == | ||
475 | start)) | ||
476 | { | ||
477 | if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) | ||
478 | { | ||
479 | count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits); | ||
480 | start += ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits); | ||
481 | elen = (etype << 30) | (0x40000000 - sb->s_blocksize); | ||
482 | } | ||
483 | else | ||
484 | { | ||
485 | elen = (etype << 30) | | ||
486 | (elen + (count << sb->s_blocksize_bits)); | ||
487 | start += count; | ||
488 | count = 0; | ||
489 | } | ||
490 | udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1); | ||
491 | } | ||
492 | else if (eloc.logicalBlockNum == (end + 1)) | ||
493 | { | ||
494 | if ((0x3FFFFFFF - elen) < (count << sb->s_blocksize_bits)) | ||
495 | { | ||
496 | count -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits); | ||
497 | end -= ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits); | ||
498 | eloc.logicalBlockNum -= | ||
499 | ((0x3FFFFFFF - elen) >> sb->s_blocksize_bits); | ||
500 | elen = (etype << 30) | (0x40000000 - sb->s_blocksize); | ||
501 | } | ||
502 | else | ||
503 | { | ||
504 | eloc.logicalBlockNum = start; | ||
505 | elen = (etype << 30) | | ||
506 | (elen + (count << sb->s_blocksize_bits)); | ||
507 | end -= count; | ||
508 | count = 0; | ||
509 | } | ||
510 | udf_write_aext(table, obloc, &oextoffset, eloc, elen, obh, 1); | ||
511 | } | ||
512 | |||
513 | if (nbh != obh) | ||
514 | { | ||
515 | i = -1; | ||
516 | obloc = nbloc; | ||
517 | udf_release_data(obh); | ||
518 | atomic_inc(&nbh->b_count); | ||
519 | obh = nbh; | ||
520 | oextoffset = 0; | ||
521 | } | ||
522 | else | ||
523 | oextoffset = nextoffset; | ||
524 | } | ||
525 | |||
526 | if (count) | ||
527 | { | ||
528 | /* NOTE: we CANNOT use udf_add_aext here, as it can try to allocate | ||
529 | a new block, and since we hold the super block lock already | ||
530 | very bad things would happen :) | ||
531 | |||
532 | We copy the behavior of udf_add_aext, but instead of | ||
533 | trying to allocate a new block close to the existing one, | ||
534 | we just steal a block from the extent we are trying to add. | ||
535 | |||
536 | It would be nice if the blocks were close together, but it | ||
537 | isn't required. | ||
538 | */ | ||
539 | |||
540 | int adsize; | ||
541 | short_ad *sad = NULL; | ||
542 | long_ad *lad = NULL; | ||
543 | struct allocExtDesc *aed; | ||
544 | |||
545 | eloc.logicalBlockNum = start; | ||
546 | elen = EXT_RECORDED_ALLOCATED | | ||
547 | (count << sb->s_blocksize_bits); | ||
548 | |||
549 | if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT) | ||
550 | adsize = sizeof(short_ad); | ||
551 | else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG) | ||
552 | adsize = sizeof(long_ad); | ||
553 | else | ||
554 | { | ||
555 | udf_release_data(obh); | ||
556 | udf_release_data(nbh); | ||
557 | goto error_return; | ||
558 | } | ||
559 | |||
560 | if (nextoffset + (2 * adsize) > sb->s_blocksize) | ||
561 | { | ||
562 | char *sptr, *dptr; | ||
563 | int loffset; | ||
564 | |||
565 | udf_release_data(obh); | ||
566 | obh = nbh; | ||
567 | obloc = nbloc; | ||
568 | oextoffset = nextoffset; | ||
569 | |||
570 | /* Steal a block from the extent being free'd */ | ||
571 | nbloc.logicalBlockNum = eloc.logicalBlockNum; | ||
572 | eloc.logicalBlockNum ++; | ||
573 | elen -= sb->s_blocksize; | ||
574 | |||
575 | if (!(nbh = udf_tread(sb, | ||
576 | udf_get_lb_pblock(sb, nbloc, 0)))) | ||
577 | { | ||
578 | udf_release_data(obh); | ||
579 | goto error_return; | ||
580 | } | ||
581 | aed = (struct allocExtDesc *)(nbh->b_data); | ||
582 | aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum); | ||
583 | if (nextoffset + adsize > sb->s_blocksize) | ||
584 | { | ||
585 | loffset = nextoffset; | ||
586 | aed->lengthAllocDescs = cpu_to_le32(adsize); | ||
587 | if (obh) | ||
588 | sptr = UDF_I_DATA(inode) + nextoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode) - adsize; | ||
589 | else | ||
590 | sptr = obh->b_data + nextoffset - adsize; | ||
591 | dptr = nbh->b_data + sizeof(struct allocExtDesc); | ||
592 | memcpy(dptr, sptr, adsize); | ||
593 | nextoffset = sizeof(struct allocExtDesc) + adsize; | ||
594 | } | ||
595 | else | ||
596 | { | ||
597 | loffset = nextoffset + adsize; | ||
598 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
599 | sptr = (obh)->b_data + nextoffset; | ||
600 | nextoffset = sizeof(struct allocExtDesc); | ||
601 | |||
602 | if (obh) | ||
603 | { | ||
604 | aed = (struct allocExtDesc *)(obh)->b_data; | ||
605 | aed->lengthAllocDescs = | ||
606 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); | ||
607 | } | ||
608 | else | ||
609 | { | ||
610 | UDF_I_LENALLOC(table) += adsize; | ||
611 | mark_inode_dirty(table); | ||
612 | } | ||
613 | } | ||
614 | if (UDF_SB_UDFREV(sb) >= 0x0200) | ||
615 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, | ||
616 | nbloc.logicalBlockNum, sizeof(tag)); | ||
617 | else | ||
618 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, | ||
619 | nbloc.logicalBlockNum, sizeof(tag)); | ||
620 | switch (UDF_I_ALLOCTYPE(table)) | ||
621 | { | ||
622 | case ICBTAG_FLAG_AD_SHORT: | ||
623 | { | ||
624 | sad = (short_ad *)sptr; | ||
625 | sad->extLength = cpu_to_le32( | ||
626 | EXT_NEXT_EXTENT_ALLOCDECS | | ||
627 | sb->s_blocksize); | ||
628 | sad->extPosition = cpu_to_le32(nbloc.logicalBlockNum); | ||
629 | break; | ||
630 | } | ||
631 | case ICBTAG_FLAG_AD_LONG: | ||
632 | { | ||
633 | lad = (long_ad *)sptr; | ||
634 | lad->extLength = cpu_to_le32( | ||
635 | EXT_NEXT_EXTENT_ALLOCDECS | | ||
636 | sb->s_blocksize); | ||
637 | lad->extLocation = cpu_to_lelb(nbloc); | ||
638 | break; | ||
639 | } | ||
640 | } | ||
641 | if (obh) | ||
642 | { | ||
643 | udf_update_tag(obh->b_data, loffset); | ||
644 | mark_buffer_dirty(obh); | ||
645 | } | ||
646 | else | ||
647 | mark_inode_dirty(table); | ||
648 | } | ||
649 | |||
650 | if (elen) /* It's possible that stealing the block emptied the extent */ | ||
651 | { | ||
652 | udf_write_aext(table, nbloc, &nextoffset, eloc, elen, nbh, 1); | ||
653 | |||
654 | if (!nbh) | ||
655 | { | ||
656 | UDF_I_LENALLOC(table) += adsize; | ||
657 | mark_inode_dirty(table); | ||
658 | } | ||
659 | else | ||
660 | { | ||
661 | aed = (struct allocExtDesc *)nbh->b_data; | ||
662 | aed->lengthAllocDescs = | ||
663 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); | ||
664 | udf_update_tag(nbh->b_data, nextoffset); | ||
665 | mark_buffer_dirty(nbh); | ||
666 | } | ||
667 | } | ||
668 | } | ||
669 | |||
670 | udf_release_data(nbh); | ||
671 | udf_release_data(obh); | ||
672 | |||
673 | error_return: | ||
674 | sb->s_dirt = 1; | ||
675 | up(&sbi->s_alloc_sem); | ||
676 | return; | ||
677 | } | ||
678 | |||
679 | static int udf_table_prealloc_blocks(struct super_block * sb, | ||
680 | struct inode * inode, | ||
681 | struct inode *table, uint16_t partition, uint32_t first_block, | ||
682 | uint32_t block_count) | ||
683 | { | ||
684 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
685 | int alloc_count = 0; | ||
686 | uint32_t extoffset, elen, adsize; | ||
687 | kernel_lb_addr bloc, eloc; | ||
688 | struct buffer_head *bh; | ||
689 | int8_t etype = -1; | ||
690 | |||
691 | if (first_block < 0 || first_block >= UDF_SB_PARTLEN(sb, partition)) | ||
692 | return 0; | ||
693 | |||
694 | if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT) | ||
695 | adsize = sizeof(short_ad); | ||
696 | else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG) | ||
697 | adsize = sizeof(long_ad); | ||
698 | else | ||
699 | return 0; | ||
700 | |||
701 | down(&sbi->s_alloc_sem); | ||
702 | extoffset = sizeof(struct unallocSpaceEntry); | ||
703 | bloc = UDF_I_LOCATION(table); | ||
704 | |||
705 | bh = NULL; | ||
706 | eloc.logicalBlockNum = 0xFFFFFFFF; | ||
707 | |||
708 | while (first_block != eloc.logicalBlockNum && (etype = | ||
709 | udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) | ||
710 | { | ||
711 | udf_debug("eloc=%d, elen=%d, first_block=%d\n", | ||
712 | eloc.logicalBlockNum, elen, first_block); | ||
713 | ; /* empty loop body */ | ||
714 | } | ||
715 | |||
716 | if (first_block == eloc.logicalBlockNum) | ||
717 | { | ||
718 | extoffset -= adsize; | ||
719 | |||
720 | alloc_count = (elen >> sb->s_blocksize_bits); | ||
721 | if (inode && DQUOT_PREALLOC_BLOCK(inode, alloc_count > block_count ? block_count : alloc_count)) | ||
722 | alloc_count = 0; | ||
723 | else if (alloc_count > block_count) | ||
724 | { | ||
725 | alloc_count = block_count; | ||
726 | eloc.logicalBlockNum += alloc_count; | ||
727 | elen -= (alloc_count << sb->s_blocksize_bits); | ||
728 | udf_write_aext(table, bloc, &extoffset, eloc, (etype << 30) | elen, bh, 1); | ||
729 | } | ||
730 | else | ||
731 | udf_delete_aext(table, bloc, extoffset, eloc, (etype << 30) | elen, bh); | ||
732 | } | ||
733 | else | ||
734 | alloc_count = 0; | ||
735 | |||
736 | udf_release_data(bh); | ||
737 | |||
738 | if (alloc_count && UDF_SB_LVIDBH(sb)) | ||
739 | { | ||
740 | UDF_SB_LVID(sb)->freeSpaceTable[partition] = | ||
741 | cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-alloc_count); | ||
742 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
743 | sb->s_dirt = 1; | ||
744 | } | ||
745 | up(&sbi->s_alloc_sem); | ||
746 | return alloc_count; | ||
747 | } | ||
748 | |||
749 | static int udf_table_new_block(struct super_block * sb, | ||
750 | struct inode * inode, | ||
751 | struct inode *table, uint16_t partition, uint32_t goal, int *err) | ||
752 | { | ||
753 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
754 | uint32_t spread = 0xFFFFFFFF, nspread = 0xFFFFFFFF; | ||
755 | uint32_t newblock = 0, adsize; | ||
756 | uint32_t extoffset, goal_extoffset, elen, goal_elen = 0; | ||
757 | kernel_lb_addr bloc, goal_bloc, eloc, goal_eloc; | ||
758 | struct buffer_head *bh, *goal_bh; | ||
759 | int8_t etype; | ||
760 | |||
761 | *err = -ENOSPC; | ||
762 | |||
763 | if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_SHORT) | ||
764 | adsize = sizeof(short_ad); | ||
765 | else if (UDF_I_ALLOCTYPE(table) == ICBTAG_FLAG_AD_LONG) | ||
766 | adsize = sizeof(long_ad); | ||
767 | else | ||
768 | return newblock; | ||
769 | |||
770 | down(&sbi->s_alloc_sem); | ||
771 | if (goal < 0 || goal >= UDF_SB_PARTLEN(sb, partition)) | ||
772 | goal = 0; | ||
773 | |||
774 | /* We search for the closest matching block to goal. If we find a exact hit, | ||
775 | we stop. Otherwise we keep going till we run out of extents. | ||
776 | We store the buffer_head, bloc, and extoffset of the current closest | ||
777 | match and use that when we are done. | ||
778 | */ | ||
779 | |||
780 | extoffset = sizeof(struct unallocSpaceEntry); | ||
781 | bloc = UDF_I_LOCATION(table); | ||
782 | |||
783 | goal_bh = bh = NULL; | ||
784 | |||
785 | while (spread && (etype = | ||
786 | udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) | ||
787 | { | ||
788 | if (goal >= eloc.logicalBlockNum) | ||
789 | { | ||
790 | if (goal < eloc.logicalBlockNum + (elen >> sb->s_blocksize_bits)) | ||
791 | nspread = 0; | ||
792 | else | ||
793 | nspread = goal - eloc.logicalBlockNum - | ||
794 | (elen >> sb->s_blocksize_bits); | ||
795 | } | ||
796 | else | ||
797 | nspread = eloc.logicalBlockNum - goal; | ||
798 | |||
799 | if (nspread < spread) | ||
800 | { | ||
801 | spread = nspread; | ||
802 | if (goal_bh != bh) | ||
803 | { | ||
804 | udf_release_data(goal_bh); | ||
805 | goal_bh = bh; | ||
806 | atomic_inc(&goal_bh->b_count); | ||
807 | } | ||
808 | goal_bloc = bloc; | ||
809 | goal_extoffset = extoffset - adsize; | ||
810 | goal_eloc = eloc; | ||
811 | goal_elen = (etype << 30) | elen; | ||
812 | } | ||
813 | } | ||
814 | |||
815 | udf_release_data(bh); | ||
816 | |||
817 | if (spread == 0xFFFFFFFF) | ||
818 | { | ||
819 | udf_release_data(goal_bh); | ||
820 | up(&sbi->s_alloc_sem); | ||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | /* Only allocate blocks from the beginning of the extent. | ||
825 | That way, we only delete (empty) extents, never have to insert an | ||
826 | extent because of splitting */ | ||
827 | /* This works, but very poorly.... */ | ||
828 | |||
829 | newblock = goal_eloc.logicalBlockNum; | ||
830 | goal_eloc.logicalBlockNum ++; | ||
831 | goal_elen -= sb->s_blocksize; | ||
832 | |||
833 | if (inode && DQUOT_ALLOC_BLOCK(inode, 1)) | ||
834 | { | ||
835 | udf_release_data(goal_bh); | ||
836 | up(&sbi->s_alloc_sem); | ||
837 | *err = -EDQUOT; | ||
838 | return 0; | ||
839 | } | ||
840 | |||
841 | if (goal_elen) | ||
842 | udf_write_aext(table, goal_bloc, &goal_extoffset, goal_eloc, goal_elen, goal_bh, 1); | ||
843 | else | ||
844 | udf_delete_aext(table, goal_bloc, goal_extoffset, goal_eloc, goal_elen, goal_bh); | ||
845 | udf_release_data(goal_bh); | ||
846 | |||
847 | if (UDF_SB_LVIDBH(sb)) | ||
848 | { | ||
849 | UDF_SB_LVID(sb)->freeSpaceTable[partition] = | ||
850 | cpu_to_le32(le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[partition])-1); | ||
851 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
852 | } | ||
853 | |||
854 | sb->s_dirt = 1; | ||
855 | up(&sbi->s_alloc_sem); | ||
856 | *err = 0; | ||
857 | return newblock; | ||
858 | } | ||
859 | |||
860 | inline void udf_free_blocks(struct super_block * sb, | ||
861 | struct inode * inode, | ||
862 | kernel_lb_addr bloc, uint32_t offset, uint32_t count) | ||
863 | { | ||
864 | uint16_t partition = bloc.partitionReferenceNum; | ||
865 | |||
866 | if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
867 | { | ||
868 | return udf_bitmap_free_blocks(sb, inode, | ||
869 | UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap, | ||
870 | bloc, offset, count); | ||
871 | } | ||
872 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) | ||
873 | { | ||
874 | return udf_table_free_blocks(sb, inode, | ||
875 | UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table, | ||
876 | bloc, offset, count); | ||
877 | } | ||
878 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) | ||
879 | { | ||
880 | return udf_bitmap_free_blocks(sb, inode, | ||
881 | UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap, | ||
882 | bloc, offset, count); | ||
883 | } | ||
884 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) | ||
885 | { | ||
886 | return udf_table_free_blocks(sb, inode, | ||
887 | UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table, | ||
888 | bloc, offset, count); | ||
889 | } | ||
890 | else | ||
891 | return; | ||
892 | } | ||
893 | |||
894 | inline int udf_prealloc_blocks(struct super_block * sb, | ||
895 | struct inode * inode, | ||
896 | uint16_t partition, uint32_t first_block, uint32_t block_count) | ||
897 | { | ||
898 | if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
899 | { | ||
900 | return udf_bitmap_prealloc_blocks(sb, inode, | ||
901 | UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap, | ||
902 | partition, first_block, block_count); | ||
903 | } | ||
904 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) | ||
905 | { | ||
906 | return udf_table_prealloc_blocks(sb, inode, | ||
907 | UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table, | ||
908 | partition, first_block, block_count); | ||
909 | } | ||
910 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) | ||
911 | { | ||
912 | return udf_bitmap_prealloc_blocks(sb, inode, | ||
913 | UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap, | ||
914 | partition, first_block, block_count); | ||
915 | } | ||
916 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) | ||
917 | { | ||
918 | return udf_table_prealloc_blocks(sb, inode, | ||
919 | UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table, | ||
920 | partition, first_block, block_count); | ||
921 | } | ||
922 | else | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | inline int udf_new_block(struct super_block * sb, | ||
927 | struct inode * inode, | ||
928 | uint16_t partition, uint32_t goal, int *err) | ||
929 | { | ||
930 | if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
931 | { | ||
932 | return udf_bitmap_new_block(sb, inode, | ||
933 | UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_bitmap, | ||
934 | partition, goal, err); | ||
935 | } | ||
936 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_UNALLOC_TABLE) | ||
937 | { | ||
938 | return udf_table_new_block(sb, inode, | ||
939 | UDF_SB_PARTMAPS(sb)[partition].s_uspace.s_table, | ||
940 | partition, goal, err); | ||
941 | } | ||
942 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_BITMAP) | ||
943 | { | ||
944 | return udf_bitmap_new_block(sb, inode, | ||
945 | UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_bitmap, | ||
946 | partition, goal, err); | ||
947 | } | ||
948 | else if (UDF_SB_PARTFLAGS(sb, partition) & UDF_PART_FLAG_FREED_TABLE) | ||
949 | { | ||
950 | return udf_table_new_block(sb, inode, | ||
951 | UDF_SB_PARTMAPS(sb)[partition].s_fspace.s_table, | ||
952 | partition, goal, err); | ||
953 | } | ||
954 | else | ||
955 | { | ||
956 | *err = -EIO; | ||
957 | return 0; | ||
958 | } | ||
959 | } | ||
diff --git a/fs/udf/crc.c b/fs/udf/crc.c new file mode 100644 index 000000000000..d95c6e38a455 --- /dev/null +++ b/fs/udf/crc.c | |||
@@ -0,0 +1,178 @@ | |||
1 | /* | ||
2 | * crc.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Routines to generate, calculate, and test a 16-bit CRC. | ||
6 | * | ||
7 | * DESCRIPTION | ||
8 | * The CRC code was devised by Don P. Mitchell of AT&T Bell Laboratories | ||
9 | * and Ned W. Rhodes of Software Systems Group. It has been published in | ||
10 | * "Design and Validation of Computer Protocols", Prentice Hall, | ||
11 | * Englewood Cliffs, NJ, 1991, Chapter 3, ISBN 0-13-539925-4. | ||
12 | * | ||
13 | * Copyright is held by AT&T. | ||
14 | * | ||
15 | * AT&T gives permission for the free use of the CRC source code. | ||
16 | * | ||
17 | * CONTACTS | ||
18 | * E-mail regarding any portion of the Linux UDF file system should be | ||
19 | * directed to the development team mailing list (run by majordomo): | ||
20 | * linux_udf@hpesjro.fc.hp.com | ||
21 | * | ||
22 | * COPYRIGHT | ||
23 | * This file is distributed under the terms of the GNU General Public | ||
24 | * License (GPL). Copies of the GPL can be obtained from: | ||
25 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
26 | * Each contributing author retains all rights to their own work. | ||
27 | */ | ||
28 | |||
29 | #include "udfdecl.h" | ||
30 | |||
31 | static uint16_t crc_table[256] = { | ||
32 | 0x0000U, 0x1021U, 0x2042U, 0x3063U, 0x4084U, 0x50a5U, 0x60c6U, 0x70e7U, | ||
33 | 0x8108U, 0x9129U, 0xa14aU, 0xb16bU, 0xc18cU, 0xd1adU, 0xe1ceU, 0xf1efU, | ||
34 | 0x1231U, 0x0210U, 0x3273U, 0x2252U, 0x52b5U, 0x4294U, 0x72f7U, 0x62d6U, | ||
35 | 0x9339U, 0x8318U, 0xb37bU, 0xa35aU, 0xd3bdU, 0xc39cU, 0xf3ffU, 0xe3deU, | ||
36 | 0x2462U, 0x3443U, 0x0420U, 0x1401U, 0x64e6U, 0x74c7U, 0x44a4U, 0x5485U, | ||
37 | 0xa56aU, 0xb54bU, 0x8528U, 0x9509U, 0xe5eeU, 0xf5cfU, 0xc5acU, 0xd58dU, | ||
38 | 0x3653U, 0x2672U, 0x1611U, 0x0630U, 0x76d7U, 0x66f6U, 0x5695U, 0x46b4U, | ||
39 | 0xb75bU, 0xa77aU, 0x9719U, 0x8738U, 0xf7dfU, 0xe7feU, 0xd79dU, 0xc7bcU, | ||
40 | 0x48c4U, 0x58e5U, 0x6886U, 0x78a7U, 0x0840U, 0x1861U, 0x2802U, 0x3823U, | ||
41 | 0xc9ccU, 0xd9edU, 0xe98eU, 0xf9afU, 0x8948U, 0x9969U, 0xa90aU, 0xb92bU, | ||
42 | 0x5af5U, 0x4ad4U, 0x7ab7U, 0x6a96U, 0x1a71U, 0x0a50U, 0x3a33U, 0x2a12U, | ||
43 | 0xdbfdU, 0xcbdcU, 0xfbbfU, 0xeb9eU, 0x9b79U, 0x8b58U, 0xbb3bU, 0xab1aU, | ||
44 | 0x6ca6U, 0x7c87U, 0x4ce4U, 0x5cc5U, 0x2c22U, 0x3c03U, 0x0c60U, 0x1c41U, | ||
45 | 0xedaeU, 0xfd8fU, 0xcdecU, 0xddcdU, 0xad2aU, 0xbd0bU, 0x8d68U, 0x9d49U, | ||
46 | 0x7e97U, 0x6eb6U, 0x5ed5U, 0x4ef4U, 0x3e13U, 0x2e32U, 0x1e51U, 0x0e70U, | ||
47 | 0xff9fU, 0xefbeU, 0xdfddU, 0xcffcU, 0xbf1bU, 0xaf3aU, 0x9f59U, 0x8f78U, | ||
48 | 0x9188U, 0x81a9U, 0xb1caU, 0xa1ebU, 0xd10cU, 0xc12dU, 0xf14eU, 0xe16fU, | ||
49 | 0x1080U, 0x00a1U, 0x30c2U, 0x20e3U, 0x5004U, 0x4025U, 0x7046U, 0x6067U, | ||
50 | 0x83b9U, 0x9398U, 0xa3fbU, 0xb3daU, 0xc33dU, 0xd31cU, 0xe37fU, 0xf35eU, | ||
51 | 0x02b1U, 0x1290U, 0x22f3U, 0x32d2U, 0x4235U, 0x5214U, 0x6277U, 0x7256U, | ||
52 | 0xb5eaU, 0xa5cbU, 0x95a8U, 0x8589U, 0xf56eU, 0xe54fU, 0xd52cU, 0xc50dU, | ||
53 | 0x34e2U, 0x24c3U, 0x14a0U, 0x0481U, 0x7466U, 0x6447U, 0x5424U, 0x4405U, | ||
54 | 0xa7dbU, 0xb7faU, 0x8799U, 0x97b8U, 0xe75fU, 0xf77eU, 0xc71dU, 0xd73cU, | ||
55 | 0x26d3U, 0x36f2U, 0x0691U, 0x16b0U, 0x6657U, 0x7676U, 0x4615U, 0x5634U, | ||
56 | 0xd94cU, 0xc96dU, 0xf90eU, 0xe92fU, 0x99c8U, 0x89e9U, 0xb98aU, 0xa9abU, | ||
57 | 0x5844U, 0x4865U, 0x7806U, 0x6827U, 0x18c0U, 0x08e1U, 0x3882U, 0x28a3U, | ||
58 | 0xcb7dU, 0xdb5cU, 0xeb3fU, 0xfb1eU, 0x8bf9U, 0x9bd8U, 0xabbbU, 0xbb9aU, | ||
59 | 0x4a75U, 0x5a54U, 0x6a37U, 0x7a16U, 0x0af1U, 0x1ad0U, 0x2ab3U, 0x3a92U, | ||
60 | 0xfd2eU, 0xed0fU, 0xdd6cU, 0xcd4dU, 0xbdaaU, 0xad8bU, 0x9de8U, 0x8dc9U, | ||
61 | 0x7c26U, 0x6c07U, 0x5c64U, 0x4c45U, 0x3ca2U, 0x2c83U, 0x1ce0U, 0x0cc1U, | ||
62 | 0xef1fU, 0xff3eU, 0xcf5dU, 0xdf7cU, 0xaf9bU, 0xbfbaU, 0x8fd9U, 0x9ff8U, | ||
63 | 0x6e17U, 0x7e36U, 0x4e55U, 0x5e74U, 0x2e93U, 0x3eb2U, 0x0ed1U, 0x1ef0U | ||
64 | }; | ||
65 | |||
66 | /* | ||
67 | * udf_crc | ||
68 | * | ||
69 | * PURPOSE | ||
70 | * Calculate a 16-bit CRC checksum using ITU-T V.41 polynomial. | ||
71 | * | ||
72 | * DESCRIPTION | ||
73 | * The OSTA-UDF(tm) 1.50 standard states that using CRCs is mandatory. | ||
74 | * The polynomial used is: x^16 + x^12 + x^15 + 1 | ||
75 | * | ||
76 | * PRE-CONDITIONS | ||
77 | * data Pointer to the data block. | ||
78 | * size Size of the data block. | ||
79 | * | ||
80 | * POST-CONDITIONS | ||
81 | * <return> CRC of the data block. | ||
82 | * | ||
83 | * HISTORY | ||
84 | * July 21, 1997 - Andrew E. Mileski | ||
85 | * Adapted from OSTA-UDF(tm) 1.50 standard. | ||
86 | */ | ||
87 | uint16_t | ||
88 | udf_crc(uint8_t *data, uint32_t size, uint16_t crc) | ||
89 | { | ||
90 | while (size--) | ||
91 | crc = crc_table[(crc >> 8 ^ *(data++)) & 0xffU] ^ (crc << 8); | ||
92 | |||
93 | return crc; | ||
94 | } | ||
95 | |||
96 | /****************************************************************************/ | ||
97 | #if defined(TEST) | ||
98 | |||
99 | /* | ||
100 | * PURPOSE | ||
101 | * Test udf_crc() | ||
102 | * | ||
103 | * HISTORY | ||
104 | * July 21, 1997 - Andrew E. Mileski | ||
105 | * Adapted from OSTA-UDF(tm) 1.50 standard. | ||
106 | */ | ||
107 | |||
108 | unsigned char bytes[] = { 0x70U, 0x6AU, 0x77U }; | ||
109 | |||
110 | int main(void) | ||
111 | { | ||
112 | unsigned short x; | ||
113 | |||
114 | x = udf_crc16(bytes, sizeof bytes); | ||
115 | printf("udf_crc16: calculated = %4.4x, correct = %4.4x\n", x, 0x3299U); | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | #endif /* defined(TEST) */ | ||
121 | |||
122 | /****************************************************************************/ | ||
123 | #if defined(GENERATE) | ||
124 | |||
125 | /* | ||
126 | * PURPOSE | ||
127 | * Generate a table for fast 16-bit CRC calculations (any polynomial). | ||
128 | * | ||
129 | * DESCRIPTION | ||
130 | * The ITU-T V.41 polynomial is 010041. | ||
131 | * | ||
132 | * HISTORY | ||
133 | * July 21, 1997 - Andrew E. Mileski | ||
134 | * Adapted from OSTA-UDF(tm) 1.50 standard. | ||
135 | */ | ||
136 | |||
137 | #include <stdio.h> | ||
138 | |||
139 | int main(int argc, char **argv) | ||
140 | { | ||
141 | unsigned long crc, poly; | ||
142 | int n, i; | ||
143 | |||
144 | /* Get the polynomial */ | ||
145 | sscanf(argv[1], "%lo", &poly); | ||
146 | if (poly & 0xffff0000U){ | ||
147 | fprintf(stderr, "polynomial is too large\en"); | ||
148 | exit(1); | ||
149 | } | ||
150 | |||
151 | printf("/* CRC 0%o */\n", poly); | ||
152 | |||
153 | /* Create a table */ | ||
154 | printf("static unsigned short crc_table[256] = {\n"); | ||
155 | for (n = 0; n < 256; n++){ | ||
156 | if (n % 8 == 0) | ||
157 | printf("\t"); | ||
158 | crc = n << 8; | ||
159 | for (i = 0; i < 8; i++){ | ||
160 | if(crc & 0x8000U) | ||
161 | crc = (crc << 1) ^ poly; | ||
162 | else | ||
163 | crc <<= 1; | ||
164 | crc &= 0xFFFFU; | ||
165 | } | ||
166 | if (n == 255) | ||
167 | printf("0x%04xU ", crc); | ||
168 | else | ||
169 | printf("0x%04xU, ", crc); | ||
170 | if(n % 8 == 7) | ||
171 | printf("\n"); | ||
172 | } | ||
173 | printf("};\n"); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | #endif /* defined(GENERATE) */ | ||
diff --git a/fs/udf/dir.c b/fs/udf/dir.c new file mode 100644 index 000000000000..82440b731142 --- /dev/null +++ b/fs/udf/dir.c | |||
@@ -0,0 +1,268 @@ | |||
1 | /* | ||
2 | * dir.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Directory handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-2004 Ben Fennema | ||
19 | * | ||
20 | * HISTORY | ||
21 | * | ||
22 | * 10/05/98 dgb Split directory operations into its own file | ||
23 | * Implemented directory reads via do_udf_readdir | ||
24 | * 10/06/98 Made directory operations work! | ||
25 | * 11/17/98 Rewrote directory to support ICBTAG_FLAG_AD_LONG | ||
26 | * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading | ||
27 | * across blocks. | ||
28 | * 12/12/98 Split out the lookup code to namei.c. bulk of directory | ||
29 | * code now in directory.c:udf_fileident_read. | ||
30 | */ | ||
31 | |||
32 | #include "udfdecl.h" | ||
33 | |||
34 | #include <linux/string.h> | ||
35 | #include <linux/errno.h> | ||
36 | #include <linux/mm.h> | ||
37 | #include <linux/slab.h> | ||
38 | #include <linux/smp_lock.h> | ||
39 | #include <linux/buffer_head.h> | ||
40 | |||
41 | #include "udf_i.h" | ||
42 | #include "udf_sb.h" | ||
43 | |||
44 | /* Prototypes for file operations */ | ||
45 | static int udf_readdir(struct file *, void *, filldir_t); | ||
46 | static int do_udf_readdir(struct inode *, struct file *, filldir_t, void *); | ||
47 | |||
48 | /* readdir and lookup functions */ | ||
49 | |||
50 | struct file_operations udf_dir_operations = { | ||
51 | .read = generic_read_dir, | ||
52 | .readdir = udf_readdir, | ||
53 | .ioctl = udf_ioctl, | ||
54 | .fsync = udf_fsync_file, | ||
55 | }; | ||
56 | |||
57 | /* | ||
58 | * udf_readdir | ||
59 | * | ||
60 | * PURPOSE | ||
61 | * Read a directory entry. | ||
62 | * | ||
63 | * DESCRIPTION | ||
64 | * Optional - sys_getdents() will return -ENOTDIR if this routine is not | ||
65 | * available. | ||
66 | * | ||
67 | * Refer to sys_getdents() in fs/readdir.c | ||
68 | * sys_getdents() -> . | ||
69 | * | ||
70 | * PRE-CONDITIONS | ||
71 | * filp Pointer to directory file. | ||
72 | * buf Pointer to directory entry buffer. | ||
73 | * filldir Pointer to filldir function. | ||
74 | * | ||
75 | * POST-CONDITIONS | ||
76 | * <return> >=0 on success. | ||
77 | * | ||
78 | * HISTORY | ||
79 | * July 1, 1997 - Andrew E. Mileski | ||
80 | * Written, tested, and released. | ||
81 | */ | ||
82 | |||
83 | int udf_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
84 | { | ||
85 | struct inode *dir = filp->f_dentry->d_inode; | ||
86 | int result; | ||
87 | |||
88 | lock_kernel(); | ||
89 | |||
90 | if ( filp->f_pos == 0 ) | ||
91 | { | ||
92 | if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) | ||
93 | { | ||
94 | unlock_kernel(); | ||
95 | return 0; | ||
96 | } | ||
97 | filp->f_pos ++; | ||
98 | } | ||
99 | |||
100 | result = do_udf_readdir(dir, filp, filldir, dirent); | ||
101 | unlock_kernel(); | ||
102 | return result; | ||
103 | } | ||
104 | |||
105 | static int | ||
106 | do_udf_readdir(struct inode * dir, struct file *filp, filldir_t filldir, void *dirent) | ||
107 | { | ||
108 | struct udf_fileident_bh fibh; | ||
109 | struct fileIdentDesc *fi=NULL; | ||
110 | struct fileIdentDesc cfi; | ||
111 | int block, iblock; | ||
112 | loff_t nf_pos = filp->f_pos - 1; | ||
113 | int flen; | ||
114 | char fname[UDF_NAME_LEN]; | ||
115 | char *nameptr; | ||
116 | uint16_t liu; | ||
117 | uint8_t lfi; | ||
118 | loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; | ||
119 | struct buffer_head * bh = NULL, * tmp, * bha[16]; | ||
120 | kernel_lb_addr bloc, eloc; | ||
121 | uint32_t extoffset, elen, offset; | ||
122 | int i, num; | ||
123 | unsigned int dt_type; | ||
124 | |||
125 | if (nf_pos >= size) | ||
126 | return 0; | ||
127 | |||
128 | if (nf_pos == 0) | ||
129 | nf_pos = (udf_ext0_offset(dir) >> 2); | ||
130 | |||
131 | fibh.soffset = fibh.eoffset = (nf_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; | ||
132 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
133 | fibh.sbh = fibh.ebh = NULL; | ||
134 | else if (inode_bmap(dir, nf_pos >> (dir->i_sb->s_blocksize_bits - 2), | ||
135 | &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) | ||
136 | { | ||
137 | offset >>= dir->i_sb->s_blocksize_bits; | ||
138 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | ||
139 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) | ||
140 | { | ||
141 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) | ||
142 | extoffset -= sizeof(short_ad); | ||
143 | else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) | ||
144 | extoffset -= sizeof(long_ad); | ||
145 | } | ||
146 | else | ||
147 | offset = 0; | ||
148 | |||
149 | if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) | ||
150 | { | ||
151 | udf_release_data(bh); | ||
152 | return -EIO; | ||
153 | } | ||
154 | |||
155 | if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) | ||
156 | { | ||
157 | i = 16 >> (dir->i_sb->s_blocksize_bits - 9); | ||
158 | if (i+offset > (elen >> dir->i_sb->s_blocksize_bits)) | ||
159 | i = (elen >> dir->i_sb->s_blocksize_bits)-offset; | ||
160 | for (num=0; i>0; i--) | ||
161 | { | ||
162 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset+i); | ||
163 | tmp = udf_tgetblk(dir->i_sb, block); | ||
164 | if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) | ||
165 | bha[num++] = tmp; | ||
166 | else | ||
167 | brelse(tmp); | ||
168 | } | ||
169 | if (num) | ||
170 | { | ||
171 | ll_rw_block(READA, num, bha); | ||
172 | for (i=0; i<num; i++) | ||
173 | brelse(bha[i]); | ||
174 | } | ||
175 | } | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | udf_release_data(bh); | ||
180 | return -ENOENT; | ||
181 | } | ||
182 | |||
183 | while ( nf_pos < size ) | ||
184 | { | ||
185 | filp->f_pos = nf_pos + 1; | ||
186 | |||
187 | fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); | ||
188 | |||
189 | if (!fi) | ||
190 | { | ||
191 | if (fibh.sbh != fibh.ebh) | ||
192 | udf_release_data(fibh.ebh); | ||
193 | udf_release_data(fibh.sbh); | ||
194 | udf_release_data(bh); | ||
195 | return 0; | ||
196 | } | ||
197 | |||
198 | liu = le16_to_cpu(cfi.lengthOfImpUse); | ||
199 | lfi = cfi.lengthFileIdent; | ||
200 | |||
201 | if (fibh.sbh == fibh.ebh) | ||
202 | nameptr = fi->fileIdent + liu; | ||
203 | else | ||
204 | { | ||
205 | int poffset; /* Unpaded ending offset */ | ||
206 | |||
207 | poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi; | ||
208 | |||
209 | if (poffset >= lfi) | ||
210 | nameptr = (char *)(fibh.ebh->b_data + poffset - lfi); | ||
211 | else | ||
212 | { | ||
213 | nameptr = fname; | ||
214 | memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); | ||
215 | memcpy(nameptr + lfi - poffset, fibh.ebh->b_data, poffset); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | if ( (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) | ||
220 | { | ||
221 | if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) ) | ||
222 | continue; | ||
223 | } | ||
224 | |||
225 | if ( (cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 ) | ||
226 | { | ||
227 | if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) ) | ||
228 | continue; | ||
229 | } | ||
230 | |||
231 | if ( cfi.fileCharacteristics & FID_FILE_CHAR_PARENT ) | ||
232 | { | ||
233 | iblock = parent_ino(filp->f_dentry); | ||
234 | flen = 2; | ||
235 | memcpy(fname, "..", flen); | ||
236 | dt_type = DT_DIR; | ||
237 | } | ||
238 | else | ||
239 | { | ||
240 | kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation); | ||
241 | |||
242 | iblock = udf_get_lb_pblock(dir->i_sb, tloc, 0); | ||
243 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); | ||
244 | dt_type = DT_UNKNOWN; | ||
245 | } | ||
246 | |||
247 | if (flen) | ||
248 | { | ||
249 | if (filldir(dirent, fname, flen, filp->f_pos, iblock, dt_type) < 0) | ||
250 | { | ||
251 | if (fibh.sbh != fibh.ebh) | ||
252 | udf_release_data(fibh.ebh); | ||
253 | udf_release_data(fibh.sbh); | ||
254 | udf_release_data(bh); | ||
255 | return 0; | ||
256 | } | ||
257 | } | ||
258 | } /* end while */ | ||
259 | |||
260 | filp->f_pos = nf_pos + 1; | ||
261 | |||
262 | if (fibh.sbh != fibh.ebh) | ||
263 | udf_release_data(fibh.ebh); | ||
264 | udf_release_data(fibh.sbh); | ||
265 | udf_release_data(bh); | ||
266 | |||
267 | return 0; | ||
268 | } | ||
diff --git a/fs/udf/directory.c b/fs/udf/directory.c new file mode 100644 index 000000000000..9a61ecc5451b --- /dev/null +++ b/fs/udf/directory.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * directory.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Directory related functions | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | */ | ||
18 | |||
19 | #include "udfdecl.h" | ||
20 | #include "udf_i.h" | ||
21 | |||
22 | #include <linux/fs.h> | ||
23 | #include <linux/string.h> | ||
24 | #include <linux/buffer_head.h> | ||
25 | |||
26 | #if 0 | ||
27 | static uint8_t * | ||
28 | udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size, | ||
29 | kernel_lb_addr fe_loc, int *pos, int *offset, | ||
30 | struct buffer_head **bh, int *error) | ||
31 | { | ||
32 | int loffset = *offset; | ||
33 | int block; | ||
34 | uint8_t *ad; | ||
35 | int remainder; | ||
36 | |||
37 | *error = 0; | ||
38 | |||
39 | ad = (uint8_t *)(*bh)->b_data + *offset; | ||
40 | *offset += ad_size; | ||
41 | |||
42 | if (!ad) | ||
43 | { | ||
44 | udf_release_data(*bh); | ||
45 | *error = 1; | ||
46 | return NULL; | ||
47 | } | ||
48 | |||
49 | if (*offset == dir->i_sb->s_blocksize) | ||
50 | { | ||
51 | udf_release_data(*bh); | ||
52 | block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); | ||
53 | if (!block) | ||
54 | return NULL; | ||
55 | if (!(*bh = udf_tread(dir->i_sb, block))) | ||
56 | return NULL; | ||
57 | } | ||
58 | else if (*offset > dir->i_sb->s_blocksize) | ||
59 | { | ||
60 | ad = tmpad; | ||
61 | |||
62 | remainder = dir->i_sb->s_blocksize - loffset; | ||
63 | memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder); | ||
64 | |||
65 | udf_release_data(*bh); | ||
66 | block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos); | ||
67 | if (!block) | ||
68 | return NULL; | ||
69 | if (!((*bh) = udf_tread(dir->i_sb, block))) | ||
70 | return NULL; | ||
71 | |||
72 | memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder); | ||
73 | *offset = ad_size - remainder; | ||
74 | } | ||
75 | return ad; | ||
76 | } | ||
77 | #endif | ||
78 | |||
79 | struct fileIdentDesc * | ||
80 | udf_fileident_read(struct inode *dir, loff_t *nf_pos, | ||
81 | struct udf_fileident_bh *fibh, | ||
82 | struct fileIdentDesc *cfi, | ||
83 | kernel_lb_addr *bloc, uint32_t *extoffset, | ||
84 | kernel_lb_addr *eloc, uint32_t *elen, | ||
85 | uint32_t *offset, struct buffer_head **bh) | ||
86 | { | ||
87 | struct fileIdentDesc *fi; | ||
88 | int i, num, block; | ||
89 | struct buffer_head * tmp, * bha[16]; | ||
90 | |||
91 | fibh->soffset = fibh->eoffset; | ||
92 | |||
93 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
94 | { | ||
95 | fi = udf_get_fileident(UDF_I_DATA(dir) - | ||
96 | (UDF_I_EFE(dir) ? | ||
97 | sizeof(struct extendedFileEntry) : | ||
98 | sizeof(struct fileEntry)), | ||
99 | dir->i_sb->s_blocksize, &(fibh->eoffset)); | ||
100 | |||
101 | if (!fi) | ||
102 | return NULL; | ||
103 | |||
104 | *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); | ||
105 | |||
106 | memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); | ||
107 | |||
108 | return fi; | ||
109 | } | ||
110 | |||
111 | if (fibh->eoffset == dir->i_sb->s_blocksize) | ||
112 | { | ||
113 | int lextoffset = *extoffset; | ||
114 | |||
115 | if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) != | ||
116 | (EXT_RECORDED_ALLOCATED >> 30)) | ||
117 | { | ||
118 | return NULL; | ||
119 | } | ||
120 | |||
121 | block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); | ||
122 | |||
123 | (*offset) ++; | ||
124 | |||
125 | if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) | ||
126 | *offset = 0; | ||
127 | else | ||
128 | *extoffset = lextoffset; | ||
129 | |||
130 | udf_release_data(fibh->sbh); | ||
131 | if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) | ||
132 | return NULL; | ||
133 | fibh->soffset = fibh->eoffset = 0; | ||
134 | |||
135 | if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1))) | ||
136 | { | ||
137 | i = 16 >> (dir->i_sb->s_blocksize_bits - 9); | ||
138 | if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits)) | ||
139 | i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset; | ||
140 | for (num=0; i>0; i--) | ||
141 | { | ||
142 | block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i); | ||
143 | tmp = udf_tgetblk(dir->i_sb, block); | ||
144 | if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp)) | ||
145 | bha[num++] = tmp; | ||
146 | else | ||
147 | brelse(tmp); | ||
148 | } | ||
149 | if (num) | ||
150 | { | ||
151 | ll_rw_block(READA, num, bha); | ||
152 | for (i=0; i<num; i++) | ||
153 | brelse(bha[i]); | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | else if (fibh->sbh != fibh->ebh) | ||
158 | { | ||
159 | udf_release_data(fibh->sbh); | ||
160 | fibh->sbh = fibh->ebh; | ||
161 | } | ||
162 | |||
163 | fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize, | ||
164 | &(fibh->eoffset)); | ||
165 | |||
166 | if (!fi) | ||
167 | return NULL; | ||
168 | |||
169 | *nf_pos += ((fibh->eoffset - fibh->soffset) >> 2); | ||
170 | |||
171 | if (fibh->eoffset <= dir->i_sb->s_blocksize) | ||
172 | { | ||
173 | memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); | ||
174 | } | ||
175 | else if (fibh->eoffset > dir->i_sb->s_blocksize) | ||
176 | { | ||
177 | int lextoffset = *extoffset; | ||
178 | |||
179 | if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) != | ||
180 | (EXT_RECORDED_ALLOCATED >> 30)) | ||
181 | { | ||
182 | return NULL; | ||
183 | } | ||
184 | |||
185 | block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset); | ||
186 | |||
187 | (*offset) ++; | ||
188 | |||
189 | if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen) | ||
190 | *offset = 0; | ||
191 | else | ||
192 | *extoffset = lextoffset; | ||
193 | |||
194 | fibh->soffset -= dir->i_sb->s_blocksize; | ||
195 | fibh->eoffset -= dir->i_sb->s_blocksize; | ||
196 | |||
197 | if (!(fibh->ebh = udf_tread(dir->i_sb, block))) | ||
198 | return NULL; | ||
199 | |||
200 | if (sizeof(struct fileIdentDesc) > - fibh->soffset) | ||
201 | { | ||
202 | int fi_len; | ||
203 | |||
204 | memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset); | ||
205 | memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data, | ||
206 | sizeof(struct fileIdentDesc) + fibh->soffset); | ||
207 | |||
208 | fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent + | ||
209 | le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3; | ||
210 | |||
211 | *nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2); | ||
212 | fibh->eoffset = fibh->soffset + fi_len; | ||
213 | } | ||
214 | else | ||
215 | { | ||
216 | memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc)); | ||
217 | } | ||
218 | } | ||
219 | return fi; | ||
220 | } | ||
221 | |||
222 | struct fileIdentDesc * | ||
223 | udf_get_fileident(void * buffer, int bufsize, int * offset) | ||
224 | { | ||
225 | struct fileIdentDesc *fi; | ||
226 | int lengthThisIdent; | ||
227 | uint8_t * ptr; | ||
228 | int padlen; | ||
229 | |||
230 | if ( (!buffer) || (!offset) ) { | ||
231 | udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset); | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | ptr = buffer; | ||
236 | |||
237 | if ( (*offset > 0) && (*offset < bufsize) ) { | ||
238 | ptr += *offset; | ||
239 | } | ||
240 | fi=(struct fileIdentDesc *)ptr; | ||
241 | if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID) | ||
242 | { | ||
243 | udf_debug("0x%x != TAG_IDENT_FID\n", | ||
244 | le16_to_cpu(fi->descTag.tagIdent)); | ||
245 | udf_debug("offset: %u sizeof: %lu bufsize: %u\n", | ||
246 | *offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize); | ||
247 | return NULL; | ||
248 | } | ||
249 | if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize ) | ||
250 | { | ||
251 | lengthThisIdent = sizeof(struct fileIdentDesc); | ||
252 | } | ||
253 | else | ||
254 | lengthThisIdent = sizeof(struct fileIdentDesc) + | ||
255 | fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse); | ||
256 | |||
257 | /* we need to figure padding, too! */ | ||
258 | padlen = lengthThisIdent % UDF_NAME_PAD; | ||
259 | if (padlen) | ||
260 | lengthThisIdent += (UDF_NAME_PAD - padlen); | ||
261 | *offset = *offset + lengthThisIdent; | ||
262 | |||
263 | return fi; | ||
264 | } | ||
265 | |||
266 | #if 0 | ||
267 | static extent_ad * | ||
268 | udf_get_fileextent(void * buffer, int bufsize, int * offset) | ||
269 | { | ||
270 | extent_ad * ext; | ||
271 | struct fileEntry *fe; | ||
272 | uint8_t * ptr; | ||
273 | |||
274 | if ( (!buffer) || (!offset) ) | ||
275 | { | ||
276 | printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n"); | ||
277 | return NULL; | ||
278 | } | ||
279 | |||
280 | fe = (struct fileEntry *)buffer; | ||
281 | |||
282 | if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE ) | ||
283 | { | ||
284 | udf_debug("0x%x != TAG_IDENT_FE\n", | ||
285 | le16_to_cpu(fe->descTag.tagIdent)); | ||
286 | return NULL; | ||
287 | } | ||
288 | |||
289 | ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr); | ||
290 | |||
291 | if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) ) | ||
292 | { | ||
293 | ptr += *offset; | ||
294 | } | ||
295 | |||
296 | ext = (extent_ad *)ptr; | ||
297 | |||
298 | *offset = *offset + sizeof(extent_ad); | ||
299 | return ext; | ||
300 | } | ||
301 | #endif | ||
302 | |||
303 | short_ad * | ||
304 | udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc) | ||
305 | { | ||
306 | short_ad *sa; | ||
307 | |||
308 | if ( (!ptr) || (!offset) ) | ||
309 | { | ||
310 | printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n"); | ||
311 | return NULL; | ||
312 | } | ||
313 | |||
314 | if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) ) | ||
315 | return NULL; | ||
316 | else if ((sa = (short_ad *)ptr)->extLength == 0) | ||
317 | return NULL; | ||
318 | |||
319 | if (inc) | ||
320 | *offset += sizeof(short_ad); | ||
321 | return sa; | ||
322 | } | ||
323 | |||
324 | long_ad * | ||
325 | udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc) | ||
326 | { | ||
327 | long_ad *la; | ||
328 | |||
329 | if ( (!ptr) || (!offset) ) | ||
330 | { | ||
331 | printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n"); | ||
332 | return NULL; | ||
333 | } | ||
334 | |||
335 | if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) ) | ||
336 | return NULL; | ||
337 | else if ((la = (long_ad *)ptr)->extLength == 0) | ||
338 | return NULL; | ||
339 | |||
340 | if (inc) | ||
341 | *offset += sizeof(long_ad); | ||
342 | return la; | ||
343 | } | ||
diff --git a/fs/udf/ecma_167.h b/fs/udf/ecma_167.h new file mode 100644 index 000000000000..f81f2ebbf508 --- /dev/null +++ b/fs/udf/ecma_167.h | |||
@@ -0,0 +1,864 @@ | |||
1 | /* | ||
2 | * ecma_167.h | ||
3 | * | ||
4 | * This file is based on ECMA-167 3rd edition (June 1997) | ||
5 | * http://www.ecma.ch | ||
6 | * | ||
7 | * Copyright (c) 2001-2002 Ben Fennema <bfennema@falcon.csc.calpoly.edu> | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted provided that the following conditions | ||
12 | * are met: | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions, and the following disclaimer, | ||
15 | * without modification. | ||
16 | * 2. The name of the author may not be used to endorse or promote products | ||
17 | * derived from this software without specific prior written permission. | ||
18 | * | ||
19 | * Alternatively, this software may be distributed under the terms of the | ||
20 | * GNU Public License ("GPL"). | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
26 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
32 | * SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | |||
37 | #ifndef _ECMA_167_H | ||
38 | #define _ECMA_167_H 1 | ||
39 | |||
40 | /* Character set specification (ECMA 167r3 1/7.2.1) */ | ||
41 | typedef struct | ||
42 | { | ||
43 | uint8_t charSetType; | ||
44 | uint8_t charSetInfo[63]; | ||
45 | } __attribute__ ((packed)) charspec; | ||
46 | |||
47 | /* Character Set Type (ECMA 167r3 1/7.2.1.1) */ | ||
48 | #define CHARSPEC_TYPE_CS0 0x00 /* (1/7.2.2) */ | ||
49 | #define CHARSPEC_TYPE_CS1 0x01 /* (1/7.2.3) */ | ||
50 | #define CHARSPEC_TYPE_CS2 0x02 /* (1/7.2.4) */ | ||
51 | #define CHARSPEC_TYPE_CS3 0x03 /* (1/7.2.5) */ | ||
52 | #define CHARSPEC_TYPE_CS4 0x04 /* (1/7.2.6) */ | ||
53 | #define CHARSPEC_TYPE_CS5 0x05 /* (1/7.2.7) */ | ||
54 | #define CHARSPEC_TYPE_CS6 0x06 /* (1/7.2.8) */ | ||
55 | #define CHARSPEC_TYPE_CS7 0x07 /* (1/7.2.9) */ | ||
56 | #define CHARSPEC_TYPE_CS8 0x08 /* (1/7.2.10) */ | ||
57 | |||
58 | typedef uint8_t dstring; | ||
59 | |||
60 | /* Timestamp (ECMA 167r3 1/7.3) */ | ||
61 | typedef struct | ||
62 | { | ||
63 | __le16 typeAndTimezone; | ||
64 | __le16 year; | ||
65 | uint8_t month; | ||
66 | uint8_t day; | ||
67 | uint8_t hour; | ||
68 | uint8_t minute; | ||
69 | uint8_t second; | ||
70 | uint8_t centiseconds; | ||
71 | uint8_t hundredsOfMicroseconds; | ||
72 | uint8_t microseconds; | ||
73 | } __attribute__ ((packed)) timestamp; | ||
74 | |||
75 | typedef struct | ||
76 | { | ||
77 | uint16_t typeAndTimezone; | ||
78 | int16_t year; | ||
79 | uint8_t month; | ||
80 | uint8_t day; | ||
81 | uint8_t hour; | ||
82 | uint8_t minute; | ||
83 | uint8_t second; | ||
84 | uint8_t centiseconds; | ||
85 | uint8_t hundredsOfMicroseconds; | ||
86 | uint8_t microseconds; | ||
87 | } __attribute__ ((packed)) kernel_timestamp; | ||
88 | |||
89 | /* Type and Time Zone (ECMA 167r3 1/7.3.1) */ | ||
90 | #define TIMESTAMP_TYPE_MASK 0xF000 | ||
91 | #define TIMESTAMP_TYPE_CUT 0x0000 | ||
92 | #define TIMESTAMP_TYPE_LOCAL 0x1000 | ||
93 | #define TIMESTAMP_TYPE_AGREEMENT 0x2000 | ||
94 | #define TIMESTAMP_TIMEZONE_MASK 0x0FFF | ||
95 | |||
96 | /* Entity identifier (ECMA 167r3 1/7.4) */ | ||
97 | typedef struct | ||
98 | { | ||
99 | uint8_t flags; | ||
100 | uint8_t ident[23]; | ||
101 | uint8_t identSuffix[8]; | ||
102 | } __attribute__ ((packed)) regid; | ||
103 | |||
104 | /* Flags (ECMA 167r3 1/7.4.1) */ | ||
105 | #define ENTITYID_FLAGS_DIRTY 0x00 | ||
106 | #define ENTITYID_FLAGS_PROTECTED 0x01 | ||
107 | |||
108 | /* Volume Structure Descriptor (ECMA 167r3 2/9.1) */ | ||
109 | #define VSD_STD_ID_LEN 5 | ||
110 | struct volStructDesc | ||
111 | { | ||
112 | uint8_t structType; | ||
113 | uint8_t stdIdent[VSD_STD_ID_LEN]; | ||
114 | uint8_t structVersion; | ||
115 | uint8_t structData[2041]; | ||
116 | } __attribute__ ((packed)); | ||
117 | |||
118 | /* Standard Identifier (EMCA 167r2 2/9.1.2) */ | ||
119 | #define VSD_STD_ID_NSR02 "NSR02" /* (3/9.1) */ | ||
120 | |||
121 | /* Standard Identifier (ECMA 167r3 2/9.1.2) */ | ||
122 | #define VSD_STD_ID_BEA01 "BEA01" /* (2/9.2) */ | ||
123 | #define VSD_STD_ID_BOOT2 "BOOT2" /* (2/9.4) */ | ||
124 | #define VSD_STD_ID_CD001 "CD001" /* (ECMA-119) */ | ||
125 | #define VSD_STD_ID_CDW02 "CDW02" /* (ECMA-168) */ | ||
126 | #define VSD_STD_ID_NSR03 "NSR03" /* (3/9.1) */ | ||
127 | #define VSD_STD_ID_TEA01 "TEA01" /* (2/9.3) */ | ||
128 | |||
129 | /* Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) */ | ||
130 | struct beginningExtendedAreaDesc | ||
131 | { | ||
132 | uint8_t structType; | ||
133 | uint8_t stdIdent[VSD_STD_ID_LEN]; | ||
134 | uint8_t structVersion; | ||
135 | uint8_t structData[2041]; | ||
136 | } __attribute__ ((packed)); | ||
137 | |||
138 | /* Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) */ | ||
139 | struct terminatingExtendedAreaDesc | ||
140 | { | ||
141 | uint8_t structType; | ||
142 | uint8_t stdIdent[VSD_STD_ID_LEN]; | ||
143 | uint8_t structVersion; | ||
144 | uint8_t structData[2041]; | ||
145 | } __attribute__ ((packed)); | ||
146 | |||
147 | /* Boot Descriptor (ECMA 167r3 2/9.4) */ | ||
148 | struct bootDesc | ||
149 | { | ||
150 | uint8_t structType; | ||
151 | uint8_t stdIdent[VSD_STD_ID_LEN]; | ||
152 | uint8_t structVersion; | ||
153 | uint8_t reserved1; | ||
154 | regid archType; | ||
155 | regid bootIdent; | ||
156 | __le32 bootExtLocation; | ||
157 | __le32 bootExtLength; | ||
158 | __le64 loadAddress; | ||
159 | __le64 startAddress; | ||
160 | timestamp descCreationDateAndTime; | ||
161 | __le16 flags; | ||
162 | uint8_t reserved2[32]; | ||
163 | uint8_t bootUse[1906]; | ||
164 | } __attribute__ ((packed)); | ||
165 | |||
166 | /* Flags (ECMA 167r3 2/9.4.12) */ | ||
167 | #define BOOT_FLAGS_ERASE 0x01 | ||
168 | |||
169 | /* Extent Descriptor (ECMA 167r3 3/7.1) */ | ||
170 | typedef struct | ||
171 | { | ||
172 | __le32 extLength; | ||
173 | __le32 extLocation; | ||
174 | } __attribute__ ((packed)) extent_ad; | ||
175 | |||
176 | typedef struct | ||
177 | { | ||
178 | uint32_t extLength; | ||
179 | uint32_t extLocation; | ||
180 | } kernel_extent_ad; | ||
181 | |||
182 | /* Descriptor Tag (ECMA 167r3 3/7.2) */ | ||
183 | typedef struct | ||
184 | { | ||
185 | __le16 tagIdent; | ||
186 | __le16 descVersion; | ||
187 | uint8_t tagChecksum; | ||
188 | uint8_t reserved; | ||
189 | __le16 tagSerialNum; | ||
190 | __le16 descCRC; | ||
191 | __le16 descCRCLength; | ||
192 | __le32 tagLocation; | ||
193 | } __attribute__ ((packed)) tag; | ||
194 | |||
195 | /* Tag Identifier (ECMA 167r3 3/7.2.1) */ | ||
196 | #define TAG_IDENT_PVD 0x0001 | ||
197 | #define TAG_IDENT_AVDP 0x0002 | ||
198 | #define TAG_IDENT_VDP 0x0003 | ||
199 | #define TAG_IDENT_IUVD 0x0004 | ||
200 | #define TAG_IDENT_PD 0x0005 | ||
201 | #define TAG_IDENT_LVD 0x0006 | ||
202 | #define TAG_IDENT_USD 0x0007 | ||
203 | #define TAG_IDENT_TD 0x0008 | ||
204 | #define TAG_IDENT_LVID 0x0009 | ||
205 | |||
206 | /* NSR Descriptor (ECMA 167r3 3/9.1) */ | ||
207 | struct NSRDesc | ||
208 | { | ||
209 | uint8_t structType; | ||
210 | uint8_t stdIdent[VSD_STD_ID_LEN]; | ||
211 | uint8_t structVersion; | ||
212 | uint8_t reserved; | ||
213 | uint8_t structData[2040]; | ||
214 | } __attribute__ ((packed)); | ||
215 | |||
216 | /* Primary Volume Descriptor (ECMA 167r3 3/10.1) */ | ||
217 | struct primaryVolDesc | ||
218 | { | ||
219 | tag descTag; | ||
220 | __le32 volDescSeqNum; | ||
221 | __le32 primaryVolDescNum; | ||
222 | dstring volIdent[32]; | ||
223 | __le16 volSeqNum; | ||
224 | __le16 maxVolSeqNum; | ||
225 | __le16 interchangeLvl; | ||
226 | __le16 maxInterchangeLvl; | ||
227 | __le32 charSetList; | ||
228 | __le32 maxCharSetList; | ||
229 | dstring volSetIdent[128]; | ||
230 | charspec descCharSet; | ||
231 | charspec explanatoryCharSet; | ||
232 | extent_ad volAbstract; | ||
233 | extent_ad volCopyright; | ||
234 | regid appIdent; | ||
235 | timestamp recordingDateAndTime; | ||
236 | regid impIdent; | ||
237 | uint8_t impUse[64]; | ||
238 | __le32 predecessorVolDescSeqLocation; | ||
239 | __le16 flags; | ||
240 | uint8_t reserved[22]; | ||
241 | } __attribute__ ((packed)); | ||
242 | |||
243 | /* Flags (ECMA 167r3 3/10.1.21) */ | ||
244 | #define PVD_FLAGS_VSID_COMMON 0x0001 | ||
245 | |||
246 | /* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) */ | ||
247 | struct anchorVolDescPtr | ||
248 | { | ||
249 | tag descTag; | ||
250 | extent_ad mainVolDescSeqExt; | ||
251 | extent_ad reserveVolDescSeqExt; | ||
252 | uint8_t reserved[480]; | ||
253 | } __attribute__ ((packed)); | ||
254 | |||
255 | /* Volume Descriptor Pointer (ECMA 167r3 3/10.3) */ | ||
256 | struct volDescPtr | ||
257 | { | ||
258 | tag descTag; | ||
259 | __le32 volDescSeqNum; | ||
260 | extent_ad nextVolDescSeqExt; | ||
261 | uint8_t reserved[484]; | ||
262 | } __attribute__ ((packed)); | ||
263 | |||
264 | /* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) */ | ||
265 | struct impUseVolDesc | ||
266 | { | ||
267 | tag descTag; | ||
268 | __le32 volDescSeqNum; | ||
269 | regid impIdent; | ||
270 | uint8_t impUse[460]; | ||
271 | } __attribute__ ((packed)); | ||
272 | |||
273 | /* Partition Descriptor (ECMA 167r3 3/10.5) */ | ||
274 | struct partitionDesc | ||
275 | { | ||
276 | tag descTag; | ||
277 | __le32 volDescSeqNum; | ||
278 | __le16 partitionFlags; | ||
279 | __le16 partitionNumber; | ||
280 | regid partitionContents; | ||
281 | uint8_t partitionContentsUse[128]; | ||
282 | __le32 accessType; | ||
283 | __le32 partitionStartingLocation; | ||
284 | __le32 partitionLength; | ||
285 | regid impIdent; | ||
286 | uint8_t impUse[128]; | ||
287 | uint8_t reserved[156]; | ||
288 | } __attribute__ ((packed)); | ||
289 | |||
290 | /* Partition Flags (ECMA 167r3 3/10.5.3) */ | ||
291 | #define PD_PARTITION_FLAGS_ALLOC 0x0001 | ||
292 | |||
293 | /* Partition Contents (ECMA 167r2 3/10.5.3) */ | ||
294 | #define PD_PARTITION_CONTENTS_NSR02 "+NSR02" | ||
295 | |||
296 | /* Partition Contents (ECMA 167r3 3/10.5.5) */ | ||
297 | #define PD_PARTITION_CONTENTS_FDC01 "+FDC01" | ||
298 | #define PD_PARTITION_CONTENTS_CD001 "+CD001" | ||
299 | #define PD_PARTITION_CONTENTS_CDW02 "+CDW02" | ||
300 | #define PD_PARTITION_CONTENTS_NSR03 "+NSR03" | ||
301 | |||
302 | /* Access Type (ECMA 167r3 3/10.5.7) */ | ||
303 | #define PD_ACCESS_TYPE_NONE 0x00000000 | ||
304 | #define PD_ACCESS_TYPE_READ_ONLY 0x00000001 | ||
305 | #define PD_ACCESS_TYPE_WRITE_ONCE 0x00000002 | ||
306 | #define PD_ACCESS_TYPE_REWRITABLE 0x00000003 | ||
307 | #define PD_ACCESS_TYPE_OVERWRITABLE 0x00000004 | ||
308 | |||
309 | /* Logical Volume Descriptor (ECMA 167r3 3/10.6) */ | ||
310 | struct logicalVolDesc | ||
311 | { | ||
312 | tag descTag; | ||
313 | __le32 volDescSeqNum; | ||
314 | charspec descCharSet; | ||
315 | dstring logicalVolIdent[128]; | ||
316 | __le32 logicalBlockSize; | ||
317 | regid domainIdent; | ||
318 | uint8_t logicalVolContentsUse[16]; | ||
319 | __le32 mapTableLength; | ||
320 | __le32 numPartitionMaps; | ||
321 | regid impIdent; | ||
322 | uint8_t impUse[128]; | ||
323 | extent_ad integritySeqExt; | ||
324 | uint8_t partitionMaps[0]; | ||
325 | } __attribute__ ((packed)); | ||
326 | |||
327 | /* Generic Partition Map (ECMA 167r3 3/10.7.1) */ | ||
328 | struct genericPartitionMap | ||
329 | { | ||
330 | uint8_t partitionMapType; | ||
331 | uint8_t partitionMapLength; | ||
332 | uint8_t partitionMapping[0]; | ||
333 | } __attribute__ ((packed)); | ||
334 | |||
335 | /* Partition Map Type (ECMA 167r3 3/10.7.1.1) */ | ||
336 | #define GP_PARTITION_MAP_TYPE_UNDEF 0x00 | ||
337 | #define GP_PARTIITON_MAP_TYPE_1 0x01 | ||
338 | #define GP_PARTITION_MAP_TYPE_2 0x02 | ||
339 | |||
340 | /* Type 1 Partition Map (ECMA 167r3 3/10.7.2) */ | ||
341 | struct genericPartitionMap1 | ||
342 | { | ||
343 | uint8_t partitionMapType; | ||
344 | uint8_t partitionMapLength; | ||
345 | __le16 volSeqNum; | ||
346 | __le16 partitionNum; | ||
347 | } __attribute__ ((packed)); | ||
348 | |||
349 | /* Type 2 Partition Map (ECMA 167r3 3/10.7.3) */ | ||
350 | struct genericPartitionMap2 | ||
351 | { | ||
352 | uint8_t partitionMapType; | ||
353 | uint8_t partitionMapLength; | ||
354 | uint8_t partitionIdent[62]; | ||
355 | } __attribute__ ((packed)); | ||
356 | |||
357 | /* Unallocated Space Descriptor (ECMA 167r3 3/10.8) */ | ||
358 | struct unallocSpaceDesc | ||
359 | { | ||
360 | tag descTag; | ||
361 | __le32 volDescSeqNum; | ||
362 | __le32 numAllocDescs; | ||
363 | extent_ad allocDescs[0]; | ||
364 | } __attribute__ ((packed)); | ||
365 | |||
366 | /* Terminating Descriptor (ECMA 167r3 3/10.9) */ | ||
367 | struct terminatingDesc | ||
368 | { | ||
369 | tag descTag; | ||
370 | uint8_t reserved[496]; | ||
371 | } __attribute__ ((packed)); | ||
372 | |||
373 | /* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) */ | ||
374 | struct logicalVolIntegrityDesc | ||
375 | { | ||
376 | tag descTag; | ||
377 | timestamp recordingDateAndTime; | ||
378 | __le32 integrityType; | ||
379 | extent_ad nextIntegrityExt; | ||
380 | uint8_t logicalVolContentsUse[32]; | ||
381 | __le32 numOfPartitions; | ||
382 | __le32 lengthOfImpUse; | ||
383 | __le32 freeSpaceTable[0]; | ||
384 | __le32 sizeTable[0]; | ||
385 | uint8_t impUse[0]; | ||
386 | } __attribute__ ((packed)); | ||
387 | |||
388 | /* Integrity Type (ECMA 167r3 3/10.10.3) */ | ||
389 | #define LVID_INTEGRITY_TYPE_OPEN 0x00000000 | ||
390 | #define LVID_INTEGRITY_TYPE_CLOSE 0x00000001 | ||
391 | |||
392 | /* Recorded Address (ECMA 167r3 4/7.1) */ | ||
393 | typedef struct | ||
394 | { | ||
395 | __le32 logicalBlockNum; | ||
396 | __le16 partitionReferenceNum; | ||
397 | } __attribute__ ((packed)) lb_addr; | ||
398 | |||
399 | /* ... and its in-core analog */ | ||
400 | typedef struct | ||
401 | { | ||
402 | uint32_t logicalBlockNum; | ||
403 | uint16_t partitionReferenceNum; | ||
404 | } kernel_lb_addr; | ||
405 | |||
406 | /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */ | ||
407 | typedef struct | ||
408 | { | ||
409 | __le32 extLength; | ||
410 | __le32 extPosition; | ||
411 | } __attribute__ ((packed)) short_ad; | ||
412 | |||
413 | /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */ | ||
414 | typedef struct | ||
415 | { | ||
416 | __le32 extLength; | ||
417 | lb_addr extLocation; | ||
418 | uint8_t impUse[6]; | ||
419 | } __attribute__ ((packed)) long_ad; | ||
420 | |||
421 | typedef struct | ||
422 | { | ||
423 | uint32_t extLength; | ||
424 | kernel_lb_addr extLocation; | ||
425 | uint8_t impUse[6]; | ||
426 | } kernel_long_ad; | ||
427 | |||
428 | /* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */ | ||
429 | typedef struct | ||
430 | { | ||
431 | __le32 extLength; | ||
432 | __le32 recordedLength; | ||
433 | __le32 informationLength; | ||
434 | lb_addr extLocation; | ||
435 | } __attribute__ ((packed)) ext_ad; | ||
436 | |||
437 | typedef struct | ||
438 | { | ||
439 | uint32_t extLength; | ||
440 | uint32_t recordedLength; | ||
441 | uint32_t informationLength; | ||
442 | kernel_lb_addr extLocation; | ||
443 | } kernel_ext_ad; | ||
444 | |||
445 | /* Descriptor Tag (ECMA 167r3 4/7.2 - See 3/7.2) */ | ||
446 | |||
447 | /* Tag Identifier (ECMA 167r3 4/7.2.1) */ | ||
448 | #define TAG_IDENT_FSD 0x0100 | ||
449 | #define TAG_IDENT_FID 0x0101 | ||
450 | #define TAG_IDENT_AED 0x0102 | ||
451 | #define TAG_IDENT_IE 0x0103 | ||
452 | #define TAG_IDENT_TE 0x0104 | ||
453 | #define TAG_IDENT_FE 0x0105 | ||
454 | #define TAG_IDENT_EAHD 0x0106 | ||
455 | #define TAG_IDENT_USE 0x0107 | ||
456 | #define TAG_IDENT_SBD 0x0108 | ||
457 | #define TAG_IDENT_PIE 0x0109 | ||
458 | #define TAG_IDENT_EFE 0x010A | ||
459 | |||
460 | /* File Set Descriptor (ECMA 167r3 4/14.1) */ | ||
461 | struct fileSetDesc | ||
462 | { | ||
463 | tag descTag; | ||
464 | timestamp recordingDateAndTime; | ||
465 | __le16 interchangeLvl; | ||
466 | __le16 maxInterchangeLvl; | ||
467 | __le32 charSetList; | ||
468 | __le32 maxCharSetList; | ||
469 | __le32 fileSetNum; | ||
470 | __le32 fileSetDescNum; | ||
471 | charspec logicalVolIdentCharSet; | ||
472 | dstring logicalVolIdent[128]; | ||
473 | charspec fileSetCharSet; | ||
474 | dstring fileSetIdent[32]; | ||
475 | dstring copyrightFileIdent[32]; | ||
476 | dstring abstractFileIdent[32]; | ||
477 | long_ad rootDirectoryICB; | ||
478 | regid domainIdent; | ||
479 | long_ad nextExt; | ||
480 | long_ad streamDirectoryICB; | ||
481 | uint8_t reserved[32]; | ||
482 | } __attribute__ ((packed)); | ||
483 | |||
484 | /* Partition Header Descriptor (ECMA 167r3 4/14.3) */ | ||
485 | struct partitionHeaderDesc | ||
486 | { | ||
487 | short_ad unallocSpaceTable; | ||
488 | short_ad unallocSpaceBitmap; | ||
489 | short_ad partitionIntegrityTable; | ||
490 | short_ad freedSpaceTable; | ||
491 | short_ad freedSpaceBitmap; | ||
492 | uint8_t reserved[88]; | ||
493 | } __attribute__ ((packed)); | ||
494 | |||
495 | /* File Identifier Descriptor (ECMA 167r3 4/14.4) */ | ||
496 | struct fileIdentDesc | ||
497 | { | ||
498 | tag descTag; | ||
499 | __le16 fileVersionNum; | ||
500 | uint8_t fileCharacteristics; | ||
501 | uint8_t lengthFileIdent; | ||
502 | long_ad icb; | ||
503 | __le16 lengthOfImpUse; | ||
504 | uint8_t impUse[0]; | ||
505 | uint8_t fileIdent[0]; | ||
506 | uint8_t padding[0]; | ||
507 | } __attribute__ ((packed)); | ||
508 | |||
509 | /* File Characteristics (ECMA 167r3 4/14.4.3) */ | ||
510 | #define FID_FILE_CHAR_HIDDEN 0x01 | ||
511 | #define FID_FILE_CHAR_DIRECTORY 0x02 | ||
512 | #define FID_FILE_CHAR_DELETED 0x04 | ||
513 | #define FID_FILE_CHAR_PARENT 0x08 | ||
514 | #define FID_FILE_CHAR_METADATA 0x10 | ||
515 | |||
516 | /* Allocation Ext Descriptor (ECMA 167r3 4/14.5) */ | ||
517 | struct allocExtDesc | ||
518 | { | ||
519 | tag descTag; | ||
520 | __le32 previousAllocExtLocation; | ||
521 | __le32 lengthAllocDescs; | ||
522 | } __attribute__ ((packed)); | ||
523 | |||
524 | /* ICB Tag (ECMA 167r3 4/14.6) */ | ||
525 | typedef struct | ||
526 | { | ||
527 | __le32 priorRecordedNumDirectEntries; | ||
528 | __le16 strategyType; | ||
529 | __le16 strategyParameter; | ||
530 | __le16 numEntries; | ||
531 | uint8_t reserved; | ||
532 | uint8_t fileType; | ||
533 | lb_addr parentICBLocation; | ||
534 | __le16 flags; | ||
535 | } __attribute__ ((packed)) icbtag; | ||
536 | |||
537 | /* Strategy Type (ECMA 167r3 4/14.6.2) */ | ||
538 | #define ICBTAG_STRATEGY_TYPE_UNDEF 0x0000 | ||
539 | #define ICBTAG_STRATEGY_TYPE_1 0x0001 | ||
540 | #define ICBTAG_STRATEGY_TYPE_2 0x0002 | ||
541 | #define ICBTAG_STRATEGY_TYPE_3 0x0003 | ||
542 | #define ICBTAG_STRATEGY_TYPE_4 0x0004 | ||
543 | |||
544 | /* File Type (ECMA 167r3 4/14.6.6) */ | ||
545 | #define ICBTAG_FILE_TYPE_UNDEF 0x00 | ||
546 | #define ICBTAG_FILE_TYPE_USE 0x01 | ||
547 | #define ICBTAG_FILE_TYPE_PIE 0x02 | ||
548 | #define ICBTAG_FILE_TYPE_IE 0x03 | ||
549 | #define ICBTAG_FILE_TYPE_DIRECTORY 0x04 | ||
550 | #define ICBTAG_FILE_TYPE_REGULAR 0x05 | ||
551 | #define ICBTAG_FILE_TYPE_BLOCK 0x06 | ||
552 | #define ICBTAG_FILE_TYPE_CHAR 0x07 | ||
553 | #define ICBTAG_FILE_TYPE_EA 0x08 | ||
554 | #define ICBTAG_FILE_TYPE_FIFO 0x09 | ||
555 | #define ICBTAG_FILE_TYPE_SOCKET 0x0A | ||
556 | #define ICBTAG_FILE_TYPE_TE 0x0B | ||
557 | #define ICBTAG_FILE_TYPE_SYMLINK 0x0C | ||
558 | #define ICBTAG_FILE_TYPE_STREAMDIR 0x0D | ||
559 | |||
560 | /* Flags (ECMA 167r3 4/14.6.8) */ | ||
561 | #define ICBTAG_FLAG_AD_MASK 0x0007 | ||
562 | #define ICBTAG_FLAG_AD_SHORT 0x0000 | ||
563 | #define ICBTAG_FLAG_AD_LONG 0x0001 | ||
564 | #define ICBTAG_FLAG_AD_EXTENDED 0x0002 | ||
565 | #define ICBTAG_FLAG_AD_IN_ICB 0x0003 | ||
566 | #define ICBTAG_FLAG_SORTED 0x0008 | ||
567 | #define ICBTAG_FLAG_NONRELOCATABLE 0x0010 | ||
568 | #define ICBTAG_FLAG_ARCHIVE 0x0020 | ||
569 | #define ICBTAG_FLAG_SETUID 0x0040 | ||
570 | #define ICBTAG_FLAG_SETGID 0x0080 | ||
571 | #define ICBTAG_FLAG_STICKY 0x0100 | ||
572 | #define ICBTAG_FLAG_CONTIGUOUS 0x0200 | ||
573 | #define ICBTAG_FLAG_SYSTEM 0x0400 | ||
574 | #define ICBTAG_FLAG_TRANSFORMED 0x0800 | ||
575 | #define ICBTAG_FLAG_MULTIVERSIONS 0x1000 | ||
576 | #define ICBTAG_FLAG_STREAM 0x2000 | ||
577 | |||
578 | /* Indirect Entry (ECMA 167r3 4/14.7) */ | ||
579 | struct indirectEntry | ||
580 | { | ||
581 | tag descTag; | ||
582 | icbtag icbTag; | ||
583 | long_ad indirectICB; | ||
584 | } __attribute__ ((packed)); | ||
585 | |||
586 | /* Terminal Entry (ECMA 167r3 4/14.8) */ | ||
587 | struct terminalEntry | ||
588 | { | ||
589 | tag descTag; | ||
590 | icbtag icbTag; | ||
591 | } __attribute__ ((packed)); | ||
592 | |||
593 | /* File Entry (ECMA 167r3 4/14.9) */ | ||
594 | struct fileEntry | ||
595 | { | ||
596 | tag descTag; | ||
597 | icbtag icbTag; | ||
598 | __le32 uid; | ||
599 | __le32 gid; | ||
600 | __le32 permissions; | ||
601 | __le16 fileLinkCount; | ||
602 | uint8_t recordFormat; | ||
603 | uint8_t recordDisplayAttr; | ||
604 | __le32 recordLength; | ||
605 | __le64 informationLength; | ||
606 | __le64 logicalBlocksRecorded; | ||
607 | timestamp accessTime; | ||
608 | timestamp modificationTime; | ||
609 | timestamp attrTime; | ||
610 | __le32 checkpoint; | ||
611 | long_ad extendedAttrICB; | ||
612 | regid impIdent; | ||
613 | __le64 uniqueID; | ||
614 | __le32 lengthExtendedAttr; | ||
615 | __le32 lengthAllocDescs; | ||
616 | uint8_t extendedAttr[0]; | ||
617 | uint8_t allocDescs[0]; | ||
618 | } __attribute__ ((packed)); | ||
619 | |||
620 | /* Permissions (ECMA 167r3 4/14.9.5) */ | ||
621 | #define FE_PERM_O_EXEC 0x00000001U | ||
622 | #define FE_PERM_O_WRITE 0x00000002U | ||
623 | #define FE_PERM_O_READ 0x00000004U | ||
624 | #define FE_PERM_O_CHATTR 0x00000008U | ||
625 | #define FE_PERM_O_DELETE 0x00000010U | ||
626 | #define FE_PERM_G_EXEC 0x00000020U | ||
627 | #define FE_PERM_G_WRITE 0x00000040U | ||
628 | #define FE_PERM_G_READ 0x00000080U | ||
629 | #define FE_PERM_G_CHATTR 0x00000100U | ||
630 | #define FE_PERM_G_DELETE 0x00000200U | ||
631 | #define FE_PERM_U_EXEC 0x00000400U | ||
632 | #define FE_PERM_U_WRITE 0x00000800U | ||
633 | #define FE_PERM_U_READ 0x00001000U | ||
634 | #define FE_PERM_U_CHATTR 0x00002000U | ||
635 | #define FE_PERM_U_DELETE 0x00004000U | ||
636 | |||
637 | /* Record Format (ECMA 167r3 4/14.9.7) */ | ||
638 | #define FE_RECORD_FMT_UNDEF 0x00 | ||
639 | #define FE_RECORD_FMT_FIXED_PAD 0x01 | ||
640 | #define FE_RECORD_FMT_FIXED 0x02 | ||
641 | #define FE_RECORD_FMT_VARIABLE8 0x03 | ||
642 | #define FE_RECORD_FMT_VARIABLE16 0x04 | ||
643 | #define FE_RECORD_FMT_VARIABLE16_MSB 0x05 | ||
644 | #define FE_RECORD_FMT_VARIABLE32 0x06 | ||
645 | #define FE_RECORD_FMT_PRINT 0x07 | ||
646 | #define FE_RECORD_FMT_LF 0x08 | ||
647 | #define FE_RECORD_FMT_CR 0x09 | ||
648 | #define FE_RECORD_FMT_CRLF 0x0A | ||
649 | #define FE_RECORD_FMT_LFCR 0x0B | ||
650 | |||
651 | /* Record Display Attributes (ECMA 167r3 4/14.9.8) */ | ||
652 | #define FE_RECORD_DISPLAY_ATTR_UNDEF 0x00 | ||
653 | #define FE_RECORD_DISPLAY_ATTR_1 0x01 | ||
654 | #define FE_RECORD_DISPLAY_ATTR_2 0x02 | ||
655 | #define FE_RECORD_DISPLAY_ATTR_3 0x03 | ||
656 | |||
657 | /* Extended Attribute Header Descriptor (ECMA 167r3 4/14.10.1) */ | ||
658 | struct extendedAttrHeaderDesc | ||
659 | { | ||
660 | tag descTag; | ||
661 | __le32 impAttrLocation; | ||
662 | __le32 appAttrLocation; | ||
663 | } __attribute__ ((packed)); | ||
664 | |||
665 | /* Generic Format (ECMA 167r3 4/14.10.2) */ | ||
666 | struct genericFormat | ||
667 | { | ||
668 | __le32 attrType; | ||
669 | uint8_t attrSubtype; | ||
670 | uint8_t reserved[3]; | ||
671 | __le32 attrLength; | ||
672 | uint8_t attrData[0]; | ||
673 | } __attribute__ ((packed)); | ||
674 | |||
675 | /* Character Set Information (ECMA 167r3 4/14.10.3) */ | ||
676 | struct charSetInfo | ||
677 | { | ||
678 | __le32 attrType; | ||
679 | uint8_t attrSubtype; | ||
680 | uint8_t reserved[3]; | ||
681 | __le32 attrLength; | ||
682 | __le32 escapeSeqLength; | ||
683 | uint8_t charSetType; | ||
684 | uint8_t escapeSeq[0]; | ||
685 | } __attribute__ ((packed)); | ||
686 | |||
687 | /* Alternate Permissions (ECMA 167r3 4/14.10.4) */ | ||
688 | struct altPerms | ||
689 | { | ||
690 | __le32 attrType; | ||
691 | uint8_t attrSubtype; | ||
692 | uint8_t reserved[3]; | ||
693 | __le32 attrLength; | ||
694 | __le16 ownerIdent; | ||
695 | __le16 groupIdent; | ||
696 | __le16 permission; | ||
697 | } __attribute__ ((packed)); | ||
698 | |||
699 | /* File Times Extended Attribute (ECMA 167r3 4/14.10.5) */ | ||
700 | struct fileTimesExtAttr | ||
701 | { | ||
702 | __le32 attrType; | ||
703 | uint8_t attrSubtype; | ||
704 | uint8_t reserved[3]; | ||
705 | __le32 attrLength; | ||
706 | __le32 dataLength; | ||
707 | __le32 fileTimeExistence; | ||
708 | uint8_t fileTimes; | ||
709 | } __attribute__ ((packed)); | ||
710 | |||
711 | /* FileTimeExistence (ECMA 167r3 4/14.10.5.6) */ | ||
712 | #define FTE_CREATION 0x00000001 | ||
713 | #define FTE_DELETION 0x00000004 | ||
714 | #define FTE_EFFECTIVE 0x00000008 | ||
715 | #define FTE_BACKUP 0x00000002 | ||
716 | |||
717 | /* Information Times Extended Attribute (ECMA 167r3 4/14.10.6) */ | ||
718 | struct infoTimesExtAttr | ||
719 | { | ||
720 | __le32 attrType; | ||
721 | uint8_t attrSubtype; | ||
722 | uint8_t reserved[3]; | ||
723 | __le32 attrLength; | ||
724 | __le32 dataLength; | ||
725 | __le32 infoTimeExistence; | ||
726 | uint8_t infoTimes[0]; | ||
727 | } __attribute__ ((packed)); | ||
728 | |||
729 | /* Device Specification (ECMA 167r3 4/14.10.7) */ | ||
730 | struct deviceSpec | ||
731 | { | ||
732 | __le32 attrType; | ||
733 | uint8_t attrSubtype; | ||
734 | uint8_t reserved[3]; | ||
735 | __le32 attrLength; | ||
736 | __le32 impUseLength; | ||
737 | __le32 majorDeviceIdent; | ||
738 | __le32 minorDeviceIdent; | ||
739 | uint8_t impUse[0]; | ||
740 | } __attribute__ ((packed)); | ||
741 | |||
742 | /* Implementation Use Extended Attr (ECMA 167r3 4/14.10.8) */ | ||
743 | struct impUseExtAttr | ||
744 | { | ||
745 | __le32 attrType; | ||
746 | uint8_t attrSubtype; | ||
747 | uint8_t reserved[3]; | ||
748 | __le32 attrLength; | ||
749 | __le32 impUseLength; | ||
750 | regid impIdent; | ||
751 | uint8_t impUse[0]; | ||
752 | } __attribute__ ((packed)); | ||
753 | |||
754 | /* Application Use Extended Attribute (ECMA 167r3 4/14.10.9) */ | ||
755 | struct appUseExtAttr | ||
756 | { | ||
757 | __le32 attrType; | ||
758 | uint8_t attrSubtype; | ||
759 | uint8_t reserved[3]; | ||
760 | __le32 attrLength; | ||
761 | __le32 appUseLength; | ||
762 | regid appIdent; | ||
763 | uint8_t appUse[0]; | ||
764 | } __attribute__ ((packed)); | ||
765 | |||
766 | #define EXTATTR_CHAR_SET 1 | ||
767 | #define EXTATTR_ALT_PERMS 3 | ||
768 | #define EXTATTR_FILE_TIMES 5 | ||
769 | #define EXTATTR_INFO_TIMES 6 | ||
770 | #define EXTATTR_DEV_SPEC 12 | ||
771 | #define EXTATTR_IMP_USE 2048 | ||
772 | #define EXTATTR_APP_USE 65536 | ||
773 | |||
774 | |||
775 | /* Unallocated Space Entry (ECMA 167r3 4/14.11) */ | ||
776 | struct unallocSpaceEntry | ||
777 | { | ||
778 | tag descTag; | ||
779 | icbtag icbTag; | ||
780 | __le32 lengthAllocDescs; | ||
781 | uint8_t allocDescs[0]; | ||
782 | } __attribute__ ((packed)); | ||
783 | |||
784 | /* Space Bitmap Descriptor (ECMA 167r3 4/14.12) */ | ||
785 | struct spaceBitmapDesc | ||
786 | { | ||
787 | tag descTag; | ||
788 | __le32 numOfBits; | ||
789 | __le32 numOfBytes; | ||
790 | uint8_t bitmap[0]; | ||
791 | } __attribute__ ((packed)); | ||
792 | |||
793 | /* Partition Integrity Entry (ECMA 167r3 4/14.13) */ | ||
794 | struct partitionIntegrityEntry | ||
795 | { | ||
796 | tag descTag; | ||
797 | icbtag icbTag; | ||
798 | timestamp recordingDateAndTime; | ||
799 | uint8_t integrityType; | ||
800 | uint8_t reserved[175]; | ||
801 | regid impIdent; | ||
802 | uint8_t impUse[256]; | ||
803 | } __attribute__ ((packed)); | ||
804 | |||
805 | /* Short Allocation Descriptor (ECMA 167r3 4/14.14.1) */ | ||
806 | |||
807 | /* Extent Length (ECMA 167r3 4/14.14.1.1) */ | ||
808 | #define EXT_RECORDED_ALLOCATED 0x00000000 | ||
809 | #define EXT_NOT_RECORDED_ALLOCATED 0x40000000 | ||
810 | #define EXT_NOT_RECORDED_NOT_ALLOCATED 0x80000000 | ||
811 | #define EXT_NEXT_EXTENT_ALLOCDECS 0xC0000000 | ||
812 | |||
813 | /* Long Allocation Descriptor (ECMA 167r3 4/14.14.2) */ | ||
814 | |||
815 | /* Extended Allocation Descriptor (ECMA 167r3 4/14.14.3) */ | ||
816 | |||
817 | /* Logical Volume Header Descriptor (ECMA 167r3 4/14.15) */ | ||
818 | struct logicalVolHeaderDesc | ||
819 | { | ||
820 | __le64 uniqueID; | ||
821 | uint8_t reserved[24]; | ||
822 | } __attribute__ ((packed)); | ||
823 | |||
824 | /* Path Component (ECMA 167r3 4/14.16.1) */ | ||
825 | struct pathComponent | ||
826 | { | ||
827 | uint8_t componentType; | ||
828 | uint8_t lengthComponentIdent; | ||
829 | __le16 componentFileVersionNum; | ||
830 | dstring componentIdent[0]; | ||
831 | } __attribute__ ((packed)); | ||
832 | |||
833 | /* File Entry (ECMA 167r3 4/14.17) */ | ||
834 | struct extendedFileEntry | ||
835 | { | ||
836 | tag descTag; | ||
837 | icbtag icbTag; | ||
838 | __le32 uid; | ||
839 | __le32 gid; | ||
840 | __le32 permissions; | ||
841 | __le16 fileLinkCount; | ||
842 | uint8_t recordFormat; | ||
843 | uint8_t recordDisplayAttr; | ||
844 | __le32 recordLength; | ||
845 | __le64 informationLength; | ||
846 | __le64 objectSize; | ||
847 | __le64 logicalBlocksRecorded; | ||
848 | timestamp accessTime; | ||
849 | timestamp modificationTime; | ||
850 | timestamp createTime; | ||
851 | timestamp attrTime; | ||
852 | __le32 checkpoint; | ||
853 | __le32 reserved; | ||
854 | long_ad extendedAttrICB; | ||
855 | long_ad streamDirectoryICB; | ||
856 | regid impIdent; | ||
857 | __le64 uniqueID; | ||
858 | __le32 lengthExtendedAttr; | ||
859 | __le32 lengthAllocDescs; | ||
860 | uint8_t extendedAttr[0]; | ||
861 | uint8_t allocDescs[0]; | ||
862 | } __attribute__ ((packed)); | ||
863 | |||
864 | #endif /* _ECMA_167_H */ | ||
diff --git a/fs/udf/file.c b/fs/udf/file.c new file mode 100644 index 000000000000..2faa4172b9f7 --- /dev/null +++ b/fs/udf/file.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * file.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * File handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-1999 Dave Boynton | ||
19 | * (C) 1998-2004 Ben Fennema | ||
20 | * (C) 1999-2000 Stelias Computing Inc | ||
21 | * | ||
22 | * HISTORY | ||
23 | * | ||
24 | * 10/02/98 dgb Attempt to integrate into udf.o | ||
25 | * 10/07/98 Switched to using generic_readpage, etc., like isofs | ||
26 | * And it works! | ||
27 | * 12/06/98 blf Added udf_file_read. uses generic_file_read for all cases but | ||
28 | * ICBTAG_FLAG_AD_IN_ICB. | ||
29 | * 04/06/99 64 bit file handling on 32 bit systems taken from ext2 file.c | ||
30 | * 05/12/99 Preliminary file write support | ||
31 | */ | ||
32 | |||
33 | #include "udfdecl.h" | ||
34 | #include <linux/fs.h> | ||
35 | #include <linux/udf_fs.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/string.h> /* memset */ | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/smp_lock.h> | ||
41 | #include <linux/pagemap.h> | ||
42 | #include <linux/buffer_head.h> | ||
43 | |||
44 | #include "udf_i.h" | ||
45 | #include "udf_sb.h" | ||
46 | |||
47 | static int udf_adinicb_readpage(struct file *file, struct page * page) | ||
48 | { | ||
49 | struct inode *inode = page->mapping->host; | ||
50 | char *kaddr; | ||
51 | |||
52 | if (!PageLocked(page)) | ||
53 | PAGE_BUG(page); | ||
54 | |||
55 | kaddr = kmap(page); | ||
56 | memset(kaddr, 0, PAGE_CACHE_SIZE); | ||
57 | memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), inode->i_size); | ||
58 | flush_dcache_page(page); | ||
59 | SetPageUptodate(page); | ||
60 | kunmap(page); | ||
61 | unlock_page(page); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc) | ||
66 | { | ||
67 | struct inode *inode = page->mapping->host; | ||
68 | char *kaddr; | ||
69 | |||
70 | if (!PageLocked(page)) | ||
71 | PAGE_BUG(page); | ||
72 | |||
73 | kaddr = kmap(page); | ||
74 | memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size); | ||
75 | mark_inode_dirty(inode); | ||
76 | SetPageUptodate(page); | ||
77 | kunmap(page); | ||
78 | unlock_page(page); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) | ||
83 | { | ||
84 | kmap(page); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) | ||
89 | { | ||
90 | struct inode *inode = page->mapping->host; | ||
91 | char *kaddr = page_address(page); | ||
92 | |||
93 | memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, | ||
94 | kaddr + offset, to - offset); | ||
95 | mark_inode_dirty(inode); | ||
96 | SetPageUptodate(page); | ||
97 | kunmap(page); | ||
98 | /* only one page here */ | ||
99 | if (to > inode->i_size) | ||
100 | inode->i_size = to; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | struct address_space_operations udf_adinicb_aops = { | ||
105 | .readpage = udf_adinicb_readpage, | ||
106 | .writepage = udf_adinicb_writepage, | ||
107 | .sync_page = block_sync_page, | ||
108 | .prepare_write = udf_adinicb_prepare_write, | ||
109 | .commit_write = udf_adinicb_commit_write, | ||
110 | }; | ||
111 | |||
112 | static ssize_t udf_file_write(struct file * file, const char __user * buf, | ||
113 | size_t count, loff_t *ppos) | ||
114 | { | ||
115 | ssize_t retval; | ||
116 | struct inode *inode = file->f_dentry->d_inode; | ||
117 | int err, pos; | ||
118 | |||
119 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
120 | { | ||
121 | if (file->f_flags & O_APPEND) | ||
122 | pos = inode->i_size; | ||
123 | else | ||
124 | pos = *ppos; | ||
125 | |||
126 | if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + | ||
127 | pos + count)) | ||
128 | { | ||
129 | udf_expand_file_adinicb(inode, pos + count, &err); | ||
130 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
131 | { | ||
132 | udf_debug("udf_expand_adinicb: err=%d\n", err); | ||
133 | return err; | ||
134 | } | ||
135 | } | ||
136 | else | ||
137 | { | ||
138 | if (pos + count > inode->i_size) | ||
139 | UDF_I_LENALLOC(inode) = pos + count; | ||
140 | else | ||
141 | UDF_I_LENALLOC(inode) = inode->i_size; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | retval = generic_file_write(file, buf, count, ppos); | ||
146 | |||
147 | if (retval > 0) | ||
148 | mark_inode_dirty(inode); | ||
149 | return retval; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * udf_ioctl | ||
154 | * | ||
155 | * PURPOSE | ||
156 | * Issue an ioctl. | ||
157 | * | ||
158 | * DESCRIPTION | ||
159 | * Optional - sys_ioctl() will return -ENOTTY if this routine is not | ||
160 | * available, and the ioctl cannot be handled without filesystem help. | ||
161 | * | ||
162 | * sys_ioctl() handles these ioctls that apply only to regular files: | ||
163 | * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD | ||
164 | * These ioctls are also handled by sys_ioctl(): | ||
165 | * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC | ||
166 | * All other ioctls are passed to the filesystem. | ||
167 | * | ||
168 | * Refer to sys_ioctl() in fs/ioctl.c | ||
169 | * sys_ioctl() -> . | ||
170 | * | ||
171 | * PRE-CONDITIONS | ||
172 | * inode Pointer to inode that ioctl was issued on. | ||
173 | * filp Pointer to file that ioctl was issued on. | ||
174 | * cmd The ioctl command. | ||
175 | * arg The ioctl argument [can be interpreted as a | ||
176 | * user-space pointer if desired]. | ||
177 | * | ||
178 | * POST-CONDITIONS | ||
179 | * <return> Success (>=0) or an error code (<=0) that | ||
180 | * sys_ioctl() will return. | ||
181 | * | ||
182 | * HISTORY | ||
183 | * July 1, 1997 - Andrew E. Mileski | ||
184 | * Written, tested, and released. | ||
185 | */ | ||
186 | int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
187 | unsigned long arg) | ||
188 | { | ||
189 | int result = -EINVAL; | ||
190 | |||
191 | if ( permission(inode, MAY_READ, NULL) != 0 ) | ||
192 | { | ||
193 | udf_debug("no permission to access inode %lu\n", | ||
194 | inode->i_ino); | ||
195 | return -EPERM; | ||
196 | } | ||
197 | |||
198 | if ( !arg ) | ||
199 | { | ||
200 | udf_debug("invalid argument to udf_ioctl\n"); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | switch (cmd) | ||
205 | { | ||
206 | case UDF_GETVOLIDENT: | ||
207 | return copy_to_user((char __user *)arg, | ||
208 | UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0; | ||
209 | case UDF_RELOCATE_BLOCKS: | ||
210 | { | ||
211 | long old, new; | ||
212 | |||
213 | if (!capable(CAP_SYS_ADMIN)) return -EACCES; | ||
214 | if (get_user(old, (long __user *)arg)) return -EFAULT; | ||
215 | if ((result = udf_relocate_blocks(inode->i_sb, | ||
216 | old, &new)) == 0) | ||
217 | result = put_user(new, (long __user *)arg); | ||
218 | |||
219 | return result; | ||
220 | } | ||
221 | case UDF_GETEASIZE: | ||
222 | result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg); | ||
223 | break; | ||
224 | |||
225 | case UDF_GETEABLOCK: | ||
226 | result = copy_to_user((char __user *)arg, UDF_I_DATA(inode), | ||
227 | UDF_I_LENEATTR(inode)) ? -EFAULT : 0; | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | return result; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * udf_release_file | ||
236 | * | ||
237 | * PURPOSE | ||
238 | * Called when all references to the file are closed | ||
239 | * | ||
240 | * DESCRIPTION | ||
241 | * Discard prealloced blocks | ||
242 | * | ||
243 | * HISTORY | ||
244 | * | ||
245 | */ | ||
246 | static int udf_release_file(struct inode * inode, struct file * filp) | ||
247 | { | ||
248 | if (filp->f_mode & FMODE_WRITE) | ||
249 | { | ||
250 | lock_kernel(); | ||
251 | udf_discard_prealloc(inode); | ||
252 | unlock_kernel(); | ||
253 | } | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | struct file_operations udf_file_operations = { | ||
258 | .read = generic_file_read, | ||
259 | .ioctl = udf_ioctl, | ||
260 | .open = generic_file_open, | ||
261 | .mmap = generic_file_mmap, | ||
262 | .write = udf_file_write, | ||
263 | .release = udf_release_file, | ||
264 | .fsync = udf_fsync_file, | ||
265 | .sendfile = generic_file_sendfile, | ||
266 | }; | ||
267 | |||
268 | struct inode_operations udf_file_inode_operations = { | ||
269 | .truncate = udf_truncate, | ||
270 | }; | ||
diff --git a/fs/udf/fsync.c b/fs/udf/fsync.c new file mode 100644 index 000000000000..2dde6b888c2b --- /dev/null +++ b/fs/udf/fsync.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * fsync.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Fsync handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1999-2001 Ben Fennema | ||
19 | * (C) 1999-2000 Stelias Computing Inc | ||
20 | * | ||
21 | * HISTORY | ||
22 | * | ||
23 | * 05/22/99 blf Created. | ||
24 | */ | ||
25 | |||
26 | #include "udfdecl.h" | ||
27 | |||
28 | #include <linux/fs.h> | ||
29 | #include <linux/smp_lock.h> | ||
30 | |||
31 | static int udf_fsync_inode(struct inode *, int); | ||
32 | |||
33 | /* | ||
34 | * File may be NULL when we are called. Perhaps we shouldn't | ||
35 | * even pass file to fsync ? | ||
36 | */ | ||
37 | |||
38 | int udf_fsync_file(struct file * file, struct dentry *dentry, int datasync) | ||
39 | { | ||
40 | struct inode *inode = dentry->d_inode; | ||
41 | return udf_fsync_inode(inode, datasync); | ||
42 | } | ||
43 | |||
44 | static int udf_fsync_inode(struct inode *inode, int datasync) | ||
45 | { | ||
46 | int err; | ||
47 | |||
48 | err = sync_mapping_buffers(inode->i_mapping); | ||
49 | if (!(inode->i_state & I_DIRTY)) | ||
50 | return err; | ||
51 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) | ||
52 | return err; | ||
53 | |||
54 | err |= udf_sync_inode (inode); | ||
55 | return err ? -EIO : 0; | ||
56 | } | ||
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c new file mode 100644 index 000000000000..a7e5d40f1ebc --- /dev/null +++ b/fs/udf/ialloc.c | |||
@@ -0,0 +1,170 @@ | |||
1 | /* | ||
2 | * ialloc.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Inode allocation handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-2001 Ben Fennema | ||
19 | * | ||
20 | * HISTORY | ||
21 | * | ||
22 | * 02/24/99 blf Created. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "udfdecl.h" | ||
27 | #include <linux/fs.h> | ||
28 | #include <linux/quotaops.h> | ||
29 | #include <linux/udf_fs.h> | ||
30 | #include <linux/sched.h> | ||
31 | #include <linux/slab.h> | ||
32 | |||
33 | #include "udf_i.h" | ||
34 | #include "udf_sb.h" | ||
35 | |||
36 | void udf_free_inode(struct inode * inode) | ||
37 | { | ||
38 | struct super_block *sb = inode->i_sb; | ||
39 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
40 | |||
41 | /* | ||
42 | * Note: we must free any quota before locking the superblock, | ||
43 | * as writing the quota to disk may need the lock as well. | ||
44 | */ | ||
45 | DQUOT_FREE_INODE(inode); | ||
46 | DQUOT_DROP(inode); | ||
47 | |||
48 | clear_inode(inode); | ||
49 | |||
50 | down(&sbi->s_alloc_sem); | ||
51 | if (sbi->s_lvidbh) { | ||
52 | if (S_ISDIR(inode->i_mode)) | ||
53 | UDF_SB_LVIDIU(sb)->numDirs = | ||
54 | cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) - 1); | ||
55 | else | ||
56 | UDF_SB_LVIDIU(sb)->numFiles = | ||
57 | cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) - 1); | ||
58 | |||
59 | mark_buffer_dirty(sbi->s_lvidbh); | ||
60 | } | ||
61 | up(&sbi->s_alloc_sem); | ||
62 | |||
63 | udf_free_blocks(sb, NULL, UDF_I_LOCATION(inode), 0, 1); | ||
64 | } | ||
65 | |||
66 | struct inode * udf_new_inode (struct inode *dir, int mode, int * err) | ||
67 | { | ||
68 | struct super_block *sb = dir->i_sb; | ||
69 | struct udf_sb_info *sbi = UDF_SB(sb); | ||
70 | struct inode * inode; | ||
71 | int block; | ||
72 | uint32_t start = UDF_I_LOCATION(dir).logicalBlockNum; | ||
73 | |||
74 | inode = new_inode(sb); | ||
75 | |||
76 | if (!inode) | ||
77 | { | ||
78 | *err = -ENOMEM; | ||
79 | return NULL; | ||
80 | } | ||
81 | *err = -ENOSPC; | ||
82 | |||
83 | block = udf_new_block(dir->i_sb, NULL, UDF_I_LOCATION(dir).partitionReferenceNum, | ||
84 | start, err); | ||
85 | if (*err) | ||
86 | { | ||
87 | iput(inode); | ||
88 | return NULL; | ||
89 | } | ||
90 | |||
91 | down(&sbi->s_alloc_sem); | ||
92 | UDF_I_UNIQUE(inode) = 0; | ||
93 | UDF_I_LENEXTENTS(inode) = 0; | ||
94 | UDF_I_NEXT_ALLOC_BLOCK(inode) = 0; | ||
95 | UDF_I_NEXT_ALLOC_GOAL(inode) = 0; | ||
96 | UDF_I_STRAT4096(inode) = 0; | ||
97 | if (UDF_SB_LVIDBH(sb)) | ||
98 | { | ||
99 | struct logicalVolHeaderDesc *lvhd; | ||
100 | uint64_t uniqueID; | ||
101 | lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(sb)->logicalVolContentsUse); | ||
102 | if (S_ISDIR(mode)) | ||
103 | UDF_SB_LVIDIU(sb)->numDirs = | ||
104 | cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs) + 1); | ||
105 | else | ||
106 | UDF_SB_LVIDIU(sb)->numFiles = | ||
107 | cpu_to_le32(le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + 1); | ||
108 | UDF_I_UNIQUE(inode) = uniqueID = le64_to_cpu(lvhd->uniqueID); | ||
109 | if (!(++uniqueID & 0x00000000FFFFFFFFUL)) | ||
110 | uniqueID += 16; | ||
111 | lvhd->uniqueID = cpu_to_le64(uniqueID); | ||
112 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
113 | } | ||
114 | inode->i_mode = mode; | ||
115 | inode->i_uid = current->fsuid; | ||
116 | if (dir->i_mode & S_ISGID) | ||
117 | { | ||
118 | inode->i_gid = dir->i_gid; | ||
119 | if (S_ISDIR(mode)) | ||
120 | mode |= S_ISGID; | ||
121 | } | ||
122 | else | ||
123 | inode->i_gid = current->fsgid; | ||
124 | |||
125 | UDF_I_LOCATION(inode).logicalBlockNum = block; | ||
126 | UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum; | ||
127 | inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0); | ||
128 | inode->i_blksize = PAGE_SIZE; | ||
129 | inode->i_blocks = 0; | ||
130 | UDF_I_LENEATTR(inode) = 0; | ||
131 | UDF_I_LENALLOC(inode) = 0; | ||
132 | UDF_I_USE(inode) = 0; | ||
133 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_EXTENDED_FE)) | ||
134 | { | ||
135 | UDF_I_EFE(inode) = 1; | ||
136 | UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE); | ||
137 | UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL); | ||
138 | memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | UDF_I_EFE(inode) = 0; | ||
143 | UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL); | ||
144 | memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct fileEntry)); | ||
145 | } | ||
146 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB)) | ||
147 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; | ||
148 | else if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) | ||
149 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT; | ||
150 | else | ||
151 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; | ||
152 | inode->i_mtime = inode->i_atime = inode->i_ctime = | ||
153 | UDF_I_CRTIME(inode) = current_fs_time(inode->i_sb); | ||
154 | insert_inode_hash(inode); | ||
155 | mark_inode_dirty(inode); | ||
156 | up(&sbi->s_alloc_sem); | ||
157 | |||
158 | if (DQUOT_ALLOC_INODE(inode)) | ||
159 | { | ||
160 | DQUOT_DROP(inode); | ||
161 | inode->i_flags |= S_NOQUOTA; | ||
162 | inode->i_nlink = 0; | ||
163 | iput(inode); | ||
164 | *err = -EDQUOT; | ||
165 | return NULL; | ||
166 | } | ||
167 | |||
168 | *err = 0; | ||
169 | return inode; | ||
170 | } | ||
diff --git a/fs/udf/inode.c b/fs/udf/inode.c new file mode 100644 index 000000000000..0506e1173784 --- /dev/null +++ b/fs/udf/inode.c | |||
@@ -0,0 +1,2010 @@ | |||
1 | /* | ||
2 | * inode.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Inode handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998 Dave Boynton | ||
19 | * (C) 1998-2004 Ben Fennema | ||
20 | * (C) 1999-2000 Stelias Computing Inc | ||
21 | * | ||
22 | * HISTORY | ||
23 | * | ||
24 | * 10/04/98 dgb Added rudimentary directory functions | ||
25 | * 10/07/98 Fully working udf_block_map! It works! | ||
26 | * 11/25/98 bmap altered to better support extents | ||
27 | * 12/06/98 blf partition support in udf_iget, udf_block_map and udf_read_inode | ||
28 | * 12/12/98 rewrote udf_block_map to handle next extents and descs across | ||
29 | * block boundaries (which is not actually allowed) | ||
30 | * 12/20/98 added support for strategy 4096 | ||
31 | * 03/07/99 rewrote udf_block_map (again) | ||
32 | * New funcs, inode_bmap, udf_next_aext | ||
33 | * 04/19/99 Support for writing device EA's for major/minor # | ||
34 | */ | ||
35 | |||
36 | #include "udfdecl.h" | ||
37 | #include <linux/mm.h> | ||
38 | #include <linux/smp_lock.h> | ||
39 | #include <linux/module.h> | ||
40 | #include <linux/pagemap.h> | ||
41 | #include <linux/buffer_head.h> | ||
42 | #include <linux/writeback.h> | ||
43 | #include <linux/slab.h> | ||
44 | |||
45 | #include "udf_i.h" | ||
46 | #include "udf_sb.h" | ||
47 | |||
48 | MODULE_AUTHOR("Ben Fennema"); | ||
49 | MODULE_DESCRIPTION("Universal Disk Format Filesystem"); | ||
50 | MODULE_LICENSE("GPL"); | ||
51 | |||
52 | #define EXTENT_MERGE_SIZE 5 | ||
53 | |||
54 | static mode_t udf_convert_permissions(struct fileEntry *); | ||
55 | static int udf_update_inode(struct inode *, int); | ||
56 | static void udf_fill_inode(struct inode *, struct buffer_head *); | ||
57 | static struct buffer_head *inode_getblk(struct inode *, long, int *, | ||
58 | long *, int *); | ||
59 | static int8_t udf_insert_aext(struct inode *, kernel_lb_addr, int, | ||
60 | kernel_lb_addr, uint32_t, struct buffer_head *); | ||
61 | static void udf_split_extents(struct inode *, int *, int, int, | ||
62 | kernel_long_ad [EXTENT_MERGE_SIZE], int *); | ||
63 | static void udf_prealloc_extents(struct inode *, int, int, | ||
64 | kernel_long_ad [EXTENT_MERGE_SIZE], int *); | ||
65 | static void udf_merge_extents(struct inode *, | ||
66 | kernel_long_ad [EXTENT_MERGE_SIZE], int *); | ||
67 | static void udf_update_extents(struct inode *, | ||
68 | kernel_long_ad [EXTENT_MERGE_SIZE], int, int, | ||
69 | kernel_lb_addr, uint32_t, struct buffer_head **); | ||
70 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); | ||
71 | |||
72 | /* | ||
73 | * udf_delete_inode | ||
74 | * | ||
75 | * PURPOSE | ||
76 | * Clean-up before the specified inode is destroyed. | ||
77 | * | ||
78 | * DESCRIPTION | ||
79 | * This routine is called when the kernel destroys an inode structure | ||
80 | * ie. when iput() finds i_count == 0. | ||
81 | * | ||
82 | * HISTORY | ||
83 | * July 1, 1997 - Andrew E. Mileski | ||
84 | * Written, tested, and released. | ||
85 | * | ||
86 | * Called at the last iput() if i_nlink is zero. | ||
87 | */ | ||
88 | void udf_delete_inode(struct inode * inode) | ||
89 | { | ||
90 | if (is_bad_inode(inode)) | ||
91 | goto no_delete; | ||
92 | |||
93 | inode->i_size = 0; | ||
94 | udf_truncate(inode); | ||
95 | lock_kernel(); | ||
96 | |||
97 | udf_update_inode(inode, IS_SYNC(inode)); | ||
98 | udf_free_inode(inode); | ||
99 | |||
100 | unlock_kernel(); | ||
101 | return; | ||
102 | no_delete: | ||
103 | clear_inode(inode); | ||
104 | } | ||
105 | |||
106 | void udf_clear_inode(struct inode *inode) | ||
107 | { | ||
108 | if (!(inode->i_sb->s_flags & MS_RDONLY)) { | ||
109 | lock_kernel(); | ||
110 | udf_discard_prealloc(inode); | ||
111 | unlock_kernel(); | ||
112 | } | ||
113 | |||
114 | kfree(UDF_I_DATA(inode)); | ||
115 | UDF_I_DATA(inode) = NULL; | ||
116 | } | ||
117 | |||
118 | static int udf_writepage(struct page *page, struct writeback_control *wbc) | ||
119 | { | ||
120 | return block_write_full_page(page, udf_get_block, wbc); | ||
121 | } | ||
122 | |||
123 | static int udf_readpage(struct file *file, struct page *page) | ||
124 | { | ||
125 | return block_read_full_page(page, udf_get_block); | ||
126 | } | ||
127 | |||
128 | static int udf_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) | ||
129 | { | ||
130 | return block_prepare_write(page, from, to, udf_get_block); | ||
131 | } | ||
132 | |||
133 | static sector_t udf_bmap(struct address_space *mapping, sector_t block) | ||
134 | { | ||
135 | return generic_block_bmap(mapping,block,udf_get_block); | ||
136 | } | ||
137 | |||
138 | struct address_space_operations udf_aops = { | ||
139 | .readpage = udf_readpage, | ||
140 | .writepage = udf_writepage, | ||
141 | .sync_page = block_sync_page, | ||
142 | .prepare_write = udf_prepare_write, | ||
143 | .commit_write = generic_commit_write, | ||
144 | .bmap = udf_bmap, | ||
145 | }; | ||
146 | |||
147 | void udf_expand_file_adinicb(struct inode * inode, int newsize, int * err) | ||
148 | { | ||
149 | struct page *page; | ||
150 | char *kaddr; | ||
151 | struct writeback_control udf_wbc = { | ||
152 | .sync_mode = WB_SYNC_NONE, | ||
153 | .nr_to_write = 1, | ||
154 | }; | ||
155 | |||
156 | /* from now on we have normal address_space methods */ | ||
157 | inode->i_data.a_ops = &udf_aops; | ||
158 | |||
159 | if (!UDF_I_LENALLOC(inode)) | ||
160 | { | ||
161 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) | ||
162 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT; | ||
163 | else | ||
164 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; | ||
165 | mark_inode_dirty(inode); | ||
166 | return; | ||
167 | } | ||
168 | |||
169 | page = grab_cache_page(inode->i_mapping, 0); | ||
170 | if (!PageLocked(page)) | ||
171 | PAGE_BUG(page); | ||
172 | if (!PageUptodate(page)) | ||
173 | { | ||
174 | kaddr = kmap(page); | ||
175 | memset(kaddr + UDF_I_LENALLOC(inode), 0x00, | ||
176 | PAGE_CACHE_SIZE - UDF_I_LENALLOC(inode)); | ||
177 | memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), | ||
178 | UDF_I_LENALLOC(inode)); | ||
179 | flush_dcache_page(page); | ||
180 | SetPageUptodate(page); | ||
181 | kunmap(page); | ||
182 | } | ||
183 | memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0x00, | ||
184 | UDF_I_LENALLOC(inode)); | ||
185 | UDF_I_LENALLOC(inode) = 0; | ||
186 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) | ||
187 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_SHORT; | ||
188 | else | ||
189 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_LONG; | ||
190 | |||
191 | inode->i_data.a_ops->writepage(page, &udf_wbc); | ||
192 | page_cache_release(page); | ||
193 | |||
194 | mark_inode_dirty(inode); | ||
195 | } | ||
196 | |||
197 | struct buffer_head * udf_expand_dir_adinicb(struct inode *inode, int *block, int *err) | ||
198 | { | ||
199 | int newblock; | ||
200 | struct buffer_head *sbh = NULL, *dbh = NULL; | ||
201 | kernel_lb_addr bloc, eloc; | ||
202 | uint32_t elen, extoffset; | ||
203 | uint8_t alloctype; | ||
204 | |||
205 | struct udf_fileident_bh sfibh, dfibh; | ||
206 | loff_t f_pos = udf_ext0_offset(inode) >> 2; | ||
207 | int size = (udf_ext0_offset(inode) + inode->i_size) >> 2; | ||
208 | struct fileIdentDesc cfi, *sfi, *dfi; | ||
209 | |||
210 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD)) | ||
211 | alloctype = ICBTAG_FLAG_AD_SHORT; | ||
212 | else | ||
213 | alloctype = ICBTAG_FLAG_AD_LONG; | ||
214 | |||
215 | if (!inode->i_size) | ||
216 | { | ||
217 | UDF_I_ALLOCTYPE(inode) = alloctype; | ||
218 | mark_inode_dirty(inode); | ||
219 | return NULL; | ||
220 | } | ||
221 | |||
222 | /* alloc block, and copy data to it */ | ||
223 | *block = udf_new_block(inode->i_sb, inode, | ||
224 | UDF_I_LOCATION(inode).partitionReferenceNum, | ||
225 | UDF_I_LOCATION(inode).logicalBlockNum, err); | ||
226 | |||
227 | if (!(*block)) | ||
228 | return NULL; | ||
229 | newblock = udf_get_pblock(inode->i_sb, *block, | ||
230 | UDF_I_LOCATION(inode).partitionReferenceNum, 0); | ||
231 | if (!newblock) | ||
232 | return NULL; | ||
233 | dbh = udf_tgetblk(inode->i_sb, newblock); | ||
234 | if (!dbh) | ||
235 | return NULL; | ||
236 | lock_buffer(dbh); | ||
237 | memset(dbh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
238 | set_buffer_uptodate(dbh); | ||
239 | unlock_buffer(dbh); | ||
240 | mark_buffer_dirty_inode(dbh, inode); | ||
241 | |||
242 | sfibh.soffset = sfibh.eoffset = (f_pos & ((inode->i_sb->s_blocksize - 1) >> 2)) << 2; | ||
243 | sbh = sfibh.sbh = sfibh.ebh = NULL; | ||
244 | dfibh.soffset = dfibh.eoffset = 0; | ||
245 | dfibh.sbh = dfibh.ebh = dbh; | ||
246 | while ( (f_pos < size) ) | ||
247 | { | ||
248 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; | ||
249 | sfi = udf_fileident_read(inode, &f_pos, &sfibh, &cfi, NULL, NULL, NULL, NULL, NULL, NULL); | ||
250 | if (!sfi) | ||
251 | { | ||
252 | udf_release_data(dbh); | ||
253 | return NULL; | ||
254 | } | ||
255 | UDF_I_ALLOCTYPE(inode) = alloctype; | ||
256 | sfi->descTag.tagLocation = cpu_to_le32(*block); | ||
257 | dfibh.soffset = dfibh.eoffset; | ||
258 | dfibh.eoffset += (sfibh.eoffset - sfibh.soffset); | ||
259 | dfi = (struct fileIdentDesc *)(dbh->b_data + dfibh.soffset); | ||
260 | if (udf_write_fi(inode, sfi, dfi, &dfibh, sfi->impUse, | ||
261 | sfi->fileIdent + le16_to_cpu(sfi->lengthOfImpUse))) | ||
262 | { | ||
263 | UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB; | ||
264 | udf_release_data(dbh); | ||
265 | return NULL; | ||
266 | } | ||
267 | } | ||
268 | mark_buffer_dirty_inode(dbh, inode); | ||
269 | |||
270 | memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), 0, UDF_I_LENALLOC(inode)); | ||
271 | UDF_I_LENALLOC(inode) = 0; | ||
272 | bloc = UDF_I_LOCATION(inode); | ||
273 | eloc.logicalBlockNum = *block; | ||
274 | eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; | ||
275 | elen = inode->i_size; | ||
276 | UDF_I_LENEXTENTS(inode) = elen; | ||
277 | extoffset = udf_file_entry_alloc_offset(inode); | ||
278 | udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &sbh, 0); | ||
279 | /* UniqueID stuff */ | ||
280 | |||
281 | udf_release_data(sbh); | ||
282 | mark_inode_dirty(inode); | ||
283 | return dbh; | ||
284 | } | ||
285 | |||
286 | static int udf_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_result, int create) | ||
287 | { | ||
288 | int err, new; | ||
289 | struct buffer_head *bh; | ||
290 | unsigned long phys; | ||
291 | |||
292 | if (!create) | ||
293 | { | ||
294 | phys = udf_block_map(inode, block); | ||
295 | if (phys) | ||
296 | map_bh(bh_result, inode->i_sb, phys); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | err = -EIO; | ||
301 | new = 0; | ||
302 | bh = NULL; | ||
303 | |||
304 | lock_kernel(); | ||
305 | |||
306 | if (block < 0) | ||
307 | goto abort_negative; | ||
308 | |||
309 | if (block == UDF_I_NEXT_ALLOC_BLOCK(inode) + 1) | ||
310 | { | ||
311 | UDF_I_NEXT_ALLOC_BLOCK(inode) ++; | ||
312 | UDF_I_NEXT_ALLOC_GOAL(inode) ++; | ||
313 | } | ||
314 | |||
315 | err = 0; | ||
316 | |||
317 | bh = inode_getblk(inode, block, &err, &phys, &new); | ||
318 | if (bh) | ||
319 | BUG(); | ||
320 | if (err) | ||
321 | goto abort; | ||
322 | if (!phys) | ||
323 | BUG(); | ||
324 | |||
325 | if (new) | ||
326 | set_buffer_new(bh_result); | ||
327 | map_bh(bh_result, inode->i_sb, phys); | ||
328 | abort: | ||
329 | unlock_kernel(); | ||
330 | return err; | ||
331 | |||
332 | abort_negative: | ||
333 | udf_warning(inode->i_sb, "udf_get_block", "block < 0"); | ||
334 | goto abort; | ||
335 | } | ||
336 | |||
337 | static struct buffer_head * | ||
338 | udf_getblk(struct inode *inode, long block, int create, int *err) | ||
339 | { | ||
340 | struct buffer_head dummy; | ||
341 | |||
342 | dummy.b_state = 0; | ||
343 | dummy.b_blocknr = -1000; | ||
344 | *err = udf_get_block(inode, block, &dummy, create); | ||
345 | if (!*err && buffer_mapped(&dummy)) | ||
346 | { | ||
347 | struct buffer_head *bh; | ||
348 | bh = sb_getblk(inode->i_sb, dummy.b_blocknr); | ||
349 | if (buffer_new(&dummy)) | ||
350 | { | ||
351 | lock_buffer(bh); | ||
352 | memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
353 | set_buffer_uptodate(bh); | ||
354 | unlock_buffer(bh); | ||
355 | mark_buffer_dirty_inode(bh, inode); | ||
356 | } | ||
357 | return bh; | ||
358 | } | ||
359 | return NULL; | ||
360 | } | ||
361 | |||
362 | static struct buffer_head * inode_getblk(struct inode * inode, long block, | ||
363 | int *err, long *phys, int *new) | ||
364 | { | ||
365 | struct buffer_head *pbh = NULL, *cbh = NULL, *nbh = NULL, *result = NULL; | ||
366 | kernel_long_ad laarr[EXTENT_MERGE_SIZE]; | ||
367 | uint32_t pextoffset = 0, cextoffset = 0, nextoffset = 0; | ||
368 | int count = 0, startnum = 0, endnum = 0; | ||
369 | uint32_t elen = 0; | ||
370 | kernel_lb_addr eloc, pbloc, cbloc, nbloc; | ||
371 | int c = 1; | ||
372 | uint64_t lbcount = 0, b_off = 0; | ||
373 | uint32_t newblocknum, newblock, offset = 0; | ||
374 | int8_t etype; | ||
375 | int goal = 0, pgoal = UDF_I_LOCATION(inode).logicalBlockNum; | ||
376 | char lastblock = 0; | ||
377 | |||
378 | pextoffset = cextoffset = nextoffset = udf_file_entry_alloc_offset(inode); | ||
379 | b_off = (uint64_t)block << inode->i_sb->s_blocksize_bits; | ||
380 | pbloc = cbloc = nbloc = UDF_I_LOCATION(inode); | ||
381 | |||
382 | /* find the extent which contains the block we are looking for. | ||
383 | alternate between laarr[0] and laarr[1] for locations of the | ||
384 | current extent, and the previous extent */ | ||
385 | do | ||
386 | { | ||
387 | if (pbh != cbh) | ||
388 | { | ||
389 | udf_release_data(pbh); | ||
390 | atomic_inc(&cbh->b_count); | ||
391 | pbh = cbh; | ||
392 | } | ||
393 | if (cbh != nbh) | ||
394 | { | ||
395 | udf_release_data(cbh); | ||
396 | atomic_inc(&nbh->b_count); | ||
397 | cbh = nbh; | ||
398 | } | ||
399 | |||
400 | lbcount += elen; | ||
401 | |||
402 | pbloc = cbloc; | ||
403 | cbloc = nbloc; | ||
404 | |||
405 | pextoffset = cextoffset; | ||
406 | cextoffset = nextoffset; | ||
407 | |||
408 | if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) == -1) | ||
409 | break; | ||
410 | |||
411 | c = !c; | ||
412 | |||
413 | laarr[c].extLength = (etype << 30) | elen; | ||
414 | laarr[c].extLocation = eloc; | ||
415 | |||
416 | if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) | ||
417 | pgoal = eloc.logicalBlockNum + | ||
418 | ((elen + inode->i_sb->s_blocksize - 1) >> | ||
419 | inode->i_sb->s_blocksize_bits); | ||
420 | |||
421 | count ++; | ||
422 | } while (lbcount + elen <= b_off); | ||
423 | |||
424 | b_off -= lbcount; | ||
425 | offset = b_off >> inode->i_sb->s_blocksize_bits; | ||
426 | |||
427 | /* if the extent is allocated and recorded, return the block | ||
428 | if the extent is not a multiple of the blocksize, round up */ | ||
429 | |||
430 | if (etype == (EXT_RECORDED_ALLOCATED >> 30)) | ||
431 | { | ||
432 | if (elen & (inode->i_sb->s_blocksize - 1)) | ||
433 | { | ||
434 | elen = EXT_RECORDED_ALLOCATED | | ||
435 | ((elen + inode->i_sb->s_blocksize - 1) & | ||
436 | ~(inode->i_sb->s_blocksize - 1)); | ||
437 | etype = udf_write_aext(inode, nbloc, &cextoffset, eloc, elen, nbh, 1); | ||
438 | } | ||
439 | udf_release_data(pbh); | ||
440 | udf_release_data(cbh); | ||
441 | udf_release_data(nbh); | ||
442 | newblock = udf_get_lb_pblock(inode->i_sb, eloc, offset); | ||
443 | *phys = newblock; | ||
444 | return NULL; | ||
445 | } | ||
446 | |||
447 | if (etype == -1) | ||
448 | { | ||
449 | endnum = startnum = ((count > 1) ? 1 : count); | ||
450 | if (laarr[c].extLength & (inode->i_sb->s_blocksize - 1)) | ||
451 | { | ||
452 | laarr[c].extLength = | ||
453 | (laarr[c].extLength & UDF_EXTENT_FLAG_MASK) | | ||
454 | (((laarr[c].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
455 | inode->i_sb->s_blocksize - 1) & | ||
456 | ~(inode->i_sb->s_blocksize - 1)); | ||
457 | UDF_I_LENEXTENTS(inode) = | ||
458 | (UDF_I_LENEXTENTS(inode) + inode->i_sb->s_blocksize - 1) & | ||
459 | ~(inode->i_sb->s_blocksize - 1); | ||
460 | } | ||
461 | c = !c; | ||
462 | laarr[c].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | | ||
463 | ((offset + 1) << inode->i_sb->s_blocksize_bits); | ||
464 | memset(&laarr[c].extLocation, 0x00, sizeof(kernel_lb_addr)); | ||
465 | count ++; | ||
466 | endnum ++; | ||
467 | lastblock = 1; | ||
468 | } | ||
469 | else | ||
470 | endnum = startnum = ((count > 2) ? 2 : count); | ||
471 | |||
472 | /* if the current extent is in position 0, swap it with the previous */ | ||
473 | if (!c && count != 1) | ||
474 | { | ||
475 | laarr[2] = laarr[0]; | ||
476 | laarr[0] = laarr[1]; | ||
477 | laarr[1] = laarr[2]; | ||
478 | c = 1; | ||
479 | } | ||
480 | |||
481 | /* if the current block is located in a extent, read the next extent */ | ||
482 | if (etype != -1) | ||
483 | { | ||
484 | if ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 0)) != -1) | ||
485 | { | ||
486 | laarr[c+1].extLength = (etype << 30) | elen; | ||
487 | laarr[c+1].extLocation = eloc; | ||
488 | count ++; | ||
489 | startnum ++; | ||
490 | endnum ++; | ||
491 | } | ||
492 | else | ||
493 | lastblock = 1; | ||
494 | } | ||
495 | udf_release_data(cbh); | ||
496 | udf_release_data(nbh); | ||
497 | |||
498 | /* if the current extent is not recorded but allocated, get the | ||
499 | block in the extent corresponding to the requested block */ | ||
500 | if ((laarr[c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
501 | newblocknum = laarr[c].extLocation.logicalBlockNum + offset; | ||
502 | else /* otherwise, allocate a new block */ | ||
503 | { | ||
504 | if (UDF_I_NEXT_ALLOC_BLOCK(inode) == block) | ||
505 | goal = UDF_I_NEXT_ALLOC_GOAL(inode); | ||
506 | |||
507 | if (!goal) | ||
508 | { | ||
509 | if (!(goal = pgoal)) | ||
510 | goal = UDF_I_LOCATION(inode).logicalBlockNum + 1; | ||
511 | } | ||
512 | |||
513 | if (!(newblocknum = udf_new_block(inode->i_sb, inode, | ||
514 | UDF_I_LOCATION(inode).partitionReferenceNum, goal, err))) | ||
515 | { | ||
516 | udf_release_data(pbh); | ||
517 | *err = -ENOSPC; | ||
518 | return NULL; | ||
519 | } | ||
520 | UDF_I_LENEXTENTS(inode) += inode->i_sb->s_blocksize; | ||
521 | } | ||
522 | |||
523 | /* if the extent the requsted block is located in contains multiple blocks, | ||
524 | split the extent into at most three extents. blocks prior to requested | ||
525 | block, requested block, and blocks after requested block */ | ||
526 | udf_split_extents(inode, &c, offset, newblocknum, laarr, &endnum); | ||
527 | |||
528 | #ifdef UDF_PREALLOCATE | ||
529 | /* preallocate blocks */ | ||
530 | udf_prealloc_extents(inode, c, lastblock, laarr, &endnum); | ||
531 | #endif | ||
532 | |||
533 | /* merge any continuous blocks in laarr */ | ||
534 | udf_merge_extents(inode, laarr, &endnum); | ||
535 | |||
536 | /* write back the new extents, inserting new extents if the new number | ||
537 | of extents is greater than the old number, and deleting extents if | ||
538 | the new number of extents is less than the old number */ | ||
539 | udf_update_extents(inode, laarr, startnum, endnum, pbloc, pextoffset, &pbh); | ||
540 | |||
541 | udf_release_data(pbh); | ||
542 | |||
543 | if (!(newblock = udf_get_pblock(inode->i_sb, newblocknum, | ||
544 | UDF_I_LOCATION(inode).partitionReferenceNum, 0))) | ||
545 | { | ||
546 | return NULL; | ||
547 | } | ||
548 | *phys = newblock; | ||
549 | *err = 0; | ||
550 | *new = 1; | ||
551 | UDF_I_NEXT_ALLOC_BLOCK(inode) = block; | ||
552 | UDF_I_NEXT_ALLOC_GOAL(inode) = newblocknum; | ||
553 | inode->i_ctime = current_fs_time(inode->i_sb); | ||
554 | |||
555 | if (IS_SYNC(inode)) | ||
556 | udf_sync_inode(inode); | ||
557 | else | ||
558 | mark_inode_dirty(inode); | ||
559 | return result; | ||
560 | } | ||
561 | |||
562 | static void udf_split_extents(struct inode *inode, int *c, int offset, int newblocknum, | ||
563 | kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum) | ||
564 | { | ||
565 | if ((laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30) || | ||
566 | (laarr[*c].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) | ||
567 | { | ||
568 | int curr = *c; | ||
569 | int blen = ((laarr[curr].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
570 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; | ||
571 | int8_t etype = (laarr[curr].extLength >> 30); | ||
572 | |||
573 | if (blen == 1) | ||
574 | ; | ||
575 | else if (!offset || blen == offset + 1) | ||
576 | { | ||
577 | laarr[curr+2] = laarr[curr+1]; | ||
578 | laarr[curr+1] = laarr[curr]; | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | laarr[curr+3] = laarr[curr+1]; | ||
583 | laarr[curr+2] = laarr[curr+1] = laarr[curr]; | ||
584 | } | ||
585 | |||
586 | if (offset) | ||
587 | { | ||
588 | if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
589 | { | ||
590 | udf_free_blocks(inode->i_sb, inode, laarr[curr].extLocation, 0, offset); | ||
591 | laarr[curr].extLength = EXT_NOT_RECORDED_NOT_ALLOCATED | | ||
592 | (offset << inode->i_sb->s_blocksize_bits); | ||
593 | laarr[curr].extLocation.logicalBlockNum = 0; | ||
594 | laarr[curr].extLocation.partitionReferenceNum = 0; | ||
595 | } | ||
596 | else | ||
597 | laarr[curr].extLength = (etype << 30) | | ||
598 | (offset << inode->i_sb->s_blocksize_bits); | ||
599 | curr ++; | ||
600 | (*c) ++; | ||
601 | (*endnum) ++; | ||
602 | } | ||
603 | |||
604 | laarr[curr].extLocation.logicalBlockNum = newblocknum; | ||
605 | if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) | ||
606 | laarr[curr].extLocation.partitionReferenceNum = | ||
607 | UDF_I_LOCATION(inode).partitionReferenceNum; | ||
608 | laarr[curr].extLength = EXT_RECORDED_ALLOCATED | | ||
609 | inode->i_sb->s_blocksize; | ||
610 | curr ++; | ||
611 | |||
612 | if (blen != offset + 1) | ||
613 | { | ||
614 | if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
615 | laarr[curr].extLocation.logicalBlockNum += (offset + 1); | ||
616 | laarr[curr].extLength = (etype << 30) | | ||
617 | ((blen - (offset + 1)) << inode->i_sb->s_blocksize_bits); | ||
618 | curr ++; | ||
619 | (*endnum) ++; | ||
620 | } | ||
621 | } | ||
622 | } | ||
623 | |||
624 | static void udf_prealloc_extents(struct inode *inode, int c, int lastblock, | ||
625 | kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum) | ||
626 | { | ||
627 | int start, length = 0, currlength = 0, i; | ||
628 | |||
629 | if (*endnum >= (c+1)) | ||
630 | { | ||
631 | if (!lastblock) | ||
632 | return; | ||
633 | else | ||
634 | start = c; | ||
635 | } | ||
636 | else | ||
637 | { | ||
638 | if ((laarr[c+1].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
639 | { | ||
640 | start = c+1; | ||
641 | length = currlength = (((laarr[c+1].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
642 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); | ||
643 | } | ||
644 | else | ||
645 | start = c; | ||
646 | } | ||
647 | |||
648 | for (i=start+1; i<=*endnum; i++) | ||
649 | { | ||
650 | if (i == *endnum) | ||
651 | { | ||
652 | if (lastblock) | ||
653 | length += UDF_DEFAULT_PREALLOC_BLOCKS; | ||
654 | } | ||
655 | else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) | ||
656 | length += (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
657 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); | ||
658 | else | ||
659 | break; | ||
660 | } | ||
661 | |||
662 | if (length) | ||
663 | { | ||
664 | int next = laarr[start].extLocation.logicalBlockNum + | ||
665 | (((laarr[start].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
666 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); | ||
667 | int numalloc = udf_prealloc_blocks(inode->i_sb, inode, | ||
668 | laarr[start].extLocation.partitionReferenceNum, | ||
669 | next, (UDF_DEFAULT_PREALLOC_BLOCKS > length ? length : | ||
670 | UDF_DEFAULT_PREALLOC_BLOCKS) - currlength); | ||
671 | |||
672 | if (numalloc) | ||
673 | { | ||
674 | if (start == (c+1)) | ||
675 | laarr[start].extLength += | ||
676 | (numalloc << inode->i_sb->s_blocksize_bits); | ||
677 | else | ||
678 | { | ||
679 | memmove(&laarr[c+2], &laarr[c+1], | ||
680 | sizeof(long_ad) * (*endnum - (c+1))); | ||
681 | (*endnum) ++; | ||
682 | laarr[c+1].extLocation.logicalBlockNum = next; | ||
683 | laarr[c+1].extLocation.partitionReferenceNum = | ||
684 | laarr[c].extLocation.partitionReferenceNum; | ||
685 | laarr[c+1].extLength = EXT_NOT_RECORDED_ALLOCATED | | ||
686 | (numalloc << inode->i_sb->s_blocksize_bits); | ||
687 | start = c+1; | ||
688 | } | ||
689 | |||
690 | for (i=start+1; numalloc && i<*endnum; i++) | ||
691 | { | ||
692 | int elen = ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
693 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; | ||
694 | |||
695 | if (elen > numalloc) | ||
696 | { | ||
697 | laarr[i].extLength -= | ||
698 | (numalloc << inode->i_sb->s_blocksize_bits); | ||
699 | numalloc = 0; | ||
700 | } | ||
701 | else | ||
702 | { | ||
703 | numalloc -= elen; | ||
704 | if (*endnum > (i+1)) | ||
705 | memmove(&laarr[i], &laarr[i+1], | ||
706 | sizeof(long_ad) * (*endnum - (i+1))); | ||
707 | i --; | ||
708 | (*endnum) --; | ||
709 | } | ||
710 | } | ||
711 | UDF_I_LENEXTENTS(inode) += numalloc << inode->i_sb->s_blocksize_bits; | ||
712 | } | ||
713 | } | ||
714 | } | ||
715 | |||
716 | static void udf_merge_extents(struct inode *inode, | ||
717 | kernel_long_ad laarr[EXTENT_MERGE_SIZE], int *endnum) | ||
718 | { | ||
719 | int i; | ||
720 | |||
721 | for (i=0; i<(*endnum-1); i++) | ||
722 | { | ||
723 | if ((laarr[i].extLength >> 30) == (laarr[i+1].extLength >> 30)) | ||
724 | { | ||
725 | if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) || | ||
726 | ((laarr[i+1].extLocation.logicalBlockNum - laarr[i].extLocation.logicalBlockNum) == | ||
727 | (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
728 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits))) | ||
729 | { | ||
730 | if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
731 | (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
732 | inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) | ||
733 | { | ||
734 | laarr[i+1].extLength = (laarr[i+1].extLength - | ||
735 | (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
736 | UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1); | ||
737 | laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) + | ||
738 | (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize; | ||
739 | laarr[i+1].extLocation.logicalBlockNum = | ||
740 | laarr[i].extLocation.logicalBlockNum + | ||
741 | ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) >> | ||
742 | inode->i_sb->s_blocksize_bits); | ||
743 | } | ||
744 | else | ||
745 | { | ||
746 | laarr[i].extLength = laarr[i+1].extLength + | ||
747 | (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
748 | inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1)); | ||
749 | if (*endnum > (i+2)) | ||
750 | memmove(&laarr[i+1], &laarr[i+2], | ||
751 | sizeof(long_ad) * (*endnum - (i+2))); | ||
752 | i --; | ||
753 | (*endnum) --; | ||
754 | } | ||
755 | } | ||
756 | } | ||
757 | else if (((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) && | ||
758 | ((laarr[i+1].extLength >> 30) == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30))) | ||
759 | { | ||
760 | udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0, | ||
761 | ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
762 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); | ||
763 | laarr[i].extLocation.logicalBlockNum = 0; | ||
764 | laarr[i].extLocation.partitionReferenceNum = 0; | ||
765 | |||
766 | if (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
767 | (laarr[i+1].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
768 | inode->i_sb->s_blocksize - 1) & ~UDF_EXTENT_LENGTH_MASK) | ||
769 | { | ||
770 | laarr[i+1].extLength = (laarr[i+1].extLength - | ||
771 | (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
772 | UDF_EXTENT_LENGTH_MASK) & ~(inode->i_sb->s_blocksize-1); | ||
773 | laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_FLAG_MASK) + | ||
774 | (UDF_EXTENT_LENGTH_MASK + 1) - inode->i_sb->s_blocksize; | ||
775 | } | ||
776 | else | ||
777 | { | ||
778 | laarr[i].extLength = laarr[i+1].extLength + | ||
779 | (((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
780 | inode->i_sb->s_blocksize - 1) & ~(inode->i_sb->s_blocksize-1)); | ||
781 | if (*endnum > (i+2)) | ||
782 | memmove(&laarr[i+1], &laarr[i+2], | ||
783 | sizeof(long_ad) * (*endnum - (i+2))); | ||
784 | i --; | ||
785 | (*endnum) --; | ||
786 | } | ||
787 | } | ||
788 | else if ((laarr[i].extLength >> 30) == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
789 | { | ||
790 | udf_free_blocks(inode->i_sb, inode, laarr[i].extLocation, 0, | ||
791 | ((laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) + | ||
792 | inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits); | ||
793 | laarr[i].extLocation.logicalBlockNum = 0; | ||
794 | laarr[i].extLocation.partitionReferenceNum = 0; | ||
795 | laarr[i].extLength = (laarr[i].extLength & UDF_EXTENT_LENGTH_MASK) | | ||
796 | EXT_NOT_RECORDED_NOT_ALLOCATED; | ||
797 | } | ||
798 | } | ||
799 | } | ||
800 | |||
801 | static void udf_update_extents(struct inode *inode, | ||
802 | kernel_long_ad laarr[EXTENT_MERGE_SIZE], int startnum, int endnum, | ||
803 | kernel_lb_addr pbloc, uint32_t pextoffset, struct buffer_head **pbh) | ||
804 | { | ||
805 | int start = 0, i; | ||
806 | kernel_lb_addr tmploc; | ||
807 | uint32_t tmplen; | ||
808 | |||
809 | if (startnum > endnum) | ||
810 | { | ||
811 | for (i=0; i<(startnum-endnum); i++) | ||
812 | { | ||
813 | udf_delete_aext(inode, pbloc, pextoffset, laarr[i].extLocation, | ||
814 | laarr[i].extLength, *pbh); | ||
815 | } | ||
816 | } | ||
817 | else if (startnum < endnum) | ||
818 | { | ||
819 | for (i=0; i<(endnum-startnum); i++) | ||
820 | { | ||
821 | udf_insert_aext(inode, pbloc, pextoffset, laarr[i].extLocation, | ||
822 | laarr[i].extLength, *pbh); | ||
823 | udf_next_aext(inode, &pbloc, &pextoffset, &laarr[i].extLocation, | ||
824 | &laarr[i].extLength, pbh, 1); | ||
825 | start ++; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | for (i=start; i<endnum; i++) | ||
830 | { | ||
831 | udf_next_aext(inode, &pbloc, &pextoffset, &tmploc, &tmplen, pbh, 0); | ||
832 | udf_write_aext(inode, pbloc, &pextoffset, laarr[i].extLocation, | ||
833 | laarr[i].extLength, *pbh, 1); | ||
834 | } | ||
835 | } | ||
836 | |||
837 | struct buffer_head * udf_bread(struct inode * inode, int block, | ||
838 | int create, int * err) | ||
839 | { | ||
840 | struct buffer_head * bh = NULL; | ||
841 | |||
842 | bh = udf_getblk(inode, block, create, err); | ||
843 | if (!bh) | ||
844 | return NULL; | ||
845 | |||
846 | if (buffer_uptodate(bh)) | ||
847 | return bh; | ||
848 | ll_rw_block(READ, 1, &bh); | ||
849 | wait_on_buffer(bh); | ||
850 | if (buffer_uptodate(bh)) | ||
851 | return bh; | ||
852 | brelse(bh); | ||
853 | *err = -EIO; | ||
854 | return NULL; | ||
855 | } | ||
856 | |||
857 | void udf_truncate(struct inode * inode) | ||
858 | { | ||
859 | int offset; | ||
860 | int err; | ||
861 | |||
862 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | ||
863 | S_ISLNK(inode->i_mode))) | ||
864 | return; | ||
865 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
866 | return; | ||
867 | |||
868 | lock_kernel(); | ||
869 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
870 | { | ||
871 | if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + | ||
872 | inode->i_size)) | ||
873 | { | ||
874 | udf_expand_file_adinicb(inode, inode->i_size, &err); | ||
875 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
876 | { | ||
877 | inode->i_size = UDF_I_LENALLOC(inode); | ||
878 | unlock_kernel(); | ||
879 | return; | ||
880 | } | ||
881 | else | ||
882 | udf_truncate_extents(inode); | ||
883 | } | ||
884 | else | ||
885 | { | ||
886 | offset = inode->i_size & (inode->i_sb->s_blocksize - 1); | ||
887 | memset(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, 0x00, inode->i_sb->s_blocksize - offset - udf_file_entry_alloc_offset(inode)); | ||
888 | UDF_I_LENALLOC(inode) = inode->i_size; | ||
889 | } | ||
890 | } | ||
891 | else | ||
892 | { | ||
893 | block_truncate_page(inode->i_mapping, inode->i_size, udf_get_block); | ||
894 | udf_truncate_extents(inode); | ||
895 | } | ||
896 | |||
897 | inode->i_mtime = inode->i_ctime = current_fs_time(inode->i_sb); | ||
898 | if (IS_SYNC(inode)) | ||
899 | udf_sync_inode (inode); | ||
900 | else | ||
901 | mark_inode_dirty(inode); | ||
902 | unlock_kernel(); | ||
903 | } | ||
904 | |||
905 | static void | ||
906 | __udf_read_inode(struct inode *inode) | ||
907 | { | ||
908 | struct buffer_head *bh = NULL; | ||
909 | struct fileEntry *fe; | ||
910 | uint16_t ident; | ||
911 | |||
912 | /* | ||
913 | * Set defaults, but the inode is still incomplete! | ||
914 | * Note: get_new_inode() sets the following on a new inode: | ||
915 | * i_sb = sb | ||
916 | * i_no = ino | ||
917 | * i_flags = sb->s_flags | ||
918 | * i_state = 0 | ||
919 | * clean_inode(): zero fills and sets | ||
920 | * i_count = 1 | ||
921 | * i_nlink = 1 | ||
922 | * i_op = NULL; | ||
923 | */ | ||
924 | inode->i_blksize = PAGE_SIZE; | ||
925 | |||
926 | bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident); | ||
927 | |||
928 | if (!bh) | ||
929 | { | ||
930 | printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed !bh\n", | ||
931 | inode->i_ino); | ||
932 | make_bad_inode(inode); | ||
933 | return; | ||
934 | } | ||
935 | |||
936 | if (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE && | ||
937 | ident != TAG_IDENT_USE) | ||
938 | { | ||
939 | printk(KERN_ERR "udf: udf_read_inode(ino %ld) failed ident=%d\n", | ||
940 | inode->i_ino, ident); | ||
941 | udf_release_data(bh); | ||
942 | make_bad_inode(inode); | ||
943 | return; | ||
944 | } | ||
945 | |||
946 | fe = (struct fileEntry *)bh->b_data; | ||
947 | |||
948 | if (le16_to_cpu(fe->icbTag.strategyType) == 4096) | ||
949 | { | ||
950 | struct buffer_head *ibh = NULL, *nbh = NULL; | ||
951 | struct indirectEntry *ie; | ||
952 | |||
953 | ibh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 1, &ident); | ||
954 | if (ident == TAG_IDENT_IE) | ||
955 | { | ||
956 | if (ibh) | ||
957 | { | ||
958 | kernel_lb_addr loc; | ||
959 | ie = (struct indirectEntry *)ibh->b_data; | ||
960 | |||
961 | loc = lelb_to_cpu(ie->indirectICB.extLocation); | ||
962 | |||
963 | if (ie->indirectICB.extLength && | ||
964 | (nbh = udf_read_ptagged(inode->i_sb, loc, 0, &ident))) | ||
965 | { | ||
966 | if (ident == TAG_IDENT_FE || | ||
967 | ident == TAG_IDENT_EFE) | ||
968 | { | ||
969 | memcpy(&UDF_I_LOCATION(inode), &loc, sizeof(kernel_lb_addr)); | ||
970 | udf_release_data(bh); | ||
971 | udf_release_data(ibh); | ||
972 | udf_release_data(nbh); | ||
973 | __udf_read_inode(inode); | ||
974 | return; | ||
975 | } | ||
976 | else | ||
977 | { | ||
978 | udf_release_data(nbh); | ||
979 | udf_release_data(ibh); | ||
980 | } | ||
981 | } | ||
982 | else | ||
983 | udf_release_data(ibh); | ||
984 | } | ||
985 | } | ||
986 | else | ||
987 | udf_release_data(ibh); | ||
988 | } | ||
989 | else if (le16_to_cpu(fe->icbTag.strategyType) != 4) | ||
990 | { | ||
991 | printk(KERN_ERR "udf: unsupported strategy type: %d\n", | ||
992 | le16_to_cpu(fe->icbTag.strategyType)); | ||
993 | udf_release_data(bh); | ||
994 | make_bad_inode(inode); | ||
995 | return; | ||
996 | } | ||
997 | udf_fill_inode(inode, bh); | ||
998 | udf_release_data(bh); | ||
999 | } | ||
1000 | |||
1001 | static void udf_fill_inode(struct inode *inode, struct buffer_head *bh) | ||
1002 | { | ||
1003 | struct fileEntry *fe; | ||
1004 | struct extendedFileEntry *efe; | ||
1005 | time_t convtime; | ||
1006 | long convtime_usec; | ||
1007 | int offset; | ||
1008 | |||
1009 | fe = (struct fileEntry *)bh->b_data; | ||
1010 | efe = (struct extendedFileEntry *)bh->b_data; | ||
1011 | |||
1012 | if (le16_to_cpu(fe->icbTag.strategyType) == 4) | ||
1013 | UDF_I_STRAT4096(inode) = 0; | ||
1014 | else /* if (le16_to_cpu(fe->icbTag.strategyType) == 4096) */ | ||
1015 | UDF_I_STRAT4096(inode) = 1; | ||
1016 | |||
1017 | UDF_I_ALLOCTYPE(inode) = le16_to_cpu(fe->icbTag.flags) & ICBTAG_FLAG_AD_MASK; | ||
1018 | UDF_I_UNIQUE(inode) = 0; | ||
1019 | UDF_I_LENEATTR(inode) = 0; | ||
1020 | UDF_I_LENEXTENTS(inode) = 0; | ||
1021 | UDF_I_LENALLOC(inode) = 0; | ||
1022 | UDF_I_NEXT_ALLOC_BLOCK(inode) = 0; | ||
1023 | UDF_I_NEXT_ALLOC_GOAL(inode) = 0; | ||
1024 | if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_EFE) | ||
1025 | { | ||
1026 | UDF_I_EFE(inode) = 1; | ||
1027 | UDF_I_USE(inode) = 0; | ||
1028 | UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL); | ||
1029 | memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct extendedFileEntry), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); | ||
1030 | } | ||
1031 | else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_FE) | ||
1032 | { | ||
1033 | UDF_I_EFE(inode) = 0; | ||
1034 | UDF_I_USE(inode) = 0; | ||
1035 | UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL); | ||
1036 | memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct fileEntry), inode->i_sb->s_blocksize - sizeof(struct fileEntry)); | ||
1037 | } | ||
1038 | else if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) | ||
1039 | { | ||
1040 | UDF_I_EFE(inode) = 0; | ||
1041 | UDF_I_USE(inode) = 1; | ||
1042 | UDF_I_LENALLOC(inode) = | ||
1043 | le32_to_cpu( | ||
1044 | ((struct unallocSpaceEntry *)bh->b_data)->lengthAllocDescs); | ||
1045 | UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry), GFP_KERNEL); | ||
1046 | memcpy(UDF_I_DATA(inode), bh->b_data + sizeof(struct unallocSpaceEntry), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)); | ||
1047 | return; | ||
1048 | } | ||
1049 | |||
1050 | inode->i_uid = le32_to_cpu(fe->uid); | ||
1051 | if ( inode->i_uid == -1 ) inode->i_uid = UDF_SB(inode->i_sb)->s_uid; | ||
1052 | |||
1053 | inode->i_gid = le32_to_cpu(fe->gid); | ||
1054 | if ( inode->i_gid == -1 ) inode->i_gid = UDF_SB(inode->i_sb)->s_gid; | ||
1055 | |||
1056 | inode->i_nlink = le16_to_cpu(fe->fileLinkCount); | ||
1057 | if (!inode->i_nlink) | ||
1058 | inode->i_nlink = 1; | ||
1059 | |||
1060 | inode->i_size = le64_to_cpu(fe->informationLength); | ||
1061 | UDF_I_LENEXTENTS(inode) = inode->i_size; | ||
1062 | |||
1063 | inode->i_mode = udf_convert_permissions(fe); | ||
1064 | inode->i_mode &= ~UDF_SB(inode->i_sb)->s_umask; | ||
1065 | |||
1066 | if (UDF_I_EFE(inode) == 0) | ||
1067 | { | ||
1068 | inode->i_blocks = le64_to_cpu(fe->logicalBlocksRecorded) << | ||
1069 | (inode->i_sb->s_blocksize_bits - 9); | ||
1070 | |||
1071 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1072 | lets_to_cpu(fe->accessTime)) ) | ||
1073 | { | ||
1074 | inode->i_atime.tv_sec = convtime; | ||
1075 | inode->i_atime.tv_nsec = convtime_usec * 1000; | ||
1076 | } | ||
1077 | else | ||
1078 | { | ||
1079 | inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); | ||
1080 | } | ||
1081 | |||
1082 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1083 | lets_to_cpu(fe->modificationTime)) ) | ||
1084 | { | ||
1085 | inode->i_mtime.tv_sec = convtime; | ||
1086 | inode->i_mtime.tv_nsec = convtime_usec * 1000; | ||
1087 | } | ||
1088 | else | ||
1089 | { | ||
1090 | inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb); | ||
1091 | } | ||
1092 | |||
1093 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1094 | lets_to_cpu(fe->attrTime)) ) | ||
1095 | { | ||
1096 | inode->i_ctime.tv_sec = convtime; | ||
1097 | inode->i_ctime.tv_nsec = convtime_usec * 1000; | ||
1098 | } | ||
1099 | else | ||
1100 | { | ||
1101 | inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb); | ||
1102 | } | ||
1103 | |||
1104 | UDF_I_UNIQUE(inode) = le64_to_cpu(fe->uniqueID); | ||
1105 | UDF_I_LENEATTR(inode) = le32_to_cpu(fe->lengthExtendedAttr); | ||
1106 | UDF_I_LENALLOC(inode) = le32_to_cpu(fe->lengthAllocDescs); | ||
1107 | offset = sizeof(struct fileEntry) + UDF_I_LENEATTR(inode); | ||
1108 | } | ||
1109 | else | ||
1110 | { | ||
1111 | inode->i_blocks = le64_to_cpu(efe->logicalBlocksRecorded) << | ||
1112 | (inode->i_sb->s_blocksize_bits - 9); | ||
1113 | |||
1114 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1115 | lets_to_cpu(efe->accessTime)) ) | ||
1116 | { | ||
1117 | inode->i_atime.tv_sec = convtime; | ||
1118 | inode->i_atime.tv_nsec = convtime_usec * 1000; | ||
1119 | } | ||
1120 | else | ||
1121 | { | ||
1122 | inode->i_atime = UDF_SB_RECORDTIME(inode->i_sb); | ||
1123 | } | ||
1124 | |||
1125 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1126 | lets_to_cpu(efe->modificationTime)) ) | ||
1127 | { | ||
1128 | inode->i_mtime.tv_sec = convtime; | ||
1129 | inode->i_mtime.tv_nsec = convtime_usec * 1000; | ||
1130 | } | ||
1131 | else | ||
1132 | { | ||
1133 | inode->i_mtime = UDF_SB_RECORDTIME(inode->i_sb); | ||
1134 | } | ||
1135 | |||
1136 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1137 | lets_to_cpu(efe->createTime)) ) | ||
1138 | { | ||
1139 | UDF_I_CRTIME(inode).tv_sec = convtime; | ||
1140 | UDF_I_CRTIME(inode).tv_nsec = convtime_usec * 1000; | ||
1141 | } | ||
1142 | else | ||
1143 | { | ||
1144 | UDF_I_CRTIME(inode) = UDF_SB_RECORDTIME(inode->i_sb); | ||
1145 | } | ||
1146 | |||
1147 | if ( udf_stamp_to_time(&convtime, &convtime_usec, | ||
1148 | lets_to_cpu(efe->attrTime)) ) | ||
1149 | { | ||
1150 | inode->i_ctime.tv_sec = convtime; | ||
1151 | inode->i_ctime.tv_nsec = convtime_usec * 1000; | ||
1152 | } | ||
1153 | else | ||
1154 | { | ||
1155 | inode->i_ctime = UDF_SB_RECORDTIME(inode->i_sb); | ||
1156 | } | ||
1157 | |||
1158 | UDF_I_UNIQUE(inode) = le64_to_cpu(efe->uniqueID); | ||
1159 | UDF_I_LENEATTR(inode) = le32_to_cpu(efe->lengthExtendedAttr); | ||
1160 | UDF_I_LENALLOC(inode) = le32_to_cpu(efe->lengthAllocDescs); | ||
1161 | offset = sizeof(struct extendedFileEntry) + UDF_I_LENEATTR(inode); | ||
1162 | } | ||
1163 | |||
1164 | switch (fe->icbTag.fileType) | ||
1165 | { | ||
1166 | case ICBTAG_FILE_TYPE_DIRECTORY: | ||
1167 | { | ||
1168 | inode->i_op = &udf_dir_inode_operations; | ||
1169 | inode->i_fop = &udf_dir_operations; | ||
1170 | inode->i_mode |= S_IFDIR; | ||
1171 | inode->i_nlink ++; | ||
1172 | break; | ||
1173 | } | ||
1174 | case ICBTAG_FILE_TYPE_REALTIME: | ||
1175 | case ICBTAG_FILE_TYPE_REGULAR: | ||
1176 | case ICBTAG_FILE_TYPE_UNDEF: | ||
1177 | { | ||
1178 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
1179 | inode->i_data.a_ops = &udf_adinicb_aops; | ||
1180 | else | ||
1181 | inode->i_data.a_ops = &udf_aops; | ||
1182 | inode->i_op = &udf_file_inode_operations; | ||
1183 | inode->i_fop = &udf_file_operations; | ||
1184 | inode->i_mode |= S_IFREG; | ||
1185 | break; | ||
1186 | } | ||
1187 | case ICBTAG_FILE_TYPE_BLOCK: | ||
1188 | { | ||
1189 | inode->i_mode |= S_IFBLK; | ||
1190 | break; | ||
1191 | } | ||
1192 | case ICBTAG_FILE_TYPE_CHAR: | ||
1193 | { | ||
1194 | inode->i_mode |= S_IFCHR; | ||
1195 | break; | ||
1196 | } | ||
1197 | case ICBTAG_FILE_TYPE_FIFO: | ||
1198 | { | ||
1199 | init_special_inode(inode, inode->i_mode | S_IFIFO, 0); | ||
1200 | break; | ||
1201 | } | ||
1202 | case ICBTAG_FILE_TYPE_SOCKET: | ||
1203 | { | ||
1204 | init_special_inode(inode, inode->i_mode | S_IFSOCK, 0); | ||
1205 | break; | ||
1206 | } | ||
1207 | case ICBTAG_FILE_TYPE_SYMLINK: | ||
1208 | { | ||
1209 | inode->i_data.a_ops = &udf_symlink_aops; | ||
1210 | inode->i_op = &page_symlink_inode_operations; | ||
1211 | inode->i_mode = S_IFLNK|S_IRWXUGO; | ||
1212 | break; | ||
1213 | } | ||
1214 | default: | ||
1215 | { | ||
1216 | printk(KERN_ERR "udf: udf_fill_inode(ino %ld) failed unknown file type=%d\n", | ||
1217 | inode->i_ino, fe->icbTag.fileType); | ||
1218 | make_bad_inode(inode); | ||
1219 | return; | ||
1220 | } | ||
1221 | } | ||
1222 | if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) | ||
1223 | { | ||
1224 | struct deviceSpec *dsea = | ||
1225 | (struct deviceSpec *) | ||
1226 | udf_get_extendedattr(inode, 12, 1); | ||
1227 | |||
1228 | if (dsea) | ||
1229 | { | ||
1230 | init_special_inode(inode, inode->i_mode, MKDEV( | ||
1231 | le32_to_cpu(dsea->majorDeviceIdent), | ||
1232 | le32_to_cpu(dsea->minorDeviceIdent))); | ||
1233 | /* Developer ID ??? */ | ||
1234 | } | ||
1235 | else | ||
1236 | { | ||
1237 | make_bad_inode(inode); | ||
1238 | } | ||
1239 | } | ||
1240 | } | ||
1241 | |||
1242 | static mode_t | ||
1243 | udf_convert_permissions(struct fileEntry *fe) | ||
1244 | { | ||
1245 | mode_t mode; | ||
1246 | uint32_t permissions; | ||
1247 | uint32_t flags; | ||
1248 | |||
1249 | permissions = le32_to_cpu(fe->permissions); | ||
1250 | flags = le16_to_cpu(fe->icbTag.flags); | ||
1251 | |||
1252 | mode = (( permissions ) & S_IRWXO) | | ||
1253 | (( permissions >> 2 ) & S_IRWXG) | | ||
1254 | (( permissions >> 4 ) & S_IRWXU) | | ||
1255 | (( flags & ICBTAG_FLAG_SETUID) ? S_ISUID : 0) | | ||
1256 | (( flags & ICBTAG_FLAG_SETGID) ? S_ISGID : 0) | | ||
1257 | (( flags & ICBTAG_FLAG_STICKY) ? S_ISVTX : 0); | ||
1258 | |||
1259 | return mode; | ||
1260 | } | ||
1261 | |||
1262 | /* | ||
1263 | * udf_write_inode | ||
1264 | * | ||
1265 | * PURPOSE | ||
1266 | * Write out the specified inode. | ||
1267 | * | ||
1268 | * DESCRIPTION | ||
1269 | * This routine is called whenever an inode is synced. | ||
1270 | * Currently this routine is just a placeholder. | ||
1271 | * | ||
1272 | * HISTORY | ||
1273 | * July 1, 1997 - Andrew E. Mileski | ||
1274 | * Written, tested, and released. | ||
1275 | */ | ||
1276 | |||
1277 | int udf_write_inode(struct inode * inode, int sync) | ||
1278 | { | ||
1279 | int ret; | ||
1280 | lock_kernel(); | ||
1281 | ret = udf_update_inode(inode, sync); | ||
1282 | unlock_kernel(); | ||
1283 | return ret; | ||
1284 | } | ||
1285 | |||
1286 | int udf_sync_inode(struct inode * inode) | ||
1287 | { | ||
1288 | return udf_update_inode(inode, 1); | ||
1289 | } | ||
1290 | |||
1291 | static int | ||
1292 | udf_update_inode(struct inode *inode, int do_sync) | ||
1293 | { | ||
1294 | struct buffer_head *bh = NULL; | ||
1295 | struct fileEntry *fe; | ||
1296 | struct extendedFileEntry *efe; | ||
1297 | uint32_t udfperms; | ||
1298 | uint16_t icbflags; | ||
1299 | uint16_t crclen; | ||
1300 | int i; | ||
1301 | kernel_timestamp cpu_time; | ||
1302 | int err = 0; | ||
1303 | |||
1304 | bh = udf_tread(inode->i_sb, | ||
1305 | udf_get_lb_pblock(inode->i_sb, UDF_I_LOCATION(inode), 0)); | ||
1306 | |||
1307 | if (!bh) | ||
1308 | { | ||
1309 | udf_debug("bread failure\n"); | ||
1310 | return -EIO; | ||
1311 | } | ||
1312 | |||
1313 | memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
1314 | |||
1315 | fe = (struct fileEntry *)bh->b_data; | ||
1316 | efe = (struct extendedFileEntry *)bh->b_data; | ||
1317 | |||
1318 | if (le16_to_cpu(fe->descTag.tagIdent) == TAG_IDENT_USE) | ||
1319 | { | ||
1320 | struct unallocSpaceEntry *use = | ||
1321 | (struct unallocSpaceEntry *)bh->b_data; | ||
1322 | |||
1323 | use->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode)); | ||
1324 | memcpy(bh->b_data + sizeof(struct unallocSpaceEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct unallocSpaceEntry)); | ||
1325 | crclen = sizeof(struct unallocSpaceEntry) + UDF_I_LENALLOC(inode) - | ||
1326 | sizeof(tag); | ||
1327 | use->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); | ||
1328 | use->descTag.descCRCLength = cpu_to_le16(crclen); | ||
1329 | use->descTag.descCRC = cpu_to_le16(udf_crc((char *)use + sizeof(tag), crclen, 0)); | ||
1330 | |||
1331 | use->descTag.tagChecksum = 0; | ||
1332 | for (i=0; i<16; i++) | ||
1333 | if (i != 4) | ||
1334 | use->descTag.tagChecksum += ((uint8_t *)&(use->descTag))[i]; | ||
1335 | |||
1336 | mark_buffer_dirty(bh); | ||
1337 | udf_release_data(bh); | ||
1338 | return err; | ||
1339 | } | ||
1340 | |||
1341 | if (inode->i_uid != UDF_SB(inode->i_sb)->s_uid) | ||
1342 | fe->uid = cpu_to_le32(inode->i_uid); | ||
1343 | |||
1344 | if (inode->i_gid != UDF_SB(inode->i_sb)->s_gid) | ||
1345 | fe->gid = cpu_to_le32(inode->i_gid); | ||
1346 | |||
1347 | udfperms = ((inode->i_mode & S_IRWXO) ) | | ||
1348 | ((inode->i_mode & S_IRWXG) << 2) | | ||
1349 | ((inode->i_mode & S_IRWXU) << 4); | ||
1350 | |||
1351 | udfperms |= (le32_to_cpu(fe->permissions) & | ||
1352 | (FE_PERM_O_DELETE | FE_PERM_O_CHATTR | | ||
1353 | FE_PERM_G_DELETE | FE_PERM_G_CHATTR | | ||
1354 | FE_PERM_U_DELETE | FE_PERM_U_CHATTR)); | ||
1355 | fe->permissions = cpu_to_le32(udfperms); | ||
1356 | |||
1357 | if (S_ISDIR(inode->i_mode)) | ||
1358 | fe->fileLinkCount = cpu_to_le16(inode->i_nlink - 1); | ||
1359 | else | ||
1360 | fe->fileLinkCount = cpu_to_le16(inode->i_nlink); | ||
1361 | |||
1362 | fe->informationLength = cpu_to_le64(inode->i_size); | ||
1363 | |||
1364 | if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) | ||
1365 | { | ||
1366 | regid *eid; | ||
1367 | struct deviceSpec *dsea = | ||
1368 | (struct deviceSpec *) | ||
1369 | udf_get_extendedattr(inode, 12, 1); | ||
1370 | |||
1371 | if (!dsea) | ||
1372 | { | ||
1373 | dsea = (struct deviceSpec *) | ||
1374 | udf_add_extendedattr(inode, | ||
1375 | sizeof(struct deviceSpec) + | ||
1376 | sizeof(regid), 12, 0x3); | ||
1377 | dsea->attrType = cpu_to_le32(12); | ||
1378 | dsea->attrSubtype = 1; | ||
1379 | dsea->attrLength = cpu_to_le32(sizeof(struct deviceSpec) + | ||
1380 | sizeof(regid)); | ||
1381 | dsea->impUseLength = cpu_to_le32(sizeof(regid)); | ||
1382 | } | ||
1383 | eid = (regid *)dsea->impUse; | ||
1384 | memset(eid, 0, sizeof(regid)); | ||
1385 | strcpy(eid->ident, UDF_ID_DEVELOPER); | ||
1386 | eid->identSuffix[0] = UDF_OS_CLASS_UNIX; | ||
1387 | eid->identSuffix[1] = UDF_OS_ID_LINUX; | ||
1388 | dsea->majorDeviceIdent = cpu_to_le32(imajor(inode)); | ||
1389 | dsea->minorDeviceIdent = cpu_to_le32(iminor(inode)); | ||
1390 | } | ||
1391 | |||
1392 | if (UDF_I_EFE(inode) == 0) | ||
1393 | { | ||
1394 | memcpy(bh->b_data + sizeof(struct fileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct fileEntry)); | ||
1395 | fe->logicalBlocksRecorded = cpu_to_le64( | ||
1396 | (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> | ||
1397 | (inode->i_sb->s_blocksize_bits - 9)); | ||
1398 | |||
1399 | if (udf_time_to_stamp(&cpu_time, inode->i_atime)) | ||
1400 | fe->accessTime = cpu_to_lets(cpu_time); | ||
1401 | if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) | ||
1402 | fe->modificationTime = cpu_to_lets(cpu_time); | ||
1403 | if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) | ||
1404 | fe->attrTime = cpu_to_lets(cpu_time); | ||
1405 | memset(&(fe->impIdent), 0, sizeof(regid)); | ||
1406 | strcpy(fe->impIdent.ident, UDF_ID_DEVELOPER); | ||
1407 | fe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | ||
1408 | fe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; | ||
1409 | fe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode)); | ||
1410 | fe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode)); | ||
1411 | fe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode)); | ||
1412 | fe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_FE); | ||
1413 | crclen = sizeof(struct fileEntry); | ||
1414 | } | ||
1415 | else | ||
1416 | { | ||
1417 | memcpy(bh->b_data + sizeof(struct extendedFileEntry), UDF_I_DATA(inode), inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry)); | ||
1418 | efe->objectSize = cpu_to_le64(inode->i_size); | ||
1419 | efe->logicalBlocksRecorded = cpu_to_le64( | ||
1420 | (inode->i_blocks + (1 << (inode->i_sb->s_blocksize_bits - 9)) - 1) >> | ||
1421 | (inode->i_sb->s_blocksize_bits - 9)); | ||
1422 | |||
1423 | if (UDF_I_CRTIME(inode).tv_sec > inode->i_atime.tv_sec || | ||
1424 | (UDF_I_CRTIME(inode).tv_sec == inode->i_atime.tv_sec && | ||
1425 | UDF_I_CRTIME(inode).tv_nsec > inode->i_atime.tv_nsec)) | ||
1426 | { | ||
1427 | UDF_I_CRTIME(inode) = inode->i_atime; | ||
1428 | } | ||
1429 | if (UDF_I_CRTIME(inode).tv_sec > inode->i_mtime.tv_sec || | ||
1430 | (UDF_I_CRTIME(inode).tv_sec == inode->i_mtime.tv_sec && | ||
1431 | UDF_I_CRTIME(inode).tv_nsec > inode->i_mtime.tv_nsec)) | ||
1432 | { | ||
1433 | UDF_I_CRTIME(inode) = inode->i_mtime; | ||
1434 | } | ||
1435 | if (UDF_I_CRTIME(inode).tv_sec > inode->i_ctime.tv_sec || | ||
1436 | (UDF_I_CRTIME(inode).tv_sec == inode->i_ctime.tv_sec && | ||
1437 | UDF_I_CRTIME(inode).tv_nsec > inode->i_ctime.tv_nsec)) | ||
1438 | { | ||
1439 | UDF_I_CRTIME(inode) = inode->i_ctime; | ||
1440 | } | ||
1441 | |||
1442 | if (udf_time_to_stamp(&cpu_time, inode->i_atime)) | ||
1443 | efe->accessTime = cpu_to_lets(cpu_time); | ||
1444 | if (udf_time_to_stamp(&cpu_time, inode->i_mtime)) | ||
1445 | efe->modificationTime = cpu_to_lets(cpu_time); | ||
1446 | if (udf_time_to_stamp(&cpu_time, UDF_I_CRTIME(inode))) | ||
1447 | efe->createTime = cpu_to_lets(cpu_time); | ||
1448 | if (udf_time_to_stamp(&cpu_time, inode->i_ctime)) | ||
1449 | efe->attrTime = cpu_to_lets(cpu_time); | ||
1450 | |||
1451 | memset(&(efe->impIdent), 0, sizeof(regid)); | ||
1452 | strcpy(efe->impIdent.ident, UDF_ID_DEVELOPER); | ||
1453 | efe->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | ||
1454 | efe->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; | ||
1455 | efe->uniqueID = cpu_to_le64(UDF_I_UNIQUE(inode)); | ||
1456 | efe->lengthExtendedAttr = cpu_to_le32(UDF_I_LENEATTR(inode)); | ||
1457 | efe->lengthAllocDescs = cpu_to_le32(UDF_I_LENALLOC(inode)); | ||
1458 | efe->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EFE); | ||
1459 | crclen = sizeof(struct extendedFileEntry); | ||
1460 | } | ||
1461 | if (UDF_I_STRAT4096(inode)) | ||
1462 | { | ||
1463 | fe->icbTag.strategyType = cpu_to_le16(4096); | ||
1464 | fe->icbTag.strategyParameter = cpu_to_le16(1); | ||
1465 | fe->icbTag.numEntries = cpu_to_le16(2); | ||
1466 | } | ||
1467 | else | ||
1468 | { | ||
1469 | fe->icbTag.strategyType = cpu_to_le16(4); | ||
1470 | fe->icbTag.numEntries = cpu_to_le16(1); | ||
1471 | } | ||
1472 | |||
1473 | if (S_ISDIR(inode->i_mode)) | ||
1474 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_DIRECTORY; | ||
1475 | else if (S_ISREG(inode->i_mode)) | ||
1476 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_REGULAR; | ||
1477 | else if (S_ISLNK(inode->i_mode)) | ||
1478 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_SYMLINK; | ||
1479 | else if (S_ISBLK(inode->i_mode)) | ||
1480 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_BLOCK; | ||
1481 | else if (S_ISCHR(inode->i_mode)) | ||
1482 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_CHAR; | ||
1483 | else if (S_ISFIFO(inode->i_mode)) | ||
1484 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_FIFO; | ||
1485 | else if (S_ISSOCK(inode->i_mode)) | ||
1486 | fe->icbTag.fileType = ICBTAG_FILE_TYPE_SOCKET; | ||
1487 | |||
1488 | icbflags = UDF_I_ALLOCTYPE(inode) | | ||
1489 | ((inode->i_mode & S_ISUID) ? ICBTAG_FLAG_SETUID : 0) | | ||
1490 | ((inode->i_mode & S_ISGID) ? ICBTAG_FLAG_SETGID : 0) | | ||
1491 | ((inode->i_mode & S_ISVTX) ? ICBTAG_FLAG_STICKY : 0) | | ||
1492 | (le16_to_cpu(fe->icbTag.flags) & | ||
1493 | ~(ICBTAG_FLAG_AD_MASK | ICBTAG_FLAG_SETUID | | ||
1494 | ICBTAG_FLAG_SETGID | ICBTAG_FLAG_STICKY)); | ||
1495 | |||
1496 | fe->icbTag.flags = cpu_to_le16(icbflags); | ||
1497 | if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) | ||
1498 | fe->descTag.descVersion = cpu_to_le16(3); | ||
1499 | else | ||
1500 | fe->descTag.descVersion = cpu_to_le16(2); | ||
1501 | fe->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb)); | ||
1502 | fe->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); | ||
1503 | crclen += UDF_I_LENEATTR(inode) + UDF_I_LENALLOC(inode) - sizeof(tag); | ||
1504 | fe->descTag.descCRCLength = cpu_to_le16(crclen); | ||
1505 | fe->descTag.descCRC = cpu_to_le16(udf_crc((char *)fe + sizeof(tag), crclen, 0)); | ||
1506 | |||
1507 | fe->descTag.tagChecksum = 0; | ||
1508 | for (i=0; i<16; i++) | ||
1509 | if (i != 4) | ||
1510 | fe->descTag.tagChecksum += ((uint8_t *)&(fe->descTag))[i]; | ||
1511 | |||
1512 | /* write the data blocks */ | ||
1513 | mark_buffer_dirty(bh); | ||
1514 | if (do_sync) | ||
1515 | { | ||
1516 | sync_dirty_buffer(bh); | ||
1517 | if (buffer_req(bh) && !buffer_uptodate(bh)) | ||
1518 | { | ||
1519 | printk("IO error syncing udf inode [%s:%08lx]\n", | ||
1520 | inode->i_sb->s_id, inode->i_ino); | ||
1521 | err = -EIO; | ||
1522 | } | ||
1523 | } | ||
1524 | udf_release_data(bh); | ||
1525 | return err; | ||
1526 | } | ||
1527 | |||
1528 | struct inode * | ||
1529 | udf_iget(struct super_block *sb, kernel_lb_addr ino) | ||
1530 | { | ||
1531 | unsigned long block = udf_get_lb_pblock(sb, ino, 0); | ||
1532 | struct inode *inode = iget_locked(sb, block); | ||
1533 | |||
1534 | if (!inode) | ||
1535 | return NULL; | ||
1536 | |||
1537 | if (inode->i_state & I_NEW) { | ||
1538 | memcpy(&UDF_I_LOCATION(inode), &ino, sizeof(kernel_lb_addr)); | ||
1539 | __udf_read_inode(inode); | ||
1540 | unlock_new_inode(inode); | ||
1541 | } | ||
1542 | |||
1543 | if (is_bad_inode(inode)) | ||
1544 | goto out_iput; | ||
1545 | |||
1546 | if (ino.logicalBlockNum >= UDF_SB_PARTLEN(sb, ino.partitionReferenceNum)) { | ||
1547 | udf_debug("block=%d, partition=%d out of range\n", | ||
1548 | ino.logicalBlockNum, ino.partitionReferenceNum); | ||
1549 | make_bad_inode(inode); | ||
1550 | goto out_iput; | ||
1551 | } | ||
1552 | |||
1553 | return inode; | ||
1554 | |||
1555 | out_iput: | ||
1556 | iput(inode); | ||
1557 | return NULL; | ||
1558 | } | ||
1559 | |||
1560 | int8_t udf_add_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, | ||
1561 | kernel_lb_addr eloc, uint32_t elen, struct buffer_head **bh, int inc) | ||
1562 | { | ||
1563 | int adsize; | ||
1564 | short_ad *sad = NULL; | ||
1565 | long_ad *lad = NULL; | ||
1566 | struct allocExtDesc *aed; | ||
1567 | int8_t etype; | ||
1568 | uint8_t *ptr; | ||
1569 | |||
1570 | if (!*bh) | ||
1571 | ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); | ||
1572 | else | ||
1573 | ptr = (*bh)->b_data + *extoffset; | ||
1574 | |||
1575 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) | ||
1576 | adsize = sizeof(short_ad); | ||
1577 | else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) | ||
1578 | adsize = sizeof(long_ad); | ||
1579 | else | ||
1580 | return -1; | ||
1581 | |||
1582 | if (*extoffset + (2 * adsize) > inode->i_sb->s_blocksize) | ||
1583 | { | ||
1584 | char *sptr, *dptr; | ||
1585 | struct buffer_head *nbh; | ||
1586 | int err, loffset; | ||
1587 | kernel_lb_addr obloc = *bloc; | ||
1588 | |||
1589 | if (!(bloc->logicalBlockNum = udf_new_block(inode->i_sb, NULL, | ||
1590 | obloc.partitionReferenceNum, obloc.logicalBlockNum, &err))) | ||
1591 | { | ||
1592 | return -1; | ||
1593 | } | ||
1594 | if (!(nbh = udf_tgetblk(inode->i_sb, udf_get_lb_pblock(inode->i_sb, | ||
1595 | *bloc, 0)))) | ||
1596 | { | ||
1597 | return -1; | ||
1598 | } | ||
1599 | lock_buffer(nbh); | ||
1600 | memset(nbh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
1601 | set_buffer_uptodate(nbh); | ||
1602 | unlock_buffer(nbh); | ||
1603 | mark_buffer_dirty_inode(nbh, inode); | ||
1604 | |||
1605 | aed = (struct allocExtDesc *)(nbh->b_data); | ||
1606 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) | ||
1607 | aed->previousAllocExtLocation = cpu_to_le32(obloc.logicalBlockNum); | ||
1608 | if (*extoffset + adsize > inode->i_sb->s_blocksize) | ||
1609 | { | ||
1610 | loffset = *extoffset; | ||
1611 | aed->lengthAllocDescs = cpu_to_le32(adsize); | ||
1612 | sptr = ptr - adsize; | ||
1613 | dptr = nbh->b_data + sizeof(struct allocExtDesc); | ||
1614 | memcpy(dptr, sptr, adsize); | ||
1615 | *extoffset = sizeof(struct allocExtDesc) + adsize; | ||
1616 | } | ||
1617 | else | ||
1618 | { | ||
1619 | loffset = *extoffset + adsize; | ||
1620 | aed->lengthAllocDescs = cpu_to_le32(0); | ||
1621 | sptr = ptr; | ||
1622 | *extoffset = sizeof(struct allocExtDesc); | ||
1623 | |||
1624 | if (*bh) | ||
1625 | { | ||
1626 | aed = (struct allocExtDesc *)(*bh)->b_data; | ||
1627 | aed->lengthAllocDescs = | ||
1628 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); | ||
1629 | } | ||
1630 | else | ||
1631 | { | ||
1632 | UDF_I_LENALLOC(inode) += adsize; | ||
1633 | mark_inode_dirty(inode); | ||
1634 | } | ||
1635 | } | ||
1636 | if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) | ||
1637 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 3, 1, | ||
1638 | bloc->logicalBlockNum, sizeof(tag)); | ||
1639 | else | ||
1640 | udf_new_tag(nbh->b_data, TAG_IDENT_AED, 2, 1, | ||
1641 | bloc->logicalBlockNum, sizeof(tag)); | ||
1642 | switch (UDF_I_ALLOCTYPE(inode)) | ||
1643 | { | ||
1644 | case ICBTAG_FLAG_AD_SHORT: | ||
1645 | { | ||
1646 | sad = (short_ad *)sptr; | ||
1647 | sad->extLength = cpu_to_le32( | ||
1648 | EXT_NEXT_EXTENT_ALLOCDECS | | ||
1649 | inode->i_sb->s_blocksize); | ||
1650 | sad->extPosition = cpu_to_le32(bloc->logicalBlockNum); | ||
1651 | break; | ||
1652 | } | ||
1653 | case ICBTAG_FLAG_AD_LONG: | ||
1654 | { | ||
1655 | lad = (long_ad *)sptr; | ||
1656 | lad->extLength = cpu_to_le32( | ||
1657 | EXT_NEXT_EXTENT_ALLOCDECS | | ||
1658 | inode->i_sb->s_blocksize); | ||
1659 | lad->extLocation = cpu_to_lelb(*bloc); | ||
1660 | memset(lad->impUse, 0x00, sizeof(lad->impUse)); | ||
1661 | break; | ||
1662 | } | ||
1663 | } | ||
1664 | if (*bh) | ||
1665 | { | ||
1666 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
1667 | udf_update_tag((*bh)->b_data, loffset); | ||
1668 | else | ||
1669 | udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); | ||
1670 | mark_buffer_dirty_inode(*bh, inode); | ||
1671 | udf_release_data(*bh); | ||
1672 | } | ||
1673 | else | ||
1674 | mark_inode_dirty(inode); | ||
1675 | *bh = nbh; | ||
1676 | } | ||
1677 | |||
1678 | etype = udf_write_aext(inode, *bloc, extoffset, eloc, elen, *bh, inc); | ||
1679 | |||
1680 | if (!*bh) | ||
1681 | { | ||
1682 | UDF_I_LENALLOC(inode) += adsize; | ||
1683 | mark_inode_dirty(inode); | ||
1684 | } | ||
1685 | else | ||
1686 | { | ||
1687 | aed = (struct allocExtDesc *)(*bh)->b_data; | ||
1688 | aed->lengthAllocDescs = | ||
1689 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) + adsize); | ||
1690 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
1691 | udf_update_tag((*bh)->b_data, *extoffset + (inc ? 0 : adsize)); | ||
1692 | else | ||
1693 | udf_update_tag((*bh)->b_data, sizeof(struct allocExtDesc)); | ||
1694 | mark_buffer_dirty_inode(*bh, inode); | ||
1695 | } | ||
1696 | |||
1697 | return etype; | ||
1698 | } | ||
1699 | |||
1700 | int8_t udf_write_aext(struct inode *inode, kernel_lb_addr bloc, int *extoffset, | ||
1701 | kernel_lb_addr eloc, uint32_t elen, struct buffer_head *bh, int inc) | ||
1702 | { | ||
1703 | int adsize; | ||
1704 | uint8_t *ptr; | ||
1705 | |||
1706 | if (!bh) | ||
1707 | ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); | ||
1708 | else | ||
1709 | { | ||
1710 | ptr = bh->b_data + *extoffset; | ||
1711 | atomic_inc(&bh->b_count); | ||
1712 | } | ||
1713 | |||
1714 | switch (UDF_I_ALLOCTYPE(inode)) | ||
1715 | { | ||
1716 | case ICBTAG_FLAG_AD_SHORT: | ||
1717 | { | ||
1718 | short_ad *sad = (short_ad *)ptr; | ||
1719 | sad->extLength = cpu_to_le32(elen); | ||
1720 | sad->extPosition = cpu_to_le32(eloc.logicalBlockNum); | ||
1721 | adsize = sizeof(short_ad); | ||
1722 | break; | ||
1723 | } | ||
1724 | case ICBTAG_FLAG_AD_LONG: | ||
1725 | { | ||
1726 | long_ad *lad = (long_ad *)ptr; | ||
1727 | lad->extLength = cpu_to_le32(elen); | ||
1728 | lad->extLocation = cpu_to_lelb(eloc); | ||
1729 | memset(lad->impUse, 0x00, sizeof(lad->impUse)); | ||
1730 | adsize = sizeof(long_ad); | ||
1731 | break; | ||
1732 | } | ||
1733 | default: | ||
1734 | return -1; | ||
1735 | } | ||
1736 | |||
1737 | if (bh) | ||
1738 | { | ||
1739 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
1740 | { | ||
1741 | struct allocExtDesc *aed = (struct allocExtDesc *)(bh)->b_data; | ||
1742 | udf_update_tag((bh)->b_data, | ||
1743 | le32_to_cpu(aed->lengthAllocDescs) + sizeof(struct allocExtDesc)); | ||
1744 | } | ||
1745 | mark_buffer_dirty_inode(bh, inode); | ||
1746 | udf_release_data(bh); | ||
1747 | } | ||
1748 | else | ||
1749 | mark_inode_dirty(inode); | ||
1750 | |||
1751 | if (inc) | ||
1752 | *extoffset += adsize; | ||
1753 | return (elen >> 30); | ||
1754 | } | ||
1755 | |||
1756 | int8_t udf_next_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, | ||
1757 | kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) | ||
1758 | { | ||
1759 | int8_t etype; | ||
1760 | |||
1761 | while ((etype = udf_current_aext(inode, bloc, extoffset, eloc, elen, bh, inc)) == | ||
1762 | (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) | ||
1763 | { | ||
1764 | *bloc = *eloc; | ||
1765 | *extoffset = sizeof(struct allocExtDesc); | ||
1766 | udf_release_data(*bh); | ||
1767 | if (!(*bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, *bloc, 0)))) | ||
1768 | { | ||
1769 | udf_debug("reading block %d failed!\n", | ||
1770 | udf_get_lb_pblock(inode->i_sb, *bloc, 0)); | ||
1771 | return -1; | ||
1772 | } | ||
1773 | } | ||
1774 | |||
1775 | return etype; | ||
1776 | } | ||
1777 | |||
1778 | int8_t udf_current_aext(struct inode *inode, kernel_lb_addr *bloc, int *extoffset, | ||
1779 | kernel_lb_addr *eloc, uint32_t *elen, struct buffer_head **bh, int inc) | ||
1780 | { | ||
1781 | int alen; | ||
1782 | int8_t etype; | ||
1783 | uint8_t *ptr; | ||
1784 | |||
1785 | if (!*bh) | ||
1786 | { | ||
1787 | if (!(*extoffset)) | ||
1788 | *extoffset = udf_file_entry_alloc_offset(inode); | ||
1789 | ptr = UDF_I_DATA(inode) + *extoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode); | ||
1790 | alen = udf_file_entry_alloc_offset(inode) + UDF_I_LENALLOC(inode); | ||
1791 | } | ||
1792 | else | ||
1793 | { | ||
1794 | if (!(*extoffset)) | ||
1795 | *extoffset = sizeof(struct allocExtDesc); | ||
1796 | ptr = (*bh)->b_data + *extoffset; | ||
1797 | alen = sizeof(struct allocExtDesc) + le32_to_cpu(((struct allocExtDesc *)(*bh)->b_data)->lengthAllocDescs); | ||
1798 | } | ||
1799 | |||
1800 | switch (UDF_I_ALLOCTYPE(inode)) | ||
1801 | { | ||
1802 | case ICBTAG_FLAG_AD_SHORT: | ||
1803 | { | ||
1804 | short_ad *sad; | ||
1805 | |||
1806 | if (!(sad = udf_get_fileshortad(ptr, alen, extoffset, inc))) | ||
1807 | return -1; | ||
1808 | |||
1809 | etype = le32_to_cpu(sad->extLength) >> 30; | ||
1810 | eloc->logicalBlockNum = le32_to_cpu(sad->extPosition); | ||
1811 | eloc->partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; | ||
1812 | *elen = le32_to_cpu(sad->extLength) & UDF_EXTENT_LENGTH_MASK; | ||
1813 | break; | ||
1814 | } | ||
1815 | case ICBTAG_FLAG_AD_LONG: | ||
1816 | { | ||
1817 | long_ad *lad; | ||
1818 | |||
1819 | if (!(lad = udf_get_filelongad(ptr, alen, extoffset, inc))) | ||
1820 | return -1; | ||
1821 | |||
1822 | etype = le32_to_cpu(lad->extLength) >> 30; | ||
1823 | *eloc = lelb_to_cpu(lad->extLocation); | ||
1824 | *elen = le32_to_cpu(lad->extLength) & UDF_EXTENT_LENGTH_MASK; | ||
1825 | break; | ||
1826 | } | ||
1827 | default: | ||
1828 | { | ||
1829 | udf_debug("alloc_type = %d unsupported\n", UDF_I_ALLOCTYPE(inode)); | ||
1830 | return -1; | ||
1831 | } | ||
1832 | } | ||
1833 | |||
1834 | return etype; | ||
1835 | } | ||
1836 | |||
1837 | static int8_t | ||
1838 | udf_insert_aext(struct inode *inode, kernel_lb_addr bloc, int extoffset, | ||
1839 | kernel_lb_addr neloc, uint32_t nelen, struct buffer_head *bh) | ||
1840 | { | ||
1841 | kernel_lb_addr oeloc; | ||
1842 | uint32_t oelen; | ||
1843 | int8_t etype; | ||
1844 | |||
1845 | if (bh) | ||
1846 | atomic_inc(&bh->b_count); | ||
1847 | |||
1848 | while ((etype = udf_next_aext(inode, &bloc, &extoffset, &oeloc, &oelen, &bh, 0)) != -1) | ||
1849 | { | ||
1850 | udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); | ||
1851 | |||
1852 | neloc = oeloc; | ||
1853 | nelen = (etype << 30) | oelen; | ||
1854 | } | ||
1855 | udf_add_aext(inode, &bloc, &extoffset, neloc, nelen, &bh, 1); | ||
1856 | udf_release_data(bh); | ||
1857 | return (nelen >> 30); | ||
1858 | } | ||
1859 | |||
1860 | int8_t udf_delete_aext(struct inode *inode, kernel_lb_addr nbloc, int nextoffset, | ||
1861 | kernel_lb_addr eloc, uint32_t elen, struct buffer_head *nbh) | ||
1862 | { | ||
1863 | struct buffer_head *obh; | ||
1864 | kernel_lb_addr obloc; | ||
1865 | int oextoffset, adsize; | ||
1866 | int8_t etype; | ||
1867 | struct allocExtDesc *aed; | ||
1868 | |||
1869 | if (nbh) | ||
1870 | { | ||
1871 | atomic_inc(&nbh->b_count); | ||
1872 | atomic_inc(&nbh->b_count); | ||
1873 | } | ||
1874 | |||
1875 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) | ||
1876 | adsize = sizeof(short_ad); | ||
1877 | else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) | ||
1878 | adsize = sizeof(long_ad); | ||
1879 | else | ||
1880 | adsize = 0; | ||
1881 | |||
1882 | obh = nbh; | ||
1883 | obloc = nbloc; | ||
1884 | oextoffset = nextoffset; | ||
1885 | |||
1886 | if (udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1) == -1) | ||
1887 | return -1; | ||
1888 | |||
1889 | while ((etype = udf_next_aext(inode, &nbloc, &nextoffset, &eloc, &elen, &nbh, 1)) != -1) | ||
1890 | { | ||
1891 | udf_write_aext(inode, obloc, &oextoffset, eloc, (etype << 30) | elen, obh, 1); | ||
1892 | if (obh != nbh) | ||
1893 | { | ||
1894 | obloc = nbloc; | ||
1895 | udf_release_data(obh); | ||
1896 | atomic_inc(&nbh->b_count); | ||
1897 | obh = nbh; | ||
1898 | oextoffset = nextoffset - adsize; | ||
1899 | } | ||
1900 | } | ||
1901 | memset(&eloc, 0x00, sizeof(kernel_lb_addr)); | ||
1902 | elen = 0; | ||
1903 | |||
1904 | if (nbh != obh) | ||
1905 | { | ||
1906 | udf_free_blocks(inode->i_sb, inode, nbloc, 0, 1); | ||
1907 | udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); | ||
1908 | udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); | ||
1909 | if (!obh) | ||
1910 | { | ||
1911 | UDF_I_LENALLOC(inode) -= (adsize * 2); | ||
1912 | mark_inode_dirty(inode); | ||
1913 | } | ||
1914 | else | ||
1915 | { | ||
1916 | aed = (struct allocExtDesc *)(obh)->b_data; | ||
1917 | aed->lengthAllocDescs = | ||
1918 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - (2*adsize)); | ||
1919 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
1920 | udf_update_tag((obh)->b_data, oextoffset - (2*adsize)); | ||
1921 | else | ||
1922 | udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); | ||
1923 | mark_buffer_dirty_inode(obh, inode); | ||
1924 | } | ||
1925 | } | ||
1926 | else | ||
1927 | { | ||
1928 | udf_write_aext(inode, obloc, &oextoffset, eloc, elen, obh, 1); | ||
1929 | if (!obh) | ||
1930 | { | ||
1931 | UDF_I_LENALLOC(inode) -= adsize; | ||
1932 | mark_inode_dirty(inode); | ||
1933 | } | ||
1934 | else | ||
1935 | { | ||
1936 | aed = (struct allocExtDesc *)(obh)->b_data; | ||
1937 | aed->lengthAllocDescs = | ||
1938 | cpu_to_le32(le32_to_cpu(aed->lengthAllocDescs) - adsize); | ||
1939 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
1940 | udf_update_tag((obh)->b_data, oextoffset - adsize); | ||
1941 | else | ||
1942 | udf_update_tag((obh)->b_data, sizeof(struct allocExtDesc)); | ||
1943 | mark_buffer_dirty_inode(obh, inode); | ||
1944 | } | ||
1945 | } | ||
1946 | |||
1947 | udf_release_data(nbh); | ||
1948 | udf_release_data(obh); | ||
1949 | return (elen >> 30); | ||
1950 | } | ||
1951 | |||
1952 | int8_t inode_bmap(struct inode *inode, int block, kernel_lb_addr *bloc, uint32_t *extoffset, | ||
1953 | kernel_lb_addr *eloc, uint32_t *elen, uint32_t *offset, struct buffer_head **bh) | ||
1954 | { | ||
1955 | uint64_t lbcount = 0, bcount = (uint64_t)block << inode->i_sb->s_blocksize_bits; | ||
1956 | int8_t etype; | ||
1957 | |||
1958 | if (block < 0) | ||
1959 | { | ||
1960 | printk(KERN_ERR "udf: inode_bmap: block < 0\n"); | ||
1961 | return -1; | ||
1962 | } | ||
1963 | if (!inode) | ||
1964 | { | ||
1965 | printk(KERN_ERR "udf: inode_bmap: NULL inode\n"); | ||
1966 | return -1; | ||
1967 | } | ||
1968 | |||
1969 | *extoffset = 0; | ||
1970 | *elen = 0; | ||
1971 | *bloc = UDF_I_LOCATION(inode); | ||
1972 | |||
1973 | do | ||
1974 | { | ||
1975 | if ((etype = udf_next_aext(inode, bloc, extoffset, eloc, elen, bh, 1)) == -1) | ||
1976 | { | ||
1977 | *offset = bcount - lbcount; | ||
1978 | UDF_I_LENEXTENTS(inode) = lbcount; | ||
1979 | return -1; | ||
1980 | } | ||
1981 | lbcount += *elen; | ||
1982 | } while (lbcount <= bcount); | ||
1983 | |||
1984 | *offset = bcount + *elen - lbcount; | ||
1985 | |||
1986 | return etype; | ||
1987 | } | ||
1988 | |||
1989 | long udf_block_map(struct inode *inode, long block) | ||
1990 | { | ||
1991 | kernel_lb_addr eloc, bloc; | ||
1992 | uint32_t offset, extoffset, elen; | ||
1993 | struct buffer_head *bh = NULL; | ||
1994 | int ret; | ||
1995 | |||
1996 | lock_kernel(); | ||
1997 | |||
1998 | if (inode_bmap(inode, block, &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) | ||
1999 | ret = udf_get_lb_pblock(inode->i_sb, eloc, offset >> inode->i_sb->s_blocksize_bits); | ||
2000 | else | ||
2001 | ret = 0; | ||
2002 | |||
2003 | unlock_kernel(); | ||
2004 | udf_release_data(bh); | ||
2005 | |||
2006 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_VARCONV)) | ||
2007 | return udf_fixed_to_variable(ret); | ||
2008 | else | ||
2009 | return ret; | ||
2010 | } | ||
diff --git a/fs/udf/lowlevel.c b/fs/udf/lowlevel.c new file mode 100644 index 000000000000..2da5087dfe05 --- /dev/null +++ b/fs/udf/lowlevel.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * lowlevel.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Low Level Device Routines for the UDF filesystem | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1999-2001 Ben Fennema | ||
19 | * | ||
20 | * HISTORY | ||
21 | * | ||
22 | * 03/26/99 blf Created. | ||
23 | */ | ||
24 | |||
25 | #include "udfdecl.h" | ||
26 | |||
27 | #include <linux/blkdev.h> | ||
28 | #include <linux/cdrom.h> | ||
29 | #include <asm/uaccess.h> | ||
30 | |||
31 | #include <linux/udf_fs.h> | ||
32 | #include "udf_sb.h" | ||
33 | |||
34 | unsigned int | ||
35 | udf_get_last_session(struct super_block *sb) | ||
36 | { | ||
37 | struct cdrom_multisession ms_info; | ||
38 | unsigned int vol_desc_start; | ||
39 | struct block_device *bdev = sb->s_bdev; | ||
40 | int i; | ||
41 | |||
42 | vol_desc_start=0; | ||
43 | ms_info.addr_format=CDROM_LBA; | ||
44 | i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); | ||
45 | |||
46 | #define WE_OBEY_THE_WRITTEN_STANDARDS 1 | ||
47 | |||
48 | if (i == 0) | ||
49 | { | ||
50 | udf_debug("XA disk: %s, vol_desc_start=%d\n", | ||
51 | (ms_info.xa_flag ? "yes" : "no"), ms_info.addr.lba); | ||
52 | #if WE_OBEY_THE_WRITTEN_STANDARDS | ||
53 | if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ | ||
54 | #endif | ||
55 | vol_desc_start = ms_info.addr.lba; | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | udf_debug("CDROMMULTISESSION not supported: rc=%d\n", i); | ||
60 | } | ||
61 | return vol_desc_start; | ||
62 | } | ||
63 | |||
64 | unsigned long | ||
65 | udf_get_last_block(struct super_block *sb) | ||
66 | { | ||
67 | struct block_device *bdev = sb->s_bdev; | ||
68 | unsigned long lblock = 0; | ||
69 | |||
70 | if (ioctl_by_bdev(bdev, CDROM_LAST_WRITTEN, (unsigned long) &lblock)) | ||
71 | lblock = bdev->bd_inode->i_size >> sb->s_blocksize_bits; | ||
72 | |||
73 | if (lblock) | ||
74 | return lblock - 1; | ||
75 | else | ||
76 | return 0; | ||
77 | } | ||
diff --git a/fs/udf/misc.c b/fs/udf/misc.c new file mode 100644 index 000000000000..fd321f9ace83 --- /dev/null +++ b/fs/udf/misc.c | |||
@@ -0,0 +1,313 @@ | |||
1 | /* | ||
2 | * misc.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Miscellaneous routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998 Dave Boynton | ||
19 | * (C) 1998-2004 Ben Fennema | ||
20 | * (C) 1999-2000 Stelias Computing Inc | ||
21 | * | ||
22 | * HISTORY | ||
23 | * | ||
24 | * 04/19/99 blf partial support for reading/writing specific EA's | ||
25 | */ | ||
26 | |||
27 | #include "udfdecl.h" | ||
28 | |||
29 | #include <linux/fs.h> | ||
30 | #include <linux/string.h> | ||
31 | #include <linux/udf_fs.h> | ||
32 | #include <linux/buffer_head.h> | ||
33 | |||
34 | #include "udf_i.h" | ||
35 | #include "udf_sb.h" | ||
36 | |||
37 | struct buffer_head * | ||
38 | udf_tgetblk(struct super_block *sb, int block) | ||
39 | { | ||
40 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV)) | ||
41 | return sb_getblk(sb, udf_fixed_to_variable(block)); | ||
42 | else | ||
43 | return sb_getblk(sb, block); | ||
44 | } | ||
45 | |||
46 | struct buffer_head * | ||
47 | udf_tread(struct super_block *sb, int block) | ||
48 | { | ||
49 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_VARCONV)) | ||
50 | return sb_bread(sb, udf_fixed_to_variable(block)); | ||
51 | else | ||
52 | return sb_bread(sb, block); | ||
53 | } | ||
54 | |||
55 | struct genericFormat * | ||
56 | udf_add_extendedattr(struct inode * inode, uint32_t size, uint32_t type, | ||
57 | uint8_t loc) | ||
58 | { | ||
59 | uint8_t *ea = NULL, *ad = NULL; | ||
60 | int offset; | ||
61 | uint16_t crclen; | ||
62 | int i; | ||
63 | |||
64 | ea = UDF_I_DATA(inode); | ||
65 | if (UDF_I_LENEATTR(inode)) | ||
66 | ad = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); | ||
67 | else | ||
68 | { | ||
69 | ad = ea; | ||
70 | size += sizeof(struct extendedAttrHeaderDesc); | ||
71 | } | ||
72 | |||
73 | offset = inode->i_sb->s_blocksize - udf_file_entry_alloc_offset(inode) - | ||
74 | UDF_I_LENALLOC(inode); | ||
75 | |||
76 | /* TODO - Check for FreeEASpace */ | ||
77 | |||
78 | if (loc & 0x01 && offset >= size) | ||
79 | { | ||
80 | struct extendedAttrHeaderDesc *eahd; | ||
81 | eahd = (struct extendedAttrHeaderDesc *)ea; | ||
82 | |||
83 | if (UDF_I_LENALLOC(inode)) | ||
84 | { | ||
85 | memmove(&ad[size], ad, UDF_I_LENALLOC(inode)); | ||
86 | } | ||
87 | |||
88 | if (UDF_I_LENEATTR(inode)) | ||
89 | { | ||
90 | /* check checksum/crc */ | ||
91 | if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || | ||
92 | le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) | ||
93 | { | ||
94 | return NULL; | ||
95 | } | ||
96 | } | ||
97 | else | ||
98 | { | ||
99 | size -= sizeof(struct extendedAttrHeaderDesc); | ||
100 | UDF_I_LENEATTR(inode) += sizeof(struct extendedAttrHeaderDesc); | ||
101 | eahd->descTag.tagIdent = cpu_to_le16(TAG_IDENT_EAHD); | ||
102 | if (UDF_SB_UDFREV(inode->i_sb) >= 0x0200) | ||
103 | eahd->descTag.descVersion = cpu_to_le16(3); | ||
104 | else | ||
105 | eahd->descTag.descVersion = cpu_to_le16(2); | ||
106 | eahd->descTag.tagSerialNum = cpu_to_le16(UDF_SB_SERIALNUM(inode->i_sb)); | ||
107 | eahd->descTag.tagLocation = cpu_to_le32(UDF_I_LOCATION(inode).logicalBlockNum); | ||
108 | eahd->impAttrLocation = cpu_to_le32(0xFFFFFFFF); | ||
109 | eahd->appAttrLocation = cpu_to_le32(0xFFFFFFFF); | ||
110 | } | ||
111 | |||
112 | offset = UDF_I_LENEATTR(inode); | ||
113 | if (type < 2048) | ||
114 | { | ||
115 | if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) | ||
116 | { | ||
117 | uint32_t aal = le32_to_cpu(eahd->appAttrLocation); | ||
118 | memmove(&ea[offset - aal + size], | ||
119 | &ea[aal], offset - aal); | ||
120 | offset -= aal; | ||
121 | eahd->appAttrLocation = cpu_to_le32(aal + size); | ||
122 | } | ||
123 | if (le32_to_cpu(eahd->impAttrLocation) < UDF_I_LENEATTR(inode)) | ||
124 | { | ||
125 | uint32_t ial = le32_to_cpu(eahd->impAttrLocation); | ||
126 | memmove(&ea[offset - ial + size], | ||
127 | &ea[ial], offset - ial); | ||
128 | offset -= ial; | ||
129 | eahd->impAttrLocation = cpu_to_le32(ial + size); | ||
130 | } | ||
131 | } | ||
132 | else if (type < 65536) | ||
133 | { | ||
134 | if (le32_to_cpu(eahd->appAttrLocation) < UDF_I_LENEATTR(inode)) | ||
135 | { | ||
136 | uint32_t aal = le32_to_cpu(eahd->appAttrLocation); | ||
137 | memmove(&ea[offset - aal + size], | ||
138 | &ea[aal], offset - aal); | ||
139 | offset -= aal; | ||
140 | eahd->appAttrLocation = cpu_to_le32(aal + size); | ||
141 | } | ||
142 | } | ||
143 | /* rewrite CRC + checksum of eahd */ | ||
144 | crclen = sizeof(struct extendedAttrHeaderDesc) - sizeof(tag); | ||
145 | eahd->descTag.descCRCLength = cpu_to_le16(crclen); | ||
146 | eahd->descTag.descCRC = cpu_to_le16(udf_crc((char *)eahd + sizeof(tag), crclen, 0)); | ||
147 | eahd->descTag.tagChecksum = 0; | ||
148 | for (i=0; i<16; i++) | ||
149 | if (i != 4) | ||
150 | eahd->descTag.tagChecksum += ((uint8_t *)&(eahd->descTag))[i]; | ||
151 | UDF_I_LENEATTR(inode) += size; | ||
152 | return (struct genericFormat *)&ea[offset]; | ||
153 | } | ||
154 | if (loc & 0x02) | ||
155 | { | ||
156 | } | ||
157 | return NULL; | ||
158 | } | ||
159 | |||
160 | struct genericFormat * | ||
161 | udf_get_extendedattr(struct inode *inode, uint32_t type, uint8_t subtype) | ||
162 | { | ||
163 | struct genericFormat *gaf; | ||
164 | uint8_t *ea = NULL; | ||
165 | uint32_t offset; | ||
166 | |||
167 | ea = UDF_I_DATA(inode); | ||
168 | |||
169 | if (UDF_I_LENEATTR(inode)) | ||
170 | { | ||
171 | struct extendedAttrHeaderDesc *eahd; | ||
172 | eahd = (struct extendedAttrHeaderDesc *)ea; | ||
173 | |||
174 | /* check checksum/crc */ | ||
175 | if (le16_to_cpu(eahd->descTag.tagIdent) != TAG_IDENT_EAHD || | ||
176 | le32_to_cpu(eahd->descTag.tagLocation) != UDF_I_LOCATION(inode).logicalBlockNum) | ||
177 | { | ||
178 | return NULL; | ||
179 | } | ||
180 | |||
181 | if (type < 2048) | ||
182 | offset = sizeof(struct extendedAttrHeaderDesc); | ||
183 | else if (type < 65536) | ||
184 | offset = le32_to_cpu(eahd->impAttrLocation); | ||
185 | else | ||
186 | offset = le32_to_cpu(eahd->appAttrLocation); | ||
187 | |||
188 | while (offset < UDF_I_LENEATTR(inode)) | ||
189 | { | ||
190 | gaf = (struct genericFormat *)&ea[offset]; | ||
191 | if (le32_to_cpu(gaf->attrType) == type && gaf->attrSubtype == subtype) | ||
192 | return gaf; | ||
193 | else | ||
194 | offset += le32_to_cpu(gaf->attrLength); | ||
195 | } | ||
196 | } | ||
197 | return NULL; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * udf_read_tagged | ||
202 | * | ||
203 | * PURPOSE | ||
204 | * Read the first block of a tagged descriptor. | ||
205 | * | ||
206 | * HISTORY | ||
207 | * July 1, 1997 - Andrew E. Mileski | ||
208 | * Written, tested, and released. | ||
209 | */ | ||
210 | struct buffer_head * | ||
211 | udf_read_tagged(struct super_block *sb, uint32_t block, uint32_t location, uint16_t *ident) | ||
212 | { | ||
213 | tag *tag_p; | ||
214 | struct buffer_head *bh = NULL; | ||
215 | register uint8_t checksum; | ||
216 | register int i; | ||
217 | |||
218 | /* Read the block */ | ||
219 | if (block == 0xFFFFFFFF) | ||
220 | return NULL; | ||
221 | |||
222 | bh = udf_tread(sb, block + UDF_SB_SESSION(sb)); | ||
223 | if (!bh) | ||
224 | { | ||
225 | udf_debug("block=%d, location=%d: read failed\n", block + UDF_SB_SESSION(sb), location); | ||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | tag_p = (tag *)(bh->b_data); | ||
230 | |||
231 | *ident = le16_to_cpu(tag_p->tagIdent); | ||
232 | |||
233 | if ( location != le32_to_cpu(tag_p->tagLocation) ) | ||
234 | { | ||
235 | udf_debug("location mismatch block %u, tag %u != %u\n", | ||
236 | block + UDF_SB_SESSION(sb), le32_to_cpu(tag_p->tagLocation), location); | ||
237 | goto error_out; | ||
238 | } | ||
239 | |||
240 | /* Verify the tag checksum */ | ||
241 | checksum = 0U; | ||
242 | for (i = 0; i < 4; i++) | ||
243 | checksum += (uint8_t)(bh->b_data[i]); | ||
244 | for (i = 5; i < 16; i++) | ||
245 | checksum += (uint8_t)(bh->b_data[i]); | ||
246 | if (checksum != tag_p->tagChecksum) { | ||
247 | printk(KERN_ERR "udf: tag checksum failed block %d\n", block); | ||
248 | goto error_out; | ||
249 | } | ||
250 | |||
251 | /* Verify the tag version */ | ||
252 | if (le16_to_cpu(tag_p->descVersion) != 0x0002U && | ||
253 | le16_to_cpu(tag_p->descVersion) != 0x0003U) | ||
254 | { | ||
255 | udf_debug("tag version 0x%04x != 0x0002 || 0x0003 block %d\n", | ||
256 | le16_to_cpu(tag_p->descVersion), block); | ||
257 | goto error_out; | ||
258 | } | ||
259 | |||
260 | /* Verify the descriptor CRC */ | ||
261 | if (le16_to_cpu(tag_p->descCRCLength) + sizeof(tag) > sb->s_blocksize || | ||
262 | le16_to_cpu(tag_p->descCRC) == udf_crc(bh->b_data + sizeof(tag), | ||
263 | le16_to_cpu(tag_p->descCRCLength), 0)) | ||
264 | { | ||
265 | return bh; | ||
266 | } | ||
267 | udf_debug("Crc failure block %d: crc = %d, crclen = %d\n", | ||
268 | block + UDF_SB_SESSION(sb), le16_to_cpu(tag_p->descCRC), le16_to_cpu(tag_p->descCRCLength)); | ||
269 | |||
270 | error_out: | ||
271 | brelse(bh); | ||
272 | return NULL; | ||
273 | } | ||
274 | |||
275 | struct buffer_head * | ||
276 | udf_read_ptagged(struct super_block *sb, kernel_lb_addr loc, uint32_t offset, uint16_t *ident) | ||
277 | { | ||
278 | return udf_read_tagged(sb, udf_get_lb_pblock(sb, loc, offset), | ||
279 | loc.logicalBlockNum + offset, ident); | ||
280 | } | ||
281 | |||
282 | void udf_release_data(struct buffer_head *bh) | ||
283 | { | ||
284 | if (bh) | ||
285 | brelse(bh); | ||
286 | } | ||
287 | |||
288 | void udf_update_tag(char *data, int length) | ||
289 | { | ||
290 | tag *tptr = (tag *)data; | ||
291 | int i; | ||
292 | |||
293 | length -= sizeof(tag); | ||
294 | |||
295 | tptr->tagChecksum = 0; | ||
296 | tptr->descCRCLength = cpu_to_le16(length); | ||
297 | tptr->descCRC = cpu_to_le16(udf_crc(data + sizeof(tag), length, 0)); | ||
298 | |||
299 | for (i=0; i<16; i++) | ||
300 | if (i != 4) | ||
301 | tptr->tagChecksum += (uint8_t)(data[i]); | ||
302 | } | ||
303 | |||
304 | void udf_new_tag(char *data, uint16_t ident, uint16_t version, uint16_t snum, | ||
305 | uint32_t loc, int length) | ||
306 | { | ||
307 | tag *tptr = (tag *)data; | ||
308 | tptr->tagIdent = cpu_to_le16(ident); | ||
309 | tptr->descVersion = cpu_to_le16(version); | ||
310 | tptr->tagSerialNum = cpu_to_le16(snum); | ||
311 | tptr->tagLocation = cpu_to_le32(loc); | ||
312 | udf_update_tag(data, length); | ||
313 | } | ||
diff --git a/fs/udf/namei.c b/fs/udf/namei.c new file mode 100644 index 000000000000..3f6dc7112bc6 --- /dev/null +++ b/fs/udf/namei.c | |||
@@ -0,0 +1,1334 @@ | |||
1 | /* | ||
2 | * namei.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Inode name handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-2004 Ben Fennema | ||
19 | * (C) 1999-2000 Stelias Computing Inc | ||
20 | * | ||
21 | * HISTORY | ||
22 | * | ||
23 | * 12/12/98 blf Created. Split out the lookup code from dir.c | ||
24 | * 04/19/99 blf link, mknod, symlink support | ||
25 | */ | ||
26 | |||
27 | #include "udfdecl.h" | ||
28 | |||
29 | #include "udf_i.h" | ||
30 | #include "udf_sb.h" | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/errno.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/quotaops.h> | ||
36 | #include <linux/smp_lock.h> | ||
37 | #include <linux/buffer_head.h> | ||
38 | |||
39 | static inline int udf_match(int len1, const char *name1, int len2, const char *name2) | ||
40 | { | ||
41 | if (len1 != len2) | ||
42 | return 0; | ||
43 | return !memcmp(name1, name2, len1); | ||
44 | } | ||
45 | |||
46 | int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi, | ||
47 | struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh, | ||
48 | uint8_t *impuse, uint8_t *fileident) | ||
49 | { | ||
50 | uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag); | ||
51 | uint16_t crc; | ||
52 | uint8_t checksum = 0; | ||
53 | int i; | ||
54 | int offset; | ||
55 | uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse); | ||
56 | uint8_t lfi = cfi->lengthFileIdent; | ||
57 | int padlen = fibh->eoffset - fibh->soffset - liu - lfi - | ||
58 | sizeof(struct fileIdentDesc); | ||
59 | int adinicb = 0; | ||
60 | |||
61 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
62 | adinicb = 1; | ||
63 | |||
64 | offset = fibh->soffset + sizeof(struct fileIdentDesc); | ||
65 | |||
66 | if (impuse) | ||
67 | { | ||
68 | if (adinicb || (offset + liu < 0)) | ||
69 | memcpy((uint8_t *)sfi->impUse, impuse, liu); | ||
70 | else if (offset >= 0) | ||
71 | memcpy(fibh->ebh->b_data + offset, impuse, liu); | ||
72 | else | ||
73 | { | ||
74 | memcpy((uint8_t *)sfi->impUse, impuse, -offset); | ||
75 | memcpy(fibh->ebh->b_data, impuse - offset, liu + offset); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | offset += liu; | ||
80 | |||
81 | if (fileident) | ||
82 | { | ||
83 | if (adinicb || (offset + lfi < 0)) | ||
84 | memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi); | ||
85 | else if (offset >= 0) | ||
86 | memcpy(fibh->ebh->b_data + offset, fileident, lfi); | ||
87 | else | ||
88 | { | ||
89 | memcpy((uint8_t *)sfi->fileIdent + liu, fileident, -offset); | ||
90 | memcpy(fibh->ebh->b_data, fileident - offset, lfi + offset); | ||
91 | } | ||
92 | } | ||
93 | |||
94 | offset += lfi; | ||
95 | |||
96 | if (adinicb || (offset + padlen < 0)) | ||
97 | memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen); | ||
98 | else if (offset >= 0) | ||
99 | memset(fibh->ebh->b_data + offset, 0x00, padlen); | ||
100 | else | ||
101 | { | ||
102 | memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset); | ||
103 | memset(fibh->ebh->b_data, 0x00, padlen + offset); | ||
104 | } | ||
105 | |||
106 | crc = udf_crc((uint8_t *)cfi + sizeof(tag), sizeof(struct fileIdentDesc) - | ||
107 | sizeof(tag), 0); | ||
108 | |||
109 | if (fibh->sbh == fibh->ebh) | ||
110 | crc = udf_crc((uint8_t *)sfi->impUse, | ||
111 | crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc); | ||
112 | else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) | ||
113 | crc = udf_crc(fibh->ebh->b_data + sizeof(struct fileIdentDesc) + fibh->soffset, | ||
114 | crclen + sizeof(tag) - sizeof(struct fileIdentDesc), crc); | ||
115 | else | ||
116 | { | ||
117 | crc = udf_crc((uint8_t *)sfi->impUse, | ||
118 | -fibh->soffset - sizeof(struct fileIdentDesc), crc); | ||
119 | crc = udf_crc(fibh->ebh->b_data, fibh->eoffset, crc); | ||
120 | } | ||
121 | |||
122 | cfi->descTag.descCRC = cpu_to_le16(crc); | ||
123 | cfi->descTag.descCRCLength = cpu_to_le16(crclen); | ||
124 | |||
125 | for (i=0; i<16; i++) | ||
126 | if (i != 4) | ||
127 | checksum += ((uint8_t *)&cfi->descTag)[i]; | ||
128 | |||
129 | cfi->descTag.tagChecksum = checksum; | ||
130 | if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) | ||
131 | memcpy((uint8_t *)sfi, (uint8_t *)cfi, sizeof(struct fileIdentDesc)); | ||
132 | else | ||
133 | { | ||
134 | memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset); | ||
135 | memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset, | ||
136 | sizeof(struct fileIdentDesc) + fibh->soffset); | ||
137 | } | ||
138 | |||
139 | if (adinicb) | ||
140 | mark_inode_dirty(inode); | ||
141 | else | ||
142 | { | ||
143 | if (fibh->sbh != fibh->ebh) | ||
144 | mark_buffer_dirty_inode(fibh->ebh, inode); | ||
145 | mark_buffer_dirty_inode(fibh->sbh, inode); | ||
146 | } | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static struct fileIdentDesc * | ||
151 | udf_find_entry(struct inode *dir, struct dentry *dentry, | ||
152 | struct udf_fileident_bh *fibh, | ||
153 | struct fileIdentDesc *cfi) | ||
154 | { | ||
155 | struct fileIdentDesc *fi=NULL; | ||
156 | loff_t f_pos; | ||
157 | int block, flen; | ||
158 | char fname[UDF_NAME_LEN]; | ||
159 | char *nameptr; | ||
160 | uint8_t lfi; | ||
161 | uint16_t liu; | ||
162 | loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; | ||
163 | kernel_lb_addr bloc, eloc; | ||
164 | uint32_t extoffset, elen, offset; | ||
165 | struct buffer_head *bh = NULL; | ||
166 | |||
167 | if (!dir) | ||
168 | return NULL; | ||
169 | |||
170 | f_pos = (udf_ext0_offset(dir) >> 2); | ||
171 | |||
172 | fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; | ||
173 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
174 | fibh->sbh = fibh->ebh = NULL; | ||
175 | else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), | ||
176 | &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) | ||
177 | { | ||
178 | offset >>= dir->i_sb->s_blocksize_bits; | ||
179 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | ||
180 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) | ||
181 | { | ||
182 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) | ||
183 | extoffset -= sizeof(short_ad); | ||
184 | else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) | ||
185 | extoffset -= sizeof(long_ad); | ||
186 | } | ||
187 | else | ||
188 | offset = 0; | ||
189 | |||
190 | if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) | ||
191 | { | ||
192 | udf_release_data(bh); | ||
193 | return NULL; | ||
194 | } | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | udf_release_data(bh); | ||
199 | return NULL; | ||
200 | } | ||
201 | |||
202 | while ( (f_pos < size) ) | ||
203 | { | ||
204 | fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); | ||
205 | |||
206 | if (!fi) | ||
207 | { | ||
208 | if (fibh->sbh != fibh->ebh) | ||
209 | udf_release_data(fibh->ebh); | ||
210 | udf_release_data(fibh->sbh); | ||
211 | udf_release_data(bh); | ||
212 | return NULL; | ||
213 | } | ||
214 | |||
215 | liu = le16_to_cpu(cfi->lengthOfImpUse); | ||
216 | lfi = cfi->lengthFileIdent; | ||
217 | |||
218 | if (fibh->sbh == fibh->ebh) | ||
219 | { | ||
220 | nameptr = fi->fileIdent + liu; | ||
221 | } | ||
222 | else | ||
223 | { | ||
224 | int poffset; /* Unpaded ending offset */ | ||
225 | |||
226 | poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi; | ||
227 | |||
228 | if (poffset >= lfi) | ||
229 | nameptr = (uint8_t *)(fibh->ebh->b_data + poffset - lfi); | ||
230 | else | ||
231 | { | ||
232 | nameptr = fname; | ||
233 | memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); | ||
234 | memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset); | ||
235 | } | ||
236 | } | ||
237 | |||
238 | if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) | ||
239 | { | ||
240 | if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE) ) | ||
241 | continue; | ||
242 | } | ||
243 | |||
244 | if ( (cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0 ) | ||
245 | { | ||
246 | if ( !UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE) ) | ||
247 | continue; | ||
248 | } | ||
249 | |||
250 | if (!lfi) | ||
251 | continue; | ||
252 | |||
253 | if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi))) | ||
254 | { | ||
255 | if (udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) | ||
256 | { | ||
257 | udf_release_data(bh); | ||
258 | return fi; | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | if (fibh->sbh != fibh->ebh) | ||
263 | udf_release_data(fibh->ebh); | ||
264 | udf_release_data(fibh->sbh); | ||
265 | udf_release_data(bh); | ||
266 | return NULL; | ||
267 | } | ||
268 | |||
269 | /* | ||
270 | * udf_lookup | ||
271 | * | ||
272 | * PURPOSE | ||
273 | * Look-up the inode for a given name. | ||
274 | * | ||
275 | * DESCRIPTION | ||
276 | * Required - lookup_dentry() will return -ENOTDIR if this routine is not | ||
277 | * available for a directory. The filesystem is useless if this routine is | ||
278 | * not available for at least the filesystem's root directory. | ||
279 | * | ||
280 | * This routine is passed an incomplete dentry - it must be completed by | ||
281 | * calling d_add(dentry, inode). If the name does not exist, then the | ||
282 | * specified inode must be set to null. An error should only be returned | ||
283 | * when the lookup fails for a reason other than the name not existing. | ||
284 | * Note that the directory inode semaphore is held during the call. | ||
285 | * | ||
286 | * Refer to lookup_dentry() in fs/namei.c | ||
287 | * lookup_dentry() -> lookup() -> real_lookup() -> . | ||
288 | * | ||
289 | * PRE-CONDITIONS | ||
290 | * dir Pointer to inode of parent directory. | ||
291 | * dentry Pointer to dentry to complete. | ||
292 | * nd Pointer to lookup nameidata | ||
293 | * | ||
294 | * POST-CONDITIONS | ||
295 | * <return> Zero on success. | ||
296 | * | ||
297 | * HISTORY | ||
298 | * July 1, 1997 - Andrew E. Mileski | ||
299 | * Written, tested, and released. | ||
300 | */ | ||
301 | |||
302 | static struct dentry * | ||
303 | udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
304 | { | ||
305 | struct inode *inode = NULL; | ||
306 | struct fileIdentDesc cfi, *fi; | ||
307 | struct udf_fileident_bh fibh; | ||
308 | |||
309 | if (dentry->d_name.len > UDF_NAME_LEN-2) | ||
310 | return ERR_PTR(-ENAMETOOLONG); | ||
311 | |||
312 | lock_kernel(); | ||
313 | #ifdef UDF_RECOVERY | ||
314 | /* temporary shorthand for specifying files by inode number */ | ||
315 | if (!strncmp(dentry->d_name.name, ".B=", 3) ) | ||
316 | { | ||
317 | kernel_lb_addr lb = { 0, simple_strtoul(dentry->d_name.name+3, NULL, 0) }; | ||
318 | inode = udf_iget(dir->i_sb, lb); | ||
319 | if (!inode) | ||
320 | { | ||
321 | unlock_kernel(); | ||
322 | return ERR_PTR(-EACCES); | ||
323 | } | ||
324 | } | ||
325 | else | ||
326 | #endif /* UDF_RECOVERY */ | ||
327 | |||
328 | if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi))) | ||
329 | { | ||
330 | if (fibh.sbh != fibh.ebh) | ||
331 | udf_release_data(fibh.ebh); | ||
332 | udf_release_data(fibh.sbh); | ||
333 | |||
334 | inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation)); | ||
335 | if ( !inode ) | ||
336 | { | ||
337 | unlock_kernel(); | ||
338 | return ERR_PTR(-EACCES); | ||
339 | } | ||
340 | } | ||
341 | unlock_kernel(); | ||
342 | d_add(dentry, inode); | ||
343 | return NULL; | ||
344 | } | ||
345 | |||
346 | static struct fileIdentDesc * | ||
347 | udf_add_entry(struct inode *dir, struct dentry *dentry, | ||
348 | struct udf_fileident_bh *fibh, | ||
349 | struct fileIdentDesc *cfi, int *err) | ||
350 | { | ||
351 | struct super_block *sb; | ||
352 | struct fileIdentDesc *fi=NULL; | ||
353 | char name[UDF_NAME_LEN], fname[UDF_NAME_LEN]; | ||
354 | int namelen; | ||
355 | loff_t f_pos; | ||
356 | int flen; | ||
357 | char *nameptr; | ||
358 | loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; | ||
359 | int nfidlen; | ||
360 | uint8_t lfi; | ||
361 | uint16_t liu; | ||
362 | int block; | ||
363 | kernel_lb_addr bloc, eloc; | ||
364 | uint32_t extoffset, elen, offset; | ||
365 | struct buffer_head *bh = NULL; | ||
366 | |||
367 | sb = dir->i_sb; | ||
368 | |||
369 | if (dentry) | ||
370 | { | ||
371 | if (!dentry->d_name.len) | ||
372 | { | ||
373 | *err = -EINVAL; | ||
374 | return NULL; | ||
375 | } | ||
376 | |||
377 | if ( !(namelen = udf_put_filename(sb, dentry->d_name.name, name, dentry->d_name.len))) | ||
378 | { | ||
379 | *err = -ENAMETOOLONG; | ||
380 | return NULL; | ||
381 | } | ||
382 | } | ||
383 | else | ||
384 | namelen = 0; | ||
385 | |||
386 | nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3; | ||
387 | |||
388 | f_pos = (udf_ext0_offset(dir) >> 2); | ||
389 | |||
390 | fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; | ||
391 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
392 | fibh->sbh = fibh->ebh = NULL; | ||
393 | else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), | ||
394 | &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) | ||
395 | { | ||
396 | offset >>= dir->i_sb->s_blocksize_bits; | ||
397 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | ||
398 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) | ||
399 | { | ||
400 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) | ||
401 | extoffset -= sizeof(short_ad); | ||
402 | else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) | ||
403 | extoffset -= sizeof(long_ad); | ||
404 | } | ||
405 | else | ||
406 | offset = 0; | ||
407 | |||
408 | if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block))) | ||
409 | { | ||
410 | udf_release_data(bh); | ||
411 | *err = -EIO; | ||
412 | return NULL; | ||
413 | } | ||
414 | |||
415 | block = UDF_I_LOCATION(dir).logicalBlockNum; | ||
416 | |||
417 | } | ||
418 | else | ||
419 | { | ||
420 | block = udf_get_lb_pblock(dir->i_sb, UDF_I_LOCATION(dir), 0); | ||
421 | fibh->sbh = fibh->ebh = NULL; | ||
422 | fibh->soffset = fibh->eoffset = sb->s_blocksize; | ||
423 | goto add; | ||
424 | } | ||
425 | |||
426 | while ( (f_pos < size) ) | ||
427 | { | ||
428 | fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); | ||
429 | |||
430 | if (!fi) | ||
431 | { | ||
432 | if (fibh->sbh != fibh->ebh) | ||
433 | udf_release_data(fibh->ebh); | ||
434 | udf_release_data(fibh->sbh); | ||
435 | udf_release_data(bh); | ||
436 | *err = -EIO; | ||
437 | return NULL; | ||
438 | } | ||
439 | |||
440 | liu = le16_to_cpu(cfi->lengthOfImpUse); | ||
441 | lfi = cfi->lengthFileIdent; | ||
442 | |||
443 | if (fibh->sbh == fibh->ebh) | ||
444 | nameptr = fi->fileIdent + liu; | ||
445 | else | ||
446 | { | ||
447 | int poffset; /* Unpaded ending offset */ | ||
448 | |||
449 | poffset = fibh->soffset + sizeof(struct fileIdentDesc) + liu + lfi; | ||
450 | |||
451 | if (poffset >= lfi) | ||
452 | nameptr = (char *)(fibh->ebh->b_data + poffset - lfi); | ||
453 | else | ||
454 | { | ||
455 | nameptr = fname; | ||
456 | memcpy(nameptr, fi->fileIdent + liu, lfi - poffset); | ||
457 | memcpy(nameptr + lfi - poffset, fibh->ebh->b_data, poffset); | ||
458 | } | ||
459 | } | ||
460 | |||
461 | if ( (cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0 ) | ||
462 | { | ||
463 | if (((sizeof(struct fileIdentDesc) + liu + lfi + 3) & ~3) == nfidlen) | ||
464 | { | ||
465 | udf_release_data(bh); | ||
466 | cfi->descTag.tagSerialNum = cpu_to_le16(1); | ||
467 | cfi->fileVersionNum = cpu_to_le16(1); | ||
468 | cfi->fileCharacteristics = 0; | ||
469 | cfi->lengthFileIdent = namelen; | ||
470 | cfi->lengthOfImpUse = cpu_to_le16(0); | ||
471 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) | ||
472 | return fi; | ||
473 | else | ||
474 | { | ||
475 | *err = -EIO; | ||
476 | return NULL; | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | |||
481 | if (!lfi || !dentry) | ||
482 | continue; | ||
483 | |||
484 | if ((flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi)) && | ||
485 | udf_match(flen, fname, dentry->d_name.len, dentry->d_name.name)) | ||
486 | { | ||
487 | if (fibh->sbh != fibh->ebh) | ||
488 | udf_release_data(fibh->ebh); | ||
489 | udf_release_data(fibh->sbh); | ||
490 | udf_release_data(bh); | ||
491 | *err = -EEXIST; | ||
492 | return NULL; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | add: | ||
497 | f_pos += nfidlen; | ||
498 | |||
499 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB && | ||
500 | sb->s_blocksize - fibh->eoffset < nfidlen) | ||
501 | { | ||
502 | udf_release_data(bh); | ||
503 | bh = NULL; | ||
504 | fibh->soffset -= udf_ext0_offset(dir); | ||
505 | fibh->eoffset -= udf_ext0_offset(dir); | ||
506 | f_pos -= (udf_ext0_offset(dir) >> 2); | ||
507 | if (fibh->sbh != fibh->ebh) | ||
508 | udf_release_data(fibh->ebh); | ||
509 | udf_release_data(fibh->sbh); | ||
510 | if (!(fibh->sbh = fibh->ebh = udf_expand_dir_adinicb(dir, &block, err))) | ||
511 | return NULL; | ||
512 | bloc = UDF_I_LOCATION(dir); | ||
513 | eloc.logicalBlockNum = block; | ||
514 | eloc.partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum; | ||
515 | elen = dir->i_sb->s_blocksize; | ||
516 | extoffset = udf_file_entry_alloc_offset(dir); | ||
517 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) | ||
518 | extoffset += sizeof(short_ad); | ||
519 | else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) | ||
520 | extoffset += sizeof(long_ad); | ||
521 | } | ||
522 | |||
523 | if (sb->s_blocksize - fibh->eoffset >= nfidlen) | ||
524 | { | ||
525 | fibh->soffset = fibh->eoffset; | ||
526 | fibh->eoffset += nfidlen; | ||
527 | if (fibh->sbh != fibh->ebh) | ||
528 | { | ||
529 | udf_release_data(fibh->sbh); | ||
530 | fibh->sbh = fibh->ebh; | ||
531 | } | ||
532 | |||
533 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
534 | { | ||
535 | block = UDF_I_LOCATION(dir).logicalBlockNum; | ||
536 | fi = (struct fileIdentDesc *)(UDF_I_DATA(dir) + fibh->soffset - udf_ext0_offset(dir) + UDF_I_LENEATTR(dir)); | ||
537 | } | ||
538 | else | ||
539 | { | ||
540 | block = eloc.logicalBlockNum + ((elen - 1) >> | ||
541 | dir->i_sb->s_blocksize_bits); | ||
542 | fi = (struct fileIdentDesc *)(fibh->sbh->b_data + fibh->soffset); | ||
543 | } | ||
544 | } | ||
545 | else | ||
546 | { | ||
547 | fibh->soffset = fibh->eoffset - sb->s_blocksize; | ||
548 | fibh->eoffset += nfidlen - sb->s_blocksize; | ||
549 | if (fibh->sbh != fibh->ebh) | ||
550 | { | ||
551 | udf_release_data(fibh->sbh); | ||
552 | fibh->sbh = fibh->ebh; | ||
553 | } | ||
554 | |||
555 | block = eloc.logicalBlockNum + ((elen - 1) >> | ||
556 | dir->i_sb->s_blocksize_bits); | ||
557 | |||
558 | if (!(fibh->ebh = udf_bread(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), 1, err))) | ||
559 | { | ||
560 | udf_release_data(bh); | ||
561 | udf_release_data(fibh->sbh); | ||
562 | return NULL; | ||
563 | } | ||
564 | |||
565 | if (!(fibh->soffset)) | ||
566 | { | ||
567 | if (udf_next_aext(dir, &bloc, &extoffset, &eloc, &elen, &bh, 1) == | ||
568 | (EXT_RECORDED_ALLOCATED >> 30)) | ||
569 | { | ||
570 | block = eloc.logicalBlockNum + ((elen - 1) >> | ||
571 | dir->i_sb->s_blocksize_bits); | ||
572 | } | ||
573 | else | ||
574 | block ++; | ||
575 | |||
576 | udf_release_data(fibh->sbh); | ||
577 | fibh->sbh = fibh->ebh; | ||
578 | fi = (struct fileIdentDesc *)(fibh->sbh->b_data); | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | fi = (struct fileIdentDesc *) | ||
583 | (fibh->sbh->b_data + sb->s_blocksize + fibh->soffset); | ||
584 | } | ||
585 | } | ||
586 | |||
587 | memset(cfi, 0, sizeof(struct fileIdentDesc)); | ||
588 | if (UDF_SB_UDFREV(sb) >= 0x0200) | ||
589 | udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block, sizeof(tag)); | ||
590 | else | ||
591 | udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block, sizeof(tag)); | ||
592 | cfi->fileVersionNum = cpu_to_le16(1); | ||
593 | cfi->lengthFileIdent = namelen; | ||
594 | cfi->lengthOfImpUse = cpu_to_le16(0); | ||
595 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) | ||
596 | { | ||
597 | udf_release_data(bh); | ||
598 | dir->i_size += nfidlen; | ||
599 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
600 | UDF_I_LENALLOC(dir) += nfidlen; | ||
601 | mark_inode_dirty(dir); | ||
602 | return fi; | ||
603 | } | ||
604 | else | ||
605 | { | ||
606 | udf_release_data(bh); | ||
607 | if (fibh->sbh != fibh->ebh) | ||
608 | udf_release_data(fibh->ebh); | ||
609 | udf_release_data(fibh->sbh); | ||
610 | *err = -EIO; | ||
611 | return NULL; | ||
612 | } | ||
613 | } | ||
614 | |||
615 | static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, | ||
616 | struct udf_fileident_bh *fibh, struct fileIdentDesc *cfi) | ||
617 | { | ||
618 | cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED; | ||
619 | if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT)) | ||
620 | memset(&(cfi->icb), 0x00, sizeof(long_ad)); | ||
621 | return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL); | ||
622 | } | ||
623 | |||
624 | static int udf_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) | ||
625 | { | ||
626 | struct udf_fileident_bh fibh; | ||
627 | struct inode *inode; | ||
628 | struct fileIdentDesc cfi, *fi; | ||
629 | int err; | ||
630 | |||
631 | lock_kernel(); | ||
632 | inode = udf_new_inode(dir, mode, &err); | ||
633 | if (!inode) | ||
634 | { | ||
635 | unlock_kernel(); | ||
636 | return err; | ||
637 | } | ||
638 | |||
639 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
640 | inode->i_data.a_ops = &udf_adinicb_aops; | ||
641 | else | ||
642 | inode->i_data.a_ops = &udf_aops; | ||
643 | inode->i_op = &udf_file_inode_operations; | ||
644 | inode->i_fop = &udf_file_operations; | ||
645 | inode->i_mode = mode; | ||
646 | mark_inode_dirty(inode); | ||
647 | |||
648 | if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) | ||
649 | { | ||
650 | inode->i_nlink --; | ||
651 | mark_inode_dirty(inode); | ||
652 | iput(inode); | ||
653 | unlock_kernel(); | ||
654 | return err; | ||
655 | } | ||
656 | cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); | ||
657 | cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); | ||
658 | *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = | ||
659 | cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); | ||
660 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | ||
661 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
662 | { | ||
663 | mark_inode_dirty(dir); | ||
664 | } | ||
665 | if (fibh.sbh != fibh.ebh) | ||
666 | udf_release_data(fibh.ebh); | ||
667 | udf_release_data(fibh.sbh); | ||
668 | unlock_kernel(); | ||
669 | d_instantiate(dentry, inode); | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int udf_mknod(struct inode * dir, struct dentry * dentry, int mode, dev_t rdev) | ||
674 | { | ||
675 | struct inode * inode; | ||
676 | struct udf_fileident_bh fibh; | ||
677 | struct fileIdentDesc cfi, *fi; | ||
678 | int err; | ||
679 | |||
680 | if (!old_valid_dev(rdev)) | ||
681 | return -EINVAL; | ||
682 | |||
683 | lock_kernel(); | ||
684 | err = -EIO; | ||
685 | inode = udf_new_inode(dir, mode, &err); | ||
686 | if (!inode) | ||
687 | goto out; | ||
688 | |||
689 | inode->i_uid = current->fsuid; | ||
690 | init_special_inode(inode, mode, rdev); | ||
691 | if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) | ||
692 | { | ||
693 | inode->i_nlink --; | ||
694 | mark_inode_dirty(inode); | ||
695 | iput(inode); | ||
696 | unlock_kernel(); | ||
697 | return err; | ||
698 | } | ||
699 | cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); | ||
700 | cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); | ||
701 | *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = | ||
702 | cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); | ||
703 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | ||
704 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
705 | { | ||
706 | mark_inode_dirty(dir); | ||
707 | } | ||
708 | mark_inode_dirty(inode); | ||
709 | |||
710 | if (fibh.sbh != fibh.ebh) | ||
711 | udf_release_data(fibh.ebh); | ||
712 | udf_release_data(fibh.sbh); | ||
713 | d_instantiate(dentry, inode); | ||
714 | err = 0; | ||
715 | out: | ||
716 | unlock_kernel(); | ||
717 | return err; | ||
718 | } | ||
719 | |||
720 | static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode) | ||
721 | { | ||
722 | struct inode * inode; | ||
723 | struct udf_fileident_bh fibh; | ||
724 | struct fileIdentDesc cfi, *fi; | ||
725 | int err; | ||
726 | |||
727 | lock_kernel(); | ||
728 | err = -EMLINK; | ||
729 | if (dir->i_nlink >= (256<<sizeof(dir->i_nlink))-1) | ||
730 | goto out; | ||
731 | |||
732 | err = -EIO; | ||
733 | inode = udf_new_inode(dir, S_IFDIR, &err); | ||
734 | if (!inode) | ||
735 | goto out; | ||
736 | |||
737 | inode->i_op = &udf_dir_inode_operations; | ||
738 | inode->i_fop = &udf_dir_operations; | ||
739 | if (!(fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err))) | ||
740 | { | ||
741 | inode->i_nlink--; | ||
742 | mark_inode_dirty(inode); | ||
743 | iput(inode); | ||
744 | goto out; | ||
745 | } | ||
746 | inode->i_nlink = 2; | ||
747 | cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); | ||
748 | cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(dir)); | ||
749 | *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = | ||
750 | cpu_to_le32(UDF_I_UNIQUE(dir) & 0x00000000FFFFFFFFUL); | ||
751 | cfi.fileCharacteristics = FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT; | ||
752 | udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL); | ||
753 | udf_release_data(fibh.sbh); | ||
754 | inode->i_mode = S_IFDIR | mode; | ||
755 | if (dir->i_mode & S_ISGID) | ||
756 | inode->i_mode |= S_ISGID; | ||
757 | mark_inode_dirty(inode); | ||
758 | |||
759 | if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) | ||
760 | { | ||
761 | inode->i_nlink = 0; | ||
762 | mark_inode_dirty(inode); | ||
763 | iput(inode); | ||
764 | goto out; | ||
765 | } | ||
766 | cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); | ||
767 | cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); | ||
768 | *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = | ||
769 | cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL); | ||
770 | cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY; | ||
771 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | ||
772 | dir->i_nlink++; | ||
773 | mark_inode_dirty(dir); | ||
774 | d_instantiate(dentry, inode); | ||
775 | if (fibh.sbh != fibh.ebh) | ||
776 | udf_release_data(fibh.ebh); | ||
777 | udf_release_data(fibh.sbh); | ||
778 | err = 0; | ||
779 | out: | ||
780 | unlock_kernel(); | ||
781 | return err; | ||
782 | } | ||
783 | |||
784 | static int empty_dir(struct inode *dir) | ||
785 | { | ||
786 | struct fileIdentDesc *fi, cfi; | ||
787 | struct udf_fileident_bh fibh; | ||
788 | loff_t f_pos; | ||
789 | loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2; | ||
790 | int block; | ||
791 | kernel_lb_addr bloc, eloc; | ||
792 | uint32_t extoffset, elen, offset; | ||
793 | struct buffer_head *bh = NULL; | ||
794 | |||
795 | f_pos = (udf_ext0_offset(dir) >> 2); | ||
796 | |||
797 | fibh.soffset = fibh.eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2; | ||
798 | |||
799 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
800 | fibh.sbh = fibh.ebh = NULL; | ||
801 | else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2), | ||
802 | &bloc, &extoffset, &eloc, &elen, &offset, &bh) == (EXT_RECORDED_ALLOCATED >> 30)) | ||
803 | { | ||
804 | offset >>= dir->i_sb->s_blocksize_bits; | ||
805 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | ||
806 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) | ||
807 | { | ||
808 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_SHORT) | ||
809 | extoffset -= sizeof(short_ad); | ||
810 | else if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_LONG) | ||
811 | extoffset -= sizeof(long_ad); | ||
812 | } | ||
813 | else | ||
814 | offset = 0; | ||
815 | |||
816 | if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) | ||
817 | { | ||
818 | udf_release_data(bh); | ||
819 | return 0; | ||
820 | } | ||
821 | } | ||
822 | else | ||
823 | { | ||
824 | udf_release_data(bh); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | |||
829 | while ( (f_pos < size) ) | ||
830 | { | ||
831 | fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &bloc, &extoffset, &eloc, &elen, &offset, &bh); | ||
832 | |||
833 | if (!fi) | ||
834 | { | ||
835 | if (fibh.sbh != fibh.ebh) | ||
836 | udf_release_data(fibh.ebh); | ||
837 | udf_release_data(fibh.sbh); | ||
838 | udf_release_data(bh); | ||
839 | return 0; | ||
840 | } | ||
841 | |||
842 | if (cfi.lengthFileIdent && (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) | ||
843 | { | ||
844 | if (fibh.sbh != fibh.ebh) | ||
845 | udf_release_data(fibh.ebh); | ||
846 | udf_release_data(fibh.sbh); | ||
847 | udf_release_data(bh); | ||
848 | return 0; | ||
849 | } | ||
850 | } | ||
851 | if (fibh.sbh != fibh.ebh) | ||
852 | udf_release_data(fibh.ebh); | ||
853 | udf_release_data(fibh.sbh); | ||
854 | udf_release_data(bh); | ||
855 | return 1; | ||
856 | } | ||
857 | |||
858 | static int udf_rmdir(struct inode * dir, struct dentry * dentry) | ||
859 | { | ||
860 | int retval; | ||
861 | struct inode * inode = dentry->d_inode; | ||
862 | struct udf_fileident_bh fibh; | ||
863 | struct fileIdentDesc *fi, cfi; | ||
864 | kernel_lb_addr tloc; | ||
865 | |||
866 | retval = -ENOENT; | ||
867 | lock_kernel(); | ||
868 | fi = udf_find_entry(dir, dentry, &fibh, &cfi); | ||
869 | if (!fi) | ||
870 | goto out; | ||
871 | |||
872 | retval = -EIO; | ||
873 | tloc = lelb_to_cpu(cfi.icb.extLocation); | ||
874 | if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino) | ||
875 | goto end_rmdir; | ||
876 | retval = -ENOTEMPTY; | ||
877 | if (!empty_dir(inode)) | ||
878 | goto end_rmdir; | ||
879 | retval = udf_delete_entry(dir, fi, &fibh, &cfi); | ||
880 | if (retval) | ||
881 | goto end_rmdir; | ||
882 | if (inode->i_nlink != 2) | ||
883 | udf_warning(inode->i_sb, "udf_rmdir", | ||
884 | "empty directory has nlink != 2 (%d)", | ||
885 | inode->i_nlink); | ||
886 | inode->i_nlink = 0; | ||
887 | inode->i_size = 0; | ||
888 | mark_inode_dirty(inode); | ||
889 | dir->i_nlink --; | ||
890 | inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); | ||
891 | mark_inode_dirty(dir); | ||
892 | |||
893 | end_rmdir: | ||
894 | if (fibh.sbh != fibh.ebh) | ||
895 | udf_release_data(fibh.ebh); | ||
896 | udf_release_data(fibh.sbh); | ||
897 | out: | ||
898 | unlock_kernel(); | ||
899 | return retval; | ||
900 | } | ||
901 | |||
902 | static int udf_unlink(struct inode * dir, struct dentry * dentry) | ||
903 | { | ||
904 | int retval; | ||
905 | struct inode * inode = dentry->d_inode; | ||
906 | struct udf_fileident_bh fibh; | ||
907 | struct fileIdentDesc *fi; | ||
908 | struct fileIdentDesc cfi; | ||
909 | kernel_lb_addr tloc; | ||
910 | |||
911 | retval = -ENOENT; | ||
912 | lock_kernel(); | ||
913 | fi = udf_find_entry(dir, dentry, &fibh, &cfi); | ||
914 | if (!fi) | ||
915 | goto out; | ||
916 | |||
917 | retval = -EIO; | ||
918 | tloc = lelb_to_cpu(cfi.icb.extLocation); | ||
919 | if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino) | ||
920 | goto end_unlink; | ||
921 | |||
922 | if (!inode->i_nlink) | ||
923 | { | ||
924 | udf_debug("Deleting nonexistent file (%lu), %d\n", | ||
925 | inode->i_ino, inode->i_nlink); | ||
926 | inode->i_nlink = 1; | ||
927 | } | ||
928 | retval = udf_delete_entry(dir, fi, &fibh, &cfi); | ||
929 | if (retval) | ||
930 | goto end_unlink; | ||
931 | dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb); | ||
932 | mark_inode_dirty(dir); | ||
933 | inode->i_nlink--; | ||
934 | mark_inode_dirty(inode); | ||
935 | inode->i_ctime = dir->i_ctime; | ||
936 | retval = 0; | ||
937 | |||
938 | end_unlink: | ||
939 | if (fibh.sbh != fibh.ebh) | ||
940 | udf_release_data(fibh.ebh); | ||
941 | udf_release_data(fibh.sbh); | ||
942 | out: | ||
943 | unlock_kernel(); | ||
944 | return retval; | ||
945 | } | ||
946 | |||
947 | static int udf_symlink(struct inode * dir, struct dentry * dentry, const char * symname) | ||
948 | { | ||
949 | struct inode * inode; | ||
950 | struct pathComponent *pc; | ||
951 | char *compstart; | ||
952 | struct udf_fileident_bh fibh; | ||
953 | struct buffer_head *bh = NULL; | ||
954 | int eoffset, elen = 0; | ||
955 | struct fileIdentDesc *fi; | ||
956 | struct fileIdentDesc cfi; | ||
957 | char *ea; | ||
958 | int err; | ||
959 | int block; | ||
960 | char name[UDF_NAME_LEN]; | ||
961 | int namelen; | ||
962 | |||
963 | lock_kernel(); | ||
964 | if (!(inode = udf_new_inode(dir, S_IFLNK, &err))) | ||
965 | goto out; | ||
966 | |||
967 | inode->i_mode = S_IFLNK | S_IRWXUGO; | ||
968 | inode->i_data.a_ops = &udf_symlink_aops; | ||
969 | inode->i_op = &page_symlink_inode_operations; | ||
970 | |||
971 | if (UDF_I_ALLOCTYPE(inode) != ICBTAG_FLAG_AD_IN_ICB) | ||
972 | { | ||
973 | struct buffer_head *bh = NULL; | ||
974 | kernel_lb_addr bloc, eloc; | ||
975 | uint32_t elen, extoffset; | ||
976 | |||
977 | block = udf_new_block(inode->i_sb, inode, | ||
978 | UDF_I_LOCATION(inode).partitionReferenceNum, | ||
979 | UDF_I_LOCATION(inode).logicalBlockNum, &err); | ||
980 | if (!block) | ||
981 | goto out_no_entry; | ||
982 | bloc = UDF_I_LOCATION(inode); | ||
983 | eloc.logicalBlockNum = block; | ||
984 | eloc.partitionReferenceNum = UDF_I_LOCATION(inode).partitionReferenceNum; | ||
985 | elen = inode->i_sb->s_blocksize; | ||
986 | UDF_I_LENEXTENTS(inode) = elen; | ||
987 | extoffset = udf_file_entry_alloc_offset(inode); | ||
988 | udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 0); | ||
989 | udf_release_data(bh); | ||
990 | |||
991 | block = udf_get_pblock(inode->i_sb, block, | ||
992 | UDF_I_LOCATION(inode).partitionReferenceNum, 0); | ||
993 | bh = udf_tread(inode->i_sb, block); | ||
994 | lock_buffer(bh); | ||
995 | memset(bh->b_data, 0x00, inode->i_sb->s_blocksize); | ||
996 | set_buffer_uptodate(bh); | ||
997 | unlock_buffer(bh); | ||
998 | mark_buffer_dirty_inode(bh, inode); | ||
999 | ea = bh->b_data + udf_ext0_offset(inode); | ||
1000 | } | ||
1001 | else | ||
1002 | ea = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); | ||
1003 | |||
1004 | eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode); | ||
1005 | pc = (struct pathComponent *)ea; | ||
1006 | |||
1007 | if (*symname == '/') | ||
1008 | { | ||
1009 | do | ||
1010 | { | ||
1011 | symname++; | ||
1012 | } while (*symname == '/'); | ||
1013 | |||
1014 | pc->componentType = 1; | ||
1015 | pc->lengthComponentIdent = 0; | ||
1016 | pc->componentFileVersionNum = 0; | ||
1017 | pc += sizeof(struct pathComponent); | ||
1018 | elen += sizeof(struct pathComponent); | ||
1019 | } | ||
1020 | |||
1021 | err = -ENAMETOOLONG; | ||
1022 | |||
1023 | while (*symname) | ||
1024 | { | ||
1025 | if (elen + sizeof(struct pathComponent) > eoffset) | ||
1026 | goto out_no_entry; | ||
1027 | |||
1028 | pc = (struct pathComponent *)(ea + elen); | ||
1029 | |||
1030 | compstart = (char *)symname; | ||
1031 | |||
1032 | do | ||
1033 | { | ||
1034 | symname++; | ||
1035 | } while (*symname && *symname != '/'); | ||
1036 | |||
1037 | pc->componentType = 5; | ||
1038 | pc->lengthComponentIdent = 0; | ||
1039 | pc->componentFileVersionNum = 0; | ||
1040 | if (compstart[0] == '.') | ||
1041 | { | ||
1042 | if ((symname-compstart) == 1) | ||
1043 | pc->componentType = 4; | ||
1044 | else if ((symname-compstart) == 2 && compstart[1] == '.') | ||
1045 | pc->componentType = 3; | ||
1046 | } | ||
1047 | |||
1048 | if (pc->componentType == 5) | ||
1049 | { | ||
1050 | if ( !(namelen = udf_put_filename(inode->i_sb, compstart, name, symname-compstart))) | ||
1051 | goto out_no_entry; | ||
1052 | |||
1053 | if (elen + sizeof(struct pathComponent) + namelen > eoffset) | ||
1054 | goto out_no_entry; | ||
1055 | else | ||
1056 | pc->lengthComponentIdent = namelen; | ||
1057 | |||
1058 | memcpy(pc->componentIdent, name, namelen); | ||
1059 | } | ||
1060 | |||
1061 | elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; | ||
1062 | |||
1063 | if (*symname) | ||
1064 | { | ||
1065 | do | ||
1066 | { | ||
1067 | symname++; | ||
1068 | } while (*symname == '/'); | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | udf_release_data(bh); | ||
1073 | inode->i_size = elen; | ||
1074 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
1075 | UDF_I_LENALLOC(inode) = inode->i_size; | ||
1076 | mark_inode_dirty(inode); | ||
1077 | |||
1078 | if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) | ||
1079 | goto out_no_entry; | ||
1080 | cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); | ||
1081 | cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); | ||
1082 | if (UDF_SB_LVIDBH(inode->i_sb)) | ||
1083 | { | ||
1084 | struct logicalVolHeaderDesc *lvhd; | ||
1085 | uint64_t uniqueID; | ||
1086 | lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse); | ||
1087 | uniqueID = le64_to_cpu(lvhd->uniqueID); | ||
1088 | *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = | ||
1089 | cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); | ||
1090 | if (!(++uniqueID & 0x00000000FFFFFFFFUL)) | ||
1091 | uniqueID += 16; | ||
1092 | lvhd->uniqueID = cpu_to_le64(uniqueID); | ||
1093 | mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb)); | ||
1094 | } | ||
1095 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | ||
1096 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
1097 | { | ||
1098 | mark_inode_dirty(dir); | ||
1099 | } | ||
1100 | if (fibh.sbh != fibh.ebh) | ||
1101 | udf_release_data(fibh.ebh); | ||
1102 | udf_release_data(fibh.sbh); | ||
1103 | d_instantiate(dentry, inode); | ||
1104 | err = 0; | ||
1105 | |||
1106 | out: | ||
1107 | unlock_kernel(); | ||
1108 | return err; | ||
1109 | |||
1110 | out_no_entry: | ||
1111 | inode->i_nlink--; | ||
1112 | mark_inode_dirty(inode); | ||
1113 | iput(inode); | ||
1114 | goto out; | ||
1115 | } | ||
1116 | |||
1117 | static int udf_link(struct dentry * old_dentry, struct inode * dir, | ||
1118 | struct dentry *dentry) | ||
1119 | { | ||
1120 | struct inode *inode = old_dentry->d_inode; | ||
1121 | struct udf_fileident_bh fibh; | ||
1122 | struct fileIdentDesc cfi, *fi; | ||
1123 | int err; | ||
1124 | |||
1125 | lock_kernel(); | ||
1126 | if (inode->i_nlink >= (256<<sizeof(inode->i_nlink))-1) | ||
1127 | { | ||
1128 | unlock_kernel(); | ||
1129 | return -EMLINK; | ||
1130 | } | ||
1131 | |||
1132 | if (!(fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err))) | ||
1133 | { | ||
1134 | unlock_kernel(); | ||
1135 | return err; | ||
1136 | } | ||
1137 | cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize); | ||
1138 | cfi.icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(inode)); | ||
1139 | if (UDF_SB_LVIDBH(inode->i_sb)) | ||
1140 | { | ||
1141 | struct logicalVolHeaderDesc *lvhd; | ||
1142 | uint64_t uniqueID; | ||
1143 | lvhd = (struct logicalVolHeaderDesc *)(UDF_SB_LVID(inode->i_sb)->logicalVolContentsUse); | ||
1144 | uniqueID = le64_to_cpu(lvhd->uniqueID); | ||
1145 | *(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse = | ||
1146 | cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL); | ||
1147 | if (!(++uniqueID & 0x00000000FFFFFFFFUL)) | ||
1148 | uniqueID += 16; | ||
1149 | lvhd->uniqueID = cpu_to_le64(uniqueID); | ||
1150 | mark_buffer_dirty(UDF_SB_LVIDBH(inode->i_sb)); | ||
1151 | } | ||
1152 | udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL); | ||
1153 | if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB) | ||
1154 | { | ||
1155 | mark_inode_dirty(dir); | ||
1156 | } | ||
1157 | if (fibh.sbh != fibh.ebh) | ||
1158 | udf_release_data(fibh.ebh); | ||
1159 | udf_release_data(fibh.sbh); | ||
1160 | inode->i_nlink ++; | ||
1161 | inode->i_ctime = current_fs_time(inode->i_sb); | ||
1162 | mark_inode_dirty(inode); | ||
1163 | atomic_inc(&inode->i_count); | ||
1164 | d_instantiate(dentry, inode); | ||
1165 | unlock_kernel(); | ||
1166 | return 0; | ||
1167 | } | ||
1168 | |||
1169 | /* Anybody can rename anything with this: the permission checks are left to the | ||
1170 | * higher-level routines. | ||
1171 | */ | ||
1172 | static int udf_rename (struct inode * old_dir, struct dentry * old_dentry, | ||
1173 | struct inode * new_dir, struct dentry * new_dentry) | ||
1174 | { | ||
1175 | struct inode * old_inode = old_dentry->d_inode; | ||
1176 | struct inode * new_inode = new_dentry->d_inode; | ||
1177 | struct udf_fileident_bh ofibh, nfibh; | ||
1178 | struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL, ocfi, ncfi; | ||
1179 | struct buffer_head *dir_bh = NULL; | ||
1180 | int retval = -ENOENT; | ||
1181 | kernel_lb_addr tloc; | ||
1182 | |||
1183 | lock_kernel(); | ||
1184 | if ((ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi))) | ||
1185 | { | ||
1186 | if (ofibh.sbh != ofibh.ebh) | ||
1187 | udf_release_data(ofibh.ebh); | ||
1188 | udf_release_data(ofibh.sbh); | ||
1189 | } | ||
1190 | tloc = lelb_to_cpu(ocfi.icb.extLocation); | ||
1191 | if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0) | ||
1192 | != old_inode->i_ino) | ||
1193 | goto end_rename; | ||
1194 | |||
1195 | nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi); | ||
1196 | if (nfi) | ||
1197 | { | ||
1198 | if (!new_inode) | ||
1199 | { | ||
1200 | if (nfibh.sbh != nfibh.ebh) | ||
1201 | udf_release_data(nfibh.ebh); | ||
1202 | udf_release_data(nfibh.sbh); | ||
1203 | nfi = NULL; | ||
1204 | } | ||
1205 | } | ||
1206 | if (S_ISDIR(old_inode->i_mode)) | ||
1207 | { | ||
1208 | uint32_t offset = udf_ext0_offset(old_inode); | ||
1209 | |||
1210 | if (new_inode) | ||
1211 | { | ||
1212 | retval = -ENOTEMPTY; | ||
1213 | if (!empty_dir(new_inode)) | ||
1214 | goto end_rename; | ||
1215 | } | ||
1216 | retval = -EIO; | ||
1217 | if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
1218 | { | ||
1219 | dir_fi = udf_get_fileident(UDF_I_DATA(old_inode) - | ||
1220 | (UDF_I_EFE(old_inode) ? | ||
1221 | sizeof(struct extendedFileEntry) : | ||
1222 | sizeof(struct fileEntry)), | ||
1223 | old_inode->i_sb->s_blocksize, &offset); | ||
1224 | } | ||
1225 | else | ||
1226 | { | ||
1227 | dir_bh = udf_bread(old_inode, 0, 0, &retval); | ||
1228 | if (!dir_bh) | ||
1229 | goto end_rename; | ||
1230 | dir_fi = udf_get_fileident(dir_bh->b_data, old_inode->i_sb->s_blocksize, &offset); | ||
1231 | } | ||
1232 | if (!dir_fi) | ||
1233 | goto end_rename; | ||
1234 | tloc = lelb_to_cpu(dir_fi->icb.extLocation); | ||
1235 | if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) | ||
1236 | != old_dir->i_ino) | ||
1237 | goto end_rename; | ||
1238 | |||
1239 | retval = -EMLINK; | ||
1240 | if (!new_inode && new_dir->i_nlink >= (256<<sizeof(new_dir->i_nlink))-1) | ||
1241 | goto end_rename; | ||
1242 | } | ||
1243 | if (!nfi) | ||
1244 | { | ||
1245 | nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi, &retval); | ||
1246 | if (!nfi) | ||
1247 | goto end_rename; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * Like most other Unix systems, set the ctime for inodes on a | ||
1252 | * rename. | ||
1253 | */ | ||
1254 | old_inode->i_ctime = current_fs_time(old_inode->i_sb); | ||
1255 | mark_inode_dirty(old_inode); | ||
1256 | |||
1257 | /* | ||
1258 | * ok, that's it | ||
1259 | */ | ||
1260 | ncfi.fileVersionNum = ocfi.fileVersionNum; | ||
1261 | ncfi.fileCharacteristics = ocfi.fileCharacteristics; | ||
1262 | memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad)); | ||
1263 | udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL); | ||
1264 | |||
1265 | /* The old fid may have moved - find it again */ | ||
1266 | ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi); | ||
1267 | udf_delete_entry(old_dir, ofi, &ofibh, &ocfi); | ||
1268 | |||
1269 | if (new_inode) | ||
1270 | { | ||
1271 | new_inode->i_nlink--; | ||
1272 | new_inode->i_ctime = current_fs_time(new_inode->i_sb); | ||
1273 | mark_inode_dirty(new_inode); | ||
1274 | } | ||
1275 | old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb); | ||
1276 | mark_inode_dirty(old_dir); | ||
1277 | |||
1278 | if (dir_fi) | ||
1279 | { | ||
1280 | dir_fi->icb.extLocation = cpu_to_lelb(UDF_I_LOCATION(new_dir)); | ||
1281 | udf_update_tag((char *)dir_fi, (sizeof(struct fileIdentDesc) + | ||
1282 | le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3); | ||
1283 | if (UDF_I_ALLOCTYPE(old_inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
1284 | { | ||
1285 | mark_inode_dirty(old_inode); | ||
1286 | } | ||
1287 | else | ||
1288 | mark_buffer_dirty_inode(dir_bh, old_inode); | ||
1289 | old_dir->i_nlink --; | ||
1290 | mark_inode_dirty(old_dir); | ||
1291 | if (new_inode) | ||
1292 | { | ||
1293 | new_inode->i_nlink --; | ||
1294 | mark_inode_dirty(new_inode); | ||
1295 | } | ||
1296 | else | ||
1297 | { | ||
1298 | new_dir->i_nlink ++; | ||
1299 | mark_inode_dirty(new_dir); | ||
1300 | } | ||
1301 | } | ||
1302 | |||
1303 | if (ofi) | ||
1304 | { | ||
1305 | if (ofibh.sbh != ofibh.ebh) | ||
1306 | udf_release_data(ofibh.ebh); | ||
1307 | udf_release_data(ofibh.sbh); | ||
1308 | } | ||
1309 | |||
1310 | retval = 0; | ||
1311 | |||
1312 | end_rename: | ||
1313 | udf_release_data(dir_bh); | ||
1314 | if (nfi) | ||
1315 | { | ||
1316 | if (nfibh.sbh != nfibh.ebh) | ||
1317 | udf_release_data(nfibh.ebh); | ||
1318 | udf_release_data(nfibh.sbh); | ||
1319 | } | ||
1320 | unlock_kernel(); | ||
1321 | return retval; | ||
1322 | } | ||
1323 | |||
1324 | struct inode_operations udf_dir_inode_operations = { | ||
1325 | .lookup = udf_lookup, | ||
1326 | .create = udf_create, | ||
1327 | .link = udf_link, | ||
1328 | .unlink = udf_unlink, | ||
1329 | .symlink = udf_symlink, | ||
1330 | .mkdir = udf_mkdir, | ||
1331 | .rmdir = udf_rmdir, | ||
1332 | .mknod = udf_mknod, | ||
1333 | .rename = udf_rename, | ||
1334 | }; | ||
diff --git a/fs/udf/osta_udf.h b/fs/udf/osta_udf.h new file mode 100644 index 000000000000..e82aae652697 --- /dev/null +++ b/fs/udf/osta_udf.h | |||
@@ -0,0 +1,296 @@ | |||
1 | /* | ||
2 | * osta_udf.h | ||
3 | * | ||
4 | * This file is based on OSTA UDF(tm) 2.50 (April 30, 2003) | ||
5 | * http://www.osta.org | ||
6 | * | ||
7 | * Copyright (c) 2001-2004 Ben Fennema <bfennema@falcon.csc.calpoly.edu> | ||
8 | * All rights reserved. | ||
9 | * | ||
10 | * Redistribution and use in source and binary forms, with or without | ||
11 | * modification, are permitted provided that the following conditions | ||
12 | * are met: | ||
13 | * 1. Redistributions of source code must retain the above copyright | ||
14 | * notice, this list of conditions, and the following disclaimer, | ||
15 | * without modification. | ||
16 | * 2. The name of the author may not be used to endorse or promote products | ||
17 | * derived from this software without specific prior written permission. | ||
18 | * | ||
19 | * Alternatively, this software may be distributed under the terms of the | ||
20 | * GNU Public License ("GPL"). | ||
21 | * | ||
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | ||
23 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR | ||
26 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
27 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||
28 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||
29 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||
31 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||
32 | * SUCH DAMAGE. | ||
33 | */ | ||
34 | |||
35 | #include "ecma_167.h" | ||
36 | |||
37 | #ifndef _OSTA_UDF_H | ||
38 | #define _OSTA_UDF_H 1 | ||
39 | |||
40 | /* OSTA CS0 Charspec (UDF 2.50 2.1.2) */ | ||
41 | #define UDF_CHAR_SET_TYPE 0 | ||
42 | #define UDF_CHAR_SET_INFO "OSTA Compressed Unicode" | ||
43 | |||
44 | /* Entity Identifier (UDF 2.50 2.1.5) */ | ||
45 | /* Identifiers (UDF 2.50 2.1.5.2) */ | ||
46 | #define UDF_ID_DEVELOPER "*Linux UDFFS" | ||
47 | #define UDF_ID_COMPLIANT "*OSTA UDF Compliant" | ||
48 | #define UDF_ID_LV_INFO "*UDF LV Info" | ||
49 | #define UDF_ID_FREE_EA "*UDF FreeEASpace" | ||
50 | #define UDF_ID_FREE_APP_EA "*UDF FreeAppEASpace" | ||
51 | #define UDF_ID_DVD_CGMS "*UDF DVD CGMS Info" | ||
52 | #define UDF_ID_OS2_EA "*UDF OS/2 EA" | ||
53 | #define UDF_ID_OS2_EA_LENGTH "*UDF OS/2 EALength" | ||
54 | #define UDF_ID_MAC_VOLUME "*UDF Mac VolumeInfo" | ||
55 | #define UDF_ID_MAC_FINDER "*UDF Mac FinderInfo" | ||
56 | #define UDF_ID_MAC_UNIQUE "*UDF Mac UniqueIDTable" | ||
57 | #define UDF_ID_MAC_RESOURCE "*UDF Mac ResourceFork" | ||
58 | #define UDF_ID_VIRTUAL "*UDF Virtual Partition" | ||
59 | #define UDF_ID_SPARABLE "*UDF Sparable Partition" | ||
60 | #define UDF_ID_ALLOC "*UDF Virtual Alloc Tbl" | ||
61 | #define UDF_ID_SPARING "*UDF Sparing Table" | ||
62 | #define UDF_ID_METADATA "*UDF Metadata Partition" | ||
63 | |||
64 | /* Identifier Suffix (UDF 2.50 2.1.5.3) */ | ||
65 | #define IS_DF_HARD_WRITE_PROTECT 0x01 | ||
66 | #define IS_DF_SOFT_WRITE_PROTECT 0x02 | ||
67 | |||
68 | struct UDFIdentSuffix | ||
69 | { | ||
70 | __le16 UDFRevision; | ||
71 | uint8_t OSClass; | ||
72 | uint8_t OSIdentifier; | ||
73 | uint8_t reserved[4]; | ||
74 | } __attribute__ ((packed)); | ||
75 | |||
76 | struct impIdentSuffix | ||
77 | { | ||
78 | uint8_t OSClass; | ||
79 | uint8_t OSIdentifier; | ||
80 | uint8_t reserved[6]; | ||
81 | } __attribute__ ((packed)); | ||
82 | |||
83 | struct appIdentSuffix | ||
84 | { | ||
85 | uint8_t impUse[8]; | ||
86 | } __attribute__ ((packed)); | ||
87 | |||
88 | /* Logical Volume Integrity Descriptor (UDF 2.50 2.2.6) */ | ||
89 | /* Implementation Use (UDF 2.50 2.2.6.4) */ | ||
90 | struct logicalVolIntegrityDescImpUse | ||
91 | { | ||
92 | regid impIdent; | ||
93 | __le32 numFiles; | ||
94 | __le32 numDirs; | ||
95 | __le16 minUDFReadRev; | ||
96 | __le16 minUDFWriteRev; | ||
97 | __le16 maxUDFWriteRev; | ||
98 | uint8_t impUse[0]; | ||
99 | } __attribute__ ((packed)); | ||
100 | |||
101 | /* Implementation Use Volume Descriptor (UDF 2.50 2.2.7) */ | ||
102 | /* Implementation Use (UDF 2.50 2.2.7.2) */ | ||
103 | struct impUseVolDescImpUse | ||
104 | { | ||
105 | charspec LVICharset; | ||
106 | dstring logicalVolIdent[128]; | ||
107 | dstring LVInfo1[36]; | ||
108 | dstring LVInfo2[36]; | ||
109 | dstring LVInfo3[36]; | ||
110 | regid impIdent; | ||
111 | uint8_t impUse[128]; | ||
112 | } __attribute__ ((packed)); | ||
113 | |||
114 | struct udfPartitionMap2 | ||
115 | { | ||
116 | uint8_t partitionMapType; | ||
117 | uint8_t partitionMapLength; | ||
118 | uint8_t reserved1[2]; | ||
119 | regid partIdent; | ||
120 | __le16 volSeqNum; | ||
121 | __le16 partitionNum; | ||
122 | } __attribute__ ((packed)); | ||
123 | |||
124 | /* Virtual Partition Map (UDF 2.50 2.2.8) */ | ||
125 | struct virtualPartitionMap | ||
126 | { | ||
127 | uint8_t partitionMapType; | ||
128 | uint8_t partitionMapLength; | ||
129 | uint8_t reserved1[2]; | ||
130 | regid partIdent; | ||
131 | __le16 volSeqNum; | ||
132 | __le16 partitionNum; | ||
133 | uint8_t reserved2[24]; | ||
134 | } __attribute__ ((packed)); | ||
135 | |||
136 | /* Sparable Partition Map (UDF 2.50 2.2.9) */ | ||
137 | struct sparablePartitionMap | ||
138 | { | ||
139 | uint8_t partitionMapType; | ||
140 | uint8_t partitionMapLength; | ||
141 | uint8_t reserved1[2]; | ||
142 | regid partIdent; | ||
143 | __le16 volSeqNum; | ||
144 | __le16 partitionNum; | ||
145 | __le16 packetLength; | ||
146 | uint8_t numSparingTables; | ||
147 | uint8_t reserved2[1]; | ||
148 | __le32 sizeSparingTable; | ||
149 | __le32 locSparingTable[4]; | ||
150 | } __attribute__ ((packed)); | ||
151 | |||
152 | /* Metadata Partition Map (UDF 2.4.0 2.2.10) */ | ||
153 | struct metadataPartitionMap | ||
154 | { | ||
155 | uint8_t partitionMapType; | ||
156 | uint8_t partitionMapLength; | ||
157 | uint8_t reserved1[2]; | ||
158 | regid partIdent; | ||
159 | __le16 volSeqNum; | ||
160 | __le16 partitionNum; | ||
161 | __le32 metadataFileLoc; | ||
162 | __le32 metadataMirrorFileLoc; | ||
163 | __le32 metadataBitmapFileLoc; | ||
164 | __le32 allocUnitSize; | ||
165 | __le16 alignUnitSize; | ||
166 | uint8_t flags; | ||
167 | uint8_t reserved2[5]; | ||
168 | } __attribute__ ((packed)); | ||
169 | |||
170 | /* Virtual Allocation Table (UDF 1.5 2.2.10) */ | ||
171 | struct virtualAllocationTable15 | ||
172 | { | ||
173 | __le32 VirtualSector[0]; | ||
174 | regid vatIdent; | ||
175 | __le32 previousVATICBLoc; | ||
176 | } __attribute__ ((packed)); | ||
177 | |||
178 | #define ICBTAG_FILE_TYPE_VAT15 0x00U | ||
179 | |||
180 | /* Virtual Allocation Table (UDF 2.50 2.2.11) */ | ||
181 | struct virtualAllocationTable20 | ||
182 | { | ||
183 | __le16 lengthHeader; | ||
184 | __le16 lengthImpUse; | ||
185 | dstring logicalVolIdent[128]; | ||
186 | __le32 previousVATICBLoc; | ||
187 | __le32 numFiles; | ||
188 | __le32 numDirs; | ||
189 | __le16 minReadRevision; | ||
190 | __le16 minWriteRevision; | ||
191 | __le16 maxWriteRevision; | ||
192 | __le16 reserved; | ||
193 | uint8_t impUse[0]; | ||
194 | __le32 vatEntry[0]; | ||
195 | } __attribute__ ((packed)); | ||
196 | |||
197 | #define ICBTAG_FILE_TYPE_VAT20 0xF8U | ||
198 | |||
199 | /* Sparing Table (UDF 2.50 2.2.12) */ | ||
200 | struct sparingEntry | ||
201 | { | ||
202 | __le32 origLocation; | ||
203 | __le32 mappedLocation; | ||
204 | } __attribute__ ((packed)); | ||
205 | |||
206 | struct sparingTable | ||
207 | { | ||
208 | tag descTag; | ||
209 | regid sparingIdent; | ||
210 | __le16 reallocationTableLen; | ||
211 | __le16 reserved; | ||
212 | __le32 sequenceNum; | ||
213 | struct sparingEntry | ||
214 | mapEntry[0]; | ||
215 | } __attribute__ ((packed)); | ||
216 | |||
217 | /* Metadata File (and Metadata Mirror File) (UDF 2.50 2.2.13.1) */ | ||
218 | #define ICBTAG_FILE_TYPE_MAIN 0xFA | ||
219 | #define ICBTAG_FILE_TYPE_MIRROR 0xFB | ||
220 | #define ICBTAG_FILE_TYPE_BITMAP 0xFC | ||
221 | |||
222 | /* struct long_ad ICB - ADImpUse (UDF 2.50 2.2.4.3) */ | ||
223 | struct allocDescImpUse | ||
224 | { | ||
225 | __le16 flags; | ||
226 | uint8_t impUse[4]; | ||
227 | } __attribute__ ((packed)); | ||
228 | |||
229 | #define AD_IU_EXT_ERASED 0x0001 | ||
230 | |||
231 | /* Real-Time Files (UDF 2.50 6.11) */ | ||
232 | #define ICBTAG_FILE_TYPE_REALTIME 0xF9U | ||
233 | |||
234 | /* Implementation Use Extended Attribute (UDF 2.50 3.3.4.5) */ | ||
235 | /* FreeEASpace (UDF 2.50 3.3.4.5.1.1) */ | ||
236 | struct freeEaSpace | ||
237 | { | ||
238 | __le16 headerChecksum; | ||
239 | uint8_t freeEASpace[0]; | ||
240 | } __attribute__ ((packed)); | ||
241 | |||
242 | /* DVD Copyright Management Information (UDF 2.50 3.3.4.5.1.2) */ | ||
243 | struct DVDCopyrightImpUse | ||
244 | { | ||
245 | __le16 headerChecksum; | ||
246 | uint8_t CGMSInfo; | ||
247 | uint8_t dataType; | ||
248 | uint8_t protectionSystemInfo[4]; | ||
249 | } __attribute__ ((packed)); | ||
250 | |||
251 | /* Application Use Extended Attribute (UDF 2.50 3.3.4.6) */ | ||
252 | /* FreeAppEASpace (UDF 2.50 3.3.4.6.1) */ | ||
253 | struct freeAppEASpace | ||
254 | { | ||
255 | __le16 headerChecksum; | ||
256 | uint8_t freeEASpace[0]; | ||
257 | } __attribute__ ((packed)); | ||
258 | |||
259 | /* UDF Defined System Stream (UDF 2.50 3.3.7) */ | ||
260 | #define UDF_ID_UNIQUE_ID "*UDF Unique ID Mapping Data" | ||
261 | #define UDF_ID_NON_ALLOC "*UDF Non-Allocatable Space" | ||
262 | #define UDF_ID_POWER_CAL "*UDF Power Cal Table" | ||
263 | #define UDF_ID_BACKUP "*UDF Backup" | ||
264 | |||
265 | /* Operating System Identifiers (UDF 2.50 6.3) */ | ||
266 | #define UDF_OS_CLASS_UNDEF 0x00U | ||
267 | #define UDF_OS_CLASS_DOS 0x01U | ||
268 | #define UDF_OS_CLASS_OS2 0x02U | ||
269 | #define UDF_OS_CLASS_MAC 0x03U | ||
270 | #define UDF_OS_CLASS_UNIX 0x04U | ||
271 | #define UDF_OS_CLASS_WIN9X 0x05U | ||
272 | #define UDF_OS_CLASS_WINNT 0x06U | ||
273 | #define UDF_OS_CLASS_OS400 0x07U | ||
274 | #define UDF_OS_CLASS_BEOS 0x08U | ||
275 | #define UDF_OS_CLASS_WINCE 0x09U | ||
276 | |||
277 | #define UDF_OS_ID_UNDEF 0x00U | ||
278 | #define UDF_OS_ID_DOS 0x00U | ||
279 | #define UDF_OS_ID_OS2 0x00U | ||
280 | #define UDF_OS_ID_MAC 0x00U | ||
281 | #define UDF_OS_ID_MAX_OSX 0x01U | ||
282 | #define UDF_OS_ID_UNIX 0x00U | ||
283 | #define UDF_OS_ID_AIX 0x01U | ||
284 | #define UDF_OS_ID_SOLARIS 0x02U | ||
285 | #define UDF_OS_ID_HPUX 0x03U | ||
286 | #define UDF_OS_ID_IRIX 0x04U | ||
287 | #define UDF_OS_ID_LINUX 0x05U | ||
288 | #define UDF_OS_ID_MKLINUX 0x06U | ||
289 | #define UDF_OS_ID_FREEBSD 0x07U | ||
290 | #define UDF_OS_ID_WIN9X 0x00U | ||
291 | #define UDF_OS_ID_WINNT 0x00U | ||
292 | #define UDF_OS_ID_OS400 0x00U | ||
293 | #define UDF_OS_ID_BEOS 0x00U | ||
294 | #define UDF_OS_ID_WINCE 0x00U | ||
295 | |||
296 | #endif /* _OSTA_UDF_H */ | ||
diff --git a/fs/udf/partition.c b/fs/udf/partition.c new file mode 100644 index 000000000000..4d36f264be0d --- /dev/null +++ b/fs/udf/partition.c | |||
@@ -0,0 +1,226 @@ | |||
1 | /* | ||
2 | * partition.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Partition handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-2001 Ben Fennema | ||
19 | * | ||
20 | * HISTORY | ||
21 | * | ||
22 | * 12/06/98 blf Created file. | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "udfdecl.h" | ||
27 | #include "udf_sb.h" | ||
28 | #include "udf_i.h" | ||
29 | |||
30 | #include <linux/fs.h> | ||
31 | #include <linux/string.h> | ||
32 | #include <linux/udf_fs.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/buffer_head.h> | ||
35 | |||
36 | inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) | ||
37 | { | ||
38 | if (partition >= UDF_SB_NUMPARTS(sb)) | ||
39 | { | ||
40 | udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n", | ||
41 | block, partition, offset); | ||
42 | return 0xFFFFFFFF; | ||
43 | } | ||
44 | if (UDF_SB_PARTFUNC(sb, partition)) | ||
45 | return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset); | ||
46 | else | ||
47 | return UDF_SB_PARTROOT(sb, partition) + block + offset; | ||
48 | } | ||
49 | |||
50 | uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) | ||
51 | { | ||
52 | struct buffer_head *bh = NULL; | ||
53 | uint32_t newblock; | ||
54 | uint32_t index; | ||
55 | uint32_t loc; | ||
56 | |||
57 | index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t); | ||
58 | |||
59 | if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries) | ||
60 | { | ||
61 | udf_debug("Trying to access block beyond end of VAT (%d max %d)\n", | ||
62 | block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries); | ||
63 | return 0xFFFFFFFF; | ||
64 | } | ||
65 | |||
66 | if (block >= index) | ||
67 | { | ||
68 | block -= index; | ||
69 | newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t))); | ||
70 | index = block % (sb->s_blocksize / sizeof(uint32_t)); | ||
71 | } | ||
72 | else | ||
73 | { | ||
74 | newblock = 0; | ||
75 | index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block; | ||
76 | } | ||
77 | |||
78 | loc = udf_block_map(UDF_SB_VAT(sb), newblock); | ||
79 | |||
80 | if (!(bh = sb_bread(sb, loc))) | ||
81 | { | ||
82 | udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n", | ||
83 | sb, block, partition, loc, index); | ||
84 | return 0xFFFFFFFF; | ||
85 | } | ||
86 | |||
87 | loc = le32_to_cpu(((__le32 *)bh->b_data)[index]); | ||
88 | |||
89 | udf_release_data(bh); | ||
90 | |||
91 | if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition) | ||
92 | { | ||
93 | udf_debug("recursive call to udf_get_pblock!\n"); | ||
94 | return 0xFFFFFFFF; | ||
95 | } | ||
96 | |||
97 | return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset); | ||
98 | } | ||
99 | |||
100 | inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) | ||
101 | { | ||
102 | return udf_get_pblock_virt15(sb, block, partition, offset); | ||
103 | } | ||
104 | |||
105 | uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset) | ||
106 | { | ||
107 | int i; | ||
108 | struct sparingTable *st = NULL; | ||
109 | uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1); | ||
110 | |||
111 | for (i=0; i<4; i++) | ||
112 | { | ||
113 | if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL) | ||
114 | { | ||
115 | st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data; | ||
116 | break; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | if (st) | ||
121 | { | ||
122 | for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++) | ||
123 | { | ||
124 | if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0) | ||
125 | break; | ||
126 | else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet) | ||
127 | { | ||
128 | return le32_to_cpu(st->mapEntry[i].mappedLocation) + | ||
129 | ((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1)); | ||
130 | } | ||
131 | else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet) | ||
132 | break; | ||
133 | } | ||
134 | } | ||
135 | return UDF_SB_PARTROOT(sb,partition) + block + offset; | ||
136 | } | ||
137 | |||
138 | int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block) | ||
139 | { | ||
140 | struct udf_sparing_data *sdata; | ||
141 | struct sparingTable *st = NULL; | ||
142 | struct sparingEntry mapEntry; | ||
143 | uint32_t packet; | ||
144 | int i, j, k, l; | ||
145 | |||
146 | for (i=0; i<UDF_SB_NUMPARTS(sb); i++) | ||
147 | { | ||
148 | if (old_block > UDF_SB_PARTROOT(sb,i) && | ||
149 | old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i)) | ||
150 | { | ||
151 | sdata = &UDF_SB_TYPESPAR(sb,i); | ||
152 | packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1); | ||
153 | |||
154 | for (j=0; j<4; j++) | ||
155 | { | ||
156 | if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) | ||
157 | { | ||
158 | st = (struct sparingTable *)sdata->s_spar_map[j]->b_data; | ||
159 | break; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | if (!st) | ||
164 | return 1; | ||
165 | |||
166 | for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++) | ||
167 | { | ||
168 | if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF) | ||
169 | { | ||
170 | for (; j<4; j++) | ||
171 | { | ||
172 | if (sdata->s_spar_map[j]) | ||
173 | { | ||
174 | st = (struct sparingTable *)sdata->s_spar_map[j]->b_data; | ||
175 | st->mapEntry[k].origLocation = cpu_to_le32(packet); | ||
176 | udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry)); | ||
177 | mark_buffer_dirty(sdata->s_spar_map[j]); | ||
178 | } | ||
179 | } | ||
180 | *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) + | ||
181 | ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1)); | ||
182 | return 0; | ||
183 | } | ||
184 | else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet) | ||
185 | { | ||
186 | *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) + | ||
187 | ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1)); | ||
188 | return 0; | ||
189 | } | ||
190 | else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet) | ||
191 | break; | ||
192 | } | ||
193 | for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++) | ||
194 | { | ||
195 | if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF) | ||
196 | { | ||
197 | for (; j<4; j++) | ||
198 | { | ||
199 | if (sdata->s_spar_map[j]) | ||
200 | { | ||
201 | st = (struct sparingTable *)sdata->s_spar_map[j]->b_data; | ||
202 | mapEntry = st->mapEntry[l]; | ||
203 | mapEntry.origLocation = cpu_to_le32(packet); | ||
204 | memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry)); | ||
205 | st->mapEntry[k] = mapEntry; | ||
206 | udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry)); | ||
207 | mark_buffer_dirty(sdata->s_spar_map[j]); | ||
208 | } | ||
209 | } | ||
210 | *new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) + | ||
211 | ((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1)); | ||
212 | return 0; | ||
213 | } | ||
214 | } | ||
215 | return 1; | ||
216 | } | ||
217 | } | ||
218 | if (i == UDF_SB_NUMPARTS(sb)) | ||
219 | { | ||
220 | /* outside of partitions */ | ||
221 | /* for now, fail =) */ | ||
222 | return 1; | ||
223 | } | ||
224 | |||
225 | return 0; | ||
226 | } | ||
diff --git a/fs/udf/super.c b/fs/udf/super.c new file mode 100644 index 000000000000..15bd4f24c5b7 --- /dev/null +++ b/fs/udf/super.c | |||
@@ -0,0 +1,1934 @@ | |||
1 | /* | ||
2 | * super.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Super block routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * DESCRIPTION | ||
8 | * OSTA-UDF(tm) = Optical Storage Technology Association | ||
9 | * Universal Disk Format. | ||
10 | * | ||
11 | * This code is based on version 2.00 of the UDF specification, | ||
12 | * and revision 3 of the ECMA 167 standard [equivalent to ISO 13346]. | ||
13 | * http://www.osta.org/ | ||
14 | * http://www.ecma.ch/ | ||
15 | * http://www.iso.org/ | ||
16 | * | ||
17 | * CONTACTS | ||
18 | * E-mail regarding any portion of the Linux UDF file system should be | ||
19 | * directed to the development team mailing list (run by majordomo): | ||
20 | * linux_udf@hpesjro.fc.hp.com | ||
21 | * | ||
22 | * COPYRIGHT | ||
23 | * This file is distributed under the terms of the GNU General Public | ||
24 | * License (GPL). Copies of the GPL can be obtained from: | ||
25 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
26 | * Each contributing author retains all rights to their own work. | ||
27 | * | ||
28 | * (C) 1998 Dave Boynton | ||
29 | * (C) 1998-2004 Ben Fennema | ||
30 | * (C) 2000 Stelias Computing Inc | ||
31 | * | ||
32 | * HISTORY | ||
33 | * | ||
34 | * 09/24/98 dgb changed to allow compiling outside of kernel, and | ||
35 | * added some debugging. | ||
36 | * 10/01/98 dgb updated to allow (some) possibility of compiling w/2.0.34 | ||
37 | * 10/16/98 attempting some multi-session support | ||
38 | * 10/17/98 added freespace count for "df" | ||
39 | * 11/11/98 gr added novrs option | ||
40 | * 11/26/98 dgb added fileset,anchor mount options | ||
41 | * 12/06/98 blf really hosed things royally. vat/sparing support. sequenced vol descs | ||
42 | * rewrote option handling based on isofs | ||
43 | * 12/20/98 find the free space bitmap (if it exists) | ||
44 | */ | ||
45 | |||
46 | #include "udfdecl.h" | ||
47 | |||
48 | #include <linux/config.h> | ||
49 | #include <linux/blkdev.h> | ||
50 | #include <linux/slab.h> | ||
51 | #include <linux/kernel.h> | ||
52 | #include <linux/module.h> | ||
53 | #include <linux/parser.h> | ||
54 | #include <linux/stat.h> | ||
55 | #include <linux/cdrom.h> | ||
56 | #include <linux/nls.h> | ||
57 | #include <linux/smp_lock.h> | ||
58 | #include <linux/buffer_head.h> | ||
59 | #include <linux/vfs.h> | ||
60 | #include <linux/vmalloc.h> | ||
61 | #include <asm/byteorder.h> | ||
62 | |||
63 | #include <linux/udf_fs.h> | ||
64 | #include "udf_sb.h" | ||
65 | #include "udf_i.h" | ||
66 | |||
67 | #include <linux/init.h> | ||
68 | #include <asm/uaccess.h> | ||
69 | |||
70 | #define VDS_POS_PRIMARY_VOL_DESC 0 | ||
71 | #define VDS_POS_UNALLOC_SPACE_DESC 1 | ||
72 | #define VDS_POS_LOGICAL_VOL_DESC 2 | ||
73 | #define VDS_POS_PARTITION_DESC 3 | ||
74 | #define VDS_POS_IMP_USE_VOL_DESC 4 | ||
75 | #define VDS_POS_VOL_DESC_PTR 5 | ||
76 | #define VDS_POS_TERMINATING_DESC 6 | ||
77 | #define VDS_POS_LENGTH 7 | ||
78 | |||
79 | static char error_buf[1024]; | ||
80 | |||
81 | /* These are the "meat" - everything else is stuffing */ | ||
82 | static int udf_fill_super(struct super_block *, void *, int); | ||
83 | static void udf_put_super(struct super_block *); | ||
84 | static void udf_write_super(struct super_block *); | ||
85 | static int udf_remount_fs(struct super_block *, int *, char *); | ||
86 | static int udf_check_valid(struct super_block *, int, int); | ||
87 | static int udf_vrs(struct super_block *sb, int silent); | ||
88 | static int udf_load_partition(struct super_block *, kernel_lb_addr *); | ||
89 | static int udf_load_logicalvol(struct super_block *, struct buffer_head *, kernel_lb_addr *); | ||
90 | static void udf_load_logicalvolint(struct super_block *, kernel_extent_ad); | ||
91 | static void udf_find_anchor(struct super_block *); | ||
92 | static int udf_find_fileset(struct super_block *, kernel_lb_addr *, kernel_lb_addr *); | ||
93 | static void udf_load_pvoldesc(struct super_block *, struct buffer_head *); | ||
94 | static void udf_load_fileset(struct super_block *, struct buffer_head *, kernel_lb_addr *); | ||
95 | static void udf_load_partdesc(struct super_block *, struct buffer_head *); | ||
96 | static void udf_open_lvid(struct super_block *); | ||
97 | static void udf_close_lvid(struct super_block *); | ||
98 | static unsigned int udf_count_free(struct super_block *); | ||
99 | static int udf_statfs(struct super_block *, struct kstatfs *); | ||
100 | |||
101 | /* UDF filesystem type */ | ||
102 | static struct super_block *udf_get_sb(struct file_system_type *fs_type, | ||
103 | int flags, const char *dev_name, void *data) | ||
104 | { | ||
105 | return get_sb_bdev(fs_type, flags, dev_name, data, udf_fill_super); | ||
106 | } | ||
107 | |||
108 | static struct file_system_type udf_fstype = { | ||
109 | .owner = THIS_MODULE, | ||
110 | .name = "udf", | ||
111 | .get_sb = udf_get_sb, | ||
112 | .kill_sb = kill_block_super, | ||
113 | .fs_flags = FS_REQUIRES_DEV, | ||
114 | }; | ||
115 | |||
116 | static kmem_cache_t * udf_inode_cachep; | ||
117 | |||
118 | static struct inode *udf_alloc_inode(struct super_block *sb) | ||
119 | { | ||
120 | struct udf_inode_info *ei; | ||
121 | ei = (struct udf_inode_info *)kmem_cache_alloc(udf_inode_cachep, SLAB_KERNEL); | ||
122 | if (!ei) | ||
123 | return NULL; | ||
124 | return &ei->vfs_inode; | ||
125 | } | ||
126 | |||
127 | static void udf_destroy_inode(struct inode *inode) | ||
128 | { | ||
129 | kmem_cache_free(udf_inode_cachep, UDF_I(inode)); | ||
130 | } | ||
131 | |||
132 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | ||
133 | { | ||
134 | struct udf_inode_info *ei = (struct udf_inode_info *) foo; | ||
135 | |||
136 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | ||
137 | SLAB_CTOR_CONSTRUCTOR) | ||
138 | { | ||
139 | ei->i_ext.i_data = NULL; | ||
140 | inode_init_once(&ei->vfs_inode); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | static int init_inodecache(void) | ||
145 | { | ||
146 | udf_inode_cachep = kmem_cache_create("udf_inode_cache", | ||
147 | sizeof(struct udf_inode_info), | ||
148 | 0, SLAB_RECLAIM_ACCOUNT, | ||
149 | init_once, NULL); | ||
150 | if (udf_inode_cachep == NULL) | ||
151 | return -ENOMEM; | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static void destroy_inodecache(void) | ||
156 | { | ||
157 | if (kmem_cache_destroy(udf_inode_cachep)) | ||
158 | printk(KERN_INFO "udf_inode_cache: not all structures were freed\n"); | ||
159 | } | ||
160 | |||
161 | /* Superblock operations */ | ||
162 | static struct super_operations udf_sb_ops = { | ||
163 | .alloc_inode = udf_alloc_inode, | ||
164 | .destroy_inode = udf_destroy_inode, | ||
165 | .write_inode = udf_write_inode, | ||
166 | .delete_inode = udf_delete_inode, | ||
167 | .clear_inode = udf_clear_inode, | ||
168 | .put_super = udf_put_super, | ||
169 | .write_super = udf_write_super, | ||
170 | .statfs = udf_statfs, | ||
171 | .remount_fs = udf_remount_fs, | ||
172 | }; | ||
173 | |||
174 | struct udf_options | ||
175 | { | ||
176 | unsigned char novrs; | ||
177 | unsigned int blocksize; | ||
178 | unsigned int session; | ||
179 | unsigned int lastblock; | ||
180 | unsigned int anchor; | ||
181 | unsigned int volume; | ||
182 | unsigned short partition; | ||
183 | unsigned int fileset; | ||
184 | unsigned int rootdir; | ||
185 | unsigned int flags; | ||
186 | mode_t umask; | ||
187 | gid_t gid; | ||
188 | uid_t uid; | ||
189 | struct nls_table *nls_map; | ||
190 | }; | ||
191 | |||
192 | static int __init init_udf_fs(void) | ||
193 | { | ||
194 | int err; | ||
195 | err = init_inodecache(); | ||
196 | if (err) | ||
197 | goto out1; | ||
198 | err = register_filesystem(&udf_fstype); | ||
199 | if (err) | ||
200 | goto out; | ||
201 | return 0; | ||
202 | out: | ||
203 | destroy_inodecache(); | ||
204 | out1: | ||
205 | return err; | ||
206 | } | ||
207 | |||
208 | static void __exit exit_udf_fs(void) | ||
209 | { | ||
210 | unregister_filesystem(&udf_fstype); | ||
211 | destroy_inodecache(); | ||
212 | } | ||
213 | |||
214 | module_init(init_udf_fs) | ||
215 | module_exit(exit_udf_fs) | ||
216 | |||
217 | /* | ||
218 | * udf_parse_options | ||
219 | * | ||
220 | * PURPOSE | ||
221 | * Parse mount options. | ||
222 | * | ||
223 | * DESCRIPTION | ||
224 | * The following mount options are supported: | ||
225 | * | ||
226 | * gid= Set the default group. | ||
227 | * umask= Set the default umask. | ||
228 | * uid= Set the default user. | ||
229 | * bs= Set the block size. | ||
230 | * unhide Show otherwise hidden files. | ||
231 | * undelete Show deleted files in lists. | ||
232 | * adinicb Embed data in the inode (default) | ||
233 | * noadinicb Don't embed data in the inode | ||
234 | * shortad Use short ad's | ||
235 | * longad Use long ad's (default) | ||
236 | * nostrict Unset strict conformance | ||
237 | * iocharset= Set the NLS character set | ||
238 | * | ||
239 | * The remaining are for debugging and disaster recovery: | ||
240 | * | ||
241 | * novrs Skip volume sequence recognition | ||
242 | * | ||
243 | * The following expect a offset from 0. | ||
244 | * | ||
245 | * session= Set the CDROM session (default= last session) | ||
246 | * anchor= Override standard anchor location. (default= 256) | ||
247 | * volume= Override the VolumeDesc location. (unused) | ||
248 | * partition= Override the PartitionDesc location. (unused) | ||
249 | * lastblock= Set the last block of the filesystem/ | ||
250 | * | ||
251 | * The following expect a offset from the partition root. | ||
252 | * | ||
253 | * fileset= Override the fileset block location. (unused) | ||
254 | * rootdir= Override the root directory location. (unused) | ||
255 | * WARNING: overriding the rootdir to a non-directory may | ||
256 | * yield highly unpredictable results. | ||
257 | * | ||
258 | * PRE-CONDITIONS | ||
259 | * options Pointer to mount options string. | ||
260 | * uopts Pointer to mount options variable. | ||
261 | * | ||
262 | * POST-CONDITIONS | ||
263 | * <return> 1 Mount options parsed okay. | ||
264 | * <return> 0 Error parsing mount options. | ||
265 | * | ||
266 | * HISTORY | ||
267 | * July 1, 1997 - Andrew E. Mileski | ||
268 | * Written, tested, and released. | ||
269 | */ | ||
270 | |||
271 | enum { | ||
272 | Opt_novrs, Opt_nostrict, Opt_bs, Opt_unhide, Opt_undelete, | ||
273 | Opt_noadinicb, Opt_adinicb, Opt_shortad, Opt_longad, | ||
274 | Opt_gid, Opt_uid, Opt_umask, Opt_session, Opt_lastblock, | ||
275 | Opt_anchor, Opt_volume, Opt_partition, Opt_fileset, | ||
276 | Opt_rootdir, Opt_utf8, Opt_iocharset, | ||
277 | Opt_err | ||
278 | }; | ||
279 | |||
280 | static match_table_t tokens = { | ||
281 | {Opt_novrs, "novrs"}, | ||
282 | {Opt_nostrict, "nostrict"}, | ||
283 | {Opt_bs, "bs=%u"}, | ||
284 | {Opt_unhide, "unhide"}, | ||
285 | {Opt_undelete, "undelete"}, | ||
286 | {Opt_noadinicb, "noadinicb"}, | ||
287 | {Opt_adinicb, "adinicb"}, | ||
288 | {Opt_shortad, "shortad"}, | ||
289 | {Opt_longad, "longad"}, | ||
290 | {Opt_gid, "gid=%u"}, | ||
291 | {Opt_uid, "uid=%u"}, | ||
292 | {Opt_umask, "umask=%o"}, | ||
293 | {Opt_session, "session=%u"}, | ||
294 | {Opt_lastblock, "lastblock=%u"}, | ||
295 | {Opt_anchor, "anchor=%u"}, | ||
296 | {Opt_volume, "volume=%u"}, | ||
297 | {Opt_partition, "partition=%u"}, | ||
298 | {Opt_fileset, "fileset=%u"}, | ||
299 | {Opt_rootdir, "rootdir=%u"}, | ||
300 | {Opt_utf8, "utf8"}, | ||
301 | {Opt_iocharset, "iocharset=%s"}, | ||
302 | {Opt_err, NULL} | ||
303 | }; | ||
304 | |||
305 | static int | ||
306 | udf_parse_options(char *options, struct udf_options *uopt) | ||
307 | { | ||
308 | char *p; | ||
309 | int option; | ||
310 | |||
311 | uopt->novrs = 0; | ||
312 | uopt->blocksize = 2048; | ||
313 | uopt->partition = 0xFFFF; | ||
314 | uopt->session = 0xFFFFFFFF; | ||
315 | uopt->lastblock = 0; | ||
316 | uopt->anchor = 0; | ||
317 | uopt->volume = 0xFFFFFFFF; | ||
318 | uopt->rootdir = 0xFFFFFFFF; | ||
319 | uopt->fileset = 0xFFFFFFFF; | ||
320 | uopt->nls_map = NULL; | ||
321 | |||
322 | if (!options) | ||
323 | return 1; | ||
324 | |||
325 | while ((p = strsep(&options, ",")) != NULL) | ||
326 | { | ||
327 | substring_t args[MAX_OPT_ARGS]; | ||
328 | int token; | ||
329 | if (!*p) | ||
330 | continue; | ||
331 | |||
332 | token = match_token(p, tokens, args); | ||
333 | switch (token) | ||
334 | { | ||
335 | case Opt_novrs: | ||
336 | uopt->novrs = 1; | ||
337 | case Opt_bs: | ||
338 | if (match_int(&args[0], &option)) | ||
339 | return 0; | ||
340 | uopt->blocksize = option; | ||
341 | break; | ||
342 | case Opt_unhide: | ||
343 | uopt->flags |= (1 << UDF_FLAG_UNHIDE); | ||
344 | break; | ||
345 | case Opt_undelete: | ||
346 | uopt->flags |= (1 << UDF_FLAG_UNDELETE); | ||
347 | break; | ||
348 | case Opt_noadinicb: | ||
349 | uopt->flags &= ~(1 << UDF_FLAG_USE_AD_IN_ICB); | ||
350 | break; | ||
351 | case Opt_adinicb: | ||
352 | uopt->flags |= (1 << UDF_FLAG_USE_AD_IN_ICB); | ||
353 | break; | ||
354 | case Opt_shortad: | ||
355 | uopt->flags |= (1 << UDF_FLAG_USE_SHORT_AD); | ||
356 | break; | ||
357 | case Opt_longad: | ||
358 | uopt->flags &= ~(1 << UDF_FLAG_USE_SHORT_AD); | ||
359 | break; | ||
360 | case Opt_gid: | ||
361 | if (match_int(args, &option)) | ||
362 | return 0; | ||
363 | uopt->gid = option; | ||
364 | break; | ||
365 | case Opt_uid: | ||
366 | if (match_int(args, &option)) | ||
367 | return 0; | ||
368 | uopt->uid = option; | ||
369 | break; | ||
370 | case Opt_umask: | ||
371 | if (match_octal(args, &option)) | ||
372 | return 0; | ||
373 | uopt->umask = option; | ||
374 | break; | ||
375 | case Opt_nostrict: | ||
376 | uopt->flags &= ~(1 << UDF_FLAG_STRICT); | ||
377 | break; | ||
378 | case Opt_session: | ||
379 | if (match_int(args, &option)) | ||
380 | return 0; | ||
381 | uopt->session = option; | ||
382 | break; | ||
383 | case Opt_lastblock: | ||
384 | if (match_int(args, &option)) | ||
385 | return 0; | ||
386 | uopt->lastblock = option; | ||
387 | break; | ||
388 | case Opt_anchor: | ||
389 | if (match_int(args, &option)) | ||
390 | return 0; | ||
391 | uopt->anchor = option; | ||
392 | break; | ||
393 | case Opt_volume: | ||
394 | if (match_int(args, &option)) | ||
395 | return 0; | ||
396 | uopt->volume = option; | ||
397 | break; | ||
398 | case Opt_partition: | ||
399 | if (match_int(args, &option)) | ||
400 | return 0; | ||
401 | uopt->partition = option; | ||
402 | break; | ||
403 | case Opt_fileset: | ||
404 | if (match_int(args, &option)) | ||
405 | return 0; | ||
406 | uopt->fileset = option; | ||
407 | break; | ||
408 | case Opt_rootdir: | ||
409 | if (match_int(args, &option)) | ||
410 | return 0; | ||
411 | uopt->rootdir = option; | ||
412 | break; | ||
413 | case Opt_utf8: | ||
414 | uopt->flags |= (1 << UDF_FLAG_UTF8); | ||
415 | break; | ||
416 | #ifdef CONFIG_UDF_NLS | ||
417 | case Opt_iocharset: | ||
418 | uopt->nls_map = load_nls(args[0].from); | ||
419 | uopt->flags |= (1 << UDF_FLAG_NLS_MAP); | ||
420 | break; | ||
421 | #endif | ||
422 | default: | ||
423 | printk(KERN_ERR "udf: bad mount option \"%s\" " | ||
424 | "or missing value\n", p); | ||
425 | return 0; | ||
426 | } | ||
427 | } | ||
428 | return 1; | ||
429 | } | ||
430 | |||
431 | void | ||
432 | udf_write_super(struct super_block *sb) | ||
433 | { | ||
434 | lock_kernel(); | ||
435 | if (!(sb->s_flags & MS_RDONLY)) | ||
436 | udf_open_lvid(sb); | ||
437 | sb->s_dirt = 0; | ||
438 | unlock_kernel(); | ||
439 | } | ||
440 | |||
441 | static int | ||
442 | udf_remount_fs(struct super_block *sb, int *flags, char *options) | ||
443 | { | ||
444 | struct udf_options uopt; | ||
445 | |||
446 | uopt.flags = UDF_SB(sb)->s_flags ; | ||
447 | uopt.uid = UDF_SB(sb)->s_uid ; | ||
448 | uopt.gid = UDF_SB(sb)->s_gid ; | ||
449 | uopt.umask = UDF_SB(sb)->s_umask ; | ||
450 | |||
451 | if ( !udf_parse_options(options, &uopt) ) | ||
452 | return -EINVAL; | ||
453 | |||
454 | UDF_SB(sb)->s_flags = uopt.flags; | ||
455 | UDF_SB(sb)->s_uid = uopt.uid; | ||
456 | UDF_SB(sb)->s_gid = uopt.gid; | ||
457 | UDF_SB(sb)->s_umask = uopt.umask; | ||
458 | |||
459 | if (UDF_SB_LVIDBH(sb)) { | ||
460 | int write_rev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev); | ||
461 | if (write_rev > UDF_MAX_WRITE_VERSION) | ||
462 | *flags |= MS_RDONLY; | ||
463 | } | ||
464 | |||
465 | if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) | ||
466 | return 0; | ||
467 | if (*flags & MS_RDONLY) | ||
468 | udf_close_lvid(sb); | ||
469 | else | ||
470 | udf_open_lvid(sb); | ||
471 | |||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | /* | ||
476 | * udf_set_blocksize | ||
477 | * | ||
478 | * PURPOSE | ||
479 | * Set the block size to be used in all transfers. | ||
480 | * | ||
481 | * DESCRIPTION | ||
482 | * To allow room for a DMA transfer, it is best to guess big when unsure. | ||
483 | * This routine picks 2048 bytes as the blocksize when guessing. This | ||
484 | * should be adequate until devices with larger block sizes become common. | ||
485 | * | ||
486 | * Note that the Linux kernel can currently only deal with blocksizes of | ||
487 | * 512, 1024, 2048, 4096, and 8192 bytes. | ||
488 | * | ||
489 | * PRE-CONDITIONS | ||
490 | * sb Pointer to _locked_ superblock. | ||
491 | * | ||
492 | * POST-CONDITIONS | ||
493 | * sb->s_blocksize Blocksize. | ||
494 | * sb->s_blocksize_bits log2 of blocksize. | ||
495 | * <return> 0 Blocksize is valid. | ||
496 | * <return> 1 Blocksize is invalid. | ||
497 | * | ||
498 | * HISTORY | ||
499 | * July 1, 1997 - Andrew E. Mileski | ||
500 | * Written, tested, and released. | ||
501 | */ | ||
502 | static int | ||
503 | udf_set_blocksize(struct super_block *sb, int bsize) | ||
504 | { | ||
505 | if (!sb_min_blocksize(sb, bsize)) { | ||
506 | udf_debug("Bad block size (%d)\n", bsize); | ||
507 | printk(KERN_ERR "udf: bad block size (%d)\n", bsize); | ||
508 | return 0; | ||
509 | } | ||
510 | return sb->s_blocksize; | ||
511 | } | ||
512 | |||
513 | static int | ||
514 | udf_vrs(struct super_block *sb, int silent) | ||
515 | { | ||
516 | struct volStructDesc *vsd = NULL; | ||
517 | int sector = 32768; | ||
518 | int sectorsize; | ||
519 | struct buffer_head *bh = NULL; | ||
520 | int iso9660=0; | ||
521 | int nsr02=0; | ||
522 | int nsr03=0; | ||
523 | |||
524 | /* Block size must be a multiple of 512 */ | ||
525 | if (sb->s_blocksize & 511) | ||
526 | return 0; | ||
527 | |||
528 | if (sb->s_blocksize < sizeof(struct volStructDesc)) | ||
529 | sectorsize = sizeof(struct volStructDesc); | ||
530 | else | ||
531 | sectorsize = sb->s_blocksize; | ||
532 | |||
533 | sector += (UDF_SB_SESSION(sb) << sb->s_blocksize_bits); | ||
534 | |||
535 | udf_debug("Starting at sector %u (%ld byte sectors)\n", | ||
536 | (sector >> sb->s_blocksize_bits), sb->s_blocksize); | ||
537 | /* Process the sequence (if applicable) */ | ||
538 | for (;!nsr02 && !nsr03; sector += sectorsize) | ||
539 | { | ||
540 | /* Read a block */ | ||
541 | bh = udf_tread(sb, sector >> sb->s_blocksize_bits); | ||
542 | if (!bh) | ||
543 | break; | ||
544 | |||
545 | /* Look for ISO descriptors */ | ||
546 | vsd = (struct volStructDesc *)(bh->b_data + | ||
547 | (sector & (sb->s_blocksize - 1))); | ||
548 | |||
549 | if (vsd->stdIdent[0] == 0) | ||
550 | { | ||
551 | udf_release_data(bh); | ||
552 | break; | ||
553 | } | ||
554 | else if (!strncmp(vsd->stdIdent, VSD_STD_ID_CD001, VSD_STD_ID_LEN)) | ||
555 | { | ||
556 | iso9660 = sector; | ||
557 | switch (vsd->structType) | ||
558 | { | ||
559 | case 0: | ||
560 | udf_debug("ISO9660 Boot Record found\n"); | ||
561 | break; | ||
562 | case 1: | ||
563 | udf_debug("ISO9660 Primary Volume Descriptor found\n"); | ||
564 | break; | ||
565 | case 2: | ||
566 | udf_debug("ISO9660 Supplementary Volume Descriptor found\n"); | ||
567 | break; | ||
568 | case 3: | ||
569 | udf_debug("ISO9660 Volume Partition Descriptor found\n"); | ||
570 | break; | ||
571 | case 255: | ||
572 | udf_debug("ISO9660 Volume Descriptor Set Terminator found\n"); | ||
573 | break; | ||
574 | default: | ||
575 | udf_debug("ISO9660 VRS (%u) found\n", vsd->structType); | ||
576 | break; | ||
577 | } | ||
578 | } | ||
579 | else if (!strncmp(vsd->stdIdent, VSD_STD_ID_BEA01, VSD_STD_ID_LEN)) | ||
580 | { | ||
581 | } | ||
582 | else if (!strncmp(vsd->stdIdent, VSD_STD_ID_TEA01, VSD_STD_ID_LEN)) | ||
583 | { | ||
584 | udf_release_data(bh); | ||
585 | break; | ||
586 | } | ||
587 | else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR02, VSD_STD_ID_LEN)) | ||
588 | { | ||
589 | nsr02 = sector; | ||
590 | } | ||
591 | else if (!strncmp(vsd->stdIdent, VSD_STD_ID_NSR03, VSD_STD_ID_LEN)) | ||
592 | { | ||
593 | nsr03 = sector; | ||
594 | } | ||
595 | udf_release_data(bh); | ||
596 | } | ||
597 | |||
598 | if (nsr03) | ||
599 | return nsr03; | ||
600 | else if (nsr02) | ||
601 | return nsr02; | ||
602 | else if (sector - (UDF_SB_SESSION(sb) << sb->s_blocksize_bits) == 32768) | ||
603 | return -1; | ||
604 | else | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | /* | ||
609 | * udf_find_anchor | ||
610 | * | ||
611 | * PURPOSE | ||
612 | * Find an anchor volume descriptor. | ||
613 | * | ||
614 | * PRE-CONDITIONS | ||
615 | * sb Pointer to _locked_ superblock. | ||
616 | * lastblock Last block on media. | ||
617 | * | ||
618 | * POST-CONDITIONS | ||
619 | * <return> 1 if not found, 0 if ok | ||
620 | * | ||
621 | * HISTORY | ||
622 | * July 1, 1997 - Andrew E. Mileski | ||
623 | * Written, tested, and released. | ||
624 | */ | ||
625 | static void | ||
626 | udf_find_anchor(struct super_block *sb) | ||
627 | { | ||
628 | int lastblock = UDF_SB_LASTBLOCK(sb); | ||
629 | struct buffer_head *bh = NULL; | ||
630 | uint16_t ident; | ||
631 | uint32_t location; | ||
632 | int i; | ||
633 | |||
634 | if (lastblock) | ||
635 | { | ||
636 | int varlastblock = udf_variable_to_fixed(lastblock); | ||
637 | int last[] = { lastblock, lastblock - 2, | ||
638 | lastblock - 150, lastblock - 152, | ||
639 | varlastblock, varlastblock - 2, | ||
640 | varlastblock - 150, varlastblock - 152 }; | ||
641 | |||
642 | lastblock = 0; | ||
643 | |||
644 | /* Search for an anchor volume descriptor pointer */ | ||
645 | |||
646 | /* according to spec, anchor is in either: | ||
647 | * block 256 | ||
648 | * lastblock-256 | ||
649 | * lastblock | ||
650 | * however, if the disc isn't closed, it could be 512 */ | ||
651 | |||
652 | for (i=0; (!lastblock && i<sizeof(last)/sizeof(int)); i++) | ||
653 | { | ||
654 | if (last[i] < 0 || !(bh = sb_bread(sb, last[i]))) | ||
655 | { | ||
656 | ident = location = 0; | ||
657 | } | ||
658 | else | ||
659 | { | ||
660 | ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); | ||
661 | location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); | ||
662 | udf_release_data(bh); | ||
663 | } | ||
664 | |||
665 | if (ident == TAG_IDENT_AVDP) | ||
666 | { | ||
667 | if (location == last[i] - UDF_SB_SESSION(sb)) | ||
668 | { | ||
669 | lastblock = UDF_SB_ANCHOR(sb)[0] = last[i] - UDF_SB_SESSION(sb); | ||
670 | UDF_SB_ANCHOR(sb)[1] = last[i] - 256 - UDF_SB_SESSION(sb); | ||
671 | } | ||
672 | else if (location == udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb)) | ||
673 | { | ||
674 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
675 | lastblock = UDF_SB_ANCHOR(sb)[0] = udf_variable_to_fixed(last[i]) - UDF_SB_SESSION(sb); | ||
676 | UDF_SB_ANCHOR(sb)[1] = lastblock - 256 - UDF_SB_SESSION(sb); | ||
677 | } | ||
678 | else | ||
679 | udf_debug("Anchor found at block %d, location mismatch %d.\n", | ||
680 | last[i], location); | ||
681 | } | ||
682 | else if (ident == TAG_IDENT_FE || ident == TAG_IDENT_EFE) | ||
683 | { | ||
684 | lastblock = last[i]; | ||
685 | UDF_SB_ANCHOR(sb)[3] = 512; | ||
686 | } | ||
687 | else | ||
688 | { | ||
689 | if (last[i] < 256 || !(bh = sb_bread(sb, last[i] - 256))) | ||
690 | { | ||
691 | ident = location = 0; | ||
692 | } | ||
693 | else | ||
694 | { | ||
695 | ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); | ||
696 | location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); | ||
697 | udf_release_data(bh); | ||
698 | } | ||
699 | |||
700 | if (ident == TAG_IDENT_AVDP && | ||
701 | location == last[i] - 256 - UDF_SB_SESSION(sb)) | ||
702 | { | ||
703 | lastblock = last[i]; | ||
704 | UDF_SB_ANCHOR(sb)[1] = last[i] - 256; | ||
705 | } | ||
706 | else | ||
707 | { | ||
708 | if (last[i] < 312 + UDF_SB_SESSION(sb) || !(bh = sb_bread(sb, last[i] - 312 - UDF_SB_SESSION(sb)))) | ||
709 | { | ||
710 | ident = location = 0; | ||
711 | } | ||
712 | else | ||
713 | { | ||
714 | ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); | ||
715 | location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); | ||
716 | udf_release_data(bh); | ||
717 | } | ||
718 | |||
719 | if (ident == TAG_IDENT_AVDP && | ||
720 | location == udf_variable_to_fixed(last[i]) - 256) | ||
721 | { | ||
722 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
723 | lastblock = udf_variable_to_fixed(last[i]); | ||
724 | UDF_SB_ANCHOR(sb)[1] = lastblock - 256; | ||
725 | } | ||
726 | } | ||
727 | } | ||
728 | } | ||
729 | } | ||
730 | |||
731 | if (!lastblock) | ||
732 | { | ||
733 | /* We havn't found the lastblock. check 312 */ | ||
734 | if ((bh = sb_bread(sb, 312 + UDF_SB_SESSION(sb)))) | ||
735 | { | ||
736 | ident = le16_to_cpu(((tag *)bh->b_data)->tagIdent); | ||
737 | location = le32_to_cpu(((tag *)bh->b_data)->tagLocation); | ||
738 | udf_release_data(bh); | ||
739 | |||
740 | if (ident == TAG_IDENT_AVDP && location == 256) | ||
741 | UDF_SET_FLAG(sb, UDF_FLAG_VARCONV); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++) | ||
746 | { | ||
747 | if (UDF_SB_ANCHOR(sb)[i]) | ||
748 | { | ||
749 | if (!(bh = udf_read_tagged(sb, | ||
750 | UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident))) | ||
751 | { | ||
752 | UDF_SB_ANCHOR(sb)[i] = 0; | ||
753 | } | ||
754 | else | ||
755 | { | ||
756 | udf_release_data(bh); | ||
757 | if ((ident != TAG_IDENT_AVDP) && (i || | ||
758 | (ident != TAG_IDENT_FE && ident != TAG_IDENT_EFE))) | ||
759 | { | ||
760 | UDF_SB_ANCHOR(sb)[i] = 0; | ||
761 | } | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | |||
766 | UDF_SB_LASTBLOCK(sb) = lastblock; | ||
767 | } | ||
768 | |||
769 | static int | ||
770 | udf_find_fileset(struct super_block *sb, kernel_lb_addr *fileset, kernel_lb_addr *root) | ||
771 | { | ||
772 | struct buffer_head *bh = NULL; | ||
773 | long lastblock; | ||
774 | uint16_t ident; | ||
775 | |||
776 | if (fileset->logicalBlockNum != 0xFFFFFFFF || | ||
777 | fileset->partitionReferenceNum != 0xFFFF) | ||
778 | { | ||
779 | bh = udf_read_ptagged(sb, *fileset, 0, &ident); | ||
780 | |||
781 | if (!bh) | ||
782 | return 1; | ||
783 | else if (ident != TAG_IDENT_FSD) | ||
784 | { | ||
785 | udf_release_data(bh); | ||
786 | return 1; | ||
787 | } | ||
788 | |||
789 | } | ||
790 | |||
791 | if (!bh) /* Search backwards through the partitions */ | ||
792 | { | ||
793 | kernel_lb_addr newfileset; | ||
794 | |||
795 | return 1; | ||
796 | |||
797 | for (newfileset.partitionReferenceNum=UDF_SB_NUMPARTS(sb)-1; | ||
798 | (newfileset.partitionReferenceNum != 0xFFFF && | ||
799 | fileset->logicalBlockNum == 0xFFFFFFFF && | ||
800 | fileset->partitionReferenceNum == 0xFFFF); | ||
801 | newfileset.partitionReferenceNum--) | ||
802 | { | ||
803 | lastblock = UDF_SB_PARTLEN(sb, newfileset.partitionReferenceNum); | ||
804 | newfileset.logicalBlockNum = 0; | ||
805 | |||
806 | do | ||
807 | { | ||
808 | bh = udf_read_ptagged(sb, newfileset, 0, &ident); | ||
809 | if (!bh) | ||
810 | { | ||
811 | newfileset.logicalBlockNum ++; | ||
812 | continue; | ||
813 | } | ||
814 | |||
815 | switch (ident) | ||
816 | { | ||
817 | case TAG_IDENT_SBD: | ||
818 | { | ||
819 | struct spaceBitmapDesc *sp; | ||
820 | sp = (struct spaceBitmapDesc *)bh->b_data; | ||
821 | newfileset.logicalBlockNum += 1 + | ||
822 | ((le32_to_cpu(sp->numOfBytes) + sizeof(struct spaceBitmapDesc) - 1) | ||
823 | >> sb->s_blocksize_bits); | ||
824 | udf_release_data(bh); | ||
825 | break; | ||
826 | } | ||
827 | case TAG_IDENT_FSD: | ||
828 | { | ||
829 | *fileset = newfileset; | ||
830 | break; | ||
831 | } | ||
832 | default: | ||
833 | { | ||
834 | newfileset.logicalBlockNum ++; | ||
835 | udf_release_data(bh); | ||
836 | bh = NULL; | ||
837 | break; | ||
838 | } | ||
839 | } | ||
840 | } | ||
841 | while (newfileset.logicalBlockNum < lastblock && | ||
842 | fileset->logicalBlockNum == 0xFFFFFFFF && | ||
843 | fileset->partitionReferenceNum == 0xFFFF); | ||
844 | } | ||
845 | } | ||
846 | |||
847 | if ((fileset->logicalBlockNum != 0xFFFFFFFF || | ||
848 | fileset->partitionReferenceNum != 0xFFFF) && bh) | ||
849 | { | ||
850 | udf_debug("Fileset at block=%d, partition=%d\n", | ||
851 | fileset->logicalBlockNum, fileset->partitionReferenceNum); | ||
852 | |||
853 | UDF_SB_PARTITION(sb) = fileset->partitionReferenceNum; | ||
854 | udf_load_fileset(sb, bh, root); | ||
855 | udf_release_data(bh); | ||
856 | return 0; | ||
857 | } | ||
858 | return 1; | ||
859 | } | ||
860 | |||
861 | static void | ||
862 | udf_load_pvoldesc(struct super_block *sb, struct buffer_head *bh) | ||
863 | { | ||
864 | struct primaryVolDesc *pvoldesc; | ||
865 | time_t recording; | ||
866 | long recording_usec; | ||
867 | struct ustr instr; | ||
868 | struct ustr outstr; | ||
869 | |||
870 | pvoldesc = (struct primaryVolDesc *)bh->b_data; | ||
871 | |||
872 | if ( udf_stamp_to_time(&recording, &recording_usec, | ||
873 | lets_to_cpu(pvoldesc->recordingDateAndTime)) ) | ||
874 | { | ||
875 | kernel_timestamp ts; | ||
876 | ts = lets_to_cpu(pvoldesc->recordingDateAndTime); | ||
877 | udf_debug("recording time %ld/%ld, %04u/%02u/%02u %02u:%02u (%x)\n", | ||
878 | recording, recording_usec, | ||
879 | ts.year, ts.month, ts.day, ts.hour, ts.minute, ts.typeAndTimezone); | ||
880 | UDF_SB_RECORDTIME(sb).tv_sec = recording; | ||
881 | UDF_SB_RECORDTIME(sb).tv_nsec = recording_usec * 1000; | ||
882 | } | ||
883 | |||
884 | if ( !udf_build_ustr(&instr, pvoldesc->volIdent, 32) ) | ||
885 | { | ||
886 | if (udf_CS0toUTF8(&outstr, &instr)) | ||
887 | { | ||
888 | strncpy( UDF_SB_VOLIDENT(sb), outstr.u_name, | ||
889 | outstr.u_len > 31 ? 31 : outstr.u_len); | ||
890 | udf_debug("volIdent[] = '%s'\n", UDF_SB_VOLIDENT(sb)); | ||
891 | } | ||
892 | } | ||
893 | |||
894 | if ( !udf_build_ustr(&instr, pvoldesc->volSetIdent, 128) ) | ||
895 | { | ||
896 | if (udf_CS0toUTF8(&outstr, &instr)) | ||
897 | udf_debug("volSetIdent[] = '%s'\n", outstr.u_name); | ||
898 | } | ||
899 | } | ||
900 | |||
901 | static void | ||
902 | udf_load_fileset(struct super_block *sb, struct buffer_head *bh, kernel_lb_addr *root) | ||
903 | { | ||
904 | struct fileSetDesc *fset; | ||
905 | |||
906 | fset = (struct fileSetDesc *)bh->b_data; | ||
907 | |||
908 | *root = lelb_to_cpu(fset->rootDirectoryICB.extLocation); | ||
909 | |||
910 | UDF_SB_SERIALNUM(sb) = le16_to_cpu(fset->descTag.tagSerialNum); | ||
911 | |||
912 | udf_debug("Rootdir at block=%d, partition=%d\n", | ||
913 | root->logicalBlockNum, root->partitionReferenceNum); | ||
914 | } | ||
915 | |||
916 | static void | ||
917 | udf_load_partdesc(struct super_block *sb, struct buffer_head *bh) | ||
918 | { | ||
919 | struct partitionDesc *p; | ||
920 | int i; | ||
921 | |||
922 | p = (struct partitionDesc *)bh->b_data; | ||
923 | |||
924 | for (i=0; i<UDF_SB_NUMPARTS(sb); i++) | ||
925 | { | ||
926 | udf_debug("Searching map: (%d == %d)\n", | ||
927 | UDF_SB_PARTMAPS(sb)[i].s_partition_num, le16_to_cpu(p->partitionNumber)); | ||
928 | if (UDF_SB_PARTMAPS(sb)[i].s_partition_num == le16_to_cpu(p->partitionNumber)) | ||
929 | { | ||
930 | UDF_SB_PARTLEN(sb,i) = le32_to_cpu(p->partitionLength); /* blocks */ | ||
931 | UDF_SB_PARTROOT(sb,i) = le32_to_cpu(p->partitionStartingLocation); | ||
932 | if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_READ_ONLY) | ||
933 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_READ_ONLY; | ||
934 | if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_WRITE_ONCE) | ||
935 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_WRITE_ONCE; | ||
936 | if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_REWRITABLE) | ||
937 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_REWRITABLE; | ||
938 | if (le32_to_cpu(p->accessType) == PD_ACCESS_TYPE_OVERWRITABLE) | ||
939 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_OVERWRITABLE; | ||
940 | |||
941 | if (!strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR02) || | ||
942 | !strcmp(p->partitionContents.ident, PD_PARTITION_CONTENTS_NSR03)) | ||
943 | { | ||
944 | struct partitionHeaderDesc *phd; | ||
945 | |||
946 | phd = (struct partitionHeaderDesc *)(p->partitionContentsUse); | ||
947 | if (phd->unallocSpaceTable.extLength) | ||
948 | { | ||
949 | kernel_lb_addr loc = { le32_to_cpu(phd->unallocSpaceTable.extPosition), i }; | ||
950 | |||
951 | UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table = | ||
952 | udf_iget(sb, loc); | ||
953 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_TABLE; | ||
954 | udf_debug("unallocSpaceTable (part %d) @ %ld\n", | ||
955 | i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_table->i_ino); | ||
956 | } | ||
957 | if (phd->unallocSpaceBitmap.extLength) | ||
958 | { | ||
959 | UDF_SB_ALLOC_BITMAP(sb, i, s_uspace); | ||
960 | if (UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap != NULL) | ||
961 | { | ||
962 | UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extLength = | ||
963 | le32_to_cpu(phd->unallocSpaceBitmap.extLength); | ||
964 | UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition = | ||
965 | le32_to_cpu(phd->unallocSpaceBitmap.extPosition); | ||
966 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_UNALLOC_BITMAP; | ||
967 | udf_debug("unallocSpaceBitmap (part %d) @ %d\n", | ||
968 | i, UDF_SB_PARTMAPS(sb)[i].s_uspace.s_bitmap->s_extPosition); | ||
969 | } | ||
970 | } | ||
971 | if (phd->partitionIntegrityTable.extLength) | ||
972 | udf_debug("partitionIntegrityTable (part %d)\n", i); | ||
973 | if (phd->freedSpaceTable.extLength) | ||
974 | { | ||
975 | kernel_lb_addr loc = { le32_to_cpu(phd->freedSpaceTable.extPosition), i }; | ||
976 | |||
977 | UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table = | ||
978 | udf_iget(sb, loc); | ||
979 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_TABLE; | ||
980 | udf_debug("freedSpaceTable (part %d) @ %ld\n", | ||
981 | i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_table->i_ino); | ||
982 | } | ||
983 | if (phd->freedSpaceBitmap.extLength) | ||
984 | { | ||
985 | UDF_SB_ALLOC_BITMAP(sb, i, s_fspace); | ||
986 | if (UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap != NULL) | ||
987 | { | ||
988 | UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extLength = | ||
989 | le32_to_cpu(phd->freedSpaceBitmap.extLength); | ||
990 | UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition = | ||
991 | le32_to_cpu(phd->freedSpaceBitmap.extPosition); | ||
992 | UDF_SB_PARTFLAGS(sb,i) |= UDF_PART_FLAG_FREED_BITMAP; | ||
993 | udf_debug("freedSpaceBitmap (part %d) @ %d\n", | ||
994 | i, UDF_SB_PARTMAPS(sb)[i].s_fspace.s_bitmap->s_extPosition); | ||
995 | } | ||
996 | } | ||
997 | } | ||
998 | break; | ||
999 | } | ||
1000 | } | ||
1001 | if (i == UDF_SB_NUMPARTS(sb)) | ||
1002 | { | ||
1003 | udf_debug("Partition (%d) not found in partition map\n", le16_to_cpu(p->partitionNumber)); | ||
1004 | } | ||
1005 | else | ||
1006 | { | ||
1007 | udf_debug("Partition (%d:%d type %x) starts at physical %d, block length %d\n", | ||
1008 | le16_to_cpu(p->partitionNumber), i, UDF_SB_PARTTYPE(sb,i), | ||
1009 | UDF_SB_PARTROOT(sb,i), UDF_SB_PARTLEN(sb,i)); | ||
1010 | } | ||
1011 | } | ||
1012 | |||
1013 | static int | ||
1014 | udf_load_logicalvol(struct super_block *sb, struct buffer_head * bh, kernel_lb_addr *fileset) | ||
1015 | { | ||
1016 | struct logicalVolDesc *lvd; | ||
1017 | int i, j, offset; | ||
1018 | uint8_t type; | ||
1019 | |||
1020 | lvd = (struct logicalVolDesc *)bh->b_data; | ||
1021 | |||
1022 | UDF_SB_ALLOC_PARTMAPS(sb, le32_to_cpu(lvd->numPartitionMaps)); | ||
1023 | |||
1024 | for (i=0,offset=0; | ||
1025 | i<UDF_SB_NUMPARTS(sb) && offset<le32_to_cpu(lvd->mapTableLength); | ||
1026 | i++,offset+=((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapLength) | ||
1027 | { | ||
1028 | type = ((struct genericPartitionMap *)&(lvd->partitionMaps[offset]))->partitionMapType; | ||
1029 | if (type == 1) | ||
1030 | { | ||
1031 | struct genericPartitionMap1 *gpm1 = (struct genericPartitionMap1 *)&(lvd->partitionMaps[offset]); | ||
1032 | UDF_SB_PARTTYPE(sb,i) = UDF_TYPE1_MAP15; | ||
1033 | UDF_SB_PARTVSN(sb,i) = le16_to_cpu(gpm1->volSeqNum); | ||
1034 | UDF_SB_PARTNUM(sb,i) = le16_to_cpu(gpm1->partitionNum); | ||
1035 | UDF_SB_PARTFUNC(sb,i) = NULL; | ||
1036 | } | ||
1037 | else if (type == 2) | ||
1038 | { | ||
1039 | struct udfPartitionMap2 *upm2 = (struct udfPartitionMap2 *)&(lvd->partitionMaps[offset]); | ||
1040 | if (!strncmp(upm2->partIdent.ident, UDF_ID_VIRTUAL, strlen(UDF_ID_VIRTUAL))) | ||
1041 | { | ||
1042 | if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0150) | ||
1043 | { | ||
1044 | UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP15; | ||
1045 | UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt15; | ||
1046 | } | ||
1047 | else if (le16_to_cpu(((__le16 *)upm2->partIdent.identSuffix)[0]) == 0x0200) | ||
1048 | { | ||
1049 | UDF_SB_PARTTYPE(sb,i) = UDF_VIRTUAL_MAP20; | ||
1050 | UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_virt20; | ||
1051 | } | ||
1052 | } | ||
1053 | else if (!strncmp(upm2->partIdent.ident, UDF_ID_SPARABLE, strlen(UDF_ID_SPARABLE))) | ||
1054 | { | ||
1055 | uint32_t loc; | ||
1056 | uint16_t ident; | ||
1057 | struct sparingTable *st; | ||
1058 | struct sparablePartitionMap *spm = (struct sparablePartitionMap *)&(lvd->partitionMaps[offset]); | ||
1059 | |||
1060 | UDF_SB_PARTTYPE(sb,i) = UDF_SPARABLE_MAP15; | ||
1061 | UDF_SB_TYPESPAR(sb,i).s_packet_len = le16_to_cpu(spm->packetLength); | ||
1062 | for (j=0; j<spm->numSparingTables; j++) | ||
1063 | { | ||
1064 | loc = le32_to_cpu(spm->locSparingTable[j]); | ||
1065 | UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = | ||
1066 | udf_read_tagged(sb, loc, loc, &ident); | ||
1067 | if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL) | ||
1068 | { | ||
1069 | st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,i).s_spar_map[j]->b_data; | ||
1070 | if (ident != 0 || | ||
1071 | strncmp(st->sparingIdent.ident, UDF_ID_SPARING, strlen(UDF_ID_SPARING))) | ||
1072 | { | ||
1073 | udf_release_data(UDF_SB_TYPESPAR(sb,i).s_spar_map[j]); | ||
1074 | UDF_SB_TYPESPAR(sb,i).s_spar_map[j] = NULL; | ||
1075 | } | ||
1076 | } | ||
1077 | } | ||
1078 | UDF_SB_PARTFUNC(sb,i) = udf_get_pblock_spar15; | ||
1079 | } | ||
1080 | else | ||
1081 | { | ||
1082 | udf_debug("Unknown ident: %s\n", upm2->partIdent.ident); | ||
1083 | continue; | ||
1084 | } | ||
1085 | UDF_SB_PARTVSN(sb,i) = le16_to_cpu(upm2->volSeqNum); | ||
1086 | UDF_SB_PARTNUM(sb,i) = le16_to_cpu(upm2->partitionNum); | ||
1087 | } | ||
1088 | udf_debug("Partition (%d:%d) type %d on volume %d\n", | ||
1089 | i, UDF_SB_PARTNUM(sb,i), type, UDF_SB_PARTVSN(sb,i)); | ||
1090 | } | ||
1091 | |||
1092 | if (fileset) | ||
1093 | { | ||
1094 | long_ad *la = (long_ad *)&(lvd->logicalVolContentsUse[0]); | ||
1095 | |||
1096 | *fileset = lelb_to_cpu(la->extLocation); | ||
1097 | udf_debug("FileSet found in LogicalVolDesc at block=%d, partition=%d\n", | ||
1098 | fileset->logicalBlockNum, | ||
1099 | fileset->partitionReferenceNum); | ||
1100 | } | ||
1101 | if (lvd->integritySeqExt.extLength) | ||
1102 | udf_load_logicalvolint(sb, leea_to_cpu(lvd->integritySeqExt)); | ||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | /* | ||
1107 | * udf_load_logicalvolint | ||
1108 | * | ||
1109 | */ | ||
1110 | static void | ||
1111 | udf_load_logicalvolint(struct super_block *sb, kernel_extent_ad loc) | ||
1112 | { | ||
1113 | struct buffer_head *bh = NULL; | ||
1114 | uint16_t ident; | ||
1115 | |||
1116 | while (loc.extLength > 0 && | ||
1117 | (bh = udf_read_tagged(sb, loc.extLocation, | ||
1118 | loc.extLocation, &ident)) && | ||
1119 | ident == TAG_IDENT_LVID) | ||
1120 | { | ||
1121 | UDF_SB_LVIDBH(sb) = bh; | ||
1122 | |||
1123 | if (UDF_SB_LVID(sb)->nextIntegrityExt.extLength) | ||
1124 | udf_load_logicalvolint(sb, leea_to_cpu(UDF_SB_LVID(sb)->nextIntegrityExt)); | ||
1125 | |||
1126 | if (UDF_SB_LVIDBH(sb) != bh) | ||
1127 | udf_release_data(bh); | ||
1128 | loc.extLength -= sb->s_blocksize; | ||
1129 | loc.extLocation ++; | ||
1130 | } | ||
1131 | if (UDF_SB_LVIDBH(sb) != bh) | ||
1132 | udf_release_data(bh); | ||
1133 | } | ||
1134 | |||
1135 | /* | ||
1136 | * udf_process_sequence | ||
1137 | * | ||
1138 | * PURPOSE | ||
1139 | * Process a main/reserve volume descriptor sequence. | ||
1140 | * | ||
1141 | * PRE-CONDITIONS | ||
1142 | * sb Pointer to _locked_ superblock. | ||
1143 | * block First block of first extent of the sequence. | ||
1144 | * lastblock Lastblock of first extent of the sequence. | ||
1145 | * | ||
1146 | * HISTORY | ||
1147 | * July 1, 1997 - Andrew E. Mileski | ||
1148 | * Written, tested, and released. | ||
1149 | */ | ||
1150 | static int | ||
1151 | udf_process_sequence(struct super_block *sb, long block, long lastblock, kernel_lb_addr *fileset) | ||
1152 | { | ||
1153 | struct buffer_head *bh = NULL; | ||
1154 | struct udf_vds_record vds[VDS_POS_LENGTH]; | ||
1155 | struct generic_desc *gd; | ||
1156 | struct volDescPtr *vdp; | ||
1157 | int done=0; | ||
1158 | int i,j; | ||
1159 | uint32_t vdsn; | ||
1160 | uint16_t ident; | ||
1161 | long next_s = 0, next_e = 0; | ||
1162 | |||
1163 | memset(vds, 0, sizeof(struct udf_vds_record) * VDS_POS_LENGTH); | ||
1164 | |||
1165 | /* Read the main descriptor sequence */ | ||
1166 | for (;(!done && block <= lastblock); block++) | ||
1167 | { | ||
1168 | |||
1169 | bh = udf_read_tagged(sb, block, block, &ident); | ||
1170 | if (!bh) | ||
1171 | break; | ||
1172 | |||
1173 | /* Process each descriptor (ISO 13346 3/8.3-8.4) */ | ||
1174 | gd = (struct generic_desc *)bh->b_data; | ||
1175 | vdsn = le32_to_cpu(gd->volDescSeqNum); | ||
1176 | switch (ident) | ||
1177 | { | ||
1178 | case TAG_IDENT_PVD: /* ISO 13346 3/10.1 */ | ||
1179 | if (vdsn >= vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum) | ||
1180 | { | ||
1181 | vds[VDS_POS_PRIMARY_VOL_DESC].volDescSeqNum = vdsn; | ||
1182 | vds[VDS_POS_PRIMARY_VOL_DESC].block = block; | ||
1183 | } | ||
1184 | break; | ||
1185 | case TAG_IDENT_VDP: /* ISO 13346 3/10.3 */ | ||
1186 | if (vdsn >= vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum) | ||
1187 | { | ||
1188 | vds[VDS_POS_VOL_DESC_PTR].volDescSeqNum = vdsn; | ||
1189 | vds[VDS_POS_VOL_DESC_PTR].block = block; | ||
1190 | |||
1191 | vdp = (struct volDescPtr *)bh->b_data; | ||
1192 | next_s = le32_to_cpu(vdp->nextVolDescSeqExt.extLocation); | ||
1193 | next_e = le32_to_cpu(vdp->nextVolDescSeqExt.extLength); | ||
1194 | next_e = next_e >> sb->s_blocksize_bits; | ||
1195 | next_e += next_s; | ||
1196 | } | ||
1197 | break; | ||
1198 | case TAG_IDENT_IUVD: /* ISO 13346 3/10.4 */ | ||
1199 | if (vdsn >= vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum) | ||
1200 | { | ||
1201 | vds[VDS_POS_IMP_USE_VOL_DESC].volDescSeqNum = vdsn; | ||
1202 | vds[VDS_POS_IMP_USE_VOL_DESC].block = block; | ||
1203 | } | ||
1204 | break; | ||
1205 | case TAG_IDENT_PD: /* ISO 13346 3/10.5 */ | ||
1206 | if (!vds[VDS_POS_PARTITION_DESC].block) | ||
1207 | vds[VDS_POS_PARTITION_DESC].block = block; | ||
1208 | break; | ||
1209 | case TAG_IDENT_LVD: /* ISO 13346 3/10.6 */ | ||
1210 | if (vdsn >= vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum) | ||
1211 | { | ||
1212 | vds[VDS_POS_LOGICAL_VOL_DESC].volDescSeqNum = vdsn; | ||
1213 | vds[VDS_POS_LOGICAL_VOL_DESC].block = block; | ||
1214 | } | ||
1215 | break; | ||
1216 | case TAG_IDENT_USD: /* ISO 13346 3/10.8 */ | ||
1217 | if (vdsn >= vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum) | ||
1218 | { | ||
1219 | vds[VDS_POS_UNALLOC_SPACE_DESC].volDescSeqNum = vdsn; | ||
1220 | vds[VDS_POS_UNALLOC_SPACE_DESC].block = block; | ||
1221 | } | ||
1222 | break; | ||
1223 | case TAG_IDENT_TD: /* ISO 13346 3/10.9 */ | ||
1224 | vds[VDS_POS_TERMINATING_DESC].block = block; | ||
1225 | if (next_e) | ||
1226 | { | ||
1227 | block = next_s; | ||
1228 | lastblock = next_e; | ||
1229 | next_s = next_e = 0; | ||
1230 | } | ||
1231 | else | ||
1232 | done = 1; | ||
1233 | break; | ||
1234 | } | ||
1235 | udf_release_data(bh); | ||
1236 | } | ||
1237 | for (i=0; i<VDS_POS_LENGTH; i++) | ||
1238 | { | ||
1239 | if (vds[i].block) | ||
1240 | { | ||
1241 | bh = udf_read_tagged(sb, vds[i].block, vds[i].block, &ident); | ||
1242 | |||
1243 | if (i == VDS_POS_PRIMARY_VOL_DESC) | ||
1244 | udf_load_pvoldesc(sb, bh); | ||
1245 | else if (i == VDS_POS_LOGICAL_VOL_DESC) | ||
1246 | udf_load_logicalvol(sb, bh, fileset); | ||
1247 | else if (i == VDS_POS_PARTITION_DESC) | ||
1248 | { | ||
1249 | struct buffer_head *bh2 = NULL; | ||
1250 | udf_load_partdesc(sb, bh); | ||
1251 | for (j=vds[i].block+1; j<vds[VDS_POS_TERMINATING_DESC].block; j++) | ||
1252 | { | ||
1253 | bh2 = udf_read_tagged(sb, j, j, &ident); | ||
1254 | gd = (struct generic_desc *)bh2->b_data; | ||
1255 | if (ident == TAG_IDENT_PD) | ||
1256 | udf_load_partdesc(sb, bh2); | ||
1257 | udf_release_data(bh2); | ||
1258 | } | ||
1259 | } | ||
1260 | udf_release_data(bh); | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | return 0; | ||
1265 | } | ||
1266 | |||
1267 | /* | ||
1268 | * udf_check_valid() | ||
1269 | */ | ||
1270 | static int | ||
1271 | udf_check_valid(struct super_block *sb, int novrs, int silent) | ||
1272 | { | ||
1273 | long block; | ||
1274 | |||
1275 | if (novrs) | ||
1276 | { | ||
1277 | udf_debug("Validity check skipped because of novrs option\n"); | ||
1278 | return 0; | ||
1279 | } | ||
1280 | /* Check that it is NSR02 compliant */ | ||
1281 | /* Process any "CD-ROM Volume Descriptor Set" (ECMA 167 2/8.3.1) */ | ||
1282 | else if ((block = udf_vrs(sb, silent)) == -1) | ||
1283 | { | ||
1284 | udf_debug("Failed to read byte 32768. Assuming open disc. Skipping validity check\n"); | ||
1285 | if (!UDF_SB_LASTBLOCK(sb)) | ||
1286 | UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb); | ||
1287 | return 0; | ||
1288 | } | ||
1289 | else | ||
1290 | return !block; | ||
1291 | } | ||
1292 | |||
1293 | static int | ||
1294 | udf_load_partition(struct super_block *sb, kernel_lb_addr *fileset) | ||
1295 | { | ||
1296 | struct anchorVolDescPtr *anchor; | ||
1297 | uint16_t ident; | ||
1298 | struct buffer_head *bh; | ||
1299 | long main_s, main_e, reserve_s, reserve_e; | ||
1300 | int i, j; | ||
1301 | |||
1302 | if (!sb) | ||
1303 | return 1; | ||
1304 | |||
1305 | for (i=0; i<sizeof(UDF_SB_ANCHOR(sb))/sizeof(int); i++) | ||
1306 | { | ||
1307 | if (UDF_SB_ANCHOR(sb)[i] && (bh = udf_read_tagged(sb, | ||
1308 | UDF_SB_ANCHOR(sb)[i], UDF_SB_ANCHOR(sb)[i], &ident))) | ||
1309 | { | ||
1310 | anchor = (struct anchorVolDescPtr *)bh->b_data; | ||
1311 | |||
1312 | /* Locate the main sequence */ | ||
1313 | main_s = le32_to_cpu( anchor->mainVolDescSeqExt.extLocation ); | ||
1314 | main_e = le32_to_cpu( anchor->mainVolDescSeqExt.extLength ); | ||
1315 | main_e = main_e >> sb->s_blocksize_bits; | ||
1316 | main_e += main_s; | ||
1317 | |||
1318 | /* Locate the reserve sequence */ | ||
1319 | reserve_s = le32_to_cpu(anchor->reserveVolDescSeqExt.extLocation); | ||
1320 | reserve_e = le32_to_cpu(anchor->reserveVolDescSeqExt.extLength); | ||
1321 | reserve_e = reserve_e >> sb->s_blocksize_bits; | ||
1322 | reserve_e += reserve_s; | ||
1323 | |||
1324 | udf_release_data(bh); | ||
1325 | |||
1326 | /* Process the main & reserve sequences */ | ||
1327 | /* responsible for finding the PartitionDesc(s) */ | ||
1328 | if (!(udf_process_sequence(sb, main_s, main_e, fileset) && | ||
1329 | udf_process_sequence(sb, reserve_s, reserve_e, fileset))) | ||
1330 | { | ||
1331 | break; | ||
1332 | } | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | if (i == sizeof(UDF_SB_ANCHOR(sb))/sizeof(int)) | ||
1337 | { | ||
1338 | udf_debug("No Anchor block found\n"); | ||
1339 | return 1; | ||
1340 | } | ||
1341 | else | ||
1342 | udf_debug("Using anchor in block %d\n", UDF_SB_ANCHOR(sb)[i]); | ||
1343 | |||
1344 | for (i=0; i<UDF_SB_NUMPARTS(sb); i++) | ||
1345 | { | ||
1346 | switch UDF_SB_PARTTYPE(sb, i) | ||
1347 | { | ||
1348 | case UDF_VIRTUAL_MAP15: | ||
1349 | case UDF_VIRTUAL_MAP20: | ||
1350 | { | ||
1351 | kernel_lb_addr ino; | ||
1352 | |||
1353 | if (!UDF_SB_LASTBLOCK(sb)) | ||
1354 | { | ||
1355 | UDF_SB_LASTBLOCK(sb) = udf_get_last_block(sb); | ||
1356 | udf_find_anchor(sb); | ||
1357 | } | ||
1358 | |||
1359 | if (!UDF_SB_LASTBLOCK(sb)) | ||
1360 | { | ||
1361 | udf_debug("Unable to determine Lastblock (For Virtual Partition)\n"); | ||
1362 | return 1; | ||
1363 | } | ||
1364 | |||
1365 | for (j=0; j<UDF_SB_NUMPARTS(sb); j++) | ||
1366 | { | ||
1367 | if (j != i && | ||
1368 | UDF_SB_PARTVSN(sb,i) == UDF_SB_PARTVSN(sb,j) && | ||
1369 | UDF_SB_PARTNUM(sb,i) == UDF_SB_PARTNUM(sb,j)) | ||
1370 | { | ||
1371 | ino.partitionReferenceNum = j; | ||
1372 | ino.logicalBlockNum = UDF_SB_LASTBLOCK(sb) - | ||
1373 | UDF_SB_PARTROOT(sb,j); | ||
1374 | break; | ||
1375 | } | ||
1376 | } | ||
1377 | |||
1378 | if (j == UDF_SB_NUMPARTS(sb)) | ||
1379 | return 1; | ||
1380 | |||
1381 | if (!(UDF_SB_VAT(sb) = udf_iget(sb, ino))) | ||
1382 | return 1; | ||
1383 | |||
1384 | if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP15) | ||
1385 | { | ||
1386 | UDF_SB_TYPEVIRT(sb,i).s_start_offset = udf_ext0_offset(UDF_SB_VAT(sb)); | ||
1387 | UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - 36) >> 2; | ||
1388 | } | ||
1389 | else if (UDF_SB_PARTTYPE(sb,i) == UDF_VIRTUAL_MAP20) | ||
1390 | { | ||
1391 | struct buffer_head *bh = NULL; | ||
1392 | uint32_t pos; | ||
1393 | |||
1394 | pos = udf_block_map(UDF_SB_VAT(sb), 0); | ||
1395 | bh = sb_bread(sb, pos); | ||
1396 | UDF_SB_TYPEVIRT(sb,i).s_start_offset = | ||
1397 | le16_to_cpu(((struct virtualAllocationTable20 *)bh->b_data + udf_ext0_offset(UDF_SB_VAT(sb)))->lengthHeader) + | ||
1398 | udf_ext0_offset(UDF_SB_VAT(sb)); | ||
1399 | UDF_SB_TYPEVIRT(sb,i).s_num_entries = (UDF_SB_VAT(sb)->i_size - | ||
1400 | UDF_SB_TYPEVIRT(sb,i).s_start_offset) >> 2; | ||
1401 | udf_release_data(bh); | ||
1402 | } | ||
1403 | UDF_SB_PARTROOT(sb,i) = udf_get_pblock(sb, 0, i, 0); | ||
1404 | UDF_SB_PARTLEN(sb,i) = UDF_SB_PARTLEN(sb,ino.partitionReferenceNum); | ||
1405 | } | ||
1406 | } | ||
1407 | } | ||
1408 | return 0; | ||
1409 | } | ||
1410 | |||
1411 | static void udf_open_lvid(struct super_block *sb) | ||
1412 | { | ||
1413 | if (UDF_SB_LVIDBH(sb)) | ||
1414 | { | ||
1415 | int i; | ||
1416 | kernel_timestamp cpu_time; | ||
1417 | |||
1418 | UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | ||
1419 | UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; | ||
1420 | if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) | ||
1421 | UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); | ||
1422 | UDF_SB_LVID(sb)->integrityType = LVID_INTEGRITY_TYPE_OPEN; | ||
1423 | |||
1424 | UDF_SB_LVID(sb)->descTag.descCRC = | ||
1425 | cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), | ||
1426 | le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); | ||
1427 | |||
1428 | UDF_SB_LVID(sb)->descTag.tagChecksum = 0; | ||
1429 | for (i=0; i<16; i++) | ||
1430 | if (i != 4) | ||
1431 | UDF_SB_LVID(sb)->descTag.tagChecksum += | ||
1432 | ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i]; | ||
1433 | |||
1434 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
1435 | } | ||
1436 | } | ||
1437 | |||
1438 | static void udf_close_lvid(struct super_block *sb) | ||
1439 | { | ||
1440 | if (UDF_SB_LVIDBH(sb) && | ||
1441 | UDF_SB_LVID(sb)->integrityType == LVID_INTEGRITY_TYPE_OPEN) | ||
1442 | { | ||
1443 | int i; | ||
1444 | kernel_timestamp cpu_time; | ||
1445 | |||
1446 | UDF_SB_LVIDIU(sb)->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; | ||
1447 | UDF_SB_LVIDIU(sb)->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; | ||
1448 | if (udf_time_to_stamp(&cpu_time, CURRENT_TIME)) | ||
1449 | UDF_SB_LVID(sb)->recordingDateAndTime = cpu_to_lets(cpu_time); | ||
1450 | if (UDF_MAX_WRITE_VERSION > le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev)) | ||
1451 | UDF_SB_LVIDIU(sb)->maxUDFWriteRev = cpu_to_le16(UDF_MAX_WRITE_VERSION); | ||
1452 | if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev)) | ||
1453 | UDF_SB_LVIDIU(sb)->minUDFReadRev = cpu_to_le16(UDF_SB_UDFREV(sb)); | ||
1454 | if (UDF_SB_UDFREV(sb) > le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev)) | ||
1455 | UDF_SB_LVIDIU(sb)->minUDFWriteRev = cpu_to_le16(UDF_SB_UDFREV(sb)); | ||
1456 | UDF_SB_LVID(sb)->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_CLOSE); | ||
1457 | |||
1458 | UDF_SB_LVID(sb)->descTag.descCRC = | ||
1459 | cpu_to_le16(udf_crc((char *)UDF_SB_LVID(sb) + sizeof(tag), | ||
1460 | le16_to_cpu(UDF_SB_LVID(sb)->descTag.descCRCLength), 0)); | ||
1461 | |||
1462 | UDF_SB_LVID(sb)->descTag.tagChecksum = 0; | ||
1463 | for (i=0; i<16; i++) | ||
1464 | if (i != 4) | ||
1465 | UDF_SB_LVID(sb)->descTag.tagChecksum += | ||
1466 | ((uint8_t *)&(UDF_SB_LVID(sb)->descTag))[i]; | ||
1467 | |||
1468 | mark_buffer_dirty(UDF_SB_LVIDBH(sb)); | ||
1469 | } | ||
1470 | } | ||
1471 | |||
1472 | /* | ||
1473 | * udf_read_super | ||
1474 | * | ||
1475 | * PURPOSE | ||
1476 | * Complete the specified super block. | ||
1477 | * | ||
1478 | * PRE-CONDITIONS | ||
1479 | * sb Pointer to superblock to complete - never NULL. | ||
1480 | * sb->s_dev Device to read suberblock from. | ||
1481 | * options Pointer to mount options. | ||
1482 | * silent Silent flag. | ||
1483 | * | ||
1484 | * HISTORY | ||
1485 | * July 1, 1997 - Andrew E. Mileski | ||
1486 | * Written, tested, and released. | ||
1487 | */ | ||
1488 | static int udf_fill_super(struct super_block *sb, void *options, int silent) | ||
1489 | { | ||
1490 | int i; | ||
1491 | struct inode *inode=NULL; | ||
1492 | struct udf_options uopt; | ||
1493 | kernel_lb_addr rootdir, fileset; | ||
1494 | struct udf_sb_info *sbi; | ||
1495 | |||
1496 | uopt.flags = (1 << UDF_FLAG_USE_AD_IN_ICB) | (1 << UDF_FLAG_STRICT); | ||
1497 | uopt.uid = -1; | ||
1498 | uopt.gid = -1; | ||
1499 | uopt.umask = 0; | ||
1500 | |||
1501 | sbi = kmalloc(sizeof(struct udf_sb_info), GFP_KERNEL); | ||
1502 | if (!sbi) | ||
1503 | return -ENOMEM; | ||
1504 | sb->s_fs_info = sbi; | ||
1505 | memset(UDF_SB(sb), 0x00, sizeof(struct udf_sb_info)); | ||
1506 | |||
1507 | init_MUTEX(&sbi->s_alloc_sem); | ||
1508 | |||
1509 | if (!udf_parse_options((char *)options, &uopt)) | ||
1510 | goto error_out; | ||
1511 | |||
1512 | if (uopt.flags & (1 << UDF_FLAG_UTF8) && | ||
1513 | uopt.flags & (1 << UDF_FLAG_NLS_MAP)) | ||
1514 | { | ||
1515 | udf_error(sb, "udf_read_super", | ||
1516 | "utf8 cannot be combined with iocharset\n"); | ||
1517 | goto error_out; | ||
1518 | } | ||
1519 | #ifdef CONFIG_UDF_NLS | ||
1520 | if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map) | ||
1521 | { | ||
1522 | uopt.nls_map = load_nls_default(); | ||
1523 | if (!uopt.nls_map) | ||
1524 | uopt.flags &= ~(1 << UDF_FLAG_NLS_MAP); | ||
1525 | else | ||
1526 | udf_debug("Using default NLS map\n"); | ||
1527 | } | ||
1528 | #endif | ||
1529 | if (!(uopt.flags & (1 << UDF_FLAG_NLS_MAP))) | ||
1530 | uopt.flags |= (1 << UDF_FLAG_UTF8); | ||
1531 | |||
1532 | fileset.logicalBlockNum = 0xFFFFFFFF; | ||
1533 | fileset.partitionReferenceNum = 0xFFFF; | ||
1534 | |||
1535 | UDF_SB(sb)->s_flags = uopt.flags; | ||
1536 | UDF_SB(sb)->s_uid = uopt.uid; | ||
1537 | UDF_SB(sb)->s_gid = uopt.gid; | ||
1538 | UDF_SB(sb)->s_umask = uopt.umask; | ||
1539 | UDF_SB(sb)->s_nls_map = uopt.nls_map; | ||
1540 | |||
1541 | /* Set the block size for all transfers */ | ||
1542 | if (!udf_set_blocksize(sb, uopt.blocksize)) | ||
1543 | goto error_out; | ||
1544 | |||
1545 | if ( uopt.session == 0xFFFFFFFF ) | ||
1546 | UDF_SB_SESSION(sb) = udf_get_last_session(sb); | ||
1547 | else | ||
1548 | UDF_SB_SESSION(sb) = uopt.session; | ||
1549 | |||
1550 | udf_debug("Multi-session=%d\n", UDF_SB_SESSION(sb)); | ||
1551 | |||
1552 | UDF_SB_LASTBLOCK(sb) = uopt.lastblock; | ||
1553 | UDF_SB_ANCHOR(sb)[0] = UDF_SB_ANCHOR(sb)[1] = 0; | ||
1554 | UDF_SB_ANCHOR(sb)[2] = uopt.anchor; | ||
1555 | UDF_SB_ANCHOR(sb)[3] = 256; | ||
1556 | |||
1557 | if (udf_check_valid(sb, uopt.novrs, silent)) /* read volume recognition sequences */ | ||
1558 | { | ||
1559 | printk("UDF-fs: No VRS found\n"); | ||
1560 | goto error_out; | ||
1561 | } | ||
1562 | |||
1563 | udf_find_anchor(sb); | ||
1564 | |||
1565 | /* Fill in the rest of the superblock */ | ||
1566 | sb->s_op = &udf_sb_ops; | ||
1567 | sb->dq_op = NULL; | ||
1568 | sb->s_dirt = 0; | ||
1569 | sb->s_magic = UDF_SUPER_MAGIC; | ||
1570 | sb->s_time_gran = 1000; | ||
1571 | |||
1572 | if (udf_load_partition(sb, &fileset)) | ||
1573 | { | ||
1574 | printk("UDF-fs: No partition found (1)\n"); | ||
1575 | goto error_out; | ||
1576 | } | ||
1577 | |||
1578 | udf_debug("Lastblock=%d\n", UDF_SB_LASTBLOCK(sb)); | ||
1579 | |||
1580 | if ( UDF_SB_LVIDBH(sb) ) | ||
1581 | { | ||
1582 | uint16_t minUDFReadRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev); | ||
1583 | uint16_t minUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFWriteRev); | ||
1584 | /* uint16_t maxUDFWriteRev = le16_to_cpu(UDF_SB_LVIDIU(sb)->maxUDFWriteRev); */ | ||
1585 | |||
1586 | if (minUDFReadRev > UDF_MAX_READ_VERSION) | ||
1587 | { | ||
1588 | printk("UDF-fs: minUDFReadRev=%x (max is %x)\n", | ||
1589 | le16_to_cpu(UDF_SB_LVIDIU(sb)->minUDFReadRev), | ||
1590 | UDF_MAX_READ_VERSION); | ||
1591 | goto error_out; | ||
1592 | } | ||
1593 | else if (minUDFWriteRev > UDF_MAX_WRITE_VERSION) | ||
1594 | { | ||
1595 | sb->s_flags |= MS_RDONLY; | ||
1596 | } | ||
1597 | |||
1598 | UDF_SB_UDFREV(sb) = minUDFWriteRev; | ||
1599 | |||
1600 | if (minUDFReadRev >= UDF_VERS_USE_EXTENDED_FE) | ||
1601 | UDF_SET_FLAG(sb, UDF_FLAG_USE_EXTENDED_FE); | ||
1602 | if (minUDFReadRev >= UDF_VERS_USE_STREAMS) | ||
1603 | UDF_SET_FLAG(sb, UDF_FLAG_USE_STREAMS); | ||
1604 | } | ||
1605 | |||
1606 | if ( !UDF_SB_NUMPARTS(sb) ) | ||
1607 | { | ||
1608 | printk("UDF-fs: No partition found (2)\n"); | ||
1609 | goto error_out; | ||
1610 | } | ||
1611 | |||
1612 | if ( udf_find_fileset(sb, &fileset, &rootdir) ) | ||
1613 | { | ||
1614 | printk("UDF-fs: No fileset found\n"); | ||
1615 | goto error_out; | ||
1616 | } | ||
1617 | |||
1618 | if (!silent) | ||
1619 | { | ||
1620 | kernel_timestamp ts; | ||
1621 | udf_time_to_stamp(&ts, UDF_SB_RECORDTIME(sb)); | ||
1622 | udf_info("UDF %s (%s) Mounting volume '%s', timestamp %04u/%02u/%02u %02u:%02u (%x)\n", | ||
1623 | UDFFS_VERSION, UDFFS_DATE, | ||
1624 | UDF_SB_VOLIDENT(sb), ts.year, ts.month, ts.day, ts.hour, ts.minute, | ||
1625 | ts.typeAndTimezone); | ||
1626 | } | ||
1627 | if (!(sb->s_flags & MS_RDONLY)) | ||
1628 | udf_open_lvid(sb); | ||
1629 | |||
1630 | /* Assign the root inode */ | ||
1631 | /* assign inodes by physical block number */ | ||
1632 | /* perhaps it's not extensible enough, but for now ... */ | ||
1633 | inode = udf_iget(sb, rootdir); | ||
1634 | if (!inode) | ||
1635 | { | ||
1636 | printk("UDF-fs: Error in udf_iget, block=%d, partition=%d\n", | ||
1637 | rootdir.logicalBlockNum, rootdir.partitionReferenceNum); | ||
1638 | goto error_out; | ||
1639 | } | ||
1640 | |||
1641 | /* Allocate a dentry for the root inode */ | ||
1642 | sb->s_root = d_alloc_root(inode); | ||
1643 | if (!sb->s_root) | ||
1644 | { | ||
1645 | printk("UDF-fs: Couldn't allocate root dentry\n"); | ||
1646 | iput(inode); | ||
1647 | goto error_out; | ||
1648 | } | ||
1649 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
1650 | return 0; | ||
1651 | |||
1652 | error_out: | ||
1653 | if (UDF_SB_VAT(sb)) | ||
1654 | iput(UDF_SB_VAT(sb)); | ||
1655 | if (UDF_SB_NUMPARTS(sb)) | ||
1656 | { | ||
1657 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) | ||
1658 | iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table); | ||
1659 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) | ||
1660 | iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); | ||
1661 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
1662 | UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace); | ||
1663 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) | ||
1664 | UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace); | ||
1665 | if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) | ||
1666 | { | ||
1667 | for (i=0; i<4; i++) | ||
1668 | udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]); | ||
1669 | } | ||
1670 | } | ||
1671 | #ifdef CONFIG_UDF_NLS | ||
1672 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) | ||
1673 | unload_nls(UDF_SB(sb)->s_nls_map); | ||
1674 | #endif | ||
1675 | if (!(sb->s_flags & MS_RDONLY)) | ||
1676 | udf_close_lvid(sb); | ||
1677 | udf_release_data(UDF_SB_LVIDBH(sb)); | ||
1678 | UDF_SB_FREE(sb); | ||
1679 | kfree(sbi); | ||
1680 | sb->s_fs_info = NULL; | ||
1681 | return -EINVAL; | ||
1682 | } | ||
1683 | |||
1684 | void udf_error(struct super_block *sb, const char *function, | ||
1685 | const char *fmt, ...) | ||
1686 | { | ||
1687 | va_list args; | ||
1688 | |||
1689 | if (!(sb->s_flags & MS_RDONLY)) | ||
1690 | { | ||
1691 | /* mark sb error */ | ||
1692 | sb->s_dirt = 1; | ||
1693 | } | ||
1694 | va_start(args, fmt); | ||
1695 | vsprintf(error_buf, fmt, args); | ||
1696 | va_end(args); | ||
1697 | printk (KERN_CRIT "UDF-fs error (device %s): %s: %s\n", | ||
1698 | sb->s_id, function, error_buf); | ||
1699 | } | ||
1700 | |||
1701 | void udf_warning(struct super_block *sb, const char *function, | ||
1702 | const char *fmt, ...) | ||
1703 | { | ||
1704 | va_list args; | ||
1705 | |||
1706 | va_start (args, fmt); | ||
1707 | vsprintf(error_buf, fmt, args); | ||
1708 | va_end(args); | ||
1709 | printk(KERN_WARNING "UDF-fs warning (device %s): %s: %s\n", | ||
1710 | sb->s_id, function, error_buf); | ||
1711 | } | ||
1712 | |||
1713 | /* | ||
1714 | * udf_put_super | ||
1715 | * | ||
1716 | * PURPOSE | ||
1717 | * Prepare for destruction of the superblock. | ||
1718 | * | ||
1719 | * DESCRIPTION | ||
1720 | * Called before the filesystem is unmounted. | ||
1721 | * | ||
1722 | * HISTORY | ||
1723 | * July 1, 1997 - Andrew E. Mileski | ||
1724 | * Written, tested, and released. | ||
1725 | */ | ||
1726 | static void | ||
1727 | udf_put_super(struct super_block *sb) | ||
1728 | { | ||
1729 | int i; | ||
1730 | |||
1731 | if (UDF_SB_VAT(sb)) | ||
1732 | iput(UDF_SB_VAT(sb)); | ||
1733 | if (UDF_SB_NUMPARTS(sb)) | ||
1734 | { | ||
1735 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) | ||
1736 | iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table); | ||
1737 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) | ||
1738 | iput(UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); | ||
1739 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
1740 | UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_uspace); | ||
1741 | if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) | ||
1742 | UDF_SB_FREE_BITMAP(sb,UDF_SB_PARTITION(sb),s_fspace); | ||
1743 | if (UDF_SB_PARTTYPE(sb, UDF_SB_PARTITION(sb)) == UDF_SPARABLE_MAP15) | ||
1744 | { | ||
1745 | for (i=0; i<4; i++) | ||
1746 | udf_release_data(UDF_SB_TYPESPAR(sb, UDF_SB_PARTITION(sb)).s_spar_map[i]); | ||
1747 | } | ||
1748 | } | ||
1749 | #ifdef CONFIG_UDF_NLS | ||
1750 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) | ||
1751 | unload_nls(UDF_SB(sb)->s_nls_map); | ||
1752 | #endif | ||
1753 | if (!(sb->s_flags & MS_RDONLY)) | ||
1754 | udf_close_lvid(sb); | ||
1755 | udf_release_data(UDF_SB_LVIDBH(sb)); | ||
1756 | UDF_SB_FREE(sb); | ||
1757 | kfree(sb->s_fs_info); | ||
1758 | sb->s_fs_info = NULL; | ||
1759 | } | ||
1760 | |||
1761 | /* | ||
1762 | * udf_stat_fs | ||
1763 | * | ||
1764 | * PURPOSE | ||
1765 | * Return info about the filesystem. | ||
1766 | * | ||
1767 | * DESCRIPTION | ||
1768 | * Called by sys_statfs() | ||
1769 | * | ||
1770 | * HISTORY | ||
1771 | * July 1, 1997 - Andrew E. Mileski | ||
1772 | * Written, tested, and released. | ||
1773 | */ | ||
1774 | static int | ||
1775 | udf_statfs(struct super_block *sb, struct kstatfs *buf) | ||
1776 | { | ||
1777 | buf->f_type = UDF_SUPER_MAGIC; | ||
1778 | buf->f_bsize = sb->s_blocksize; | ||
1779 | buf->f_blocks = UDF_SB_PARTLEN(sb, UDF_SB_PARTITION(sb)); | ||
1780 | buf->f_bfree = udf_count_free(sb); | ||
1781 | buf->f_bavail = buf->f_bfree; | ||
1782 | buf->f_files = (UDF_SB_LVIDBH(sb) ? | ||
1783 | (le32_to_cpu(UDF_SB_LVIDIU(sb)->numFiles) + | ||
1784 | le32_to_cpu(UDF_SB_LVIDIU(sb)->numDirs)) : 0) + buf->f_bfree; | ||
1785 | buf->f_ffree = buf->f_bfree; | ||
1786 | /* __kernel_fsid_t f_fsid */ | ||
1787 | buf->f_namelen = UDF_NAME_LEN-2; | ||
1788 | |||
1789 | return 0; | ||
1790 | } | ||
1791 | |||
1792 | static unsigned char udf_bitmap_lookup[16] = { | ||
1793 | 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 | ||
1794 | }; | ||
1795 | |||
1796 | static unsigned int | ||
1797 | udf_count_free_bitmap(struct super_block *sb, struct udf_bitmap *bitmap) | ||
1798 | { | ||
1799 | struct buffer_head *bh = NULL; | ||
1800 | unsigned int accum = 0; | ||
1801 | int index; | ||
1802 | int block = 0, newblock; | ||
1803 | kernel_lb_addr loc; | ||
1804 | uint32_t bytes; | ||
1805 | uint8_t value; | ||
1806 | uint8_t *ptr; | ||
1807 | uint16_t ident; | ||
1808 | struct spaceBitmapDesc *bm; | ||
1809 | |||
1810 | lock_kernel(); | ||
1811 | |||
1812 | loc.logicalBlockNum = bitmap->s_extPosition; | ||
1813 | loc.partitionReferenceNum = UDF_SB_PARTITION(sb); | ||
1814 | bh = udf_read_ptagged(sb, loc, 0, &ident); | ||
1815 | |||
1816 | if (!bh) | ||
1817 | { | ||
1818 | printk(KERN_ERR "udf: udf_count_free failed\n"); | ||
1819 | goto out; | ||
1820 | } | ||
1821 | else if (ident != TAG_IDENT_SBD) | ||
1822 | { | ||
1823 | udf_release_data(bh); | ||
1824 | printk(KERN_ERR "udf: udf_count_free failed\n"); | ||
1825 | goto out; | ||
1826 | } | ||
1827 | |||
1828 | bm = (struct spaceBitmapDesc *)bh->b_data; | ||
1829 | bytes = le32_to_cpu(bm->numOfBytes); | ||
1830 | index = sizeof(struct spaceBitmapDesc); /* offset in first block only */ | ||
1831 | ptr = (uint8_t *)bh->b_data; | ||
1832 | |||
1833 | while ( bytes > 0 ) | ||
1834 | { | ||
1835 | while ((bytes > 0) && (index < sb->s_blocksize)) | ||
1836 | { | ||
1837 | value = ptr[index]; | ||
1838 | accum += udf_bitmap_lookup[ value & 0x0f ]; | ||
1839 | accum += udf_bitmap_lookup[ value >> 4 ]; | ||
1840 | index++; | ||
1841 | bytes--; | ||
1842 | } | ||
1843 | if ( bytes ) | ||
1844 | { | ||
1845 | udf_release_data(bh); | ||
1846 | newblock = udf_get_lb_pblock(sb, loc, ++block); | ||
1847 | bh = udf_tread(sb, newblock); | ||
1848 | if (!bh) | ||
1849 | { | ||
1850 | udf_debug("read failed\n"); | ||
1851 | goto out; | ||
1852 | } | ||
1853 | index = 0; | ||
1854 | ptr = (uint8_t *)bh->b_data; | ||
1855 | } | ||
1856 | } | ||
1857 | udf_release_data(bh); | ||
1858 | |||
1859 | out: | ||
1860 | unlock_kernel(); | ||
1861 | |||
1862 | return accum; | ||
1863 | } | ||
1864 | |||
1865 | static unsigned int | ||
1866 | udf_count_free_table(struct super_block *sb, struct inode * table) | ||
1867 | { | ||
1868 | unsigned int accum = 0; | ||
1869 | uint32_t extoffset, elen; | ||
1870 | kernel_lb_addr bloc, eloc; | ||
1871 | int8_t etype; | ||
1872 | struct buffer_head *bh = NULL; | ||
1873 | |||
1874 | lock_kernel(); | ||
1875 | |||
1876 | bloc = UDF_I_LOCATION(table); | ||
1877 | extoffset = sizeof(struct unallocSpaceEntry); | ||
1878 | |||
1879 | while ((etype = udf_next_aext(table, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) | ||
1880 | { | ||
1881 | accum += (elen >> table->i_sb->s_blocksize_bits); | ||
1882 | } | ||
1883 | udf_release_data(bh); | ||
1884 | |||
1885 | unlock_kernel(); | ||
1886 | |||
1887 | return accum; | ||
1888 | } | ||
1889 | |||
1890 | static unsigned int | ||
1891 | udf_count_free(struct super_block *sb) | ||
1892 | { | ||
1893 | unsigned int accum = 0; | ||
1894 | |||
1895 | if (UDF_SB_LVIDBH(sb)) | ||
1896 | { | ||
1897 | if (le32_to_cpu(UDF_SB_LVID(sb)->numOfPartitions) > UDF_SB_PARTITION(sb)) | ||
1898 | { | ||
1899 | accum = le32_to_cpu(UDF_SB_LVID(sb)->freeSpaceTable[UDF_SB_PARTITION(sb)]); | ||
1900 | |||
1901 | if (accum == 0xFFFFFFFF) | ||
1902 | accum = 0; | ||
1903 | } | ||
1904 | } | ||
1905 | |||
1906 | if (accum) | ||
1907 | return accum; | ||
1908 | |||
1909 | if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_BITMAP) | ||
1910 | { | ||
1911 | accum += udf_count_free_bitmap(sb, | ||
1912 | UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_bitmap); | ||
1913 | } | ||
1914 | if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_BITMAP) | ||
1915 | { | ||
1916 | accum += udf_count_free_bitmap(sb, | ||
1917 | UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_bitmap); | ||
1918 | } | ||
1919 | if (accum) | ||
1920 | return accum; | ||
1921 | |||
1922 | if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_UNALLOC_TABLE) | ||
1923 | { | ||
1924 | accum += udf_count_free_table(sb, | ||
1925 | UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_uspace.s_table); | ||
1926 | } | ||
1927 | if (UDF_SB_PARTFLAGS(sb,UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_FREED_TABLE) | ||
1928 | { | ||
1929 | accum += udf_count_free_table(sb, | ||
1930 | UDF_SB_PARTMAPS(sb)[UDF_SB_PARTITION(sb)].s_fspace.s_table); | ||
1931 | } | ||
1932 | |||
1933 | return accum; | ||
1934 | } | ||
diff --git a/fs/udf/symlink.c b/fs/udf/symlink.c new file mode 100644 index 000000000000..43f3051ef756 --- /dev/null +++ b/fs/udf/symlink.c | |||
@@ -0,0 +1,123 @@ | |||
1 | /* | ||
2 | * symlink.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Symlink handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-2001 Ben Fennema | ||
19 | * (C) 1999 Stelias Computing Inc | ||
20 | * | ||
21 | * HISTORY | ||
22 | * | ||
23 | * 04/16/99 blf Created. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "udfdecl.h" | ||
28 | #include <asm/uaccess.h> | ||
29 | #include <linux/errno.h> | ||
30 | #include <linux/fs.h> | ||
31 | #include <linux/udf_fs.h> | ||
32 | #include <linux/time.h> | ||
33 | #include <linux/mm.h> | ||
34 | #include <linux/stat.h> | ||
35 | #include <linux/slab.h> | ||
36 | #include <linux/pagemap.h> | ||
37 | #include <linux/smp_lock.h> | ||
38 | #include <linux/buffer_head.h> | ||
39 | #include "udf_i.h" | ||
40 | |||
41 | static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, char *to) | ||
42 | { | ||
43 | struct pathComponent *pc; | ||
44 | int elen = 0; | ||
45 | char *p = to; | ||
46 | |||
47 | while (elen < fromlen) | ||
48 | { | ||
49 | pc = (struct pathComponent *)(from + elen); | ||
50 | switch (pc->componentType) | ||
51 | { | ||
52 | case 1: | ||
53 | if (pc->lengthComponentIdent == 0) | ||
54 | { | ||
55 | p = to; | ||
56 | *p++ = '/'; | ||
57 | } | ||
58 | break; | ||
59 | case 3: | ||
60 | memcpy(p, "../", 3); | ||
61 | p += 3; | ||
62 | break; | ||
63 | case 4: | ||
64 | memcpy(p, "./", 2); | ||
65 | p += 2; | ||
66 | /* that would be . - just ignore */ | ||
67 | break; | ||
68 | case 5: | ||
69 | p += udf_get_filename(sb, pc->componentIdent, p, pc->lengthComponentIdent); | ||
70 | *p++ = '/'; | ||
71 | break; | ||
72 | } | ||
73 | elen += sizeof(struct pathComponent) + pc->lengthComponentIdent; | ||
74 | } | ||
75 | if (p > to+1) | ||
76 | p[-1] = '\0'; | ||
77 | else | ||
78 | p[0] = '\0'; | ||
79 | } | ||
80 | |||
81 | static int udf_symlink_filler(struct file *file, struct page *page) | ||
82 | { | ||
83 | struct inode *inode = page->mapping->host; | ||
84 | struct buffer_head *bh = NULL; | ||
85 | char *symlink; | ||
86 | int err = -EIO; | ||
87 | char *p = kmap(page); | ||
88 | |||
89 | lock_kernel(); | ||
90 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
91 | symlink = UDF_I_DATA(inode) + UDF_I_LENEATTR(inode); | ||
92 | else | ||
93 | { | ||
94 | bh = sb_bread(inode->i_sb, udf_block_map(inode, 0)); | ||
95 | |||
96 | if (!bh) | ||
97 | goto out; | ||
98 | |||
99 | symlink = bh->b_data; | ||
100 | } | ||
101 | |||
102 | udf_pc_to_char(inode->i_sb, symlink, inode->i_size, p); | ||
103 | udf_release_data(bh); | ||
104 | |||
105 | unlock_kernel(); | ||
106 | SetPageUptodate(page); | ||
107 | kunmap(page); | ||
108 | unlock_page(page); | ||
109 | return 0; | ||
110 | out: | ||
111 | unlock_kernel(); | ||
112 | SetPageError(page); | ||
113 | kunmap(page); | ||
114 | unlock_page(page); | ||
115 | return err; | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * symlinks can't do much... | ||
120 | */ | ||
121 | struct address_space_operations udf_symlink_aops = { | ||
122 | .readpage = udf_symlink_filler, | ||
123 | }; | ||
diff --git a/fs/udf/truncate.c b/fs/udf/truncate.c new file mode 100644 index 000000000000..7dc8a5572ca1 --- /dev/null +++ b/fs/udf/truncate.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * truncate.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Truncate handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1999-2004 Ben Fennema | ||
19 | * (C) 1999 Stelias Computing Inc | ||
20 | * | ||
21 | * HISTORY | ||
22 | * | ||
23 | * 02/24/99 blf Created. | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include "udfdecl.h" | ||
28 | #include <linux/fs.h> | ||
29 | #include <linux/mm.h> | ||
30 | #include <linux/udf_fs.h> | ||
31 | #include <linux/buffer_head.h> | ||
32 | |||
33 | #include "udf_i.h" | ||
34 | #include "udf_sb.h" | ||
35 | |||
36 | static void extent_trunc(struct inode * inode, kernel_lb_addr bloc, int extoffset, | ||
37 | kernel_lb_addr eloc, int8_t etype, uint32_t elen, struct buffer_head *bh, uint32_t nelen) | ||
38 | { | ||
39 | kernel_lb_addr neloc = { 0, 0 }; | ||
40 | int last_block = (elen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; | ||
41 | int first_block = (nelen + inode->i_sb->s_blocksize - 1) >> inode->i_sb->s_blocksize_bits; | ||
42 | |||
43 | if (nelen) | ||
44 | { | ||
45 | if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
46 | { | ||
47 | udf_free_blocks(inode->i_sb, inode, eloc, 0, last_block); | ||
48 | etype = (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30); | ||
49 | } | ||
50 | else | ||
51 | neloc = eloc; | ||
52 | nelen = (etype << 30) | nelen; | ||
53 | } | ||
54 | |||
55 | if (elen != nelen) | ||
56 | { | ||
57 | udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0); | ||
58 | if (last_block - first_block > 0) | ||
59 | { | ||
60 | if (etype == (EXT_RECORDED_ALLOCATED >> 30)) | ||
61 | mark_inode_dirty(inode); | ||
62 | |||
63 | if (etype != (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) | ||
64 | udf_free_blocks(inode->i_sb, inode, eloc, first_block, last_block - first_block); | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | |||
69 | void udf_discard_prealloc(struct inode * inode) | ||
70 | { | ||
71 | kernel_lb_addr bloc, eloc; | ||
72 | uint32_t extoffset = 0, elen, nelen; | ||
73 | uint64_t lbcount = 0; | ||
74 | int8_t etype = -1, netype; | ||
75 | struct buffer_head *bh = NULL; | ||
76 | int adsize; | ||
77 | |||
78 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB || | ||
79 | inode->i_size == UDF_I_LENEXTENTS(inode)) | ||
80 | { | ||
81 | return; | ||
82 | } | ||
83 | |||
84 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) | ||
85 | adsize = sizeof(short_ad); | ||
86 | else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) | ||
87 | adsize = sizeof(long_ad); | ||
88 | else | ||
89 | adsize = 0; | ||
90 | |||
91 | bloc = UDF_I_LOCATION(inode); | ||
92 | |||
93 | while ((netype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1)) != -1) | ||
94 | { | ||
95 | etype = netype; | ||
96 | lbcount += elen; | ||
97 | if (lbcount > inode->i_size && lbcount - inode->i_size < inode->i_sb->s_blocksize) | ||
98 | { | ||
99 | nelen = elen - (lbcount - inode->i_size); | ||
100 | extent_trunc(inode, bloc, extoffset-adsize, eloc, etype, elen, bh, nelen); | ||
101 | lbcount = inode->i_size; | ||
102 | } | ||
103 | } | ||
104 | if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
105 | { | ||
106 | extoffset -= adsize; | ||
107 | lbcount -= elen; | ||
108 | extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); | ||
109 | if (!bh) | ||
110 | { | ||
111 | UDF_I_LENALLOC(inode) = extoffset - udf_file_entry_alloc_offset(inode); | ||
112 | mark_inode_dirty(inode); | ||
113 | } | ||
114 | else | ||
115 | { | ||
116 | struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); | ||
117 | aed->lengthAllocDescs = cpu_to_le32(extoffset - sizeof(struct allocExtDesc)); | ||
118 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
119 | udf_update_tag(bh->b_data, extoffset); | ||
120 | else | ||
121 | udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); | ||
122 | mark_buffer_dirty_inode(bh, inode); | ||
123 | } | ||
124 | } | ||
125 | UDF_I_LENEXTENTS(inode) = lbcount; | ||
126 | |||
127 | udf_release_data(bh); | ||
128 | } | ||
129 | |||
130 | void udf_truncate_extents(struct inode * inode) | ||
131 | { | ||
132 | kernel_lb_addr bloc, eloc, neloc = { 0, 0 }; | ||
133 | uint32_t extoffset, elen, offset, nelen = 0, lelen = 0, lenalloc; | ||
134 | int8_t etype; | ||
135 | int first_block = inode->i_size >> inode->i_sb->s_blocksize_bits; | ||
136 | struct buffer_head *bh = NULL; | ||
137 | int adsize; | ||
138 | |||
139 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_SHORT) | ||
140 | adsize = sizeof(short_ad); | ||
141 | else if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_LONG) | ||
142 | adsize = sizeof(long_ad); | ||
143 | else | ||
144 | adsize = 0; | ||
145 | |||
146 | etype = inode_bmap(inode, first_block, &bloc, &extoffset, &eloc, &elen, &offset, &bh); | ||
147 | offset += (inode->i_size & (inode->i_sb->s_blocksize - 1)); | ||
148 | if (etype != -1) | ||
149 | { | ||
150 | extoffset -= adsize; | ||
151 | extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, offset); | ||
152 | extoffset += adsize; | ||
153 | |||
154 | if (offset) | ||
155 | lenalloc = extoffset; | ||
156 | else | ||
157 | lenalloc = extoffset - adsize; | ||
158 | |||
159 | if (!bh) | ||
160 | lenalloc -= udf_file_entry_alloc_offset(inode); | ||
161 | else | ||
162 | lenalloc -= sizeof(struct allocExtDesc); | ||
163 | |||
164 | while ((etype = udf_current_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 0)) != -1) | ||
165 | { | ||
166 | if (etype == (EXT_NEXT_EXTENT_ALLOCDECS >> 30)) | ||
167 | { | ||
168 | udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 0); | ||
169 | extoffset = 0; | ||
170 | if (lelen) | ||
171 | { | ||
172 | if (!bh) | ||
173 | BUG(); | ||
174 | else | ||
175 | memset(bh->b_data, 0x00, sizeof(struct allocExtDesc)); | ||
176 | udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen); | ||
177 | } | ||
178 | else | ||
179 | { | ||
180 | if (!bh) | ||
181 | { | ||
182 | UDF_I_LENALLOC(inode) = lenalloc; | ||
183 | mark_inode_dirty(inode); | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); | ||
188 | aed->lengthAllocDescs = cpu_to_le32(lenalloc); | ||
189 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
190 | udf_update_tag(bh->b_data, lenalloc + | ||
191 | sizeof(struct allocExtDesc)); | ||
192 | else | ||
193 | udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); | ||
194 | mark_buffer_dirty_inode(bh, inode); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | udf_release_data(bh); | ||
199 | extoffset = sizeof(struct allocExtDesc); | ||
200 | bloc = eloc; | ||
201 | bh = udf_tread(inode->i_sb, udf_get_lb_pblock(inode->i_sb, bloc, 0)); | ||
202 | if (elen) | ||
203 | lelen = (elen + inode->i_sb->s_blocksize - 1) >> | ||
204 | inode->i_sb->s_blocksize_bits; | ||
205 | else | ||
206 | lelen = 1; | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | extent_trunc(inode, bloc, extoffset, eloc, etype, elen, bh, 0); | ||
211 | extoffset += adsize; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | if (lelen) | ||
216 | { | ||
217 | if (!bh) | ||
218 | BUG(); | ||
219 | else | ||
220 | memset(bh->b_data, 0x00, sizeof(struct allocExtDesc)); | ||
221 | udf_free_blocks(inode->i_sb, inode, bloc, 0, lelen); | ||
222 | } | ||
223 | else | ||
224 | { | ||
225 | if (!bh) | ||
226 | { | ||
227 | UDF_I_LENALLOC(inode) = lenalloc; | ||
228 | mark_inode_dirty(inode); | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | struct allocExtDesc *aed = (struct allocExtDesc *)(bh->b_data); | ||
233 | aed->lengthAllocDescs = cpu_to_le32(lenalloc); | ||
234 | if (!UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT) || UDF_SB_UDFREV(inode->i_sb) >= 0x0201) | ||
235 | udf_update_tag(bh->b_data, lenalloc + | ||
236 | sizeof(struct allocExtDesc)); | ||
237 | else | ||
238 | udf_update_tag(bh->b_data, sizeof(struct allocExtDesc)); | ||
239 | mark_buffer_dirty_inode(bh, inode); | ||
240 | } | ||
241 | } | ||
242 | } | ||
243 | else if (inode->i_size) | ||
244 | { | ||
245 | if (offset) | ||
246 | { | ||
247 | extoffset -= adsize; | ||
248 | etype = udf_next_aext(inode, &bloc, &extoffset, &eloc, &elen, &bh, 1); | ||
249 | if (etype == (EXT_NOT_RECORDED_NOT_ALLOCATED >> 30)) | ||
250 | { | ||
251 | extoffset -= adsize; | ||
252 | elen = EXT_NOT_RECORDED_NOT_ALLOCATED | (elen + offset); | ||
253 | udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 0); | ||
254 | } | ||
255 | else if (etype == (EXT_NOT_RECORDED_ALLOCATED >> 30)) | ||
256 | { | ||
257 | kernel_lb_addr neloc = { 0, 0 }; | ||
258 | extoffset -= adsize; | ||
259 | nelen = EXT_NOT_RECORDED_NOT_ALLOCATED | | ||
260 | ((elen + offset + inode->i_sb->s_blocksize - 1) & | ||
261 | ~(inode->i_sb->s_blocksize - 1)); | ||
262 | udf_write_aext(inode, bloc, &extoffset, neloc, nelen, bh, 1); | ||
263 | udf_add_aext(inode, &bloc, &extoffset, eloc, (etype << 30) | elen, &bh, 1); | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | if (elen & (inode->i_sb->s_blocksize - 1)) | ||
268 | { | ||
269 | extoffset -= adsize; | ||
270 | elen = EXT_RECORDED_ALLOCATED | | ||
271 | ((elen + inode->i_sb->s_blocksize - 1) & | ||
272 | ~(inode->i_sb->s_blocksize - 1)); | ||
273 | udf_write_aext(inode, bloc, &extoffset, eloc, elen, bh, 1); | ||
274 | } | ||
275 | memset(&eloc, 0x00, sizeof(kernel_lb_addr)); | ||
276 | elen = EXT_NOT_RECORDED_NOT_ALLOCATED | offset; | ||
277 | udf_add_aext(inode, &bloc, &extoffset, eloc, elen, &bh, 1); | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | UDF_I_LENEXTENTS(inode) = inode->i_size; | ||
282 | |||
283 | udf_release_data(bh); | ||
284 | } | ||
diff --git a/fs/udf/udf_i.h b/fs/udf/udf_i.h new file mode 100644 index 000000000000..d7dbe6f3ba0c --- /dev/null +++ b/fs/udf/udf_i.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifndef __LINUX_UDF_I_H | ||
2 | #define __LINUX_UDF_I_H | ||
3 | |||
4 | #include <linux/udf_fs_i.h> | ||
5 | static inline struct udf_inode_info *UDF_I(struct inode *inode) | ||
6 | { | ||
7 | return list_entry(inode, struct udf_inode_info, vfs_inode); | ||
8 | } | ||
9 | |||
10 | #define UDF_I_LOCATION(X) ( UDF_I(X)->i_location ) | ||
11 | #define UDF_I_LENEATTR(X) ( UDF_I(X)->i_lenEAttr ) | ||
12 | #define UDF_I_LENALLOC(X) ( UDF_I(X)->i_lenAlloc ) | ||
13 | #define UDF_I_LENEXTENTS(X) ( UDF_I(X)->i_lenExtents ) | ||
14 | #define UDF_I_UNIQUE(X) ( UDF_I(X)->i_unique ) | ||
15 | #define UDF_I_ALLOCTYPE(X) ( UDF_I(X)->i_alloc_type ) | ||
16 | #define UDF_I_EFE(X) ( UDF_I(X)->i_efe ) | ||
17 | #define UDF_I_USE(X) ( UDF_I(X)->i_use ) | ||
18 | #define UDF_I_STRAT4096(X) ( UDF_I(X)->i_strat4096 ) | ||
19 | #define UDF_I_NEXT_ALLOC_BLOCK(X) ( UDF_I(X)->i_next_alloc_block ) | ||
20 | #define UDF_I_NEXT_ALLOC_GOAL(X) ( UDF_I(X)->i_next_alloc_goal ) | ||
21 | #define UDF_I_CRTIME(X) ( UDF_I(X)->i_crtime ) | ||
22 | #define UDF_I_SAD(X) ( UDF_I(X)->i_ext.i_sad ) | ||
23 | #define UDF_I_LAD(X) ( UDF_I(X)->i_ext.i_lad ) | ||
24 | #define UDF_I_DATA(X) ( UDF_I(X)->i_ext.i_data ) | ||
25 | |||
26 | #endif /* !defined(_LINUX_UDF_I_H) */ | ||
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h new file mode 100644 index 000000000000..0e54922daa09 --- /dev/null +++ b/fs/udf/udf_sb.h | |||
@@ -0,0 +1,139 @@ | |||
1 | #ifndef __LINUX_UDF_SB_H | ||
2 | #define __LINUX_UDF_SB_H | ||
3 | |||
4 | /* Since UDF 2.01 is ISO 13346 based... */ | ||
5 | #define UDF_SUPER_MAGIC 0x15013346 | ||
6 | |||
7 | #define UDF_MAX_READ_VERSION 0x0201 | ||
8 | #define UDF_MAX_WRITE_VERSION 0x0201 | ||
9 | |||
10 | #define UDF_FLAG_USE_EXTENDED_FE 0 | ||
11 | #define UDF_VERS_USE_EXTENDED_FE 0x0200 | ||
12 | #define UDF_FLAG_USE_STREAMS 1 | ||
13 | #define UDF_VERS_USE_STREAMS 0x0200 | ||
14 | #define UDF_FLAG_USE_SHORT_AD 2 | ||
15 | #define UDF_FLAG_USE_AD_IN_ICB 3 | ||
16 | #define UDF_FLAG_USE_FILE_CTIME_EA 4 | ||
17 | #define UDF_FLAG_STRICT 5 | ||
18 | #define UDF_FLAG_UNDELETE 6 | ||
19 | #define UDF_FLAG_UNHIDE 7 | ||
20 | #define UDF_FLAG_VARCONV 8 | ||
21 | #define UDF_FLAG_NLS_MAP 9 | ||
22 | #define UDF_FLAG_UTF8 10 | ||
23 | |||
24 | #define UDF_PART_FLAG_UNALLOC_BITMAP 0x0001 | ||
25 | #define UDF_PART_FLAG_UNALLOC_TABLE 0x0002 | ||
26 | #define UDF_PART_FLAG_FREED_BITMAP 0x0004 | ||
27 | #define UDF_PART_FLAG_FREED_TABLE 0x0008 | ||
28 | #define UDF_PART_FLAG_READ_ONLY 0x0010 | ||
29 | #define UDF_PART_FLAG_WRITE_ONCE 0x0020 | ||
30 | #define UDF_PART_FLAG_REWRITABLE 0x0040 | ||
31 | #define UDF_PART_FLAG_OVERWRITABLE 0x0080 | ||
32 | |||
33 | static inline struct udf_sb_info *UDF_SB(struct super_block *sb) | ||
34 | { | ||
35 | return sb->s_fs_info; | ||
36 | } | ||
37 | |||
38 | #define UDF_SB_FREE(X)\ | ||
39 | {\ | ||
40 | if (UDF_SB(X))\ | ||
41 | {\ | ||
42 | if (UDF_SB_PARTMAPS(X))\ | ||
43 | kfree(UDF_SB_PARTMAPS(X));\ | ||
44 | UDF_SB_PARTMAPS(X) = NULL;\ | ||
45 | }\ | ||
46 | } | ||
47 | |||
48 | #define UDF_SB_ALLOC_PARTMAPS(X,Y)\ | ||
49 | {\ | ||
50 | UDF_SB_PARTMAPS(X) = kmalloc(sizeof(struct udf_part_map) * Y, GFP_KERNEL);\ | ||
51 | if (UDF_SB_PARTMAPS(X) != NULL)\ | ||
52 | {\ | ||
53 | UDF_SB_NUMPARTS(X) = Y;\ | ||
54 | memset(UDF_SB_PARTMAPS(X), 0x00, sizeof(struct udf_part_map) * Y);\ | ||
55 | }\ | ||
56 | else\ | ||
57 | {\ | ||
58 | UDF_SB_NUMPARTS(X) = 0;\ | ||
59 | udf_error(X, __FUNCTION__, "Unable to allocate space for %d partition maps", Y);\ | ||
60 | }\ | ||
61 | } | ||
62 | |||
63 | #define UDF_SB_ALLOC_BITMAP(X,Y,Z)\ | ||
64 | {\ | ||
65 | int nr_groups = ((UDF_SB_PARTLEN((X),(Y)) + (sizeof(struct spaceBitmapDesc) << 3) +\ | ||
66 | ((X)->s_blocksize * 8) - 1) / ((X)->s_blocksize * 8));\ | ||
67 | int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\ | ||
68 | if (size <= PAGE_SIZE)\ | ||
69 | UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = kmalloc(size, GFP_KERNEL);\ | ||
70 | else\ | ||
71 | UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap = vmalloc(size);\ | ||
72 | if (UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap != NULL)\ | ||
73 | {\ | ||
74 | memset(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap, 0x00, size);\ | ||
75 | UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap =\ | ||
76 | (struct buffer_head **)(UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap + 1);\ | ||
77 | UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups = nr_groups;\ | ||
78 | }\ | ||
79 | else\ | ||
80 | {\ | ||
81 | udf_error(X, __FUNCTION__, "Unable to allocate space for bitmap and %d buffer_head pointers", nr_groups);\ | ||
82 | }\ | ||
83 | } | ||
84 | |||
85 | #define UDF_SB_FREE_BITMAP(X,Y,Z)\ | ||
86 | {\ | ||
87 | int i;\ | ||
88 | int nr_groups = UDF_SB_BITMAP_NR_GROUPS(X,Y,Z);\ | ||
89 | int size = sizeof(struct udf_bitmap) + (sizeof(struct buffer_head *) * nr_groups);\ | ||
90 | for (i=0; i<nr_groups; i++)\ | ||
91 | {\ | ||
92 | if (UDF_SB_BITMAP(X,Y,Z,i))\ | ||
93 | udf_release_data(UDF_SB_BITMAP(X,Y,Z,i));\ | ||
94 | }\ | ||
95 | if (size <= PAGE_SIZE)\ | ||
96 | kfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\ | ||
97 | else\ | ||
98 | vfree(UDF_SB_PARTMAPS(X)[Y].Z.s_bitmap);\ | ||
99 | } | ||
100 | |||
101 | #define UDF_QUERY_FLAG(X,Y) ( UDF_SB(X)->s_flags & ( 1 << (Y) ) ) | ||
102 | #define UDF_SET_FLAG(X,Y) ( UDF_SB(X)->s_flags |= ( 1 << (Y) ) ) | ||
103 | #define UDF_CLEAR_FLAG(X,Y) ( UDF_SB(X)->s_flags &= ~( 1 << (Y) ) ) | ||
104 | |||
105 | #define UDF_UPDATE_UDFREV(X,Y) ( ((Y) > UDF_SB_UDFREV(X)) ? UDF_SB_UDFREV(X) = (Y) : UDF_SB_UDFREV(X) ) | ||
106 | |||
107 | #define UDF_SB_PARTMAPS(X) ( UDF_SB(X)->s_partmaps ) | ||
108 | #define UDF_SB_PARTTYPE(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_type ) | ||
109 | #define UDF_SB_PARTROOT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_root ) | ||
110 | #define UDF_SB_PARTLEN(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_len ) | ||
111 | #define UDF_SB_PARTVSN(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_volumeseqnum ) | ||
112 | #define UDF_SB_PARTNUM(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_num ) | ||
113 | #define UDF_SB_TYPESPAR(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_sparing ) | ||
114 | #define UDF_SB_TYPEVIRT(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_type_specific.s_virtual ) | ||
115 | #define UDF_SB_PARTFUNC(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_func ) | ||
116 | #define UDF_SB_PARTFLAGS(X,Y) ( UDF_SB_PARTMAPS(X)[(Y)].s_partition_flags ) | ||
117 | #define UDF_SB_BITMAP(X,Y,Z,I) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_block_bitmap[I] ) | ||
118 | #define UDF_SB_BITMAP_NR_GROUPS(X,Y,Z) ( UDF_SB_PARTMAPS(X)[(Y)].Z.s_bitmap->s_nr_groups ) | ||
119 | |||
120 | #define UDF_SB_VOLIDENT(X) ( UDF_SB(X)->s_volident ) | ||
121 | #define UDF_SB_NUMPARTS(X) ( UDF_SB(X)->s_partitions ) | ||
122 | #define UDF_SB_PARTITION(X) ( UDF_SB(X)->s_partition ) | ||
123 | #define UDF_SB_SESSION(X) ( UDF_SB(X)->s_session ) | ||
124 | #define UDF_SB_ANCHOR(X) ( UDF_SB(X)->s_anchor ) | ||
125 | #define UDF_SB_LASTBLOCK(X) ( UDF_SB(X)->s_lastblock ) | ||
126 | #define UDF_SB_LVIDBH(X) ( UDF_SB(X)->s_lvidbh ) | ||
127 | #define UDF_SB_LVID(X) ( (struct logicalVolIntegrityDesc *)UDF_SB_LVIDBH(X)->b_data ) | ||
128 | #define UDF_SB_LVIDIU(X) ( (struct logicalVolIntegrityDescImpUse *)&(UDF_SB_LVID(X)->impUse[le32_to_cpu(UDF_SB_LVID(X)->numOfPartitions) * 2 * sizeof(uint32_t)/sizeof(uint8_t)]) ) | ||
129 | |||
130 | #define UDF_SB_UMASK(X) ( UDF_SB(X)->s_umask ) | ||
131 | #define UDF_SB_GID(X) ( UDF_SB(X)->s_gid ) | ||
132 | #define UDF_SB_UID(X) ( UDF_SB(X)->s_uid ) | ||
133 | #define UDF_SB_RECORDTIME(X) ( UDF_SB(X)->s_recordtime ) | ||
134 | #define UDF_SB_SERIALNUM(X) ( UDF_SB(X)->s_serialnum ) | ||
135 | #define UDF_SB_UDFREV(X) ( UDF_SB(X)->s_udfrev ) | ||
136 | #define UDF_SB_FLAGS(X) ( UDF_SB(X)->s_flags ) | ||
137 | #define UDF_SB_VAT(X) ( UDF_SB(X)->s_vat ) | ||
138 | |||
139 | #endif /* __LINUX_UDF_SB_H */ | ||
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h new file mode 100644 index 000000000000..1d5800e0cbe7 --- /dev/null +++ b/fs/udf/udfdecl.h | |||
@@ -0,0 +1,167 @@ | |||
1 | #ifndef __UDF_DECL_H | ||
2 | #define __UDF_DECL_H | ||
3 | |||
4 | #include <linux/udf_fs.h> | ||
5 | #include "ecma_167.h" | ||
6 | #include "osta_udf.h" | ||
7 | |||
8 | #include <linux/fs.h> | ||
9 | #include <linux/config.h> | ||
10 | #include <linux/types.h> | ||
11 | #include <linux/udf_fs_i.h> | ||
12 | #include <linux/udf_fs_sb.h> | ||
13 | #include <linux/buffer_head.h> | ||
14 | |||
15 | #include "udfend.h" | ||
16 | |||
17 | #define udf_fixed_to_variable(x) ( ( ( (x) >> 5 ) * 39 ) + ( (x) & 0x0000001F ) ) | ||
18 | #define udf_variable_to_fixed(x) ( ( ( (x) / 39 ) << 5 ) + ( (x) % 39 ) ) | ||
19 | |||
20 | #define UDF_EXTENT_LENGTH_MASK 0x3FFFFFFF | ||
21 | #define UDF_EXTENT_FLAG_MASK 0xC0000000 | ||
22 | |||
23 | #define UDF_NAME_PAD 4 | ||
24 | #define UDF_NAME_LEN 256 | ||
25 | #define UDF_PATH_LEN 1023 | ||
26 | |||
27 | #define udf_file_entry_alloc_offset(inode)\ | ||
28 | (UDF_I_USE(inode) ?\ | ||
29 | sizeof(struct unallocSpaceEntry) :\ | ||
30 | ((UDF_I_EFE(inode) ?\ | ||
31 | sizeof(struct extendedFileEntry) :\ | ||
32 | sizeof(struct fileEntry)) + UDF_I_LENEATTR(inode))) | ||
33 | |||
34 | #define udf_ext0_offset(inode)\ | ||
35 | (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB ?\ | ||
36 | udf_file_entry_alloc_offset(inode) : 0) | ||
37 | |||
38 | #define udf_get_lb_pblock(sb,loc,offset) udf_get_pblock((sb), (loc).logicalBlockNum, (loc).partitionReferenceNum, (offset)) | ||
39 | |||
40 | struct dentry; | ||
41 | struct inode; | ||
42 | struct task_struct; | ||
43 | struct buffer_head; | ||
44 | struct super_block; | ||
45 | |||
46 | extern struct inode_operations udf_dir_inode_operations; | ||
47 | extern struct file_operations udf_dir_operations; | ||
48 | extern struct inode_operations udf_file_inode_operations; | ||
49 | extern struct file_operations udf_file_operations; | ||
50 | extern struct address_space_operations udf_aops; | ||
51 | extern struct address_space_operations udf_adinicb_aops; | ||
52 | extern struct address_space_operations udf_symlink_aops; | ||
53 | |||
54 | struct udf_fileident_bh | ||
55 | { | ||
56 | struct buffer_head *sbh; | ||
57 | struct buffer_head *ebh; | ||
58 | int soffset; | ||
59 | int eoffset; | ||
60 | }; | ||
61 | |||
62 | struct udf_vds_record | ||
63 | { | ||
64 | uint32_t block; | ||
65 | uint32_t volDescSeqNum; | ||
66 | }; | ||
67 | |||
68 | struct generic_desc | ||
69 | { | ||
70 | tag descTag; | ||
71 | __le32 volDescSeqNum; | ||
72 | }; | ||
73 | |||
74 | struct ustr | ||
75 | { | ||
76 | uint8_t u_cmpID; | ||
77 | uint8_t u_name[UDF_NAME_LEN-2]; | ||
78 | uint8_t u_len; | ||
79 | }; | ||
80 | |||
81 | /* super.c */ | ||
82 | extern void udf_error(struct super_block *, const char *, const char *, ...); | ||
83 | extern void udf_warning(struct super_block *, const char *, const char *, ...); | ||
84 | |||
85 | /* namei.c */ | ||
86 | extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, struct fileIdentDesc *, struct udf_fileident_bh *, uint8_t *, uint8_t *); | ||
87 | |||
88 | /* file.c */ | ||
89 | extern int udf_ioctl(struct inode *, struct file *, unsigned int, unsigned long); | ||
90 | |||
91 | /* inode.c */ | ||
92 | extern struct inode *udf_iget(struct super_block *, kernel_lb_addr); | ||
93 | extern int udf_sync_inode(struct inode *); | ||
94 | extern void udf_expand_file_adinicb(struct inode *, int, int *); | ||
95 | extern struct buffer_head * udf_expand_dir_adinicb(struct inode *, int *, int *); | ||
96 | extern struct buffer_head * udf_bread(struct inode *, int, int, int *); | ||
97 | extern void udf_truncate(struct inode *); | ||
98 | extern void udf_read_inode(struct inode *); | ||
99 | extern void udf_delete_inode(struct inode *); | ||
100 | extern void udf_clear_inode(struct inode *); | ||
101 | extern int udf_write_inode(struct inode *, int); | ||
102 | extern long udf_block_map(struct inode *, long); | ||
103 | extern int8_t inode_bmap(struct inode *, int, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **); | ||
104 | extern int8_t udf_add_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr, uint32_t, struct buffer_head **, int); | ||
105 | extern int8_t udf_write_aext(struct inode *, kernel_lb_addr, int *, kernel_lb_addr, uint32_t, struct buffer_head *, int); | ||
106 | extern int8_t udf_delete_aext(struct inode *, kernel_lb_addr, int, kernel_lb_addr, uint32_t, struct buffer_head *); | ||
107 | extern int8_t udf_next_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int); | ||
108 | extern int8_t udf_current_aext(struct inode *, kernel_lb_addr *, int *, kernel_lb_addr *, uint32_t *, struct buffer_head **, int); | ||
109 | |||
110 | /* misc.c */ | ||
111 | extern struct buffer_head *udf_tgetblk(struct super_block *, int); | ||
112 | extern struct buffer_head *udf_tread(struct super_block *, int); | ||
113 | extern struct genericFormat *udf_add_extendedattr(struct inode *, uint32_t, uint32_t, uint8_t); | ||
114 | extern struct genericFormat *udf_get_extendedattr(struct inode *, uint32_t, uint8_t); | ||
115 | extern struct buffer_head *udf_read_tagged(struct super_block *, uint32_t, uint32_t, uint16_t *); | ||
116 | extern struct buffer_head *udf_read_ptagged(struct super_block *, kernel_lb_addr, uint32_t, uint16_t *); | ||
117 | extern void udf_release_data(struct buffer_head *); | ||
118 | extern void udf_update_tag(char *, int); | ||
119 | extern void udf_new_tag(char *, uint16_t, uint16_t, uint16_t, uint32_t, int); | ||
120 | |||
121 | /* lowlevel.c */ | ||
122 | extern unsigned int udf_get_last_session(struct super_block *); | ||
123 | extern unsigned long udf_get_last_block(struct super_block *); | ||
124 | |||
125 | /* partition.c */ | ||
126 | extern uint32_t udf_get_pblock(struct super_block *, uint32_t, uint16_t, uint32_t); | ||
127 | extern uint32_t udf_get_pblock_virt15(struct super_block *, uint32_t, uint16_t, uint32_t); | ||
128 | extern uint32_t udf_get_pblock_virt20(struct super_block *, uint32_t, uint16_t, uint32_t); | ||
129 | extern uint32_t udf_get_pblock_spar15(struct super_block *, uint32_t, uint16_t, uint32_t); | ||
130 | extern int udf_relocate_blocks(struct super_block *, long, long *); | ||
131 | |||
132 | /* unicode.c */ | ||
133 | extern int udf_get_filename(struct super_block *, uint8_t *, uint8_t *, int); | ||
134 | extern int udf_put_filename(struct super_block *, const uint8_t *, uint8_t *, int); | ||
135 | extern int udf_build_ustr(struct ustr *, dstring *, int); | ||
136 | extern int udf_CS0toUTF8(struct ustr *, struct ustr *); | ||
137 | |||
138 | /* ialloc.c */ | ||
139 | extern void udf_free_inode(struct inode *); | ||
140 | extern struct inode * udf_new_inode (struct inode *, int, int *); | ||
141 | |||
142 | /* truncate.c */ | ||
143 | extern void udf_discard_prealloc(struct inode *); | ||
144 | extern void udf_truncate_extents(struct inode *); | ||
145 | |||
146 | /* balloc.c */ | ||
147 | extern void udf_free_blocks(struct super_block *, struct inode *, kernel_lb_addr, uint32_t, uint32_t); | ||
148 | extern int udf_prealloc_blocks(struct super_block *, struct inode *, uint16_t, uint32_t, uint32_t); | ||
149 | extern int udf_new_block(struct super_block *, struct inode *, uint16_t, uint32_t, int *); | ||
150 | |||
151 | /* fsync.c */ | ||
152 | extern int udf_fsync_file(struct file *, struct dentry *, int); | ||
153 | |||
154 | /* directory.c */ | ||
155 | extern struct fileIdentDesc * udf_fileident_read(struct inode *, loff_t *, struct udf_fileident_bh *, struct fileIdentDesc *, kernel_lb_addr *, uint32_t *, kernel_lb_addr *, uint32_t *, uint32_t *, struct buffer_head **); | ||
156 | extern struct fileIdentDesc * udf_get_fileident(void * buffer, int bufsize, int * offset); | ||
157 | extern long_ad * udf_get_filelongad(uint8_t *, int, int *, int); | ||
158 | extern short_ad * udf_get_fileshortad(uint8_t *, int, int *, int); | ||
159 | |||
160 | /* crc.c */ | ||
161 | extern uint16_t udf_crc(uint8_t *, uint32_t, uint16_t); | ||
162 | |||
163 | /* udftime.c */ | ||
164 | extern time_t *udf_stamp_to_time(time_t *, long *, kernel_timestamp); | ||
165 | extern kernel_timestamp *udf_time_to_stamp(kernel_timestamp *, struct timespec); | ||
166 | |||
167 | #endif /* __UDF_DECL_H */ | ||
diff --git a/fs/udf/udfend.h b/fs/udf/udfend.h new file mode 100644 index 000000000000..17d378879561 --- /dev/null +++ b/fs/udf/udfend.h | |||
@@ -0,0 +1,81 @@ | |||
1 | #ifndef __UDF_ENDIAN_H | ||
2 | #define __UDF_ENDIAN_H | ||
3 | |||
4 | #include <asm/byteorder.h> | ||
5 | #include <linux/string.h> | ||
6 | |||
7 | static inline kernel_lb_addr lelb_to_cpu(lb_addr in) | ||
8 | { | ||
9 | kernel_lb_addr out; | ||
10 | out.logicalBlockNum = le32_to_cpu(in.logicalBlockNum); | ||
11 | out.partitionReferenceNum = le16_to_cpu(in.partitionReferenceNum); | ||
12 | return out; | ||
13 | } | ||
14 | |||
15 | static inline lb_addr cpu_to_lelb(kernel_lb_addr in) | ||
16 | { | ||
17 | lb_addr out; | ||
18 | out.logicalBlockNum = cpu_to_le32(in.logicalBlockNum); | ||
19 | out.partitionReferenceNum = cpu_to_le16(in.partitionReferenceNum); | ||
20 | return out; | ||
21 | } | ||
22 | |||
23 | static inline kernel_timestamp lets_to_cpu(timestamp in) | ||
24 | { | ||
25 | kernel_timestamp out; | ||
26 | memcpy(&out, &in, sizeof(timestamp)); | ||
27 | out.typeAndTimezone = le16_to_cpu(in.typeAndTimezone); | ||
28 | out.year = le16_to_cpu(in.year); | ||
29 | return out; | ||
30 | } | ||
31 | |||
32 | static inline short_ad lesa_to_cpu(short_ad in) | ||
33 | { | ||
34 | short_ad out; | ||
35 | out.extLength = le32_to_cpu(in.extLength); | ||
36 | out.extPosition = le32_to_cpu(in.extPosition); | ||
37 | return out; | ||
38 | } | ||
39 | |||
40 | static inline short_ad cpu_to_lesa(short_ad in) | ||
41 | { | ||
42 | short_ad out; | ||
43 | out.extLength = cpu_to_le32(in.extLength); | ||
44 | out.extPosition = cpu_to_le32(in.extPosition); | ||
45 | return out; | ||
46 | } | ||
47 | |||
48 | static inline kernel_long_ad lela_to_cpu(long_ad in) | ||
49 | { | ||
50 | kernel_long_ad out; | ||
51 | out.extLength = le32_to_cpu(in.extLength); | ||
52 | out.extLocation = lelb_to_cpu(in.extLocation); | ||
53 | return out; | ||
54 | } | ||
55 | |||
56 | static inline long_ad cpu_to_lela(kernel_long_ad in) | ||
57 | { | ||
58 | long_ad out; | ||
59 | out.extLength = cpu_to_le32(in.extLength); | ||
60 | out.extLocation = cpu_to_lelb(in.extLocation); | ||
61 | return out; | ||
62 | } | ||
63 | |||
64 | static inline kernel_extent_ad leea_to_cpu(extent_ad in) | ||
65 | { | ||
66 | kernel_extent_ad out; | ||
67 | out.extLength = le32_to_cpu(in.extLength); | ||
68 | out.extLocation = le32_to_cpu(in.extLocation); | ||
69 | return out; | ||
70 | } | ||
71 | |||
72 | static inline timestamp cpu_to_lets(kernel_timestamp in) | ||
73 | { | ||
74 | timestamp out; | ||
75 | memcpy(&out, &in, sizeof(timestamp)); | ||
76 | out.typeAndTimezone = cpu_to_le16(in.typeAndTimezone); | ||
77 | out.year = cpu_to_le16(in.year); | ||
78 | return out; | ||
79 | } | ||
80 | |||
81 | #endif /* __UDF_ENDIAN_H */ | ||
diff --git a/fs/udf/udftime.c b/fs/udf/udftime.c new file mode 100644 index 000000000000..c2634bda6b50 --- /dev/null +++ b/fs/udf/udftime.c | |||
@@ -0,0 +1,174 @@ | |||
1 | /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. | ||
2 | This file is part of the GNU C Library. | ||
3 | Contributed by Paul Eggert (eggert@twinsun.com). | ||
4 | |||
5 | The GNU C Library is free software; you can redistribute it and/or | ||
6 | modify it under the terms of the GNU Library General Public License as | ||
7 | published by the Free Software Foundation; either version 2 of the | ||
8 | License, or (at your option) any later version. | ||
9 | |||
10 | The GNU C Library is distributed in the hope that it will be useful, | ||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Library General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Library General Public | ||
16 | License along with the GNU C Library; see the file COPYING.LIB. If not, | ||
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. */ | ||
19 | |||
20 | /* | ||
21 | * dgb 10/02/98: ripped this from glibc source to help convert timestamps to unix time | ||
22 | * 10/04/98: added new table-based lookup after seeing how ugly the gnu code is | ||
23 | * blf 09/27/99: ripped out all the old code and inserted new table from | ||
24 | * John Brockmeyer (without leap second corrections) | ||
25 | * rewrote udf_stamp_to_time and fixed timezone accounting in | ||
26 | udf_time_to_stamp. | ||
27 | */ | ||
28 | |||
29 | /* | ||
30 | * We don't take into account leap seconds. This may be correct or incorrect. | ||
31 | * For more NIST information (especially dealing with leap seconds), see: | ||
32 | * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm | ||
33 | */ | ||
34 | |||
35 | #include <linux/types.h> | ||
36 | #include <linux/kernel.h> | ||
37 | #include "udfdecl.h" | ||
38 | |||
39 | #define EPOCH_YEAR 1970 | ||
40 | |||
41 | #ifndef __isleap | ||
42 | /* Nonzero if YEAR is a leap year (every 4 years, | ||
43 | except every 100th isn't, and every 400th is). */ | ||
44 | #define __isleap(year) \ | ||
45 | ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) | ||
46 | #endif | ||
47 | |||
48 | /* How many days come before each month (0-12). */ | ||
49 | const unsigned short int __mon_yday[2][13] = | ||
50 | { | ||
51 | /* Normal years. */ | ||
52 | { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | ||
53 | /* Leap years. */ | ||
54 | { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | ||
55 | }; | ||
56 | |||
57 | #define MAX_YEAR_SECONDS 69 | ||
58 | #define SPD 0x15180 /*3600*24*/ | ||
59 | #define SPY(y,l,s) (SPD * (365*y+l)+s) | ||
60 | |||
61 | static time_t year_seconds[MAX_YEAR_SECONDS]= { | ||
62 | /*1970*/ SPY( 0, 0,0), SPY( 1, 0,0), SPY( 2, 0,0), SPY( 3, 1,0), | ||
63 | /*1974*/ SPY( 4, 1,0), SPY( 5, 1,0), SPY( 6, 1,0), SPY( 7, 2,0), | ||
64 | /*1978*/ SPY( 8, 2,0), SPY( 9, 2,0), SPY(10, 2,0), SPY(11, 3,0), | ||
65 | /*1982*/ SPY(12, 3,0), SPY(13, 3,0), SPY(14, 3,0), SPY(15, 4,0), | ||
66 | /*1986*/ SPY(16, 4,0), SPY(17, 4,0), SPY(18, 4,0), SPY(19, 5,0), | ||
67 | /*1990*/ SPY(20, 5,0), SPY(21, 5,0), SPY(22, 5,0), SPY(23, 6,0), | ||
68 | /*1994*/ SPY(24, 6,0), SPY(25, 6,0), SPY(26, 6,0), SPY(27, 7,0), | ||
69 | /*1998*/ SPY(28, 7,0), SPY(29, 7,0), SPY(30, 7,0), SPY(31, 8,0), | ||
70 | /*2002*/ SPY(32, 8,0), SPY(33, 8,0), SPY(34, 8,0), SPY(35, 9,0), | ||
71 | /*2006*/ SPY(36, 9,0), SPY(37, 9,0), SPY(38, 9,0), SPY(39,10,0), | ||
72 | /*2010*/ SPY(40,10,0), SPY(41,10,0), SPY(42,10,0), SPY(43,11,0), | ||
73 | /*2014*/ SPY(44,11,0), SPY(45,11,0), SPY(46,11,0), SPY(47,12,0), | ||
74 | /*2018*/ SPY(48,12,0), SPY(49,12,0), SPY(50,12,0), SPY(51,13,0), | ||
75 | /*2022*/ SPY(52,13,0), SPY(53,13,0), SPY(54,13,0), SPY(55,14,0), | ||
76 | /*2026*/ SPY(56,14,0), SPY(57,14,0), SPY(58,14,0), SPY(59,15,0), | ||
77 | /*2030*/ SPY(60,15,0), SPY(61,15,0), SPY(62,15,0), SPY(63,16,0), | ||
78 | /*2034*/ SPY(64,16,0), SPY(65,16,0), SPY(66,16,0), SPY(67,17,0), | ||
79 | /*2038*/ SPY(68,17,0) | ||
80 | }; | ||
81 | |||
82 | extern struct timezone sys_tz; | ||
83 | |||
84 | #define SECS_PER_HOUR (60 * 60) | ||
85 | #define SECS_PER_DAY (SECS_PER_HOUR * 24) | ||
86 | |||
87 | time_t * | ||
88 | udf_stamp_to_time(time_t *dest, long *dest_usec, kernel_timestamp src) | ||
89 | { | ||
90 | int yday; | ||
91 | uint8_t type = src.typeAndTimezone >> 12; | ||
92 | int16_t offset; | ||
93 | |||
94 | if (type == 1) | ||
95 | { | ||
96 | offset = src.typeAndTimezone << 4; | ||
97 | /* sign extent offset */ | ||
98 | offset = (offset >> 4); | ||
99 | if (offset == -2047) /* unspecified offset */ | ||
100 | offset = 0; | ||
101 | } | ||
102 | else | ||
103 | offset = 0; | ||
104 | |||
105 | if ((src.year < EPOCH_YEAR) || | ||
106 | (src.year > EPOCH_YEAR+MAX_YEAR_SECONDS)) | ||
107 | { | ||
108 | *dest = -1; | ||
109 | *dest_usec = -1; | ||
110 | return NULL; | ||
111 | } | ||
112 | *dest = year_seconds[src.year - EPOCH_YEAR]; | ||
113 | *dest -= offset * 60; | ||
114 | |||
115 | yday = ((__mon_yday[__isleap (src.year)] | ||
116 | [src.month-1]) + (src.day-1)); | ||
117 | *dest += ( ( (yday* 24) + src.hour ) * 60 + src.minute ) * 60 + src.second; | ||
118 | *dest_usec = src.centiseconds * 10000 + src.hundredsOfMicroseconds * 100 + src.microseconds; | ||
119 | return dest; | ||
120 | } | ||
121 | |||
122 | |||
123 | kernel_timestamp * | ||
124 | udf_time_to_stamp(kernel_timestamp *dest, struct timespec ts) | ||
125 | { | ||
126 | long int days, rem, y; | ||
127 | const unsigned short int *ip; | ||
128 | int16_t offset; | ||
129 | |||
130 | offset = -sys_tz.tz_minuteswest; | ||
131 | |||
132 | if (!dest) | ||
133 | return NULL; | ||
134 | |||
135 | dest->typeAndTimezone = 0x1000 | (offset & 0x0FFF); | ||
136 | |||
137 | ts.tv_sec += offset * 60; | ||
138 | days = ts.tv_sec / SECS_PER_DAY; | ||
139 | rem = ts.tv_sec % SECS_PER_DAY; | ||
140 | dest->hour = rem / SECS_PER_HOUR; | ||
141 | rem %= SECS_PER_HOUR; | ||
142 | dest->minute = rem / 60; | ||
143 | dest->second = rem % 60; | ||
144 | y = 1970; | ||
145 | |||
146 | #define DIV(a,b) ((a) / (b) - ((a) % (b) < 0)) | ||
147 | #define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400)) | ||
148 | |||
149 | while (days < 0 || days >= (__isleap(y) ? 366 : 365)) | ||
150 | { | ||
151 | long int yg = y + days / 365 - (days % 365 < 0); | ||
152 | |||
153 | /* Adjust DAYS and Y to match the guessed year. */ | ||
154 | days -= ((yg - y) * 365 | ||
155 | + LEAPS_THRU_END_OF (yg - 1) | ||
156 | - LEAPS_THRU_END_OF (y - 1)); | ||
157 | y = yg; | ||
158 | } | ||
159 | dest->year = y; | ||
160 | ip = __mon_yday[__isleap(y)]; | ||
161 | for (y = 11; days < (long int) ip[y]; --y) | ||
162 | continue; | ||
163 | days -= ip[y]; | ||
164 | dest->month = y + 1; | ||
165 | dest->day = days + 1; | ||
166 | |||
167 | dest->centiseconds = ts.tv_nsec / 10000000; | ||
168 | dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000) / 100; | ||
169 | dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 - | ||
170 | dest->hundredsOfMicroseconds * 100); | ||
171 | return dest; | ||
172 | } | ||
173 | |||
174 | /* EOF */ | ||
diff --git a/fs/udf/unicode.c b/fs/udf/unicode.c new file mode 100644 index 000000000000..5a80efd8debc --- /dev/null +++ b/fs/udf/unicode.c | |||
@@ -0,0 +1,516 @@ | |||
1 | /* | ||
2 | * unicode.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * Routines for converting between UTF-8 and OSTA Compressed Unicode. | ||
6 | * Also handles filename mangling | ||
7 | * | ||
8 | * DESCRIPTION | ||
9 | * OSTA Compressed Unicode is explained in the OSTA UDF specification. | ||
10 | * http://www.osta.org/ | ||
11 | * UTF-8 is explained in the IETF RFC XXXX. | ||
12 | * ftp://ftp.internic.net/rfc/rfcxxxx.txt | ||
13 | * | ||
14 | * CONTACTS | ||
15 | * E-mail regarding any portion of the Linux UDF file system should be | ||
16 | * directed to the development team's mailing list (run by majordomo): | ||
17 | * linux_udf@hpesjro.fc.hp.com | ||
18 | * | ||
19 | * COPYRIGHT | ||
20 | * This file is distributed under the terms of the GNU General Public | ||
21 | * License (GPL). Copies of the GPL can be obtained from: | ||
22 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
23 | * Each contributing author retains all rights to their own work. | ||
24 | */ | ||
25 | |||
26 | #include "udfdecl.h" | ||
27 | |||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/string.h> /* for memset */ | ||
30 | #include <linux/nls.h> | ||
31 | #include <linux/udf_fs.h> | ||
32 | |||
33 | #include "udf_sb.h" | ||
34 | |||
35 | static int udf_translate_to_linux(uint8_t *, uint8_t *, int, uint8_t *, int); | ||
36 | |||
37 | static int udf_char_to_ustr(struct ustr *dest, const uint8_t *src, int strlen) | ||
38 | { | ||
39 | if ( (!dest) || (!src) || (!strlen) || (strlen > UDF_NAME_LEN-2) ) | ||
40 | return 0; | ||
41 | memset(dest, 0, sizeof(struct ustr)); | ||
42 | memcpy(dest->u_name, src, strlen); | ||
43 | dest->u_cmpID = 0x08; | ||
44 | dest->u_len = strlen; | ||
45 | return strlen; | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * udf_build_ustr | ||
50 | */ | ||
51 | int udf_build_ustr(struct ustr *dest, dstring *ptr, int size) | ||
52 | { | ||
53 | int usesize; | ||
54 | |||
55 | if ( (!dest) || (!ptr) || (!size) ) | ||
56 | return -1; | ||
57 | |||
58 | memset(dest, 0, sizeof(struct ustr)); | ||
59 | usesize= (size > UDF_NAME_LEN) ? UDF_NAME_LEN : size; | ||
60 | dest->u_cmpID=ptr[0]; | ||
61 | dest->u_len=ptr[size-1]; | ||
62 | memcpy(dest->u_name, ptr+1, usesize-1); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * udf_build_ustr_exact | ||
68 | */ | ||
69 | static int udf_build_ustr_exact(struct ustr *dest, dstring *ptr, int exactsize) | ||
70 | { | ||
71 | if ( (!dest) || (!ptr) || (!exactsize) ) | ||
72 | return -1; | ||
73 | |||
74 | memset(dest, 0, sizeof(struct ustr)); | ||
75 | dest->u_cmpID=ptr[0]; | ||
76 | dest->u_len=exactsize-1; | ||
77 | memcpy(dest->u_name, ptr+1, exactsize-1); | ||
78 | return 0; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * udf_ocu_to_utf8 | ||
83 | * | ||
84 | * PURPOSE | ||
85 | * Convert OSTA Compressed Unicode to the UTF-8 equivalent. | ||
86 | * | ||
87 | * DESCRIPTION | ||
88 | * This routine is only called by udf_filldir(). | ||
89 | * | ||
90 | * PRE-CONDITIONS | ||
91 | * utf Pointer to UTF-8 output buffer. | ||
92 | * ocu Pointer to OSTA Compressed Unicode input buffer | ||
93 | * of size UDF_NAME_LEN bytes. | ||
94 | * both of type "struct ustr *" | ||
95 | * | ||
96 | * POST-CONDITIONS | ||
97 | * <return> Zero on success. | ||
98 | * | ||
99 | * HISTORY | ||
100 | * November 12, 1997 - Andrew E. Mileski | ||
101 | * Written, tested, and released. | ||
102 | */ | ||
103 | int udf_CS0toUTF8(struct ustr *utf_o, struct ustr *ocu_i) | ||
104 | { | ||
105 | uint8_t *ocu; | ||
106 | uint32_t c; | ||
107 | uint8_t cmp_id, ocu_len; | ||
108 | int i; | ||
109 | |||
110 | ocu = ocu_i->u_name; | ||
111 | |||
112 | ocu_len = ocu_i->u_len; | ||
113 | cmp_id = ocu_i->u_cmpID; | ||
114 | utf_o->u_len = 0; | ||
115 | |||
116 | if (ocu_len == 0) | ||
117 | { | ||
118 | memset(utf_o, 0, sizeof(struct ustr)); | ||
119 | utf_o->u_cmpID = 0; | ||
120 | utf_o->u_len = 0; | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | if ((cmp_id != 8) && (cmp_id != 16)) | ||
125 | { | ||
126 | printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;) | ||
131 | { | ||
132 | |||
133 | /* Expand OSTA compressed Unicode to Unicode */ | ||
134 | c = ocu[i++]; | ||
135 | if (cmp_id == 16) | ||
136 | c = (c << 8) | ocu[i++]; | ||
137 | |||
138 | /* Compress Unicode to UTF-8 */ | ||
139 | if (c < 0x80U) | ||
140 | utf_o->u_name[utf_o->u_len++] = (uint8_t)c; | ||
141 | else if (c < 0x800U) | ||
142 | { | ||
143 | utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xc0 | (c >> 6)); | ||
144 | utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f)); | ||
145 | } | ||
146 | else | ||
147 | { | ||
148 | utf_o->u_name[utf_o->u_len++] = (uint8_t)(0xe0 | (c >> 12)); | ||
149 | utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | ((c >> 6) & 0x3f)); | ||
150 | utf_o->u_name[utf_o->u_len++] = (uint8_t)(0x80 | (c & 0x3f)); | ||
151 | } | ||
152 | } | ||
153 | utf_o->u_cmpID=8; | ||
154 | |||
155 | return utf_o->u_len; | ||
156 | } | ||
157 | |||
158 | /* | ||
159 | * | ||
160 | * udf_utf8_to_ocu | ||
161 | * | ||
162 | * PURPOSE | ||
163 | * Convert UTF-8 to the OSTA Compressed Unicode equivalent. | ||
164 | * | ||
165 | * DESCRIPTION | ||
166 | * This routine is only called by udf_lookup(). | ||
167 | * | ||
168 | * PRE-CONDITIONS | ||
169 | * ocu Pointer to OSTA Compressed Unicode output | ||
170 | * buffer of size UDF_NAME_LEN bytes. | ||
171 | * utf Pointer to UTF-8 input buffer. | ||
172 | * utf_len Length of UTF-8 input buffer in bytes. | ||
173 | * | ||
174 | * POST-CONDITIONS | ||
175 | * <return> Zero on success. | ||
176 | * | ||
177 | * HISTORY | ||
178 | * November 12, 1997 - Andrew E. Mileski | ||
179 | * Written, tested, and released. | ||
180 | */ | ||
181 | static int udf_UTF8toCS0(dstring *ocu, struct ustr *utf, int length) | ||
182 | { | ||
183 | unsigned c, i, max_val, utf_char; | ||
184 | int utf_cnt, u_len; | ||
185 | |||
186 | memset(ocu, 0, sizeof(dstring) * length); | ||
187 | ocu[0] = 8; | ||
188 | max_val = 0xffU; | ||
189 | |||
190 | try_again: | ||
191 | u_len = 0U; | ||
192 | utf_char = 0U; | ||
193 | utf_cnt = 0U; | ||
194 | for (i = 0U; i < utf->u_len; i++) | ||
195 | { | ||
196 | c = (uint8_t)utf->u_name[i]; | ||
197 | |||
198 | /* Complete a multi-byte UTF-8 character */ | ||
199 | if (utf_cnt) | ||
200 | { | ||
201 | utf_char = (utf_char << 6) | (c & 0x3fU); | ||
202 | if (--utf_cnt) | ||
203 | continue; | ||
204 | } | ||
205 | else | ||
206 | { | ||
207 | /* Check for a multi-byte UTF-8 character */ | ||
208 | if (c & 0x80U) | ||
209 | { | ||
210 | /* Start a multi-byte UTF-8 character */ | ||
211 | if ((c & 0xe0U) == 0xc0U) | ||
212 | { | ||
213 | utf_char = c & 0x1fU; | ||
214 | utf_cnt = 1; | ||
215 | } | ||
216 | else if ((c & 0xf0U) == 0xe0U) | ||
217 | { | ||
218 | utf_char = c & 0x0fU; | ||
219 | utf_cnt = 2; | ||
220 | } | ||
221 | else if ((c & 0xf8U) == 0xf0U) | ||
222 | { | ||
223 | utf_char = c & 0x07U; | ||
224 | utf_cnt = 3; | ||
225 | } | ||
226 | else if ((c & 0xfcU) == 0xf8U) | ||
227 | { | ||
228 | utf_char = c & 0x03U; | ||
229 | utf_cnt = 4; | ||
230 | } | ||
231 | else if ((c & 0xfeU) == 0xfcU) | ||
232 | { | ||
233 | utf_char = c & 0x01U; | ||
234 | utf_cnt = 5; | ||
235 | } | ||
236 | else | ||
237 | goto error_out; | ||
238 | continue; | ||
239 | } else | ||
240 | /* Single byte UTF-8 character (most common) */ | ||
241 | utf_char = c; | ||
242 | } | ||
243 | |||
244 | /* Choose no compression if necessary */ | ||
245 | if (utf_char > max_val) | ||
246 | { | ||
247 | if ( 0xffU == max_val ) | ||
248 | { | ||
249 | max_val = 0xffffU; | ||
250 | ocu[0] = (uint8_t)0x10U; | ||
251 | goto try_again; | ||
252 | } | ||
253 | goto error_out; | ||
254 | } | ||
255 | |||
256 | if (max_val == 0xffffU) | ||
257 | { | ||
258 | ocu[++u_len] = (uint8_t)(utf_char >> 8); | ||
259 | } | ||
260 | ocu[++u_len] = (uint8_t)(utf_char & 0xffU); | ||
261 | } | ||
262 | |||
263 | |||
264 | if (utf_cnt) | ||
265 | { | ||
266 | error_out: | ||
267 | ocu[++u_len] = '?'; | ||
268 | printk(KERN_DEBUG "udf: bad UTF-8 character\n"); | ||
269 | } | ||
270 | |||
271 | ocu[length - 1] = (uint8_t)u_len + 1; | ||
272 | return u_len + 1; | ||
273 | } | ||
274 | |||
275 | static int udf_CS0toNLS(struct nls_table *nls, struct ustr *utf_o, struct ustr *ocu_i) | ||
276 | { | ||
277 | uint8_t *ocu; | ||
278 | uint32_t c; | ||
279 | uint8_t cmp_id, ocu_len; | ||
280 | int i; | ||
281 | |||
282 | ocu = ocu_i->u_name; | ||
283 | |||
284 | ocu_len = ocu_i->u_len; | ||
285 | cmp_id = ocu_i->u_cmpID; | ||
286 | utf_o->u_len = 0; | ||
287 | |||
288 | if (ocu_len == 0) | ||
289 | { | ||
290 | memset(utf_o, 0, sizeof(struct ustr)); | ||
291 | utf_o->u_cmpID = 0; | ||
292 | utf_o->u_len = 0; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | if ((cmp_id != 8) && (cmp_id != 16)) | ||
297 | { | ||
298 | printk(KERN_ERR "udf: unknown compression code (%d) stri=%s\n", cmp_id, ocu_i->u_name); | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | for (i = 0; (i < ocu_len) && (utf_o->u_len <= (UDF_NAME_LEN-3)) ;) | ||
303 | { | ||
304 | /* Expand OSTA compressed Unicode to Unicode */ | ||
305 | c = ocu[i++]; | ||
306 | if (cmp_id == 16) | ||
307 | c = (c << 8) | ocu[i++]; | ||
308 | |||
309 | utf_o->u_len += nls->uni2char(c, &utf_o->u_name[utf_o->u_len], | ||
310 | UDF_NAME_LEN - utf_o->u_len); | ||
311 | } | ||
312 | utf_o->u_cmpID=8; | ||
313 | |||
314 | return utf_o->u_len; | ||
315 | } | ||
316 | |||
317 | static int udf_NLStoCS0(struct nls_table *nls, dstring *ocu, struct ustr *uni, int length) | ||
318 | { | ||
319 | unsigned len, i, max_val; | ||
320 | uint16_t uni_char; | ||
321 | int u_len; | ||
322 | |||
323 | memset(ocu, 0, sizeof(dstring) * length); | ||
324 | ocu[0] = 8; | ||
325 | max_val = 0xffU; | ||
326 | |||
327 | try_again: | ||
328 | u_len = 0U; | ||
329 | for (i = 0U; i < uni->u_len; i++) | ||
330 | { | ||
331 | len = nls->char2uni(&uni->u_name[i], uni->u_len-i, &uni_char); | ||
332 | if (len <= 0) | ||
333 | continue; | ||
334 | |||
335 | if (uni_char > max_val) | ||
336 | { | ||
337 | max_val = 0xffffU; | ||
338 | ocu[0] = (uint8_t)0x10U; | ||
339 | goto try_again; | ||
340 | } | ||
341 | |||
342 | if (max_val == 0xffffU) | ||
343 | ocu[++u_len] = (uint8_t)(uni_char >> 8); | ||
344 | ocu[++u_len] = (uint8_t)(uni_char & 0xffU); | ||
345 | i += len - 1; | ||
346 | } | ||
347 | |||
348 | ocu[length - 1] = (uint8_t)u_len + 1; | ||
349 | return u_len + 1; | ||
350 | } | ||
351 | |||
352 | int udf_get_filename(struct super_block *sb, uint8_t *sname, uint8_t *dname, int flen) | ||
353 | { | ||
354 | struct ustr filename, unifilename; | ||
355 | int len; | ||
356 | |||
357 | if (udf_build_ustr_exact(&unifilename, sname, flen)) | ||
358 | { | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) | ||
363 | { | ||
364 | if (!udf_CS0toUTF8(&filename, &unifilename) ) | ||
365 | { | ||
366 | udf_debug("Failed in udf_get_filename: sname = %s\n", sname); | ||
367 | return 0; | ||
368 | } | ||
369 | } | ||
370 | else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) | ||
371 | { | ||
372 | if (!udf_CS0toNLS(UDF_SB(sb)->s_nls_map, &filename, &unifilename) ) | ||
373 | { | ||
374 | udf_debug("Failed in udf_get_filename: sname = %s\n", sname); | ||
375 | return 0; | ||
376 | } | ||
377 | } | ||
378 | else | ||
379 | return 0; | ||
380 | |||
381 | if ((len = udf_translate_to_linux(dname, filename.u_name, filename.u_len, | ||
382 | unifilename.u_name, unifilename.u_len))) | ||
383 | { | ||
384 | return len; | ||
385 | } | ||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | int udf_put_filename(struct super_block *sb, const uint8_t *sname, uint8_t *dname, int flen) | ||
390 | { | ||
391 | struct ustr unifilename; | ||
392 | int namelen; | ||
393 | |||
394 | if ( !(udf_char_to_ustr(&unifilename, sname, flen)) ) | ||
395 | { | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | if (UDF_QUERY_FLAG(sb, UDF_FLAG_UTF8)) | ||
400 | { | ||
401 | if ( !(namelen = udf_UTF8toCS0(dname, &unifilename, UDF_NAME_LEN)) ) | ||
402 | { | ||
403 | return 0; | ||
404 | } | ||
405 | } | ||
406 | else if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP)) | ||
407 | { | ||
408 | if ( !(namelen = udf_NLStoCS0(UDF_SB(sb)->s_nls_map, dname, &unifilename, UDF_NAME_LEN)) ) | ||
409 | { | ||
410 | return 0; | ||
411 | } | ||
412 | } | ||
413 | else | ||
414 | return 0; | ||
415 | |||
416 | return namelen; | ||
417 | } | ||
418 | |||
419 | #define ILLEGAL_CHAR_MARK '_' | ||
420 | #define EXT_MARK '.' | ||
421 | #define CRC_MARK '#' | ||
422 | #define EXT_SIZE 5 | ||
423 | |||
424 | static int udf_translate_to_linux(uint8_t *newName, uint8_t *udfName, int udfLen, uint8_t *fidName, int fidNameLen) | ||
425 | { | ||
426 | int index, newIndex = 0, needsCRC = 0; | ||
427 | int extIndex = 0, newExtIndex = 0, hasExt = 0; | ||
428 | unsigned short valueCRC; | ||
429 | uint8_t curr; | ||
430 | const uint8_t hexChar[] = "0123456789ABCDEF"; | ||
431 | |||
432 | if (udfName[0] == '.' && (udfLen == 1 || | ||
433 | (udfLen == 2 && udfName[1] == '.'))) | ||
434 | { | ||
435 | needsCRC = 1; | ||
436 | newIndex = udfLen; | ||
437 | memcpy(newName, udfName, udfLen); | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | for (index = 0; index < udfLen; index++) | ||
442 | { | ||
443 | curr = udfName[index]; | ||
444 | if (curr == '/' || curr == 0) | ||
445 | { | ||
446 | needsCRC = 1; | ||
447 | curr = ILLEGAL_CHAR_MARK; | ||
448 | while (index+1 < udfLen && (udfName[index+1] == '/' || | ||
449 | udfName[index+1] == 0)) | ||
450 | index++; | ||
451 | } | ||
452 | if (curr == EXT_MARK && (udfLen - index - 1) <= EXT_SIZE) | ||
453 | { | ||
454 | if (udfLen == index + 1) | ||
455 | hasExt = 0; | ||
456 | else | ||
457 | { | ||
458 | hasExt = 1; | ||
459 | extIndex = index; | ||
460 | newExtIndex = newIndex; | ||
461 | } | ||
462 | } | ||
463 | if (newIndex < 256) | ||
464 | newName[newIndex++] = curr; | ||
465 | else | ||
466 | needsCRC = 1; | ||
467 | } | ||
468 | } | ||
469 | if (needsCRC) | ||
470 | { | ||
471 | uint8_t ext[EXT_SIZE]; | ||
472 | int localExtIndex = 0; | ||
473 | |||
474 | if (hasExt) | ||
475 | { | ||
476 | int maxFilenameLen; | ||
477 | for(index = 0; index<EXT_SIZE && extIndex + index +1 < udfLen; | ||
478 | index++ ) | ||
479 | { | ||
480 | curr = udfName[extIndex + index + 1]; | ||
481 | |||
482 | if (curr == '/' || curr == 0) | ||
483 | { | ||
484 | needsCRC = 1; | ||
485 | curr = ILLEGAL_CHAR_MARK; | ||
486 | while(extIndex + index + 2 < udfLen && (index + 1 < EXT_SIZE | ||
487 | && (udfName[extIndex + index + 2] == '/' || | ||
488 | udfName[extIndex + index + 2] == 0))) | ||
489 | index++; | ||
490 | } | ||
491 | ext[localExtIndex++] = curr; | ||
492 | } | ||
493 | maxFilenameLen = 250 - localExtIndex; | ||
494 | if (newIndex > maxFilenameLen) | ||
495 | newIndex = maxFilenameLen; | ||
496 | else | ||
497 | newIndex = newExtIndex; | ||
498 | } | ||
499 | else if (newIndex > 250) | ||
500 | newIndex = 250; | ||
501 | newName[newIndex++] = CRC_MARK; | ||
502 | valueCRC = udf_crc(fidName, fidNameLen, 0); | ||
503 | newName[newIndex++] = hexChar[(valueCRC & 0xf000) >> 12]; | ||
504 | newName[newIndex++] = hexChar[(valueCRC & 0x0f00) >> 8]; | ||
505 | newName[newIndex++] = hexChar[(valueCRC & 0x00f0) >> 4]; | ||
506 | newName[newIndex++] = hexChar[(valueCRC & 0x000f)]; | ||
507 | |||
508 | if (hasExt) | ||
509 | { | ||
510 | newName[newIndex++] = EXT_MARK; | ||
511 | for (index = 0;index < localExtIndex ;index++ ) | ||
512 | newName[newIndex++] = ext[index]; | ||
513 | } | ||
514 | } | ||
515 | return newIndex; | ||
516 | } | ||