diff options
Diffstat (limited to 'fs/befs')
-rw-r--r-- | fs/befs/ChangeLog | 417 | ||||
-rw-r--r-- | fs/befs/Makefile | 7 | ||||
-rw-r--r-- | fs/befs/TODO | 14 | ||||
-rw-r--r-- | fs/befs/attribute.c | 117 | ||||
-rw-r--r-- | fs/befs/befs.h | 154 | ||||
-rw-r--r-- | fs/befs/befs_fs_types.h | 213 | ||||
-rw-r--r-- | fs/befs/btree.c | 788 | ||||
-rw-r--r-- | fs/befs/btree.h | 13 | ||||
-rw-r--r-- | fs/befs/datastream.c | 528 | ||||
-rw-r--r-- | fs/befs/datastream.h | 19 | ||||
-rw-r--r-- | fs/befs/debug.c | 283 | ||||
-rw-r--r-- | fs/befs/endian.h | 126 | ||||
-rw-r--r-- | fs/befs/inode.c | 53 | ||||
-rw-r--r-- | fs/befs/inode.h | 8 | ||||
-rw-r--r-- | fs/befs/io.c | 83 | ||||
-rw-r--r-- | fs/befs/io.h | 9 | ||||
-rw-r--r-- | fs/befs/linuxvfs.c | 964 | ||||
-rw-r--r-- | fs/befs/super.c | 112 | ||||
-rw-r--r-- | fs/befs/super.h | 8 |
19 files changed, 3916 insertions, 0 deletions
diff --git a/fs/befs/ChangeLog b/fs/befs/ChangeLog new file mode 100644 index 000000000000..ce8c787916be --- /dev/null +++ b/fs/befs/ChangeLog | |||
@@ -0,0 +1,417 @@ | |||
1 | Version 0.92 (2002-03-29) | ||
2 | ========== | ||
3 | * Minor cleanup. Ran Lindent on the sources. | ||
4 | |||
5 | Version 0.92 (2002-03-27) | ||
6 | ========== | ||
7 | * Fixed module makefile problem. It was not compiling all the correct | ||
8 | source files! | ||
9 | * Removed duplicated function definition | ||
10 | * Fixed potential null pointer dereference when reporting an error | ||
11 | |||
12 | Version 0.91 (2002-03-26) | ||
13 | ========== | ||
14 | * Oy! Fixed stupid bug that would cause an unresolved symbol error. | ||
15 | Thanks to Laszlo Boszormenyi for pointing this out to me. | ||
16 | |||
17 | Version 0.9 (2002-03-14) | ||
18 | ========== | ||
19 | * Added Sergey S. Kostyliov's patch to eliminate memcpy() overhead | ||
20 | from b+tree operations. Changes the befs_read_datastream() interface. | ||
21 | |||
22 | * Segregated the functions that interface directly with the linux vfs | ||
23 | interface into their own file called linuxvfs.c. [WD] | ||
24 | |||
25 | Version 0.64 (2002-02-07) | ||
26 | ========== | ||
27 | * Did the string comparision really right this time (btree.c) [WD] | ||
28 | |||
29 | * Fixed up some places where I assumed that a long int could hold | ||
30 | a pointer value. (btree.c) [WD] | ||
31 | |||
32 | * Andrew Farnham <andrewfarnham@uq.net.au> pointed out that the module | ||
33 | wouldn't work on older (<2.4.10) kernels due to an unresolved symbol. | ||
34 | This is bad, since 2.4.9 is still the current RedHat kernel. I added | ||
35 | a workaround for this problem (compatibility.h) [WD] | ||
36 | |||
37 | * Sergey S. Kostyliov made befs_find_key() use a binary search to find | ||
38 | keys within btree nodes, rather than the linear search we were using | ||
39 | before. (btree.c) [Sergey S. Kostyliov <rathamahata@php4.ru>] | ||
40 | |||
41 | * Made a debian package of the source for use with kernel-package. [WD] | ||
42 | |||
43 | |||
44 | Version 0.63 (2002-01-31) | ||
45 | ========== | ||
46 | * Fixed bug in befs_find_brun_indirect() that would result in the wrong | ||
47 | block being read. It was introduced when adding byteswapping in | ||
48 | 0.61. (datastream.c) [WD] | ||
49 | |||
50 | * Fixed a longstanding bug in befs_find_key() that would result in it | ||
51 | finding the first key that is a substring of the string it is searching | ||
52 | for. For example, this would cause files in the same directory with | ||
53 | names like file1 and file2 to mysteriously be duplicates of each other | ||
54 | (because they have the same inode number). Many thanks to Pavel Roskin | ||
55 | for reporting this serious bug!!! | ||
56 | (btree.c) [WD] | ||
57 | |||
58 | * Added support for long symlinks, after Axel Dorfler explained up how | ||
59 | they work. I had forgotten all about them. (inode.c, symlink.c) [WD] | ||
60 | |||
61 | * Documentation improvements in source. [WD] | ||
62 | |||
63 | * Makefile fix for independent module when CONFIG_MODVERSION is set in | ||
64 | kernel config [Pavel Roskin <proski@gnu.org>] | ||
65 | |||
66 | * Compile warning fix for namei.c. [Sergey S. Kostyliov <rathamahata@php4.ru>] | ||
67 | |||
68 | |||
69 | Version 0.62 | ||
70 | ========== | ||
71 | * Fixed makefile for module install [WD] | ||
72 | |||
73 | |||
74 | Version 0.61 (2002-01-20) | ||
75 | ========== | ||
76 | * Made functions in endian.h to do the correct byteswapping, no matter | ||
77 | the arch. [WD] | ||
78 | |||
79 | * Abbandoned silly checks for a NULL superblock pointer in debug.c. [WD] | ||
80 | |||
81 | * Misc code cleanups. Also cleanup of this changelog file. [WD] | ||
82 | |||
83 | * Added byteswapping to all metadata reads from disk. | ||
84 | Uses the functions from endian.h [WD] | ||
85 | |||
86 | * Remove the typedef of struct super_block to vfs_sb, as it offended | ||
87 | certain peoples' aesthetic sense. [WD] | ||
88 | |||
89 | * Ditto with the befs_read_block() interface. [WD] | ||
90 | |||
91 | |||
92 | Version 0.6 (2001-12-15) | ||
93 | ========== | ||
94 | * Cleanup of NLS functions (util.c) [WD] | ||
95 | |||
96 | * Make directory lookup/read use the NLS if an iocharset is provided. [WD] | ||
97 | |||
98 | * Fixed stupid bug where specifying the uid or gid mount options as '0' | ||
99 | would result in the filesystem using the on-disk uid and gid. [WD] | ||
100 | |||
101 | * Added mount option to control debug printing. | ||
102 | The option is, simply enough, 'debug'. | ||
103 | (super.c, debug.c) [WD] | ||
104 | |||
105 | * Removed notion of btree handle from btree.c. It was unnecessary, as the | ||
106 | linux VFS doesn't allow us to keep any state between calls. Updated | ||
107 | dir.c, namei.c befs_fs.h to account for it. [WD] | ||
108 | |||
109 | * Improved handleing of overflow nodes when listing directories. | ||
110 | Now works for overflow nodes hanging off of nodes other than the root | ||
111 | node. This is the cleaner solution to Brent Miszalaski's problem. [WD] | ||
112 | |||
113 | * Added new debug/warning/error print functions in debug.c. | ||
114 | More flexible. Will soon be controllable at mount time | ||
115 | (see TODO). [WD] | ||
116 | |||
117 | * Rewrote datastream positon lookups. | ||
118 | (datastream.c) [WD] | ||
119 | |||
120 | * Moved the TODO list to its own file. | ||
121 | |||
122 | |||
123 | Version 0.50 (2001-11-13) | ||
124 | ========== | ||
125 | * Added workaround for mis-understanding of the nature of the b+trees used | ||
126 | in directories. A cleaner solution will come after I've thought about it | ||
127 | for a while. Thanks to Brent Miszalaski for finding and reporting this bug. | ||
128 | (btree.c) [WD] | ||
129 | |||
130 | * Minor cleanups | ||
131 | |||
132 | * Added test for "impossible" condition of empty internal nodes in | ||
133 | seekleaf() in btree.c [WD] | ||
134 | |||
135 | * Implemented the abstracted read_block() in io.c [WD] | ||
136 | |||
137 | * Cleaned up the inode validation in inode.c [WD] | ||
138 | |||
139 | * Anton Altaparmakov figured out (by asking Linus :) ) what was causing the | ||
140 | hanging disk io problem. It turns out you need to have the sync_pages | ||
141 | callback defined in your address_space_ops, even if it just uses the | ||
142 | default linux-supplied implementation. Fixed. Works now. | ||
143 | (file.c) [WD] | ||
144 | |||
145 | * Anton Altaparmakov and Christoph Hellwig alerted me to the fact that | ||
146 | filesystem code should be using GFP_NOFS instead of GFP_KERNEL as the | ||
147 | priority parameter to kmalloc(). Fixed. | ||
148 | (datastream.c, btree.c super.c inode.c) [WD] | ||
149 | |||
150 | * Anton also told me that the blocksize is not allowed to be larger than | ||
151 | the page size in linux, which is 4k i386. Oops. Added a test for | ||
152 | (blocksize > PAGE_SIZE), and refuse to mount in that case. What this | ||
153 | practicaly means is that 8k blocksize volumes won't work without a major | ||
154 | restructuring of the driver (or an alpha or other 64bit hardware). [WD] | ||
155 | |||
156 | * Cleaned up the befs_count_blocks() function. Much smarter now. | ||
157 | And somewhat smaller too. [WD] | ||
158 | |||
159 | * Made inode allocations use a slab cache | ||
160 | (super.c inode.c) [WD] | ||
161 | |||
162 | * Moved the freeing of the private inode section from put_inode() to | ||
163 | clear_inode(). This fixes a potential free twice type bug. Put_inode() | ||
164 | can be called multiple times for each inode struct. [WD] | ||
165 | |||
166 | * Converted all non vfs-callback functions to use befs_sb_info as the | ||
167 | superblock type, rather than struct super_block. This is for | ||
168 | portablity. [WD] | ||
169 | |||
170 | * Fixed a couple of compile warnings due to use of malloc.h, when slab.h | ||
171 | is the new way. (inode.c, super.c) [WD] | ||
172 | |||
173 | * Fixed erronous includes of linux/befs_fs_i.h and linux/befs_fs_sb.h | ||
174 | in inode.c [WD] | ||
175 | |||
176 | Version 0.45 (2001-10-29) | ||
177 | ========== | ||
178 | * Added functions to get the private superblock and inode structures from | ||
179 | their enclosing public structures. Switched all references to the | ||
180 | private portions to use them. (many files) [WD] | ||
181 | |||
182 | * Made read_super and read_inode allocate the private portions of those | ||
183 | structures into the generic pointer fields of the public structures | ||
184 | with kmalloc(). put_super and put_inode free them. This allows us not | ||
185 | to have to touch the definitions of the public structures in | ||
186 | include/linux/fs.h. Also, befs_inode_info is huge (becuase of the | ||
187 | symlink string). (super.c, inode.c, befs_fs.h) [WD] | ||
188 | |||
189 | * Fixed a thinko that was corrupting file reads after the first block_run | ||
190 | is done being read. (datastream.c) [WD] | ||
191 | |||
192 | * Removed fsync() hooks, since a read-only filesystem doesn't need them. | ||
193 | [Christoph Hellwig]. | ||
194 | |||
195 | * Fixed befs_readlink() (symlink.c) [Christoph Hellwig]. | ||
196 | |||
197 | * Removed all the Read-Write stuff. I'll redo it when it is time to add | ||
198 | write support (various files) [WD]. | ||
199 | |||
200 | * Removed prototypes for functions who's definitions have been removed | ||
201 | (befs_fs.h) [WD]. | ||
202 | |||
203 | |||
204 | Version 0.4 (2001-10-28) | ||
205 | ========== | ||
206 | * Made it an option to use the old non-pagecache befs_file_read() for | ||
207 | testing purposes. (fs/Config.in) | ||
208 | |||
209 | * Fixed unused variable warnings when compiling without debugging. | ||
210 | |||
211 | * Fixed a bug where the inode and super_block didn't get their blockbits | ||
212 | fields set (inode.c and super.c). | ||
213 | |||
214 | * Release patch version 11. AKA befs-driver version 0.4. | ||
215 | |||
216 | * Thats right. New versioning scheme. | ||
217 | I've done some serious testing on it now (on my box anyhow), and it | ||
218 | seems stable and not outragously slow. Existing features are more-or-less | ||
219 | correct (see TODO list). But it isn't 1.0 yet. I think 0.4 gives me some | ||
220 | headroom before the big 1.0. | ||
221 | |||
222 | |||
223 | 2001-10-26 | ||
224 | ========== | ||
225 | * Fixed date format in this file. Was I smoking crack? | ||
226 | |||
227 | * Removed old datastream code from file.c, since it is nolonger used. | ||
228 | |||
229 | * Generic_read_file() is now used to read regular file data. | ||
230 | It doesn't chew up the buffer cache (it does page io instead), and seems | ||
231 | to be about as fast (even though it has to look up each file block | ||
232 | indivdualy). And it knows about doing readahead, which is a major plus. | ||
233 | So it does i/o in much larger chunks. It is the correct linux way. It | ||
234 | uses befs_get_block() by way of befs_readpage() to find the disk offsets | ||
235 | of blocks, which in turn calls befs_fpos2brun() in datastream.c to do | ||
236 | the hard work of finding the disk block number. | ||
237 | |||
238 | * Changed method of checking for a dirty filesystem in befs_read_super | ||
239 | (super.c). Now we check to see if log_start and log_end differ. If so, | ||
240 | the journal needs to be replayed, and the filesystem cannot be mounted. | ||
241 | |||
242 | * Fixed an extra instance of MOD_DEC_USE_COUNT in super.c | ||
243 | |||
244 | * Fixed a problem with reading the superblock on devices with large sector | ||
245 | sizes (such as cdroms) on linux 2.4.10 and up. | ||
246 | |||
247 | 2001-10-24 | ||
248 | ========== | ||
249 | * Fix nasty bug in converting block numbers to struct befs_inode_addr. | ||
250 | Subtle, because the old version was only sometimes wrong. | ||
251 | Probably responsible for lots of problems. (inode.c) | ||
252 | |||
253 | * Fix bug with reading an empty directory. (btree.c and dir.c) | ||
254 | |||
255 | * This one looks good. Release patch version 10 | ||
256 | |||
257 | 2001-10-23 | ||
258 | ========== | ||
259 | * Added btree searching function. | ||
260 | |||
261 | * Use befs_btree_find in befs_lookup (namei.c) | ||
262 | |||
263 | * Additional comments in btree.c | ||
264 | |||
265 | 2001-10-22 | ||
266 | ========== | ||
267 | * Added B+tree reading functions (in btree.c). | ||
268 | Made befs_readdir() use them them instead of the cruft in index.c. | ||
269 | |||
270 | 2001-09-11 | ||
271 | ========== | ||
272 | * Converted befs_read_file() to use the new datastream code. | ||
273 | |||
274 | * Finally updated the README file. | ||
275 | |||
276 | * Added many comments. | ||
277 | |||
278 | * Posted version 6 | ||
279 | |||
280 | * Removed byte-order conversion code. | ||
281 | I have no intention of supporting it, and it was very ugly. | ||
282 | Flow control with #ifdef (ugh). Maybe I'll redo it once | ||
283 | native byteorder works 100%. | ||
284 | |||
285 | 2001-09-10 | ||
286 | ========== | ||
287 | * Finished implementing read_datastream() | ||
288 | |||
289 | * made befs_read_brun() more general | ||
290 | Supports an offset to start at and a max bytes to read | ||
291 | Added a wrapper function to give the old call | ||
292 | |||
293 | 2001-09-30 | ||
294 | ========== | ||
295 | * Discovered that the datastream handleing code in file.c is quite deficient | ||
296 | in several respects. For one thing, it doesn't deal with indirect blocks | ||
297 | |||
298 | * Rewrote datastream handleing. | ||
299 | |||
300 | * Created io.c, for io related functions. | ||
301 | Previously, the befs_bread() funtions lived in file.c | ||
302 | Created the befs_read_brun() function. | ||
303 | |||
304 | |||
305 | 2001-09-07 | ||
306 | ========== | ||
307 | * Made a function to actually count the number of fs blocks used by a file. | ||
308 | And helper functions. | ||
309 | (fs/befs/inode.c) | ||
310 | |||
311 | 2001-09-05 | ||
312 | ========== | ||
313 | * Fixed a misunderstanding of the inode fields. | ||
314 | This fixed the problmem with wrong file sizes from du and others. | ||
315 | The i_blocks field of the inode struct is not the number of blocks for the | ||
316 | inode, it is the number of blocks for the file. Also, i_blksize is not | ||
317 | necessarily the size of the inode, although in practice it works out. | ||
318 | Changed to blocksize of filesystem. | ||
319 | (fs/befs/inode.c) | ||
320 | |||
321 | * Permanently removed code that had been provisionally ifdefed out of befs_fs.h | ||
322 | |||
323 | * Since we don't support access time, make that field zero, instead of | ||
324 | copying m_time. | ||
325 | (fs/befs/inode.c) | ||
326 | |||
327 | * Added sanity check for inode reading | ||
328 | Make sure inode we got was the one we asked for. | ||
329 | (fs/befs/inode.c) | ||
330 | |||
331 | * Code cleanup | ||
332 | Local pointers to commonly used structures in inode.c. | ||
333 | Got rid of abominations befs_iaddr2inode() and befs_inode2ino(). | ||
334 | Replaced with single function iaddr2blockno(). | ||
335 | (fs/befs/super.c) (fs/befs/inode.c) | ||
336 | |||
337 | 2001-09-01 | ||
338 | ========== | ||
339 | * Fixed the problem with statfs where it would always claim the disk was | ||
340 | half full, due to improper understanding of the statfs fields. | ||
341 | (fs/befs/super.c) | ||
342 | |||
343 | * Posted verion 4 of the patch | ||
344 | |||
345 | 2001-09-01 | ||
346 | ========== | ||
347 | * Changed the macros in befs_fs.h to inline functions. | ||
348 | More readable. Typesafe. Better | ||
349 | (include/linux/befs_fs.h) | ||
350 | |||
351 | * Moved type definitions from befs_fs.h to a new file, befs_fs_types.h | ||
352 | Because befs_fs_i.h and befs_fs_sb.h were including befs_fs.h for the | ||
353 | typedefs, and they are inlcuded in <linux/fs.h>, which has definitions | ||
354 | that I want the inline functions in befs_fs.h to be able to see. Nasty | ||
355 | circularity. | ||
356 | (include/linux/befs_fs.h) | ||
357 | |||
358 | 2001-08-30 | ||
359 | ========== | ||
360 | * Cleaned up some wording. | ||
361 | |||
362 | * Added additional consitency checks on mount | ||
363 | Check block_size agrees with block_shift | ||
364 | Check flags == BEFS_CLEAN | ||
365 | (fs/befs/super.c) | ||
366 | |||
367 | * Tell the kernel to only mount befs read-only. | ||
368 | By setting the MS_RDONLY flag in befs_read_super(). | ||
369 | Not that it was possible to write before. But now the kernel won't even try. | ||
370 | (fs/befs/super.c) | ||
371 | |||
372 | * Got rid of kernel warning on mount. | ||
373 | The kernel doesn't like it if you call set_blocksize() on a device when | ||
374 | you have some of its blocks open. Moved the second set_blocksize() to the | ||
375 | very end of befs_read_super(), after we are done with the disk superblock. | ||
376 | (fs/befs/super.c) | ||
377 | |||
378 | * Fixed wrong number of args bug in befs_dump_inode | ||
379 | (fs/befs/debug.c) | ||
380 | |||
381 | * Solved lots of type mismatches in kprint()s | ||
382 | (everwhere) | ||
383 | |||
384 | 2001-08-27 | ||
385 | ========== | ||
386 | * Cleaned up the fs/Config.in entries a bit, now slightly more descriptive. | ||
387 | |||
388 | * BeFS depends on NLS, so I made activating BeFS enable the NLS questions | ||
389 | (fs/nls/Config.in) | ||
390 | |||
391 | * Added Configure.help entries for CONFIG_BEFS_FS and CONFIG_DEBUG_BEFS | ||
392 | (Documentation/Configure.help) | ||
393 | |||
394 | 2001-08-?? | ||
395 | ========== | ||
396 | * Removed superblock locking calls in befs_read_super(). In 2.4, the VFS | ||
397 | hands us a super_block struct that is already locked. | ||
398 | |||
399 | 2001-08-13 | ||
400 | ========== | ||
401 | * Will Dyson <will_dyson@pobox.com> is now attempting to maintain this module | ||
402 | Makoto Kato <m_kato@ga2.so-net.ne.jp> is original author.Daniel Berlin | ||
403 | also did some work on it (fixing it up for the later 2.3.x kernels, IIRC). | ||
404 | |||
405 | * Fixed compile errors on 2.4.1 kernel (WD) | ||
406 | Resolve rejected patches | ||
407 | Accomodate changed NLS interface (util.h) | ||
408 | Needed to include <linux/slab.h> in most files | ||
409 | Makefile changes | ||
410 | fs/Config.in changes | ||
411 | |||
412 | * Tried to niceify the code using the ext2 fs as a guide | ||
413 | Declare befs_fs_type using the DECLARE_FSTYPE_DEV() macro | ||
414 | |||
415 | * Made it a configure option to turn on debugging (fs/Config.in) | ||
416 | |||
417 | * Compiles on 2.4.7 | ||
diff --git a/fs/befs/Makefile b/fs/befs/Makefile new file mode 100644 index 000000000000..2f370bd7a50d --- /dev/null +++ b/fs/befs/Makefile | |||
@@ -0,0 +1,7 @@ | |||
1 | # | ||
2 | # Makefile for the linux BeOS filesystem routines. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_BEFS_FS) += befs.o | ||
6 | |||
7 | befs-objs := datastream.o btree.o super.o inode.o debug.o io.o linuxvfs.o | ||
diff --git a/fs/befs/TODO b/fs/befs/TODO new file mode 100644 index 000000000000..3250921aa2e6 --- /dev/null +++ b/fs/befs/TODO | |||
@@ -0,0 +1,14 @@ | |||
1 | TODO | ||
2 | ========== | ||
3 | |||
4 | * Convert comments to the Kernel-Doc format. | ||
5 | |||
6 | * Befs_fs.h has gotten big and messy. No reason not to break it up into | ||
7 | smaller peices. | ||
8 | |||
9 | * See if Alexander Viro's option parser made it into the kernel tree. | ||
10 | Use that if we can. (include/linux/parser.h) | ||
11 | |||
12 | * See if we really need separate types for on-disk and in-memory | ||
13 | representations of the superblock and inode. | ||
14 | |||
diff --git a/fs/befs/attribute.c b/fs/befs/attribute.c new file mode 100644 index 000000000000..e329d727053e --- /dev/null +++ b/fs/befs/attribute.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/attribute.c | ||
3 | * | ||
4 | * Copyright (C) 2002 Will Dyson <will_dyson@pobox.com> | ||
5 | * | ||
6 | * Many thanks to Dominic Giampaolo, author of "Practical File System | ||
7 | * Design with the Be File System", for such a helpful book. | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/fs.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/string.h> | ||
14 | |||
15 | #include "befs.h" | ||
16 | #include "endian.h" | ||
17 | |||
18 | #define SD_DATA(sd)\ | ||
19 | (void*)((char*)sd + sizeof(*sd) + (sd->name_size - sizeof(sd->name))) | ||
20 | |||
21 | #define SD_NEXT(sd)\ | ||
22 | (befs_small_data*)((char*)sd + sizeof(*sd) + (sd->name_size - \ | ||
23 | sizeof(sd->name) + sd->data_size)) | ||
24 | |||
25 | int | ||
26 | list_small_data(struct super_block *sb, befs_inode * inode, filldir_t filldir); | ||
27 | |||
28 | befs_small_data * | ||
29 | find_small_data(struct super_block *sb, befs_inode * inode, | ||
30 | const char *name); | ||
31 | int | ||
32 | read_small_data(struct super_block *sb, befs_inode * inode, | ||
33 | befs_small_data * sdata, void *buf, size_t bufsize); | ||
34 | |||
35 | /** | ||
36 | * | ||
37 | * | ||
38 | * | ||
39 | * | ||
40 | * | ||
41 | */ | ||
42 | befs_small_data * | ||
43 | find_small_data(struct super_block *sb, befs_inode * inode, const char *name) | ||
44 | { | ||
45 | befs_small_data *sdata = inode->small_data; | ||
46 | |||
47 | while (sdata->type != 0) { | ||
48 | if (strcmp(name, sdata->name) != 0) { | ||
49 | return sdata; | ||
50 | } | ||
51 | sdata = SD_NEXT(sdata); | ||
52 | } | ||
53 | return NULL; | ||
54 | } | ||
55 | |||
56 | /** | ||
57 | * | ||
58 | * | ||
59 | * | ||
60 | * | ||
61 | * | ||
62 | */ | ||
63 | int | ||
64 | read_small_data(struct super_block *sb, befs_inode * inode, | ||
65 | const char *name, void *buf, size_t bufsize) | ||
66 | { | ||
67 | befs_small_data *sdata; | ||
68 | |||
69 | sdata = find_small_data(sb, inode, name); | ||
70 | if (sdata == NULL) | ||
71 | return BEFS_ERR; | ||
72 | else if (sdata->data_size > bufsize) | ||
73 | return BEFS_ERR; | ||
74 | |||
75 | memcpy(buf, SD_DATA(sdata), sdata->data_size); | ||
76 | |||
77 | return BEFS_OK; | ||
78 | } | ||
79 | |||
80 | /** | ||
81 | * | ||
82 | * | ||
83 | * | ||
84 | * | ||
85 | * | ||
86 | */ | ||
87 | int | ||
88 | list_small_data(struct super_block *sb, befs_inode * inode) | ||
89 | { | ||
90 | |||
91 | } | ||
92 | |||
93 | /** | ||
94 | * | ||
95 | * | ||
96 | * | ||
97 | * | ||
98 | * | ||
99 | */ | ||
100 | int | ||
101 | list_attr(struct super_block *sb, befs_inode * inode) | ||
102 | { | ||
103 | |||
104 | } | ||
105 | |||
106 | /** | ||
107 | * | ||
108 | * | ||
109 | * | ||
110 | * | ||
111 | * | ||
112 | */ | ||
113 | int | ||
114 | read_attr(struct super_block *sb, befs_inode * inode) | ||
115 | { | ||
116 | |||
117 | } | ||
diff --git a/fs/befs/befs.h b/fs/befs/befs.h new file mode 100644 index 000000000000..057a2c3d73b7 --- /dev/null +++ b/fs/befs/befs.h | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * befs.h | ||
3 | * | ||
4 | * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> | ||
5 | * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp) | ||
6 | */ | ||
7 | |||
8 | #ifndef _LINUX_BEFS_H | ||
9 | #define _LINUX_BEFS_H | ||
10 | |||
11 | #include "befs_fs_types.h" | ||
12 | |||
13 | /* used in debug.c */ | ||
14 | #define BEFS_VERSION "0.9.3" | ||
15 | |||
16 | |||
17 | typedef u64 befs_blocknr_t; | ||
18 | /* | ||
19 | * BeFS in memory structures | ||
20 | */ | ||
21 | |||
22 | typedef struct befs_mount_options { | ||
23 | gid_t gid; | ||
24 | uid_t uid; | ||
25 | int use_gid; | ||
26 | int use_uid; | ||
27 | int debug; | ||
28 | char *iocharset; | ||
29 | } befs_mount_options; | ||
30 | |||
31 | typedef struct befs_sb_info { | ||
32 | u32 magic1; | ||
33 | u32 block_size; | ||
34 | u32 block_shift; | ||
35 | int byte_order; | ||
36 | befs_off_t num_blocks; | ||
37 | befs_off_t used_blocks; | ||
38 | u32 inode_size; | ||
39 | u32 magic2; | ||
40 | |||
41 | /* Allocation group information */ | ||
42 | u32 blocks_per_ag; | ||
43 | u32 ag_shift; | ||
44 | u32 num_ags; | ||
45 | |||
46 | /* jornal log entry */ | ||
47 | befs_block_run log_blocks; | ||
48 | befs_off_t log_start; | ||
49 | befs_off_t log_end; | ||
50 | |||
51 | befs_inode_addr root_dir; | ||
52 | befs_inode_addr indices; | ||
53 | u32 magic3; | ||
54 | |||
55 | befs_mount_options mount_opts; | ||
56 | struct nls_table *nls; | ||
57 | |||
58 | } befs_sb_info; | ||
59 | |||
60 | typedef struct befs_inode_info { | ||
61 | u32 i_flags; | ||
62 | u32 i_type; | ||
63 | |||
64 | befs_inode_addr i_inode_num; | ||
65 | befs_inode_addr i_parent; | ||
66 | befs_inode_addr i_attribute; | ||
67 | |||
68 | union { | ||
69 | befs_data_stream ds; | ||
70 | char symlink[BEFS_SYMLINK_LEN]; | ||
71 | } i_data; | ||
72 | |||
73 | struct inode vfs_inode; | ||
74 | |||
75 | } befs_inode_info; | ||
76 | |||
77 | enum befs_err { | ||
78 | BEFS_OK, | ||
79 | BEFS_ERR, | ||
80 | BEFS_BAD_INODE, | ||
81 | BEFS_BT_END, | ||
82 | BEFS_BT_EMPTY, | ||
83 | BEFS_BT_MATCH, | ||
84 | BEFS_BT_PARMATCH, | ||
85 | BEFS_BT_NOT_FOUND | ||
86 | }; | ||
87 | |||
88 | |||
89 | /****************************/ | ||
90 | /* debug.c */ | ||
91 | void befs_error(const struct super_block *sb, const char *fmt, ...); | ||
92 | void befs_warning(const struct super_block *sb, const char *fmt, ...); | ||
93 | void befs_debug(const struct super_block *sb, const char *fmt, ...); | ||
94 | |||
95 | void befs_dump_super_block(const struct super_block *sb, befs_super_block *); | ||
96 | void befs_dump_inode(const struct super_block *sb, befs_inode *); | ||
97 | void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *); | ||
98 | void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *); | ||
99 | /****************************/ | ||
100 | |||
101 | |||
102 | /* Gets a pointer to the private portion of the super_block | ||
103 | * structure from the public part | ||
104 | */ | ||
105 | static inline befs_sb_info * | ||
106 | BEFS_SB(const struct super_block *super) | ||
107 | { | ||
108 | return (befs_sb_info *) super->s_fs_info; | ||
109 | } | ||
110 | |||
111 | static inline befs_inode_info * | ||
112 | BEFS_I(const struct inode *inode) | ||
113 | { | ||
114 | return list_entry(inode, struct befs_inode_info, vfs_inode); | ||
115 | } | ||
116 | |||
117 | static inline befs_blocknr_t | ||
118 | iaddr2blockno(struct super_block *sb, befs_inode_addr * iaddr) | ||
119 | { | ||
120 | return ((iaddr->allocation_group << BEFS_SB(sb)->ag_shift) + | ||
121 | iaddr->start); | ||
122 | } | ||
123 | |||
124 | static inline befs_inode_addr | ||
125 | blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno) | ||
126 | { | ||
127 | befs_inode_addr iaddr; | ||
128 | iaddr.allocation_group = blockno >> BEFS_SB(sb)->ag_shift; | ||
129 | iaddr.start = | ||
130 | blockno - (iaddr.allocation_group << BEFS_SB(sb)->ag_shift); | ||
131 | iaddr.len = 1; | ||
132 | |||
133 | return iaddr; | ||
134 | } | ||
135 | |||
136 | static inline unsigned int | ||
137 | befs_iaddrs_per_block(struct super_block *sb) | ||
138 | { | ||
139 | return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr); | ||
140 | } | ||
141 | |||
142 | static inline int | ||
143 | befs_iaddr_is_empty(befs_inode_addr * iaddr) | ||
144 | { | ||
145 | return (!iaddr->allocation_group) && (!iaddr->start) && (!iaddr->len); | ||
146 | } | ||
147 | |||
148 | static inline size_t | ||
149 | befs_brun_size(struct super_block *sb, befs_block_run run) | ||
150 | { | ||
151 | return BEFS_SB(sb)->block_size * run.len; | ||
152 | } | ||
153 | |||
154 | #endif /* _LINUX_BEFS_H */ | ||
diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h new file mode 100644 index 000000000000..9095518e918d --- /dev/null +++ b/fs/befs/befs_fs_types.h | |||
@@ -0,0 +1,213 @@ | |||
1 | /* | ||
2 | * include/linux/befs_fs_types.h | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson (will@cs.earlham.edu) | ||
5 | * | ||
6 | * | ||
7 | * | ||
8 | * from linux/include/linux/befs_fs.h | ||
9 | * | ||
10 | * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp) | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef _LINUX_BEFS_FS_TYPES | ||
15 | #define _LINUX_BEFS_FS_TYPES | ||
16 | |||
17 | #ifdef __KERNEL__ | ||
18 | #include <linux/types.h> | ||
19 | #endif /*__KERNEL__*/ | ||
20 | |||
21 | #define PACKED __attribute__ ((__packed__)) | ||
22 | |||
23 | /* | ||
24 | * Max name lengths of BFS | ||
25 | */ | ||
26 | |||
27 | #define BEFS_NAME_LEN 255 | ||
28 | |||
29 | #define BEFS_SYMLINK_LEN 144 | ||
30 | #define BEFS_NUM_DIRECT_BLOCKS 12 | ||
31 | #define B_OS_NAME_LENGTH 32 | ||
32 | |||
33 | /* The datastream blocks mapped by the double-indirect | ||
34 | * block are always 4 fs blocks long. | ||
35 | * This eliminates the need for linear searches among | ||
36 | * the potentially huge number of indirect blocks | ||
37 | * | ||
38 | * Err. Should that be 4 fs blocks or 4k??? | ||
39 | * It matters on large blocksize volumes | ||
40 | */ | ||
41 | #define BEFS_DBLINDIR_BRUN_LEN 4 | ||
42 | |||
43 | /* | ||
44 | * Flags of superblock | ||
45 | */ | ||
46 | |||
47 | enum super_flags { | ||
48 | BEFS_BYTESEX_BE, | ||
49 | BEFS_BYTESEX_LE, | ||
50 | BEFS_CLEAN = 0x434c454e, | ||
51 | BEFS_DIRTY = 0x44495254, | ||
52 | BEFS_SUPER_MAGIC1 = 0x42465331, /* BFS1 */ | ||
53 | BEFS_SUPER_MAGIC2 = 0xdd121031, | ||
54 | BEFS_SUPER_MAGIC3 = 0x15b6830e, | ||
55 | }; | ||
56 | |||
57 | #define BEFS_BYTEORDER_NATIVE 0x42494745 | ||
58 | |||
59 | #define BEFS_SUPER_MAGIC BEFS_SUPER_MAGIC1 | ||
60 | |||
61 | /* | ||
62 | * Flags of inode | ||
63 | */ | ||
64 | |||
65 | #define BEFS_INODE_MAGIC1 0x3bbe0ad9 | ||
66 | |||
67 | enum inode_flags { | ||
68 | BEFS_INODE_IN_USE = 0x00000001, | ||
69 | BEFS_ATTR_INODE = 0x00000004, | ||
70 | BEFS_INODE_LOGGED = 0x00000008, | ||
71 | BEFS_INODE_DELETED = 0x00000010, | ||
72 | BEFS_LONG_SYMLINK = 0x00000040, | ||
73 | BEFS_PERMANENT_FLAG = 0x0000ffff, | ||
74 | BEFS_INODE_NO_CREATE = 0x00010000, | ||
75 | BEFS_INODE_WAS_WRITTEN = 0x00020000, | ||
76 | BEFS_NO_TRANSACTION = 0x00040000, | ||
77 | }; | ||
78 | /* | ||
79 | * On-Disk datastructures of BeFS | ||
80 | */ | ||
81 | |||
82 | typedef u64 befs_off_t; | ||
83 | typedef u64 befs_time_t; | ||
84 | typedef void befs_binode_etc; | ||
85 | |||
86 | /* Block runs */ | ||
87 | typedef struct { | ||
88 | u32 allocation_group; | ||
89 | u16 start; | ||
90 | u16 len; | ||
91 | } PACKED befs_block_run; | ||
92 | |||
93 | typedef befs_block_run befs_inode_addr; | ||
94 | |||
95 | /* | ||
96 | * The Superblock Structure | ||
97 | */ | ||
98 | typedef struct { | ||
99 | char name[B_OS_NAME_LENGTH]; | ||
100 | u32 magic1; | ||
101 | u32 fs_byte_order; | ||
102 | |||
103 | u32 block_size; | ||
104 | u32 block_shift; | ||
105 | |||
106 | befs_off_t num_blocks; | ||
107 | befs_off_t used_blocks; | ||
108 | |||
109 | u32 inode_size; | ||
110 | |||
111 | u32 magic2; | ||
112 | u32 blocks_per_ag; | ||
113 | u32 ag_shift; | ||
114 | u32 num_ags; | ||
115 | |||
116 | u32 flags; | ||
117 | |||
118 | befs_block_run log_blocks; | ||
119 | befs_off_t log_start; | ||
120 | befs_off_t log_end; | ||
121 | |||
122 | u32 magic3; | ||
123 | befs_inode_addr root_dir; | ||
124 | befs_inode_addr indices; | ||
125 | |||
126 | } PACKED befs_super_block; | ||
127 | |||
128 | /* | ||
129 | * Note: the indirect and dbl_indir block_runs may | ||
130 | * be longer than one block! | ||
131 | */ | ||
132 | typedef struct { | ||
133 | befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS]; | ||
134 | befs_off_t max_direct_range; | ||
135 | befs_block_run indirect; | ||
136 | befs_off_t max_indirect_range; | ||
137 | befs_block_run double_indirect; | ||
138 | befs_off_t max_double_indirect_range; | ||
139 | befs_off_t size; | ||
140 | } PACKED befs_data_stream; | ||
141 | |||
142 | /* Attribute */ | ||
143 | typedef struct { | ||
144 | u32 type; | ||
145 | u16 name_size; | ||
146 | u16 data_size; | ||
147 | char name[1]; | ||
148 | } PACKED befs_small_data; | ||
149 | |||
150 | /* Inode structure */ | ||
151 | typedef struct { | ||
152 | u32 magic1; | ||
153 | befs_inode_addr inode_num; | ||
154 | u32 uid; | ||
155 | u32 gid; | ||
156 | u32 mode; | ||
157 | u32 flags; | ||
158 | befs_time_t create_time; | ||
159 | befs_time_t last_modified_time; | ||
160 | befs_inode_addr parent; | ||
161 | befs_inode_addr attributes; | ||
162 | u32 type; | ||
163 | |||
164 | u32 inode_size; | ||
165 | u32 etc; /* not use */ | ||
166 | |||
167 | union { | ||
168 | befs_data_stream datastream; | ||
169 | char symlink[BEFS_SYMLINK_LEN]; | ||
170 | } data; | ||
171 | |||
172 | u32 pad[4]; /* not use */ | ||
173 | befs_small_data small_data[1]; | ||
174 | } PACKED befs_inode; | ||
175 | |||
176 | /* | ||
177 | * B+tree superblock | ||
178 | */ | ||
179 | |||
180 | #define BEFS_BTREE_MAGIC 0x69f6c2e8 | ||
181 | |||
182 | enum btree_types { | ||
183 | BTREE_STRING_TYPE = 0, | ||
184 | BTREE_INT32_TYPE = 1, | ||
185 | BTREE_UINT32_TYPE = 2, | ||
186 | BTREE_INT64_TYPE = 3, | ||
187 | BTREE_UINT64_TYPE = 4, | ||
188 | BTREE_FLOAT_TYPE = 5, | ||
189 | BTREE_DOUBLE_TYPE = 6 | ||
190 | }; | ||
191 | |||
192 | typedef struct { | ||
193 | u32 magic; | ||
194 | u32 node_size; | ||
195 | u32 max_depth; | ||
196 | u32 data_type; | ||
197 | befs_off_t root_node_ptr; | ||
198 | befs_off_t free_node_ptr; | ||
199 | befs_off_t max_size; | ||
200 | } PACKED befs_btree_super; | ||
201 | |||
202 | /* | ||
203 | * Header stucture of each btree node | ||
204 | */ | ||
205 | typedef struct { | ||
206 | befs_off_t left; | ||
207 | befs_off_t right; | ||
208 | befs_off_t overflow; | ||
209 | u16 all_key_count; | ||
210 | u16 all_key_length; | ||
211 | } PACKED befs_btree_nodehead; | ||
212 | |||
213 | #endif /* _LINUX_BEFS_FS_TYPES */ | ||
diff --git a/fs/befs/btree.c b/fs/befs/btree.c new file mode 100644 index 000000000000..76e219799409 --- /dev/null +++ b/fs/befs/btree.c | |||
@@ -0,0 +1,788 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/btree.c | ||
3 | * | ||
4 | * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> | ||
5 | * | ||
6 | * Licensed under the GNU GPL. See the file COPYING for details. | ||
7 | * | ||
8 | * 2002-02-05: Sergey S. Kostyliov added binary search withing | ||
9 | * btree nodes. | ||
10 | * | ||
11 | * Many thanks to: | ||
12 | * | ||
13 | * Dominic Giampaolo, author of "Practical File System | ||
14 | * Design with the Be File System", for such a helpful book. | ||
15 | * | ||
16 | * Marcus J. Ranum, author of the b+tree package in | ||
17 | * comp.sources.misc volume 10. This code is not copied from that | ||
18 | * work, but it is partially based on it. | ||
19 | * | ||
20 | * Makoto Kato, author of the original BeFS for linux filesystem | ||
21 | * driver. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/mm.h> | ||
28 | #include <linux/buffer_head.h> | ||
29 | |||
30 | #include "befs.h" | ||
31 | #include "btree.h" | ||
32 | #include "datastream.h" | ||
33 | #include "endian.h" | ||
34 | |||
35 | /* | ||
36 | * The btree functions in this file are built on top of the | ||
37 | * datastream.c interface, which is in turn built on top of the | ||
38 | * io.c interface. | ||
39 | */ | ||
40 | |||
41 | /* Befs B+tree structure: | ||
42 | * | ||
43 | * The first thing in the tree is the tree superblock. It tells you | ||
44 | * all kinds of useful things about the tree, like where the rootnode | ||
45 | * is located, and the size of the nodes (always 1024 with current version | ||
46 | * of BeOS). | ||
47 | * | ||
48 | * The rest of the tree consists of a series of nodes. Nodes contain a header | ||
49 | * (struct befs_btree_nodehead), the packed key data, an array of shorts | ||
50 | * containing the ending offsets for each of the keys, and an array of | ||
51 | * befs_off_t values. In interior nodes, the keys are the ending keys for | ||
52 | * the childnode they point to, and the values are offsets into the | ||
53 | * datastream containing the tree. | ||
54 | */ | ||
55 | |||
56 | /* Note: | ||
57 | * | ||
58 | * The book states 2 confusing things about befs b+trees. First, | ||
59 | * it states that the overflow field of node headers is used by internal nodes | ||
60 | * to point to another node that "effectively continues this one". Here is what | ||
61 | * I believe that means. Each key in internal nodes points to another node that | ||
62 | * contains key values less than itself. Inspection reveals that the last key | ||
63 | * in the internal node is not the last key in the index. Keys that are | ||
64 | * greater than the last key in the internal node go into the overflow node. | ||
65 | * I imagine there is a performance reason for this. | ||
66 | * | ||
67 | * Second, it states that the header of a btree node is sufficient to | ||
68 | * distinguish internal nodes from leaf nodes. Without saying exactly how. | ||
69 | * After figuring out the first, it becomes obvious that internal nodes have | ||
70 | * overflow nodes and leafnodes do not. | ||
71 | */ | ||
72 | |||
73 | /* | ||
74 | * Currently, this code is only good for directory B+trees. | ||
75 | * In order to be used for other BFS indexes, it needs to be extended to handle | ||
76 | * duplicate keys and non-string keytypes (int32, int64, float, double). | ||
77 | */ | ||
78 | |||
79 | /* | ||
80 | * In memory structure of each btree node | ||
81 | */ | ||
82 | typedef struct { | ||
83 | befs_btree_nodehead head; /* head of node converted to cpu byteorder */ | ||
84 | struct buffer_head *bh; | ||
85 | befs_btree_nodehead *od_node; /* on disk node */ | ||
86 | } befs_btree_node; | ||
87 | |||
88 | /* local constants */ | ||
89 | static const befs_off_t befs_bt_inval = 0xffffffffffffffffULL; | ||
90 | |||
91 | /* local functions */ | ||
92 | static int befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, | ||
93 | befs_btree_super * bt_super, | ||
94 | befs_btree_node * this_node, | ||
95 | befs_off_t * node_off); | ||
96 | |||
97 | static int befs_bt_read_super(struct super_block *sb, befs_data_stream * ds, | ||
98 | befs_btree_super * sup); | ||
99 | |||
100 | static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds, | ||
101 | befs_btree_node * node, befs_off_t node_off); | ||
102 | |||
103 | static int befs_leafnode(befs_btree_node * node); | ||
104 | |||
105 | static u16 *befs_bt_keylen_index(befs_btree_node * node); | ||
106 | |||
107 | static befs_off_t *befs_bt_valarray(befs_btree_node * node); | ||
108 | |||
109 | static char *befs_bt_keydata(befs_btree_node * node); | ||
110 | |||
111 | static int befs_find_key(struct super_block *sb, befs_btree_node * node, | ||
112 | const char *findkey, befs_off_t * value); | ||
113 | |||
114 | static char *befs_bt_get_key(struct super_block *sb, befs_btree_node * node, | ||
115 | int index, u16 * keylen); | ||
116 | |||
117 | static int befs_compare_strings(const void *key1, int keylen1, | ||
118 | const void *key2, int keylen2); | ||
119 | |||
120 | /** | ||
121 | * befs_bt_read_super - read in btree superblock convert to cpu byteorder | ||
122 | * @sb: Filesystem superblock | ||
123 | * @ds: Datastream to read from | ||
124 | * @sup: Buffer in which to place the btree superblock | ||
125 | * | ||
126 | * Calls befs_read_datastream to read in the btree superblock and | ||
127 | * makes sure it is in cpu byteorder, byteswapping if necessary. | ||
128 | * | ||
129 | * On success, returns BEFS_OK and *@sup contains the btree superblock, | ||
130 | * in cpu byte order. | ||
131 | * | ||
132 | * On failure, BEFS_ERR is returned. | ||
133 | */ | ||
134 | static int | ||
135 | befs_bt_read_super(struct super_block *sb, befs_data_stream * ds, | ||
136 | befs_btree_super * sup) | ||
137 | { | ||
138 | struct buffer_head *bh = NULL; | ||
139 | befs_btree_super *od_sup = NULL; | ||
140 | |||
141 | befs_debug(sb, "---> befs_btree_read_super()"); | ||
142 | |||
143 | bh = befs_read_datastream(sb, ds, 0, NULL); | ||
144 | |||
145 | if (!bh) { | ||
146 | befs_error(sb, "Couldn't read index header."); | ||
147 | goto error; | ||
148 | } | ||
149 | od_sup = (befs_btree_super *) bh->b_data; | ||
150 | befs_dump_index_entry(sb, od_sup); | ||
151 | |||
152 | sup->magic = fs32_to_cpu(sb, od_sup->magic); | ||
153 | sup->node_size = fs32_to_cpu(sb, od_sup->node_size); | ||
154 | sup->max_depth = fs32_to_cpu(sb, od_sup->max_depth); | ||
155 | sup->data_type = fs32_to_cpu(sb, od_sup->data_type); | ||
156 | sup->root_node_ptr = fs64_to_cpu(sb, od_sup->root_node_ptr); | ||
157 | sup->free_node_ptr = fs64_to_cpu(sb, od_sup->free_node_ptr); | ||
158 | sup->max_size = fs64_to_cpu(sb, od_sup->max_size); | ||
159 | |||
160 | brelse(bh); | ||
161 | if (sup->magic != BEFS_BTREE_MAGIC) { | ||
162 | befs_error(sb, "Index header has bad magic."); | ||
163 | goto error; | ||
164 | } | ||
165 | |||
166 | befs_debug(sb, "<--- befs_btree_read_super()"); | ||
167 | return BEFS_OK; | ||
168 | |||
169 | error: | ||
170 | befs_debug(sb, "<--- befs_btree_read_super() ERROR"); | ||
171 | return BEFS_ERR; | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * befs_bt_read_node - read in btree node and convert to cpu byteorder | ||
176 | * @sb: Filesystem superblock | ||
177 | * @ds: Datastream to read from | ||
178 | * @node: Buffer in which to place the btree node | ||
179 | * @node_off: Starting offset (in bytes) of the node in @ds | ||
180 | * | ||
181 | * Calls befs_read_datastream to read in the indicated btree node and | ||
182 | * makes sure its header fields are in cpu byteorder, byteswapping if | ||
183 | * necessary. | ||
184 | * Note: node->bh must be NULL when this function called first | ||
185 | * time. Don't forget brelse(node->bh) after last call. | ||
186 | * | ||
187 | * On success, returns BEFS_OK and *@node contains the btree node that | ||
188 | * starts at @node_off, with the node->head fields in cpu byte order. | ||
189 | * | ||
190 | * On failure, BEFS_ERR is returned. | ||
191 | */ | ||
192 | |||
193 | static int | ||
194 | befs_bt_read_node(struct super_block *sb, befs_data_stream * ds, | ||
195 | befs_btree_node * node, befs_off_t node_off) | ||
196 | { | ||
197 | uint off = 0; | ||
198 | |||
199 | befs_debug(sb, "---> befs_bt_read_node()"); | ||
200 | |||
201 | if (node->bh) | ||
202 | brelse(node->bh); | ||
203 | |||
204 | node->bh = befs_read_datastream(sb, ds, node_off, &off); | ||
205 | if (!node->bh) { | ||
206 | befs_error(sb, "befs_bt_read_node() failed to read " | ||
207 | "node at %Lu", node_off); | ||
208 | befs_debug(sb, "<--- befs_bt_read_node() ERROR"); | ||
209 | |||
210 | return BEFS_ERR; | ||
211 | } | ||
212 | node->od_node = | ||
213 | (befs_btree_nodehead *) ((void *) node->bh->b_data + off); | ||
214 | |||
215 | befs_dump_index_node(sb, node->od_node); | ||
216 | |||
217 | node->head.left = fs64_to_cpu(sb, node->od_node->left); | ||
218 | node->head.right = fs64_to_cpu(sb, node->od_node->right); | ||
219 | node->head.overflow = fs64_to_cpu(sb, node->od_node->overflow); | ||
220 | node->head.all_key_count = | ||
221 | fs16_to_cpu(sb, node->od_node->all_key_count); | ||
222 | node->head.all_key_length = | ||
223 | fs16_to_cpu(sb, node->od_node->all_key_length); | ||
224 | |||
225 | befs_debug(sb, "<--- befs_btree_read_node()"); | ||
226 | return BEFS_OK; | ||
227 | } | ||
228 | |||
229 | /** | ||
230 | * befs_btree_find - Find a key in a befs B+tree | ||
231 | * @sb: Filesystem superblock | ||
232 | * @ds: Datastream containing btree | ||
233 | * @key: Key string to lookup in btree | ||
234 | * @value: Value stored with @key | ||
235 | * | ||
236 | * On sucess, returns BEFS_OK and sets *@value to the value stored | ||
237 | * with @key (usually the disk block number of an inode). | ||
238 | * | ||
239 | * On failure, returns BEFS_ERR or BEFS_BT_NOT_FOUND. | ||
240 | * | ||
241 | * Algorithm: | ||
242 | * Read the superblock and rootnode of the b+tree. | ||
243 | * Drill down through the interior nodes using befs_find_key(). | ||
244 | * Once at the correct leaf node, use befs_find_key() again to get the | ||
245 | * actuall value stored with the key. | ||
246 | */ | ||
247 | int | ||
248 | befs_btree_find(struct super_block *sb, befs_data_stream * ds, | ||
249 | const char *key, befs_off_t * value) | ||
250 | { | ||
251 | befs_btree_node *this_node = NULL; | ||
252 | befs_btree_super bt_super; | ||
253 | befs_off_t node_off; | ||
254 | int res; | ||
255 | |||
256 | befs_debug(sb, "---> befs_btree_find() Key: %s", key); | ||
257 | |||
258 | if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) { | ||
259 | befs_error(sb, | ||
260 | "befs_btree_find() failed to read index superblock"); | ||
261 | goto error; | ||
262 | } | ||
263 | |||
264 | this_node = (befs_btree_node *) kmalloc(sizeof (befs_btree_node), | ||
265 | GFP_NOFS); | ||
266 | if (!this_node) { | ||
267 | befs_error(sb, "befs_btree_find() failed to allocate %u " | ||
268 | "bytes of memory", sizeof (befs_btree_node)); | ||
269 | goto error; | ||
270 | } | ||
271 | |||
272 | this_node->bh = NULL; | ||
273 | |||
274 | /* read in root node */ | ||
275 | node_off = bt_super.root_node_ptr; | ||
276 | if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { | ||
277 | befs_error(sb, "befs_btree_find() failed to read " | ||
278 | "node at %Lu", node_off); | ||
279 | goto error_alloc; | ||
280 | } | ||
281 | |||
282 | while (!befs_leafnode(this_node)) { | ||
283 | res = befs_find_key(sb, this_node, key, &node_off); | ||
284 | if (res == BEFS_BT_NOT_FOUND) | ||
285 | node_off = this_node->head.overflow; | ||
286 | /* if no match, go to overflow node */ | ||
287 | if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { | ||
288 | befs_error(sb, "befs_btree_find() failed to read " | ||
289 | "node at %Lu", node_off); | ||
290 | goto error_alloc; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | /* at the correct leaf node now */ | ||
295 | |||
296 | res = befs_find_key(sb, this_node, key, value); | ||
297 | |||
298 | brelse(this_node->bh); | ||
299 | kfree(this_node); | ||
300 | |||
301 | if (res != BEFS_BT_MATCH) { | ||
302 | befs_debug(sb, "<--- befs_btree_find() Key %s not found", key); | ||
303 | *value = 0; | ||
304 | return BEFS_BT_NOT_FOUND; | ||
305 | } | ||
306 | befs_debug(sb, "<--- befs_btree_find() Found key %s, value %Lu", | ||
307 | key, *value); | ||
308 | return BEFS_OK; | ||
309 | |||
310 | error_alloc: | ||
311 | kfree(this_node); | ||
312 | error: | ||
313 | *value = 0; | ||
314 | befs_debug(sb, "<--- befs_btree_find() ERROR"); | ||
315 | return BEFS_ERR; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * befs_find_key - Search for a key within a node | ||
320 | * @sb: Filesystem superblock | ||
321 | * @node: Node to find the key within | ||
322 | * @key: Keystring to search for | ||
323 | * @value: If key is found, the value stored with the key is put here | ||
324 | * | ||
325 | * finds exact match if one exists, and returns BEFS_BT_MATCH | ||
326 | * If no exact match, finds first key in node that is greater | ||
327 | * (alphabetically) than the search key and returns BEFS_BT_PARMATCH | ||
328 | * (for partial match, I guess). Can you think of something better to | ||
329 | * call it? | ||
330 | * | ||
331 | * If no key was a match or greater than the search key, return | ||
332 | * BEFS_BT_NOT_FOUND. | ||
333 | * | ||
334 | * Use binary search instead of a linear. | ||
335 | */ | ||
336 | static int | ||
337 | befs_find_key(struct super_block *sb, befs_btree_node * node, | ||
338 | const char *findkey, befs_off_t * value) | ||
339 | { | ||
340 | int first, last, mid; | ||
341 | int eq; | ||
342 | u16 keylen; | ||
343 | int findkey_len; | ||
344 | char *thiskey; | ||
345 | befs_off_t *valarray; | ||
346 | |||
347 | befs_debug(sb, "---> befs_find_key() %s", findkey); | ||
348 | |||
349 | *value = 0; | ||
350 | |||
351 | findkey_len = strlen(findkey); | ||
352 | |||
353 | /* if node can not contain key, just skeep this node */ | ||
354 | last = node->head.all_key_count - 1; | ||
355 | thiskey = befs_bt_get_key(sb, node, last, &keylen); | ||
356 | |||
357 | eq = befs_compare_strings(thiskey, keylen, findkey, findkey_len); | ||
358 | if (eq < 0) { | ||
359 | befs_debug(sb, "<--- befs_find_key() %s not found", findkey); | ||
360 | return BEFS_BT_NOT_FOUND; | ||
361 | } | ||
362 | |||
363 | valarray = befs_bt_valarray(node); | ||
364 | |||
365 | /* simple binary search */ | ||
366 | first = 0; | ||
367 | mid = 0; | ||
368 | while (last >= first) { | ||
369 | mid = (last + first) / 2; | ||
370 | befs_debug(sb, "first: %d, last: %d, mid: %d", first, last, | ||
371 | mid); | ||
372 | thiskey = befs_bt_get_key(sb, node, mid, &keylen); | ||
373 | eq = befs_compare_strings(thiskey, keylen, findkey, | ||
374 | findkey_len); | ||
375 | |||
376 | if (eq == 0) { | ||
377 | befs_debug(sb, "<--- befs_find_key() found %s at %d", | ||
378 | thiskey, mid); | ||
379 | |||
380 | *value = fs64_to_cpu(sb, valarray[mid]); | ||
381 | return BEFS_BT_MATCH; | ||
382 | } | ||
383 | if (eq > 0) | ||
384 | last = mid - 1; | ||
385 | else | ||
386 | first = mid + 1; | ||
387 | } | ||
388 | if (eq < 0) | ||
389 | *value = fs64_to_cpu(sb, valarray[mid + 1]); | ||
390 | else | ||
391 | *value = fs64_to_cpu(sb, valarray[mid]); | ||
392 | befs_debug(sb, "<--- befs_find_key() found %s at %d", thiskey, mid); | ||
393 | return BEFS_BT_PARMATCH; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * befs_btree_read - Traverse leafnodes of a btree | ||
398 | * @sb: Filesystem superblock | ||
399 | * @ds: Datastream containing btree | ||
400 | * @key_no: Key number (alphabetical order) of key to read | ||
401 | * @bufsize: Size of the buffer to return key in | ||
402 | * @keybuf: Pointer to a buffer to put the key in | ||
403 | * @keysize: Length of the returned key | ||
404 | * @value: Value stored with the returned key | ||
405 | * | ||
406 | * Heres how it works: Key_no is the index of the key/value pair to | ||
407 | * return in keybuf/value. | ||
408 | * Bufsize is the size of keybuf (BEFS_NAME_LEN+1 is a good size). Keysize is | ||
409 | * the number of charecters in the key (just a convenience). | ||
410 | * | ||
411 | * Algorithm: | ||
412 | * Get the first leafnode of the tree. See if the requested key is in that | ||
413 | * node. If not, follow the node->right link to the next leafnode. Repeat | ||
414 | * until the (key_no)th key is found or the tree is out of keys. | ||
415 | */ | ||
416 | int | ||
417 | befs_btree_read(struct super_block *sb, befs_data_stream * ds, | ||
418 | loff_t key_no, size_t bufsize, char *keybuf, size_t * keysize, | ||
419 | befs_off_t * value) | ||
420 | { | ||
421 | befs_btree_node *this_node; | ||
422 | befs_btree_super bt_super; | ||
423 | befs_off_t node_off = 0; | ||
424 | int cur_key; | ||
425 | befs_off_t *valarray; | ||
426 | char *keystart; | ||
427 | u16 keylen; | ||
428 | int res; | ||
429 | |||
430 | uint key_sum = 0; | ||
431 | |||
432 | befs_debug(sb, "---> befs_btree_read()"); | ||
433 | |||
434 | if (befs_bt_read_super(sb, ds, &bt_super) != BEFS_OK) { | ||
435 | befs_error(sb, | ||
436 | "befs_btree_read() failed to read index superblock"); | ||
437 | goto error; | ||
438 | } | ||
439 | |||
440 | if ((this_node = (befs_btree_node *) | ||
441 | kmalloc(sizeof (befs_btree_node), GFP_NOFS)) == NULL) { | ||
442 | befs_error(sb, "befs_btree_read() failed to allocate %u " | ||
443 | "bytes of memory", sizeof (befs_btree_node)); | ||
444 | goto error; | ||
445 | } | ||
446 | |||
447 | node_off = bt_super.root_node_ptr; | ||
448 | this_node->bh = NULL; | ||
449 | |||
450 | /* seeks down to first leafnode, reads it into this_node */ | ||
451 | res = befs_btree_seekleaf(sb, ds, &bt_super, this_node, &node_off); | ||
452 | if (res == BEFS_BT_EMPTY) { | ||
453 | brelse(this_node->bh); | ||
454 | kfree(this_node); | ||
455 | *value = 0; | ||
456 | *keysize = 0; | ||
457 | befs_debug(sb, "<--- befs_btree_read() Tree is EMPTY"); | ||
458 | return BEFS_BT_EMPTY; | ||
459 | } else if (res == BEFS_ERR) { | ||
460 | goto error_alloc; | ||
461 | } | ||
462 | |||
463 | /* find the leaf node containing the key_no key */ | ||
464 | |||
465 | while (key_sum + this_node->head.all_key_count <= key_no) { | ||
466 | |||
467 | /* no more nodes to look in: key_no is too large */ | ||
468 | if (this_node->head.right == befs_bt_inval) { | ||
469 | *keysize = 0; | ||
470 | *value = 0; | ||
471 | befs_debug(sb, | ||
472 | "<--- befs_btree_read() END of keys at %Lu", | ||
473 | key_sum + this_node->head.all_key_count); | ||
474 | brelse(this_node->bh); | ||
475 | kfree(this_node); | ||
476 | return BEFS_BT_END; | ||
477 | } | ||
478 | |||
479 | key_sum += this_node->head.all_key_count; | ||
480 | node_off = this_node->head.right; | ||
481 | |||
482 | if (befs_bt_read_node(sb, ds, this_node, node_off) != BEFS_OK) { | ||
483 | befs_error(sb, "befs_btree_read() failed to read " | ||
484 | "node at %Lu", node_off); | ||
485 | goto error_alloc; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | /* how many keys into this_node is key_no */ | ||
490 | cur_key = key_no - key_sum; | ||
491 | |||
492 | /* get pointers to datastructures within the node body */ | ||
493 | valarray = befs_bt_valarray(this_node); | ||
494 | |||
495 | keystart = befs_bt_get_key(sb, this_node, cur_key, &keylen); | ||
496 | |||
497 | befs_debug(sb, "Read [%Lu,%d]: keysize %d", node_off, cur_key, keylen); | ||
498 | |||
499 | if (bufsize < keylen + 1) { | ||
500 | befs_error(sb, "befs_btree_read() keybuf too small (%u) " | ||
501 | "for key of size %d", bufsize, keylen); | ||
502 | brelse(this_node->bh); | ||
503 | goto error_alloc; | ||
504 | }; | ||
505 | |||
506 | strncpy(keybuf, keystart, keylen); | ||
507 | *value = fs64_to_cpu(sb, valarray[cur_key]); | ||
508 | *keysize = keylen; | ||
509 | keybuf[keylen] = '\0'; | ||
510 | |||
511 | befs_debug(sb, "Read [%Lu,%d]: Key \"%.*s\", Value %Lu", node_off, | ||
512 | cur_key, keylen, keybuf, *value); | ||
513 | |||
514 | brelse(this_node->bh); | ||
515 | kfree(this_node); | ||
516 | |||
517 | befs_debug(sb, "<--- befs_btree_read()"); | ||
518 | |||
519 | return BEFS_OK; | ||
520 | |||
521 | error_alloc: | ||
522 | kfree(this_node); | ||
523 | |||
524 | error: | ||
525 | *keysize = 0; | ||
526 | *value = 0; | ||
527 | befs_debug(sb, "<--- befs_btree_read() ERROR"); | ||
528 | return BEFS_ERR; | ||
529 | } | ||
530 | |||
531 | /** | ||
532 | * befs_btree_seekleaf - Find the first leafnode in the btree | ||
533 | * @sb: Filesystem superblock | ||
534 | * @ds: Datastream containing btree | ||
535 | * @bt_super: Pointer to the superblock of the btree | ||
536 | * @this_node: Buffer to return the leafnode in | ||
537 | * @node_off: Pointer to offset of current node within datastream. Modified | ||
538 | * by the function. | ||
539 | * | ||
540 | * | ||
541 | * Helper function for btree traverse. Moves the current position to the | ||
542 | * start of the first leaf node. | ||
543 | * | ||
544 | * Also checks for an empty tree. If there are no keys, returns BEFS_BT_EMPTY. | ||
545 | */ | ||
546 | static int | ||
547 | befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds, | ||
548 | befs_btree_super * bt_super, befs_btree_node * this_node, | ||
549 | befs_off_t * node_off) | ||
550 | { | ||
551 | |||
552 | befs_debug(sb, "---> befs_btree_seekleaf()"); | ||
553 | |||
554 | if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { | ||
555 | befs_error(sb, "befs_btree_seekleaf() failed to read " | ||
556 | "node at %Lu", *node_off); | ||
557 | goto error; | ||
558 | } | ||
559 | befs_debug(sb, "Seekleaf to root node %Lu", *node_off); | ||
560 | |||
561 | if (this_node->head.all_key_count == 0 && befs_leafnode(this_node)) { | ||
562 | befs_debug(sb, "<--- befs_btree_seekleaf() Tree is EMPTY"); | ||
563 | return BEFS_BT_EMPTY; | ||
564 | } | ||
565 | |||
566 | while (!befs_leafnode(this_node)) { | ||
567 | |||
568 | if (this_node->head.all_key_count == 0) { | ||
569 | befs_debug(sb, "befs_btree_seekleaf() encountered " | ||
570 | "an empty interior node: %Lu. Using Overflow " | ||
571 | "node: %Lu", *node_off, | ||
572 | this_node->head.overflow); | ||
573 | *node_off = this_node->head.overflow; | ||
574 | } else { | ||
575 | befs_off_t *valarray = befs_bt_valarray(this_node); | ||
576 | *node_off = fs64_to_cpu(sb, valarray[0]); | ||
577 | } | ||
578 | if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) { | ||
579 | befs_error(sb, "befs_btree_seekleaf() failed to read " | ||
580 | "node at %Lu", *node_off); | ||
581 | goto error; | ||
582 | } | ||
583 | |||
584 | befs_debug(sb, "Seekleaf to child node %Lu", *node_off); | ||
585 | } | ||
586 | befs_debug(sb, "Node %Lu is a leaf node", *node_off); | ||
587 | |||
588 | return BEFS_OK; | ||
589 | |||
590 | error: | ||
591 | befs_debug(sb, "<--- befs_btree_seekleaf() ERROR"); | ||
592 | return BEFS_ERR; | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * befs_leafnode - Determine if the btree node is a leaf node or an | ||
597 | * interior node | ||
598 | * @node: Pointer to node structure to test | ||
599 | * | ||
600 | * Return 1 if leaf, 0 if interior | ||
601 | */ | ||
602 | static int | ||
603 | befs_leafnode(befs_btree_node * node) | ||
604 | { | ||
605 | /* all interior nodes (and only interior nodes) have an overflow node */ | ||
606 | if (node->head.overflow == befs_bt_inval) | ||
607 | return 1; | ||
608 | else | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | /** | ||
613 | * befs_bt_keylen_index - Finds start of keylen index in a node | ||
614 | * @node: Pointer to the node structure to find the keylen index within | ||
615 | * | ||
616 | * Returns a pointer to the start of the key length index array | ||
617 | * of the B+tree node *@node | ||
618 | * | ||
619 | * "The length of all the keys in the node is added to the size of the | ||
620 | * header and then rounded up to a multiple of four to get the beginning | ||
621 | * of the key length index" (p.88, practical filesystem design). | ||
622 | * | ||
623 | * Except that rounding up to 8 works, and rounding up to 4 doesn't. | ||
624 | */ | ||
625 | static u16 * | ||
626 | befs_bt_keylen_index(befs_btree_node * node) | ||
627 | { | ||
628 | const int keylen_align = 8; | ||
629 | unsigned long int off = | ||
630 | (sizeof (befs_btree_nodehead) + node->head.all_key_length); | ||
631 | ulong tmp = off % keylen_align; | ||
632 | |||
633 | if (tmp) | ||
634 | off += keylen_align - tmp; | ||
635 | |||
636 | return (u16 *) ((void *) node->od_node + off); | ||
637 | } | ||
638 | |||
639 | /** | ||
640 | * befs_bt_valarray - Finds the start of value array in a node | ||
641 | * @node: Pointer to the node structure to find the value array within | ||
642 | * | ||
643 | * Returns a pointer to the start of the value array | ||
644 | * of the node pointed to by the node header | ||
645 | */ | ||
646 | static befs_off_t * | ||
647 | befs_bt_valarray(befs_btree_node * node) | ||
648 | { | ||
649 | void *keylen_index_start = (void *) befs_bt_keylen_index(node); | ||
650 | size_t keylen_index_size = node->head.all_key_count * sizeof (u16); | ||
651 | |||
652 | return (befs_off_t *) (keylen_index_start + keylen_index_size); | ||
653 | } | ||
654 | |||
655 | /** | ||
656 | * befs_bt_keydata - Finds start of keydata array in a node | ||
657 | * @node: Pointer to the node structure to find the keydata array within | ||
658 | * | ||
659 | * Returns a pointer to the start of the keydata array | ||
660 | * of the node pointed to by the node header | ||
661 | */ | ||
662 | static char * | ||
663 | befs_bt_keydata(befs_btree_node * node) | ||
664 | { | ||
665 | return (char *) ((void *) node->od_node + sizeof (befs_btree_nodehead)); | ||
666 | } | ||
667 | |||
668 | /** | ||
669 | * befs_bt_get_key - returns a pointer to the start of a key | ||
670 | * @sb: filesystem superblock | ||
671 | * @node: node in which to look for the key | ||
672 | * @index: the index of the key to get | ||
673 | * @keylen: modified to be the length of the key at @index | ||
674 | * | ||
675 | * Returns a valid pointer into @node on success. | ||
676 | * Returns NULL on failure (bad input) and sets *@keylen = 0 | ||
677 | */ | ||
678 | static char * | ||
679 | befs_bt_get_key(struct super_block *sb, befs_btree_node * node, | ||
680 | int index, u16 * keylen) | ||
681 | { | ||
682 | int prev_key_end; | ||
683 | char *keystart; | ||
684 | u16 *keylen_index; | ||
685 | |||
686 | if (index < 0 || index > node->head.all_key_count) { | ||
687 | *keylen = 0; | ||
688 | return NULL; | ||
689 | } | ||
690 | |||
691 | keystart = befs_bt_keydata(node); | ||
692 | keylen_index = befs_bt_keylen_index(node); | ||
693 | |||
694 | if (index == 0) | ||
695 | prev_key_end = 0; | ||
696 | else | ||
697 | prev_key_end = fs16_to_cpu(sb, keylen_index[index - 1]); | ||
698 | |||
699 | *keylen = fs16_to_cpu(sb, keylen_index[index]) - prev_key_end; | ||
700 | |||
701 | return keystart + prev_key_end; | ||
702 | } | ||
703 | |||
704 | /** | ||
705 | * befs_compare_strings - compare two strings | ||
706 | * @key1: pointer to the first key to be compared | ||
707 | * @keylen1: length in bytes of key1 | ||
708 | * @key2: pointer to the second key to be compared | ||
709 | * @kelen2: length in bytes of key2 | ||
710 | * | ||
711 | * Returns 0 if @key1 and @key2 are equal. | ||
712 | * Returns >0 if @key1 is greater. | ||
713 | * Returns <0 if @key2 is greater.. | ||
714 | */ | ||
715 | static int | ||
716 | befs_compare_strings(const void *key1, int keylen1, | ||
717 | const void *key2, int keylen2) | ||
718 | { | ||
719 | int len = min_t(int, keylen1, keylen2); | ||
720 | int result = strncmp(key1, key2, len); | ||
721 | if (result == 0) | ||
722 | result = keylen1 - keylen2; | ||
723 | return result; | ||
724 | } | ||
725 | |||
726 | /* These will be used for non-string keyed btrees */ | ||
727 | #if 0 | ||
728 | static int | ||
729 | btree_compare_int32(cont void *key1, int keylen1, const void *key2, int keylen2) | ||
730 | { | ||
731 | return *(int32_t *) key1 - *(int32_t *) key2; | ||
732 | } | ||
733 | |||
734 | static int | ||
735 | btree_compare_uint32(cont void *key1, int keylen1, | ||
736 | const void *key2, int keylen2) | ||
737 | { | ||
738 | if (*(u_int32_t *) key1 == *(u_int32_t *) key2) | ||
739 | return 0; | ||
740 | else if (*(u_int32_t *) key1 > *(u_int32_t *) key2) | ||
741 | return 1; | ||
742 | |||
743 | return -1; | ||
744 | } | ||
745 | static int | ||
746 | btree_compare_int64(cont void *key1, int keylen1, const void *key2, int keylen2) | ||
747 | { | ||
748 | if (*(int64_t *) key1 == *(int64_t *) key2) | ||
749 | return 0; | ||
750 | else if (*(int64_t *) key1 > *(int64_t *) key2) | ||
751 | return 1; | ||
752 | |||
753 | return -1; | ||
754 | } | ||
755 | |||
756 | static int | ||
757 | btree_compare_uint64(cont void *key1, int keylen1, | ||
758 | const void *key2, int keylen2) | ||
759 | { | ||
760 | if (*(u_int64_t *) key1 == *(u_int64_t *) key2) | ||
761 | return 0; | ||
762 | else if (*(u_int64_t *) key1 > *(u_int64_t *) key2) | ||
763 | return 1; | ||
764 | |||
765 | return -1; | ||
766 | } | ||
767 | |||
768 | static int | ||
769 | btree_compare_float(cont void *key1, int keylen1, const void *key2, int keylen2) | ||
770 | { | ||
771 | float result = *(float *) key1 - *(float *) key2; | ||
772 | if (result == 0.0f) | ||
773 | return 0; | ||
774 | |||
775 | return (result < 0.0f) ? -1 : 1; | ||
776 | } | ||
777 | |||
778 | static int | ||
779 | btree_compare_double(cont void *key1, int keylen1, | ||
780 | const void *key2, int keylen2) | ||
781 | { | ||
782 | double result = *(double *) key1 - *(double *) key2; | ||
783 | if (result == 0.0) | ||
784 | return 0; | ||
785 | |||
786 | return (result < 0.0) ? -1 : 1; | ||
787 | } | ||
788 | #endif //0 | ||
diff --git a/fs/befs/btree.h b/fs/befs/btree.h new file mode 100644 index 000000000000..92e781e5f30e --- /dev/null +++ b/fs/befs/btree.h | |||
@@ -0,0 +1,13 @@ | |||
1 | /* | ||
2 | * btree.h | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | |||
7 | int befs_btree_find(struct super_block *sb, befs_data_stream * ds, | ||
8 | const char *key, befs_off_t * value); | ||
9 | |||
10 | int befs_btree_read(struct super_block *sb, befs_data_stream * ds, | ||
11 | loff_t key_no, size_t bufsize, char *keybuf, | ||
12 | size_t * keysize, befs_off_t * value); | ||
13 | |||
diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c new file mode 100644 index 000000000000..785f6b2d5d10 --- /dev/null +++ b/fs/befs/datastream.c | |||
@@ -0,0 +1,528 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/datastream.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com> | ||
5 | * | ||
6 | * Based on portions of file.c by Makoto Kato <m_kato@ga2.so-net.ne.jp> | ||
7 | * | ||
8 | * Many thanks to Dominic Giampaolo, author of "Practical File System | ||
9 | * Design with the Be File System", for such a helpful book. | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/buffer_head.h> | ||
16 | #include <linux/string.h> | ||
17 | |||
18 | #include "befs.h" | ||
19 | #include "datastream.h" | ||
20 | #include "io.h" | ||
21 | #include "endian.h" | ||
22 | |||
23 | const befs_inode_addr BAD_IADDR = { 0, 0, 0 }; | ||
24 | |||
25 | static int befs_find_brun_direct(struct super_block *sb, | ||
26 | befs_data_stream * data, | ||
27 | befs_blocknr_t blockno, befs_block_run * run); | ||
28 | |||
29 | static int befs_find_brun_indirect(struct super_block *sb, | ||
30 | befs_data_stream * data, | ||
31 | befs_blocknr_t blockno, | ||
32 | befs_block_run * run); | ||
33 | |||
34 | static int befs_find_brun_dblindirect(struct super_block *sb, | ||
35 | befs_data_stream * data, | ||
36 | befs_blocknr_t blockno, | ||
37 | befs_block_run * run); | ||
38 | |||
39 | /** | ||
40 | * befs_read_datastream - get buffer_head containing data, starting from pos. | ||
41 | * @sb: Filesystem superblock | ||
42 | * @ds: datastrem to find data with | ||
43 | * @pos: start of data | ||
44 | * @off: offset of data in buffer_head->b_data | ||
45 | * | ||
46 | * Returns pointer to buffer_head containing data starting with offset @off, | ||
47 | * if you don't need to know offset just set @off = NULL. | ||
48 | */ | ||
49 | struct buffer_head * | ||
50 | befs_read_datastream(struct super_block *sb, befs_data_stream * ds, | ||
51 | befs_off_t pos, uint * off) | ||
52 | { | ||
53 | struct buffer_head *bh = NULL; | ||
54 | befs_block_run run; | ||
55 | befs_blocknr_t block; /* block coresponding to pos */ | ||
56 | |||
57 | befs_debug(sb, "---> befs_read_datastream() %Lu", pos); | ||
58 | block = pos >> BEFS_SB(sb)->block_shift; | ||
59 | if (off) | ||
60 | *off = pos - (block << BEFS_SB(sb)->block_shift); | ||
61 | |||
62 | if (befs_fblock2brun(sb, ds, block, &run) != BEFS_OK) { | ||
63 | befs_error(sb, "BeFS: Error finding disk addr of block %lu", | ||
64 | block); | ||
65 | befs_debug(sb, "<--- befs_read_datastream() ERROR"); | ||
66 | return NULL; | ||
67 | } | ||
68 | bh = befs_bread_iaddr(sb, run); | ||
69 | if (!bh) { | ||
70 | befs_error(sb, "BeFS: Error reading block %lu from datastream", | ||
71 | block); | ||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | befs_debug(sb, "<--- befs_read_datastream() read data, starting at %Lu", | ||
76 | pos); | ||
77 | |||
78 | return bh; | ||
79 | } | ||
80 | |||
81 | /* | ||
82 | * Takes a file position and gives back a brun who's starting block | ||
83 | * is block number fblock of the file. | ||
84 | * | ||
85 | * Returns BEFS_OK or BEFS_ERR. | ||
86 | * | ||
87 | * Calls specialized functions for each of the three possible | ||
88 | * datastream regions. | ||
89 | * | ||
90 | * 2001-11-15 Will Dyson | ||
91 | */ | ||
92 | int | ||
93 | befs_fblock2brun(struct super_block *sb, befs_data_stream * data, | ||
94 | befs_blocknr_t fblock, befs_block_run * run) | ||
95 | { | ||
96 | int err; | ||
97 | befs_off_t pos = fblock << BEFS_SB(sb)->block_shift; | ||
98 | |||
99 | if (pos < data->max_direct_range) { | ||
100 | err = befs_find_brun_direct(sb, data, fblock, run); | ||
101 | |||
102 | } else if (pos < data->max_indirect_range) { | ||
103 | err = befs_find_brun_indirect(sb, data, fblock, run); | ||
104 | |||
105 | } else if (pos < data->max_double_indirect_range) { | ||
106 | err = befs_find_brun_dblindirect(sb, data, fblock, run); | ||
107 | |||
108 | } else { | ||
109 | befs_error(sb, | ||
110 | "befs_fblock2brun() was asked to find block %lu, " | ||
111 | "which is not mapped by the datastream\n", fblock); | ||
112 | err = BEFS_ERR; | ||
113 | } | ||
114 | return err; | ||
115 | } | ||
116 | |||
117 | /** | ||
118 | * befs_read_lsmylink - read long symlink from datastream. | ||
119 | * @sb: Filesystem superblock | ||
120 | * @ds: Datastrem to read from | ||
121 | * @buf: Buffer in wich to place long symlink data | ||
122 | * @len: Length of the long symlink in bytes | ||
123 | * | ||
124 | * Returns the number of bytes read | ||
125 | */ | ||
126 | size_t | ||
127 | befs_read_lsymlink(struct super_block * sb, befs_data_stream * ds, void *buff, | ||
128 | befs_off_t len) | ||
129 | { | ||
130 | befs_off_t bytes_read = 0; /* bytes readed */ | ||
131 | u16 plen; | ||
132 | struct buffer_head *bh = NULL; | ||
133 | befs_debug(sb, "---> befs_read_lsymlink() length: %Lu", len); | ||
134 | |||
135 | while (bytes_read < len) { | ||
136 | bh = befs_read_datastream(sb, ds, bytes_read, NULL); | ||
137 | if (!bh) { | ||
138 | befs_error(sb, "BeFS: Error reading datastream block " | ||
139 | "starting from %Lu", bytes_read); | ||
140 | befs_debug(sb, "<--- befs_read_lsymlink() ERROR"); | ||
141 | return bytes_read; | ||
142 | |||
143 | } | ||
144 | plen = ((bytes_read + BEFS_SB(sb)->block_size) < len) ? | ||
145 | BEFS_SB(sb)->block_size : len - bytes_read; | ||
146 | memcpy(buff + bytes_read, bh->b_data, plen); | ||
147 | brelse(bh); | ||
148 | bytes_read += plen; | ||
149 | } | ||
150 | |||
151 | befs_debug(sb, "<--- befs_read_lsymlink() read %u bytes", bytes_read); | ||
152 | return bytes_read; | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * befs_count_blocks - blocks used by a file | ||
157 | * @sb: Filesystem superblock | ||
158 | * @ds: Datastream of the file | ||
159 | * | ||
160 | * Counts the number of fs blocks that the file represented by | ||
161 | * inode occupies on the filesystem, counting both regular file | ||
162 | * data and filesystem metadata (and eventually attribute data | ||
163 | * when we support attributes) | ||
164 | */ | ||
165 | |||
166 | befs_blocknr_t | ||
167 | befs_count_blocks(struct super_block * sb, befs_data_stream * ds) | ||
168 | { | ||
169 | befs_blocknr_t blocks; | ||
170 | befs_blocknr_t datablocks; /* File data blocks */ | ||
171 | befs_blocknr_t metablocks; /* FS metadata blocks */ | ||
172 | befs_sb_info *befs_sb = BEFS_SB(sb); | ||
173 | |||
174 | befs_debug(sb, "---> befs_count_blocks()"); | ||
175 | |||
176 | datablocks = ds->size >> befs_sb->block_shift; | ||
177 | if (ds->size & (befs_sb->block_size - 1)) | ||
178 | datablocks += 1; | ||
179 | |||
180 | metablocks = 1; /* Start with 1 block for inode */ | ||
181 | |||
182 | /* Size of indirect block */ | ||
183 | if (ds->size > ds->max_direct_range) | ||
184 | metablocks += ds->indirect.len; | ||
185 | |||
186 | /* | ||
187 | Double indir block, plus all the indirect blocks it mapps | ||
188 | In the double-indirect range, all block runs of data are | ||
189 | BEFS_DBLINDIR_BRUN_LEN blocks long. Therefore, we know | ||
190 | how many data block runs are in the double-indirect region, | ||
191 | and from that we know how many indirect blocks it takes to | ||
192 | map them. We assume that the indirect blocks are also | ||
193 | BEFS_DBLINDIR_BRUN_LEN blocks long. | ||
194 | */ | ||
195 | if (ds->size > ds->max_indirect_range && ds->max_indirect_range != 0) { | ||
196 | uint dbl_bytes; | ||
197 | uint dbl_bruns; | ||
198 | uint indirblocks; | ||
199 | |||
200 | dbl_bytes = | ||
201 | ds->max_double_indirect_range - ds->max_indirect_range; | ||
202 | dbl_bruns = | ||
203 | dbl_bytes / (befs_sb->block_size * BEFS_DBLINDIR_BRUN_LEN); | ||
204 | indirblocks = dbl_bruns / befs_iaddrs_per_block(sb); | ||
205 | |||
206 | metablocks += ds->double_indirect.len; | ||
207 | metablocks += indirblocks; | ||
208 | } | ||
209 | |||
210 | blocks = datablocks + metablocks; | ||
211 | befs_debug(sb, "<--- befs_count_blocks() %u blocks", blocks); | ||
212 | |||
213 | return blocks; | ||
214 | } | ||
215 | |||
216 | /* | ||
217 | Finds the block run that starts at file block number blockno | ||
218 | in the file represented by the datastream data, if that | ||
219 | blockno is in the direct region of the datastream. | ||
220 | |||
221 | sb: the superblock | ||
222 | data: the datastream | ||
223 | blockno: the blocknumber to find | ||
224 | run: The found run is passed back through this pointer | ||
225 | |||
226 | Return value is BEFS_OK if the blockrun is found, BEFS_ERR | ||
227 | otherwise. | ||
228 | |||
229 | Algorithm: | ||
230 | Linear search. Checks each element of array[] to see if it | ||
231 | contains the blockno-th filesystem block. This is necessary | ||
232 | because the block runs map variable amounts of data. Simply | ||
233 | keeps a count of the number of blocks searched so far (sum), | ||
234 | incrementing this by the length of each block run as we come | ||
235 | across it. Adds sum to *count before returning (this is so | ||
236 | you can search multiple arrays that are logicaly one array, | ||
237 | as in the indirect region code). | ||
238 | |||
239 | When/if blockno is found, if blockno is inside of a block | ||
240 | run as stored on disk, we offset the start and lenght members | ||
241 | of the block run, so that blockno is the start and len is | ||
242 | still valid (the run ends in the same place). | ||
243 | |||
244 | 2001-11-15 Will Dyson | ||
245 | */ | ||
246 | static int | ||
247 | befs_find_brun_direct(struct super_block *sb, befs_data_stream * data, | ||
248 | befs_blocknr_t blockno, befs_block_run * run) | ||
249 | { | ||
250 | int i; | ||
251 | befs_block_run *array = data->direct; | ||
252 | befs_blocknr_t sum; | ||
253 | befs_blocknr_t max_block = | ||
254 | data->max_direct_range >> BEFS_SB(sb)->block_shift; | ||
255 | |||
256 | befs_debug(sb, "---> befs_find_brun_direct(), find %lu", blockno); | ||
257 | |||
258 | if (blockno > max_block) { | ||
259 | befs_error(sb, "befs_find_brun_direct() passed block outside of" | ||
260 | "direct region"); | ||
261 | return BEFS_ERR; | ||
262 | } | ||
263 | |||
264 | for (i = 0, sum = 0; i < BEFS_NUM_DIRECT_BLOCKS; | ||
265 | sum += array[i].len, i++) { | ||
266 | if (blockno >= sum && blockno < sum + (array[i].len)) { | ||
267 | int offset = blockno - sum; | ||
268 | run->allocation_group = array[i].allocation_group; | ||
269 | run->start = array[i].start + offset; | ||
270 | run->len = array[i].len - offset; | ||
271 | |||
272 | befs_debug(sb, "---> befs_find_brun_direct(), " | ||
273 | "found %lu at direct[%d]", blockno, i); | ||
274 | return BEFS_OK; | ||
275 | } | ||
276 | } | ||
277 | |||
278 | befs_debug(sb, "---> befs_find_brun_direct() ERROR"); | ||
279 | return BEFS_ERR; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | Finds the block run that starts at file block number blockno | ||
284 | in the file represented by the datastream data, if that | ||
285 | blockno is in the indirect region of the datastream. | ||
286 | |||
287 | sb: the superblock | ||
288 | data: the datastream | ||
289 | blockno: the blocknumber to find | ||
290 | run: The found run is passed back through this pointer | ||
291 | |||
292 | Return value is BEFS_OK if the blockrun is found, BEFS_ERR | ||
293 | otherwise. | ||
294 | |||
295 | Algorithm: | ||
296 | For each block in the indirect run of the datastream, read | ||
297 | it in and search through it for search_blk. | ||
298 | |||
299 | XXX: | ||
300 | Really should check to make sure blockno is inside indirect | ||
301 | region. | ||
302 | |||
303 | 2001-11-15 Will Dyson | ||
304 | */ | ||
305 | static int | ||
306 | befs_find_brun_indirect(struct super_block *sb, | ||
307 | befs_data_stream * data, befs_blocknr_t blockno, | ||
308 | befs_block_run * run) | ||
309 | { | ||
310 | int i, j; | ||
311 | befs_blocknr_t sum = 0; | ||
312 | befs_blocknr_t indir_start_blk; | ||
313 | befs_blocknr_t search_blk; | ||
314 | struct buffer_head *indirblock; | ||
315 | befs_block_run *array; | ||
316 | |||
317 | befs_block_run indirect = data->indirect; | ||
318 | befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect); | ||
319 | int arraylen = befs_iaddrs_per_block(sb); | ||
320 | |||
321 | befs_debug(sb, "---> befs_find_brun_indirect(), find %lu", blockno); | ||
322 | |||
323 | indir_start_blk = data->max_direct_range >> BEFS_SB(sb)->block_shift; | ||
324 | search_blk = blockno - indir_start_blk; | ||
325 | |||
326 | /* Examine blocks of the indirect run one at a time */ | ||
327 | for (i = 0; i < indirect.len; i++) { | ||
328 | indirblock = befs_bread(sb, indirblockno + i); | ||
329 | if (indirblock == NULL) { | ||
330 | befs_debug(sb, | ||
331 | "---> befs_find_brun_indirect() failed to " | ||
332 | "read disk block %lu from the indirect brun", | ||
333 | indirblockno + i); | ||
334 | return BEFS_ERR; | ||
335 | } | ||
336 | |||
337 | array = (befs_block_run *) indirblock->b_data; | ||
338 | |||
339 | for (j = 0; j < arraylen; ++j) { | ||
340 | int len = fs16_to_cpu(sb, array[j].len); | ||
341 | |||
342 | if (search_blk >= sum && search_blk < sum + len) { | ||
343 | int offset = search_blk - sum; | ||
344 | run->allocation_group = | ||
345 | fs32_to_cpu(sb, array[j].allocation_group); | ||
346 | run->start = | ||
347 | fs16_to_cpu(sb, array[j].start) + offset; | ||
348 | run->len = | ||
349 | fs16_to_cpu(sb, array[j].len) - offset; | ||
350 | |||
351 | brelse(indirblock); | ||
352 | befs_debug(sb, | ||
353 | "<--- befs_find_brun_indirect() found " | ||
354 | "file block %lu at indirect[%d]", | ||
355 | blockno, j + (i * arraylen)); | ||
356 | return BEFS_OK; | ||
357 | } | ||
358 | sum += len; | ||
359 | } | ||
360 | |||
361 | brelse(indirblock); | ||
362 | } | ||
363 | |||
364 | /* Only fallthrough is an error */ | ||
365 | befs_error(sb, "BeFS: befs_find_brun_indirect() failed to find " | ||
366 | "file block %lu", blockno); | ||
367 | |||
368 | befs_debug(sb, "<--- befs_find_brun_indirect() ERROR"); | ||
369 | return BEFS_ERR; | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | Finds the block run that starts at file block number blockno | ||
374 | in the file represented by the datastream data, if that | ||
375 | blockno is in the double-indirect region of the datastream. | ||
376 | |||
377 | sb: the superblock | ||
378 | data: the datastream | ||
379 | blockno: the blocknumber to find | ||
380 | run: The found run is passed back through this pointer | ||
381 | |||
382 | Return value is BEFS_OK if the blockrun is found, BEFS_ERR | ||
383 | otherwise. | ||
384 | |||
385 | Algorithm: | ||
386 | The block runs in the double-indirect region are different. | ||
387 | They are always allocated 4 fs blocks at a time, so each | ||
388 | block run maps a constant amount of file data. This means | ||
389 | that we can directly calculate how many block runs into the | ||
390 | double-indirect region we need to go to get to the one that | ||
391 | maps a particular filesystem block. | ||
392 | |||
393 | We do this in two stages. First we calculate which of the | ||
394 | inode addresses in the double-indirect block will point us | ||
395 | to the indirect block that contains the mapping for the data, | ||
396 | then we calculate which of the inode addresses in that | ||
397 | indirect block maps the data block we are after. | ||
398 | |||
399 | Oh, and once we've done that, we actually read in the blocks | ||
400 | that contain the inode addresses we calculated above. Even | ||
401 | though the double-indirect run may be several blocks long, | ||
402 | we can calculate which of those blocks will contain the index | ||
403 | we are after and only read that one. We then follow it to | ||
404 | the indirect block and perform a similar process to find | ||
405 | the actual block run that maps the data block we are interested | ||
406 | in. | ||
407 | |||
408 | Then we offset the run as in befs_find_brun_array() and we are | ||
409 | done. | ||
410 | |||
411 | 2001-11-15 Will Dyson | ||
412 | */ | ||
413 | static int | ||
414 | befs_find_brun_dblindirect(struct super_block *sb, | ||
415 | befs_data_stream * data, befs_blocknr_t blockno, | ||
416 | befs_block_run * run) | ||
417 | { | ||
418 | int dblindir_indx; | ||
419 | int indir_indx; | ||
420 | int offset; | ||
421 | int dbl_which_block; | ||
422 | int which_block; | ||
423 | int dbl_block_indx; | ||
424 | int block_indx; | ||
425 | off_t dblindir_leftover; | ||
426 | befs_blocknr_t blockno_at_run_start; | ||
427 | struct buffer_head *dbl_indir_block; | ||
428 | struct buffer_head *indir_block; | ||
429 | befs_block_run indir_run; | ||
430 | befs_inode_addr *iaddr_array = NULL; | ||
431 | befs_sb_info *befs_sb = BEFS_SB(sb); | ||
432 | |||
433 | befs_blocknr_t indir_start_blk = | ||
434 | data->max_indirect_range >> befs_sb->block_shift; | ||
435 | |||
436 | off_t dbl_indir_off = blockno - indir_start_blk; | ||
437 | |||
438 | /* number of data blocks mapped by each of the iaddrs in | ||
439 | * the indirect block pointed to by the double indirect block | ||
440 | */ | ||
441 | size_t iblklen = BEFS_DBLINDIR_BRUN_LEN; | ||
442 | |||
443 | /* number of data blocks mapped by each of the iaddrs in | ||
444 | * the double indirect block | ||
445 | */ | ||
446 | size_t diblklen = iblklen * befs_iaddrs_per_block(sb) | ||
447 | * BEFS_DBLINDIR_BRUN_LEN; | ||
448 | |||
449 | befs_debug(sb, "---> befs_find_brun_dblindirect() find %lu", blockno); | ||
450 | |||
451 | /* First, discover which of the double_indir->indir blocks | ||
452 | * contains pos. Then figure out how much of pos that | ||
453 | * accounted for. Then discover which of the iaddrs in | ||
454 | * the indirect block contains pos. | ||
455 | */ | ||
456 | |||
457 | dblindir_indx = dbl_indir_off / diblklen; | ||
458 | dblindir_leftover = dbl_indir_off % diblklen; | ||
459 | indir_indx = dblindir_leftover / diblklen; | ||
460 | |||
461 | /* Read double indirect block */ | ||
462 | dbl_which_block = dblindir_indx / befs_iaddrs_per_block(sb); | ||
463 | if (dbl_which_block > data->double_indirect.len) { | ||
464 | befs_error(sb, "The double-indirect index calculated by " | ||
465 | "befs_read_brun_dblindirect(), %d, is outside the range " | ||
466 | "of the double-indirect block", dblindir_indx); | ||
467 | return BEFS_ERR; | ||
468 | } | ||
469 | |||
470 | dbl_indir_block = | ||
471 | befs_bread(sb, iaddr2blockno(sb, &data->double_indirect) + | ||
472 | dbl_which_block); | ||
473 | if (dbl_indir_block == NULL) { | ||
474 | befs_error(sb, "befs_read_brun_dblindirect() couldn't read the " | ||
475 | "double-indirect block at blockno %lu", | ||
476 | iaddr2blockno(sb, | ||
477 | &data->double_indirect) + | ||
478 | dbl_which_block); | ||
479 | brelse(dbl_indir_block); | ||
480 | return BEFS_ERR; | ||
481 | } | ||
482 | |||
483 | dbl_block_indx = | ||
484 | dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb)); | ||
485 | iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data; | ||
486 | indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]); | ||
487 | brelse(dbl_indir_block); | ||
488 | iaddr_array = NULL; | ||
489 | |||
490 | /* Read indirect block */ | ||
491 | which_block = indir_indx / befs_iaddrs_per_block(sb); | ||
492 | if (which_block > indir_run.len) { | ||
493 | befs_error(sb, "The indirect index calculated by " | ||
494 | "befs_read_brun_dblindirect(), %d, is outside the range " | ||
495 | "of the indirect block", indir_indx); | ||
496 | return BEFS_ERR; | ||
497 | } | ||
498 | |||
499 | indir_block = | ||
500 | befs_bread(sb, iaddr2blockno(sb, &indir_run) + which_block); | ||
501 | if (indir_block == NULL) { | ||
502 | befs_error(sb, "befs_read_brun_dblindirect() couldn't read the " | ||
503 | "indirect block at blockno %lu", | ||
504 | iaddr2blockno(sb, &indir_run) + which_block); | ||
505 | brelse(indir_block); | ||
506 | return BEFS_ERR; | ||
507 | } | ||
508 | |||
509 | block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb)); | ||
510 | iaddr_array = (befs_inode_addr *) indir_block->b_data; | ||
511 | *run = fsrun_to_cpu(sb, iaddr_array[block_indx]); | ||
512 | brelse(indir_block); | ||
513 | iaddr_array = NULL; | ||
514 | |||
515 | blockno_at_run_start = indir_start_blk; | ||
516 | blockno_at_run_start += diblklen * dblindir_indx; | ||
517 | blockno_at_run_start += iblklen * indir_indx; | ||
518 | offset = blockno - blockno_at_run_start; | ||
519 | |||
520 | run->start += offset; | ||
521 | run->len -= offset; | ||
522 | |||
523 | befs_debug(sb, "Found file block %lu in double_indirect[%d][%d]," | ||
524 | " double_indirect_leftover = %lu", | ||
525 | blockno, dblindir_indx, indir_indx, dblindir_leftover); | ||
526 | |||
527 | return BEFS_OK; | ||
528 | } | ||
diff --git a/fs/befs/datastream.h b/fs/befs/datastream.h new file mode 100644 index 000000000000..45e8a3c98249 --- /dev/null +++ b/fs/befs/datastream.h | |||
@@ -0,0 +1,19 @@ | |||
1 | /* | ||
2 | * datastream.h | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | struct buffer_head *befs_read_datastream(struct super_block *sb, | ||
7 | befs_data_stream * ds, befs_off_t pos, | ||
8 | uint * off); | ||
9 | |||
10 | int befs_fblock2brun(struct super_block *sb, befs_data_stream * data, | ||
11 | befs_blocknr_t fblock, befs_block_run * run); | ||
12 | |||
13 | size_t befs_read_lsymlink(struct super_block *sb, befs_data_stream * data, | ||
14 | void *buff, befs_off_t len); | ||
15 | |||
16 | befs_blocknr_t befs_count_blocks(struct super_block *sb, befs_data_stream * ds); | ||
17 | |||
18 | extern const befs_inode_addr BAD_IADDR; | ||
19 | |||
diff --git a/fs/befs/debug.c b/fs/befs/debug.c new file mode 100644 index 000000000000..875cc0aa318c --- /dev/null +++ b/fs/befs/debug.c | |||
@@ -0,0 +1,283 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/debug.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson (will_dyson at pobox.com) | ||
5 | * | ||
6 | * With help from the ntfs-tng driver by Anton Altparmakov | ||
7 | * | ||
8 | * Copyright (C) 1999 Makoto Kato (m_kato@ga2.so-net.ne.jp) | ||
9 | * | ||
10 | * debug functions | ||
11 | */ | ||
12 | |||
13 | #ifdef __KERNEL__ | ||
14 | |||
15 | #include <stdarg.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/spinlock.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/fs.h> | ||
20 | |||
21 | #endif /* __KERNEL__ */ | ||
22 | |||
23 | #include "befs.h" | ||
24 | #include "endian.h" | ||
25 | |||
26 | #define ERRBUFSIZE 1024 | ||
27 | |||
28 | void | ||
29 | befs_error(const struct super_block *sb, const char *fmt, ...) | ||
30 | { | ||
31 | va_list args; | ||
32 | char *err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL); | ||
33 | if (err_buf == NULL) { | ||
34 | printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE); | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | va_start(args, fmt); | ||
39 | vsnprintf(err_buf, ERRBUFSIZE, fmt, args); | ||
40 | va_end(args); | ||
41 | |||
42 | printk(KERN_ERR "BeFS(%s): %s\n", sb->s_id, err_buf); | ||
43 | kfree(err_buf); | ||
44 | } | ||
45 | |||
46 | void | ||
47 | befs_warning(const struct super_block *sb, const char *fmt, ...) | ||
48 | { | ||
49 | va_list args; | ||
50 | char *err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL); | ||
51 | if (err_buf == NULL) { | ||
52 | printk(KERN_ERR "could not allocate %d bytes\n", ERRBUFSIZE); | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | va_start(args, fmt); | ||
57 | vsnprintf(err_buf, ERRBUFSIZE, fmt, args); | ||
58 | va_end(args); | ||
59 | |||
60 | printk(KERN_WARNING "BeFS(%s): %s\n", sb->s_id, err_buf); | ||
61 | |||
62 | kfree(err_buf); | ||
63 | } | ||
64 | |||
65 | void | ||
66 | befs_debug(const struct super_block *sb, const char *fmt, ...) | ||
67 | { | ||
68 | #ifdef CONFIG_BEFS_DEBUG | ||
69 | |||
70 | va_list args; | ||
71 | char *err_buf = NULL; | ||
72 | |||
73 | if (BEFS_SB(sb)->mount_opts.debug) { | ||
74 | err_buf = (char *) kmalloc(ERRBUFSIZE, GFP_KERNEL); | ||
75 | if (err_buf == NULL) { | ||
76 | printk(KERN_ERR "could not allocate %d bytes\n", | ||
77 | ERRBUFSIZE); | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | va_start(args, fmt); | ||
82 | vsnprintf(err_buf, ERRBUFSIZE, fmt, args); | ||
83 | va_end(args); | ||
84 | |||
85 | printk(KERN_DEBUG "BeFS(%s): %s\n", sb->s_id, err_buf); | ||
86 | |||
87 | kfree(err_buf); | ||
88 | } | ||
89 | |||
90 | #endif //CONFIG_BEFS_DEBUG | ||
91 | } | ||
92 | |||
93 | void | ||
94 | befs_dump_inode(const struct super_block *sb, befs_inode * inode) | ||
95 | { | ||
96 | #ifdef CONFIG_BEFS_DEBUG | ||
97 | |||
98 | befs_block_run tmp_run; | ||
99 | |||
100 | befs_debug(sb, "befs_inode information"); | ||
101 | |||
102 | befs_debug(sb, " magic1 %08x", fs32_to_cpu(sb, inode->magic1)); | ||
103 | |||
104 | tmp_run = fsrun_to_cpu(sb, inode->inode_num); | ||
105 | befs_debug(sb, " inode_num %u, %hu, %hu", | ||
106 | tmp_run.allocation_group, tmp_run.start, tmp_run.len); | ||
107 | |||
108 | befs_debug(sb, " uid %u", fs32_to_cpu(sb, inode->uid)); | ||
109 | befs_debug(sb, " gid %u", fs32_to_cpu(sb, inode->gid)); | ||
110 | befs_debug(sb, " mode %08x", fs32_to_cpu(sb, inode->mode)); | ||
111 | befs_debug(sb, " flags %08x", fs32_to_cpu(sb, inode->flags)); | ||
112 | befs_debug(sb, " create_time %Lu", | ||
113 | fs64_to_cpu(sb, inode->create_time)); | ||
114 | befs_debug(sb, " last_modified_time %Lu", | ||
115 | fs64_to_cpu(sb, inode->last_modified_time)); | ||
116 | |||
117 | tmp_run = fsrun_to_cpu(sb, inode->parent); | ||
118 | befs_debug(sb, " parent [%u, %hu, %hu]", | ||
119 | tmp_run.allocation_group, tmp_run.start, tmp_run.len); | ||
120 | |||
121 | tmp_run = fsrun_to_cpu(sb, inode->attributes); | ||
122 | befs_debug(sb, " attributes [%u, %hu, %hu]", | ||
123 | tmp_run.allocation_group, tmp_run.start, tmp_run.len); | ||
124 | |||
125 | befs_debug(sb, " type %08x", fs32_to_cpu(sb, inode->type)); | ||
126 | befs_debug(sb, " inode_size %u", fs32_to_cpu(sb, inode->inode_size)); | ||
127 | |||
128 | if (S_ISLNK(inode->mode)) { | ||
129 | befs_debug(sb, " Symbolic link [%s]", inode->data.symlink); | ||
130 | } else { | ||
131 | int i; | ||
132 | |||
133 | for (i = 0; i < BEFS_NUM_DIRECT_BLOCKS; i++) { | ||
134 | tmp_run = | ||
135 | fsrun_to_cpu(sb, inode->data.datastream.direct[i]); | ||
136 | befs_debug(sb, " direct %d [%u, %hu, %hu]", i, | ||
137 | tmp_run.allocation_group, tmp_run.start, | ||
138 | tmp_run.len); | ||
139 | } | ||
140 | befs_debug(sb, " max_direct_range %Lu", | ||
141 | fs64_to_cpu(sb, | ||
142 | inode->data.datastream. | ||
143 | max_direct_range)); | ||
144 | |||
145 | tmp_run = fsrun_to_cpu(sb, inode->data.datastream.indirect); | ||
146 | befs_debug(sb, " indirect [%u, %hu, %hu]", | ||
147 | tmp_run.allocation_group, | ||
148 | tmp_run.start, tmp_run.len); | ||
149 | |||
150 | befs_debug(sb, " max_indirect_range %Lu", | ||
151 | fs64_to_cpu(sb, | ||
152 | inode->data.datastream. | ||
153 | max_indirect_range)); | ||
154 | |||
155 | tmp_run = | ||
156 | fsrun_to_cpu(sb, inode->data.datastream.double_indirect); | ||
157 | befs_debug(sb, " double indirect [%u, %hu, %hu]", | ||
158 | tmp_run.allocation_group, tmp_run.start, | ||
159 | tmp_run.len); | ||
160 | |||
161 | befs_debug(sb, " max_double_indirect_range %Lu", | ||
162 | fs64_to_cpu(sb, | ||
163 | inode->data.datastream. | ||
164 | max_double_indirect_range)); | ||
165 | |||
166 | befs_debug(sb, " size %Lu", | ||
167 | fs64_to_cpu(sb, inode->data.datastream.size)); | ||
168 | } | ||
169 | |||
170 | #endif //CONFIG_BEFS_DEBUG | ||
171 | } | ||
172 | |||
173 | /* | ||
174 | * Display super block structure for debug. | ||
175 | */ | ||
176 | |||
177 | void | ||
178 | befs_dump_super_block(const struct super_block *sb, befs_super_block * sup) | ||
179 | { | ||
180 | #ifdef CONFIG_BEFS_DEBUG | ||
181 | |||
182 | befs_block_run tmp_run; | ||
183 | |||
184 | befs_debug(sb, "befs_super_block information"); | ||
185 | |||
186 | befs_debug(sb, " name %s", sup->name); | ||
187 | befs_debug(sb, " magic1 %08x", fs32_to_cpu(sb, sup->magic1)); | ||
188 | befs_debug(sb, " fs_byte_order %08x", | ||
189 | fs32_to_cpu(sb, sup->fs_byte_order)); | ||
190 | |||
191 | befs_debug(sb, " block_size %u", fs32_to_cpu(sb, sup->block_size)); | ||
192 | befs_debug(sb, " block_shift %u", fs32_to_cpu(sb, sup->block_shift)); | ||
193 | |||
194 | befs_debug(sb, " num_blocks %Lu", fs64_to_cpu(sb, sup->num_blocks)); | ||
195 | befs_debug(sb, " used_blocks %Lu", fs64_to_cpu(sb, sup->used_blocks)); | ||
196 | |||
197 | befs_debug(sb, " magic2 %08x", fs32_to_cpu(sb, sup->magic2)); | ||
198 | befs_debug(sb, " blocks_per_ag %u", | ||
199 | fs32_to_cpu(sb, sup->blocks_per_ag)); | ||
200 | befs_debug(sb, " ag_shift %u", fs32_to_cpu(sb, sup->ag_shift)); | ||
201 | befs_debug(sb, " num_ags %u", fs32_to_cpu(sb, sup->num_ags)); | ||
202 | |||
203 | befs_debug(sb, " flags %08x", fs32_to_cpu(sb, sup->flags)); | ||
204 | |||
205 | tmp_run = fsrun_to_cpu(sb, sup->log_blocks); | ||
206 | befs_debug(sb, " log_blocks %u, %hu, %hu", | ||
207 | tmp_run.allocation_group, tmp_run.start, tmp_run.len); | ||
208 | |||
209 | befs_debug(sb, " log_start %Ld", fs64_to_cpu(sb, sup->log_start)); | ||
210 | befs_debug(sb, " log_end %Ld", fs64_to_cpu(sb, sup->log_end)); | ||
211 | |||
212 | befs_debug(sb, " magic3 %08x", fs32_to_cpu(sb, sup->magic3)); | ||
213 | |||
214 | tmp_run = fsrun_to_cpu(sb, sup->root_dir); | ||
215 | befs_debug(sb, " root_dir %u, %hu, %hu", | ||
216 | tmp_run.allocation_group, tmp_run.start, tmp_run.len); | ||
217 | |||
218 | tmp_run = fsrun_to_cpu(sb, sup->indices); | ||
219 | befs_debug(sb, " indices %u, %hu, %hu", | ||
220 | tmp_run.allocation_group, tmp_run.start, tmp_run.len); | ||
221 | |||
222 | #endif //CONFIG_BEFS_DEBUG | ||
223 | } | ||
224 | |||
225 | #if 0 | ||
226 | /* unused */ | ||
227 | void | ||
228 | befs_dump_small_data(const struct super_block *sb, befs_small_data * sd) | ||
229 | { | ||
230 | } | ||
231 | |||
232 | /* unused */ | ||
233 | void | ||
234 | befs_dump_run(const struct super_block *sb, befs_block_run run) | ||
235 | { | ||
236 | #ifdef CONFIG_BEFS_DEBUG | ||
237 | |||
238 | run = fsrun_to_cpu(sb, run); | ||
239 | |||
240 | befs_debug(sb, "[%u, %hu, %hu]", | ||
241 | run.allocation_group, run.start, run.len); | ||
242 | |||
243 | #endif //CONFIG_BEFS_DEBUG | ||
244 | } | ||
245 | #endif /* 0 */ | ||
246 | |||
247 | void | ||
248 | befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super) | ||
249 | { | ||
250 | #ifdef CONFIG_BEFS_DEBUG | ||
251 | |||
252 | befs_debug(sb, "Btree super structure"); | ||
253 | befs_debug(sb, " magic %08x", fs32_to_cpu(sb, super->magic)); | ||
254 | befs_debug(sb, " node_size %u", fs32_to_cpu(sb, super->node_size)); | ||
255 | befs_debug(sb, " max_depth %08x", fs32_to_cpu(sb, super->max_depth)); | ||
256 | |||
257 | befs_debug(sb, " data_type %08x", fs32_to_cpu(sb, super->data_type)); | ||
258 | befs_debug(sb, " root_node_pointer %016LX", | ||
259 | fs64_to_cpu(sb, super->root_node_ptr)); | ||
260 | befs_debug(sb, " free_node_pointer %016LX", | ||
261 | fs64_to_cpu(sb, super->free_node_ptr)); | ||
262 | befs_debug(sb, " maximum size %016LX", | ||
263 | fs64_to_cpu(sb, super->max_size)); | ||
264 | |||
265 | #endif //CONFIG_BEFS_DEBUG | ||
266 | } | ||
267 | |||
268 | void | ||
269 | befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead * node) | ||
270 | { | ||
271 | #ifdef CONFIG_BEFS_DEBUG | ||
272 | |||
273 | befs_debug(sb, "Btree node structure"); | ||
274 | befs_debug(sb, " left %016LX", fs64_to_cpu(sb, node->left)); | ||
275 | befs_debug(sb, " right %016LX", fs64_to_cpu(sb, node->right)); | ||
276 | befs_debug(sb, " overflow %016LX", fs64_to_cpu(sb, node->overflow)); | ||
277 | befs_debug(sb, " all_key_count %hu", | ||
278 | fs16_to_cpu(sb, node->all_key_count)); | ||
279 | befs_debug(sb, " all_key_length %hu", | ||
280 | fs16_to_cpu(sb, node->all_key_length)); | ||
281 | |||
282 | #endif //CONFIG_BEFS_DEBUG | ||
283 | } | ||
diff --git a/fs/befs/endian.h b/fs/befs/endian.h new file mode 100644 index 000000000000..9ecaea4e3325 --- /dev/null +++ b/fs/befs/endian.h | |||
@@ -0,0 +1,126 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/endian.h | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com> | ||
5 | * | ||
6 | * Partially based on similar funtions in the sysv driver. | ||
7 | */ | ||
8 | |||
9 | #ifndef LINUX_BEFS_ENDIAN | ||
10 | #define LINUX_BEFS_ENDIAN | ||
11 | |||
12 | #include <linux/byteorder/generic.h> | ||
13 | #include "befs.h" | ||
14 | |||
15 | static inline u64 | ||
16 | fs64_to_cpu(const struct super_block *sb, u64 n) | ||
17 | { | ||
18 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) | ||
19 | return le64_to_cpu(n); | ||
20 | else | ||
21 | return be64_to_cpu(n); | ||
22 | } | ||
23 | |||
24 | static inline u64 | ||
25 | cpu_to_fs64(const struct super_block *sb, u64 n) | ||
26 | { | ||
27 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) | ||
28 | return cpu_to_le64(n); | ||
29 | else | ||
30 | return cpu_to_be64(n); | ||
31 | } | ||
32 | |||
33 | static inline u32 | ||
34 | fs32_to_cpu(const struct super_block *sb, u32 n) | ||
35 | { | ||
36 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) | ||
37 | return le32_to_cpu(n); | ||
38 | else | ||
39 | return be32_to_cpu(n); | ||
40 | } | ||
41 | |||
42 | static inline u32 | ||
43 | cpu_to_fs32(const struct super_block *sb, u32 n) | ||
44 | { | ||
45 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) | ||
46 | return cpu_to_le32(n); | ||
47 | else | ||
48 | return cpu_to_be32(n); | ||
49 | } | ||
50 | |||
51 | static inline u16 | ||
52 | fs16_to_cpu(const struct super_block *sb, u16 n) | ||
53 | { | ||
54 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) | ||
55 | return le16_to_cpu(n); | ||
56 | else | ||
57 | return be16_to_cpu(n); | ||
58 | } | ||
59 | |||
60 | static inline u16 | ||
61 | cpu_to_fs16(const struct super_block *sb, u16 n) | ||
62 | { | ||
63 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) | ||
64 | return cpu_to_le16(n); | ||
65 | else | ||
66 | return cpu_to_be16(n); | ||
67 | } | ||
68 | |||
69 | /* Composite types below here */ | ||
70 | |||
71 | static inline befs_block_run | ||
72 | fsrun_to_cpu(const struct super_block *sb, befs_block_run n) | ||
73 | { | ||
74 | befs_block_run run; | ||
75 | |||
76 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) { | ||
77 | run.allocation_group = le32_to_cpu(n.allocation_group); | ||
78 | run.start = le16_to_cpu(n.start); | ||
79 | run.len = le16_to_cpu(n.len); | ||
80 | } else { | ||
81 | run.allocation_group = be32_to_cpu(n.allocation_group); | ||
82 | run.start = be16_to_cpu(n.start); | ||
83 | run.len = be16_to_cpu(n.len); | ||
84 | } | ||
85 | return run; | ||
86 | } | ||
87 | |||
88 | static inline befs_block_run | ||
89 | cpu_to_fsrun(const struct super_block *sb, befs_block_run n) | ||
90 | { | ||
91 | befs_block_run run; | ||
92 | |||
93 | if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) { | ||
94 | run.allocation_group = cpu_to_le32(n.allocation_group); | ||
95 | run.start = cpu_to_le16(n.start); | ||
96 | run.len = cpu_to_le16(n.len); | ||
97 | } else { | ||
98 | run.allocation_group = cpu_to_be32(n.allocation_group); | ||
99 | run.start = cpu_to_be16(n.start); | ||
100 | run.len = cpu_to_be16(n.len); | ||
101 | } | ||
102 | return run; | ||
103 | } | ||
104 | |||
105 | static inline befs_data_stream | ||
106 | fsds_to_cpu(const struct super_block *sb, befs_data_stream n) | ||
107 | { | ||
108 | befs_data_stream data; | ||
109 | int i; | ||
110 | |||
111 | for (i = 0; i < BEFS_NUM_DIRECT_BLOCKS; ++i) | ||
112 | data.direct[i] = fsrun_to_cpu(sb, n.direct[i]); | ||
113 | |||
114 | data.max_direct_range = fs64_to_cpu(sb, n.max_direct_range); | ||
115 | data.indirect = fsrun_to_cpu(sb, n.indirect); | ||
116 | data.max_indirect_range = fs64_to_cpu(sb, n.max_indirect_range); | ||
117 | data.double_indirect = fsrun_to_cpu(sb, n.double_indirect); | ||
118 | data.max_double_indirect_range = fs64_to_cpu(sb, | ||
119 | n. | ||
120 | max_double_indirect_range); | ||
121 | data.size = fs64_to_cpu(sb, n.size); | ||
122 | |||
123 | return data; | ||
124 | } | ||
125 | |||
126 | #endif //LINUX_BEFS_ENDIAN | ||
diff --git a/fs/befs/inode.c b/fs/befs/inode.c new file mode 100644 index 000000000000..d41c9247ae8a --- /dev/null +++ b/fs/befs/inode.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * inode.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com> | ||
5 | */ | ||
6 | |||
7 | #include <linux/fs.h> | ||
8 | |||
9 | #include "befs.h" | ||
10 | #include "inode.h" | ||
11 | #include "endian.h" | ||
12 | |||
13 | /* | ||
14 | Validates the correctness of the befs inode | ||
15 | Returns BEFS_OK if the inode should be used, otherwise | ||
16 | returns BEFS_BAD_INODE | ||
17 | */ | ||
18 | int | ||
19 | befs_check_inode(struct super_block *sb, befs_inode * raw_inode, | ||
20 | befs_blocknr_t inode) | ||
21 | { | ||
22 | u32 magic1 = fs32_to_cpu(sb, raw_inode->magic1); | ||
23 | befs_inode_addr ino_num = fsrun_to_cpu(sb, raw_inode->inode_num); | ||
24 | u32 flags = fs32_to_cpu(sb, raw_inode->flags); | ||
25 | |||
26 | /* check magic header. */ | ||
27 | if (magic1 != BEFS_INODE_MAGIC1) { | ||
28 | befs_error(sb, | ||
29 | "Inode has a bad magic header - inode = %lu", inode); | ||
30 | return BEFS_BAD_INODE; | ||
31 | } | ||
32 | |||
33 | /* | ||
34 | * Sanity check2: inodes store their own block address. Check it. | ||
35 | */ | ||
36 | if (inode != iaddr2blockno(sb, &ino_num)) { | ||
37 | befs_error(sb, "inode blocknr field disagrees with vfs " | ||
38 | "VFS: %lu, Inode %lu", | ||
39 | inode, iaddr2blockno(sb, &ino_num)); | ||
40 | return BEFS_BAD_INODE; | ||
41 | } | ||
42 | |||
43 | /* | ||
44 | * check flag | ||
45 | */ | ||
46 | |||
47 | if (!(flags & BEFS_INODE_IN_USE)) { | ||
48 | befs_error(sb, "inode is not used - inode = %lu", inode); | ||
49 | return BEFS_BAD_INODE; | ||
50 | } | ||
51 | |||
52 | return BEFS_OK; | ||
53 | } | ||
diff --git a/fs/befs/inode.h b/fs/befs/inode.h new file mode 100644 index 000000000000..9dc7fd9b7570 --- /dev/null +++ b/fs/befs/inode.h | |||
@@ -0,0 +1,8 @@ | |||
1 | /* | ||
2 | * inode.h | ||
3 | * | ||
4 | */ | ||
5 | |||
6 | int befs_check_inode(struct super_block *sb, befs_inode * raw_inode, | ||
7 | befs_blocknr_t inode); | ||
8 | |||
diff --git a/fs/befs/io.c b/fs/befs/io.c new file mode 100644 index 000000000000..ddef98aa255d --- /dev/null +++ b/fs/befs/io.c | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/io.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com | ||
5 | * | ||
6 | * Based on portions of file.c and inode.c | ||
7 | * by Makoto Kato (m_kato@ga2.so-net.ne.jp) | ||
8 | * | ||
9 | * Many thanks to Dominic Giampaolo, author of Practical File System | ||
10 | * Design with the Be File System, for such a helpful book. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/buffer_head.h> | ||
15 | |||
16 | #include "befs.h" | ||
17 | #include "io.h" | ||
18 | |||
19 | /* | ||
20 | * Converts befs notion of disk addr to a disk offset and uses | ||
21 | * linux kernel function sb_bread() to get the buffer containing | ||
22 | * the offset. -Will Dyson | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | struct buffer_head * | ||
27 | befs_bread_iaddr(struct super_block *sb, befs_inode_addr iaddr) | ||
28 | { | ||
29 | struct buffer_head *bh = NULL; | ||
30 | befs_blocknr_t block = 0; | ||
31 | befs_sb_info *befs_sb = BEFS_SB(sb); | ||
32 | |||
33 | befs_debug(sb, "---> Enter befs_read_iaddr() " | ||
34 | "[%u, %hu, %hu]", | ||
35 | iaddr.allocation_group, iaddr.start, iaddr.len); | ||
36 | |||
37 | if (iaddr.allocation_group > befs_sb->num_ags) { | ||
38 | befs_error(sb, "BEFS: Invalid allocation group %u, max is %u", | ||
39 | iaddr.allocation_group, befs_sb->num_ags); | ||
40 | goto error; | ||
41 | } | ||
42 | |||
43 | block = iaddr2blockno(sb, &iaddr); | ||
44 | |||
45 | befs_debug(sb, "befs_read_iaddr: offset = %lu", block); | ||
46 | |||
47 | bh = sb_bread(sb, block); | ||
48 | |||
49 | if (bh == NULL) { | ||
50 | befs_error(sb, "Failed to read block %lu", block); | ||
51 | goto error; | ||
52 | } | ||
53 | |||
54 | befs_debug(sb, "<--- befs_read_iaddr()"); | ||
55 | return bh; | ||
56 | |||
57 | error: | ||
58 | befs_debug(sb, "<--- befs_read_iaddr() ERROR"); | ||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | struct buffer_head * | ||
63 | befs_bread(struct super_block *sb, befs_blocknr_t block) | ||
64 | { | ||
65 | struct buffer_head *bh = NULL; | ||
66 | |||
67 | befs_debug(sb, "---> Enter befs_read() %Lu", block); | ||
68 | |||
69 | bh = sb_bread(sb, block); | ||
70 | |||
71 | if (bh == NULL) { | ||
72 | befs_error(sb, "Failed to read block %lu", block); | ||
73 | goto error; | ||
74 | } | ||
75 | |||
76 | befs_debug(sb, "<--- befs_read()"); | ||
77 | |||
78 | return bh; | ||
79 | |||
80 | error: | ||
81 | befs_debug(sb, "<--- befs_read() ERROR"); | ||
82 | return NULL; | ||
83 | } | ||
diff --git a/fs/befs/io.h b/fs/befs/io.h new file mode 100644 index 000000000000..9b78266b6aa5 --- /dev/null +++ b/fs/befs/io.h | |||
@@ -0,0 +1,9 @@ | |||
1 | /* | ||
2 | * io.h | ||
3 | */ | ||
4 | |||
5 | struct buffer_head *befs_bread_iaddr(struct super_block *sb, | ||
6 | befs_inode_addr iaddr); | ||
7 | |||
8 | struct buffer_head *befs_bread(struct super_block *sb, befs_blocknr_t block); | ||
9 | |||
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c new file mode 100644 index 000000000000..de5bb280a828 --- /dev/null +++ b/fs/befs/linuxvfs.c | |||
@@ -0,0 +1,964 @@ | |||
1 | /* | ||
2 | * linux/fs/befs/linuxvfs.c | ||
3 | * | ||
4 | * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com | ||
5 | * | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/fs.h> | ||
11 | #include <linux/errno.h> | ||
12 | #include <linux/stat.h> | ||
13 | #include <linux/nls.h> | ||
14 | #include <linux/buffer_head.h> | ||
15 | #include <linux/vfs.h> | ||
16 | #include <linux/parser.h> | ||
17 | #include <linux/namei.h> | ||
18 | |||
19 | #include "befs.h" | ||
20 | #include "btree.h" | ||
21 | #include "inode.h" | ||
22 | #include "datastream.h" | ||
23 | #include "super.h" | ||
24 | #include "io.h" | ||
25 | #include "endian.h" | ||
26 | |||
27 | MODULE_DESCRIPTION("BeOS File System (BeFS) driver"); | ||
28 | MODULE_AUTHOR("Will Dyson"); | ||
29 | MODULE_LICENSE("GPL"); | ||
30 | |||
31 | /* The units the vfs expects inode->i_blocks to be in */ | ||
32 | #define VFS_BLOCK_SIZE 512 | ||
33 | |||
34 | static int befs_readdir(struct file *, void *, filldir_t); | ||
35 | static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int); | ||
36 | static int befs_readpage(struct file *file, struct page *page); | ||
37 | static sector_t befs_bmap(struct address_space *mapping, sector_t block); | ||
38 | static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *); | ||
39 | static void befs_read_inode(struct inode *ino); | ||
40 | static struct inode *befs_alloc_inode(struct super_block *sb); | ||
41 | static void befs_destroy_inode(struct inode *inode); | ||
42 | static int befs_init_inodecache(void); | ||
43 | static void befs_destroy_inodecache(void); | ||
44 | static int befs_follow_link(struct dentry *, struct nameidata *); | ||
45 | static void befs_put_link(struct dentry *, struct nameidata *); | ||
46 | static int befs_utf2nls(struct super_block *sb, const char *in, int in_len, | ||
47 | char **out, int *out_len); | ||
48 | static int befs_nls2utf(struct super_block *sb, const char *in, int in_len, | ||
49 | char **out, int *out_len); | ||
50 | static void befs_put_super(struct super_block *); | ||
51 | static int befs_remount(struct super_block *, int *, char *); | ||
52 | static int befs_statfs(struct super_block *, struct kstatfs *); | ||
53 | static int parse_options(char *, befs_mount_options *); | ||
54 | |||
55 | static const struct super_operations befs_sops = { | ||
56 | .read_inode = befs_read_inode, /* initialize & read inode */ | ||
57 | .alloc_inode = befs_alloc_inode, /* allocate a new inode */ | ||
58 | .destroy_inode = befs_destroy_inode, /* deallocate an inode */ | ||
59 | .put_super = befs_put_super, /* uninit super */ | ||
60 | .statfs = befs_statfs, /* statfs */ | ||
61 | .remount_fs = befs_remount, | ||
62 | }; | ||
63 | |||
64 | /* slab cache for befs_inode_info objects */ | ||
65 | static kmem_cache_t *befs_inode_cachep; | ||
66 | |||
67 | static struct file_operations befs_dir_operations = { | ||
68 | .read = generic_read_dir, | ||
69 | .readdir = befs_readdir, | ||
70 | }; | ||
71 | |||
72 | static struct inode_operations befs_dir_inode_operations = { | ||
73 | .lookup = befs_lookup, | ||
74 | }; | ||
75 | |||
76 | static struct file_operations befs_file_operations = { | ||
77 | .llseek = default_llseek, | ||
78 | .read = generic_file_read, | ||
79 | .mmap = generic_file_readonly_mmap, | ||
80 | }; | ||
81 | |||
82 | static struct address_space_operations befs_aops = { | ||
83 | .readpage = befs_readpage, | ||
84 | .sync_page = block_sync_page, | ||
85 | .bmap = befs_bmap, | ||
86 | }; | ||
87 | |||
88 | static struct inode_operations befs_symlink_inode_operations = { | ||
89 | .readlink = generic_readlink, | ||
90 | .follow_link = befs_follow_link, | ||
91 | .put_link = befs_put_link, | ||
92 | }; | ||
93 | |||
94 | /* | ||
95 | * Called by generic_file_read() to read a page of data | ||
96 | * | ||
97 | * In turn, simply calls a generic block read function and | ||
98 | * passes it the address of befs_get_block, for mapping file | ||
99 | * positions to disk blocks. | ||
100 | */ | ||
101 | static int | ||
102 | befs_readpage(struct file *file, struct page *page) | ||
103 | { | ||
104 | return block_read_full_page(page, befs_get_block); | ||
105 | } | ||
106 | |||
107 | static sector_t | ||
108 | befs_bmap(struct address_space *mapping, sector_t block) | ||
109 | { | ||
110 | return generic_block_bmap(mapping, block, befs_get_block); | ||
111 | } | ||
112 | |||
113 | /* | ||
114 | * Generic function to map a file position (block) to a | ||
115 | * disk offset (passed back in bh_result). | ||
116 | * | ||
117 | * Used by many higher level functions. | ||
118 | * | ||
119 | * Calls befs_fblock2brun() in datastream.c to do the real work. | ||
120 | * | ||
121 | * -WD 10-26-01 | ||
122 | */ | ||
123 | |||
124 | static int | ||
125 | befs_get_block(struct inode *inode, sector_t block, | ||
126 | struct buffer_head *bh_result, int create) | ||
127 | { | ||
128 | struct super_block *sb = inode->i_sb; | ||
129 | befs_data_stream *ds = &BEFS_I(inode)->i_data.ds; | ||
130 | befs_block_run run = BAD_IADDR; | ||
131 | int res = 0; | ||
132 | ulong disk_off; | ||
133 | |||
134 | befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld", | ||
135 | inode->i_ino, block); | ||
136 | |||
137 | if (block < 0) { | ||
138 | befs_error(sb, "befs_get_block() was asked for a block " | ||
139 | "number less than zero: block %ld in inode %lu", | ||
140 | block, inode->i_ino); | ||
141 | return -EIO; | ||
142 | } | ||
143 | |||
144 | if (create) { | ||
145 | befs_error(sb, "befs_get_block() was asked to write to " | ||
146 | "block %ld in inode %lu", block, inode->i_ino); | ||
147 | return -EPERM; | ||
148 | } | ||
149 | |||
150 | res = befs_fblock2brun(sb, ds, block, &run); | ||
151 | if (res != BEFS_OK) { | ||
152 | befs_error(sb, | ||
153 | "<--- befs_get_block() for inode %lu, block " | ||
154 | "%ld ERROR", inode->i_ino, block); | ||
155 | return -EFBIG; | ||
156 | } | ||
157 | |||
158 | disk_off = (ulong) iaddr2blockno(sb, &run); | ||
159 | |||
160 | map_bh(bh_result, inode->i_sb, disk_off); | ||
161 | |||
162 | befs_debug(sb, "<--- befs_get_block() for inode %lu, block %ld, " | ||
163 | "disk address %lu", inode->i_ino, block, disk_off); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static struct dentry * | ||
169 | befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | ||
170 | { | ||
171 | struct inode *inode = NULL; | ||
172 | struct super_block *sb = dir->i_sb; | ||
173 | befs_data_stream *ds = &BEFS_I(dir)->i_data.ds; | ||
174 | befs_off_t offset; | ||
175 | int ret; | ||
176 | int utfnamelen; | ||
177 | char *utfname; | ||
178 | const char *name = dentry->d_name.name; | ||
179 | |||
180 | befs_debug(sb, "---> befs_lookup() " | ||
181 | "name %s inode %ld", dentry->d_name.name, dir->i_ino); | ||
182 | |||
183 | /* Convert to UTF-8 */ | ||
184 | if (BEFS_SB(sb)->nls) { | ||
185 | ret = | ||
186 | befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen); | ||
187 | if (ret < 0) { | ||
188 | befs_debug(sb, "<--- befs_lookup() ERROR"); | ||
189 | return ERR_PTR(ret); | ||
190 | } | ||
191 | ret = befs_btree_find(sb, ds, utfname, &offset); | ||
192 | kfree(utfname); | ||
193 | |||
194 | } else { | ||
195 | ret = befs_btree_find(sb, ds, dentry->d_name.name, &offset); | ||
196 | } | ||
197 | |||
198 | if (ret == BEFS_BT_NOT_FOUND) { | ||
199 | befs_debug(sb, "<--- befs_lookup() %s not found", | ||
200 | dentry->d_name.name); | ||
201 | return ERR_PTR(-ENOENT); | ||
202 | |||
203 | } else if (ret != BEFS_OK || offset == 0) { | ||
204 | befs_warning(sb, "<--- befs_lookup() Error"); | ||
205 | return ERR_PTR(-ENODATA); | ||
206 | } | ||
207 | |||
208 | inode = iget(dir->i_sb, (ino_t) offset); | ||
209 | if (!inode) | ||
210 | return ERR_PTR(-EACCES); | ||
211 | |||
212 | d_add(dentry, inode); | ||
213 | |||
214 | befs_debug(sb, "<--- befs_lookup()"); | ||
215 | |||
216 | return NULL; | ||
217 | } | ||
218 | |||
219 | static int | ||
220 | befs_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
221 | { | ||
222 | struct inode *inode = filp->f_dentry->d_inode; | ||
223 | struct super_block *sb = inode->i_sb; | ||
224 | befs_data_stream *ds = &BEFS_I(inode)->i_data.ds; | ||
225 | befs_off_t value; | ||
226 | int result; | ||
227 | size_t keysize; | ||
228 | unsigned char d_type; | ||
229 | char keybuf[BEFS_NAME_LEN + 1]; | ||
230 | char *nlsname; | ||
231 | int nlsnamelen; | ||
232 | const char *dirname = filp->f_dentry->d_name.name; | ||
233 | |||
234 | befs_debug(sb, "---> befs_readdir() " | ||
235 | "name %s, inode %ld, filp->f_pos %Ld", | ||
236 | dirname, inode->i_ino, filp->f_pos); | ||
237 | |||
238 | result = befs_btree_read(sb, ds, filp->f_pos, BEFS_NAME_LEN + 1, | ||
239 | keybuf, &keysize, &value); | ||
240 | |||
241 | if (result == BEFS_ERR) { | ||
242 | befs_debug(sb, "<--- befs_readdir() ERROR"); | ||
243 | befs_error(sb, "IO error reading %s (inode %lu)", | ||
244 | dirname, inode->i_ino); | ||
245 | return -EIO; | ||
246 | |||
247 | } else if (result == BEFS_BT_END) { | ||
248 | befs_debug(sb, "<--- befs_readdir() END"); | ||
249 | return 0; | ||
250 | |||
251 | } else if (result == BEFS_BT_EMPTY) { | ||
252 | befs_debug(sb, "<--- befs_readdir() Empty directory"); | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | d_type = DT_UNKNOWN; | ||
257 | |||
258 | /* Convert to NLS */ | ||
259 | if (BEFS_SB(sb)->nls) { | ||
260 | result = | ||
261 | befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen); | ||
262 | if (result < 0) { | ||
263 | befs_debug(sb, "<--- befs_readdir() ERROR"); | ||
264 | return result; | ||
265 | } | ||
266 | result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos, | ||
267 | (ino_t) value, d_type); | ||
268 | kfree(nlsname); | ||
269 | |||
270 | } else { | ||
271 | result = filldir(dirent, keybuf, keysize, filp->f_pos, | ||
272 | (ino_t) value, d_type); | ||
273 | } | ||
274 | |||
275 | filp->f_pos++; | ||
276 | |||
277 | befs_debug(sb, "<--- befs_readdir() filp->f_pos %Ld", filp->f_pos); | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | static struct inode * | ||
283 | befs_alloc_inode(struct super_block *sb) | ||
284 | { | ||
285 | struct befs_inode_info *bi; | ||
286 | bi = (struct befs_inode_info *)kmem_cache_alloc(befs_inode_cachep, | ||
287 | SLAB_KERNEL); | ||
288 | if (!bi) | ||
289 | return NULL; | ||
290 | return &bi->vfs_inode; | ||
291 | } | ||
292 | |||
293 | static void | ||
294 | befs_destroy_inode(struct inode *inode) | ||
295 | { | ||
296 | kmem_cache_free(befs_inode_cachep, BEFS_I(inode)); | ||
297 | } | ||
298 | |||
299 | static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags) | ||
300 | { | ||
301 | struct befs_inode_info *bi = (struct befs_inode_info *) foo; | ||
302 | |||
303 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | ||
304 | SLAB_CTOR_CONSTRUCTOR) { | ||
305 | inode_init_once(&bi->vfs_inode); | ||
306 | } | ||
307 | } | ||
308 | |||
309 | static void | ||
310 | befs_read_inode(struct inode *inode) | ||
311 | { | ||
312 | struct buffer_head *bh = NULL; | ||
313 | befs_inode *raw_inode = NULL; | ||
314 | |||
315 | struct super_block *sb = inode->i_sb; | ||
316 | befs_sb_info *befs_sb = BEFS_SB(sb); | ||
317 | befs_inode_info *befs_ino = NULL; | ||
318 | |||
319 | befs_debug(sb, "---> befs_read_inode() " "inode = %lu", inode->i_ino); | ||
320 | |||
321 | befs_ino = BEFS_I(inode); | ||
322 | |||
323 | /* convert from vfs's inode number to befs's inode number */ | ||
324 | befs_ino->i_inode_num = blockno2iaddr(sb, inode->i_ino); | ||
325 | |||
326 | befs_debug(sb, " real inode number [%u, %hu, %hu]", | ||
327 | befs_ino->i_inode_num.allocation_group, | ||
328 | befs_ino->i_inode_num.start, befs_ino->i_inode_num.len); | ||
329 | |||
330 | bh = befs_bread(sb, inode->i_ino); | ||
331 | if (!bh) { | ||
332 | befs_error(sb, "unable to read inode block - " | ||
333 | "inode = %lu", inode->i_ino); | ||
334 | goto unaquire_none; | ||
335 | } | ||
336 | |||
337 | raw_inode = (befs_inode *) bh->b_data; | ||
338 | |||
339 | befs_dump_inode(sb, raw_inode); | ||
340 | |||
341 | if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) { | ||
342 | befs_error(sb, "Bad inode: %lu", inode->i_ino); | ||
343 | goto unaquire_bh; | ||
344 | } | ||
345 | |||
346 | inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode); | ||
347 | |||
348 | /* | ||
349 | * set uid and gid. But since current BeOS is single user OS, so | ||
350 | * you can change by "uid" or "gid" options. | ||
351 | */ | ||
352 | |||
353 | inode->i_uid = befs_sb->mount_opts.use_uid ? | ||
354 | befs_sb->mount_opts.uid : (uid_t) fs32_to_cpu(sb, raw_inode->uid); | ||
355 | inode->i_gid = befs_sb->mount_opts.use_gid ? | ||
356 | befs_sb->mount_opts.gid : (gid_t) fs32_to_cpu(sb, raw_inode->gid); | ||
357 | |||
358 | inode->i_nlink = 1; | ||
359 | |||
360 | /* | ||
361 | * BEFS's time is 64 bits, but current VFS is 32 bits... | ||
362 | * BEFS don't have access time. Nor inode change time. VFS | ||
363 | * doesn't have creation time. | ||
364 | * Also, the lower 16 bits of the last_modified_time and | ||
365 | * create_time are just a counter to help ensure uniqueness | ||
366 | * for indexing purposes. (PFD, page 54) | ||
367 | */ | ||
368 | |||
369 | inode->i_mtime.tv_sec = | ||
370 | fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16; | ||
371 | inode->i_mtime.tv_nsec = 0; /* lower 16 bits are not a time */ | ||
372 | inode->i_ctime = inode->i_mtime; | ||
373 | inode->i_atime = inode->i_mtime; | ||
374 | inode->i_blksize = befs_sb->block_size; | ||
375 | |||
376 | befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num); | ||
377 | befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent); | ||
378 | befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes); | ||
379 | befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags); | ||
380 | |||
381 | if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){ | ||
382 | inode->i_size = 0; | ||
383 | inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE; | ||
384 | strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink, | ||
385 | BEFS_SYMLINK_LEN); | ||
386 | } else { | ||
387 | int num_blks; | ||
388 | |||
389 | befs_ino->i_data.ds = | ||
390 | fsds_to_cpu(sb, raw_inode->data.datastream); | ||
391 | |||
392 | num_blks = befs_count_blocks(sb, &befs_ino->i_data.ds); | ||
393 | inode->i_blocks = | ||
394 | num_blks * (befs_sb->block_size / VFS_BLOCK_SIZE); | ||
395 | inode->i_size = befs_ino->i_data.ds.size; | ||
396 | } | ||
397 | |||
398 | inode->i_mapping->a_ops = &befs_aops; | ||
399 | |||
400 | if (S_ISREG(inode->i_mode)) { | ||
401 | inode->i_fop = &befs_file_operations; | ||
402 | } else if (S_ISDIR(inode->i_mode)) { | ||
403 | inode->i_op = &befs_dir_inode_operations; | ||
404 | inode->i_fop = &befs_dir_operations; | ||
405 | } else if (S_ISLNK(inode->i_mode)) { | ||
406 | inode->i_op = &befs_symlink_inode_operations; | ||
407 | } else { | ||
408 | befs_error(sb, "Inode %lu is not a regular file, " | ||
409 | "directory or symlink. THAT IS WRONG! BeFS has no " | ||
410 | "on disk special files", inode->i_ino); | ||
411 | goto unaquire_bh; | ||
412 | } | ||
413 | |||
414 | brelse(bh); | ||
415 | befs_debug(sb, "<--- befs_read_inode()"); | ||
416 | return; | ||
417 | |||
418 | unaquire_bh: | ||
419 | brelse(bh); | ||
420 | |||
421 | unaquire_none: | ||
422 | make_bad_inode(inode); | ||
423 | befs_debug(sb, "<--- befs_read_inode() - Bad inode"); | ||
424 | return; | ||
425 | } | ||
426 | |||
427 | /* Initialize the inode cache. Called at fs setup. | ||
428 | * | ||
429 | * Taken from NFS implementation by Al Viro. | ||
430 | */ | ||
431 | static int | ||
432 | befs_init_inodecache(void) | ||
433 | { | ||
434 | befs_inode_cachep = kmem_cache_create("befs_inode_cache", | ||
435 | sizeof (struct befs_inode_info), | ||
436 | 0, SLAB_RECLAIM_ACCOUNT, | ||
437 | init_once, NULL); | ||
438 | if (befs_inode_cachep == NULL) { | ||
439 | printk(KERN_ERR "befs_init_inodecache: " | ||
440 | "Couldn't initalize inode slabcache\n"); | ||
441 | return -ENOMEM; | ||
442 | } | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | /* Called at fs teardown. | ||
448 | * | ||
449 | * Taken from NFS implementation by Al Viro. | ||
450 | */ | ||
451 | static void | ||
452 | befs_destroy_inodecache(void) | ||
453 | { | ||
454 | if (kmem_cache_destroy(befs_inode_cachep)) | ||
455 | printk(KERN_ERR "befs_destroy_inodecache: " | ||
456 | "not all structures were freed\n"); | ||
457 | } | ||
458 | |||
459 | /* | ||
460 | * The inode of symbolic link is different to data stream. | ||
461 | * The data stream become link name. Unless the LONG_SYMLINK | ||
462 | * flag is set. | ||
463 | */ | ||
464 | static int | ||
465 | befs_follow_link(struct dentry *dentry, struct nameidata *nd) | ||
466 | { | ||
467 | befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); | ||
468 | char *link; | ||
469 | |||
470 | if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { | ||
471 | struct super_block *sb = dentry->d_sb; | ||
472 | befs_data_stream *data = &befs_ino->i_data.ds; | ||
473 | befs_off_t len = data->size; | ||
474 | |||
475 | befs_debug(sb, "Follow long symlink"); | ||
476 | |||
477 | link = kmalloc(len, GFP_NOFS); | ||
478 | if (!link) { | ||
479 | link = ERR_PTR(-ENOMEM); | ||
480 | } else if (befs_read_lsymlink(sb, data, link, len) != len) { | ||
481 | kfree(link); | ||
482 | befs_error(sb, "Failed to read entire long symlink"); | ||
483 | link = ERR_PTR(-EIO); | ||
484 | } | ||
485 | } else { | ||
486 | link = befs_ino->i_data.symlink; | ||
487 | } | ||
488 | |||
489 | nd_set_link(nd, link); | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static void befs_put_link(struct dentry *dentry, struct nameidata *nd) | ||
494 | { | ||
495 | befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); | ||
496 | if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { | ||
497 | char *p = nd_get_link(nd); | ||
498 | if (!IS_ERR(p)) | ||
499 | kfree(p); | ||
500 | } | ||
501 | } | ||
502 | |||
503 | /* | ||
504 | * UTF-8 to NLS charset convert routine | ||
505 | * | ||
506 | * | ||
507 | * Changed 8/10/01 by Will Dyson. Now use uni2char() / char2uni() rather than | ||
508 | * the nls tables directly | ||
509 | */ | ||
510 | |||
511 | static int | ||
512 | befs_utf2nls(struct super_block *sb, const char *in, | ||
513 | int in_len, char **out, int *out_len) | ||
514 | { | ||
515 | struct nls_table *nls = BEFS_SB(sb)->nls; | ||
516 | int i, o; | ||
517 | wchar_t uni; | ||
518 | int unilen, utflen; | ||
519 | char *result; | ||
520 | int maxlen = in_len; /* The utf8->nls conversion can't make more chars */ | ||
521 | |||
522 | befs_debug(sb, "---> utf2nls()"); | ||
523 | |||
524 | if (!nls) { | ||
525 | befs_error(sb, "befs_utf2nls called with no NLS table loaded"); | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | *out = result = kmalloc(maxlen, GFP_NOFS); | ||
530 | if (!*out) { | ||
531 | befs_error(sb, "befs_utf2nls() cannot allocate memory"); | ||
532 | *out_len = 0; | ||
533 | return -ENOMEM; | ||
534 | } | ||
535 | |||
536 | for (i = o = 0; i < in_len; i += utflen, o += unilen) { | ||
537 | |||
538 | /* convert from UTF-8 to Unicode */ | ||
539 | utflen = utf8_mbtowc(&uni, &in[i], in_len - i); | ||
540 | if (utflen < 0) { | ||
541 | goto conv_err; | ||
542 | } | ||
543 | |||
544 | /* convert from Unicode to nls */ | ||
545 | unilen = nls->uni2char(uni, &result[o], in_len - o); | ||
546 | if (unilen < 0) { | ||
547 | goto conv_err; | ||
548 | } | ||
549 | } | ||
550 | result[o] = '\0'; | ||
551 | *out_len = o; | ||
552 | |||
553 | befs_debug(sb, "<--- utf2nls()"); | ||
554 | |||
555 | return o; | ||
556 | |||
557 | conv_err: | ||
558 | befs_error(sb, "Name using character set %s contains a character that " | ||
559 | "cannot be converted to unicode.", nls->charset); | ||
560 | befs_debug(sb, "<--- utf2nls()"); | ||
561 | kfree(result); | ||
562 | return -EILSEQ; | ||
563 | } | ||
564 | |||
565 | /** | ||
566 | * befs_nls2utf - Convert NLS string to utf8 encodeing | ||
567 | * @sb: Superblock | ||
568 | * @src: Input string buffer in NLS format | ||
569 | * @srclen: Length of input string in bytes | ||
570 | * @dest: The output string in UTF8 format | ||
571 | * @destlen: Length of the output buffer | ||
572 | * | ||
573 | * Converts input string @src, which is in the format of the loaded NLS map, | ||
574 | * into a utf8 string. | ||
575 | * | ||
576 | * The destination string @dest is allocated by this function and the caller is | ||
577 | * responsible for freeing it with kfree() | ||
578 | * | ||
579 | * On return, *@destlen is the length of @dest in bytes. | ||
580 | * | ||
581 | * On success, the return value is the number of utf8 characters written to | ||
582 | * the output buffer @dest. | ||
583 | * | ||
584 | * On Failure, a negative number coresponding to the error code is returned. | ||
585 | */ | ||
586 | |||
587 | static int | ||
588 | befs_nls2utf(struct super_block *sb, const char *in, | ||
589 | int in_len, char **out, int *out_len) | ||
590 | { | ||
591 | struct nls_table *nls = BEFS_SB(sb)->nls; | ||
592 | int i, o; | ||
593 | wchar_t uni; | ||
594 | int unilen, utflen; | ||
595 | char *result; | ||
596 | int maxlen = 3 * in_len; | ||
597 | |||
598 | befs_debug(sb, "---> nls2utf()\n"); | ||
599 | |||
600 | if (!nls) { | ||
601 | befs_error(sb, "befs_nls2utf called with no NLS table loaded."); | ||
602 | return -EINVAL; | ||
603 | } | ||
604 | |||
605 | *out = result = kmalloc(maxlen, GFP_NOFS); | ||
606 | if (!*out) { | ||
607 | befs_error(sb, "befs_nls2utf() cannot allocate memory"); | ||
608 | *out_len = 0; | ||
609 | return -ENOMEM; | ||
610 | } | ||
611 | |||
612 | for (i = o = 0; i < in_len; i += unilen, o += utflen) { | ||
613 | |||
614 | /* convert from nls to unicode */ | ||
615 | unilen = nls->char2uni(&in[i], in_len - i, &uni); | ||
616 | if (unilen < 0) { | ||
617 | goto conv_err; | ||
618 | } | ||
619 | |||
620 | /* convert from unicode to UTF-8 */ | ||
621 | utflen = utf8_wctomb(&result[o], uni, 3); | ||
622 | if (utflen <= 0) { | ||
623 | goto conv_err; | ||
624 | } | ||
625 | } | ||
626 | |||
627 | result[o] = '\0'; | ||
628 | *out_len = o; | ||
629 | |||
630 | befs_debug(sb, "<--- nls2utf()"); | ||
631 | |||
632 | return i; | ||
633 | |||
634 | conv_err: | ||
635 | befs_error(sb, "Name using charecter set %s contains a charecter that " | ||
636 | "cannot be converted to unicode.", nls->charset); | ||
637 | befs_debug(sb, "<--- nls2utf()"); | ||
638 | kfree(result); | ||
639 | return -EILSEQ; | ||
640 | } | ||
641 | |||
642 | /** | ||
643 | * Use the | ||
644 | * | ||
645 | */ | ||
646 | enum { | ||
647 | Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err, | ||
648 | }; | ||
649 | |||
650 | static match_table_t befs_tokens = { | ||
651 | {Opt_uid, "uid=%d"}, | ||
652 | {Opt_gid, "gid=%d"}, | ||
653 | {Opt_charset, "iocharset=%s"}, | ||
654 | {Opt_debug, "debug"}, | ||
655 | {Opt_err, NULL} | ||
656 | }; | ||
657 | |||
658 | static int | ||
659 | parse_options(char *options, befs_mount_options * opts) | ||
660 | { | ||
661 | char *p; | ||
662 | substring_t args[MAX_OPT_ARGS]; | ||
663 | int option; | ||
664 | |||
665 | /* Initialize options */ | ||
666 | opts->uid = 0; | ||
667 | opts->gid = 0; | ||
668 | opts->use_uid = 0; | ||
669 | opts->use_gid = 0; | ||
670 | opts->iocharset = NULL; | ||
671 | opts->debug = 0; | ||
672 | |||
673 | if (!options) | ||
674 | return 1; | ||
675 | |||
676 | while ((p = strsep(&options, ",")) != NULL) { | ||
677 | int token; | ||
678 | if (!*p) | ||
679 | continue; | ||
680 | |||
681 | token = match_token(p, befs_tokens, args); | ||
682 | switch (token) { | ||
683 | case Opt_uid: | ||
684 | if (match_int(&args[0], &option)) | ||
685 | return 0; | ||
686 | if (option < 0) { | ||
687 | printk(KERN_ERR "BeFS: Invalid uid %d, " | ||
688 | "using default\n", option); | ||
689 | break; | ||
690 | } | ||
691 | opts->uid = option; | ||
692 | opts->use_uid = 1; | ||
693 | break; | ||
694 | case Opt_gid: | ||
695 | if (match_int(&args[0], &option)) | ||
696 | return 0; | ||
697 | if (option < 0) { | ||
698 | printk(KERN_ERR "BeFS: Invalid gid %d, " | ||
699 | "using default\n", option); | ||
700 | break; | ||
701 | } | ||
702 | opts->gid = option; | ||
703 | opts->use_gid = 1; | ||
704 | break; | ||
705 | case Opt_charset: | ||
706 | kfree(opts->iocharset); | ||
707 | opts->iocharset = match_strdup(&args[0]); | ||
708 | if (!opts->iocharset) { | ||
709 | printk(KERN_ERR "BeFS: allocation failure for " | ||
710 | "iocharset string\n"); | ||
711 | return 0; | ||
712 | } | ||
713 | break; | ||
714 | case Opt_debug: | ||
715 | opts->debug = 1; | ||
716 | break; | ||
717 | default: | ||
718 | printk(KERN_ERR "BeFS: Unrecognized mount option \"%s\" " | ||
719 | "or missing value\n", p); | ||
720 | return 0; | ||
721 | } | ||
722 | } | ||
723 | return 1; | ||
724 | } | ||
725 | |||
726 | /* This function has the responsibiltiy of getting the | ||
727 | * filesystem ready for unmounting. | ||
728 | * Basicly, we free everything that we allocated in | ||
729 | * befs_read_inode | ||
730 | */ | ||
731 | static void | ||
732 | befs_put_super(struct super_block *sb) | ||
733 | { | ||
734 | if (BEFS_SB(sb)->mount_opts.iocharset) { | ||
735 | kfree(BEFS_SB(sb)->mount_opts.iocharset); | ||
736 | BEFS_SB(sb)->mount_opts.iocharset = NULL; | ||
737 | } | ||
738 | |||
739 | if (BEFS_SB(sb)->nls) { | ||
740 | unload_nls(BEFS_SB(sb)->nls); | ||
741 | BEFS_SB(sb)->nls = NULL; | ||
742 | } | ||
743 | |||
744 | if (sb->s_fs_info) { | ||
745 | kfree(sb->s_fs_info); | ||
746 | sb->s_fs_info = NULL; | ||
747 | } | ||
748 | return; | ||
749 | } | ||
750 | |||
751 | /* Allocate private field of the superblock, fill it. | ||
752 | * | ||
753 | * Finish filling the public superblock fields | ||
754 | * Make the root directory | ||
755 | * Load a set of NLS translations if needed. | ||
756 | */ | ||
757 | static int | ||
758 | befs_fill_super(struct super_block *sb, void *data, int silent) | ||
759 | { | ||
760 | struct buffer_head *bh; | ||
761 | befs_sb_info *befs_sb; | ||
762 | befs_super_block *disk_sb; | ||
763 | struct inode *root; | ||
764 | |||
765 | const unsigned long sb_block = 0; | ||
766 | const off_t x86_sb_off = 512; | ||
767 | |||
768 | sb->s_fs_info = kmalloc(sizeof (*befs_sb), GFP_KERNEL); | ||
769 | if (sb->s_fs_info == NULL) { | ||
770 | printk(KERN_ERR | ||
771 | "BeFS(%s): Unable to allocate memory for private " | ||
772 | "portion of superblock. Bailing.\n", sb->s_id); | ||
773 | goto unaquire_none; | ||
774 | } | ||
775 | befs_sb = BEFS_SB(sb); | ||
776 | memset(befs_sb, 0, sizeof(befs_sb_info)); | ||
777 | |||
778 | if (!parse_options((char *) data, &befs_sb->mount_opts)) { | ||
779 | befs_error(sb, "cannot parse mount options"); | ||
780 | goto unaquire_priv_sbp; | ||
781 | } | ||
782 | |||
783 | befs_debug(sb, "---> befs_fill_super()"); | ||
784 | |||
785 | #ifndef CONFIG_BEFS_RW | ||
786 | if (!(sb->s_flags & MS_RDONLY)) { | ||
787 | befs_warning(sb, | ||
788 | "No write support. Marking filesystem read-only"); | ||
789 | sb->s_flags |= MS_RDONLY; | ||
790 | } | ||
791 | #endif /* CONFIG_BEFS_RW */ | ||
792 | |||
793 | /* | ||
794 | * Set dummy blocksize to read super block. | ||
795 | * Will be set to real fs blocksize later. | ||
796 | * | ||
797 | * Linux 2.4.10 and later refuse to read blocks smaller than | ||
798 | * the hardsect size for the device. But we also need to read at | ||
799 | * least 1k to get the second 512 bytes of the volume. | ||
800 | * -WD 10-26-01 | ||
801 | */ | ||
802 | sb_min_blocksize(sb, 1024); | ||
803 | |||
804 | if (!(bh = sb_bread(sb, sb_block))) { | ||
805 | befs_error(sb, "unable to read superblock"); | ||
806 | goto unaquire_priv_sbp; | ||
807 | } | ||
808 | |||
809 | /* account for offset of super block on x86 */ | ||
810 | disk_sb = (befs_super_block *) bh->b_data; | ||
811 | if ((le32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1) || | ||
812 | (be32_to_cpu(disk_sb->magic1) == BEFS_SUPER_MAGIC1)) { | ||
813 | befs_debug(sb, "Using PPC superblock location"); | ||
814 | } else { | ||
815 | befs_debug(sb, "Using x86 superblock location"); | ||
816 | disk_sb = | ||
817 | (befs_super_block *) ((void *) bh->b_data + x86_sb_off); | ||
818 | } | ||
819 | |||
820 | if (befs_load_sb(sb, disk_sb) != BEFS_OK) | ||
821 | goto unaquire_bh; | ||
822 | |||
823 | befs_dump_super_block(sb, disk_sb); | ||
824 | |||
825 | brelse(bh); | ||
826 | |||
827 | if (befs_check_sb(sb) != BEFS_OK) | ||
828 | goto unaquire_priv_sbp; | ||
829 | |||
830 | if( befs_sb->num_blocks > ~((sector_t)0) ) { | ||
831 | befs_error(sb, "blocks count: %Lu " | ||
832 | "is larger than the host can use", | ||
833 | befs_sb->num_blocks); | ||
834 | goto unaquire_priv_sbp; | ||
835 | } | ||
836 | |||
837 | /* | ||
838 | * set up enough so that it can read an inode | ||
839 | * Fill in kernel superblock fields from private sb | ||
840 | */ | ||
841 | sb->s_magic = BEFS_SUPER_MAGIC; | ||
842 | /* Set real blocksize of fs */ | ||
843 | sb_set_blocksize(sb, (ulong) befs_sb->block_size); | ||
844 | sb->s_op = (struct super_operations *) &befs_sops; | ||
845 | root = iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir))); | ||
846 | sb->s_root = d_alloc_root(root); | ||
847 | if (!sb->s_root) { | ||
848 | iput(root); | ||
849 | befs_error(sb, "get root inode failed"); | ||
850 | goto unaquire_priv_sbp; | ||
851 | } | ||
852 | |||
853 | /* load nls library */ | ||
854 | if (befs_sb->mount_opts.iocharset) { | ||
855 | befs_debug(sb, "Loading nls: %s", | ||
856 | befs_sb->mount_opts.iocharset); | ||
857 | befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset); | ||
858 | if (!befs_sb->nls) { | ||
859 | befs_warning(sb, "Cannot load nls %s" | ||
860 | " loading default nls", | ||
861 | befs_sb->mount_opts.iocharset); | ||
862 | befs_sb->nls = load_nls_default(); | ||
863 | } | ||
864 | /* load default nls if none is specified in mount options */ | ||
865 | } else { | ||
866 | befs_debug(sb, "Loading default nls"); | ||
867 | befs_sb->nls = load_nls_default(); | ||
868 | } | ||
869 | |||
870 | return 0; | ||
871 | /*****************/ | ||
872 | unaquire_bh: | ||
873 | brelse(bh); | ||
874 | |||
875 | unaquire_priv_sbp: | ||
876 | kfree(sb->s_fs_info); | ||
877 | |||
878 | unaquire_none: | ||
879 | sb->s_fs_info = NULL; | ||
880 | return -EINVAL; | ||
881 | } | ||
882 | |||
883 | static int | ||
884 | befs_remount(struct super_block *sb, int *flags, char *data) | ||
885 | { | ||
886 | if (!(*flags & MS_RDONLY)) | ||
887 | return -EINVAL; | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static int | ||
892 | befs_statfs(struct super_block *sb, struct kstatfs *buf) | ||
893 | { | ||
894 | |||
895 | befs_debug(sb, "---> befs_statfs()"); | ||
896 | |||
897 | buf->f_type = BEFS_SUPER_MAGIC; | ||
898 | buf->f_bsize = sb->s_blocksize; | ||
899 | buf->f_blocks = BEFS_SB(sb)->num_blocks; | ||
900 | buf->f_bfree = BEFS_SB(sb)->num_blocks - BEFS_SB(sb)->used_blocks; | ||
901 | buf->f_bavail = buf->f_bfree; | ||
902 | buf->f_files = 0; /* UNKNOWN */ | ||
903 | buf->f_ffree = 0; /* UNKNOWN */ | ||
904 | buf->f_namelen = BEFS_NAME_LEN; | ||
905 | |||
906 | befs_debug(sb, "<--- befs_statfs()"); | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static struct super_block * | ||
912 | befs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, | ||
913 | void *data) | ||
914 | { | ||
915 | return get_sb_bdev(fs_type, flags, dev_name, data, befs_fill_super); | ||
916 | } | ||
917 | |||
918 | static struct file_system_type befs_fs_type = { | ||
919 | .owner = THIS_MODULE, | ||
920 | .name = "befs", | ||
921 | .get_sb = befs_get_sb, | ||
922 | .kill_sb = kill_block_super, | ||
923 | .fs_flags = FS_REQUIRES_DEV, | ||
924 | }; | ||
925 | |||
926 | static int __init | ||
927 | init_befs_fs(void) | ||
928 | { | ||
929 | int err; | ||
930 | |||
931 | printk(KERN_INFO "BeFS version: %s\n", BEFS_VERSION); | ||
932 | |||
933 | err = befs_init_inodecache(); | ||
934 | if (err) | ||
935 | goto unaquire_none; | ||
936 | |||
937 | err = register_filesystem(&befs_fs_type); | ||
938 | if (err) | ||
939 | goto unaquire_inodecache; | ||
940 | |||
941 | return 0; | ||
942 | |||
943 | unaquire_inodecache: | ||
944 | befs_destroy_inodecache(); | ||
945 | |||
946 | unaquire_none: | ||
947 | return err; | ||
948 | } | ||
949 | |||
950 | static void __exit | ||
951 | exit_befs_fs(void) | ||
952 | { | ||
953 | befs_destroy_inodecache(); | ||
954 | |||
955 | unregister_filesystem(&befs_fs_type); | ||
956 | } | ||
957 | |||
958 | /* | ||
959 | Macros that typecheck the init and exit functions, | ||
960 | ensures that they are called at init and cleanup, | ||
961 | and eliminates warnings about unused functions. | ||
962 | */ | ||
963 | module_init(init_befs_fs) | ||
964 | module_exit(exit_befs_fs) | ||
diff --git a/fs/befs/super.c b/fs/befs/super.c new file mode 100644 index 000000000000..4557acbac528 --- /dev/null +++ b/fs/befs/super.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /* | ||
2 | * super.c | ||
3 | * | ||
4 | * Copyright (C) 2001-2002 Will Dyson <will_dyson@pobox.com> | ||
5 | * | ||
6 | * Licensed under the GNU GPL. See the file COPYING for details. | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/fs.h> | ||
11 | |||
12 | #include "befs.h" | ||
13 | #include "super.h" | ||
14 | #include "endian.h" | ||
15 | |||
16 | /** | ||
17 | * load_befs_sb -- Read from disk and properly byteswap all the fields | ||
18 | * of the befs superblock | ||
19 | * | ||
20 | * | ||
21 | * | ||
22 | * | ||
23 | */ | ||
24 | int | ||
25 | befs_load_sb(struct super_block *sb, befs_super_block * disk_sb) | ||
26 | { | ||
27 | befs_sb_info *befs_sb = BEFS_SB(sb); | ||
28 | |||
29 | /* Check the byte order of the filesystem */ | ||
30 | if (le32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE) | ||
31 | befs_sb->byte_order = BEFS_BYTESEX_LE; | ||
32 | else if (be32_to_cpu(disk_sb->fs_byte_order) == BEFS_BYTEORDER_NATIVE) | ||
33 | befs_sb->byte_order = BEFS_BYTESEX_BE; | ||
34 | |||
35 | befs_sb->magic1 = fs32_to_cpu(sb, disk_sb->magic1); | ||
36 | befs_sb->magic2 = fs32_to_cpu(sb, disk_sb->magic2); | ||
37 | befs_sb->magic3 = fs32_to_cpu(sb, disk_sb->magic3); | ||
38 | befs_sb->block_size = fs32_to_cpu(sb, disk_sb->block_size); | ||
39 | befs_sb->block_shift = fs32_to_cpu(sb, disk_sb->block_shift); | ||
40 | befs_sb->num_blocks = fs64_to_cpu(sb, disk_sb->num_blocks); | ||
41 | befs_sb->used_blocks = fs64_to_cpu(sb, disk_sb->used_blocks); | ||
42 | befs_sb->inode_size = fs32_to_cpu(sb, disk_sb->inode_size); | ||
43 | |||
44 | befs_sb->blocks_per_ag = fs32_to_cpu(sb, disk_sb->blocks_per_ag); | ||
45 | befs_sb->ag_shift = fs32_to_cpu(sb, disk_sb->ag_shift); | ||
46 | befs_sb->num_ags = fs32_to_cpu(sb, disk_sb->num_ags); | ||
47 | |||
48 | befs_sb->log_blocks = fsrun_to_cpu(sb, disk_sb->log_blocks); | ||
49 | befs_sb->log_start = fs64_to_cpu(sb, disk_sb->log_start); | ||
50 | befs_sb->log_end = fs64_to_cpu(sb, disk_sb->log_end); | ||
51 | |||
52 | befs_sb->root_dir = fsrun_to_cpu(sb, disk_sb->root_dir); | ||
53 | befs_sb->indices = fsrun_to_cpu(sb, disk_sb->indices); | ||
54 | befs_sb->nls = NULL; | ||
55 | |||
56 | return BEFS_OK; | ||
57 | } | ||
58 | |||
59 | int | ||
60 | befs_check_sb(struct super_block *sb) | ||
61 | { | ||
62 | befs_sb_info *befs_sb = BEFS_SB(sb); | ||
63 | |||
64 | /* Check magic headers of super block */ | ||
65 | if ((befs_sb->magic1 != BEFS_SUPER_MAGIC1) | ||
66 | || (befs_sb->magic2 != BEFS_SUPER_MAGIC2) | ||
67 | || (befs_sb->magic3 != BEFS_SUPER_MAGIC3)) { | ||
68 | befs_error(sb, "invalid magic header"); | ||
69 | return BEFS_ERR; | ||
70 | } | ||
71 | |||
72 | /* | ||
73 | * Check blocksize of BEFS. | ||
74 | * | ||
75 | * Blocksize of BEFS is 1024, 2048, 4096 or 8192. | ||
76 | */ | ||
77 | |||
78 | if ((befs_sb->block_size != 1024) | ||
79 | && (befs_sb->block_size != 2048) | ||
80 | && (befs_sb->block_size != 4096) | ||
81 | && (befs_sb->block_size != 8192)) { | ||
82 | befs_error(sb, "invalid blocksize: %u", befs_sb->block_size); | ||
83 | return BEFS_ERR; | ||
84 | } | ||
85 | |||
86 | if (befs_sb->block_size > PAGE_SIZE) { | ||
87 | befs_error(sb, "blocksize(%u) cannot be larger" | ||
88 | "than system pagesize(%lu)", befs_sb->block_size, | ||
89 | PAGE_SIZE); | ||
90 | return BEFS_ERR; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * block_shift and block_size encode the same information | ||
95 | * in different ways as a consistency check. | ||
96 | */ | ||
97 | |||
98 | if ((1 << befs_sb->block_shift) != befs_sb->block_size) { | ||
99 | befs_error(sb, "block_shift disagrees with block_size. " | ||
100 | "Corruption likely."); | ||
101 | return BEFS_ERR; | ||
102 | } | ||
103 | |||
104 | if (befs_sb->log_start != befs_sb->log_end) { | ||
105 | befs_error(sb, "Filesystem not clean! There are blocks in the " | ||
106 | "journal. You must boot into BeOS and mount this volume " | ||
107 | "to make it clean."); | ||
108 | return BEFS_ERR; | ||
109 | } | ||
110 | |||
111 | return BEFS_OK; | ||
112 | } | ||
diff --git a/fs/befs/super.h b/fs/befs/super.h new file mode 100644 index 000000000000..dc4556376a22 --- /dev/null +++ b/fs/befs/super.h | |||
@@ -0,0 +1,8 @@ | |||
1 | /* | ||
2 | * super.h | ||
3 | */ | ||
4 | |||
5 | int befs_load_sb(struct super_block *sb, befs_super_block * disk_sb); | ||
6 | |||
7 | int befs_check_sb(struct super_block *sb); | ||
8 | |||