11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/isofs/inode.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * (C) 1991 Linus Torvalds - minix filesystem 51da177e4SLinus Torvalds * 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem. 61da177e4SLinus Torvalds * 1994 Eberhard Moenkeberg - multi session handling. 71da177e4SLinus Torvalds * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. 81da177e4SLinus Torvalds * 1997 Gordon Chaffee - Joliet CDs 91da177e4SLinus Torvalds * 1998 Eric Lammerts - ISO 9660 Level 3 101da177e4SLinus Torvalds * 2004 Paul Serice - Inode Support pushed out from 4GB to 128GB 111da177e4SLinus Torvalds * 2004 Paul Serice - NFS Export Operations 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/config.h> 1594f2f715SAl Viro #include <linux/init.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds 181da177e4SLinus Torvalds #include <linux/slab.h> 191da177e4SLinus Torvalds #include <linux/nls.h> 201da177e4SLinus Torvalds #include <linux/ctype.h> 211da177e4SLinus Torvalds #include <linux/smp_lock.h> 2294f2f715SAl Viro #include <linux/statfs.h> 2394f2f715SAl Viro #include <linux/cdrom.h> 241da177e4SLinus Torvalds #include <linux/parser.h> 251da177e4SLinus Torvalds 2694f2f715SAl Viro #include "isofs.h" 271da177e4SLinus Torvalds #include "zisofs.h" 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #define BEQUIET 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds static int isofs_hashi(struct dentry *parent, struct qstr *qstr); 321da177e4SLinus Torvalds static int isofs_hash(struct dentry *parent, struct qstr *qstr); 331da177e4SLinus Torvalds static int isofs_dentry_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b); 341da177e4SLinus Torvalds static int isofs_dentry_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 371da177e4SLinus Torvalds static int isofs_hashi_ms(struct dentry *parent, struct qstr *qstr); 381da177e4SLinus Torvalds static int isofs_hash_ms(struct dentry *parent, struct qstr *qstr); 391da177e4SLinus Torvalds static int isofs_dentry_cmpi_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); 401da177e4SLinus Torvalds static int isofs_dentry_cmp_ms(struct dentry *dentry, struct qstr *a, struct qstr *b); 411da177e4SLinus Torvalds #endif 421da177e4SLinus Torvalds 431da177e4SLinus Torvalds static void isofs_put_super(struct super_block *sb) 441da177e4SLinus Torvalds { 451da177e4SLinus Torvalds struct isofs_sb_info *sbi = ISOFS_SB(sb); 461da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 471da177e4SLinus Torvalds if (sbi->s_nls_iocharset) { 481da177e4SLinus Torvalds unload_nls(sbi->s_nls_iocharset); 491da177e4SLinus Torvalds sbi->s_nls_iocharset = NULL; 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds #endif 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds kfree(sbi); 541da177e4SLinus Torvalds sb->s_fs_info = NULL; 551da177e4SLinus Torvalds return; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static void isofs_read_inode(struct inode *); 591da177e4SLinus Torvalds static int isofs_statfs (struct super_block *, struct kstatfs *); 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds static kmem_cache_t *isofs_inode_cachep; 621da177e4SLinus Torvalds 631da177e4SLinus Torvalds static struct inode *isofs_alloc_inode(struct super_block *sb) 641da177e4SLinus Torvalds { 651da177e4SLinus Torvalds struct iso_inode_info *ei; 669eb7f2c6SAndrew Morton ei = kmem_cache_alloc(isofs_inode_cachep, SLAB_KERNEL); 671da177e4SLinus Torvalds if (!ei) 681da177e4SLinus Torvalds return NULL; 691da177e4SLinus Torvalds return &ei->vfs_inode; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds static void isofs_destroy_inode(struct inode *inode) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); 751da177e4SLinus Torvalds } 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags) 781da177e4SLinus Torvalds { 799eb7f2c6SAndrew Morton struct iso_inode_info *ei = foo; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == 821da177e4SLinus Torvalds SLAB_CTOR_CONSTRUCTOR) 831da177e4SLinus Torvalds inode_init_once(&ei->vfs_inode); 841da177e4SLinus Torvalds } 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds static int init_inodecache(void) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds isofs_inode_cachep = kmem_cache_create("isofs_inode_cache", 891da177e4SLinus Torvalds sizeof(struct iso_inode_info), 901da177e4SLinus Torvalds 0, SLAB_RECLAIM_ACCOUNT, 911da177e4SLinus Torvalds init_once, NULL); 921da177e4SLinus Torvalds if (isofs_inode_cachep == NULL) 931da177e4SLinus Torvalds return -ENOMEM; 941da177e4SLinus Torvalds return 0; 951da177e4SLinus Torvalds } 961da177e4SLinus Torvalds 971da177e4SLinus Torvalds static void destroy_inodecache(void) 981da177e4SLinus Torvalds { 991da177e4SLinus Torvalds if (kmem_cache_destroy(isofs_inode_cachep)) 1009eb7f2c6SAndrew Morton printk(KERN_INFO "iso_inode_cache: not all structures were " 1019eb7f2c6SAndrew Morton "freed\n"); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds static int isofs_remount(struct super_block *sb, int *flags, char *data) 1051da177e4SLinus Torvalds { 1061da177e4SLinus Torvalds /* we probably want a lot more here */ 1071da177e4SLinus Torvalds *flags |= MS_RDONLY; 1081da177e4SLinus Torvalds return 0; 1091da177e4SLinus Torvalds } 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds static struct super_operations isofs_sops = { 1121da177e4SLinus Torvalds .alloc_inode = isofs_alloc_inode, 1131da177e4SLinus Torvalds .destroy_inode = isofs_destroy_inode, 1141da177e4SLinus Torvalds .read_inode = isofs_read_inode, 1151da177e4SLinus Torvalds .put_super = isofs_put_super, 1161da177e4SLinus Torvalds .statfs = isofs_statfs, 1171da177e4SLinus Torvalds .remount_fs = isofs_remount, 1181da177e4SLinus Torvalds }; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds static struct dentry_operations isofs_dentry_ops[] = { 1221da177e4SLinus Torvalds { 1231da177e4SLinus Torvalds .d_hash = isofs_hash, 1241da177e4SLinus Torvalds .d_compare = isofs_dentry_cmp, 1251da177e4SLinus Torvalds }, 1261da177e4SLinus Torvalds { 1271da177e4SLinus Torvalds .d_hash = isofs_hashi, 1281da177e4SLinus Torvalds .d_compare = isofs_dentry_cmpi, 1291da177e4SLinus Torvalds }, 1301da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 1311da177e4SLinus Torvalds { 1321da177e4SLinus Torvalds .d_hash = isofs_hash_ms, 1331da177e4SLinus Torvalds .d_compare = isofs_dentry_cmp_ms, 1341da177e4SLinus Torvalds }, 1351da177e4SLinus Torvalds { 1361da177e4SLinus Torvalds .d_hash = isofs_hashi_ms, 1371da177e4SLinus Torvalds .d_compare = isofs_dentry_cmpi_ms, 1389eb7f2c6SAndrew Morton }, 1391da177e4SLinus Torvalds #endif 1401da177e4SLinus Torvalds }; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds struct iso9660_options{ 1431da177e4SLinus Torvalds char map; 1441da177e4SLinus Torvalds char rock; 1451da177e4SLinus Torvalds char joliet; 1461da177e4SLinus Torvalds char cruft; 147*9769f4ebSJeremy White char hide; 148*9769f4ebSJeremy White char showassoc; 1491da177e4SLinus Torvalds char nocompress; 1501da177e4SLinus Torvalds unsigned char check; 1511da177e4SLinus Torvalds unsigned int blocksize; 1521da177e4SLinus Torvalds mode_t mode; 1531da177e4SLinus Torvalds gid_t gid; 1541da177e4SLinus Torvalds uid_t uid; 1551da177e4SLinus Torvalds char *iocharset; 1561da177e4SLinus Torvalds unsigned char utf8; 1571da177e4SLinus Torvalds /* LVE */ 1581da177e4SLinus Torvalds s32 session; 1591da177e4SLinus Torvalds s32 sbsector; 1601da177e4SLinus Torvalds }; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds /* 1631da177e4SLinus Torvalds * Compute the hash for the isofs name corresponding to the dentry. 1641da177e4SLinus Torvalds */ 1651da177e4SLinus Torvalds static int 1661da177e4SLinus Torvalds isofs_hash_common(struct dentry *dentry, struct qstr *qstr, int ms) 1671da177e4SLinus Torvalds { 1681da177e4SLinus Torvalds const char *name; 1691da177e4SLinus Torvalds int len; 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds len = qstr->len; 1721da177e4SLinus Torvalds name = qstr->name; 1731da177e4SLinus Torvalds if (ms) { 1741da177e4SLinus Torvalds while (len && name[len-1] == '.') 1751da177e4SLinus Torvalds len--; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds qstr->hash = full_name_hash(name, len); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds return 0; 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds /* 1841da177e4SLinus Torvalds * Compute the hash for the isofs name corresponding to the dentry. 1851da177e4SLinus Torvalds */ 1861da177e4SLinus Torvalds static int 1871da177e4SLinus Torvalds isofs_hashi_common(struct dentry *dentry, struct qstr *qstr, int ms) 1881da177e4SLinus Torvalds { 1891da177e4SLinus Torvalds const char *name; 1901da177e4SLinus Torvalds int len; 1911da177e4SLinus Torvalds char c; 1921da177e4SLinus Torvalds unsigned long hash; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds len = qstr->len; 1951da177e4SLinus Torvalds name = qstr->name; 1961da177e4SLinus Torvalds if (ms) { 1971da177e4SLinus Torvalds while (len && name[len-1] == '.') 1981da177e4SLinus Torvalds len--; 1991da177e4SLinus Torvalds } 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds hash = init_name_hash(); 2021da177e4SLinus Torvalds while (len--) { 2031da177e4SLinus Torvalds c = tolower(*name++); 2041da177e4SLinus Torvalds hash = partial_name_hash(tolower(c), hash); 2051da177e4SLinus Torvalds } 2061da177e4SLinus Torvalds qstr->hash = end_name_hash(hash); 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds return 0; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds /* 2121da177e4SLinus Torvalds * Case insensitive compare of two isofs names. 2131da177e4SLinus Torvalds */ 2149eb7f2c6SAndrew Morton static int isofs_dentry_cmpi_common(struct dentry *dentry, struct qstr *a, 2159eb7f2c6SAndrew Morton struct qstr *b, int ms) 2161da177e4SLinus Torvalds { 2171da177e4SLinus Torvalds int alen, blen; 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /* A filename cannot end in '.' or we treat it like it has none */ 2201da177e4SLinus Torvalds alen = a->len; 2211da177e4SLinus Torvalds blen = b->len; 2221da177e4SLinus Torvalds if (ms) { 2231da177e4SLinus Torvalds while (alen && a->name[alen-1] == '.') 2241da177e4SLinus Torvalds alen--; 2251da177e4SLinus Torvalds while (blen && b->name[blen-1] == '.') 2261da177e4SLinus Torvalds blen--; 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds if (alen == blen) { 2291da177e4SLinus Torvalds if (strnicmp(a->name, b->name, alen) == 0) 2301da177e4SLinus Torvalds return 0; 2311da177e4SLinus Torvalds } 2321da177e4SLinus Torvalds return 1; 2331da177e4SLinus Torvalds } 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* 2361da177e4SLinus Torvalds * Case sensitive compare of two isofs names. 2371da177e4SLinus Torvalds */ 2389eb7f2c6SAndrew Morton static int isofs_dentry_cmp_common(struct dentry *dentry, struct qstr *a, 2399eb7f2c6SAndrew Morton struct qstr *b, int ms) 2401da177e4SLinus Torvalds { 2411da177e4SLinus Torvalds int alen, blen; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* A filename cannot end in '.' or we treat it like it has none */ 2441da177e4SLinus Torvalds alen = a->len; 2451da177e4SLinus Torvalds blen = b->len; 2461da177e4SLinus Torvalds if (ms) { 2471da177e4SLinus Torvalds while (alen && a->name[alen-1] == '.') 2481da177e4SLinus Torvalds alen--; 2491da177e4SLinus Torvalds while (blen && b->name[blen-1] == '.') 2501da177e4SLinus Torvalds blen--; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds if (alen == blen) { 2531da177e4SLinus Torvalds if (strncmp(a->name, b->name, alen) == 0) 2541da177e4SLinus Torvalds return 0; 2551da177e4SLinus Torvalds } 2561da177e4SLinus Torvalds return 1; 2571da177e4SLinus Torvalds } 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds static int 2601da177e4SLinus Torvalds isofs_hash(struct dentry *dentry, struct qstr *qstr) 2611da177e4SLinus Torvalds { 2621da177e4SLinus Torvalds return isofs_hash_common(dentry, qstr, 0); 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds static int 2661da177e4SLinus Torvalds isofs_hashi(struct dentry *dentry, struct qstr *qstr) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds return isofs_hashi_common(dentry, qstr, 0); 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds static int 2721da177e4SLinus Torvalds isofs_dentry_cmp(struct dentry *dentry,struct qstr *a,struct qstr *b) 2731da177e4SLinus Torvalds { 2741da177e4SLinus Torvalds return isofs_dentry_cmp_common(dentry, a, b, 0); 2751da177e4SLinus Torvalds } 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds static int 2781da177e4SLinus Torvalds isofs_dentry_cmpi(struct dentry *dentry,struct qstr *a,struct qstr *b) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds return isofs_dentry_cmpi_common(dentry, a, b, 0); 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 2841da177e4SLinus Torvalds static int 2851da177e4SLinus Torvalds isofs_hash_ms(struct dentry *dentry, struct qstr *qstr) 2861da177e4SLinus Torvalds { 2871da177e4SLinus Torvalds return isofs_hash_common(dentry, qstr, 1); 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static int 2911da177e4SLinus Torvalds isofs_hashi_ms(struct dentry *dentry, struct qstr *qstr) 2921da177e4SLinus Torvalds { 2931da177e4SLinus Torvalds return isofs_hashi_common(dentry, qstr, 1); 2941da177e4SLinus Torvalds } 2951da177e4SLinus Torvalds 2961da177e4SLinus Torvalds static int 2971da177e4SLinus Torvalds isofs_dentry_cmp_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) 2981da177e4SLinus Torvalds { 2991da177e4SLinus Torvalds return isofs_dentry_cmp_common(dentry, a, b, 1); 3001da177e4SLinus Torvalds } 3011da177e4SLinus Torvalds 3021da177e4SLinus Torvalds static int 3031da177e4SLinus Torvalds isofs_dentry_cmpi_ms(struct dentry *dentry,struct qstr *a,struct qstr *b) 3041da177e4SLinus Torvalds { 3051da177e4SLinus Torvalds return isofs_dentry_cmpi_common(dentry, a, b, 1); 3061da177e4SLinus Torvalds } 3071da177e4SLinus Torvalds #endif 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds enum { 3101da177e4SLinus Torvalds Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, 3111da177e4SLinus Torvalds Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, 3121da177e4SLinus Torvalds Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, 313*9769f4ebSJeremy White Opt_nocompress, Opt_hide, Opt_showassoc, 3141da177e4SLinus Torvalds }; 3151da177e4SLinus Torvalds 3161da177e4SLinus Torvalds static match_table_t tokens = { 3171da177e4SLinus Torvalds {Opt_norock, "norock"}, 3181da177e4SLinus Torvalds {Opt_nojoliet, "nojoliet"}, 3191da177e4SLinus Torvalds {Opt_unhide, "unhide"}, 320*9769f4ebSJeremy White {Opt_hide, "hide"}, 321*9769f4ebSJeremy White {Opt_showassoc, "showassoc"}, 3221da177e4SLinus Torvalds {Opt_cruft, "cruft"}, 3231da177e4SLinus Torvalds {Opt_utf8, "utf8"}, 3241da177e4SLinus Torvalds {Opt_iocharset, "iocharset=%s"}, 3251da177e4SLinus Torvalds {Opt_map_a, "map=acorn"}, 3261da177e4SLinus Torvalds {Opt_map_a, "map=a"}, 3271da177e4SLinus Torvalds {Opt_map_n, "map=normal"}, 3281da177e4SLinus Torvalds {Opt_map_n, "map=n"}, 3291da177e4SLinus Torvalds {Opt_map_o, "map=off"}, 3301da177e4SLinus Torvalds {Opt_map_o, "map=o"}, 3311da177e4SLinus Torvalds {Opt_session, "session=%u"}, 3321da177e4SLinus Torvalds {Opt_sb, "sbsector=%u"}, 3331da177e4SLinus Torvalds {Opt_check_r, "check=relaxed"}, 3341da177e4SLinus Torvalds {Opt_check_r, "check=r"}, 3351da177e4SLinus Torvalds {Opt_check_s, "check=strict"}, 3361da177e4SLinus Torvalds {Opt_check_s, "check=s"}, 3371da177e4SLinus Torvalds {Opt_uid, "uid=%u"}, 3381da177e4SLinus Torvalds {Opt_gid, "gid=%u"}, 3391da177e4SLinus Torvalds {Opt_mode, "mode=%u"}, 3401da177e4SLinus Torvalds {Opt_block, "block=%u"}, 3411da177e4SLinus Torvalds {Opt_ignore, "conv=binary"}, 3421da177e4SLinus Torvalds {Opt_ignore, "conv=b"}, 3431da177e4SLinus Torvalds {Opt_ignore, "conv=text"}, 3441da177e4SLinus Torvalds {Opt_ignore, "conv=t"}, 3451da177e4SLinus Torvalds {Opt_ignore, "conv=mtext"}, 3461da177e4SLinus Torvalds {Opt_ignore, "conv=m"}, 3471da177e4SLinus Torvalds {Opt_ignore, "conv=auto"}, 3481da177e4SLinus Torvalds {Opt_ignore, "conv=a"}, 3491da177e4SLinus Torvalds {Opt_nocompress, "nocompress"}, 3501da177e4SLinus Torvalds {Opt_err, NULL} 3511da177e4SLinus Torvalds }; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds static int parse_options(char *options, struct iso9660_options *popt) 3541da177e4SLinus Torvalds { 3551da177e4SLinus Torvalds char *p; 3561da177e4SLinus Torvalds int option; 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds popt->map = 'n'; 3591da177e4SLinus Torvalds popt->rock = 'y'; 3601da177e4SLinus Torvalds popt->joliet = 'y'; 3611da177e4SLinus Torvalds popt->cruft = 'n'; 362*9769f4ebSJeremy White popt->hide = 'n'; 363*9769f4ebSJeremy White popt->showassoc = 'n'; 3641da177e4SLinus Torvalds popt->check = 'u'; /* unset */ 3651da177e4SLinus Torvalds popt->nocompress = 0; 3661da177e4SLinus Torvalds popt->blocksize = 1024; 3671da177e4SLinus Torvalds popt->mode = S_IRUGO | S_IXUGO; /* r-x for all. The disc could 3681da177e4SLinus Torvalds be shared with DOS machines so 3691da177e4SLinus Torvalds virtually anything could be 3701da177e4SLinus Torvalds a valid executable. */ 3711da177e4SLinus Torvalds popt->gid = 0; 3721da177e4SLinus Torvalds popt->uid = 0; 3731da177e4SLinus Torvalds popt->iocharset = NULL; 3741da177e4SLinus Torvalds popt->utf8 = 0; 3751da177e4SLinus Torvalds popt->session=-1; 3761da177e4SLinus Torvalds popt->sbsector=-1; 3771da177e4SLinus Torvalds if (!options) 3781da177e4SLinus Torvalds return 1; 3791da177e4SLinus Torvalds 3801da177e4SLinus Torvalds while ((p = strsep(&options, ",")) != NULL) { 3811da177e4SLinus Torvalds int token; 3821da177e4SLinus Torvalds substring_t args[MAX_OPT_ARGS]; 3831da177e4SLinus Torvalds unsigned n; 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds if (!*p) 3861da177e4SLinus Torvalds continue; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds token = match_token(p, tokens, args); 3891da177e4SLinus Torvalds switch (token) { 3901da177e4SLinus Torvalds case Opt_norock: 3911da177e4SLinus Torvalds popt->rock = 'n'; 3921da177e4SLinus Torvalds break; 3931da177e4SLinus Torvalds case Opt_nojoliet: 3941da177e4SLinus Torvalds popt->joliet = 'n'; 3951da177e4SLinus Torvalds break; 396*9769f4ebSJeremy White case Opt_hide: 397*9769f4ebSJeremy White popt->hide = 'y'; 398*9769f4ebSJeremy White break; 3991da177e4SLinus Torvalds case Opt_unhide: 400*9769f4ebSJeremy White case Opt_showassoc: 401*9769f4ebSJeremy White popt->showassoc = 'y'; 4021da177e4SLinus Torvalds break; 4031da177e4SLinus Torvalds case Opt_cruft: 4041da177e4SLinus Torvalds popt->cruft = 'y'; 4051da177e4SLinus Torvalds break; 4061da177e4SLinus Torvalds case Opt_utf8: 4071da177e4SLinus Torvalds popt->utf8 = 1; 4081da177e4SLinus Torvalds break; 4091da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 4101da177e4SLinus Torvalds case Opt_iocharset: 4111da177e4SLinus Torvalds popt->iocharset = match_strdup(&args[0]); 4121da177e4SLinus Torvalds break; 4131da177e4SLinus Torvalds #endif 4141da177e4SLinus Torvalds case Opt_map_a: 4151da177e4SLinus Torvalds popt->map = 'a'; 4161da177e4SLinus Torvalds break; 4171da177e4SLinus Torvalds case Opt_map_o: 4181da177e4SLinus Torvalds popt->map = 'o'; 4191da177e4SLinus Torvalds break; 4201da177e4SLinus Torvalds case Opt_map_n: 4211da177e4SLinus Torvalds popt->map = 'n'; 4221da177e4SLinus Torvalds break; 4231da177e4SLinus Torvalds case Opt_session: 4241da177e4SLinus Torvalds if (match_int(&args[0], &option)) 4251da177e4SLinus Torvalds return 0; 4261da177e4SLinus Torvalds n = option; 4271da177e4SLinus Torvalds if (n > 99) 4281da177e4SLinus Torvalds return 0; 4291da177e4SLinus Torvalds popt->session = n + 1; 4301da177e4SLinus Torvalds break; 4311da177e4SLinus Torvalds case Opt_sb: 4321da177e4SLinus Torvalds if (match_int(&args[0], &option)) 4331da177e4SLinus Torvalds return 0; 4341da177e4SLinus Torvalds popt->sbsector = option; 4351da177e4SLinus Torvalds break; 4361da177e4SLinus Torvalds case Opt_check_r: 4371da177e4SLinus Torvalds popt->check = 'r'; 4381da177e4SLinus Torvalds break; 4391da177e4SLinus Torvalds case Opt_check_s: 4401da177e4SLinus Torvalds popt->check = 's'; 4411da177e4SLinus Torvalds break; 4421da177e4SLinus Torvalds case Opt_ignore: 4431da177e4SLinus Torvalds break; 4441da177e4SLinus Torvalds case Opt_uid: 4451da177e4SLinus Torvalds if (match_int(&args[0], &option)) 4461da177e4SLinus Torvalds return 0; 4471da177e4SLinus Torvalds popt->uid = option; 4481da177e4SLinus Torvalds break; 4491da177e4SLinus Torvalds case Opt_gid: 4501da177e4SLinus Torvalds if (match_int(&args[0], &option)) 4511da177e4SLinus Torvalds return 0; 4521da177e4SLinus Torvalds popt->gid = option; 4531da177e4SLinus Torvalds break; 4541da177e4SLinus Torvalds case Opt_mode: 4551da177e4SLinus Torvalds if (match_int(&args[0], &option)) 4561da177e4SLinus Torvalds return 0; 4571da177e4SLinus Torvalds popt->mode = option; 4581da177e4SLinus Torvalds break; 4591da177e4SLinus Torvalds case Opt_block: 4601da177e4SLinus Torvalds if (match_int(&args[0], &option)) 4611da177e4SLinus Torvalds return 0; 4621da177e4SLinus Torvalds n = option; 4631da177e4SLinus Torvalds if (n != 512 && n != 1024 && n != 2048) 4641da177e4SLinus Torvalds return 0; 4651da177e4SLinus Torvalds popt->blocksize = n; 4661da177e4SLinus Torvalds break; 4671da177e4SLinus Torvalds case Opt_nocompress: 4681da177e4SLinus Torvalds popt->nocompress = 1; 4691da177e4SLinus Torvalds break; 4701da177e4SLinus Torvalds default: 4711da177e4SLinus Torvalds return 0; 4721da177e4SLinus Torvalds } 4731da177e4SLinus Torvalds } 4741da177e4SLinus Torvalds return 1; 4751da177e4SLinus Torvalds } 4761da177e4SLinus Torvalds 4771da177e4SLinus Torvalds /* 4781da177e4SLinus Torvalds * look if the driver can tell the multi session redirection value 4791da177e4SLinus Torvalds * 4801da177e4SLinus Torvalds * don't change this if you don't know what you do, please! 4811da177e4SLinus Torvalds * Multisession is legal only with XA disks. 4821da177e4SLinus Torvalds * A non-XA disk with more than one volume descriptor may do it right, but 4831da177e4SLinus Torvalds * usually is written in a nowhere standardized "multi-partition" manner. 4841da177e4SLinus Torvalds * Multisession uses absolute addressing (solely the first frame of the whole 4851da177e4SLinus Torvalds * track is #0), multi-partition uses relative addressing (each first frame of 4861da177e4SLinus Torvalds * each track is #0), and a track is not a session. 4871da177e4SLinus Torvalds * 4881da177e4SLinus Torvalds * A broken CDwriter software or drive firmware does not set new standards, 4891da177e4SLinus Torvalds * at least not if conflicting with the existing ones. 4901da177e4SLinus Torvalds * 4911da177e4SLinus Torvalds * emoenke@gwdg.de 4921da177e4SLinus Torvalds */ 4931da177e4SLinus Torvalds #define WE_OBEY_THE_WRITTEN_STANDARDS 1 4941da177e4SLinus Torvalds 4951da177e4SLinus Torvalds static unsigned int isofs_get_last_session(struct super_block *sb, s32 session) 4961da177e4SLinus Torvalds { 4971da177e4SLinus Torvalds struct cdrom_multisession ms_info; 4981da177e4SLinus Torvalds unsigned int vol_desc_start; 4991da177e4SLinus Torvalds struct block_device *bdev = sb->s_bdev; 5001da177e4SLinus Torvalds int i; 5011da177e4SLinus Torvalds 5021da177e4SLinus Torvalds vol_desc_start=0; 5031da177e4SLinus Torvalds ms_info.addr_format=CDROM_LBA; 5041da177e4SLinus Torvalds if(session >= 0 && session <= 99) { 5051da177e4SLinus Torvalds struct cdrom_tocentry Te; 5061da177e4SLinus Torvalds Te.cdte_track=session; 5071da177e4SLinus Torvalds Te.cdte_format=CDROM_LBA; 5081da177e4SLinus Torvalds i = ioctl_by_bdev(bdev, CDROMREADTOCENTRY, (unsigned long) &Te); 5091da177e4SLinus Torvalds if (!i) { 5101da177e4SLinus Torvalds printk(KERN_DEBUG "Session %d start %d type %d\n", 5111da177e4SLinus Torvalds session, Te.cdte_addr.lba, 5121da177e4SLinus Torvalds Te.cdte_ctrl&CDROM_DATA_TRACK); 5131da177e4SLinus Torvalds if ((Te.cdte_ctrl&CDROM_DATA_TRACK) == 4) 5141da177e4SLinus Torvalds return Te.cdte_addr.lba; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds printk(KERN_ERR "Invalid session number or type of track\n"); 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds i = ioctl_by_bdev(bdev, CDROMMULTISESSION, (unsigned long) &ms_info); 5209eb7f2c6SAndrew Morton if (session > 0) 5219eb7f2c6SAndrew Morton printk(KERN_ERR "Invalid session number\n"); 5221da177e4SLinus Torvalds #if 0 5231da177e4SLinus Torvalds printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i); 5241da177e4SLinus Torvalds if (i==0) { 5251da177e4SLinus Torvalds printk("isofs.inode: XA disk: %s\n",ms_info.xa_flag?"yes":"no"); 5261da177e4SLinus Torvalds printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba); 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds #endif 5291da177e4SLinus Torvalds if (i==0) 5301da177e4SLinus Torvalds #if WE_OBEY_THE_WRITTEN_STANDARDS 5311da177e4SLinus Torvalds if (ms_info.xa_flag) /* necessary for a valid ms_info.addr */ 5321da177e4SLinus Torvalds #endif 5331da177e4SLinus Torvalds vol_desc_start=ms_info.addr.lba; 5341da177e4SLinus Torvalds return vol_desc_start; 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds 5371da177e4SLinus Torvalds /* 5381da177e4SLinus Torvalds * Initialize the superblock and read the root inode. 5391da177e4SLinus Torvalds * 5401da177e4SLinus Torvalds * Note: a check_disk_change() has been done immediately prior 5411da177e4SLinus Torvalds * to this call, so we don't need to check again. 5421da177e4SLinus Torvalds */ 5431da177e4SLinus Torvalds static int isofs_fill_super(struct super_block *s, void *data, int silent) 5441da177e4SLinus Torvalds { 5451da177e4SLinus Torvalds struct buffer_head * bh = NULL, *pri_bh = NULL; 5461da177e4SLinus Torvalds struct hs_primary_descriptor * h_pri = NULL; 5471da177e4SLinus Torvalds struct iso_primary_descriptor * pri = NULL; 5481da177e4SLinus Torvalds struct iso_supplementary_descriptor *sec = NULL; 5491da177e4SLinus Torvalds struct iso_directory_record * rootp; 5501da177e4SLinus Torvalds int joliet_level = 0; 5511da177e4SLinus Torvalds int iso_blknum, block; 5521da177e4SLinus Torvalds int orig_zonesize; 5531da177e4SLinus Torvalds int table; 5541da177e4SLinus Torvalds unsigned int vol_desc_start; 5551da177e4SLinus Torvalds unsigned long first_data_zone; 5561da177e4SLinus Torvalds struct inode * inode; 5571da177e4SLinus Torvalds struct iso9660_options opt; 5581da177e4SLinus Torvalds struct isofs_sb_info * sbi; 5591da177e4SLinus Torvalds 5609eb7f2c6SAndrew Morton sbi = kmalloc(sizeof(*sbi), GFP_KERNEL); 5611da177e4SLinus Torvalds if (!sbi) 5621da177e4SLinus Torvalds return -ENOMEM; 5631da177e4SLinus Torvalds s->s_fs_info = sbi; 5649eb7f2c6SAndrew Morton memset(sbi, 0, sizeof(*sbi)); 5651da177e4SLinus Torvalds 5661da177e4SLinus Torvalds if (!parse_options((char *)data, &opt)) 5671da177e4SLinus Torvalds goto out_freesbi; 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds /* 5701da177e4SLinus Torvalds * First of all, get the hardware blocksize for this device. 5711da177e4SLinus Torvalds * If we don't know what it is, or the hardware blocksize is 5721da177e4SLinus Torvalds * larger than the blocksize the user specified, then use 5731da177e4SLinus Torvalds * that value. 5741da177e4SLinus Torvalds */ 5751da177e4SLinus Torvalds /* 5761da177e4SLinus Torvalds * What if bugger tells us to go beyond page size? 5771da177e4SLinus Torvalds */ 5781da177e4SLinus Torvalds opt.blocksize = sb_min_blocksize(s, opt.blocksize); 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds sbi->s_high_sierra = 0; /* default is iso9660 */ 5811da177e4SLinus Torvalds 5821da177e4SLinus Torvalds vol_desc_start = (opt.sbsector != -1) ? 5831da177e4SLinus Torvalds opt.sbsector : isofs_get_last_session(s,opt.session); 5841da177e4SLinus Torvalds 5851da177e4SLinus Torvalds for (iso_blknum = vol_desc_start+16; 5861da177e4SLinus Torvalds iso_blknum < vol_desc_start+100; iso_blknum++) 5871da177e4SLinus Torvalds { 5881da177e4SLinus Torvalds struct hs_volume_descriptor * hdp; 5891da177e4SLinus Torvalds struct iso_volume_descriptor * vdp; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits); 5921da177e4SLinus Torvalds if (!(bh = sb_bread(s, block))) 5931da177e4SLinus Torvalds goto out_no_read; 5941da177e4SLinus Torvalds 5951da177e4SLinus Torvalds vdp = (struct iso_volume_descriptor *)bh->b_data; 5961da177e4SLinus Torvalds hdp = (struct hs_volume_descriptor *)bh->b_data; 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds /* Due to the overlapping physical location of the descriptors, 5991da177e4SLinus Torvalds * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 6001da177e4SLinus Torvalds * proper identification in this case, we first check for ISO. 6011da177e4SLinus Torvalds */ 6021da177e4SLinus Torvalds if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { 6031da177e4SLinus Torvalds if (isonum_711 (vdp->type) == ISO_VD_END) 6041da177e4SLinus Torvalds break; 6051da177e4SLinus Torvalds if (isonum_711 (vdp->type) == ISO_VD_PRIMARY) { 6061da177e4SLinus Torvalds if (pri == NULL) { 6071da177e4SLinus Torvalds pri = (struct iso_primary_descriptor *)vdp; 6081da177e4SLinus Torvalds /* Save the buffer in case we need it ... */ 6091da177e4SLinus Torvalds pri_bh = bh; 6101da177e4SLinus Torvalds bh = NULL; 6111da177e4SLinus Torvalds } 6121da177e4SLinus Torvalds } 6131da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 6141da177e4SLinus Torvalds else if (isonum_711 (vdp->type) == ISO_VD_SUPPLEMENTARY) { 6151da177e4SLinus Torvalds sec = (struct iso_supplementary_descriptor *)vdp; 6161da177e4SLinus Torvalds if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { 6171da177e4SLinus Torvalds if (opt.joliet == 'y') { 6181da177e4SLinus Torvalds if (sec->escape[2] == 0x40) { 6191da177e4SLinus Torvalds joliet_level = 1; 6201da177e4SLinus Torvalds } else if (sec->escape[2] == 0x43) { 6211da177e4SLinus Torvalds joliet_level = 2; 6221da177e4SLinus Torvalds } else if (sec->escape[2] == 0x45) { 6231da177e4SLinus Torvalds joliet_level = 3; 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds printk(KERN_DEBUG"ISO 9660 Extensions: Microsoft Joliet Level %d\n", 6261da177e4SLinus Torvalds joliet_level); 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds goto root_found; 6291da177e4SLinus Torvalds } else { 6301da177e4SLinus Torvalds /* Unknown supplementary volume descriptor */ 6311da177e4SLinus Torvalds sec = NULL; 6321da177e4SLinus Torvalds } 6331da177e4SLinus Torvalds } 6341da177e4SLinus Torvalds #endif 6351da177e4SLinus Torvalds } else { 6361da177e4SLinus Torvalds if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { 6371da177e4SLinus Torvalds if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) 6381da177e4SLinus Torvalds goto out_freebh; 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds sbi->s_high_sierra = 1; 6411da177e4SLinus Torvalds opt.rock = 'n'; 6421da177e4SLinus Torvalds h_pri = (struct hs_primary_descriptor *)vdp; 6431da177e4SLinus Torvalds goto root_found; 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds } 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds /* Just skip any volume descriptors we don't recognize */ 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds brelse(bh); 6501da177e4SLinus Torvalds bh = NULL; 6511da177e4SLinus Torvalds } 6521da177e4SLinus Torvalds /* 6531da177e4SLinus Torvalds * If we fall through, either no volume descriptor was found, 6541da177e4SLinus Torvalds * or else we passed a primary descriptor looking for others. 6551da177e4SLinus Torvalds */ 6561da177e4SLinus Torvalds if (!pri) 6571da177e4SLinus Torvalds goto out_unknown_format; 6581da177e4SLinus Torvalds brelse(bh); 6591da177e4SLinus Torvalds bh = pri_bh; 6601da177e4SLinus Torvalds pri_bh = NULL; 6611da177e4SLinus Torvalds 6621da177e4SLinus Torvalds root_found: 6631da177e4SLinus Torvalds 6641da177e4SLinus Torvalds if (joliet_level && (pri == NULL || opt.rock == 'n')) { 6651da177e4SLinus Torvalds /* This is the case of Joliet with the norock mount flag. 6661da177e4SLinus Torvalds * A disc with both Joliet and Rock Ridge is handled later 6671da177e4SLinus Torvalds */ 6681da177e4SLinus Torvalds pri = (struct iso_primary_descriptor *) sec; 6691da177e4SLinus Torvalds } 6701da177e4SLinus Torvalds 6711da177e4SLinus Torvalds if(sbi->s_high_sierra){ 6721da177e4SLinus Torvalds rootp = (struct iso_directory_record *) h_pri->root_directory_record; 6731da177e4SLinus Torvalds sbi->s_nzones = isonum_733 (h_pri->volume_space_size); 6741da177e4SLinus Torvalds sbi->s_log_zone_size = isonum_723 (h_pri->logical_block_size); 6751da177e4SLinus Torvalds sbi->s_max_size = isonum_733(h_pri->volume_space_size); 6761da177e4SLinus Torvalds } else { 6771da177e4SLinus Torvalds if (!pri) 6781da177e4SLinus Torvalds goto out_freebh; 6791da177e4SLinus Torvalds rootp = (struct iso_directory_record *) pri->root_directory_record; 6801da177e4SLinus Torvalds sbi->s_nzones = isonum_733 (pri->volume_space_size); 6811da177e4SLinus Torvalds sbi->s_log_zone_size = isonum_723 (pri->logical_block_size); 6821da177e4SLinus Torvalds sbi->s_max_size = isonum_733(pri->volume_space_size); 6831da177e4SLinus Torvalds } 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds sbi->s_ninodes = 0; /* No way to figure this out easily */ 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds orig_zonesize = sbi->s_log_zone_size; 6881da177e4SLinus Torvalds /* 6891da177e4SLinus Torvalds * If the zone size is smaller than the hardware sector size, 6901da177e4SLinus Torvalds * this is a fatal error. This would occur if the disc drive 6911da177e4SLinus Torvalds * had sectors that were 2048 bytes, but the filesystem had 6921da177e4SLinus Torvalds * blocks that were 512 bytes (which should only very rarely 6931da177e4SLinus Torvalds * happen.) 6941da177e4SLinus Torvalds */ 6951da177e4SLinus Torvalds if(orig_zonesize < opt.blocksize) 6961da177e4SLinus Torvalds goto out_bad_size; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds /* RDE: convert log zone size to bit shift */ 6991da177e4SLinus Torvalds switch (sbi->s_log_zone_size) 7001da177e4SLinus Torvalds { case 512: sbi->s_log_zone_size = 9; break; 7011da177e4SLinus Torvalds case 1024: sbi->s_log_zone_size = 10; break; 7021da177e4SLinus Torvalds case 2048: sbi->s_log_zone_size = 11; break; 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds default: 7051da177e4SLinus Torvalds goto out_bad_zone_size; 7061da177e4SLinus Torvalds } 7071da177e4SLinus Torvalds 7081da177e4SLinus Torvalds s->s_magic = ISOFS_SUPER_MAGIC; 7091da177e4SLinus Torvalds s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */ 7101da177e4SLinus Torvalds 7111da177e4SLinus Torvalds /* The CDROM is read-only, has no nodes (devices) on it, and since 7121da177e4SLinus Torvalds all of the files appear to be owned by root, we really do not want 7131da177e4SLinus Torvalds to allow suid. (suid or devices will not show up unless we have 7141da177e4SLinus Torvalds Rock Ridge extensions) */ 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; 7171da177e4SLinus Torvalds 7181da177e4SLinus Torvalds /* Set this for reference. Its not currently used except on write 7191da177e4SLinus Torvalds which we don't have .. */ 7201da177e4SLinus Torvalds 7211da177e4SLinus Torvalds first_data_zone = isonum_733 (rootp->extent) + 7221da177e4SLinus Torvalds isonum_711 (rootp->ext_attr_length); 7231da177e4SLinus Torvalds sbi->s_firstdatazone = first_data_zone; 7241da177e4SLinus Torvalds #ifndef BEQUIET 7251da177e4SLinus Torvalds printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n", 7261da177e4SLinus Torvalds sbi->s_max_size, 7271da177e4SLinus Torvalds 1UL << sbi->s_log_zone_size); 7281da177e4SLinus Torvalds printk(KERN_DEBUG "First datazone:%ld\n", sbi->s_firstdatazone); 7291da177e4SLinus Torvalds if(sbi->s_high_sierra) 7301da177e4SLinus Torvalds printk(KERN_DEBUG "Disc in High Sierra format.\n"); 7311da177e4SLinus Torvalds #endif 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds /* 7341da177e4SLinus Torvalds * If the Joliet level is set, we _may_ decide to use the 7351da177e4SLinus Torvalds * secondary descriptor, but can't be sure until after we 7361da177e4SLinus Torvalds * read the root inode. But before reading the root inode 7371da177e4SLinus Torvalds * we may need to change the device blocksize, and would 7381da177e4SLinus Torvalds * rather release the old buffer first. So, we cache the 7391da177e4SLinus Torvalds * first_data_zone value from the secondary descriptor. 7401da177e4SLinus Torvalds */ 7411da177e4SLinus Torvalds if (joliet_level) { 7421da177e4SLinus Torvalds pri = (struct iso_primary_descriptor *) sec; 7431da177e4SLinus Torvalds rootp = (struct iso_directory_record *) 7441da177e4SLinus Torvalds pri->root_directory_record; 7451da177e4SLinus Torvalds first_data_zone = isonum_733 (rootp->extent) + 7461da177e4SLinus Torvalds isonum_711 (rootp->ext_attr_length); 7471da177e4SLinus Torvalds } 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds /* 7501da177e4SLinus Torvalds * We're all done using the volume descriptor, and may need 7511da177e4SLinus Torvalds * to change the device blocksize, so release the buffer now. 7521da177e4SLinus Torvalds */ 7531da177e4SLinus Torvalds brelse(pri_bh); 7541da177e4SLinus Torvalds brelse(bh); 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds /* 7571da177e4SLinus Torvalds * Force the blocksize to 512 for 512 byte sectors. The file 7581da177e4SLinus Torvalds * read primitives really get it wrong in a bad way if we don't 7591da177e4SLinus Torvalds * do this. 7601da177e4SLinus Torvalds * 7611da177e4SLinus Torvalds * Note - we should never be setting the blocksize to something 7621da177e4SLinus Torvalds * less than the hardware sector size for the device. If we 7631da177e4SLinus Torvalds * do, we would end up having to read larger buffers and split 7641da177e4SLinus Torvalds * out portions to satisfy requests. 7651da177e4SLinus Torvalds * 7661da177e4SLinus Torvalds * Note2- the idea here is that we want to deal with the optimal 7671da177e4SLinus Torvalds * zonesize in the filesystem. If we have it set to something less, 7681da177e4SLinus Torvalds * then we have horrible problems with trying to piece together 7691da177e4SLinus Torvalds * bits of adjacent blocks in order to properly read directory 7701da177e4SLinus Torvalds * entries. By forcing the blocksize in this way, we ensure 7711da177e4SLinus Torvalds * that we will never be required to do this. 7721da177e4SLinus Torvalds */ 7731da177e4SLinus Torvalds sb_set_blocksize(s, orig_zonesize); 7741da177e4SLinus Torvalds 7751da177e4SLinus Torvalds sbi->s_nls_iocharset = NULL; 7761da177e4SLinus Torvalds 7771da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 7781da177e4SLinus Torvalds if (joliet_level && opt.utf8 == 0) { 7791da177e4SLinus Torvalds char * p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT; 7801da177e4SLinus Torvalds sbi->s_nls_iocharset = load_nls(p); 7811da177e4SLinus Torvalds if (! sbi->s_nls_iocharset) { 7821da177e4SLinus Torvalds /* Fail only if explicit charset specified */ 7831da177e4SLinus Torvalds if (opt.iocharset) 7841da177e4SLinus Torvalds goto out_freesbi; 7851da177e4SLinus Torvalds sbi->s_nls_iocharset = load_nls_default(); 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds #endif 7891da177e4SLinus Torvalds s->s_op = &isofs_sops; 7901da177e4SLinus Torvalds s->s_export_op = &isofs_export_ops; 7911da177e4SLinus Torvalds sbi->s_mapping = opt.map; 7921da177e4SLinus Torvalds sbi->s_rock = (opt.rock == 'y' ? 2 : 0); 7931da177e4SLinus Torvalds sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ 7941da177e4SLinus Torvalds sbi->s_cruft = opt.cruft; 795*9769f4ebSJeremy White sbi->s_hide = opt.hide; 796*9769f4ebSJeremy White sbi->s_showassoc = opt.showassoc; 7971da177e4SLinus Torvalds sbi->s_uid = opt.uid; 7981da177e4SLinus Torvalds sbi->s_gid = opt.gid; 7991da177e4SLinus Torvalds sbi->s_utf8 = opt.utf8; 8001da177e4SLinus Torvalds sbi->s_nocompress = opt.nocompress; 8011da177e4SLinus Torvalds /* 8021da177e4SLinus Torvalds * It would be incredibly stupid to allow people to mark every file 8031da177e4SLinus Torvalds * on the disk as suid, so we merely allow them to set the default 8041da177e4SLinus Torvalds * permissions. 8051da177e4SLinus Torvalds */ 8061da177e4SLinus Torvalds sbi->s_mode = opt.mode & 0777; 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds /* 8091da177e4SLinus Torvalds * Read the root inode, which _may_ result in changing 8101da177e4SLinus Torvalds * the s_rock flag. Once we have the final s_rock value, 8111da177e4SLinus Torvalds * we then decide whether to use the Joliet descriptor. 8121da177e4SLinus Torvalds */ 8131da177e4SLinus Torvalds inode = isofs_iget(s, sbi->s_firstdatazone, 0); 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds /* 8161da177e4SLinus Torvalds * If this disk has both Rock Ridge and Joliet on it, then we 8171da177e4SLinus Torvalds * want to use Rock Ridge by default. This can be overridden 8181da177e4SLinus Torvalds * by using the norock mount option. There is still one other 8191da177e4SLinus Torvalds * possibility that is not taken into account: a Rock Ridge 8201da177e4SLinus Torvalds * CD with Unicode names. Until someone sees such a beast, it 8211da177e4SLinus Torvalds * will not be supported. 8221da177e4SLinus Torvalds */ 8231da177e4SLinus Torvalds if (sbi->s_rock == 1) { 8241da177e4SLinus Torvalds joliet_level = 0; 8251da177e4SLinus Torvalds } else if (joliet_level) { 8261da177e4SLinus Torvalds sbi->s_rock = 0; 8271da177e4SLinus Torvalds if (sbi->s_firstdatazone != first_data_zone) { 8281da177e4SLinus Torvalds sbi->s_firstdatazone = first_data_zone; 8291da177e4SLinus Torvalds printk(KERN_DEBUG 8301da177e4SLinus Torvalds "ISOFS: changing to secondary root\n"); 8311da177e4SLinus Torvalds iput(inode); 8321da177e4SLinus Torvalds inode = isofs_iget(s, sbi->s_firstdatazone, 0); 8331da177e4SLinus Torvalds } 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds 8361da177e4SLinus Torvalds if (opt.check == 'u') { 8371da177e4SLinus Torvalds /* Only Joliet is case insensitive by default */ 8381da177e4SLinus Torvalds if (joliet_level) opt.check = 'r'; 8391da177e4SLinus Torvalds else opt.check = 's'; 8401da177e4SLinus Torvalds } 8411da177e4SLinus Torvalds sbi->s_joliet_level = joliet_level; 8421da177e4SLinus Torvalds 8431da177e4SLinus Torvalds /* check the root inode */ 8441da177e4SLinus Torvalds if (!inode) 8451da177e4SLinus Torvalds goto out_no_root; 8461da177e4SLinus Torvalds if (!inode->i_op) 8471da177e4SLinus Torvalds goto out_bad_root; 8481da177e4SLinus Torvalds /* get the root dentry */ 8491da177e4SLinus Torvalds s->s_root = d_alloc_root(inode); 8501da177e4SLinus Torvalds if (!(s->s_root)) 8511da177e4SLinus Torvalds goto out_no_root; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds table = 0; 8541da177e4SLinus Torvalds if (joliet_level) table += 2; 8551da177e4SLinus Torvalds if (opt.check == 'r') table++; 8561da177e4SLinus Torvalds s->s_root->d_op = &isofs_dentry_ops[table]; 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds if (opt.iocharset) 8591da177e4SLinus Torvalds kfree(opt.iocharset); 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds return 0; 8621da177e4SLinus Torvalds 8631da177e4SLinus Torvalds /* 8641da177e4SLinus Torvalds * Display error messages and free resources. 8651da177e4SLinus Torvalds */ 8661da177e4SLinus Torvalds out_bad_root: 8671da177e4SLinus Torvalds printk(KERN_WARNING "isofs_fill_super: root inode not initialized\n"); 8681da177e4SLinus Torvalds goto out_iput; 8691da177e4SLinus Torvalds out_no_root: 8701da177e4SLinus Torvalds printk(KERN_WARNING "isofs_fill_super: get root inode failed\n"); 8711da177e4SLinus Torvalds out_iput: 8721da177e4SLinus Torvalds iput(inode); 8731da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 8741da177e4SLinus Torvalds if (sbi->s_nls_iocharset) 8751da177e4SLinus Torvalds unload_nls(sbi->s_nls_iocharset); 8761da177e4SLinus Torvalds #endif 8771da177e4SLinus Torvalds goto out_freesbi; 8781da177e4SLinus Torvalds out_no_read: 8791da177e4SLinus Torvalds printk(KERN_WARNING "isofs_fill_super: " 8801da177e4SLinus Torvalds "bread failed, dev=%s, iso_blknum=%d, block=%d\n", 8811da177e4SLinus Torvalds s->s_id, iso_blknum, block); 8821da177e4SLinus Torvalds goto out_freesbi; 8831da177e4SLinus Torvalds out_bad_zone_size: 8841da177e4SLinus Torvalds printk(KERN_WARNING "Bad logical zone size %ld\n", 8851da177e4SLinus Torvalds sbi->s_log_zone_size); 8861da177e4SLinus Torvalds goto out_freebh; 8871da177e4SLinus Torvalds out_bad_size: 8881da177e4SLinus Torvalds printk(KERN_WARNING "Logical zone size(%d) < hardware blocksize(%u)\n", 8891da177e4SLinus Torvalds orig_zonesize, opt.blocksize); 8901da177e4SLinus Torvalds goto out_freebh; 8911da177e4SLinus Torvalds out_unknown_format: 8921da177e4SLinus Torvalds if (!silent) 8931da177e4SLinus Torvalds printk(KERN_WARNING "Unable to identify CD-ROM format.\n"); 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds out_freebh: 8961da177e4SLinus Torvalds brelse(bh); 8971da177e4SLinus Torvalds out_freesbi: 8981da177e4SLinus Torvalds if (opt.iocharset) 8991da177e4SLinus Torvalds kfree(opt.iocharset); 9001da177e4SLinus Torvalds kfree(sbi); 9011da177e4SLinus Torvalds s->s_fs_info = NULL; 9021da177e4SLinus Torvalds return -EINVAL; 9031da177e4SLinus Torvalds } 9041da177e4SLinus Torvalds 9051da177e4SLinus Torvalds static int isofs_statfs (struct super_block *sb, struct kstatfs *buf) 9061da177e4SLinus Torvalds { 9071da177e4SLinus Torvalds buf->f_type = ISOFS_SUPER_MAGIC; 9081da177e4SLinus Torvalds buf->f_bsize = sb->s_blocksize; 9091da177e4SLinus Torvalds buf->f_blocks = (ISOFS_SB(sb)->s_nzones 9101da177e4SLinus Torvalds << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits)); 9111da177e4SLinus Torvalds buf->f_bfree = 0; 9121da177e4SLinus Torvalds buf->f_bavail = 0; 9131da177e4SLinus Torvalds buf->f_files = ISOFS_SB(sb)->s_ninodes; 9141da177e4SLinus Torvalds buf->f_ffree = 0; 9151da177e4SLinus Torvalds buf->f_namelen = NAME_MAX; 9161da177e4SLinus Torvalds return 0; 9171da177e4SLinus Torvalds } 9181da177e4SLinus Torvalds 9191da177e4SLinus Torvalds /* 9201da177e4SLinus Torvalds * Get a set of blocks; filling in buffer_heads if already allocated 9211da177e4SLinus Torvalds * or getblk() if they are not. Returns the number of blocks inserted 9221da177e4SLinus Torvalds * (0 == error.) 9231da177e4SLinus Torvalds */ 9241da177e4SLinus Torvalds int isofs_get_blocks(struct inode *inode, sector_t iblock_s, 9251da177e4SLinus Torvalds struct buffer_head **bh, unsigned long nblocks) 9261da177e4SLinus Torvalds { 9271da177e4SLinus Torvalds unsigned long b_off; 9281da177e4SLinus Torvalds unsigned offset, sect_size; 9291da177e4SLinus Torvalds unsigned int firstext; 9301da177e4SLinus Torvalds unsigned long nextblk, nextoff; 9311da177e4SLinus Torvalds long iblock = (long)iblock_s; 9321da177e4SLinus Torvalds int section, rv; 9331da177e4SLinus Torvalds struct iso_inode_info *ei = ISOFS_I(inode); 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds lock_kernel(); 9361da177e4SLinus Torvalds 9371da177e4SLinus Torvalds rv = 0; 9381da177e4SLinus Torvalds if (iblock < 0 || iblock != iblock_s) { 9391da177e4SLinus Torvalds printk("isofs_get_blocks: block number too large\n"); 9401da177e4SLinus Torvalds goto abort; 9411da177e4SLinus Torvalds } 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds b_off = iblock; 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds offset = 0; 9461da177e4SLinus Torvalds firstext = ei->i_first_extent; 9471da177e4SLinus Torvalds sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode); 9481da177e4SLinus Torvalds nextblk = ei->i_next_section_block; 9491da177e4SLinus Torvalds nextoff = ei->i_next_section_offset; 9501da177e4SLinus Torvalds section = 0; 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds while ( nblocks ) { 9531da177e4SLinus Torvalds /* If we are *way* beyond the end of the file, print a message. 9541da177e4SLinus Torvalds * Access beyond the end of the file up to the next page boundary 9551da177e4SLinus Torvalds * is normal, however because of the way the page cache works. 9561da177e4SLinus Torvalds * In this case, we just return 0 so that we can properly fill 9571da177e4SLinus Torvalds * the page with useless information without generating any 9581da177e4SLinus Torvalds * I/O errors. 9591da177e4SLinus Torvalds */ 9601da177e4SLinus Torvalds if (b_off > ((inode->i_size + PAGE_CACHE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) { 9611da177e4SLinus Torvalds printk("isofs_get_blocks: block >= EOF (%ld, %ld)\n", 9621da177e4SLinus Torvalds iblock, (unsigned long) inode->i_size); 9631da177e4SLinus Torvalds goto abort; 9641da177e4SLinus Torvalds } 9651da177e4SLinus Torvalds 9661da177e4SLinus Torvalds if (nextblk) { 9671da177e4SLinus Torvalds while (b_off >= (offset + sect_size)) { 9681da177e4SLinus Torvalds struct inode *ninode; 9691da177e4SLinus Torvalds 9701da177e4SLinus Torvalds offset += sect_size; 9711da177e4SLinus Torvalds if (nextblk == 0) 9721da177e4SLinus Torvalds goto abort; 9731da177e4SLinus Torvalds ninode = isofs_iget(inode->i_sb, nextblk, nextoff); 9741da177e4SLinus Torvalds if (!ninode) 9751da177e4SLinus Torvalds goto abort; 9761da177e4SLinus Torvalds firstext = ISOFS_I(ninode)->i_first_extent; 9771da177e4SLinus Torvalds sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode); 9781da177e4SLinus Torvalds nextblk = ISOFS_I(ninode)->i_next_section_block; 9791da177e4SLinus Torvalds nextoff = ISOFS_I(ninode)->i_next_section_offset; 9801da177e4SLinus Torvalds iput(ninode); 9811da177e4SLinus Torvalds 9821da177e4SLinus Torvalds if (++section > 100) { 9831da177e4SLinus Torvalds printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n"); 9841da177e4SLinus Torvalds printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u " 9851da177e4SLinus Torvalds "nextblk=%lu nextoff=%lu\n", 9861da177e4SLinus Torvalds iblock, firstext, (unsigned) sect_size, 9871da177e4SLinus Torvalds nextblk, nextoff); 9881da177e4SLinus Torvalds goto abort; 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds } 9921da177e4SLinus Torvalds 9931da177e4SLinus Torvalds if ( *bh ) { 9941da177e4SLinus Torvalds map_bh(*bh, inode->i_sb, firstext + b_off - offset); 9951da177e4SLinus Torvalds } else { 9961da177e4SLinus Torvalds *bh = sb_getblk(inode->i_sb, firstext+b_off-offset); 9971da177e4SLinus Torvalds if ( !*bh ) 9981da177e4SLinus Torvalds goto abort; 9991da177e4SLinus Torvalds } 10001da177e4SLinus Torvalds bh++; /* Next buffer head */ 10011da177e4SLinus Torvalds b_off++; /* Next buffer offset */ 10021da177e4SLinus Torvalds nblocks--; 10031da177e4SLinus Torvalds rv++; 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds abort: 10071da177e4SLinus Torvalds unlock_kernel(); 10081da177e4SLinus Torvalds return rv; 10091da177e4SLinus Torvalds } 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds /* 10121da177e4SLinus Torvalds * Used by the standard interfaces. 10131da177e4SLinus Torvalds */ 10141da177e4SLinus Torvalds static int isofs_get_block(struct inode *inode, sector_t iblock, 10151da177e4SLinus Torvalds struct buffer_head *bh_result, int create) 10161da177e4SLinus Torvalds { 10171da177e4SLinus Torvalds if (create) { 10181da177e4SLinus Torvalds printk("isofs_get_block: Kernel tries to allocate a block\n"); 10191da177e4SLinus Torvalds return -EROFS; 10201da177e4SLinus Torvalds } 10211da177e4SLinus Torvalds 10221da177e4SLinus Torvalds return isofs_get_blocks(inode, iblock, &bh_result, 1) ? 0 : -EIO; 10231da177e4SLinus Torvalds } 10241da177e4SLinus Torvalds 10251da177e4SLinus Torvalds static int isofs_bmap(struct inode *inode, sector_t block) 10261da177e4SLinus Torvalds { 10271da177e4SLinus Torvalds struct buffer_head dummy; 10281da177e4SLinus Torvalds int error; 10291da177e4SLinus Torvalds 10301da177e4SLinus Torvalds dummy.b_state = 0; 10311da177e4SLinus Torvalds dummy.b_blocknr = -1000; 10321da177e4SLinus Torvalds error = isofs_get_block(inode, block, &dummy, 0); 10331da177e4SLinus Torvalds if (!error) 10341da177e4SLinus Torvalds return dummy.b_blocknr; 10351da177e4SLinus Torvalds return 0; 10361da177e4SLinus Torvalds } 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds struct buffer_head *isofs_bread(struct inode *inode, sector_t block) 10391da177e4SLinus Torvalds { 10401da177e4SLinus Torvalds sector_t blknr = isofs_bmap(inode, block); 10411da177e4SLinus Torvalds if (!blknr) 10421da177e4SLinus Torvalds return NULL; 10431da177e4SLinus Torvalds return sb_bread(inode->i_sb, blknr); 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds static int isofs_readpage(struct file *file, struct page *page) 10471da177e4SLinus Torvalds { 10481da177e4SLinus Torvalds return block_read_full_page(page,isofs_get_block); 10491da177e4SLinus Torvalds } 10501da177e4SLinus Torvalds 10511da177e4SLinus Torvalds static sector_t _isofs_bmap(struct address_space *mapping, sector_t block) 10521da177e4SLinus Torvalds { 10531da177e4SLinus Torvalds return generic_block_bmap(mapping,block,isofs_get_block); 10541da177e4SLinus Torvalds } 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds static struct address_space_operations isofs_aops = { 10571da177e4SLinus Torvalds .readpage = isofs_readpage, 10581da177e4SLinus Torvalds .sync_page = block_sync_page, 10591da177e4SLinus Torvalds .bmap = _isofs_bmap 10601da177e4SLinus Torvalds }; 10611da177e4SLinus Torvalds 10621da177e4SLinus Torvalds static inline void test_and_set_uid(uid_t *p, uid_t value) 10631da177e4SLinus Torvalds { 10649eb7f2c6SAndrew Morton if (value) 10651da177e4SLinus Torvalds *p = value; 10661da177e4SLinus Torvalds } 10671da177e4SLinus Torvalds 10681da177e4SLinus Torvalds static inline void test_and_set_gid(gid_t *p, gid_t value) 10691da177e4SLinus Torvalds { 10709eb7f2c6SAndrew Morton if (value) 10711da177e4SLinus Torvalds *p = value; 10721da177e4SLinus Torvalds } 10731da177e4SLinus Torvalds 10741da177e4SLinus Torvalds static int isofs_read_level3_size(struct inode *inode) 10751da177e4SLinus Torvalds { 10761da177e4SLinus Torvalds unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 10771da177e4SLinus Torvalds int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; 10781da177e4SLinus Torvalds struct buffer_head * bh = NULL; 10791da177e4SLinus Torvalds unsigned long block, offset, block_saved, offset_saved; 10801da177e4SLinus Torvalds int i = 0; 10811da177e4SLinus Torvalds int more_entries = 0; 10821da177e4SLinus Torvalds struct iso_directory_record * tmpde = NULL; 10831da177e4SLinus Torvalds struct iso_inode_info *ei = ISOFS_I(inode); 10841da177e4SLinus Torvalds 10851da177e4SLinus Torvalds inode->i_size = 0; 10861da177e4SLinus Torvalds 10871da177e4SLinus Torvalds /* The first 16 blocks are reserved as the System Area. Thus, 10881da177e4SLinus Torvalds * no inodes can appear in block 0. We use this to flag that 10891da177e4SLinus Torvalds * this is the last section. */ 10901da177e4SLinus Torvalds ei->i_next_section_block = 0; 10911da177e4SLinus Torvalds ei->i_next_section_offset = 0; 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds block = ei->i_iget5_block; 10941da177e4SLinus Torvalds offset = ei->i_iget5_offset; 10951da177e4SLinus Torvalds 10961da177e4SLinus Torvalds do { 10971da177e4SLinus Torvalds struct iso_directory_record * de; 10981da177e4SLinus Torvalds unsigned int de_len; 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds if (!bh) { 11011da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, block); 11021da177e4SLinus Torvalds if (!bh) 11031da177e4SLinus Torvalds goto out_noread; 11041da177e4SLinus Torvalds } 11051da177e4SLinus Torvalds de = (struct iso_directory_record *) (bh->b_data + offset); 11061da177e4SLinus Torvalds de_len = *(unsigned char *) de; 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds if (de_len == 0) { 11091da177e4SLinus Torvalds brelse(bh); 11101da177e4SLinus Torvalds bh = NULL; 11111da177e4SLinus Torvalds ++block; 11121da177e4SLinus Torvalds offset = 0; 11131da177e4SLinus Torvalds continue; 11141da177e4SLinus Torvalds } 11151da177e4SLinus Torvalds 11161da177e4SLinus Torvalds block_saved = block; 11171da177e4SLinus Torvalds offset_saved = offset; 11181da177e4SLinus Torvalds offset += de_len; 11191da177e4SLinus Torvalds 11201da177e4SLinus Torvalds /* Make sure we have a full directory entry */ 11211da177e4SLinus Torvalds if (offset >= bufsize) { 11221da177e4SLinus Torvalds int slop = bufsize - offset + de_len; 11231da177e4SLinus Torvalds if (!tmpde) { 11241da177e4SLinus Torvalds tmpde = kmalloc(256, GFP_KERNEL); 11251da177e4SLinus Torvalds if (!tmpde) 11261da177e4SLinus Torvalds goto out_nomem; 11271da177e4SLinus Torvalds } 11281da177e4SLinus Torvalds memcpy(tmpde, de, slop); 11291da177e4SLinus Torvalds offset &= bufsize - 1; 11301da177e4SLinus Torvalds block++; 11311da177e4SLinus Torvalds brelse(bh); 11321da177e4SLinus Torvalds bh = NULL; 11331da177e4SLinus Torvalds if (offset) { 11341da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, block); 11351da177e4SLinus Torvalds if (!bh) 11361da177e4SLinus Torvalds goto out_noread; 11371da177e4SLinus Torvalds memcpy((void *)tmpde+slop, bh->b_data, offset); 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds de = tmpde; 11401da177e4SLinus Torvalds } 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds inode->i_size += isonum_733(de->size); 11431da177e4SLinus Torvalds if (i == 1) { 11441da177e4SLinus Torvalds ei->i_next_section_block = block_saved; 11451da177e4SLinus Torvalds ei->i_next_section_offset = offset_saved; 11461da177e4SLinus Torvalds } 11471da177e4SLinus Torvalds 11481da177e4SLinus Torvalds more_entries = de->flags[-high_sierra] & 0x80; 11491da177e4SLinus Torvalds 11501da177e4SLinus Torvalds i++; 11511da177e4SLinus Torvalds if (i > 100) 11521da177e4SLinus Torvalds goto out_toomany; 11531da177e4SLinus Torvalds } while (more_entries); 11541da177e4SLinus Torvalds out: 11551da177e4SLinus Torvalds kfree(tmpde); 11561da177e4SLinus Torvalds if (bh) 11571da177e4SLinus Torvalds brelse(bh); 11581da177e4SLinus Torvalds return 0; 11591da177e4SLinus Torvalds 11601da177e4SLinus Torvalds out_nomem: 11611da177e4SLinus Torvalds if (bh) 11621da177e4SLinus Torvalds brelse(bh); 11631da177e4SLinus Torvalds return -ENOMEM; 11641da177e4SLinus Torvalds 11651da177e4SLinus Torvalds out_noread: 11661da177e4SLinus Torvalds printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block); 11671da177e4SLinus Torvalds if (tmpde) 11681da177e4SLinus Torvalds kfree(tmpde); 11691da177e4SLinus Torvalds return -EIO; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds out_toomany: 11721da177e4SLinus Torvalds printk(KERN_INFO "isofs_read_level3_size: " 11731da177e4SLinus Torvalds "More than 100 file sections ?!?, aborting...\n" 11741da177e4SLinus Torvalds "isofs_read_level3_size: inode=%lu\n", 11751da177e4SLinus Torvalds inode->i_ino); 11761da177e4SLinus Torvalds goto out; 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds 11791da177e4SLinus Torvalds static void isofs_read_inode(struct inode *inode) 11801da177e4SLinus Torvalds { 11811da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 11821da177e4SLinus Torvalds struct isofs_sb_info *sbi = ISOFS_SB(sb); 11831da177e4SLinus Torvalds unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 11841da177e4SLinus Torvalds unsigned long block; 11851da177e4SLinus Torvalds int high_sierra = sbi->s_high_sierra; 11861da177e4SLinus Torvalds struct buffer_head * bh = NULL; 11871da177e4SLinus Torvalds struct iso_directory_record * de; 11881da177e4SLinus Torvalds struct iso_directory_record * tmpde = NULL; 11891da177e4SLinus Torvalds unsigned int de_len; 11901da177e4SLinus Torvalds unsigned long offset; 11911da177e4SLinus Torvalds struct iso_inode_info *ei = ISOFS_I(inode); 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds block = ei->i_iget5_block; 11941da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, block); 11951da177e4SLinus Torvalds if (!bh) 11961da177e4SLinus Torvalds goto out_badread; 11971da177e4SLinus Torvalds 11981da177e4SLinus Torvalds offset = ei->i_iget5_offset; 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds de = (struct iso_directory_record *) (bh->b_data + offset); 12011da177e4SLinus Torvalds de_len = *(unsigned char *) de; 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds if (offset + de_len > bufsize) { 12041da177e4SLinus Torvalds int frag1 = bufsize - offset; 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds tmpde = kmalloc(de_len, GFP_KERNEL); 12071da177e4SLinus Torvalds if (tmpde == NULL) { 12081da177e4SLinus Torvalds printk(KERN_INFO "isofs_read_inode: out of memory\n"); 12091da177e4SLinus Torvalds goto fail; 12101da177e4SLinus Torvalds } 12111da177e4SLinus Torvalds memcpy(tmpde, bh->b_data + offset, frag1); 12121da177e4SLinus Torvalds brelse(bh); 12131da177e4SLinus Torvalds bh = sb_bread(inode->i_sb, ++block); 12141da177e4SLinus Torvalds if (!bh) 12151da177e4SLinus Torvalds goto out_badread; 12161da177e4SLinus Torvalds memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1); 12171da177e4SLinus Torvalds de = tmpde; 12181da177e4SLinus Torvalds } 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds inode->i_ino = isofs_get_ino(ei->i_iget5_block, 12211da177e4SLinus Torvalds ei->i_iget5_offset, 12221da177e4SLinus Torvalds ISOFS_BUFFER_BITS(inode)); 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds /* Assume it is a normal-format file unless told otherwise */ 12251da177e4SLinus Torvalds ei->i_file_format = isofs_file_normal; 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds if (de->flags[-high_sierra] & 2) { 12281da177e4SLinus Torvalds inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; 12291da177e4SLinus Torvalds inode->i_nlink = 1; /* Set to 1. We know there are 2, but 12301da177e4SLinus Torvalds the find utility tries to optimize 12311da177e4SLinus Torvalds if it is 2, and it screws up. It is 12321da177e4SLinus Torvalds easier to give 1 which tells find to 12331da177e4SLinus Torvalds do it the hard way. */ 12341da177e4SLinus Torvalds } else { 12351da177e4SLinus Torvalds /* Everybody gets to read the file. */ 12361da177e4SLinus Torvalds inode->i_mode = sbi->s_mode; 12371da177e4SLinus Torvalds inode->i_nlink = 1; 12381da177e4SLinus Torvalds inode->i_mode |= S_IFREG; 12391da177e4SLinus Torvalds } 12401da177e4SLinus Torvalds inode->i_uid = sbi->s_uid; 12411da177e4SLinus Torvalds inode->i_gid = sbi->s_gid; 12421da177e4SLinus Torvalds inode->i_blocks = inode->i_blksize = 0; 12431da177e4SLinus Torvalds 12441da177e4SLinus Torvalds ei->i_format_parm[0] = 0; 12451da177e4SLinus Torvalds ei->i_format_parm[1] = 0; 12461da177e4SLinus Torvalds ei->i_format_parm[2] = 0; 12471da177e4SLinus Torvalds 12481da177e4SLinus Torvalds ei->i_section_size = isonum_733 (de->size); 12491da177e4SLinus Torvalds if (de->flags[-high_sierra] & 0x80) { 12501da177e4SLinus Torvalds if(isofs_read_level3_size(inode)) goto fail; 12511da177e4SLinus Torvalds } else { 12521da177e4SLinus Torvalds ei->i_next_section_block = 0; 12531da177e4SLinus Torvalds ei->i_next_section_offset = 0; 12541da177e4SLinus Torvalds inode->i_size = isonum_733 (de->size); 12551da177e4SLinus Torvalds } 12561da177e4SLinus Torvalds 12571da177e4SLinus Torvalds /* 12581da177e4SLinus Torvalds * Some dipshit decided to store some other bit of information 12591da177e4SLinus Torvalds * in the high byte of the file length. Truncate size in case 12601da177e4SLinus Torvalds * this CDROM was mounted with the cruft option. 12611da177e4SLinus Torvalds */ 12621da177e4SLinus Torvalds 12631da177e4SLinus Torvalds if (sbi->s_cruft == 'y') 12641da177e4SLinus Torvalds inode->i_size &= 0x00ffffff; 12651da177e4SLinus Torvalds 12661da177e4SLinus Torvalds if (de->interleave[0]) { 12671da177e4SLinus Torvalds printk("Interleaved files not (yet) supported.\n"); 12681da177e4SLinus Torvalds inode->i_size = 0; 12691da177e4SLinus Torvalds } 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds /* I have no idea what file_unit_size is used for, so 12721da177e4SLinus Torvalds we will flag it for now */ 12731da177e4SLinus Torvalds if (de->file_unit_size[0] != 0) { 12741da177e4SLinus Torvalds printk("File unit size != 0 for ISO file (%ld).\n", 12751da177e4SLinus Torvalds inode->i_ino); 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds /* I have no idea what other flag bits are used for, so 12791da177e4SLinus Torvalds we will flag it for now */ 12801da177e4SLinus Torvalds #ifdef DEBUG 12811da177e4SLinus Torvalds if((de->flags[-high_sierra] & ~2)!= 0){ 12821da177e4SLinus Torvalds printk("Unusual flag settings for ISO file (%ld %x).\n", 12831da177e4SLinus Torvalds inode->i_ino, de->flags[-high_sierra]); 12841da177e4SLinus Torvalds } 12851da177e4SLinus Torvalds #endif 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds inode->i_mtime.tv_sec = 12881da177e4SLinus Torvalds inode->i_atime.tv_sec = 12891da177e4SLinus Torvalds inode->i_ctime.tv_sec = iso_date(de->date, high_sierra); 12901da177e4SLinus Torvalds inode->i_mtime.tv_nsec = 12911da177e4SLinus Torvalds inode->i_atime.tv_nsec = 12921da177e4SLinus Torvalds inode->i_ctime.tv_nsec = 0; 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds ei->i_first_extent = (isonum_733 (de->extent) + 12951da177e4SLinus Torvalds isonum_711 (de->ext_attr_length)); 12961da177e4SLinus Torvalds 12971da177e4SLinus Torvalds /* Set the number of blocks for stat() - should be done before RR */ 12981da177e4SLinus Torvalds inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */ 12991da177e4SLinus Torvalds inode->i_blocks = (inode->i_size + 511) >> 9; 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds /* 13021da177e4SLinus Torvalds * Now test for possible Rock Ridge extensions which will override 13031da177e4SLinus Torvalds * some of these numbers in the inode structure. 13041da177e4SLinus Torvalds */ 13051da177e4SLinus Torvalds 13061da177e4SLinus Torvalds if (!high_sierra) { 13071da177e4SLinus Torvalds parse_rock_ridge_inode(de, inode); 13081da177e4SLinus Torvalds /* if we want uid/gid set, override the rock ridge setting */ 13091da177e4SLinus Torvalds test_and_set_uid(&inode->i_uid, sbi->s_uid); 13101da177e4SLinus Torvalds test_and_set_gid(&inode->i_gid, sbi->s_gid); 13111da177e4SLinus Torvalds } 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds /* Install the inode operations vector */ 13141da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 13151da177e4SLinus Torvalds inode->i_fop = &generic_ro_fops; 13161da177e4SLinus Torvalds switch ( ei->i_file_format ) { 13171da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS 13181da177e4SLinus Torvalds case isofs_file_compressed: 13191da177e4SLinus Torvalds inode->i_data.a_ops = &zisofs_aops; 13201da177e4SLinus Torvalds break; 13211da177e4SLinus Torvalds #endif 13221da177e4SLinus Torvalds default: 13231da177e4SLinus Torvalds inode->i_data.a_ops = &isofs_aops; 13241da177e4SLinus Torvalds break; 13251da177e4SLinus Torvalds } 13261da177e4SLinus Torvalds } else if (S_ISDIR(inode->i_mode)) { 13271da177e4SLinus Torvalds inode->i_op = &isofs_dir_inode_operations; 13281da177e4SLinus Torvalds inode->i_fop = &isofs_dir_operations; 13291da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 13301da177e4SLinus Torvalds inode->i_op = &page_symlink_inode_operations; 13311da177e4SLinus Torvalds inode->i_data.a_ops = &isofs_symlink_aops; 13321da177e4SLinus Torvalds } else 13331da177e4SLinus Torvalds /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ 13341da177e4SLinus Torvalds init_special_inode(inode, inode->i_mode, inode->i_rdev); 13351da177e4SLinus Torvalds 13361da177e4SLinus Torvalds out: 13371da177e4SLinus Torvalds if (tmpde) 13381da177e4SLinus Torvalds kfree(tmpde); 13391da177e4SLinus Torvalds if (bh) 13401da177e4SLinus Torvalds brelse(bh); 13411da177e4SLinus Torvalds return; 13421da177e4SLinus Torvalds 13431da177e4SLinus Torvalds out_badread: 13441da177e4SLinus Torvalds printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); 13451da177e4SLinus Torvalds fail: 13461da177e4SLinus Torvalds make_bad_inode(inode); 13471da177e4SLinus Torvalds goto out; 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds struct isofs_iget5_callback_data { 13511da177e4SLinus Torvalds unsigned long block; 13521da177e4SLinus Torvalds unsigned long offset; 13531da177e4SLinus Torvalds }; 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds static int isofs_iget5_test(struct inode *ino, void *data) 13561da177e4SLinus Torvalds { 13571da177e4SLinus Torvalds struct iso_inode_info *i = ISOFS_I(ino); 13581da177e4SLinus Torvalds struct isofs_iget5_callback_data *d = 13591da177e4SLinus Torvalds (struct isofs_iget5_callback_data*)data; 13601da177e4SLinus Torvalds return (i->i_iget5_block == d->block) 13611da177e4SLinus Torvalds && (i->i_iget5_offset == d->offset); 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds 13641da177e4SLinus Torvalds static int isofs_iget5_set(struct inode *ino, void *data) 13651da177e4SLinus Torvalds { 13661da177e4SLinus Torvalds struct iso_inode_info *i = ISOFS_I(ino); 13671da177e4SLinus Torvalds struct isofs_iget5_callback_data *d = 13681da177e4SLinus Torvalds (struct isofs_iget5_callback_data*)data; 13691da177e4SLinus Torvalds i->i_iget5_block = d->block; 13701da177e4SLinus Torvalds i->i_iget5_offset = d->offset; 13711da177e4SLinus Torvalds return 0; 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds /* Store, in the inode's containing structure, the block and block 13751da177e4SLinus Torvalds * offset that point to the underlying meta-data for the inode. The 13761da177e4SLinus Torvalds * code below is otherwise similar to the iget() code in 13771da177e4SLinus Torvalds * include/linux/fs.h */ 13781da177e4SLinus Torvalds struct inode *isofs_iget(struct super_block *sb, 13791da177e4SLinus Torvalds unsigned long block, 13801da177e4SLinus Torvalds unsigned long offset) 13811da177e4SLinus Torvalds { 13821da177e4SLinus Torvalds unsigned long hashval; 13831da177e4SLinus Torvalds struct inode *inode; 13841da177e4SLinus Torvalds struct isofs_iget5_callback_data data; 13851da177e4SLinus Torvalds 13861da177e4SLinus Torvalds if (offset >= 1ul << sb->s_blocksize_bits) 13871da177e4SLinus Torvalds return NULL; 13881da177e4SLinus Torvalds 13891da177e4SLinus Torvalds data.block = block; 13901da177e4SLinus Torvalds data.offset = offset; 13911da177e4SLinus Torvalds 13921da177e4SLinus Torvalds hashval = (block << sb->s_blocksize_bits) | offset; 13931da177e4SLinus Torvalds 13949eb7f2c6SAndrew Morton inode = iget5_locked(sb, hashval, &isofs_iget5_test, 13959eb7f2c6SAndrew Morton &isofs_iget5_set, &data); 13961da177e4SLinus Torvalds 13971da177e4SLinus Torvalds if (inode && (inode->i_state & I_NEW)) { 13981da177e4SLinus Torvalds sb->s_op->read_inode(inode); 13991da177e4SLinus Torvalds unlock_new_inode(inode); 14001da177e4SLinus Torvalds } 14011da177e4SLinus Torvalds 14021da177e4SLinus Torvalds return inode; 14031da177e4SLinus Torvalds } 14041da177e4SLinus Torvalds 14051da177e4SLinus Torvalds static struct super_block *isofs_get_sb(struct file_system_type *fs_type, 14061da177e4SLinus Torvalds int flags, const char *dev_name, void *data) 14071da177e4SLinus Torvalds { 14081da177e4SLinus Torvalds return get_sb_bdev(fs_type, flags, dev_name, data, isofs_fill_super); 14091da177e4SLinus Torvalds } 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds static struct file_system_type iso9660_fs_type = { 14121da177e4SLinus Torvalds .owner = THIS_MODULE, 14131da177e4SLinus Torvalds .name = "iso9660", 14141da177e4SLinus Torvalds .get_sb = isofs_get_sb, 14151da177e4SLinus Torvalds .kill_sb = kill_block_super, 14161da177e4SLinus Torvalds .fs_flags = FS_REQUIRES_DEV, 14171da177e4SLinus Torvalds }; 14181da177e4SLinus Torvalds 14191da177e4SLinus Torvalds static int __init init_iso9660_fs(void) 14201da177e4SLinus Torvalds { 14211da177e4SLinus Torvalds int err = init_inodecache(); 14221da177e4SLinus Torvalds if (err) 14231da177e4SLinus Torvalds goto out; 14241da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS 14251da177e4SLinus Torvalds err = zisofs_init(); 14261da177e4SLinus Torvalds if (err) 14271da177e4SLinus Torvalds goto out1; 14281da177e4SLinus Torvalds #endif 14291da177e4SLinus Torvalds err = register_filesystem(&iso9660_fs_type); 14301da177e4SLinus Torvalds if (err) 14311da177e4SLinus Torvalds goto out2; 14321da177e4SLinus Torvalds return 0; 14331da177e4SLinus Torvalds out2: 14341da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS 14351da177e4SLinus Torvalds zisofs_cleanup(); 14361da177e4SLinus Torvalds out1: 14371da177e4SLinus Torvalds #endif 14381da177e4SLinus Torvalds destroy_inodecache(); 14391da177e4SLinus Torvalds out: 14401da177e4SLinus Torvalds return err; 14411da177e4SLinus Torvalds } 14421da177e4SLinus Torvalds 14431da177e4SLinus Torvalds static void __exit exit_iso9660_fs(void) 14441da177e4SLinus Torvalds { 14451da177e4SLinus Torvalds unregister_filesystem(&iso9660_fs_type); 14461da177e4SLinus Torvalds #ifdef CONFIG_ZISOFS 14471da177e4SLinus Torvalds zisofs_cleanup(); 14481da177e4SLinus Torvalds #endif 14491da177e4SLinus Torvalds destroy_inodecache(); 14501da177e4SLinus Torvalds } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds module_init(init_iso9660_fs) 14531da177e4SLinus Torvalds module_exit(exit_iso9660_fs) 14541da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 14551da177e4SLinus Torvalds /* Actual filesystem name is iso9660, as requested in filesystems.c */ 14561da177e4SLinus Torvalds MODULE_ALIAS("iso9660"); 1457