diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/befs/linuxvfs.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/befs/linuxvfs.c')
-rw-r--r-- | fs/befs/linuxvfs.c | 964 |
1 files changed, 964 insertions, 0 deletions
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) | ||