Blame view

fs/isofs/inode.c 40 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
  /*
   *  linux/fs/isofs/inode.c
   *
   *  (C) 1991  Linus Torvalds - minix filesystem
   *      1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
96de0e252   Jan Engelhardt   Convert files to ...
6
   *      1994  Eberhard Mönkeberg - multi session handling.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
9
10
11
12
   *      1995  Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs.
   *	1997  Gordon Chaffee - Joliet CDs
   *	1998  Eric Lammerts - ISO 9660 Level 3
   *	2004  Paul Serice - Inode Support pushed out from 4GB to 128GB
   *	2004  Paul Serice - NFS Export Operations
   */
94f2f7157   Al Viro   [PATCH] isofs inc...
13
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <linux/nls.h>
  #include <linux/ctype.h>
94f2f7157   Al Viro   [PATCH] isofs inc...
18
19
  #include <linux/statfs.h>
  #include <linux/cdrom.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/parser.h>
3069083cc   Namjae Jeon   isofs: add readpa...
21
  #include <linux/mpage.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22

94f2f7157   Al Viro   [PATCH] isofs inc...
23
  #include "isofs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
  #include "zisofs.h"
  
  #define BEQUIET
b1e6a015a   Nick Piggin   fs: change d_hash...
27
28
29
30
  static int isofs_hashi(const struct dentry *parent, const struct inode *inode,
  		struct qstr *qstr);
  static int isofs_hash(const struct dentry *parent, const struct inode *inode,
  		struct qstr *qstr);
621e155a3   Nick Piggin   fs: change d_comp...
31
32
33
34
35
36
37
38
  static int isofs_dentry_cmpi(const struct dentry *parent,
  		const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name);
  static int isofs_dentry_cmp(const struct dentry *parent,
  		const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  
  #ifdef CONFIG_JOLIET
b1e6a015a   Nick Piggin   fs: change d_hash...
41
42
43
44
  static int isofs_hashi_ms(const struct dentry *parent, const struct inode *inode,
  		struct qstr *qstr);
  static int isofs_hash_ms(const struct dentry *parent, const struct inode *inode,
  		struct qstr *qstr);
621e155a3   Nick Piggin   fs: change d_comp...
45
46
47
48
49
50
51
52
  static int isofs_dentry_cmpi_ms(const struct dentry *parent,
  		const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name);
  static int isofs_dentry_cmp_ms(const struct dentry *parent,
  		const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
54
55
56
57
  #endif
  
  static void isofs_put_super(struct super_block *sb)
  {
  	struct isofs_sb_info *sbi = ISOFS_SB(sb);
6cfd01484   Christoph Hellwig   push BKL down int...
58

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  #ifdef CONFIG_JOLIET
6d729e44a   Thomas Gleixner   fs: Make unload_n...
60
  	unload_nls(sbi->s_nls_iocharset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
  	kfree(sbi);
  	sb->s_fs_info = NULL;
  	return;
  }
c4386c83b   David Howells   iget: stop ISOFS ...
66
  static int isofs_read_inode(struct inode *);
726c33422   David Howells   [PATCH] VFS: Perm...
67
  static int isofs_statfs (struct dentry *, struct kstatfs *);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

e18b890bb   Christoph Lameter   [PATCH] slab: rem...
69
  static struct kmem_cache *isofs_inode_cachep;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
71
72
73
  
  static struct inode *isofs_alloc_inode(struct super_block *sb)
  {
  	struct iso_inode_info *ei;
e94b17660   Christoph Lameter   [PATCH] slab: rem...
74
  	ei = kmem_cache_alloc(isofs_inode_cachep, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
  	if (!ei)
  		return NULL;
  	return &ei->vfs_inode;
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
79
  static void isofs_i_callback(struct rcu_head *head)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
80
  {
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
81
  	struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  	kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode));
  }
fa0d7e3de   Nick Piggin   fs: icache RCU fr...
84
85
86
87
  static void isofs_destroy_inode(struct inode *inode)
  {
  	call_rcu(&inode->i_rcu, isofs_i_callback);
  }
51cc50685   Alexey Dobriyan   SL*B: drop kmem c...
88
  static void init_once(void *foo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  {
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
90
  	struct iso_inode_info *ei = foo;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

a35afb830   Christoph Lameter   Remove SLAB_CTOR_...
92
  	inode_init_once(&ei->vfs_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  }
c3ed85a36   Dave Jones   isofs: fix up Cod...
94

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
  static int init_inodecache(void)
  {
  	isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
c3ed85a36   Dave Jones   isofs: fix up Cod...
98
99
100
  					sizeof(struct iso_inode_info),
  					0, (SLAB_RECLAIM_ACCOUNT|
  					SLAB_MEM_SPREAD),
20c2df83d   Paul Mundt   mm: Remove slab d...
101
  					init_once);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
  	if (isofs_inode_cachep == NULL)
  		return -ENOMEM;
  	return 0;
  }
  
  static void destroy_inodecache(void)
  {
1a1d92c10   Alexey Dobriyan   [PATCH] Really ig...
109
  	kmem_cache_destroy(isofs_inode_cachep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
114
115
116
117
  }
  
  static int isofs_remount(struct super_block *sb, int *flags, char *data)
  {
  	/* we probably want a lot more here */
  	*flags |= MS_RDONLY;
  	return 0;
  }
ee9b6d61a   Josef 'Jeff' Sipek   [PATCH] Mark stru...
118
  static const struct super_operations isofs_sops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
119
120
  	.alloc_inode	= isofs_alloc_inode,
  	.destroy_inode	= isofs_destroy_inode,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
122
123
  	.put_super	= isofs_put_super,
  	.statfs		= isofs_statfs,
  	.remount_fs	= isofs_remount,
d0132eea7   Miklos Szeredi   mount options: fi...
124
  	.show_options	= generic_show_options,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  };
e16404ed0   Al Viro   constify dentry_o...
126
  static const struct dentry_operations isofs_dentry_ops[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  	{
  		.d_hash		= isofs_hash,
  		.d_compare	= isofs_dentry_cmp,
  	},
  	{
  		.d_hash		= isofs_hashi,
  		.d_compare	= isofs_dentry_cmpi,
  	},
  #ifdef CONFIG_JOLIET
  	{
  		.d_hash		= isofs_hash_ms,
  		.d_compare	= isofs_dentry_cmp_ms,
  	},
  	{
  		.d_hash		= isofs_hashi_ms,
  		.d_compare	= isofs_dentry_cmpi_ms,
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
143
  	},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
147
  #endif
  };
  
  struct iso9660_options{
5404ac8e4   Jan Kara   isofs: cleanup mo...
148
  	unsigned int rock:1;
8711c67be   Bartlomiej Zolnierkiewicz   isofs: fix Joliet...
149
  	unsigned int joliet:1;
5404ac8e4   Jan Kara   isofs: cleanup mo...
150
151
152
153
154
155
156
157
158
  	unsigned int cruft:1;
  	unsigned int hide:1;
  	unsigned int showassoc:1;
  	unsigned int nocompress:1;
  	unsigned int overriderockperm:1;
  	unsigned int uid_set:1;
  	unsigned int gid_set:1;
  	unsigned int utf8:1;
  	unsigned char map;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
  	unsigned char check;
  	unsigned int blocksize;
7328bdd6c   Al Viro   isofs: propagate ...
161
162
  	umode_t fmode;
  	umode_t dmode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
  	gid_t gid;
  	uid_t uid;
  	char *iocharset;
c3ed85a36   Dave Jones   isofs: fix up Cod...
166
167
168
  	/* LVE */
  	s32 session;
  	s32 sbsector;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
  };
  
  /*
   * Compute the hash for the isofs name corresponding to the dentry.
   */
  static int
b1e6a015a   Nick Piggin   fs: change d_hash...
175
  isofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  {
  	const char *name;
  	int len;
  
  	len = qstr->len;
  	name = qstr->name;
  	if (ms) {
  		while (len && name[len-1] == '.')
  			len--;
  	}
  
  	qstr->hash = full_name_hash(name, len);
  
  	return 0;
  }
  
  /*
   * Compute the hash for the isofs name corresponding to the dentry.
   */
  static int
b1e6a015a   Nick Piggin   fs: change d_hash...
196
  isofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
  {
  	const char *name;
  	int len;
  	char c;
  	unsigned long hash;
  
  	len = qstr->len;
  	name = qstr->name;
  	if (ms) {
  		while (len && name[len-1] == '.')
  			len--;
  	}
  
  	hash = init_name_hash();
  	while (len--) {
  		c = tolower(*name++);
f17e121fd   young dave   remove useless to...
213
  		hash = partial_name_hash(c, hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
217
218
219
220
  	}
  	qstr->hash = end_name_hash(hash);
  
  	return 0;
  }
  
  /*
621e155a3   Nick Piggin   fs: change d_comp...
221
   * Compare of two isofs names.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
   */
621e155a3   Nick Piggin   fs: change d_comp...
223
224
225
  static int isofs_dentry_cmp_common(
  		unsigned int len, const char *str,
  		const struct qstr *name, int ms, int ci)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
226
227
228
229
  {
  	int alen, blen;
  
  	/* A filename cannot end in '.' or we treat it like it has none */
621e155a3   Nick Piggin   fs: change d_comp...
230
231
  	alen = name->len;
  	blen = len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  	if (ms) {
621e155a3   Nick Piggin   fs: change d_comp...
233
  		while (alen && name->name[alen-1] == '.')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  			alen--;
621e155a3   Nick Piggin   fs: change d_comp...
235
  		while (blen && str[blen-1] == '.')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
  			blen--;
  	}
  	if (alen == blen) {
621e155a3   Nick Piggin   fs: change d_comp...
239
240
241
242
243
244
245
  		if (ci) {
  			if (strnicmp(name->name, str, alen) == 0)
  				return 0;
  		} else {
  			if (strncmp(name->name, str, alen) == 0)
  				return 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
250
  	}
  	return 1;
  }
  
  static int
b1e6a015a   Nick Piggin   fs: change d_hash...
251
252
  isofs_hash(const struct dentry *dentry, const struct inode *inode,
  		struct qstr *qstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
254
255
256
257
  {
  	return isofs_hash_common(dentry, qstr, 0);
  }
  
  static int
b1e6a015a   Nick Piggin   fs: change d_hash...
258
259
  isofs_hashi(const struct dentry *dentry, const struct inode *inode,
  		struct qstr *qstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
262
263
264
  {
  	return isofs_hashi_common(dentry, qstr, 0);
  }
  
  static int
621e155a3   Nick Piggin   fs: change d_comp...
265
266
267
  isofs_dentry_cmp(const struct dentry *parent, const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  {
621e155a3   Nick Piggin   fs: change d_comp...
269
  	return isofs_dentry_cmp_common(len, str, name, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
  }
  
  static int
621e155a3   Nick Piggin   fs: change d_comp...
273
274
275
  isofs_dentry_cmpi(const struct dentry *parent, const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  {
621e155a3   Nick Piggin   fs: change d_comp...
277
  	return isofs_dentry_cmp_common(len, str, name, 0, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
281
  }
  
  #ifdef CONFIG_JOLIET
  static int
b1e6a015a   Nick Piggin   fs: change d_hash...
282
283
  isofs_hash_ms(const struct dentry *dentry, const struct inode *inode,
  		struct qstr *qstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
285
286
287
288
  {
  	return isofs_hash_common(dentry, qstr, 1);
  }
  
  static int
b1e6a015a   Nick Piggin   fs: change d_hash...
289
290
  isofs_hashi_ms(const struct dentry *dentry, const struct inode *inode,
  		struct qstr *qstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
  {
  	return isofs_hashi_common(dentry, qstr, 1);
  }
  
  static int
621e155a3   Nick Piggin   fs: change d_comp...
296
297
298
  isofs_dentry_cmp_ms(const struct dentry *parent, const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  {
621e155a3   Nick Piggin   fs: change d_comp...
300
  	return isofs_dentry_cmp_common(len, str, name, 1, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
302
303
  }
  
  static int
621e155a3   Nick Piggin   fs: change d_comp...
304
305
306
  isofs_dentry_cmpi_ms(const struct dentry *parent, const struct inode *pinode,
  		const struct dentry *dentry, const struct inode *inode,
  		unsigned int len, const char *str, const struct qstr *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
  {
621e155a3   Nick Piggin   fs: change d_comp...
308
  	return isofs_dentry_cmp_common(len, str, name, 1, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
310
311
312
313
314
315
  }
  #endif
  
  enum {
  	Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore,
  	Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet,
  	Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err,
52b680c81   Jan Kara   isofs: let mode a...
316
  	Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  };
a447c0932   Steven Whitehouse   vfs: Use const fo...
318
  static const match_table_t tokens = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
  	{Opt_norock, "norock"},
  	{Opt_nojoliet, "nojoliet"},
  	{Opt_unhide, "unhide"},
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
322
323
  	{Opt_hide, "hide"},
  	{Opt_showassoc, "showassoc"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
  	{Opt_cruft, "cruft"},
  	{Opt_utf8, "utf8"},
  	{Opt_iocharset, "iocharset=%s"},
  	{Opt_map_a, "map=acorn"},
  	{Opt_map_a, "map=a"},
  	{Opt_map_n, "map=normal"},
  	{Opt_map_n, "map=n"},
  	{Opt_map_o, "map=off"},
  	{Opt_map_o, "map=o"},
  	{Opt_session, "session=%u"},
  	{Opt_sb, "sbsector=%u"},
  	{Opt_check_r, "check=relaxed"},
  	{Opt_check_r, "check=r"},
  	{Opt_check_s, "check=strict"},
  	{Opt_check_s, "check=s"},
  	{Opt_uid, "uid=%u"},
  	{Opt_gid, "gid=%u"},
  	{Opt_mode, "mode=%u"},
9b7880e7b   Jan Kara   isofs: implement ...
342
  	{Opt_dmode, "dmode=%u"},
52b680c81   Jan Kara   isofs: let mode a...
343
  	{Opt_overriderockperm, "overriderockperm"},
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
352
353
354
355
  	{Opt_block, "block=%u"},
  	{Opt_ignore, "conv=binary"},
  	{Opt_ignore, "conv=b"},
  	{Opt_ignore, "conv=text"},
  	{Opt_ignore, "conv=t"},
  	{Opt_ignore, "conv=mtext"},
  	{Opt_ignore, "conv=m"},
  	{Opt_ignore, "conv=auto"},
  	{Opt_ignore, "conv=a"},
  	{Opt_nocompress, "nocompress"},
  	{Opt_err, NULL}
  };
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
356
  static int parse_options(char *options, struct iso9660_options *popt)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
361
  {
  	char *p;
  	int option;
  
  	popt->map = 'n';
5404ac8e4   Jan Kara   isofs: cleanup mo...
362
363
364
365
366
  	popt->rock = 1;
  	popt->joliet = 1;
  	popt->cruft = 0;
  	popt->hide = 0;
  	popt->showassoc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  	popt->check = 'u';		/* unset */
  	popt->nocompress = 0;
  	popt->blocksize = 1024;
52b680c81   Jan Kara   isofs: let mode a...
370
  	popt->fmode = popt->dmode = ISOFS_INVALID_MODE;
5c4a656b7   Jan Kara   isofs: fix settin...
371
372
  	popt->uid_set = 0;
  	popt->gid_set = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
  	popt->gid = 0;
  	popt->uid = 0;
  	popt->iocharset = NULL;
  	popt->utf8 = 0;
52b680c81   Jan Kara   isofs: let mode a...
377
  	popt->overriderockperm = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  	popt->session=-1;
  	popt->sbsector=-1;
  	if (!options)
  		return 1;
  
  	while ((p = strsep(&options, ",")) != NULL) {
  		int token;
  		substring_t args[MAX_OPT_ARGS];
  		unsigned n;
  
  		if (!*p)
  			continue;
  
  		token = match_token(p, tokens, args);
  		switch (token) {
  		case Opt_norock:
5404ac8e4   Jan Kara   isofs: cleanup mo...
394
  			popt->rock = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
  			break;
  		case Opt_nojoliet:
5404ac8e4   Jan Kara   isofs: cleanup mo...
397
  			popt->joliet = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398
  			break;
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
399
  		case Opt_hide:
5404ac8e4   Jan Kara   isofs: cleanup mo...
400
  			popt->hide = 1;
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
401
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  		case Opt_unhide:
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
403
  		case Opt_showassoc:
5404ac8e4   Jan Kara   isofs: cleanup mo...
404
  			popt->showassoc = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  			break;
  		case Opt_cruft:
5404ac8e4   Jan Kara   isofs: cleanup mo...
407
  			popt->cruft = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
  			break;
  		case Opt_utf8:
  			popt->utf8 = 1;
  			break;
  #ifdef CONFIG_JOLIET
  		case Opt_iocharset:
  			popt->iocharset = match_strdup(&args[0]);
  			break;
  #endif
  		case Opt_map_a:
  			popt->map = 'a';
  			break;
  		case Opt_map_o:
  			popt->map = 'o';
  			break;
  		case Opt_map_n:
  			popt->map = 'n';
  			break;
  		case Opt_session:
  			if (match_int(&args[0], &option))
  				return 0;
  			n = option;
  			if (n > 99)
  				return 0;
  			popt->session = n + 1;
  			break;
  		case Opt_sb:
  			if (match_int(&args[0], &option))
  				return 0;
  			popt->sbsector = option;
  			break;
  		case Opt_check_r:
  			popt->check = 'r';
  			break;
  		case Opt_check_s:
  			popt->check = 's';
  			break;
  		case Opt_ignore:
  			break;
  		case Opt_uid:
  			if (match_int(&args[0], &option))
  				return 0;
  			popt->uid = option;
5c4a656b7   Jan Kara   isofs: fix settin...
451
  			popt->uid_set = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
453
454
455
456
  			break;
  		case Opt_gid:
  			if (match_int(&args[0], &option))
  				return 0;
  			popt->gid = option;
5c4a656b7   Jan Kara   isofs: fix settin...
457
  			popt->gid_set = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
458
459
460
461
  			break;
  		case Opt_mode:
  			if (match_int(&args[0], &option))
  				return 0;
9b7880e7b   Jan Kara   isofs: implement ...
462
463
464
465
466
467
  			popt->fmode = option;
  			break;
  		case Opt_dmode:
  			if (match_int(&args[0], &option))
  				return 0;
  			popt->dmode = option;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  			break;
52b680c81   Jan Kara   isofs: let mode a...
469
470
471
  		case Opt_overriderockperm:
  			popt->overriderockperm = 1;
  			break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
  		case Opt_block:
  			if (match_int(&args[0], &option))
  				return 0;
  			n = option;
  			if (n != 512 && n != 1024 && n != 2048)
  				return 0;
  			popt->blocksize = n;
  			break;
  		case Opt_nocompress:
  			popt->nocompress = 1;
  			break;
  		default:
  			return 0;
  		}
  	}
  	return 1;
  }
  
  /*
   * look if the driver can tell the multi session redirection value
   *
   * don't change this if you don't know what you do, please!
   * Multisession is legal only with XA disks.
   * A non-XA disk with more than one volume descriptor may do it right, but
   * usually is written in a nowhere standardized "multi-partition" manner.
   * Multisession uses absolute addressing (solely the first frame of the whole
   * track is #0), multi-partition uses relative addressing (each first frame of
   * each track is #0), and a track is not a session.
   *
   * A broken CDwriter software or drive firmware does not set new standards,
   * at least not if conflicting with the existing ones.
   *
   * emoenke@gwdg.de
   */
  #define WE_OBEY_THE_WRITTEN_STANDARDS 1
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
507
  static unsigned int isofs_get_last_session(struct super_block *sb, s32 session)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  {
  	struct cdrom_multisession ms_info;
  	unsigned int vol_desc_start;
  	struct block_device *bdev = sb->s_bdev;
  	int i;
  
  	vol_desc_start=0;
  	ms_info.addr_format=CDROM_LBA;
  	if(session >= 0 && session <= 99) {
  		struct cdrom_tocentry Te;
  		Te.cdte_track=session;
  		Te.cdte_format=CDROM_LBA;
  		i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te);
  		if (!i) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
522
523
524
525
  			printk(KERN_DEBUG "ISOFS: Session %d start %d type %d
  ",
  				session, Te.cdte_addr.lba,
  				Te.cdte_ctrl&CDROM_DATA_TRACK);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
526
527
528
  			if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4)
  				return Te.cdte_addr.lba;
  		}
c3ed85a36   Dave Jones   isofs: fix up Cod...
529
530
531
  
  		printk(KERN_ERR "ISOFS: Invalid session number or type of track
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
  	}
  	i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info);
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
534
  	if (session > 0)
c3ed85a36   Dave Jones   isofs: fix up Cod...
535
536
  		printk(KERN_ERR "ISOFS: Invalid session number
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  #if 0
c3ed85a36   Dave Jones   isofs: fix up Cod...
538
539
  	printk(KERN_DEBUG "isofs.inode: CDROMMULTISESSION: rc=%d
  ",i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
  	if (i==0) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
541
542
543
544
  		printk(KERN_DEBUG "isofs.inode: XA disk: %s
  ",ms_info.xa_flag?"yes":"no");
  		printk(KERN_DEBUG "isofs.inode: vol_desc_start = %d
  ", ms_info.addr.lba);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
  	}
  #endif
  	if (i==0)
  #if WE_OBEY_THE_WRITTEN_STANDARDS
c3ed85a36   Dave Jones   isofs: fix up Cod...
549
  		if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  #endif
c3ed85a36   Dave Jones   isofs: fix up Cod...
551
  			vol_desc_start=ms_info.addr.lba;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
554
555
  	return vol_desc_start;
  }
  
  /*
e45c9effe   Ondrej Zary   isofs: work-aroun...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
   * Check if root directory is empty (has less than 3 files).
   *
   * Used to detect broken CDs where ISO root directory is empty but Joliet root
   * directory is OK. If such CD has Rock Ridge extensions, they will be disabled
   * (and Joliet used instead) or else no files would be visible.
   */
  static bool rootdir_empty(struct super_block *sb, unsigned long block)
  {
  	int offset = 0, files = 0, de_len;
  	struct iso_directory_record *de;
  	struct buffer_head *bh;
  
  	bh = sb_bread(sb, block);
  	if (!bh)
  		return true;
  	while (files < 3) {
  		de = (struct iso_directory_record *) (bh->b_data + offset);
  		de_len = *(unsigned char *) de;
  		if (de_len == 0)
  			break;
  		files++;
  		offset += de_len;
  	}
  	brelse(bh);
  	return files < 3;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
586
587
588
589
590
   * Initialize the superblock and read the root inode.
   *
   * Note: a check_disk_change() has been done immediately prior
   * to this call, so we don't need to check again.
   */
  static int isofs_fill_super(struct super_block *s, void *data, int silent)
  {
c3ed85a36   Dave Jones   isofs: fix up Cod...
591
592
593
  	struct buffer_head *bh = NULL, *pri_bh = NULL;
  	struct hs_primary_descriptor *h_pri = NULL;
  	struct iso_primary_descriptor *pri = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
  	struct iso_supplementary_descriptor *sec = NULL;
c3ed85a36   Dave Jones   isofs: fix up Cod...
595
596
597
598
599
600
601
602
  	struct iso_directory_record *rootp;
  	struct inode *inode;
  	struct iso9660_options opt;
  	struct isofs_sb_info *sbi;
  	unsigned long first_data_zone;
  	int joliet_level = 0;
  	int iso_blknum, block;
  	int orig_zonesize;
c4386c83b   David Howells   iget: stop ISOFS ...
603
  	int table, error = -EINVAL;
c3ed85a36   Dave Jones   isofs: fix up Cod...
604
  	unsigned int vol_desc_start;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605

d0132eea7   Miklos Szeredi   mount options: fi...
606
  	save_mount_options(s, data);
f8314dc60   Panagiotis Issaris   [PATCH] fs: Conve...
607
  	sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
4f819a789   Arnd Bergmann   BKL: Remove BKL f...
608
  	if (!sbi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  		return -ENOMEM;
  	s->s_fs_info = sbi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611

9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
612
  	if (!parse_options((char *)data, &opt))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
  		goto out_freesbi;
  
  	/*
  	 * First of all, get the hardware blocksize for this device.
  	 * If we don't know what it is, or the hardware blocksize is
  	 * larger than the blocksize the user specified, then use
  	 * that value.
  	 */
  	/*
  	 * What if bugger tells us to go beyond page size?
  	 */
  	opt.blocksize = sb_min_blocksize(s, opt.blocksize);
  
  	sbi->s_high_sierra = 0; /* default is iso9660 */
  
  	vol_desc_start = (opt.sbsector != -1) ?
  		opt.sbsector : isofs_get_last_session(s,opt.session);
c3ed85a36   Dave Jones   isofs: fix up Cod...
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
  	for (iso_blknum = vol_desc_start+16;
  		iso_blknum < vol_desc_start+100; iso_blknum++) {
  		struct hs_volume_descriptor *hdp;
  		struct iso_volume_descriptor  *vdp;
  
  		block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits);
  		if (!(bh = sb_bread(s, block)))
  			goto out_no_read;
  
  		vdp = (struct iso_volume_descriptor *)bh->b_data;
  		hdp = (struct hs_volume_descriptor *)bh->b_data;
  
  		/*
  		 * Due to the overlapping physical location of the descriptors,
  		 * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure
  		 * proper identification in this case, we first check for ISO.
  		 */
  		if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) {
  			if (isonum_711(vdp->type) == ISO_VD_END)
  				break;
  			if (isonum_711(vdp->type) == ISO_VD_PRIMARY) {
  				if (pri == NULL) {
  					pri = (struct iso_primary_descriptor *)vdp;
  					/* Save the buffer in case we need it ... */
  					pri_bh = bh;
  					bh = NULL;
  				}
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  #ifdef CONFIG_JOLIET
c3ed85a36   Dave Jones   isofs: fix up Cod...
659
660
661
  			else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) {
  				sec = (struct iso_supplementary_descriptor *)vdp;
  				if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) {
8711c67be   Bartlomiej Zolnierkiewicz   isofs: fix Joliet...
662
  					if (opt.joliet) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  						if (sec->escape[2] == 0x40)
  							joliet_level = 1;
  						else if (sec->escape[2] == 0x43)
  							joliet_level = 2;
  						else if (sec->escape[2] == 0x45)
  							joliet_level = 3;
  
  						printk(KERN_DEBUG "ISO 9660 Extensions: "
  							"Microsoft Joliet Level %d
  ",
  							joliet_level);
  					}
  					goto root_found;
  				} else {
  				/* Unknown supplementary volume descriptor */
  				sec = NULL;
  				}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
  #endif
c3ed85a36   Dave Jones   isofs: fix up Cod...
682
683
684
685
686
687
  		} else {
  			if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) {
  				if (isonum_711(hdp->type) != ISO_VD_PRIMARY)
  					goto out_freebh;
  
  				sbi->s_high_sierra = 1;
5404ac8e4   Jan Kara   isofs: cleanup mo...
688
  				opt.rock = 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
689
690
691
  				h_pri = (struct hs_primary_descriptor *)vdp;
  				goto root_found;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
693

c3ed85a36   Dave Jones   isofs: fix up Cod...
694
  		/* Just skip any volume descriptors we don't recognize */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695

c3ed85a36   Dave Jones   isofs: fix up Cod...
696
697
  		brelse(bh);
  		bh = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
702
703
704
705
706
707
708
709
  	}
  	/*
  	 * If we fall through, either no volume descriptor was found,
  	 * or else we passed a primary descriptor looking for others.
  	 */
  	if (!pri)
  		goto out_unknown_format;
  	brelse(bh);
  	bh = pri_bh;
  	pri_bh = NULL;
  
  root_found:
5404ac8e4   Jan Kara   isofs: cleanup mo...
710
  	if (joliet_level && (pri == NULL || !opt.rock)) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
711
712
713
714
  		/* This is the case of Joliet with the norock mount flag.
  		 * A disc with both Joliet and Rock Ridge is handled later
  		 */
  		pri = (struct iso_primary_descriptor *) sec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
  	}
  
  	if(sbi->s_high_sierra){
c3ed85a36   Dave Jones   isofs: fix up Cod...
718
719
720
721
  		rootp = (struct iso_directory_record *) h_pri->root_directory_record;
  		sbi->s_nzones = isonum_733(h_pri->volume_space_size);
  		sbi->s_log_zone_size = isonum_723(h_pri->logical_block_size);
  		sbi->s_max_size = isonum_733(h_pri->volume_space_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
  	} else {
c3ed85a36   Dave Jones   isofs: fix up Cod...
723
724
725
726
727
728
  		if (!pri)
  			goto out_freebh;
  		rootp = (struct iso_directory_record *) pri->root_directory_record;
  		sbi->s_nzones = isonum_733(pri->volume_space_size);
  		sbi->s_log_zone_size = isonum_723(pri->logical_block_size);
  		sbi->s_max_size = isonum_733(pri->volume_space_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
730
731
732
733
734
735
736
737
738
739
740
  	}
  
  	sbi->s_ninodes = 0; /* No way to figure this out easily */
  
  	orig_zonesize = sbi->s_log_zone_size;
  	/*
  	 * If the zone size is smaller than the hardware sector size,
  	 * this is a fatal error.  This would occur if the disc drive
  	 * had sectors that were 2048 bytes, but the filesystem had
  	 * blocks that were 512 bytes (which should only very rarely
  	 * happen.)
  	 */
c3ed85a36   Dave Jones   isofs: fix up Cod...
741
  	if (orig_zonesize < opt.blocksize)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
743
744
  		goto out_bad_size;
  
  	/* RDE: convert log zone size to bit shift */
c3ed85a36   Dave Jones   isofs: fix up Cod...
745
746
747
748
  	switch (sbi->s_log_zone_size) {
  	case  512: sbi->s_log_zone_size =  9; break;
  	case 1024: sbi->s_log_zone_size = 10; break;
  	case 2048: sbi->s_log_zone_size = 11; break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749

c3ed85a36   Dave Jones   isofs: fix up Cod...
750
  	default:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
751
  		goto out_bad_zone_size;
c3ed85a36   Dave Jones   isofs: fix up Cod...
752
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
  
  	s->s_magic = ISOFS_SUPER_MAGIC;
66a362a2a   Jan Andres   isofs: Fix lseek(...
755
756
757
758
759
760
  
  	/*
  	 * With multi-extent files, file size is only limited by the maximum
  	 * size of a file system, which is 8 TB.
  	 */
  	s->s_maxbytes = 0x80000000000LL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
761

c3ed85a36   Dave Jones   isofs: fix up Cod...
762
763
764
765
766
767
  	/*
  	 * The CDROM is read-only, has no nodes (devices) on it, and since
  	 * all of the files appear to be owned by root, we really do not want
  	 * to allow suid.  (suid or devices will not show up unless we have
  	 * Rock Ridge extensions)
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
  
  	s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */;
  
  	/* Set this for reference. Its not currently used except on write
  	   which we don't have .. */
c3ed85a36   Dave Jones   isofs: fix up Cod...
773
774
775
  
  	first_data_zone = isonum_733(rootp->extent) +
  			  isonum_711(rootp->ext_attr_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
777
  	sbi->s_firstdatazone = first_data_zone;
  #ifndef BEQUIET
c3ed85a36   Dave Jones   isofs: fix up Cod...
778
779
780
781
782
  	printk(KERN_DEBUG "ISOFS: Max size:%ld   Log zone size:%ld
  ",
  		sbi->s_max_size, 1UL << sbi->s_log_zone_size);
  	printk(KERN_DEBUG "ISOFS: First datazone:%ld
  ", sbi->s_firstdatazone);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
783
  	if(sbi->s_high_sierra)
c3ed85a36   Dave Jones   isofs: fix up Cod...
784
785
  		printk(KERN_DEBUG "ISOFS: Disc in High Sierra format.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
788
789
790
791
792
793
794
795
796
797
798
799
  #endif
  
  	/*
  	 * If the Joliet level is set, we _may_ decide to use the
  	 * secondary descriptor, but can't be sure until after we
  	 * read the root inode. But before reading the root inode
  	 * we may need to change the device blocksize, and would
  	 * rather release the old buffer first. So, we cache the
  	 * first_data_zone value from the secondary descriptor.
  	 */
  	if (joliet_level) {
  		pri = (struct iso_primary_descriptor *) sec;
  		rootp = (struct iso_directory_record *)
  			pri->root_directory_record;
c3ed85a36   Dave Jones   isofs: fix up Cod...
800
801
  		first_data_zone = isonum_733(rootp->extent) +
  				isonum_711(rootp->ext_attr_length);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
  	}
  
  	/*
  	 * We're all done using the volume descriptor, and may need
  	 * to change the device blocksize, so release the buffer now.
  	 */
  	brelse(pri_bh);
  	brelse(bh);
  
  	/*
  	 * Force the blocksize to 512 for 512 byte sectors.  The file
  	 * read primitives really get it wrong in a bad way if we don't
  	 * do this.
  	 *
  	 * Note - we should never be setting the blocksize to something
  	 * less than the hardware sector size for the device.  If we
  	 * do, we would end up having to read larger buffers and split
  	 * out portions to satisfy requests.
  	 *
  	 * Note2- the idea here is that we want to deal with the optimal
  	 * zonesize in the filesystem.  If we have it set to something less,
  	 * then we have horrible problems with trying to piece together
  	 * bits of adjacent blocks in order to properly read directory
  	 * entries.  By forcing the blocksize in this way, we ensure
  	 * that we will never be required to do this.
  	 */
  	sb_set_blocksize(s, orig_zonesize);
  
  	sbi->s_nls_iocharset = NULL;
  
  #ifdef CONFIG_JOLIET
  	if (joliet_level && opt.utf8 == 0) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
834
  		char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
836
837
838
839
840
841
842
843
844
845
846
  		sbi->s_nls_iocharset = load_nls(p);
  		if (! sbi->s_nls_iocharset) {
  			/* Fail only if explicit charset specified */
  			if (opt.iocharset)
  				goto out_freesbi;
  			sbi->s_nls_iocharset = load_nls_default();
  		}
  	}
  #endif
  	s->s_op = &isofs_sops;
  	s->s_export_op = &isofs_export_ops;
  	sbi->s_mapping = opt.map;
5404ac8e4   Jan Kara   isofs: cleanup mo...
847
  	sbi->s_rock = (opt.rock ? 2 : 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
849
  	sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/
  	sbi->s_cruft = opt.cruft;
9769f4eb3   Jeremy White   [PATCH] isofs: sh...
850
851
  	sbi->s_hide = opt.hide;
  	sbi->s_showassoc = opt.showassoc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
852
853
  	sbi->s_uid = opt.uid;
  	sbi->s_gid = opt.gid;
5c4a656b7   Jan Kara   isofs: fix settin...
854
855
  	sbi->s_uid_set = opt.uid_set;
  	sbi->s_gid_set = opt.gid_set;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  	sbi->s_utf8 = opt.utf8;
  	sbi->s_nocompress = opt.nocompress;
52b680c81   Jan Kara   isofs: let mode a...
858
  	sbi->s_overriderockperm = opt.overriderockperm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
860
861
862
863
  	/*
  	 * It would be incredibly stupid to allow people to mark every file
  	 * on the disk as suid, so we merely allow them to set the default
  	 * permissions.
  	 */
52b680c81   Jan Kara   isofs: let mode a...
864
865
866
867
868
869
870
871
  	if (opt.fmode != ISOFS_INVALID_MODE)
  		sbi->s_fmode = opt.fmode & 0777;
  	else
  		sbi->s_fmode = ISOFS_INVALID_MODE;
  	if (opt.dmode != ISOFS_INVALID_MODE)
  		sbi->s_dmode = opt.dmode & 0777;
  	else
  		sbi->s_dmode = ISOFS_INVALID_MODE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
872
873
874
875
876
877
878
  
  	/*
  	 * Read the root inode, which _may_ result in changing
  	 * the s_rock flag. Once we have the final s_rock value,
  	 * we then decide whether to use the Joliet descriptor.
  	 */
  	inode = isofs_iget(s, sbi->s_firstdatazone, 0);
c4386c83b   David Howells   iget: stop ISOFS ...
879
880
  	if (IS_ERR(inode))
  		goto out_no_root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
881
882
  
  	/*
e45c9effe   Ondrej Zary   isofs: work-aroun...
883
884
885
886
887
888
889
890
891
892
893
894
  	 * Fix for broken CDs with Rock Ridge and empty ISO root directory but
  	 * correct Joliet root directory.
  	 */
  	if (sbi->s_rock == 1 && joliet_level &&
  				rootdir_empty(s, sbi->s_firstdatazone)) {
  		printk(KERN_NOTICE
  			"ISOFS: primary root directory is empty. "
  			"Disabling Rock Ridge and switching to Joliet.");
  		sbi->s_rock = 0;
  	}
  
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
895
896
897
898
899
900
901
902
903
904
905
906
907
  	 * If this disk has both Rock Ridge and Joliet on it, then we
  	 * want to use Rock Ridge by default.  This can be overridden
  	 * by using the norock mount option.  There is still one other
  	 * possibility that is not taken into account: a Rock Ridge
  	 * CD with Unicode names.  Until someone sees such a beast, it
  	 * will not be supported.
  	 */
  	if (sbi->s_rock == 1) {
  		joliet_level = 0;
  	} else if (joliet_level) {
  		sbi->s_rock = 0;
  		if (sbi->s_firstdatazone != first_data_zone) {
  			sbi->s_firstdatazone = first_data_zone;
c3ed85a36   Dave Jones   isofs: fix up Cod...
908
  			printk(KERN_DEBUG
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
909
910
911
912
  				"ISOFS: changing to secondary root
  ");
  			iput(inode);
  			inode = isofs_iget(s, sbi->s_firstdatazone, 0);
c4386c83b   David Howells   iget: stop ISOFS ...
913
914
  			if (IS_ERR(inode))
  				goto out_no_root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
915
916
917
918
919
  		}
  	}
  
  	if (opt.check == 'u') {
  		/* Only Joliet is case insensitive by default */
c3ed85a36   Dave Jones   isofs: fix up Cod...
920
921
922
923
  		if (joliet_level)
  			opt.check = 'r';
  		else
  			opt.check = 's';
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
924
925
  	}
  	sbi->s_joliet_level = joliet_level;
817794e0d   Kirill Kuvaldin   isofs: mounting t...
926
927
928
929
930
931
932
933
  	/* Make sure the root inode is a directory */
  	if (!S_ISDIR(inode->i_mode)) {
  		printk(KERN_WARNING
  			"isofs_fill_super: root inode is not a directory. "
  			"Corrupted media?
  ");
  		goto out_iput;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
934
  	table = 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
935
936
937
938
  	if (joliet_level)
  		table += 2;
  	if (opt.check == 'r')
  		table++;
6cc9c1d2c   Al Viro   fix isofs d_op ha...
939
940
941
942
943
  
  	s->s_d_op = &isofs_dentry_ops[table];
  
  	/* get the root dentry */
  	s->s_root = d_alloc_root(inode);
8fdd8c49f   Al Viro   isofs: inode leak...
944
945
946
947
948
  	if (!(s->s_root)) {
  		iput(inode);
  		error = -ENOMEM;
  		goto out_no_inode;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949

f99d49adf   Jesper Juhl   [PATCH] kfree cle...
950
  	kfree(opt.iocharset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
955
956
  
  	return 0;
  
  	/*
  	 * Display error messages and free resources.
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
  out_iput:
  	iput(inode);
c4386c83b   David Howells   iget: stop ISOFS ...
959
960
961
962
963
964
965
  	goto out_no_inode;
  out_no_root:
  	error = PTR_ERR(inode);
  	if (error != -ENOMEM)
  		printk(KERN_WARNING "%s: get root inode failed
  ", __func__);
  out_no_inode:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
  #ifdef CONFIG_JOLIET
6d729e44a   Thomas Gleixner   fs: Make unload_n...
967
  	unload_nls(sbi->s_nls_iocharset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
968
969
970
  #endif
  	goto out_freesbi;
  out_no_read:
c3ed85a36   Dave Jones   isofs: fix up Cod...
971
972
973
  	printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d
  ",
  		__func__, s->s_id, iso_blknum, block);
c11760c6d   Linus Torvalds   isofs: fix bh lea...
974
  	goto out_freebh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
975
  out_bad_zone_size:
c3ed85a36   Dave Jones   isofs: fix up Cod...
976
977
  	printk(KERN_WARNING "ISOFS: Bad logical zone size %ld
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
978
979
980
  		sbi->s_log_zone_size);
  	goto out_freebh;
  out_bad_size:
c3ed85a36   Dave Jones   isofs: fix up Cod...
981
982
  	printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983
984
985
986
  		orig_zonesize, opt.blocksize);
  	goto out_freebh;
  out_unknown_format:
  	if (!silent)
c3ed85a36   Dave Jones   isofs: fix up Cod...
987
988
  		printk(KERN_WARNING "ISOFS: Unable to identify CD-ROM format.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
990
991
  
  out_freebh:
  	brelse(bh);
c11760c6d   Linus Torvalds   isofs: fix bh lea...
992
  	brelse(pri_bh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
993
  out_freesbi:
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
994
  	kfree(opt.iocharset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
995
996
  	kfree(sbi);
  	s->s_fs_info = NULL;
c4386c83b   David Howells   iget: stop ISOFS ...
997
  	return error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
  }
726c33422   David Howells   [PATCH] VFS: Perm...
999
  static int isofs_statfs (struct dentry *dentry, struct kstatfs *buf)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1000
  {
726c33422   David Howells   [PATCH] VFS: Perm...
1001
  	struct super_block *sb = dentry->d_sb;
2430c4daf   Coly Li   fs/isofs: return ...
1002
  	u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
726c33422   David Howells   [PATCH] VFS: Perm...
1003

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1004
1005
1006
  	buf->f_type = ISOFS_SUPER_MAGIC;
  	buf->f_bsize = sb->s_blocksize;
  	buf->f_blocks = (ISOFS_SB(sb)->s_nzones
c3ed85a36   Dave Jones   isofs: fix up Cod...
1007
  		<< (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
1009
1010
1011
  	buf->f_bfree = 0;
  	buf->f_bavail = 0;
  	buf->f_files = ISOFS_SB(sb)->s_ninodes;
  	buf->f_ffree = 0;
2430c4daf   Coly Li   fs/isofs: return ...
1012
1013
  	buf->f_fsid.val[0] = (u32)id;
  	buf->f_fsid.val[1] = (u32)(id >> 32);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
1017
1018
1019
1020
  	buf->f_namelen = NAME_MAX;
  	return 0;
  }
  
  /*
   * Get a set of blocks; filling in buffer_heads if already allocated
   * or getblk() if they are not.  Returns the number of blocks inserted
c4386c83b   David Howells   iget: stop ISOFS ...
1021
   * (-ve == error.)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1022
   */
fde214d41   Jan Kara   isofs: Fix isofs_...
1023
  int isofs_get_blocks(struct inode *inode, sector_t iblock,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1024
1025
  		     struct buffer_head **bh, unsigned long nblocks)
  {
fde214d41   Jan Kara   isofs: Fix isofs_...
1026
  	unsigned long b_off = iblock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1027
1028
1029
  	unsigned offset, sect_size;
  	unsigned int firstext;
  	unsigned long nextblk, nextoff;
c4386c83b   David Howells   iget: stop ISOFS ...
1030
  	int section, rv, error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1031
  	struct iso_inode_info *ei = ISOFS_I(inode);
c4386c83b   David Howells   iget: stop ISOFS ...
1032
  	error = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1033
  	rv = 0;
fde214d41   Jan Kara   isofs: Fix isofs_...
1034
  	if (iblock != b_off) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1035
1036
  		printk(KERN_DEBUG "%s: block number too large
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
  		goto abort;
  	}
c3ed85a36   Dave Jones   isofs: fix up Cod...
1039
1040
1041
  
  	offset = 0;
  	firstext = ei->i_first_extent;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1042
  	sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode);
c3ed85a36   Dave Jones   isofs: fix up Cod...
1043
1044
1045
  	nextblk = ei->i_next_section_block;
  	nextoff = ei->i_next_section_offset;
  	section = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046

c3ed85a36   Dave Jones   isofs: fix up Cod...
1047
  	while (nblocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1048
1049
1050
1051
1052
1053
1054
1055
  		/* If we are *way* beyond the end of the file, print a message.
  		 * Access beyond the end of the file up to the next page boundary
  		 * is normal, however because of the way the page cache works.
  		 * In this case, we just return 0 so that we can properly fill
  		 * the page with useless information without generating any
  		 * I/O errors.
  		 */
  		if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) {
fde214d41   Jan Kara   isofs: Fix isofs_...
1056
1057
1058
1059
  			printk(KERN_DEBUG "%s: block >= EOF (%lu, %llu)
  ",
  				__func__, b_off,
  				(unsigned long long)inode->i_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
  			goto abort;
  		}
c3ed85a36   Dave Jones   isofs: fix up Cod...
1062

fb50ae744   Joel & Rebecca VanderZee   [PATCH] I/O Error...
1063
1064
1065
1066
1067
1068
1069
1070
1071
  		/* On the last section, nextblk == 0, section size is likely to
  		 * exceed sect_size by a partial block, and access beyond the
  		 * end of the file will reach beyond the section size, too.
  		 */
  		while (nextblk && (b_off >= (offset + sect_size))) {
  			struct inode *ninode;
  
  			offset += sect_size;
  			ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
c4386c83b   David Howells   iget: stop ISOFS ...
1072
1073
  			if (IS_ERR(ninode)) {
  				error = PTR_ERR(ninode);
fb50ae744   Joel & Rebecca VanderZee   [PATCH] I/O Error...
1074
  				goto abort;
c4386c83b   David Howells   iget: stop ISOFS ...
1075
  			}
fb50ae744   Joel & Rebecca VanderZee   [PATCH] I/O Error...
1076
1077
1078
1079
1080
1081
1082
  			firstext  = ISOFS_I(ninode)->i_first_extent;
  			sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
  			nextblk   = ISOFS_I(ninode)->i_next_section_block;
  			nextoff   = ISOFS_I(ninode)->i_next_section_offset;
  			iput(ninode);
  
  			if (++section > 100) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1083
1084
1085
  				printk(KERN_DEBUG "%s: More than 100 file sections ?!?"
  					" aborting...
  ", __func__);
fde214d41   Jan Kara   isofs: Fix isofs_...
1086
  				printk(KERN_DEBUG "%s: block=%lu firstext=%u sect_size=%u "
c3ed85a36   Dave Jones   isofs: fix up Cod...
1087
1088
  					"nextblk=%lu nextoff=%lu
  ", __func__,
fde214d41   Jan Kara   isofs: Fix isofs_...
1089
  					b_off, firstext, (unsigned) sect_size,
c3ed85a36   Dave Jones   isofs: fix up Cod...
1090
  					nextblk, nextoff);
fb50ae744   Joel & Rebecca VanderZee   [PATCH] I/O Error...
1091
  				goto abort;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1092
1093
  			}
  		}
c3ed85a36   Dave Jones   isofs: fix up Cod...
1094
1095
  
  		if (*bh) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1096
1097
1098
  			map_bh(*bh, inode->i_sb, firstext + b_off - offset);
  		} else {
  			*bh = sb_getblk(inode->i_sb, firstext+b_off-offset);
c3ed85a36   Dave Jones   isofs: fix up Cod...
1099
  			if (!*bh)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
1101
1102
1103
1104
1105
1106
  				goto abort;
  		}
  		bh++;	/* Next buffer head */
  		b_off++;	/* Next buffer offset */
  		nblocks--;
  		rv++;
  	}
c4386c83b   David Howells   iget: stop ISOFS ...
1107
  	error = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1108
  abort:
c4386c83b   David Howells   iget: stop ISOFS ...
1109
  	return rv != 0 ? rv : error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1110
1111
1112
1113
1114
1115
1116
1117
  }
  
  /*
   * Used by the standard interfaces.
   */
  static int isofs_get_block(struct inode *inode, sector_t iblock,
  		    struct buffer_head *bh_result, int create)
  {
c4386c83b   David Howells   iget: stop ISOFS ...
1118
  	int ret;
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1119
  	if (create) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1120
1121
  		printk(KERN_DEBUG "%s: Kernel tries to allocate a block
  ", __func__);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
1123
  		return -EROFS;
  	}
c4386c83b   David Howells   iget: stop ISOFS ...
1124
1125
  	ret = isofs_get_blocks(inode, iblock, &bh_result, 1);
  	return ret < 0 ? ret : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
  }
  
  static int isofs_bmap(struct inode *inode, sector_t block)
  {
  	struct buffer_head dummy;
  	int error;
  
  	dummy.b_state = 0;
  	dummy.b_blocknr = -1000;
  	error = isofs_get_block(inode, block, &dummy, 0);
  	if (!error)
  		return dummy.b_blocknr;
  	return 0;
  }
  
  struct buffer_head *isofs_bread(struct inode *inode, sector_t block)
  {
  	sector_t blknr = isofs_bmap(inode, block);
  	if (!blknr)
  		return NULL;
  	return sb_bread(inode->i_sb, blknr);
  }
  
  static int isofs_readpage(struct file *file, struct page *page)
  {
3069083cc   Namjae Jeon   isofs: add readpa...
1151
1152
1153
1154
1155
1156
1157
  	return mpage_readpage(page, isofs_get_block);
  }
  
  static int isofs_readpages(struct file *file, struct address_space *mapping,
  			struct list_head *pages, unsigned nr_pages)
  {
  	return mpage_readpages(mapping, pages, nr_pages, isofs_get_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1158
1159
1160
1161
1162
1163
  }
  
  static sector_t _isofs_bmap(struct address_space *mapping, sector_t block)
  {
  	return generic_block_bmap(mapping,block,isofs_get_block);
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
1164
  static const struct address_space_operations isofs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
  	.readpage = isofs_readpage,
3069083cc   Namjae Jeon   isofs: add readpa...
1166
  	.readpages = isofs_readpages,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1167
1168
  	.bmap = _isofs_bmap
  };
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1169
  static int isofs_read_level3_size(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1170
1171
1172
  {
  	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  	int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1173
  	struct buffer_head *bh = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
  	unsigned long block, offset, block_saved, offset_saved;
  	int i = 0;
  	int more_entries = 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1177
  	struct iso_directory_record *tmpde = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
  	struct iso_inode_info *ei = ISOFS_I(inode);
  
  	inode->i_size = 0;
  
  	/* The first 16 blocks are reserved as the System Area.  Thus,
  	 * no inodes can appear in block 0.  We use this to flag that
  	 * this is the last section. */
  	ei->i_next_section_block = 0;
  	ei->i_next_section_offset = 0;
  
  	block = ei->i_iget5_block;
  	offset = ei->i_iget5_offset;
  
  	do {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1192
  		struct iso_directory_record *de;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
  		unsigned int de_len;
  
  		if (!bh) {
  			bh = sb_bread(inode->i_sb, block);
  			if (!bh)
  				goto out_noread;
  		}
  		de = (struct iso_directory_record *) (bh->b_data + offset);
  		de_len = *(unsigned char *) de;
  
  		if (de_len == 0) {
  			brelse(bh);
  			bh = NULL;
  			++block;
  			offset = 0;
  			continue;
  		}
  
  		block_saved = block;
  		offset_saved = offset;
  		offset += de_len;
  
  		/* Make sure we have a full directory entry */
  		if (offset >= bufsize) {
  			int slop = bufsize - offset + de_len;
  			if (!tmpde) {
  				tmpde = kmalloc(256, GFP_KERNEL);
  				if (!tmpde)
  					goto out_nomem;
  			}
  			memcpy(tmpde, de, slop);
  			offset &= bufsize - 1;
  			block++;
  			brelse(bh);
  			bh = NULL;
  			if (offset) {
  				bh = sb_bread(inode->i_sb, block);
  				if (!bh)
  					goto out_noread;
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1232
  				memcpy((void *)tmpde+slop, bh->b_data, offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
  			}
  			de = tmpde;
  		}
  
  		inode->i_size += isonum_733(de->size);
  		if (i == 1) {
  			ei->i_next_section_block = block_saved;
  			ei->i_next_section_offset = offset_saved;
  		}
  
  		more_entries = de->flags[-high_sierra] & 0x80;
  
  		i++;
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1246
  		if (i > 100)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1247
  			goto out_toomany;
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1248
  	} while (more_entries);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1249
  out:
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1250
  	kfree(tmpde);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
  	if (bh)
  		brelse(bh);
  	return 0;
  
  out_nomem:
  	if (bh)
  		brelse(bh);
  	return -ENOMEM;
  
  out_noread:
  	printk(KERN_INFO "ISOFS: unable to read i-node block %lu
  ", block);
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
1263
  	kfree(tmpde);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1264
1265
1266
  	return -EIO;
  
  out_toomany:
c3ed85a36   Dave Jones   isofs: fix up Cod...
1267
1268
1269
1270
1271
  	printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...
  "
  		"isofs_read_level3_size: inode=%lu
  ",
  		__func__, inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1272
1273
  	goto out;
  }
c4386c83b   David Howells   iget: stop ISOFS ...
1274
  static int isofs_read_inode(struct inode *inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1275
1276
1277
1278
1279
1280
  {
  	struct super_block *sb = inode->i_sb;
  	struct isofs_sb_info *sbi = ISOFS_SB(sb);
  	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
  	unsigned long block;
  	int high_sierra = sbi->s_high_sierra;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1281
1282
1283
  	struct buffer_head *bh = NULL;
  	struct iso_directory_record *de;
  	struct iso_directory_record *tmpde = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1284
1285
1286
  	unsigned int de_len;
  	unsigned long offset;
  	struct iso_inode_info *ei = ISOFS_I(inode);
c4386c83b   David Howells   iget: stop ISOFS ...
1287
  	int ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
  
  	block = ei->i_iget5_block;
  	bh = sb_bread(inode->i_sb, block);
  	if (!bh)
  		goto out_badread;
  
  	offset = ei->i_iget5_offset;
  
  	de = (struct iso_directory_record *) (bh->b_data + offset);
  	de_len = *(unsigned char *) de;
  
  	if (offset + de_len > bufsize) {
  		int frag1 = bufsize - offset;
  
  		tmpde = kmalloc(de_len, GFP_KERNEL);
  		if (tmpde == NULL) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1304
1305
  			printk(KERN_INFO "%s: out of memory
  ", __func__);
c4386c83b   David Howells   iget: stop ISOFS ...
1306
  			ret = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
  			goto fail;
  		}
  		memcpy(tmpde, bh->b_data + offset, frag1);
  		brelse(bh);
  		bh = sb_bread(inode->i_sb, ++block);
  		if (!bh)
  			goto out_badread;
  		memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1);
  		de = tmpde;
  	}
  
  	inode->i_ino = isofs_get_ino(ei->i_iget5_block,
c3ed85a36   Dave Jones   isofs: fix up Cod...
1319
1320
  					ei->i_iget5_offset,
  					ISOFS_BUFFER_BITS(inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1321
1322
1323
1324
1325
  
  	/* Assume it is a normal-format file unless told otherwise */
  	ei->i_file_format = isofs_file_normal;
  
  	if (de->flags[-high_sierra] & 2) {
52b680c81   Jan Kara   isofs: let mode a...
1326
1327
1328
1329
  		if (sbi->s_dmode != ISOFS_INVALID_MODE)
  			inode->i_mode = S_IFDIR | sbi->s_dmode;
  		else
  			inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
bfe868486   Miklos Szeredi   filesystems: add ...
1330
  		set_nlink(inode, 1);	/*
c3ed85a36   Dave Jones   isofs: fix up Cod...
1331
1332
1333
1334
1335
1336
  					 * Set to 1.  We know there are 2, but
  					 * the find utility tries to optimize
  					 * if it is 2, and it screws up.  It is
  					 * easier to give 1 which tells find to
  					 * do it the hard way.
  					 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1337
  	} else {
52b680c81   Jan Kara   isofs: let mode a...
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
  		if (sbi->s_fmode != ISOFS_INVALID_MODE) {
  			inode->i_mode = S_IFREG | sbi->s_fmode;
  		} else {
  			/*
  			 * Set default permissions: r-x for all.  The disc
  			 * could be shared with DOS machines so virtually
  			 * anything could be a valid executable.
  			 */
  			inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO;
  		}
bfe868486   Miklos Szeredi   filesystems: add ...
1348
  		set_nlink(inode, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1349
1350
1351
  	}
  	inode->i_uid = sbi->s_uid;
  	inode->i_gid = sbi->s_gid;
ba52de123   Theodore Ts'o   [PATCH] inode-die...
1352
  	inode->i_blocks = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1353
1354
1355
1356
  
  	ei->i_format_parm[0] = 0;
  	ei->i_format_parm[1] = 0;
  	ei->i_format_parm[2] = 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1357
  	ei->i_section_size = isonum_733(de->size);
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1358
  	if (de->flags[-high_sierra] & 0x80) {
c4386c83b   David Howells   iget: stop ISOFS ...
1359
1360
  		ret = isofs_read_level3_size(inode);
  		if (ret < 0)
c3ed85a36   Dave Jones   isofs: fix up Cod...
1361
  			goto fail;
c4386c83b   David Howells   iget: stop ISOFS ...
1362
  		ret = -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1363
1364
1365
  	} else {
  		ei->i_next_section_block = 0;
  		ei->i_next_section_offset = 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1366
  		inode->i_size = isonum_733(de->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1367
1368
1369
1370
1371
1372
1373
  	}
  
  	/*
  	 * Some dipshit decided to store some other bit of information
  	 * in the high byte of the file length.  Truncate size in case
  	 * this CDROM was mounted with the cruft option.
  	 */
5404ac8e4   Jan Kara   isofs: cleanup mo...
1374
  	if (sbi->s_cruft)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1375
1376
1377
  		inode->i_size &= 0x00ffffff;
  
  	if (de->interleave[0]) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1378
1379
  		printk(KERN_DEBUG "ISOFS: Interleaved files not (yet) supported.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1380
1381
1382
1383
1384
1385
  		inode->i_size = 0;
  	}
  
  	/* I have no idea what file_unit_size is used for, so
  	   we will flag it for now */
  	if (de->file_unit_size[0] != 0) {
c3ed85a36   Dave Jones   isofs: fix up Cod...
1386
1387
1388
  		printk(KERN_DEBUG "ISOFS: File unit size != 0 for ISO file (%ld).
  ",
  			inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1389
1390
1391
1392
1393
1394
  	}
  
  	/* I have no idea what other flag bits are used for, so
  	   we will flag it for now */
  #ifdef DEBUG
  	if((de->flags[-high_sierra] & ~2)!= 0){
c3ed85a36   Dave Jones   isofs: fix up Cod...
1395
1396
1397
1398
  		printk(KERN_DEBUG "ISOFS: Unusual flag settings for ISO file "
  				"(%ld %x).
  ",
  			inode->i_ino, de->flags[-high_sierra]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1399
1400
1401
1402
1403
1404
1405
1406
1407
  	}
  #endif
  
  	inode->i_mtime.tv_sec =
  	inode->i_atime.tv_sec =
  	inode->i_ctime.tv_sec = iso_date(de->date, high_sierra);
  	inode->i_mtime.tv_nsec =
  	inode->i_atime.tv_nsec =
  	inode->i_ctime.tv_nsec = 0;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1408
1409
  	ei->i_first_extent = (isonum_733(de->extent) +
  			isonum_711(de->ext_attr_length));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1410
1411
  
  	/* Set the number of blocks for stat() - should be done before RR */
c3ed85a36   Dave Jones   isofs: fix up Cod...
1412
  	inode->i_blocks = (inode->i_size + 511) >> 9;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1413
1414
1415
1416
1417
1418
1419
1420
1421
  
  	/*
  	 * Now test for possible Rock Ridge extensions which will override
  	 * some of these numbers in the inode structure.
  	 */
  
  	if (!high_sierra) {
  		parse_rock_ridge_inode(de, inode);
  		/* if we want uid/gid set, override the rock ridge setting */
5c4a656b7   Jan Kara   isofs: fix settin...
1422
1423
1424
1425
  		if (sbi->s_uid_set)
  			inode->i_uid = sbi->s_uid;
  		if (sbi->s_gid_set)
  			inode->i_gid = sbi->s_gid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1426
  	}
52b680c81   Jan Kara   isofs: let mode a...
1427
1428
1429
1430
1431
1432
1433
  	/* Now set final access rights if overriding rock ridge setting */
  	if (S_ISDIR(inode->i_mode) && sbi->s_overriderockperm &&
  	    sbi->s_dmode != ISOFS_INVALID_MODE)
  		inode->i_mode = S_IFDIR | sbi->s_dmode;
  	if (S_ISREG(inode->i_mode) && sbi->s_overriderockperm &&
  	    sbi->s_fmode != ISOFS_INVALID_MODE)
  		inode->i_mode = S_IFREG | sbi->s_fmode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1434
1435
1436
1437
  
  	/* Install the inode operations vector */
  	if (S_ISREG(inode->i_mode)) {
  		inode->i_fop = &generic_ro_fops;
c3ed85a36   Dave Jones   isofs: fix up Cod...
1438
  		switch (ei->i_file_format) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
  #ifdef CONFIG_ZISOFS
  		case isofs_file_compressed:
  			inode->i_data.a_ops = &zisofs_aops;
  			break;
  #endif
  		default:
  			inode->i_data.a_ops = &isofs_aops;
  			break;
  		}
  	} else if (S_ISDIR(inode->i_mode)) {
  		inode->i_op = &isofs_dir_inode_operations;
  		inode->i_fop = &isofs_dir_operations;
  	} else if (S_ISLNK(inode->i_mode)) {
  		inode->i_op = &page_symlink_inode_operations;
  		inode->i_data.a_ops = &isofs_symlink_aops;
  	} else
  		/* XXX - parse_rock_ridge_inode() had already set i_rdev. */
  		init_special_inode(inode, inode->i_mode, inode->i_rdev);
c4386c83b   David Howells   iget: stop ISOFS ...
1457
  	ret = 0;
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1458
  out:
f99d49adf   Jesper Juhl   [PATCH] kfree cle...
1459
  	kfree(tmpde);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1460
1461
  	if (bh)
  		brelse(bh);
c4386c83b   David Howells   iget: stop ISOFS ...
1462
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1463

9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1464
  out_badread:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1465
1466
  	printk(KERN_WARNING "ISOFS: unable to read i-node block
  ");
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1467
  fail:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
  	goto out;
  }
  
  struct isofs_iget5_callback_data {
  	unsigned long block;
  	unsigned long offset;
  };
  
  static int isofs_iget5_test(struct inode *ino, void *data)
  {
  	struct iso_inode_info *i = ISOFS_I(ino);
  	struct isofs_iget5_callback_data *d =
  		(struct isofs_iget5_callback_data*)data;
  	return (i->i_iget5_block == d->block)
c3ed85a36   Dave Jones   isofs: fix up Cod...
1482
  		&& (i->i_iget5_offset == d->offset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
  }
  
  static int isofs_iget5_set(struct inode *ino, void *data)
  {
  	struct iso_inode_info *i = ISOFS_I(ino);
  	struct isofs_iget5_callback_data *d =
  		(struct isofs_iget5_callback_data*)data;
  	i->i_iget5_block = d->block;
  	i->i_iget5_offset = d->offset;
  	return 0;
  }
  
  /* Store, in the inode's containing structure, the block and block
   * offset that point to the underlying meta-data for the inode.  The
   * code below is otherwise similar to the iget() code in
   * include/linux/fs.h */
  struct inode *isofs_iget(struct super_block *sb,
  			 unsigned long block,
  			 unsigned long offset)
  {
  	unsigned long hashval;
  	struct inode *inode;
  	struct isofs_iget5_callback_data data;
c4386c83b   David Howells   iget: stop ISOFS ...
1506
  	long ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1507
1508
  
  	if (offset >= 1ul << sb->s_blocksize_bits)
c4386c83b   David Howells   iget: stop ISOFS ...
1509
  		return ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1510
1511
1512
1513
1514
  
  	data.block = block;
  	data.offset = offset;
  
  	hashval = (block << sb->s_blocksize_bits) | offset;
9eb7f2c67   Andrew Morton   [PATCH] isofs: re...
1515
  	inode = iget5_locked(sb, hashval, &isofs_iget5_test,
c3ed85a36   Dave Jones   isofs: fix up Cod...
1516
  				&isofs_iget5_set, &data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1517

c4386c83b   David Howells   iget: stop ISOFS ...
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  
  	if (inode->i_state & I_NEW) {
  		ret = isofs_read_inode(inode);
  		if (ret < 0) {
  			iget_failed(inode);
  			inode = ERR_PTR(ret);
  		} else {
  			unlock_new_inode(inode);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1529
1530
1531
1532
  	}
  
  	return inode;
  }
152a08366   Al Viro   new helper: mount...
1533
1534
  static struct dentry *isofs_mount(struct file_system_type *fs_type,
  	int flags, const char *dev_name, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1535
  {
152a08366   Al Viro   new helper: mount...
1536
  	return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1537
1538
1539
1540
1541
  }
  
  static struct file_system_type iso9660_fs_type = {
  	.owner		= THIS_MODULE,
  	.name		= "iso9660",
152a08366   Al Viro   new helper: mount...
1542
  	.mount		= isofs_mount,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
  	.kill_sb	= kill_block_super,
  	.fs_flags	= FS_REQUIRES_DEV,
  };
  
  static int __init init_iso9660_fs(void)
  {
  	int err = init_inodecache();
  	if (err)
  		goto out;
  #ifdef CONFIG_ZISOFS
  	err = zisofs_init();
  	if (err)
  		goto out1;
  #endif
  	err = register_filesystem(&iso9660_fs_type);
  	if (err)
  		goto out2;
  	return 0;
  out2:
  #ifdef CONFIG_ZISOFS
  	zisofs_cleanup();
  out1:
  #endif
  	destroy_inodecache();
  out:
  	return err;
  }
  
  static void __exit exit_iso9660_fs(void)
  {
          unregister_filesystem(&iso9660_fs_type);
  #ifdef CONFIG_ZISOFS
  	zisofs_cleanup();
  #endif
  	destroy_inodecache();
  }
  
  module_init(init_iso9660_fs)
  module_exit(exit_iso9660_fs)
  MODULE_LICENSE("GPL");
  /* Actual filesystem name is iso9660, as requested in filesystems.c */
  MODULE_ALIAS("iso9660");