| Start/ | End/ | |||
| True | False | - | Line | Source |
| 1 | /* | |||
| 2 | * linux/fs/isofs/inode.c | |||
| 3 | * | |||
| 4 | * (C) 1991 Linus Torvalds - minix filesystem | |||
| 5 | * 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem. | |||
| 6 | * 1994 Eberhard Moenkeberg - multi session handling. | |||
| 7 | * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. | |||
| 8 | * 1997 Gordon Chaffee - Joliet CDs | |||
| 9 | * 1998 Eric Lammerts - ISO 9660 Level 3 | |||
| 10 | * 2004 Paul Serice - Inode Support pushed out from 4GB to 128GB | |||
| 11 | * 2004 Paul Serice - NFS Export Operations | |||
| 12 | */ | |||
| 13 | ||||
| 14 | #include <linux/config.h> | |||
| 15 | #include <linux/init.h> | |||
| 16 | #include <linux/module.h> | |||
| 17 | ||||
| 18 | #include <linux/slab.h> | |||
| 19 | #include <linux/nls.h> | |||
| 20 | #include <linux/ctype.h> | |||
| 21 | #include <linux/smp_lock.h> | |||
| 22 | #include <linux/statfs.h> | |||
| 23 | #include <linux/cdrom.h> | |||
| 24 | #include <linux/parser.h> | |||
| 25 | ||||
| 26 | #include "isofs.h" | |||
| 27 | #include "zisofs.h" | |||
| 28 | ||||
| 29 | #define BEQUIET | |||
| 30 | ||||
| 31 | static int isofs_hashi(struct dentry *parent, struct qstr *qstr); | |||
| 32 | static int isofs_hash(struct dentry *parent, struct qstr *qstr); | |||
| 33 | static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); | |||
| 34 | static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); | |||
| 35 | ||||
| 36 | #ifdef CONFIG_JOLIET | |||
| 37 | static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr); | |||
| 38 | static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr); | |||
| 39 | static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); | |||
| 40 | static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); | |||
| 41 | #endif | |||
| 42 | ||||
| 0 | 0 | - | 43 | static void isofs_put_super(struct super_block *sb) |
| 44 | { | |||
| 45 | struct isofs_sb_info *sbi = ISOFS_SB(sb); | |||
| 46 | #ifdef CONFIG_JOLIET | |||
| 0 | 0 | - | 47 | if (sbi->s_nls_iocharset) { |
| 48 | unload_nls(sbi->s_nls_iocharset); | |||
| 49 | sbi->s_nls_iocharset = NULL; | |||
| 50 | } | |||
| 51 | #endif | |||
| 52 | ||||
| 53 | kfree(sbi); | |||
| 54 | sb->s_fs_info = NULL; | |||
| 0 | - | 55 | return; | |
| 56 | } | |||
| 57 | ||||
| 58 | static void isofs_read_inode(struct inode *); | |||
| 59 | static int isofs_statfs (struct super_block *, struct kstatfs *); | |||
| 60 | ||||
| 61 | static kmem_cache_t *isofs_inode_cachep; | |||
| 62 | ||||
| 0 | 0 | - | 63 | static struct inode *isofs_alloc_inode(struct super_block *sb) |
| 64 | { | |||
| 65 | struct iso_inode_info *ei; | |||
| 66 | ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); | |||
| 0 | 0 | - | 67 | if (!ei) |
| 0 | - | 68 | return NULL; | |
| 0 | - | 69 | return &ei->vfs_inode; | |
| 70 | } | |||
| 71 | ||||
| 0 | 0 | - | 72 | static void isofs_destroy_inode(struct inode *inode) |
| 73 | { | |||
| 74 | kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); | |||
| 75 | } | |||
| 76 | ||||
| 0 | 0 | - | 77 | static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) |
| 78 | { | |||
| 79 | struct iso_inode_info *ei = foo; | |||
| 80 | ||||
| 81 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | |||
| 0 | 0 | - | 82 | SLAB_CTOR_CONSTRUCTOR) |
| 83 | inode_init_once(&ei->vfs_inode); | |||
| 84 | } | |||
| 85 | ||||
| 6 | 0 | 86 | static int init_inodecache(void) | |
| 87 | { | |||
| 88 | isofs_inode_cachep = kmem_cache_create("isofs_inode_cache", | |||
| 89 | sizeof(struct iso_inode_info), | |||
| 90 | 0, SLAB_RECLAIM_ACCOUNT, | |||
| 91 | init_once, NULL); | |||
| 0 | 6 | - | 92 | if (isofs_inode_cachep == NULL) |
| 0 | - | 93 | return -ENOMEM; | |
| 6 | 94 | return 0; | ||
| 95 | } | |||
| 96 | ||||
| 0 | 0 | - | 97 | static void destroy_inodecache(void) |
| 98 | { | |||
| 0 | 0 | - | 99 | if (kmem_cache_destroy(isofs_inode_cachep)) |
| 100 | printk(KERN_INFO "iso_inode_cache: not all structures were " | |||
| 101 | "freed\n"); | |||
| 102 | } | |||
| 103 | ||||
| 0 | 0 | - | 104 | static int isofs_remount(struct super_block *sb, int *flags, char *data) |
| 105 | { | |||
| 106 | /* we probably want a lot more here */ | |||
| 107 | *flags |= MS_RDONLY; | |||
| 0 | - | 108 | return 0; | |
| 109 | } | |||
| 110 | ||||
| 111 | static struct super_operations isofs_sops = { | |||
| 112 | .alloc_inode = isofs_alloc_inode, | |||
| 113 | .destroy_inode = isofs_destroy_inode, | |||
| 114 | .read_inode = isofs_read_inode, | |||
| 115 | .put_super = isofs_put_super, | |||
| 116 | .statfs = isofs_statfs, | |||
| 117 | .remount_fs = isofs_remount, | |||
| 118 | }; | |||
| 119 | ||||
| 120 | ||||
| 121 | static struct dentry_operations isofs_dentry_ops[] = { | |||
| 122 | { | |||
| 123 | .d_hash = isofs_hash, | |||
| 124 | .d_compare = isofs_dentry_cmp, | |||
| 125 | }, | |||
| 126 | { | |||
| 127 | .d_hash = isofs_hashi, | |||
| 128 | .d_compare = isofs_dentry_cmpi, | |||
| 129 | }, | |||
| 130 | #ifdef CONFIG_JOLIET | |||
| 131 | { | |||
| 132 | .d_hash = isofs_hash_ms, | |||
| 133 | .d_compare = isofs_dentry_cmp_ms, | |||
| 134 | }, | |||
| 135 | { | |||
| 136 | .d_hash = isofs_hashi_ms, | |||
| 137 | .d_compare = isofs_dentry_cmpi_ms, | |||
| 138 | }, | |||
| 139 | #endif | |||
| 140 | }; | |||
| 141 | ||||
| 142 | struct iso9660_options{ | |||
| 143 | char map; | |||
| 144 | char rock; | |||
| 145 | char joliet; | |||
| 146 | char cruft; | |||
| 147 | char hide; | |||
| 148 | char showassoc; | |||
| 149 | char nocompress; | |||
| 150 | unsigned char check; | |||
| 151 | unsigned int blocksize; | |||
| 152 | mode_t mode; | |||
| 153 | gid_t gid; | |||
| 154 | uid_t uid; | |||
| 155 | char *iocharset; | |||
| 156 | unsigned char utf8; | |||
| 157 | /* LVE */ | |||
| 158 | s32 session; | |||
| 159 | s32 sbsector; | |||
| 160 | }; | |||
| 161 | ||||
| 162 | /* | |||
| 163 | * Compute the hash for the isofs name corresponding to the dentry. | |||
| 164 | */ | |||
| 165 | static int | |||
| 0 | 0 | - | 166 | isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms) |
| 167 | { | |||
| 168 | const char *name; | |||
| 169 | int len; | |||
| 170 | ||||
| 171 | len = qstr->len; | |||
| 172 | name = qstr->name; | |||
| 0 | 0 | - | 173 | if (ms) { |
| 0 | 0 | - | 174 | while (len && name[len-1] == '.') |
| 0 | - | 174 | T && T | |
| 0 | - | 174 | T && F | |
| 0 | - | 174 | F && _ | |
| 175 | len--; | |||
| 176 | } | |||
| 177 | ||||
| 178 | qstr->hash = full_name_hash(name, len); | |||
| 179 | ||||
| 0 | - | 180 | return 0; | |
| 181 | } | |||
| 182 | ||||
| 183 | /* | |||
| 184 | * Compute the hash for the isofs name corresponding to the dentry. | |||
| 185 | */ | |||
| 186 | static int | |||
| 0 | 0 | - | 187 | isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) |
| 188 | { | |||
| 189 | const char *name; | |||
| 190 | int len; | |||
| 191 | char c; | |||
| 192 | unsigned long hash; | |||
| 193 | ||||
| 194 | len = qstr->len; | |||
| 195 | name = qstr->name; | |||
| 0 | 0 | - | 196 | if (ms) { |
| 0 | 0 | - | 197 | while (len && name[len-1] == '.') |
| 0 | - | 197 | T && T | |
| 0 | - | 197 | T && F | |
| 0 | - | 197 | F && _ | |
| 198 | len--; | |||
| 199 | } | |||
| 200 | ||||
| 201 | hash = init_name_hash(); | |||
| 0 | 0 | - | 202 | while (len--) { |
| 203 | c = tolower(*name++); | |||
| 204 | hash = partial_name_hash(tolower(c), hash); | |||
| 205 | } | |||
| 206 | qstr->hash = end_name_hash(hash); | |||
| 207 | ||||
| 0 | - | 208 | return 0; | |
| 209 | } | |||
| 210 | ||||
| 211 | /* | |||
| 212 | * Case insensitive compare of two isofs names. | |||
| 213 | */ | |||
| 0 | 0 | - | 214 | static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, |
| 215 | struct qstr *b, int ms) | |||
| 216 | { | |||
| 217 | int alen, blen; | |||
| 218 | ||||
| 219 | /* A filename cannot end in '.' or we treat it like it has none */ | |||
| 220 | alen = a->len; | |||
| 221 | blen = b->len; | |||
| 0 | 0 | - | 222 | if (ms) { |
| 0 | 0 | - | 223 | while (alen && a->name[alen-1] == '.') |
| 0 | - | 223 | T && T | |
| 0 | - | 223 | T && F | |
| 0 | - | 223 | F && _ | |
| 224 | alen--; | |||
| 0 | 0 | - | 225 | while (blen && b->name[blen-1] == '.') |
| 0 | - | 225 | T && T | |
| 0 | - | 225 | T && F | |
| 0 | - | 225 | F && _ | |
| 226 | blen--; | |||
| 227 | } | |||
| 0 | 0 | - | 228 | if (alen == blen) { |
| 0 | 0 | - | 229 | if (strnicmp(a->name, b->name, alen) == 0) |
| 0 | - | 230 | return 0; | |
| 231 | } | |||
| 0 | - | 232 | return 1; | |
| 233 | } | |||
| 234 | ||||
| 235 | /* | |||
| 236 | * Case sensitive compare of two isofs names. | |||
| 237 | */ | |||
| 0 | 0 | - | 238 | static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a, |
| 239 | struct qstr *b, int ms) | |||
| 240 | { | |||
| 241 | int alen, blen; | |||
| 242 | ||||
| 243 | /* A filename cannot end in '.' or we treat it like it has none */ | |||
| 244 | alen = a->len; | |||
| 245 | blen = b->len; | |||
| 0 | 0 | - | 246 | if (ms) { |
| 0 | 0 | - | 247 | while (alen && a->name[alen-1] == '.') |
| 0 | - | 247 | T && T | |
| 0 | - | 247 | T && F | |
| 0 | - | 247 | F && _ | |
| 248 | alen--; | |||
| 0 | 0 | - | 249 | while (blen && b->name[blen-1] == '.') |
| 0 | - | 249 | T && T | |
| 0 | - | 249 | T && F | |
| 0 | - | 249 | F && _ | |
| 250 | blen--; | |||
| 251 | } | |||
| 0 | 0 | - | 252 | if (alen == blen) { |
| 0 | 0 | - | 253 | if (strncmp(a->name, b->name, alen) == 0) |
| 0 | - | 254 | return 0; | |
| 255 | } | |||
| 0 | - | 256 | return 1; | |
| 257 | } | |||
| 258 | ||||
| 259 | static int | |||
| 0 | 0 | - | 260 | isofs_hash(struct dentry *dentry, struct qstr *qstr) |
| 261 | { | |||
| 0 | - | 262 | return isofs_hash_common(dentry, qstr, 0); | |
| 263 | } | |||
| 264 | ||||
| 265 | static int | |||
| 0 | 0 | - | 266 | isofs_hashi(struct dentry *dentry, struct qstr *qstr) |
| 267 | { | |||
| 0 | - | 268 | return isofs_hashi_common(dentry, qstr, 0); | |
| 269 | } | |||
| 270 | ||||
| 271 | static int | |||
| 0 | 0 | - | 272 | isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b) |
| 273 | { | |||
| 0 | - | 274 | return isofs_dentry_cmp_common(dentry, a, b, 0); | |
| 275 | } | |||
| 276 | ||||
| 277 | static int | |||
| 0 | 0 | - | 278 | isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b) |
| 279 | { | |||
| 0 | - | 280 | return isofs_dentry_cmpi_common(dentry, a, b, 0); | |
| 281 | } | |||
| 282 | ||||
| 283 | #ifdef CONFIG_JOLIET | |||
| 284 | static int | |||
| 0 | 0 | - | 285 | isofs_hash_ms(struct dentry *dentry, struct qstr *qstr) |
| 286 | { | |||
| 0 | - | 287 | return isofs_hash_common(dentry, qstr, 1); | |
| 288 | } | |||
| 289 | ||||
| 290 | static int | |||
| 0 | 0 | - | 291 | isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr) |
| 292 | { | |||
| 0 | - | 293 | return isofs_hashi_common(dentry, qstr, 1); | |
| 294 | } | |||
| 295 | ||||
| 296 | static int | |||
| 0 | 0 | - | 297 | isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) |
| 298 | { | |||
| 0 | - | 299 | return isofs_dentry_cmp_common(dentry, a, b, 1); | |
| 300 | } | |||
| 301 | ||||
| 302 | static int | |||
| 0 | 0 | - | 303 | isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) |
| 304 | { | |||
| 0 | - | 305 | return isofs_dentry_cmpi_common(dentry, a, b, 1); | |
| 306 | } | |||
| 307 | #endif | |||
| 308 | ||||
| 309 | enum { | |||
| 310 | Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, | |||
| 311 | Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, | |||
| 312 | Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, | |||
| 313 | Opt_nocompress, Opt_hide, Opt_showassoc, | |||
| 314 | }; | |||
| 315 | ||||
| 316 | static match_table_t tokens = { | |||
| 317 | {Opt_norock, "norock"}, | |||
| 318 | {Opt_nojoliet, "nojoliet"}, | |||
| 319 | {Opt_unhide, "unhide"}, | |||
| 320 | {Opt_hide, "hide"}, | |||
| 321 | {Opt_showassoc, "showassoc"}, | |||
| 322 | {Opt_cruft, "cruft"}, | |||
| 323 | {Opt_utf8, "utf8"}, | |||
| 324 | {Opt_iocharset, "iocharset=%s"}, | |||
| 325 | {Opt_map_a, "map=acorn"}, | |||
| 326 | {Opt_map_a, "map=a"}, | |||
| 327 | {Opt_map_n, "map=normal"}, | |||
| 328 | {Opt_map_n, "map=n"}, | |||
| 329 | {Opt_map_o, "map=off"}, | |||
| 330 | {Opt_map_o, "map=o"}, | |||
| 331 | {Opt_session, "session=%u"}, | |||
| 332 | {Opt_sb, "sbsector=%u"}, | |||
| 333 | {Opt_check_r, "check=relaxed"}, | |||
| 334 | {Opt_check_r, "check=r"}, | |||
| 335 | {Opt_check_s, "check=strict"}, | |||
| 336 | {Opt_check_s, "check=s"}, | |||
| 337 | {Opt_uid, "uid=%u"}, | |||
| 338 | {Opt_gid, "gid=%u"}, | |||
| 339 | {Opt_mode, "mode=%u"}, | |||
| 340 | {Opt_block, "block=%u"}, | |||
| 341 | {Opt_ignore, "conv=binary"}, | |||
| 342 | {Opt_ignore, "conv=b"}, | |||
| 343 | {Opt_ignore, "conv=text"}, | |||
| 344 | {Opt_ignore, "conv=t"}, | |||
| 345 | {Opt_ignore, "conv=mtext"}, | |||
| 346 | {Opt_ignore, "conv=m"}, | |||
| 347 | {Opt_ignore, "conv=auto"}, | |||
| 348 | {Opt_ignore, "conv=a"}, | |||
| 349 | {Opt_nocompress, "nocompress"}, | |||
| 350 | {Opt_err, NULL} | |||
| 351 | }; | |||
| 352 | ||||
| 0 | 0 | - | 353 | static int parse_options(char *options, struct iso9660_options *popt) |
| 354 | { | |||
| 355 | char *p; | |||
| 356 | int option; | |||
| 357 | ||||
| 358 | popt->map = 'n'; | |||
| 359 | popt->rock = 'y'; | |||
| 360 | popt->joliet = 'y'; | |||
| 361 | popt->cruft = 'n'; | |||
| 362 | popt->hide = 'n'; | |||
| 363 | popt->showassoc = 'n'; | |||
| 364 | popt->check = 'u'; /* unset */ | |||
| 365 | popt->nocompress = 0; | |||
| 366 | popt->blocksize = 1024; | |||
| 367 | popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could | |||
| 368 | be shared with DOS machines so | |||
| 369 | virtually anything could be | |||
| 370 | a valid executable. */ | |||
| 371 | popt->gid = 0; | |||
| 372 | popt->uid = 0; | |||
| 373 | popt->iocharset = NULL; | |||
| 374 | popt->utf8 = 0; | |||
| 375 | popt->session=-1; | |||
| 376 | popt->sbsector=-1; | |||
| 0 | 0 | - | 377 | if (!options) |
| 0 | - | 378 | return 1; | |
| 379 | ||||
| 0 | 0 | - | 380 | while ((p = strsep(&options, ",")) != NULL) { |
| 381 | int token; | |||
| 382 | substring_t args[MAX_OPT_ARGS]; | |||
| 383 | unsigned n; | |||
| 384 | ||||
| 0 | 0 | - | 385 | if (!*p) |
| 0 | - | 386 | continue; | |
| 387 | ||||
| 388 | token = match_token(p, tokens, args); | |||
| 389 | switch (token) { | |||
| 0 | - | 390 | case Opt_norock: | |
| 391 | popt->rock = 'n'; | |||
| 0 | - | 392 | break; | |
| 0 | - | 393 | case Opt_nojoliet: | |
| 394 | popt->joliet = 'n'; | |||
| 0 | - | 395 | break; | |
| 0 | - | 396 | case Opt_hide: | |
| 397 | popt->hide = 'y'; | |||
| 0 | - | 398 | break; | |
| 0 | - | 399 | case Opt_unhide: | |
| 0 | - | 400 | case Opt_showassoc: | |
| 401 | popt->showassoc = 'y'; | |||
| 0 | - | 402 | break; | |
| 0 | - | 403 | case Opt_cruft: | |
| 404 | popt->cruft = 'y'; | |||
| 0 | - | 405 | break; | |
| 0 | - | 406 | case Opt_utf8: | |
| 407 | popt->utf8 = 1; | |||
| 0 | - | 408 | break; | |
| 409 | #ifdef CONFIG_JOLIET | |||
| 0 | - | 410 | case Opt_iocharset: | |
| 411 | popt->iocharset = match_strdup(&args[0]); | |||
| 0 | - | 412 | break; | |
| 413 | #endif | |||
| 0 | - | 414 | case Opt_map_a: | |
| 415 | popt->map = 'a'; | |||
| 0 | - | 416 | break; | |
| 0 | - | 417 | case Opt_map_o: | |
| 418 | popt->map = 'o'; | |||
| 0 | - | 419 | break; | |
| 0 | - | 420 | case Opt_map_n: | |
| 421 | popt->map = 'n'; | |||
| 0 | - | 422 | break; | |
| 0 | - | 423 | case Opt_session: | |
| 0 | 0 | - | 424 | if (match_int(&args[0], &option)) |
| 0 | - | 425 | return 0; | |
| 426 | n = option; | |||
| 0 | 0 | - | 427 | if (n > 99) |
| 0 | - | 428 | return 0; | |
| 429 | popt->session = n + 1; | |||
| 0 | - | 430 | break; | |
| 0 | - | 431 | case Opt_sb: | |
| 0 | 0 | - | 432 | if (match_int(&args[0], &option)) |
| 0 | - | 433 | return 0; | |
| 434 | popt->sbsector = option; | |||
| 0 | - | 435 | break; | |
| 0 | - | 436 | case Opt_check_r: | |
| 437 | popt->check = 'r'; | |||
| 0 | - | 438 | break; | |
| 0 | - | 439 | case Opt_check_s: | |
| 440 | popt->check = 's'; | |||
| 0 | - | 441 | break; | |
| 0 | - | 442 | case Opt_ignore: | |
| 0 | - | 443 | break; | |
| 0 | - | 444 | case Opt_uid: | |
| 0 | 0 | - | 445 | if (match_int(&args[0], &option)) |
| 0 | - | 446 | return 0; | |
| 447 | popt->uid = option; | |||
| 0 | - | 448 | break; | |
| 0 | - | 449 | case Opt_gid: | |
| 0 | 0 | - | 450 | if (match_int(&args[0], &option)) |
| 0 | - | 451 | return 0; | |
| 452 | popt->gid = option; | |||
| 0 | - | 453 | break; | |
| 0 | - | 454 | case Opt_mode: | |
| 0 | 0 | - | 455 | if (match_int(&args[0], &option)) |
| 0 | - | 456 | return 0; | |
| 457 | popt->mode = option; | |||
| 0 | - | 458 | break; | |
| 0 | - | 459 | case Opt_block: | |
| 0 | 0 | - | 460 | if (match_int(&args[0], &option)) |
| 0 | - | 461 | return 0; | |
| 462 | n = option; | |||
| 0 | 0 | - | 463 | if (n != 512 && n != 1024 && n != 2048) |
| 0 | - | 463 | T && T && T | |
| 0 | - | 463 | T && T && F | |
| 0 | - | 463 | T && F && _ | |
| 0 | - | 463 | F && _ && _ | |
| 0 | - | 464 | return 0; | |
| 465 | popt->blocksize = n; | |||
| 0 | - | 466 | break; | |
| 0 | - | 467 | case Opt_nocompress: | |
| 468 | popt->nocompress = 1; | |||
| 0 | - | 469 | break; | |
| 0 | - | 470 | default: | |
| 0 | - | 471 | return 0; | |
| 472 | } | |||
| 473 | } | |||
| 0 | - | 474 | return 1; | |
| 475 | } | |||
| 476 | ||||
| 477 | /* | |||
| 478 | * look if the driver can tell the multi session redirection value | |||
| 479 | * | |||
| 480 | * don't change this if you don't know what you do, please! | |||
| 481 | * Multisession is legal only with XA disks. | |||
| 482 | * A non-XA disk with more than one volume descriptor may do it right, but | |||
| 483 | * usually is written in a nowhere standardized "multi-partition" manner. | |||
| 484 | * Multisession uses absolute addressing (solely the first frame of the whole | |||
| 485 | * track is #0), multi-partition uses relative addressing (each first frame of | |||
| 486 | * each track is #0), and a track is not a session. | |||
| 487 | * | |||
| 488 | * A broken CDwriter software or drive firmware does not set new standards, | |||
| 489 | * at least not if conflicting with the existing ones. | |||
| 490 | * | |||
| 491 | * emoenke@gwdg.de | |||
| 492 | */ | |||
| 493 | #define WE_OBEY_THE_WRITTEN_STANDARDS 1 | |||
| 494 | ||||
| 0 | 0 | - | 495 | static unsigned int isofs_get_last_session(struct super_block *sb, s32 session) |
| 496 | { | |||
| 497 | struct cdrom_multisession ms_info; | |||
| 498 | unsigned int vol_desc_start; | |||
| 499 | struct block_device *bdev = sb->s_bdev; | |||
| 500 | int i; | |||
| 501 | ||||
| 502 | vol_desc_start=0; | |||
| 503 | ms_info.addr_format=CDROM_LBA; | |||
| 0 | 0 | - | 504 | if(session >= 0 && session <= 99) { |
| 0 | - | 504 | T && T | |
| 0 | - | 504 | T && F | |
| 0 | - | 504 | F && _ | |
| 505 | struct cdrom_tocentry Te; | |||
| 506 | Te.cdte_track=session; | |||