Blame view

fs/befs/linuxvfs.c 24.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  /*
   * linux/fs/befs/linuxvfs.c
   *
   * Copyright (C) 2001 Will Dyson <will_dyson@pobox.com
   *
   */
  
  #include <linux/module.h>
  #include <linux/slab.h>
  #include <linux/fs.h>
  #include <linux/errno.h>
  #include <linux/stat.h>
  #include <linux/nls.h>
  #include <linux/buffer_head.h>
  #include <linux/vfs.h>
  #include <linux/parser.h>
  #include <linux/namei.h>
  
  #include "befs.h"
  #include "btree.h"
  #include "inode.h"
  #include "datastream.h"
  #include "super.h"
  #include "io.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
29
30
31
32
33
34
35
36
37
  
  MODULE_DESCRIPTION("BeOS File System (BeFS) driver");
  MODULE_AUTHOR("Will Dyson");
  MODULE_LICENSE("GPL");
  
  /* The units the vfs expects inode->i_blocks to be in */
  #define VFS_BLOCK_SIZE 512
  
  static int befs_readdir(struct file *, void *, filldir_t);
  static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
  static int befs_readpage(struct file *file, struct page *page);
  static sector_t befs_bmap(struct address_space *mapping, sector_t block);
  static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
96eb54194   David Howells   iget: stop BEFS f...
38
  static struct inode *befs_iget(struct super_block *, unsigned long);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
  static struct inode *befs_alloc_inode(struct super_block *sb);
  static void befs_destroy_inode(struct inode *inode);
  static int befs_init_inodecache(void);
  static void befs_destroy_inodecache(void);
008b150a3   Al Viro   [PATCH] Fix up sy...
43
44
  static void *befs_follow_link(struct dentry *, struct nameidata *);
  static void befs_put_link(struct dentry *, struct nameidata *, void *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
46
47
48
49
50
  static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
  			char **out, int *out_len);
  static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
  			char **out, int *out_len);
  static void befs_put_super(struct super_block *);
  static int befs_remount(struct super_block *, int *, char *);
726c33422   David Howells   [PATCH] VFS: Perm...
51
  static int befs_statfs(struct dentry *, struct kstatfs *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
  static int parse_options(char *, befs_mount_options *);
  
  static const struct super_operations befs_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
  	.alloc_inode	= befs_alloc_inode,	/* allocate a new inode */
  	.destroy_inode	= befs_destroy_inode, /* deallocate an inode */
  	.put_super	= befs_put_super,	/* uninit super */
  	.statfs		= befs_statfs,	/* statfs */
  	.remount_fs	= befs_remount,
552c3c6c5   Miklos Szeredi   mount options: fi...
60
  	.show_options	= generic_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
63
  };
  
  /* slab cache for befs_inode_info objects */
e18b890bb   Christoph Lameter   [PATCH] slab: rem...
64
  static struct kmem_cache *befs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
65

4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
66
  static const struct file_operations befs_dir_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
  	.read		= generic_read_dir,
  	.readdir	= befs_readdir,
59af1584b   Al Viro   [PATCH] fix ->lls...
69
  	.llseek		= generic_file_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  };
754661f14   Arjan van de Ven   [PATCH] mark stru...
71
  static const struct inode_operations befs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	.lookup		= befs_lookup,
  };
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
74
  static const struct address_space_operations befs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  	.readpage	= befs_readpage,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
  	.bmap		= befs_bmap,
  };
754661f14   Arjan van de Ven   [PATCH] mark stru...
78
  static const struct inode_operations befs_symlink_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  	.readlink	= generic_readlink,
  	.follow_link	= befs_follow_link,
  	.put_link	= befs_put_link,
  };
  
  /* 
   * Called by generic_file_read() to read a page of data
   * 
   * In turn, simply calls a generic block read function and
   * passes it the address of befs_get_block, for mapping file
   * positions to disk blocks.
   */
  static int
  befs_readpage(struct file *file, struct page *page)
  {
  	return block_read_full_page(page, befs_get_block);
  }
  
  static sector_t
  befs_bmap(struct address_space *mapping, sector_t block)
  {
  	return generic_block_bmap(mapping, block, befs_get_block);
  }
  
  /* 
   * Generic function to map a file position (block) to a 
   * disk offset (passed back in bh_result).
   *
   * Used by many higher level functions.
   *
   * Calls befs_fblock2brun() in datastream.c to do the real work.
   *
   * -WD 10-26-01
   */
  
  static int
  befs_get_block(struct inode *inode, sector_t block,
  	       struct buffer_head *bh_result, int create)
  {
  	struct super_block *sb = inode->i_sb;
  	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
  	befs_block_run run = BAD_IADDR;
  	int res = 0;
  	ulong disk_off;
  
  	befs_debug(sb, "---> befs_get_block() for inode %lu, block %ld",
  		   inode->i_ino, block);
  
  	if (block < 0) {
  		befs_error(sb, "befs_get_block() was asked for a block "
  			   "number less than zero: block %ld in inode %lu",
  			   block, inode->i_ino);
  		return -EIO;
  	}
  
  	if (create) {
  		befs_error(sb, "befs_get_block() was asked to write to "
  			   "block %ld in inode %lu", block, inode->i_ino);
  		return -EPERM;
  	}
  
  	res = befs_fblock2brun(sb, ds, block, &run);
  	if (res != BEFS_OK) {
  		befs_error(sb,
  			   "<--- befs_get_block() for inode %lu, block "
  			   "%ld ERROR", inode->i_ino, block);
  		return -EFBIG;
  	}
  
  	disk_off = (ulong) iaddr2blockno(sb, &run);
  
  	map_bh(bh_result, inode->i_sb, disk_off);
  
  	befs_debug(sb, "<--- befs_get_block() for inode %lu, block %ld, "
  		   "disk address %lu", inode->i_ino, block, disk_off);
  
  	return 0;
  }
  
  static struct dentry *
  befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
  {
  	struct inode *inode = NULL;
  	struct super_block *sb = dir->i_sb;
  	befs_data_stream *ds = &BEFS_I(dir)->i_data.ds;
  	befs_off_t offset;
  	int ret;
  	int utfnamelen;
  	char *utfname;
  	const char *name = dentry->d_name.name;
  
  	befs_debug(sb, "---> befs_lookup() "
  		   "name %s inode %ld", dentry->d_name.name, dir->i_ino);
  
  	/* Convert to UTF-8 */
  	if (BEFS_SB(sb)->nls) {
  		ret =
  		    befs_nls2utf(sb, name, strlen(name), &utfname, &utfnamelen);
  		if (ret < 0) {
  			befs_debug(sb, "<--- befs_lookup() ERROR");
  			return ERR_PTR(ret);
  		}
  		ret = befs_btree_find(sb, ds, utfname, &offset);
  		kfree(utfname);
  
  	} else {
  		ret = befs_btree_find(sb, ds, dentry->d_name.name, &offset);
  	}
  
  	if (ret == BEFS_BT_NOT_FOUND) {
  		befs_debug(sb, "<--- befs_lookup() %s not found",
  			   dentry->d_name.name);
  		return ERR_PTR(-ENOENT);
  
  	} else if (ret != BEFS_OK || offset == 0) {
  		befs_warning(sb, "<--- befs_lookup() Error");
  		return ERR_PTR(-ENODATA);
  	}
96eb54194   David Howells   iget: stop BEFS f...
197
198
199
  	inode = befs_iget(dir->i_sb, (ino_t) offset);
  	if (IS_ERR(inode))
  		return ERR_CAST(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
208
209
210
  
  	d_add(dentry, inode);
  
  	befs_debug(sb, "<--- befs_lookup()");
  
  	return NULL;
  }
  
  static int
  befs_readdir(struct file *filp, void *dirent, filldir_t filldir)
  {
28f375fd6   Josef Sipek   [PATCH] struct pa...
211
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
  	struct super_block *sb = inode->i_sb;
  	befs_data_stream *ds = &BEFS_I(inode)->i_data.ds;
  	befs_off_t value;
  	int result;
  	size_t keysize;
  	unsigned char d_type;
  	char keybuf[BEFS_NAME_LEN + 1];
  	char *nlsname;
  	int nlsnamelen;
28f375fd6   Josef Sipek   [PATCH] struct pa...
221
  	const char *dirname = filp->f_path.dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
  
  	befs_debug(sb, "---> befs_readdir() "
  		   "name %s, inode %ld, filp->f_pos %Ld",
  		   dirname, inode->i_ino, filp->f_pos);
  
  	result = befs_btree_read(sb, ds, filp->f_pos, BEFS_NAME_LEN + 1,
  				 keybuf, &keysize, &value);
  
  	if (result == BEFS_ERR) {
  		befs_debug(sb, "<--- befs_readdir() ERROR");
  		befs_error(sb, "IO error reading %s (inode %lu)",
  			   dirname, inode->i_ino);
  		return -EIO;
  
  	} else if (result == BEFS_BT_END) {
  		befs_debug(sb, "<--- befs_readdir() END");
  		return 0;
  
  	} else if (result == BEFS_BT_EMPTY) {
  		befs_debug(sb, "<--- befs_readdir() Empty directory");
  		return 0;
  	}
  
  	d_type = DT_UNKNOWN;
  
  	/* Convert to NLS */
  	if (BEFS_SB(sb)->nls) {
  		result =
  		    befs_utf2nls(sb, keybuf, keysize, &nlsname, &nlsnamelen);
  		if (result < 0) {
  			befs_debug(sb, "<--- befs_readdir() ERROR");
  			return result;
  		}
  		result = filldir(dirent, nlsname, nlsnamelen, filp->f_pos,
  				 (ino_t) value, d_type);
  		kfree(nlsname);
  
  	} else {
  		result = filldir(dirent, keybuf, keysize, filp->f_pos,
  				 (ino_t) value, d_type);
  	}
  
  	filp->f_pos++;
  
  	befs_debug(sb, "<--- befs_readdir() filp->f_pos %Ld", filp->f_pos);
  
  	return 0;
  }
  
  static struct inode *
  befs_alloc_inode(struct super_block *sb)
  {
          struct befs_inode_info *bi;
          bi = (struct befs_inode_info *)kmem_cache_alloc(befs_inode_cachep,
e94b17660   Christoph Lameter   [PATCH] slab: rem...
276
  							GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
          if (!bi)
                  return NULL;
          return &bi->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
281
  static void befs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
283
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
          kmem_cache_free(befs_inode_cachep, BEFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
286
287
288
289
  static void befs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, befs_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
290
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
  {
          struct befs_inode_info *bi = (struct befs_inode_info *) foo;
a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
293
294
  
  	inode_init_once(&bi->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
295
  }
96eb54194   David Howells   iget: stop BEFS f...
296
  static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
  {
  	struct buffer_head *bh = NULL;
  	befs_inode *raw_inode = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  	befs_sb_info *befs_sb = BEFS_SB(sb);
  	befs_inode_info *befs_ino = NULL;
96eb54194   David Howells   iget: stop BEFS f...
302
303
  	struct inode *inode;
  	long ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304

96eb54194   David Howells   iget: stop BEFS f...
305
306
307
308
309
310
311
  	befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino);
  
  	inode = iget_locked(sb, ino);
  	if (IS_ERR(inode))
  		return inode;
  	if (!(inode->i_state & I_NEW))
  		return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
313
314
315
316
317
318
319
320
321
322
323
324
325
  
  	befs_ino = BEFS_I(inode);
  
  	/* convert from vfs's inode number to befs's inode number */
  	befs_ino->i_inode_num = blockno2iaddr(sb, inode->i_ino);
  
  	befs_debug(sb, "  real inode number [%u, %hu, %hu]",
  		   befs_ino->i_inode_num.allocation_group,
  		   befs_ino->i_inode_num.start, befs_ino->i_inode_num.len);
  
  	bh = befs_bread(sb, inode->i_ino);
  	if (!bh) {
  		befs_error(sb, "unable to read inode block - "
  			   "inode = %lu", inode->i_ino);
0418726bb   Adrian Bunk   typo fixes: aquir...
326
  		goto unacquire_none;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
327
328
329
330
331
332
333
334
  	}
  
  	raw_inode = (befs_inode *) bh->b_data;
  
  	befs_dump_inode(sb, raw_inode);
  
  	if (befs_check_inode(sb, raw_inode, inode->i_ino) != BEFS_OK) {
  		befs_error(sb, "Bad inode: %lu", inode->i_ino);
0418726bb   Adrian Bunk   typo fixes: aquir...
335
  		goto unacquire_bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
338
339
340
341
342
343
344
345
346
347
348
  	}
  
  	inode->i_mode = (umode_t) fs32_to_cpu(sb, raw_inode->mode);
  
  	/*
  	 * set uid and gid.  But since current BeOS is single user OS, so
  	 * you can change by "uid" or "gid" options.
  	 */   
  
  	inode->i_uid = befs_sb->mount_opts.use_uid ?
  	    befs_sb->mount_opts.uid : (uid_t) fs32_to_cpu(sb, raw_inode->uid);
  	inode->i_gid = befs_sb->mount_opts.use_gid ?
  	    befs_sb->mount_opts.gid : (gid_t) fs32_to_cpu(sb, raw_inode->gid);
bfe868486   Miklos Szeredi   filesystems: add ...
349
  	set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  
  	/*
  	 * BEFS's time is 64 bits, but current VFS is 32 bits...
  	 * BEFS don't have access time. Nor inode change time. VFS
  	 * doesn't have creation time.
  	 * Also, the lower 16 bits of the last_modified_time and 
  	 * create_time are just a counter to help ensure uniqueness
  	 * for indexing purposes. (PFD, page 54)
  	 */
  
  	inode->i_mtime.tv_sec =
  	    fs64_to_cpu(sb, raw_inode->last_modified_time) >> 16;
  	inode->i_mtime.tv_nsec = 0;   /* lower 16 bits are not a time */	
  	inode->i_ctime = inode->i_mtime;
  	inode->i_atime = inode->i_mtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
372
373
374
  
  	befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
  	befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent);
  	befs_ino->i_attribute = fsrun_to_cpu(sb, raw_inode->attributes);
  	befs_ino->i_flags = fs32_to_cpu(sb, raw_inode->flags);
  
  	if (S_ISLNK(inode->i_mode) && !(befs_ino->i_flags & BEFS_LONG_SYMLINK)){
  		inode->i_size = 0;
  		inode->i_blocks = befs_sb->block_size / VFS_BLOCK_SIZE;
  		strncpy(befs_ino->i_data.symlink, raw_inode->data.symlink,
7df5fa06d   Duane Griffin   befs: ensure fast...
375
376
  			BEFS_SYMLINK_LEN - 1);
  		befs_ino->i_data.symlink[BEFS_SYMLINK_LEN - 1] = '\0';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
377
378
379
380
  	} else {
  		int num_blks;
  
  		befs_ino->i_data.ds =
e0e3d32bb   Jesper Juhl   befs: don't pass ...
381
  		    fsds_to_cpu(sb, &raw_inode->data.datastream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
386
387
388
389
390
391
  
  		num_blks = befs_count_blocks(sb, &befs_ino->i_data.ds);
  		inode->i_blocks =
  		    num_blks * (befs_sb->block_size / VFS_BLOCK_SIZE);
  		inode->i_size = befs_ino->i_data.ds.size;
  	}
  
  	inode->i_mapping->a_ops = &befs_aops;
  
  	if (S_ISREG(inode->i_mode)) {
2cf069162   Christoph Hellwig   [PATCH] befs: use...
392
  		inode->i_fop = &generic_ro_fops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393
394
395
396
397
398
399
400
401
  	} else if (S_ISDIR(inode->i_mode)) {
  		inode->i_op = &befs_dir_inode_operations;
  		inode->i_fop = &befs_dir_operations;
  	} else if (S_ISLNK(inode->i_mode)) {
  		inode->i_op = &befs_symlink_inode_operations;
  	} else {
  		befs_error(sb, "Inode %lu is not a regular file, "
  			   "directory or symlink. THAT IS WRONG! BeFS has no "
  			   "on disk special files", inode->i_ino);
0418726bb   Adrian Bunk   typo fixes: aquir...
402
  		goto unacquire_bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
404
405
406
  	}
  
  	brelse(bh);
  	befs_debug(sb, "<--- befs_read_inode()");
96eb54194   David Howells   iget: stop BEFS f...
407
408
  	unlock_new_inode(inode);
  	return inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
409

0418726bb   Adrian Bunk   typo fixes: aquir...
410
        unacquire_bh:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	brelse(bh);
0418726bb   Adrian Bunk   typo fixes: aquir...
412
        unacquire_none:
96eb54194   David Howells   iget: stop BEFS f...
413
  	iget_failed(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
  	befs_debug(sb, "<--- befs_read_inode() - Bad inode");
96eb54194   David Howells   iget: stop BEFS f...
415
  	return ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
  }
  
  /* Initialize the inode cache. Called at fs setup.
20c2df83d   Paul Mundt   mm: Remove slab d...
419
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
426
   * Taken from NFS implementation by Al Viro.
   */
  static int
  befs_init_inodecache(void)
  {
  	befs_inode_cachep = kmem_cache_create("befs_inode_cache",
  					      sizeof (struct befs_inode_info),
fffb60f93   Paul Jackson   [PATCH] cpuset me...
427
428
  					      0, (SLAB_RECLAIM_ACCOUNT|
  						SLAB_MEM_SPREAD),
20c2df83d   Paul Mundt   mm: Remove slab d...
429
  					      init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
431
  	if (befs_inode_cachep == NULL) {
  		printk(KERN_ERR "befs_init_inodecache: "
421f91d21   Uwe Kleine-König   fix typos concern...
432
433
  		       "Couldn't initialize inode slabcache
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
440
441
442
443
444
445
446
  		return -ENOMEM;
  	}
  
  	return 0;
  }
  
  /* Called at fs teardown.
   * 
   * Taken from NFS implementation by Al Viro.
   */
  static void
  befs_destroy_inodecache(void)
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
447
  	kmem_cache_destroy(befs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
449
450
451
452
453
454
  }
  
  /*
   * The inode of symbolic link is different to data stream.
   * The data stream become link name. Unless the LONG_SYMLINK
   * flag is set.
   */
db873896d   Linus Torvalds   befs: fix up miss...
455
  static void *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
456
457
458
459
460
461
462
463
464
  befs_follow_link(struct dentry *dentry, struct nameidata *nd)
  {
  	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
  	char *link;
  
  	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
  		struct super_block *sb = dentry->d_sb;
  		befs_data_stream *data = &befs_ino->i_data.ds;
  		befs_off_t len = data->size;
338d0f0a6   Timo Warns   befs: Validate le...
465
466
  		if (len == 0) {
  			befs_error(sb, "Long symlink with illegal length");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
  			link = ERR_PTR(-EIO);
7df5fa06d   Duane Griffin   befs: ensure fast...
468
  		} else {
338d0f0a6   Timo Warns   befs: Validate le...
469
470
471
472
473
474
475
476
477
478
479
480
  			befs_debug(sb, "Follow long symlink");
  
  			link = kmalloc(len, GFP_NOFS);
  			if (!link) {
  				link = ERR_PTR(-ENOMEM);
  			} else if (befs_read_lsymlink(sb, data, link, len) != len) {
  				kfree(link);
  				befs_error(sb, "Failed to read entire long symlink");
  				link = ERR_PTR(-EIO);
  			} else {
  				link[len - 1] = '\0';
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
  		}
  	} else {
  		link = befs_ino->i_data.symlink;
  	}
  
  	nd_set_link(nd, link);
008b150a3   Al Viro   [PATCH] Fix up sy...
487
  	return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  }
008b150a3   Al Viro   [PATCH] Fix up sy...
489
  static void befs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
490
491
492
  {
  	befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
  	if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
63e3453e5   Harvey Harrison   befs: fix sparse ...
493
494
495
  		char *link = nd_get_link(nd);
  		if (!IS_ERR(link))
  			kfree(link);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
  	}
  }
  
  /*
   * UTF-8 to NLS charset  convert routine
   * 
   *
   * Changed 8/10/01 by Will Dyson. Now use uni2char() / char2uni() rather than
   * the nls tables directly
   */
  
  static int
  befs_utf2nls(struct super_block *sb, const char *in,
  	     int in_len, char **out, int *out_len)
  {
  	struct nls_table *nls = BEFS_SB(sb)->nls;
  	int i, o;
74675a585   Alan Stern   NLS: update handl...
513
  	unicode_t uni;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
  	int unilen, utflen;
  	char *result;
94f563c42   Diego Calleja   [PATCH] Fix BeFS ...
516
517
518
519
520
  	/* The utf8->nls conversion won't make the final nls string bigger
  	 * than the utf one, but if the string is pure ascii they'll have the
  	 * same width and an extra char is needed to save the additional \0
  	 */
  	int maxlen = in_len + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  
  	befs_debug(sb, "---> utf2nls()");
  
  	if (!nls) {
  		befs_error(sb, "befs_utf2nls called with no NLS table loaded");
  		return -EINVAL;
  	}
  
  	*out = result = kmalloc(maxlen, GFP_NOFS);
  	if (!*out) {
  		befs_error(sb, "befs_utf2nls() cannot allocate memory");
  		*out_len = 0;
  		return -ENOMEM;
  	}
  
  	for (i = o = 0; i < in_len; i += utflen, o += unilen) {
  
  		/* convert from UTF-8 to Unicode */
74675a585   Alan Stern   NLS: update handl...
539
540
  		utflen = utf8_to_utf32(&in[i], in_len - i, &uni);
  		if (utflen < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  			goto conv_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  
  		/* convert from Unicode to nls */
74675a585   Alan Stern   NLS: update handl...
544
545
  		if (uni > MAX_WCHAR_T)
  			goto conv_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  		unilen = nls->uni2char(uni, &result[o], in_len - o);
74675a585   Alan Stern   NLS: update handl...
547
  		if (unilen < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  			goto conv_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  	}
  	result[o] = '\0';
  	*out_len = o;
  
  	befs_debug(sb, "<--- utf2nls()");
  
  	return o;
  
        conv_err:
  	befs_error(sb, "Name using character set %s contains a character that "
  		   "cannot be converted to unicode.", nls->charset);
  	befs_debug(sb, "<--- utf2nls()");
  	kfree(result);
  	return -EILSEQ;
  }
  
  /**
   * befs_nls2utf - Convert NLS string to utf8 encodeing
   * @sb: Superblock
   * @src: Input string buffer in NLS format
   * @srclen: Length of input string in bytes
4de151d8c   Alexey Dobriyan   It's UTF-8
570
   * @dest: The output string in UTF-8 format
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
   * @destlen: Length of the output buffer
   * 
   * Converts input string @src, which is in the format of the loaded NLS map,
   * into a utf8 string.
   * 
   * The destination string @dest is allocated by this function and the caller is
   * responsible for freeing it with kfree()
   * 
   * On return, *@destlen is the length of @dest in bytes.
   *
   * On success, the return value is the number of utf8 characters written to
   * the output buffer @dest.
   *  
   * On Failure, a negative number coresponding to the error code is returned.
   */
  
  static int
  befs_nls2utf(struct super_block *sb, const char *in,
  	     int in_len, char **out, int *out_len)
  {
  	struct nls_table *nls = BEFS_SB(sb)->nls;
  	int i, o;
  	wchar_t uni;
  	int unilen, utflen;
  	char *result;
94f563c42   Diego Calleja   [PATCH] Fix BeFS ...
596
597
598
599
  	/* There're nls characters that will translate to 3-chars-wide UTF-8
  	 * characters, a additional byte is needed to save the final \0
  	 * in special cases */
  	int maxlen = (3 * in_len) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
  
  	befs_debug(sb, "---> nls2utf()
  ");
  
  	if (!nls) {
  		befs_error(sb, "befs_nls2utf called with no NLS table loaded.");
  		return -EINVAL;
  	}
  
  	*out = result = kmalloc(maxlen, GFP_NOFS);
  	if (!*out) {
  		befs_error(sb, "befs_nls2utf() cannot allocate memory");
  		*out_len = 0;
  		return -ENOMEM;
  	}
  
  	for (i = o = 0; i < in_len; i += unilen, o += utflen) {
  
  		/* convert from nls to unicode */
  		unilen = nls->char2uni(&in[i], in_len - i, &uni);
74675a585   Alan Stern   NLS: update handl...
620
  		if (unilen < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
  			goto conv_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
622
623
  
  		/* convert from unicode to UTF-8 */
74675a585   Alan Stern   NLS: update handl...
624
625
  		utflen = utf32_to_utf8(uni, &result[o], 3);
  		if (utflen <= 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  			goto conv_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
  	}
  
  	result[o] = '\0';
  	*out_len = o;
  
  	befs_debug(sb, "<--- nls2utf()");
  
  	return i;
  
        conv_err:
  	befs_error(sb, "Name using charecter set %s contains a charecter that "
  		   "cannot be converted to unicode.", nls->charset);
  	befs_debug(sb, "<--- nls2utf()");
  	kfree(result);
  	return -EILSEQ;
  }
  
  /**
   * Use the
   *
   */
  enum {
  	Opt_uid, Opt_gid, Opt_charset, Opt_debug, Opt_err,
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
651
  static const match_table_t befs_tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  	{Opt_uid, "uid=%d"},
  	{Opt_gid, "gid=%d"},
  	{Opt_charset, "iocharset=%s"},
  	{Opt_debug, "debug"},
  	{Opt_err, NULL}
  };
  
  static int
  parse_options(char *options, befs_mount_options * opts)
  {
  	char *p;
  	substring_t args[MAX_OPT_ARGS];
  	int option;
  
  	/* Initialize options */
  	opts->uid = 0;
  	opts->gid = 0;
  	opts->use_uid = 0;
  	opts->use_gid = 0;
  	opts->iocharset = NULL;
  	opts->debug = 0;
  
  	if (!options)
  		return 1;
  
  	while ((p = strsep(&options, ",")) != NULL) {
  		int token;
  		if (!*p)
  			continue;
  
  		token = match_token(p, befs_tokens, args);
  		switch (token) {
  		case Opt_uid:
  			if (match_int(&args[0], &option))
  				return 0;
  			if (option < 0) {
  				printk(KERN_ERR "BeFS: Invalid uid %d, "
  						"using default
  ", option);
  				break;
  			}
  			opts->uid = option;
  			opts->use_uid = 1;
  			break;
  		case Opt_gid:
  			if (match_int(&args[0], &option))
  				return 0;
  			if (option < 0) {
  				printk(KERN_ERR "BeFS: Invalid gid %d, "
  						"using default
  ", option);
  				break;
  			}
  			opts->gid = option;
  			opts->use_gid = 1;
  			break;
  		case Opt_charset:
  			kfree(opts->iocharset);
  			opts->iocharset = match_strdup(&args[0]);
  			if (!opts->iocharset) {
  				printk(KERN_ERR "BeFS: allocation failure for "
  						"iocharset string
  ");
  				return 0;
  			}
  			break;
  		case Opt_debug:
  			opts->debug = 1;
  			break;
  		default:
  			printk(KERN_ERR "BeFS: Unrecognized mount option \"%s\" "
  					"or missing value
  ", p);
  			return 0;
  		}
  	}
  	return 1;
  }
  
  /* This function has the responsibiltiy of getting the
   * filesystem ready for unmounting. 
25985edce   Lucas De Marchi   Fix common misspe...
733
   * Basically, we free everything that we allocated in
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
   * befs_read_inode
   */
  static void
  befs_put_super(struct super_block *sb)
  {
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
739
740
  	kfree(BEFS_SB(sb)->mount_opts.iocharset);
  	BEFS_SB(sb)->mount_opts.iocharset = NULL;
6d729e44a   Thomas Gleixner   fs: Make unload_n...
741
  	unload_nls(BEFS_SB(sb)->nls);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
742
743
  	kfree(sb->s_fs_info);
  	sb->s_fs_info = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
  }
  
  /* Allocate private field of the superblock, fill it.
   *
   * Finish filling the public superblock fields
   * Make the root directory
   * Load a set of NLS translations if needed.
   */
  static int
  befs_fill_super(struct super_block *sb, void *data, int silent)
  {
  	struct buffer_head *bh;
  	befs_sb_info *befs_sb;
  	befs_super_block *disk_sb;
  	struct inode *root;
96eb54194   David Howells   iget: stop BEFS f...
759
  	long ret = -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
761
  	const unsigned long sb_block = 0;
  	const off_t x86_sb_off = 512;
552c3c6c5   Miklos Szeredi   mount options: fi...
762
  	save_mount_options(sb, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
765
766
767
768
  	sb->s_fs_info = kmalloc(sizeof (*befs_sb), GFP_KERNEL);
  	if (sb->s_fs_info == NULL) {
  		printk(KERN_ERR
  		       "BeFS(%s): Unable to allocate memory for private "
  		       "portion of superblock. Bailing.
  ", sb->s_id);
0418726bb   Adrian Bunk   typo fixes: aquir...
769
  		goto unacquire_none;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
772
773
774
775
  	}
  	befs_sb = BEFS_SB(sb);
  	memset(befs_sb, 0, sizeof(befs_sb_info));
  
  	if (!parse_options((char *) data, &befs_sb->mount_opts)) {
  		befs_error(sb, "cannot parse mount options");
0418726bb   Adrian Bunk   typo fixes: aquir...
776
  		goto unacquire_priv_sbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
  	}
  
  	befs_debug(sb, "---> befs_fill_super()");
  
  #ifndef CONFIG_BEFS_RW
  	if (!(sb->s_flags & MS_RDONLY)) {
  		befs_warning(sb,
  			     "No write support. Marking filesystem read-only");
  		sb->s_flags |= MS_RDONLY;
  	}
  #endif				/* CONFIG_BEFS_RW */
  
  	/*
  	 * Set dummy blocksize to read super block.
  	 * Will be set to real fs blocksize later.
  	 *
  	 * Linux 2.4.10 and later refuse to read blocks smaller than
  	 * the hardsect size for the device. But we also need to read at 
  	 * least 1k to get the second 512 bytes of the volume.
  	 * -WD 10-26-01
  	 */ 
  	sb_min_blocksize(sb, 1024);
  
  	if (!(bh = sb_bread(sb, sb_block))) {
  		befs_error(sb, "unable to read superblock");
0418726bb   Adrian Bunk   typo fixes: aquir...
802
  		goto unacquire_priv_sbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
803
804
805
806
  	}
  
  	/* account for offset of super block on x86 */
  	disk_sb = (befs_super_block *) bh->b_data;
152b95a1e   Harvey Harrison   befs: annotate fs...
807
808
  	if ((disk_sb->magic1 == BEFS_SUPER_MAGIC1_LE) ||
  	    (disk_sb->magic1 == BEFS_SUPER_MAGIC1_BE)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
809
810
811
812
813
814
815
816
  		befs_debug(sb, "Using PPC superblock location");
  	} else {
  		befs_debug(sb, "Using x86 superblock location");
  		disk_sb =
  		    (befs_super_block *) ((void *) bh->b_data + x86_sb_off);
  	}
  
  	if (befs_load_sb(sb, disk_sb) != BEFS_OK)
0418726bb   Adrian Bunk   typo fixes: aquir...
817
  		goto unacquire_bh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
822
823
  
  	befs_dump_super_block(sb, disk_sb);
  
  	brelse(bh);
  
  	if (befs_check_sb(sb) != BEFS_OK)
0418726bb   Adrian Bunk   typo fixes: aquir...
824
  		goto unacquire_priv_sbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
827
828
829
  
  	if( befs_sb->num_blocks > ~((sector_t)0) ) {
  		befs_error(sb, "blocks count: %Lu "
  			"is larger than the host can use",
  			befs_sb->num_blocks);
0418726bb   Adrian Bunk   typo fixes: aquir...
830
  		goto unacquire_priv_sbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
833
834
835
836
837
838
839
  	}
  
  	/*
  	 * set up enough so that it can read an inode
  	 * Fill in kernel superblock fields from private sb
  	 */
  	sb->s_magic = BEFS_SUPER_MAGIC;
  	/* Set real blocksize of fs */
  	sb_set_blocksize(sb, (ulong) befs_sb->block_size);
b87221de6   Alexey Dobriyan   const: mark remai...
840
  	sb->s_op = &befs_sops;
96eb54194   David Howells   iget: stop BEFS f...
841
842
843
844
845
  	root = befs_iget(sb, iaddr2blockno(sb, &(befs_sb->root_dir)));
  	if (IS_ERR(root)) {
  		ret = PTR_ERR(root);
  		goto unacquire_priv_sbp;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
846
847
848
849
  	sb->s_root = d_alloc_root(root);
  	if (!sb->s_root) {
  		iput(root);
  		befs_error(sb, "get root inode failed");
0418726bb   Adrian Bunk   typo fixes: aquir...
850
  		goto unacquire_priv_sbp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
  	}
  
  	/* load nls library */
  	if (befs_sb->mount_opts.iocharset) {
  		befs_debug(sb, "Loading nls: %s",
  			   befs_sb->mount_opts.iocharset);
  		befs_sb->nls = load_nls(befs_sb->mount_opts.iocharset);
  		if (!befs_sb->nls) {
  			befs_warning(sb, "Cannot load nls %s"
  					" loading default nls",
  					befs_sb->mount_opts.iocharset);
  			befs_sb->nls = load_nls_default();
  		}
  	/* load default nls if none is specified  in mount options */
  	} else {
  		befs_debug(sb, "Loading default nls");
  		befs_sb->nls = load_nls_default();
  	}
  
  	return 0;
  /*****************/
0418726bb   Adrian Bunk   typo fixes: aquir...
872
        unacquire_bh:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
  	brelse(bh);
0418726bb   Adrian Bunk   typo fixes: aquir...
874
        unacquire_priv_sbp:
8dd5ca532   Al Viro   befs: fix leak
875
  	kfree(befs_sb->mount_opts.iocharset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
  	kfree(sb->s_fs_info);
0418726bb   Adrian Bunk   typo fixes: aquir...
877
        unacquire_none:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
878
  	sb->s_fs_info = NULL;
96eb54194   David Howells   iget: stop BEFS f...
879
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
880
881
882
883
884
885
886
887
888
889
890
  }
  
  static int
  befs_remount(struct super_block *sb, int *flags, char *data)
  {
  	if (!(*flags & MS_RDONLY))
  		return -EINVAL;
  	return 0;
  }
  
  static int
726c33422   David Howells   [PATCH] VFS: Perm...
891
  befs_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
892
  {
726c33422   David Howells   [PATCH] VFS: Perm...
893
  	struct super_block *sb = dentry->d_sb;
8587246a0   Coly Li   fs/befs: return f...
894
  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
900
901
902
903
904
  
  	befs_debug(sb, "---> befs_statfs()");
  
  	buf->f_type = BEFS_SUPER_MAGIC;
  	buf->f_bsize = sb->s_blocksize;
  	buf->f_blocks = BEFS_SB(sb)->num_blocks;
  	buf->f_bfree = BEFS_SB(sb)->num_blocks - BEFS_SB(sb)->used_blocks;
  	buf->f_bavail = buf->f_bfree;
  	buf->f_files = 0;	/* UNKNOWN */
  	buf->f_ffree = 0;	/* UNKNOWN */
8587246a0   Coly Li   fs/befs: return f...
905
906
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
907
908
909
910
911
912
  	buf->f_namelen = BEFS_NAME_LEN;
  
  	befs_debug(sb, "<--- befs_statfs()");
  
  	return 0;
  }
152a08366   Al Viro   new helper: mount...
913
914
915
  static struct dentry *
  befs_mount(struct file_system_type *fs_type, int flags, const char *dev_name,
  	    void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  {
152a08366   Al Viro   new helper: mount...
917
  	return mount_bdev(fs_type, flags, dev_name, data, befs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
918
919
920
921
922
  }
  
  static struct file_system_type befs_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "befs",
152a08366   Al Viro   new helper: mount...
923
  	.mount		= befs_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
926
927
928
929
930
931
932
933
934
935
936
937
  	.kill_sb	= kill_block_super,
  	.fs_flags	= FS_REQUIRES_DEV,	
  };
  
  static int __init
  init_befs_fs(void)
  {
  	int err;
  
  	printk(KERN_INFO "BeFS version: %s
  ", BEFS_VERSION);
  
  	err = befs_init_inodecache();
  	if (err)
0418726bb   Adrian Bunk   typo fixes: aquir...
938
  		goto unacquire_none;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
939
940
941
  
  	err = register_filesystem(&befs_fs_type);
  	if (err)
0418726bb   Adrian Bunk   typo fixes: aquir...
942
  		goto unacquire_inodecache;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
943
944
  
  	return 0;
0418726bb   Adrian Bunk   typo fixes: aquir...
945
  unacquire_inodecache:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  	befs_destroy_inodecache();
0418726bb   Adrian Bunk   typo fixes: aquir...
947
  unacquire_none:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
  	return err;
  }
  
  static void __exit
  exit_befs_fs(void)
  {
  	befs_destroy_inodecache();
  
  	unregister_filesystem(&befs_fs_type);
  }
  
  /*
  Macros that typecheck the init and exit functions,
  ensures that they are called at init and cleanup,
  and eliminates warnings about unused functions.
  */
  module_init(init_befs_fs)
  module_exit(exit_befs_fs)