162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/isofs/inode.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (C) 1991 Linus Torvalds - minix filesystem 662306a36Sopenharmony_ci * 1992, 1993, 1994 Eric Youngdale Modified for ISO 9660 filesystem. 762306a36Sopenharmony_ci * 1994 Eberhard Mönkeberg - multi session handling. 862306a36Sopenharmony_ci * 1995 Mark Dobie - allow mounting of some weird VideoCDs and PhotoCDs. 962306a36Sopenharmony_ci * 1997 Gordon Chaffee - Joliet CDs 1062306a36Sopenharmony_ci * 1998 Eric Lammerts - ISO 9660 Level 3 1162306a36Sopenharmony_ci * 2004 Paul Serice - Inode Support pushed out from 4GB to 128GB 1262306a36Sopenharmony_ci * 2004 Paul Serice - NFS Export Operations 1362306a36Sopenharmony_ci */ 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/cred.h> 2062306a36Sopenharmony_ci#include <linux/nls.h> 2162306a36Sopenharmony_ci#include <linux/ctype.h> 2262306a36Sopenharmony_ci#include <linux/statfs.h> 2362306a36Sopenharmony_ci#include <linux/cdrom.h> 2462306a36Sopenharmony_ci#include <linux/parser.h> 2562306a36Sopenharmony_ci#include <linux/mpage.h> 2662306a36Sopenharmony_ci#include <linux/user_namespace.h> 2762306a36Sopenharmony_ci#include <linux/seq_file.h> 2862306a36Sopenharmony_ci#include <linux/blkdev.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#include "isofs.h" 3162306a36Sopenharmony_ci#include "zisofs.h" 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* max tz offset is 13 hours */ 3462306a36Sopenharmony_ci#define MAX_TZ_OFFSET (52*15*60) 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define BEQUIET 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int isofs_hashi(const struct dentry *parent, struct qstr *qstr); 3962306a36Sopenharmony_cistatic int isofs_dentry_cmpi(const struct dentry *dentry, 4062306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 4362306a36Sopenharmony_cistatic int isofs_hashi_ms(const struct dentry *parent, struct qstr *qstr); 4462306a36Sopenharmony_cistatic int isofs_hash_ms(const struct dentry *parent, struct qstr *qstr); 4562306a36Sopenharmony_cistatic int isofs_dentry_cmpi_ms(const struct dentry *dentry, 4662306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name); 4762306a36Sopenharmony_cistatic int isofs_dentry_cmp_ms(const struct dentry *dentry, 4862306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name); 4962306a36Sopenharmony_ci#endif 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void isofs_put_super(struct super_block *sb) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci struct isofs_sb_info *sbi = ISOFS_SB(sb); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 5662306a36Sopenharmony_ci unload_nls(sbi->s_nls_iocharset); 5762306a36Sopenharmony_ci#endif 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci kfree(sbi); 6062306a36Sopenharmony_ci sb->s_fs_info = NULL; 6162306a36Sopenharmony_ci return; 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic int isofs_read_inode(struct inode *, int relocated); 6562306a36Sopenharmony_cistatic int isofs_statfs (struct dentry *, struct kstatfs *); 6662306a36Sopenharmony_cistatic int isofs_show_options(struct seq_file *, struct dentry *); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic struct kmem_cache *isofs_inode_cachep; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic struct inode *isofs_alloc_inode(struct super_block *sb) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct iso_inode_info *ei; 7362306a36Sopenharmony_ci ei = alloc_inode_sb(sb, isofs_inode_cachep, GFP_KERNEL); 7462306a36Sopenharmony_ci if (!ei) 7562306a36Sopenharmony_ci return NULL; 7662306a36Sopenharmony_ci return &ei->vfs_inode; 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic void isofs_free_inode(struct inode *inode) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci kmem_cache_free(isofs_inode_cachep, ISOFS_I(inode)); 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic void init_once(void *foo) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci struct iso_inode_info *ei = foo; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci inode_init_once(&ei->vfs_inode); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int __init init_inodecache(void) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci isofs_inode_cachep = kmem_cache_create("isofs_inode_cache", 9462306a36Sopenharmony_ci sizeof(struct iso_inode_info), 9562306a36Sopenharmony_ci 0, (SLAB_RECLAIM_ACCOUNT| 9662306a36Sopenharmony_ci SLAB_MEM_SPREAD|SLAB_ACCOUNT), 9762306a36Sopenharmony_ci init_once); 9862306a36Sopenharmony_ci if (!isofs_inode_cachep) 9962306a36Sopenharmony_ci return -ENOMEM; 10062306a36Sopenharmony_ci return 0; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void destroy_inodecache(void) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci /* 10662306a36Sopenharmony_ci * Make sure all delayed rcu free inodes are flushed before we 10762306a36Sopenharmony_ci * destroy cache. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_ci rcu_barrier(); 11062306a36Sopenharmony_ci kmem_cache_destroy(isofs_inode_cachep); 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cistatic int isofs_remount(struct super_block *sb, int *flags, char *data) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci sync_filesystem(sb); 11662306a36Sopenharmony_ci if (!(*flags & SB_RDONLY)) 11762306a36Sopenharmony_ci return -EROFS; 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic const struct super_operations isofs_sops = { 12262306a36Sopenharmony_ci .alloc_inode = isofs_alloc_inode, 12362306a36Sopenharmony_ci .free_inode = isofs_free_inode, 12462306a36Sopenharmony_ci .put_super = isofs_put_super, 12562306a36Sopenharmony_ci .statfs = isofs_statfs, 12662306a36Sopenharmony_ci .remount_fs = isofs_remount, 12762306a36Sopenharmony_ci .show_options = isofs_show_options, 12862306a36Sopenharmony_ci}; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic const struct dentry_operations isofs_dentry_ops[] = { 13262306a36Sopenharmony_ci { 13362306a36Sopenharmony_ci .d_hash = isofs_hashi, 13462306a36Sopenharmony_ci .d_compare = isofs_dentry_cmpi, 13562306a36Sopenharmony_ci }, 13662306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 13762306a36Sopenharmony_ci { 13862306a36Sopenharmony_ci .d_hash = isofs_hash_ms, 13962306a36Sopenharmony_ci .d_compare = isofs_dentry_cmp_ms, 14062306a36Sopenharmony_ci }, 14162306a36Sopenharmony_ci { 14262306a36Sopenharmony_ci .d_hash = isofs_hashi_ms, 14362306a36Sopenharmony_ci .d_compare = isofs_dentry_cmpi_ms, 14462306a36Sopenharmony_ci }, 14562306a36Sopenharmony_ci#endif 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistruct iso9660_options{ 14962306a36Sopenharmony_ci unsigned int rock:1; 15062306a36Sopenharmony_ci unsigned int joliet:1; 15162306a36Sopenharmony_ci unsigned int cruft:1; 15262306a36Sopenharmony_ci unsigned int hide:1; 15362306a36Sopenharmony_ci unsigned int showassoc:1; 15462306a36Sopenharmony_ci unsigned int nocompress:1; 15562306a36Sopenharmony_ci unsigned int overriderockperm:1; 15662306a36Sopenharmony_ci unsigned int uid_set:1; 15762306a36Sopenharmony_ci unsigned int gid_set:1; 15862306a36Sopenharmony_ci unsigned char map; 15962306a36Sopenharmony_ci unsigned char check; 16062306a36Sopenharmony_ci unsigned int blocksize; 16162306a36Sopenharmony_ci umode_t fmode; 16262306a36Sopenharmony_ci umode_t dmode; 16362306a36Sopenharmony_ci kgid_t gid; 16462306a36Sopenharmony_ci kuid_t uid; 16562306a36Sopenharmony_ci char *iocharset; 16662306a36Sopenharmony_ci /* LVE */ 16762306a36Sopenharmony_ci s32 session; 16862306a36Sopenharmony_ci s32 sbsector; 16962306a36Sopenharmony_ci}; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci/* 17262306a36Sopenharmony_ci * Compute the hash for the isofs name corresponding to the dentry. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_cistatic int 17562306a36Sopenharmony_ciisofs_hashi_common(const struct dentry *dentry, struct qstr *qstr, int ms) 17662306a36Sopenharmony_ci{ 17762306a36Sopenharmony_ci const char *name; 17862306a36Sopenharmony_ci int len; 17962306a36Sopenharmony_ci char c; 18062306a36Sopenharmony_ci unsigned long hash; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci len = qstr->len; 18362306a36Sopenharmony_ci name = qstr->name; 18462306a36Sopenharmony_ci if (ms) { 18562306a36Sopenharmony_ci while (len && name[len-1] == '.') 18662306a36Sopenharmony_ci len--; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci hash = init_name_hash(dentry); 19062306a36Sopenharmony_ci while (len--) { 19162306a36Sopenharmony_ci c = tolower(*name++); 19262306a36Sopenharmony_ci hash = partial_name_hash(c, hash); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci qstr->hash = end_name_hash(hash); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return 0; 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * Compare of two isofs names. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_cistatic int isofs_dentry_cmp_common( 20362306a36Sopenharmony_ci unsigned int len, const char *str, 20462306a36Sopenharmony_ci const struct qstr *name, int ms, int ci) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int alen, blen; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci /* A filename cannot end in '.' or we treat it like it has none */ 20962306a36Sopenharmony_ci alen = name->len; 21062306a36Sopenharmony_ci blen = len; 21162306a36Sopenharmony_ci if (ms) { 21262306a36Sopenharmony_ci while (alen && name->name[alen-1] == '.') 21362306a36Sopenharmony_ci alen--; 21462306a36Sopenharmony_ci while (blen && str[blen-1] == '.') 21562306a36Sopenharmony_ci blen--; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci if (alen == blen) { 21862306a36Sopenharmony_ci if (ci) { 21962306a36Sopenharmony_ci if (strncasecmp(name->name, str, alen) == 0) 22062306a36Sopenharmony_ci return 0; 22162306a36Sopenharmony_ci } else { 22262306a36Sopenharmony_ci if (strncmp(name->name, str, alen) == 0) 22362306a36Sopenharmony_ci return 0; 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci return 1; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic int 23062306a36Sopenharmony_ciisofs_hashi(const struct dentry *dentry, struct qstr *qstr) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci return isofs_hashi_common(dentry, qstr, 0); 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic int 23662306a36Sopenharmony_ciisofs_dentry_cmpi(const struct dentry *dentry, 23762306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci return isofs_dentry_cmp_common(len, str, name, 0, 1); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 24362306a36Sopenharmony_ci/* 24462306a36Sopenharmony_ci * Compute the hash for the isofs name corresponding to the dentry. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_cistatic int 24762306a36Sopenharmony_ciisofs_hash_common(const struct dentry *dentry, struct qstr *qstr, int ms) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci const char *name; 25062306a36Sopenharmony_ci int len; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci len = qstr->len; 25362306a36Sopenharmony_ci name = qstr->name; 25462306a36Sopenharmony_ci if (ms) { 25562306a36Sopenharmony_ci while (len && name[len-1] == '.') 25662306a36Sopenharmony_ci len--; 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci qstr->hash = full_name_hash(dentry, name, len); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int 26562306a36Sopenharmony_ciisofs_hash_ms(const struct dentry *dentry, struct qstr *qstr) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci return isofs_hash_common(dentry, qstr, 1); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic int 27162306a36Sopenharmony_ciisofs_hashi_ms(const struct dentry *dentry, struct qstr *qstr) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci return isofs_hashi_common(dentry, qstr, 1); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic int 27762306a36Sopenharmony_ciisofs_dentry_cmp_ms(const struct dentry *dentry, 27862306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci return isofs_dentry_cmp_common(len, str, name, 1, 0); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic int 28462306a36Sopenharmony_ciisofs_dentry_cmpi_ms(const struct dentry *dentry, 28562306a36Sopenharmony_ci unsigned int len, const char *str, const struct qstr *name) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci return isofs_dentry_cmp_common(len, str, name, 1, 1); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci#endif 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cienum { 29262306a36Sopenharmony_ci Opt_block, Opt_check_r, Opt_check_s, Opt_cruft, Opt_gid, Opt_ignore, 29362306a36Sopenharmony_ci Opt_iocharset, Opt_map_a, Opt_map_n, Opt_map_o, Opt_mode, Opt_nojoliet, 29462306a36Sopenharmony_ci Opt_norock, Opt_sb, Opt_session, Opt_uid, Opt_unhide, Opt_utf8, Opt_err, 29562306a36Sopenharmony_ci Opt_nocompress, Opt_hide, Opt_showassoc, Opt_dmode, Opt_overriderockperm, 29662306a36Sopenharmony_ci}; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic const match_table_t tokens = { 29962306a36Sopenharmony_ci {Opt_norock, "norock"}, 30062306a36Sopenharmony_ci {Opt_nojoliet, "nojoliet"}, 30162306a36Sopenharmony_ci {Opt_unhide, "unhide"}, 30262306a36Sopenharmony_ci {Opt_hide, "hide"}, 30362306a36Sopenharmony_ci {Opt_showassoc, "showassoc"}, 30462306a36Sopenharmony_ci {Opt_cruft, "cruft"}, 30562306a36Sopenharmony_ci {Opt_utf8, "utf8"}, 30662306a36Sopenharmony_ci {Opt_iocharset, "iocharset=%s"}, 30762306a36Sopenharmony_ci {Opt_map_a, "map=acorn"}, 30862306a36Sopenharmony_ci {Opt_map_a, "map=a"}, 30962306a36Sopenharmony_ci {Opt_map_n, "map=normal"}, 31062306a36Sopenharmony_ci {Opt_map_n, "map=n"}, 31162306a36Sopenharmony_ci {Opt_map_o, "map=off"}, 31262306a36Sopenharmony_ci {Opt_map_o, "map=o"}, 31362306a36Sopenharmony_ci {Opt_session, "session=%u"}, 31462306a36Sopenharmony_ci {Opt_sb, "sbsector=%u"}, 31562306a36Sopenharmony_ci {Opt_check_r, "check=relaxed"}, 31662306a36Sopenharmony_ci {Opt_check_r, "check=r"}, 31762306a36Sopenharmony_ci {Opt_check_s, "check=strict"}, 31862306a36Sopenharmony_ci {Opt_check_s, "check=s"}, 31962306a36Sopenharmony_ci {Opt_uid, "uid=%u"}, 32062306a36Sopenharmony_ci {Opt_gid, "gid=%u"}, 32162306a36Sopenharmony_ci {Opt_mode, "mode=%u"}, 32262306a36Sopenharmony_ci {Opt_dmode, "dmode=%u"}, 32362306a36Sopenharmony_ci {Opt_overriderockperm, "overriderockperm"}, 32462306a36Sopenharmony_ci {Opt_block, "block=%u"}, 32562306a36Sopenharmony_ci {Opt_ignore, "conv=binary"}, 32662306a36Sopenharmony_ci {Opt_ignore, "conv=b"}, 32762306a36Sopenharmony_ci {Opt_ignore, "conv=text"}, 32862306a36Sopenharmony_ci {Opt_ignore, "conv=t"}, 32962306a36Sopenharmony_ci {Opt_ignore, "conv=mtext"}, 33062306a36Sopenharmony_ci {Opt_ignore, "conv=m"}, 33162306a36Sopenharmony_ci {Opt_ignore, "conv=auto"}, 33262306a36Sopenharmony_ci {Opt_ignore, "conv=a"}, 33362306a36Sopenharmony_ci {Opt_nocompress, "nocompress"}, 33462306a36Sopenharmony_ci {Opt_err, NULL} 33562306a36Sopenharmony_ci}; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic int parse_options(char *options, struct iso9660_options *popt) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci char *p; 34062306a36Sopenharmony_ci int option; 34162306a36Sopenharmony_ci unsigned int uv; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci popt->map = 'n'; 34462306a36Sopenharmony_ci popt->rock = 1; 34562306a36Sopenharmony_ci popt->joliet = 1; 34662306a36Sopenharmony_ci popt->cruft = 0; 34762306a36Sopenharmony_ci popt->hide = 0; 34862306a36Sopenharmony_ci popt->showassoc = 0; 34962306a36Sopenharmony_ci popt->check = 'u'; /* unset */ 35062306a36Sopenharmony_ci popt->nocompress = 0; 35162306a36Sopenharmony_ci popt->blocksize = 1024; 35262306a36Sopenharmony_ci popt->fmode = popt->dmode = ISOFS_INVALID_MODE; 35362306a36Sopenharmony_ci popt->uid_set = 0; 35462306a36Sopenharmony_ci popt->gid_set = 0; 35562306a36Sopenharmony_ci popt->gid = GLOBAL_ROOT_GID; 35662306a36Sopenharmony_ci popt->uid = GLOBAL_ROOT_UID; 35762306a36Sopenharmony_ci popt->iocharset = NULL; 35862306a36Sopenharmony_ci popt->overriderockperm = 0; 35962306a36Sopenharmony_ci popt->session=-1; 36062306a36Sopenharmony_ci popt->sbsector=-1; 36162306a36Sopenharmony_ci if (!options) 36262306a36Sopenharmony_ci return 1; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci while ((p = strsep(&options, ",")) != NULL) { 36562306a36Sopenharmony_ci int token; 36662306a36Sopenharmony_ci substring_t args[MAX_OPT_ARGS]; 36762306a36Sopenharmony_ci unsigned n; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (!*p) 37062306a36Sopenharmony_ci continue; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci token = match_token(p, tokens, args); 37362306a36Sopenharmony_ci switch (token) { 37462306a36Sopenharmony_ci case Opt_norock: 37562306a36Sopenharmony_ci popt->rock = 0; 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case Opt_nojoliet: 37862306a36Sopenharmony_ci popt->joliet = 0; 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci case Opt_hide: 38162306a36Sopenharmony_ci popt->hide = 1; 38262306a36Sopenharmony_ci break; 38362306a36Sopenharmony_ci case Opt_unhide: 38462306a36Sopenharmony_ci case Opt_showassoc: 38562306a36Sopenharmony_ci popt->showassoc = 1; 38662306a36Sopenharmony_ci break; 38762306a36Sopenharmony_ci case Opt_cruft: 38862306a36Sopenharmony_ci popt->cruft = 1; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 39162306a36Sopenharmony_ci case Opt_utf8: 39262306a36Sopenharmony_ci kfree(popt->iocharset); 39362306a36Sopenharmony_ci popt->iocharset = kstrdup("utf8", GFP_KERNEL); 39462306a36Sopenharmony_ci if (!popt->iocharset) 39562306a36Sopenharmony_ci return 0; 39662306a36Sopenharmony_ci break; 39762306a36Sopenharmony_ci case Opt_iocharset: 39862306a36Sopenharmony_ci kfree(popt->iocharset); 39962306a36Sopenharmony_ci popt->iocharset = match_strdup(&args[0]); 40062306a36Sopenharmony_ci if (!popt->iocharset) 40162306a36Sopenharmony_ci return 0; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci#endif 40462306a36Sopenharmony_ci case Opt_map_a: 40562306a36Sopenharmony_ci popt->map = 'a'; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci case Opt_map_o: 40862306a36Sopenharmony_ci popt->map = 'o'; 40962306a36Sopenharmony_ci break; 41062306a36Sopenharmony_ci case Opt_map_n: 41162306a36Sopenharmony_ci popt->map = 'n'; 41262306a36Sopenharmony_ci break; 41362306a36Sopenharmony_ci case Opt_session: 41462306a36Sopenharmony_ci if (match_int(&args[0], &option)) 41562306a36Sopenharmony_ci return 0; 41662306a36Sopenharmony_ci n = option; 41762306a36Sopenharmony_ci /* 41862306a36Sopenharmony_ci * Track numbers are supposed to be in range 1-99, the 41962306a36Sopenharmony_ci * mount option starts indexing at 0. 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci if (n >= 99) 42262306a36Sopenharmony_ci return 0; 42362306a36Sopenharmony_ci popt->session = n + 1; 42462306a36Sopenharmony_ci break; 42562306a36Sopenharmony_ci case Opt_sb: 42662306a36Sopenharmony_ci if (match_int(&args[0], &option)) 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci popt->sbsector = option; 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci case Opt_check_r: 43162306a36Sopenharmony_ci popt->check = 'r'; 43262306a36Sopenharmony_ci break; 43362306a36Sopenharmony_ci case Opt_check_s: 43462306a36Sopenharmony_ci popt->check = 's'; 43562306a36Sopenharmony_ci break; 43662306a36Sopenharmony_ci case Opt_ignore: 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case Opt_uid: 43962306a36Sopenharmony_ci if (match_uint(&args[0], &uv)) 44062306a36Sopenharmony_ci return 0; 44162306a36Sopenharmony_ci popt->uid = make_kuid(current_user_ns(), uv); 44262306a36Sopenharmony_ci if (!uid_valid(popt->uid)) 44362306a36Sopenharmony_ci return 0; 44462306a36Sopenharmony_ci popt->uid_set = 1; 44562306a36Sopenharmony_ci break; 44662306a36Sopenharmony_ci case Opt_gid: 44762306a36Sopenharmony_ci if (match_uint(&args[0], &uv)) 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci popt->gid = make_kgid(current_user_ns(), uv); 45062306a36Sopenharmony_ci if (!gid_valid(popt->gid)) 45162306a36Sopenharmony_ci return 0; 45262306a36Sopenharmony_ci popt->gid_set = 1; 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci case Opt_mode: 45562306a36Sopenharmony_ci if (match_int(&args[0], &option)) 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci popt->fmode = option; 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci case Opt_dmode: 46062306a36Sopenharmony_ci if (match_int(&args[0], &option)) 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci popt->dmode = option; 46362306a36Sopenharmony_ci break; 46462306a36Sopenharmony_ci case Opt_overriderockperm: 46562306a36Sopenharmony_ci popt->overriderockperm = 1; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case Opt_block: 46862306a36Sopenharmony_ci if (match_int(&args[0], &option)) 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci n = option; 47162306a36Sopenharmony_ci if (n != 512 && n != 1024 && n != 2048) 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci popt->blocksize = n; 47462306a36Sopenharmony_ci break; 47562306a36Sopenharmony_ci case Opt_nocompress: 47662306a36Sopenharmony_ci popt->nocompress = 1; 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci default: 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci return 1; 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci/* 48662306a36Sopenharmony_ci * Display the mount options in /proc/mounts. 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_cistatic int isofs_show_options(struct seq_file *m, struct dentry *root) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct isofs_sb_info *sbi = ISOFS_SB(root->d_sb); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci if (!sbi->s_rock) seq_puts(m, ",norock"); 49362306a36Sopenharmony_ci else if (!sbi->s_joliet_level) seq_puts(m, ",nojoliet"); 49462306a36Sopenharmony_ci if (sbi->s_cruft) seq_puts(m, ",cruft"); 49562306a36Sopenharmony_ci if (sbi->s_hide) seq_puts(m, ",hide"); 49662306a36Sopenharmony_ci if (sbi->s_nocompress) seq_puts(m, ",nocompress"); 49762306a36Sopenharmony_ci if (sbi->s_overriderockperm) seq_puts(m, ",overriderockperm"); 49862306a36Sopenharmony_ci if (sbi->s_showassoc) seq_puts(m, ",showassoc"); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (sbi->s_check) seq_printf(m, ",check=%c", sbi->s_check); 50162306a36Sopenharmony_ci if (sbi->s_mapping) seq_printf(m, ",map=%c", sbi->s_mapping); 50262306a36Sopenharmony_ci if (sbi->s_session != 255) seq_printf(m, ",session=%u", sbi->s_session - 1); 50362306a36Sopenharmony_ci if (sbi->s_sbsector != -1) seq_printf(m, ",sbsector=%u", sbi->s_sbsector); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (root->d_sb->s_blocksize != 1024) 50662306a36Sopenharmony_ci seq_printf(m, ",blocksize=%lu", root->d_sb->s_blocksize); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (sbi->s_uid_set) 50962306a36Sopenharmony_ci seq_printf(m, ",uid=%u", 51062306a36Sopenharmony_ci from_kuid_munged(&init_user_ns, sbi->s_uid)); 51162306a36Sopenharmony_ci if (sbi->s_gid_set) 51262306a36Sopenharmony_ci seq_printf(m, ",gid=%u", 51362306a36Sopenharmony_ci from_kgid_munged(&init_user_ns, sbi->s_gid)); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (sbi->s_dmode != ISOFS_INVALID_MODE) 51662306a36Sopenharmony_ci seq_printf(m, ",dmode=%o", sbi->s_dmode); 51762306a36Sopenharmony_ci if (sbi->s_fmode != ISOFS_INVALID_MODE) 51862306a36Sopenharmony_ci seq_printf(m, ",fmode=%o", sbi->s_fmode); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 52162306a36Sopenharmony_ci if (sbi->s_nls_iocharset) 52262306a36Sopenharmony_ci seq_printf(m, ",iocharset=%s", sbi->s_nls_iocharset->charset); 52362306a36Sopenharmony_ci else 52462306a36Sopenharmony_ci seq_puts(m, ",iocharset=utf8"); 52562306a36Sopenharmony_ci#endif 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci/* 53062306a36Sopenharmony_ci * look if the driver can tell the multi session redirection value 53162306a36Sopenharmony_ci * 53262306a36Sopenharmony_ci * don't change this if you don't know what you do, please! 53362306a36Sopenharmony_ci * Multisession is legal only with XA disks. 53462306a36Sopenharmony_ci * A non-XA disk with more than one volume descriptor may do it right, but 53562306a36Sopenharmony_ci * usually is written in a nowhere standardized "multi-partition" manner. 53662306a36Sopenharmony_ci * Multisession uses absolute addressing (solely the first frame of the whole 53762306a36Sopenharmony_ci * track is #0), multi-partition uses relative addressing (each first frame of 53862306a36Sopenharmony_ci * each track is #0), and a track is not a session. 53962306a36Sopenharmony_ci * 54062306a36Sopenharmony_ci * A broken CDwriter software or drive firmware does not set new standards, 54162306a36Sopenharmony_ci * at least not if conflicting with the existing ones. 54262306a36Sopenharmony_ci * 54362306a36Sopenharmony_ci * emoenke@gwdg.de 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci#define WE_OBEY_THE_WRITTEN_STANDARDS 1 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic unsigned int isofs_get_last_session(struct super_block *sb, s32 session) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct cdrom_device_info *cdi = disk_to_cdi(sb->s_bdev->bd_disk); 55062306a36Sopenharmony_ci unsigned int vol_desc_start = 0; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (session > 0) { 55362306a36Sopenharmony_ci struct cdrom_tocentry te; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (!cdi) 55662306a36Sopenharmony_ci return 0; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci te.cdte_track = session; 55962306a36Sopenharmony_ci te.cdte_format = CDROM_LBA; 56062306a36Sopenharmony_ci if (cdrom_read_tocentry(cdi, &te) == 0) { 56162306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: Session %d start %d type %d\n", 56262306a36Sopenharmony_ci session, te.cdte_addr.lba, 56362306a36Sopenharmony_ci te.cdte_ctrl & CDROM_DATA_TRACK); 56462306a36Sopenharmony_ci if ((te.cdte_ctrl & CDROM_DATA_TRACK) == 4) 56562306a36Sopenharmony_ci return te.cdte_addr.lba; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci printk(KERN_ERR "ISOFS: Invalid session number or type of track\n"); 56962306a36Sopenharmony_ci } 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci if (cdi) { 57262306a36Sopenharmony_ci struct cdrom_multisession ms_info; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci ms_info.addr_format = CDROM_LBA; 57562306a36Sopenharmony_ci if (cdrom_multisession(cdi, &ms_info) == 0) { 57662306a36Sopenharmony_ci#if WE_OBEY_THE_WRITTEN_STANDARDS 57762306a36Sopenharmony_ci /* necessary for a valid ms_info.addr */ 57862306a36Sopenharmony_ci if (ms_info.xa_flag) 57962306a36Sopenharmony_ci#endif 58062306a36Sopenharmony_ci vol_desc_start = ms_info.addr.lba; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci return vol_desc_start; 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci/* 58862306a36Sopenharmony_ci * Check if root directory is empty (has less than 3 files). 58962306a36Sopenharmony_ci * 59062306a36Sopenharmony_ci * Used to detect broken CDs where ISO root directory is empty but Joliet root 59162306a36Sopenharmony_ci * directory is OK. If such CD has Rock Ridge extensions, they will be disabled 59262306a36Sopenharmony_ci * (and Joliet used instead) or else no files would be visible. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_cistatic bool rootdir_empty(struct super_block *sb, unsigned long block) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci int offset = 0, files = 0, de_len; 59762306a36Sopenharmony_ci struct iso_directory_record *de; 59862306a36Sopenharmony_ci struct buffer_head *bh; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci bh = sb_bread(sb, block); 60162306a36Sopenharmony_ci if (!bh) 60262306a36Sopenharmony_ci return true; 60362306a36Sopenharmony_ci while (files < 3) { 60462306a36Sopenharmony_ci de = (struct iso_directory_record *) (bh->b_data + offset); 60562306a36Sopenharmony_ci de_len = *(unsigned char *) de; 60662306a36Sopenharmony_ci if (de_len == 0) 60762306a36Sopenharmony_ci break; 60862306a36Sopenharmony_ci files++; 60962306a36Sopenharmony_ci offset += de_len; 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci brelse(bh); 61262306a36Sopenharmony_ci return files < 3; 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * Initialize the superblock and read the root inode. 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic int isofs_fill_super(struct super_block *s, void *data, int silent) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct buffer_head *bh = NULL, *pri_bh = NULL; 62162306a36Sopenharmony_ci struct hs_primary_descriptor *h_pri = NULL; 62262306a36Sopenharmony_ci struct iso_primary_descriptor *pri = NULL; 62362306a36Sopenharmony_ci struct iso_supplementary_descriptor *sec = NULL; 62462306a36Sopenharmony_ci struct iso_directory_record *rootp; 62562306a36Sopenharmony_ci struct inode *inode; 62662306a36Sopenharmony_ci struct iso9660_options opt; 62762306a36Sopenharmony_ci struct isofs_sb_info *sbi; 62862306a36Sopenharmony_ci unsigned long first_data_zone; 62962306a36Sopenharmony_ci int joliet_level = 0; 63062306a36Sopenharmony_ci int iso_blknum, block; 63162306a36Sopenharmony_ci int orig_zonesize; 63262306a36Sopenharmony_ci int table, error = -EINVAL; 63362306a36Sopenharmony_ci unsigned int vol_desc_start; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); 63662306a36Sopenharmony_ci if (!sbi) 63762306a36Sopenharmony_ci return -ENOMEM; 63862306a36Sopenharmony_ci s->s_fs_info = sbi; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (!parse_options((char *)data, &opt)) 64162306a36Sopenharmony_ci goto out_freesbi; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci /* 64462306a36Sopenharmony_ci * First of all, get the hardware blocksize for this device. 64562306a36Sopenharmony_ci * If we don't know what it is, or the hardware blocksize is 64662306a36Sopenharmony_ci * larger than the blocksize the user specified, then use 64762306a36Sopenharmony_ci * that value. 64862306a36Sopenharmony_ci */ 64962306a36Sopenharmony_ci /* 65062306a36Sopenharmony_ci * What if bugger tells us to go beyond page size? 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci if (bdev_logical_block_size(s->s_bdev) > 2048) { 65362306a36Sopenharmony_ci printk(KERN_WARNING 65462306a36Sopenharmony_ci "ISOFS: unsupported/invalid hardware sector size %d\n", 65562306a36Sopenharmony_ci bdev_logical_block_size(s->s_bdev)); 65662306a36Sopenharmony_ci goto out_freesbi; 65762306a36Sopenharmony_ci } 65862306a36Sopenharmony_ci opt.blocksize = sb_min_blocksize(s, opt.blocksize); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci sbi->s_high_sierra = 0; /* default is iso9660 */ 66162306a36Sopenharmony_ci sbi->s_session = opt.session; 66262306a36Sopenharmony_ci sbi->s_sbsector = opt.sbsector; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci vol_desc_start = (opt.sbsector != -1) ? 66562306a36Sopenharmony_ci opt.sbsector : isofs_get_last_session(s,opt.session); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci for (iso_blknum = vol_desc_start+16; 66862306a36Sopenharmony_ci iso_blknum < vol_desc_start+100; iso_blknum++) { 66962306a36Sopenharmony_ci struct hs_volume_descriptor *hdp; 67062306a36Sopenharmony_ci struct iso_volume_descriptor *vdp; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci block = iso_blknum << (ISOFS_BLOCK_BITS - s->s_blocksize_bits); 67362306a36Sopenharmony_ci if (!(bh = sb_bread(s, block))) 67462306a36Sopenharmony_ci goto out_no_read; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci vdp = (struct iso_volume_descriptor *)bh->b_data; 67762306a36Sopenharmony_ci hdp = (struct hs_volume_descriptor *)bh->b_data; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* 68062306a36Sopenharmony_ci * Due to the overlapping physical location of the descriptors, 68162306a36Sopenharmony_ci * ISO CDs can match hdp->id==HS_STANDARD_ID as well. To ensure 68262306a36Sopenharmony_ci * proper identification in this case, we first check for ISO. 68362306a36Sopenharmony_ci */ 68462306a36Sopenharmony_ci if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { 68562306a36Sopenharmony_ci if (isonum_711(vdp->type) == ISO_VD_END) 68662306a36Sopenharmony_ci break; 68762306a36Sopenharmony_ci if (isonum_711(vdp->type) == ISO_VD_PRIMARY) { 68862306a36Sopenharmony_ci if (!pri) { 68962306a36Sopenharmony_ci pri = (struct iso_primary_descriptor *)vdp; 69062306a36Sopenharmony_ci /* Save the buffer in case we need it ... */ 69162306a36Sopenharmony_ci pri_bh = bh; 69262306a36Sopenharmony_ci bh = NULL; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 69662306a36Sopenharmony_ci else if (isonum_711(vdp->type) == ISO_VD_SUPPLEMENTARY) { 69762306a36Sopenharmony_ci sec = (struct iso_supplementary_descriptor *)vdp; 69862306a36Sopenharmony_ci if (sec->escape[0] == 0x25 && sec->escape[1] == 0x2f) { 69962306a36Sopenharmony_ci if (opt.joliet) { 70062306a36Sopenharmony_ci if (sec->escape[2] == 0x40) 70162306a36Sopenharmony_ci joliet_level = 1; 70262306a36Sopenharmony_ci else if (sec->escape[2] == 0x43) 70362306a36Sopenharmony_ci joliet_level = 2; 70462306a36Sopenharmony_ci else if (sec->escape[2] == 0x45) 70562306a36Sopenharmony_ci joliet_level = 3; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci printk(KERN_DEBUG "ISO 9660 Extensions: " 70862306a36Sopenharmony_ci "Microsoft Joliet Level %d\n", 70962306a36Sopenharmony_ci joliet_level); 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci goto root_found; 71262306a36Sopenharmony_ci } else { 71362306a36Sopenharmony_ci /* Unknown supplementary volume descriptor */ 71462306a36Sopenharmony_ci sec = NULL; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci#endif 71862306a36Sopenharmony_ci } else { 71962306a36Sopenharmony_ci if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { 72062306a36Sopenharmony_ci if (isonum_711(hdp->type) != ISO_VD_PRIMARY) 72162306a36Sopenharmony_ci goto out_freebh; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci sbi->s_high_sierra = 1; 72462306a36Sopenharmony_ci opt.rock = 0; 72562306a36Sopenharmony_ci h_pri = (struct hs_primary_descriptor *)vdp; 72662306a36Sopenharmony_ci goto root_found; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* Just skip any volume descriptors we don't recognize */ 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci brelse(bh); 73362306a36Sopenharmony_ci bh = NULL; 73462306a36Sopenharmony_ci } 73562306a36Sopenharmony_ci /* 73662306a36Sopenharmony_ci * If we fall through, either no volume descriptor was found, 73762306a36Sopenharmony_ci * or else we passed a primary descriptor looking for others. 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci if (!pri) 74062306a36Sopenharmony_ci goto out_unknown_format; 74162306a36Sopenharmony_ci brelse(bh); 74262306a36Sopenharmony_ci bh = pri_bh; 74362306a36Sopenharmony_ci pri_bh = NULL; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ciroot_found: 74662306a36Sopenharmony_ci /* We don't support read-write mounts */ 74762306a36Sopenharmony_ci if (!sb_rdonly(s)) { 74862306a36Sopenharmony_ci error = -EACCES; 74962306a36Sopenharmony_ci goto out_freebh; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci if (joliet_level && (!pri || !opt.rock)) { 75362306a36Sopenharmony_ci /* This is the case of Joliet with the norock mount flag. 75462306a36Sopenharmony_ci * A disc with both Joliet and Rock Ridge is handled later 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_ci pri = (struct iso_primary_descriptor *) sec; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if(sbi->s_high_sierra){ 76062306a36Sopenharmony_ci rootp = (struct iso_directory_record *) h_pri->root_directory_record; 76162306a36Sopenharmony_ci sbi->s_nzones = isonum_733(h_pri->volume_space_size); 76262306a36Sopenharmony_ci sbi->s_log_zone_size = isonum_723(h_pri->logical_block_size); 76362306a36Sopenharmony_ci sbi->s_max_size = isonum_733(h_pri->volume_space_size); 76462306a36Sopenharmony_ci } else { 76562306a36Sopenharmony_ci if (!pri) 76662306a36Sopenharmony_ci goto out_freebh; 76762306a36Sopenharmony_ci rootp = (struct iso_directory_record *) pri->root_directory_record; 76862306a36Sopenharmony_ci sbi->s_nzones = isonum_733(pri->volume_space_size); 76962306a36Sopenharmony_ci sbi->s_log_zone_size = isonum_723(pri->logical_block_size); 77062306a36Sopenharmony_ci sbi->s_max_size = isonum_733(pri->volume_space_size); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci sbi->s_ninodes = 0; /* No way to figure this out easily */ 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci orig_zonesize = sbi->s_log_zone_size; 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * If the zone size is smaller than the hardware sector size, 77862306a36Sopenharmony_ci * this is a fatal error. This would occur if the disc drive 77962306a36Sopenharmony_ci * had sectors that were 2048 bytes, but the filesystem had 78062306a36Sopenharmony_ci * blocks that were 512 bytes (which should only very rarely 78162306a36Sopenharmony_ci * happen.) 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_ci if (orig_zonesize < opt.blocksize) 78462306a36Sopenharmony_ci goto out_bad_size; 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci /* RDE: convert log zone size to bit shift */ 78762306a36Sopenharmony_ci switch (sbi->s_log_zone_size) { 78862306a36Sopenharmony_ci case 512: sbi->s_log_zone_size = 9; break; 78962306a36Sopenharmony_ci case 1024: sbi->s_log_zone_size = 10; break; 79062306a36Sopenharmony_ci case 2048: sbi->s_log_zone_size = 11; break; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci default: 79362306a36Sopenharmony_ci goto out_bad_zone_size; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci s->s_magic = ISOFS_SUPER_MAGIC; 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_ci /* 79962306a36Sopenharmony_ci * With multi-extent files, file size is only limited by the maximum 80062306a36Sopenharmony_ci * size of a file system, which is 8 TB. 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_ci s->s_maxbytes = 0x80000000000LL; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci /* ECMA-119 timestamp from 1900/1/1 with tz offset */ 80562306a36Sopenharmony_ci s->s_time_min = mktime64(1900, 1, 1, 0, 0, 0) - MAX_TZ_OFFSET; 80662306a36Sopenharmony_ci s->s_time_max = mktime64(U8_MAX+1900, 12, 31, 23, 59, 59) + MAX_TZ_OFFSET; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* Set this for reference. Its not currently used except on write 80962306a36Sopenharmony_ci which we don't have .. */ 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci first_data_zone = isonum_733(rootp->extent) + 81262306a36Sopenharmony_ci isonum_711(rootp->ext_attr_length); 81362306a36Sopenharmony_ci sbi->s_firstdatazone = first_data_zone; 81462306a36Sopenharmony_ci#ifndef BEQUIET 81562306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: Max size:%ld Log zone size:%ld\n", 81662306a36Sopenharmony_ci sbi->s_max_size, 1UL << sbi->s_log_zone_size); 81762306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: First datazone:%ld\n", sbi->s_firstdatazone); 81862306a36Sopenharmony_ci if(sbi->s_high_sierra) 81962306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: Disc in High Sierra format.\n"); 82062306a36Sopenharmony_ci#endif 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci /* 82362306a36Sopenharmony_ci * If the Joliet level is set, we _may_ decide to use the 82462306a36Sopenharmony_ci * secondary descriptor, but can't be sure until after we 82562306a36Sopenharmony_ci * read the root inode. But before reading the root inode 82662306a36Sopenharmony_ci * we may need to change the device blocksize, and would 82762306a36Sopenharmony_ci * rather release the old buffer first. So, we cache the 82862306a36Sopenharmony_ci * first_data_zone value from the secondary descriptor. 82962306a36Sopenharmony_ci */ 83062306a36Sopenharmony_ci if (joliet_level) { 83162306a36Sopenharmony_ci pri = (struct iso_primary_descriptor *) sec; 83262306a36Sopenharmony_ci rootp = (struct iso_directory_record *) 83362306a36Sopenharmony_ci pri->root_directory_record; 83462306a36Sopenharmony_ci first_data_zone = isonum_733(rootp->extent) + 83562306a36Sopenharmony_ci isonum_711(rootp->ext_attr_length); 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci /* 83962306a36Sopenharmony_ci * We're all done using the volume descriptor, and may need 84062306a36Sopenharmony_ci * to change the device blocksize, so release the buffer now. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci brelse(pri_bh); 84362306a36Sopenharmony_ci brelse(bh); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci /* 84662306a36Sopenharmony_ci * Force the blocksize to 512 for 512 byte sectors. The file 84762306a36Sopenharmony_ci * read primitives really get it wrong in a bad way if we don't 84862306a36Sopenharmony_ci * do this. 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * Note - we should never be setting the blocksize to something 85162306a36Sopenharmony_ci * less than the hardware sector size for the device. If we 85262306a36Sopenharmony_ci * do, we would end up having to read larger buffers and split 85362306a36Sopenharmony_ci * out portions to satisfy requests. 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Note2- the idea here is that we want to deal with the optimal 85662306a36Sopenharmony_ci * zonesize in the filesystem. If we have it set to something less, 85762306a36Sopenharmony_ci * then we have horrible problems with trying to piece together 85862306a36Sopenharmony_ci * bits of adjacent blocks in order to properly read directory 85962306a36Sopenharmony_ci * entries. By forcing the blocksize in this way, we ensure 86062306a36Sopenharmony_ci * that we will never be required to do this. 86162306a36Sopenharmony_ci */ 86262306a36Sopenharmony_ci sb_set_blocksize(s, orig_zonesize); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci sbi->s_nls_iocharset = NULL; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 86762306a36Sopenharmony_ci if (joliet_level) { 86862306a36Sopenharmony_ci char *p = opt.iocharset ? opt.iocharset : CONFIG_NLS_DEFAULT; 86962306a36Sopenharmony_ci if (strcmp(p, "utf8") != 0) { 87062306a36Sopenharmony_ci sbi->s_nls_iocharset = opt.iocharset ? 87162306a36Sopenharmony_ci load_nls(opt.iocharset) : load_nls_default(); 87262306a36Sopenharmony_ci if (!sbi->s_nls_iocharset) 87362306a36Sopenharmony_ci goto out_freesbi; 87462306a36Sopenharmony_ci } 87562306a36Sopenharmony_ci } 87662306a36Sopenharmony_ci#endif 87762306a36Sopenharmony_ci s->s_op = &isofs_sops; 87862306a36Sopenharmony_ci s->s_export_op = &isofs_export_ops; 87962306a36Sopenharmony_ci sbi->s_mapping = opt.map; 88062306a36Sopenharmony_ci sbi->s_rock = (opt.rock ? 2 : 0); 88162306a36Sopenharmony_ci sbi->s_rock_offset = -1; /* initial offset, will guess until SP is found*/ 88262306a36Sopenharmony_ci sbi->s_cruft = opt.cruft; 88362306a36Sopenharmony_ci sbi->s_hide = opt.hide; 88462306a36Sopenharmony_ci sbi->s_showassoc = opt.showassoc; 88562306a36Sopenharmony_ci sbi->s_uid = opt.uid; 88662306a36Sopenharmony_ci sbi->s_gid = opt.gid; 88762306a36Sopenharmony_ci sbi->s_uid_set = opt.uid_set; 88862306a36Sopenharmony_ci sbi->s_gid_set = opt.gid_set; 88962306a36Sopenharmony_ci sbi->s_nocompress = opt.nocompress; 89062306a36Sopenharmony_ci sbi->s_overriderockperm = opt.overriderockperm; 89162306a36Sopenharmony_ci /* 89262306a36Sopenharmony_ci * It would be incredibly stupid to allow people to mark every file 89362306a36Sopenharmony_ci * on the disk as suid, so we merely allow them to set the default 89462306a36Sopenharmony_ci * permissions. 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_ci if (opt.fmode != ISOFS_INVALID_MODE) 89762306a36Sopenharmony_ci sbi->s_fmode = opt.fmode & 0777; 89862306a36Sopenharmony_ci else 89962306a36Sopenharmony_ci sbi->s_fmode = ISOFS_INVALID_MODE; 90062306a36Sopenharmony_ci if (opt.dmode != ISOFS_INVALID_MODE) 90162306a36Sopenharmony_ci sbi->s_dmode = opt.dmode & 0777; 90262306a36Sopenharmony_ci else 90362306a36Sopenharmony_ci sbi->s_dmode = ISOFS_INVALID_MODE; 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* 90662306a36Sopenharmony_ci * Read the root inode, which _may_ result in changing 90762306a36Sopenharmony_ci * the s_rock flag. Once we have the final s_rock value, 90862306a36Sopenharmony_ci * we then decide whether to use the Joliet descriptor. 90962306a36Sopenharmony_ci */ 91062306a36Sopenharmony_ci inode = isofs_iget(s, sbi->s_firstdatazone, 0); 91162306a36Sopenharmony_ci if (IS_ERR(inode)) 91262306a36Sopenharmony_ci goto out_no_root; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* 91562306a36Sopenharmony_ci * Fix for broken CDs with Rock Ridge and empty ISO root directory but 91662306a36Sopenharmony_ci * correct Joliet root directory. 91762306a36Sopenharmony_ci */ 91862306a36Sopenharmony_ci if (sbi->s_rock == 1 && joliet_level && 91962306a36Sopenharmony_ci rootdir_empty(s, sbi->s_firstdatazone)) { 92062306a36Sopenharmony_ci printk(KERN_NOTICE 92162306a36Sopenharmony_ci "ISOFS: primary root directory is empty. " 92262306a36Sopenharmony_ci "Disabling Rock Ridge and switching to Joliet."); 92362306a36Sopenharmony_ci sbi->s_rock = 0; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci /* 92762306a36Sopenharmony_ci * If this disk has both Rock Ridge and Joliet on it, then we 92862306a36Sopenharmony_ci * want to use Rock Ridge by default. This can be overridden 92962306a36Sopenharmony_ci * by using the norock mount option. There is still one other 93062306a36Sopenharmony_ci * possibility that is not taken into account: a Rock Ridge 93162306a36Sopenharmony_ci * CD with Unicode names. Until someone sees such a beast, it 93262306a36Sopenharmony_ci * will not be supported. 93362306a36Sopenharmony_ci */ 93462306a36Sopenharmony_ci if (sbi->s_rock == 1) { 93562306a36Sopenharmony_ci joliet_level = 0; 93662306a36Sopenharmony_ci } else if (joliet_level) { 93762306a36Sopenharmony_ci sbi->s_rock = 0; 93862306a36Sopenharmony_ci if (sbi->s_firstdatazone != first_data_zone) { 93962306a36Sopenharmony_ci sbi->s_firstdatazone = first_data_zone; 94062306a36Sopenharmony_ci printk(KERN_DEBUG 94162306a36Sopenharmony_ci "ISOFS: changing to secondary root\n"); 94262306a36Sopenharmony_ci iput(inode); 94362306a36Sopenharmony_ci inode = isofs_iget(s, sbi->s_firstdatazone, 0); 94462306a36Sopenharmony_ci if (IS_ERR(inode)) 94562306a36Sopenharmony_ci goto out_no_root; 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci if (opt.check == 'u') { 95062306a36Sopenharmony_ci /* Only Joliet is case insensitive by default */ 95162306a36Sopenharmony_ci if (joliet_level) 95262306a36Sopenharmony_ci opt.check = 'r'; 95362306a36Sopenharmony_ci else 95462306a36Sopenharmony_ci opt.check = 's'; 95562306a36Sopenharmony_ci } 95662306a36Sopenharmony_ci sbi->s_joliet_level = joliet_level; 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* Make sure the root inode is a directory */ 95962306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) { 96062306a36Sopenharmony_ci printk(KERN_WARNING 96162306a36Sopenharmony_ci "isofs_fill_super: root inode is not a directory. " 96262306a36Sopenharmony_ci "Corrupted media?\n"); 96362306a36Sopenharmony_ci goto out_iput; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci table = 0; 96762306a36Sopenharmony_ci if (joliet_level) 96862306a36Sopenharmony_ci table += 2; 96962306a36Sopenharmony_ci if (opt.check == 'r') 97062306a36Sopenharmony_ci table++; 97162306a36Sopenharmony_ci sbi->s_check = opt.check; 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (table) 97462306a36Sopenharmony_ci s->s_d_op = &isofs_dentry_ops[table - 1]; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci /* get the root dentry */ 97762306a36Sopenharmony_ci s->s_root = d_make_root(inode); 97862306a36Sopenharmony_ci if (!(s->s_root)) { 97962306a36Sopenharmony_ci error = -ENOMEM; 98062306a36Sopenharmony_ci goto out_no_inode; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci kfree(opt.iocharset); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci return 0; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci /* 98862306a36Sopenharmony_ci * Display error messages and free resources. 98962306a36Sopenharmony_ci */ 99062306a36Sopenharmony_ciout_iput: 99162306a36Sopenharmony_ci iput(inode); 99262306a36Sopenharmony_ci goto out_no_inode; 99362306a36Sopenharmony_ciout_no_root: 99462306a36Sopenharmony_ci error = PTR_ERR(inode); 99562306a36Sopenharmony_ci if (error != -ENOMEM) 99662306a36Sopenharmony_ci printk(KERN_WARNING "%s: get root inode failed\n", __func__); 99762306a36Sopenharmony_ciout_no_inode: 99862306a36Sopenharmony_ci#ifdef CONFIG_JOLIET 99962306a36Sopenharmony_ci unload_nls(sbi->s_nls_iocharset); 100062306a36Sopenharmony_ci#endif 100162306a36Sopenharmony_ci goto out_freesbi; 100262306a36Sopenharmony_ciout_no_read: 100362306a36Sopenharmony_ci printk(KERN_WARNING "%s: bread failed, dev=%s, iso_blknum=%d, block=%d\n", 100462306a36Sopenharmony_ci __func__, s->s_id, iso_blknum, block); 100562306a36Sopenharmony_ci goto out_freebh; 100662306a36Sopenharmony_ciout_bad_zone_size: 100762306a36Sopenharmony_ci printk(KERN_WARNING "ISOFS: Bad logical zone size %ld\n", 100862306a36Sopenharmony_ci sbi->s_log_zone_size); 100962306a36Sopenharmony_ci goto out_freebh; 101062306a36Sopenharmony_ciout_bad_size: 101162306a36Sopenharmony_ci printk(KERN_WARNING "ISOFS: Logical zone size(%d) < hardware blocksize(%u)\n", 101262306a36Sopenharmony_ci orig_zonesize, opt.blocksize); 101362306a36Sopenharmony_ci goto out_freebh; 101462306a36Sopenharmony_ciout_unknown_format: 101562306a36Sopenharmony_ci if (!silent) 101662306a36Sopenharmony_ci printk(KERN_WARNING "ISOFS: Unable to identify CD-ROM format.\n"); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ciout_freebh: 101962306a36Sopenharmony_ci brelse(bh); 102062306a36Sopenharmony_ci brelse(pri_bh); 102162306a36Sopenharmony_ciout_freesbi: 102262306a36Sopenharmony_ci kfree(opt.iocharset); 102362306a36Sopenharmony_ci kfree(sbi); 102462306a36Sopenharmony_ci s->s_fs_info = NULL; 102562306a36Sopenharmony_ci return error; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int isofs_statfs (struct dentry *dentry, struct kstatfs *buf) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct super_block *sb = dentry->d_sb; 103162306a36Sopenharmony_ci u64 id = huge_encode_dev(sb->s_bdev->bd_dev); 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci buf->f_type = ISOFS_SUPER_MAGIC; 103462306a36Sopenharmony_ci buf->f_bsize = sb->s_blocksize; 103562306a36Sopenharmony_ci buf->f_blocks = (ISOFS_SB(sb)->s_nzones 103662306a36Sopenharmony_ci << (ISOFS_SB(sb)->s_log_zone_size - sb->s_blocksize_bits)); 103762306a36Sopenharmony_ci buf->f_bfree = 0; 103862306a36Sopenharmony_ci buf->f_bavail = 0; 103962306a36Sopenharmony_ci buf->f_files = ISOFS_SB(sb)->s_ninodes; 104062306a36Sopenharmony_ci buf->f_ffree = 0; 104162306a36Sopenharmony_ci buf->f_fsid = u64_to_fsid(id); 104262306a36Sopenharmony_ci buf->f_namelen = NAME_MAX; 104362306a36Sopenharmony_ci return 0; 104462306a36Sopenharmony_ci} 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci/* 104762306a36Sopenharmony_ci * Get a set of blocks; filling in buffer_heads if already allocated 104862306a36Sopenharmony_ci * or getblk() if they are not. Returns the number of blocks inserted 104962306a36Sopenharmony_ci * (-ve == error.) 105062306a36Sopenharmony_ci */ 105162306a36Sopenharmony_ciint isofs_get_blocks(struct inode *inode, sector_t iblock, 105262306a36Sopenharmony_ci struct buffer_head **bh, unsigned long nblocks) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci unsigned long b_off = iblock; 105562306a36Sopenharmony_ci unsigned offset, sect_size; 105662306a36Sopenharmony_ci unsigned int firstext; 105762306a36Sopenharmony_ci unsigned long nextblk, nextoff; 105862306a36Sopenharmony_ci int section, rv, error; 105962306a36Sopenharmony_ci struct iso_inode_info *ei = ISOFS_I(inode); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci error = -EIO; 106262306a36Sopenharmony_ci rv = 0; 106362306a36Sopenharmony_ci if (iblock != b_off) { 106462306a36Sopenharmony_ci printk(KERN_DEBUG "%s: block number too large\n", __func__); 106562306a36Sopenharmony_ci goto abort; 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci offset = 0; 107062306a36Sopenharmony_ci firstext = ei->i_first_extent; 107162306a36Sopenharmony_ci sect_size = ei->i_section_size >> ISOFS_BUFFER_BITS(inode); 107262306a36Sopenharmony_ci nextblk = ei->i_next_section_block; 107362306a36Sopenharmony_ci nextoff = ei->i_next_section_offset; 107462306a36Sopenharmony_ci section = 0; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci while (nblocks) { 107762306a36Sopenharmony_ci /* If we are *way* beyond the end of the file, print a message. 107862306a36Sopenharmony_ci * Access beyond the end of the file up to the next page boundary 107962306a36Sopenharmony_ci * is normal, however because of the way the page cache works. 108062306a36Sopenharmony_ci * In this case, we just return 0 so that we can properly fill 108162306a36Sopenharmony_ci * the page with useless information without generating any 108262306a36Sopenharmony_ci * I/O errors. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_ci if (b_off > ((inode->i_size + PAGE_SIZE - 1) >> ISOFS_BUFFER_BITS(inode))) { 108562306a36Sopenharmony_ci printk(KERN_DEBUG "%s: block >= EOF (%lu, %llu)\n", 108662306a36Sopenharmony_ci __func__, b_off, 108762306a36Sopenharmony_ci (unsigned long long)inode->i_size); 108862306a36Sopenharmony_ci goto abort; 108962306a36Sopenharmony_ci } 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci /* On the last section, nextblk == 0, section size is likely to 109262306a36Sopenharmony_ci * exceed sect_size by a partial block, and access beyond the 109362306a36Sopenharmony_ci * end of the file will reach beyond the section size, too. 109462306a36Sopenharmony_ci */ 109562306a36Sopenharmony_ci while (nextblk && (b_off >= (offset + sect_size))) { 109662306a36Sopenharmony_ci struct inode *ninode; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci offset += sect_size; 109962306a36Sopenharmony_ci ninode = isofs_iget(inode->i_sb, nextblk, nextoff); 110062306a36Sopenharmony_ci if (IS_ERR(ninode)) { 110162306a36Sopenharmony_ci error = PTR_ERR(ninode); 110262306a36Sopenharmony_ci goto abort; 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci firstext = ISOFS_I(ninode)->i_first_extent; 110562306a36Sopenharmony_ci sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode); 110662306a36Sopenharmony_ci nextblk = ISOFS_I(ninode)->i_next_section_block; 110762306a36Sopenharmony_ci nextoff = ISOFS_I(ninode)->i_next_section_offset; 110862306a36Sopenharmony_ci iput(ninode); 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (++section > 100) { 111162306a36Sopenharmony_ci printk(KERN_DEBUG "%s: More than 100 file sections ?!?" 111262306a36Sopenharmony_ci " aborting...\n", __func__); 111362306a36Sopenharmony_ci printk(KERN_DEBUG "%s: block=%lu firstext=%u sect_size=%u " 111462306a36Sopenharmony_ci "nextblk=%lu nextoff=%lu\n", __func__, 111562306a36Sopenharmony_ci b_off, firstext, (unsigned) sect_size, 111662306a36Sopenharmony_ci nextblk, nextoff); 111762306a36Sopenharmony_ci goto abort; 111862306a36Sopenharmony_ci } 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (*bh) { 112262306a36Sopenharmony_ci map_bh(*bh, inode->i_sb, firstext + b_off - offset); 112362306a36Sopenharmony_ci } else { 112462306a36Sopenharmony_ci *bh = sb_getblk(inode->i_sb, firstext+b_off-offset); 112562306a36Sopenharmony_ci if (!*bh) 112662306a36Sopenharmony_ci goto abort; 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci bh++; /* Next buffer head */ 112962306a36Sopenharmony_ci b_off++; /* Next buffer offset */ 113062306a36Sopenharmony_ci nblocks--; 113162306a36Sopenharmony_ci rv++; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci error = 0; 113562306a36Sopenharmony_ciabort: 113662306a36Sopenharmony_ci return rv != 0 ? rv : error; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci/* 114062306a36Sopenharmony_ci * Used by the standard interfaces. 114162306a36Sopenharmony_ci */ 114262306a36Sopenharmony_cistatic int isofs_get_block(struct inode *inode, sector_t iblock, 114362306a36Sopenharmony_ci struct buffer_head *bh_result, int create) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci int ret; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (create) { 114862306a36Sopenharmony_ci printk(KERN_DEBUG "%s: Kernel tries to allocate a block\n", __func__); 114962306a36Sopenharmony_ci return -EROFS; 115062306a36Sopenharmony_ci } 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_ci ret = isofs_get_blocks(inode, iblock, &bh_result, 1); 115362306a36Sopenharmony_ci return ret < 0 ? ret : 0; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic int isofs_bmap(struct inode *inode, sector_t block) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci struct buffer_head dummy; 115962306a36Sopenharmony_ci int error; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci dummy.b_state = 0; 116262306a36Sopenharmony_ci dummy.b_blocknr = -1000; 116362306a36Sopenharmony_ci error = isofs_get_block(inode, block, &dummy, 0); 116462306a36Sopenharmony_ci if (!error) 116562306a36Sopenharmony_ci return dummy.b_blocknr; 116662306a36Sopenharmony_ci return 0; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistruct buffer_head *isofs_bread(struct inode *inode, sector_t block) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci sector_t blknr = isofs_bmap(inode, block); 117262306a36Sopenharmony_ci if (!blknr) 117362306a36Sopenharmony_ci return NULL; 117462306a36Sopenharmony_ci return sb_bread(inode->i_sb, blknr); 117562306a36Sopenharmony_ci} 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cistatic int isofs_read_folio(struct file *file, struct folio *folio) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci return mpage_read_folio(folio, isofs_get_block); 118062306a36Sopenharmony_ci} 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_cistatic void isofs_readahead(struct readahead_control *rac) 118362306a36Sopenharmony_ci{ 118462306a36Sopenharmony_ci mpage_readahead(rac, isofs_get_block); 118562306a36Sopenharmony_ci} 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_cistatic sector_t _isofs_bmap(struct address_space *mapping, sector_t block) 118862306a36Sopenharmony_ci{ 118962306a36Sopenharmony_ci return generic_block_bmap(mapping,block,isofs_get_block); 119062306a36Sopenharmony_ci} 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_cistatic const struct address_space_operations isofs_aops = { 119362306a36Sopenharmony_ci .read_folio = isofs_read_folio, 119462306a36Sopenharmony_ci .readahead = isofs_readahead, 119562306a36Sopenharmony_ci .bmap = _isofs_bmap 119662306a36Sopenharmony_ci}; 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_cistatic int isofs_read_level3_size(struct inode *inode) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 120162306a36Sopenharmony_ci int high_sierra = ISOFS_SB(inode->i_sb)->s_high_sierra; 120262306a36Sopenharmony_ci struct buffer_head *bh = NULL; 120362306a36Sopenharmony_ci unsigned long block, offset, block_saved, offset_saved; 120462306a36Sopenharmony_ci int i = 0; 120562306a36Sopenharmony_ci int more_entries = 0; 120662306a36Sopenharmony_ci struct iso_directory_record *tmpde = NULL; 120762306a36Sopenharmony_ci struct iso_inode_info *ei = ISOFS_I(inode); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci inode->i_size = 0; 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci /* The first 16 blocks are reserved as the System Area. Thus, 121262306a36Sopenharmony_ci * no inodes can appear in block 0. We use this to flag that 121362306a36Sopenharmony_ci * this is the last section. */ 121462306a36Sopenharmony_ci ei->i_next_section_block = 0; 121562306a36Sopenharmony_ci ei->i_next_section_offset = 0; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci block = ei->i_iget5_block; 121862306a36Sopenharmony_ci offset = ei->i_iget5_offset; 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci do { 122162306a36Sopenharmony_ci struct iso_directory_record *de; 122262306a36Sopenharmony_ci unsigned int de_len; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (!bh) { 122562306a36Sopenharmony_ci bh = sb_bread(inode->i_sb, block); 122662306a36Sopenharmony_ci if (!bh) 122762306a36Sopenharmony_ci goto out_noread; 122862306a36Sopenharmony_ci } 122962306a36Sopenharmony_ci de = (struct iso_directory_record *) (bh->b_data + offset); 123062306a36Sopenharmony_ci de_len = *(unsigned char *) de; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (de_len == 0) { 123362306a36Sopenharmony_ci brelse(bh); 123462306a36Sopenharmony_ci bh = NULL; 123562306a36Sopenharmony_ci ++block; 123662306a36Sopenharmony_ci offset = 0; 123762306a36Sopenharmony_ci continue; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci block_saved = block; 124162306a36Sopenharmony_ci offset_saved = offset; 124262306a36Sopenharmony_ci offset += de_len; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci /* Make sure we have a full directory entry */ 124562306a36Sopenharmony_ci if (offset >= bufsize) { 124662306a36Sopenharmony_ci int slop = bufsize - offset + de_len; 124762306a36Sopenharmony_ci if (!tmpde) { 124862306a36Sopenharmony_ci tmpde = kmalloc(256, GFP_KERNEL); 124962306a36Sopenharmony_ci if (!tmpde) 125062306a36Sopenharmony_ci goto out_nomem; 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci memcpy(tmpde, de, slop); 125362306a36Sopenharmony_ci offset &= bufsize - 1; 125462306a36Sopenharmony_ci block++; 125562306a36Sopenharmony_ci brelse(bh); 125662306a36Sopenharmony_ci bh = NULL; 125762306a36Sopenharmony_ci if (offset) { 125862306a36Sopenharmony_ci bh = sb_bread(inode->i_sb, block); 125962306a36Sopenharmony_ci if (!bh) 126062306a36Sopenharmony_ci goto out_noread; 126162306a36Sopenharmony_ci memcpy((void *)tmpde+slop, bh->b_data, offset); 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci de = tmpde; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci inode->i_size += isonum_733(de->size); 126762306a36Sopenharmony_ci if (i == 1) { 126862306a36Sopenharmony_ci ei->i_next_section_block = block_saved; 126962306a36Sopenharmony_ci ei->i_next_section_offset = offset_saved; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci more_entries = de->flags[-high_sierra] & 0x80; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci i++; 127562306a36Sopenharmony_ci if (i > 100) 127662306a36Sopenharmony_ci goto out_toomany; 127762306a36Sopenharmony_ci } while (more_entries); 127862306a36Sopenharmony_ciout: 127962306a36Sopenharmony_ci kfree(tmpde); 128062306a36Sopenharmony_ci brelse(bh); 128162306a36Sopenharmony_ci return 0; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ciout_nomem: 128462306a36Sopenharmony_ci brelse(bh); 128562306a36Sopenharmony_ci return -ENOMEM; 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ciout_noread: 128862306a36Sopenharmony_ci printk(KERN_INFO "ISOFS: unable to read i-node block %lu\n", block); 128962306a36Sopenharmony_ci kfree(tmpde); 129062306a36Sopenharmony_ci return -EIO; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ciout_toomany: 129362306a36Sopenharmony_ci printk(KERN_INFO "%s: More than 100 file sections ?!?, aborting...\n" 129462306a36Sopenharmony_ci "isofs_read_level3_size: inode=%lu\n", 129562306a36Sopenharmony_ci __func__, inode->i_ino); 129662306a36Sopenharmony_ci goto out; 129762306a36Sopenharmony_ci} 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_cistatic int isofs_read_inode(struct inode *inode, int relocated) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 130262306a36Sopenharmony_ci struct isofs_sb_info *sbi = ISOFS_SB(sb); 130362306a36Sopenharmony_ci unsigned long bufsize = ISOFS_BUFFER_SIZE(inode); 130462306a36Sopenharmony_ci unsigned long block; 130562306a36Sopenharmony_ci int high_sierra = sbi->s_high_sierra; 130662306a36Sopenharmony_ci struct buffer_head *bh; 130762306a36Sopenharmony_ci struct iso_directory_record *de; 130862306a36Sopenharmony_ci struct iso_directory_record *tmpde = NULL; 130962306a36Sopenharmony_ci unsigned int de_len; 131062306a36Sopenharmony_ci unsigned long offset; 131162306a36Sopenharmony_ci struct iso_inode_info *ei = ISOFS_I(inode); 131262306a36Sopenharmony_ci int ret = -EIO; 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci block = ei->i_iget5_block; 131562306a36Sopenharmony_ci bh = sb_bread(inode->i_sb, block); 131662306a36Sopenharmony_ci if (!bh) 131762306a36Sopenharmony_ci goto out_badread; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci offset = ei->i_iget5_offset; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci de = (struct iso_directory_record *) (bh->b_data + offset); 132262306a36Sopenharmony_ci de_len = *(unsigned char *) de; 132362306a36Sopenharmony_ci if (de_len < sizeof(struct iso_directory_record)) 132462306a36Sopenharmony_ci goto fail; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (offset + de_len > bufsize) { 132762306a36Sopenharmony_ci int frag1 = bufsize - offset; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci tmpde = kmalloc(de_len, GFP_KERNEL); 133062306a36Sopenharmony_ci if (!tmpde) { 133162306a36Sopenharmony_ci ret = -ENOMEM; 133262306a36Sopenharmony_ci goto fail; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci memcpy(tmpde, bh->b_data + offset, frag1); 133562306a36Sopenharmony_ci brelse(bh); 133662306a36Sopenharmony_ci bh = sb_bread(inode->i_sb, ++block); 133762306a36Sopenharmony_ci if (!bh) 133862306a36Sopenharmony_ci goto out_badread; 133962306a36Sopenharmony_ci memcpy((char *)tmpde+frag1, bh->b_data, de_len - frag1); 134062306a36Sopenharmony_ci de = tmpde; 134162306a36Sopenharmony_ci } 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci inode->i_ino = isofs_get_ino(ei->i_iget5_block, 134462306a36Sopenharmony_ci ei->i_iget5_offset, 134562306a36Sopenharmony_ci ISOFS_BUFFER_BITS(inode)); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci /* Assume it is a normal-format file unless told otherwise */ 134862306a36Sopenharmony_ci ei->i_file_format = isofs_file_normal; 134962306a36Sopenharmony_ci 135062306a36Sopenharmony_ci if (de->flags[-high_sierra] & 2) { 135162306a36Sopenharmony_ci if (sbi->s_dmode != ISOFS_INVALID_MODE) 135262306a36Sopenharmony_ci inode->i_mode = S_IFDIR | sbi->s_dmode; 135362306a36Sopenharmony_ci else 135462306a36Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; 135562306a36Sopenharmony_ci set_nlink(inode, 1); /* 135662306a36Sopenharmony_ci * Set to 1. We know there are 2, but 135762306a36Sopenharmony_ci * the find utility tries to optimize 135862306a36Sopenharmony_ci * if it is 2, and it screws up. It is 135962306a36Sopenharmony_ci * easier to give 1 which tells find to 136062306a36Sopenharmony_ci * do it the hard way. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci } else { 136362306a36Sopenharmony_ci if (sbi->s_fmode != ISOFS_INVALID_MODE) { 136462306a36Sopenharmony_ci inode->i_mode = S_IFREG | sbi->s_fmode; 136562306a36Sopenharmony_ci } else { 136662306a36Sopenharmony_ci /* 136762306a36Sopenharmony_ci * Set default permissions: r-x for all. The disc 136862306a36Sopenharmony_ci * could be shared with DOS machines so virtually 136962306a36Sopenharmony_ci * anything could be a valid executable. 137062306a36Sopenharmony_ci */ 137162306a36Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUGO | S_IXUGO; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci set_nlink(inode, 1); 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci inode->i_uid = sbi->s_uid; 137662306a36Sopenharmony_ci inode->i_gid = sbi->s_gid; 137762306a36Sopenharmony_ci inode->i_blocks = 0; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ei->i_format_parm[0] = 0; 138062306a36Sopenharmony_ci ei->i_format_parm[1] = 0; 138162306a36Sopenharmony_ci ei->i_format_parm[2] = 0; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci ei->i_section_size = isonum_733(de->size); 138462306a36Sopenharmony_ci if (de->flags[-high_sierra] & 0x80) { 138562306a36Sopenharmony_ci ret = isofs_read_level3_size(inode); 138662306a36Sopenharmony_ci if (ret < 0) 138762306a36Sopenharmony_ci goto fail; 138862306a36Sopenharmony_ci ret = -EIO; 138962306a36Sopenharmony_ci } else { 139062306a36Sopenharmony_ci ei->i_next_section_block = 0; 139162306a36Sopenharmony_ci ei->i_next_section_offset = 0; 139262306a36Sopenharmony_ci inode->i_size = isonum_733(de->size); 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci /* 139662306a36Sopenharmony_ci * Some dipshit decided to store some other bit of information 139762306a36Sopenharmony_ci * in the high byte of the file length. Truncate size in case 139862306a36Sopenharmony_ci * this CDROM was mounted with the cruft option. 139962306a36Sopenharmony_ci */ 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci if (sbi->s_cruft) 140262306a36Sopenharmony_ci inode->i_size &= 0x00ffffff; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (de->interleave[0]) { 140562306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: Interleaved files not (yet) supported.\n"); 140662306a36Sopenharmony_ci inode->i_size = 0; 140762306a36Sopenharmony_ci } 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci /* I have no idea what file_unit_size is used for, so 141062306a36Sopenharmony_ci we will flag it for now */ 141162306a36Sopenharmony_ci if (de->file_unit_size[0] != 0) { 141262306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: File unit size != 0 for ISO file (%ld).\n", 141362306a36Sopenharmony_ci inode->i_ino); 141462306a36Sopenharmony_ci } 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci /* I have no idea what other flag bits are used for, so 141762306a36Sopenharmony_ci we will flag it for now */ 141862306a36Sopenharmony_ci#ifdef DEBUG 141962306a36Sopenharmony_ci if((de->flags[-high_sierra] & ~2)!= 0){ 142062306a36Sopenharmony_ci printk(KERN_DEBUG "ISOFS: Unusual flag settings for ISO file " 142162306a36Sopenharmony_ci "(%ld %x).\n", 142262306a36Sopenharmony_ci inode->i_ino, de->flags[-high_sierra]); 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci#endif 142562306a36Sopenharmony_ci inode->i_mtime = inode->i_atime = 142662306a36Sopenharmony_ci inode_set_ctime(inode, iso_date(de->date, high_sierra), 0); 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci ei->i_first_extent = (isonum_733(de->extent) + 142962306a36Sopenharmony_ci isonum_711(de->ext_attr_length)); 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci /* Set the number of blocks for stat() - should be done before RR */ 143262306a36Sopenharmony_ci inode->i_blocks = (inode->i_size + 511) >> 9; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* 143562306a36Sopenharmony_ci * Now test for possible Rock Ridge extensions which will override 143662306a36Sopenharmony_ci * some of these numbers in the inode structure. 143762306a36Sopenharmony_ci */ 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (!high_sierra) { 144062306a36Sopenharmony_ci parse_rock_ridge_inode(de, inode, relocated); 144162306a36Sopenharmony_ci /* if we want uid/gid set, override the rock ridge setting */ 144262306a36Sopenharmony_ci if (sbi->s_uid_set) 144362306a36Sopenharmony_ci inode->i_uid = sbi->s_uid; 144462306a36Sopenharmony_ci if (sbi->s_gid_set) 144562306a36Sopenharmony_ci inode->i_gid = sbi->s_gid; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci /* Now set final access rights if overriding rock ridge setting */ 144862306a36Sopenharmony_ci if (S_ISDIR(inode->i_mode) && sbi->s_overriderockperm && 144962306a36Sopenharmony_ci sbi->s_dmode != ISOFS_INVALID_MODE) 145062306a36Sopenharmony_ci inode->i_mode = S_IFDIR | sbi->s_dmode; 145162306a36Sopenharmony_ci if (S_ISREG(inode->i_mode) && sbi->s_overriderockperm && 145262306a36Sopenharmony_ci sbi->s_fmode != ISOFS_INVALID_MODE) 145362306a36Sopenharmony_ci inode->i_mode = S_IFREG | sbi->s_fmode; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci /* Install the inode operations vector */ 145662306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 145762306a36Sopenharmony_ci inode->i_fop = &generic_ro_fops; 145862306a36Sopenharmony_ci switch (ei->i_file_format) { 145962306a36Sopenharmony_ci#ifdef CONFIG_ZISOFS 146062306a36Sopenharmony_ci case isofs_file_compressed: 146162306a36Sopenharmony_ci inode->i_data.a_ops = &zisofs_aops; 146262306a36Sopenharmony_ci break; 146362306a36Sopenharmony_ci#endif 146462306a36Sopenharmony_ci default: 146562306a36Sopenharmony_ci inode->i_data.a_ops = &isofs_aops; 146662306a36Sopenharmony_ci break; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci } else if (S_ISDIR(inode->i_mode)) { 146962306a36Sopenharmony_ci inode->i_op = &isofs_dir_inode_operations; 147062306a36Sopenharmony_ci inode->i_fop = &isofs_dir_operations; 147162306a36Sopenharmony_ci } else if (S_ISLNK(inode->i_mode)) { 147262306a36Sopenharmony_ci inode->i_op = &page_symlink_inode_operations; 147362306a36Sopenharmony_ci inode_nohighmem(inode); 147462306a36Sopenharmony_ci inode->i_data.a_ops = &isofs_symlink_aops; 147562306a36Sopenharmony_ci } else 147662306a36Sopenharmony_ci /* XXX - parse_rock_ridge_inode() had already set i_rdev. */ 147762306a36Sopenharmony_ci init_special_inode(inode, inode->i_mode, inode->i_rdev); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci ret = 0; 148062306a36Sopenharmony_ciout: 148162306a36Sopenharmony_ci kfree(tmpde); 148262306a36Sopenharmony_ci brelse(bh); 148362306a36Sopenharmony_ci return ret; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ciout_badread: 148662306a36Sopenharmony_ci printk(KERN_WARNING "ISOFS: unable to read i-node block\n"); 148762306a36Sopenharmony_cifail: 148862306a36Sopenharmony_ci goto out; 148962306a36Sopenharmony_ci} 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_cistruct isofs_iget5_callback_data { 149262306a36Sopenharmony_ci unsigned long block; 149362306a36Sopenharmony_ci unsigned long offset; 149462306a36Sopenharmony_ci}; 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_cistatic int isofs_iget5_test(struct inode *ino, void *data) 149762306a36Sopenharmony_ci{ 149862306a36Sopenharmony_ci struct iso_inode_info *i = ISOFS_I(ino); 149962306a36Sopenharmony_ci struct isofs_iget5_callback_data *d = 150062306a36Sopenharmony_ci (struct isofs_iget5_callback_data*)data; 150162306a36Sopenharmony_ci return (i->i_iget5_block == d->block) 150262306a36Sopenharmony_ci && (i->i_iget5_offset == d->offset); 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cistatic int isofs_iget5_set(struct inode *ino, void *data) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci struct iso_inode_info *i = ISOFS_I(ino); 150862306a36Sopenharmony_ci struct isofs_iget5_callback_data *d = 150962306a36Sopenharmony_ci (struct isofs_iget5_callback_data*)data; 151062306a36Sopenharmony_ci i->i_iget5_block = d->block; 151162306a36Sopenharmony_ci i->i_iget5_offset = d->offset; 151262306a36Sopenharmony_ci return 0; 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci/* Store, in the inode's containing structure, the block and block 151662306a36Sopenharmony_ci * offset that point to the underlying meta-data for the inode. The 151762306a36Sopenharmony_ci * code below is otherwise similar to the iget() code in 151862306a36Sopenharmony_ci * include/linux/fs.h */ 151962306a36Sopenharmony_cistruct inode *__isofs_iget(struct super_block *sb, 152062306a36Sopenharmony_ci unsigned long block, 152162306a36Sopenharmony_ci unsigned long offset, 152262306a36Sopenharmony_ci int relocated) 152362306a36Sopenharmony_ci{ 152462306a36Sopenharmony_ci unsigned long hashval; 152562306a36Sopenharmony_ci struct inode *inode; 152662306a36Sopenharmony_ci struct isofs_iget5_callback_data data; 152762306a36Sopenharmony_ci long ret; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (offset >= 1ul << sb->s_blocksize_bits) 153062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci data.block = block; 153362306a36Sopenharmony_ci data.offset = offset; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci hashval = (block << sb->s_blocksize_bits) | offset; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci inode = iget5_locked(sb, hashval, &isofs_iget5_test, 153862306a36Sopenharmony_ci &isofs_iget5_set, &data); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (!inode) 154162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (inode->i_state & I_NEW) { 154462306a36Sopenharmony_ci ret = isofs_read_inode(inode, relocated); 154562306a36Sopenharmony_ci if (ret < 0) { 154662306a36Sopenharmony_ci iget_failed(inode); 154762306a36Sopenharmony_ci inode = ERR_PTR(ret); 154862306a36Sopenharmony_ci } else { 154962306a36Sopenharmony_ci unlock_new_inode(inode); 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci return inode; 155462306a36Sopenharmony_ci} 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_cistatic struct dentry *isofs_mount(struct file_system_type *fs_type, 155762306a36Sopenharmony_ci int flags, const char *dev_name, void *data) 155862306a36Sopenharmony_ci{ 155962306a36Sopenharmony_ci return mount_bdev(fs_type, flags, dev_name, data, isofs_fill_super); 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_cistatic struct file_system_type iso9660_fs_type = { 156362306a36Sopenharmony_ci .owner = THIS_MODULE, 156462306a36Sopenharmony_ci .name = "iso9660", 156562306a36Sopenharmony_ci .mount = isofs_mount, 156662306a36Sopenharmony_ci .kill_sb = kill_block_super, 156762306a36Sopenharmony_ci .fs_flags = FS_REQUIRES_DEV, 156862306a36Sopenharmony_ci}; 156962306a36Sopenharmony_ciMODULE_ALIAS_FS("iso9660"); 157062306a36Sopenharmony_ciMODULE_ALIAS("iso9660"); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_cistatic int __init init_iso9660_fs(void) 157362306a36Sopenharmony_ci{ 157462306a36Sopenharmony_ci int err = init_inodecache(); 157562306a36Sopenharmony_ci if (err) 157662306a36Sopenharmony_ci goto out; 157762306a36Sopenharmony_ci#ifdef CONFIG_ZISOFS 157862306a36Sopenharmony_ci err = zisofs_init(); 157962306a36Sopenharmony_ci if (err) 158062306a36Sopenharmony_ci goto out1; 158162306a36Sopenharmony_ci#endif 158262306a36Sopenharmony_ci err = register_filesystem(&iso9660_fs_type); 158362306a36Sopenharmony_ci if (err) 158462306a36Sopenharmony_ci goto out2; 158562306a36Sopenharmony_ci return 0; 158662306a36Sopenharmony_ciout2: 158762306a36Sopenharmony_ci#ifdef CONFIG_ZISOFS 158862306a36Sopenharmony_ci zisofs_cleanup(); 158962306a36Sopenharmony_ciout1: 159062306a36Sopenharmony_ci#endif 159162306a36Sopenharmony_ci destroy_inodecache(); 159262306a36Sopenharmony_ciout: 159362306a36Sopenharmony_ci return err; 159462306a36Sopenharmony_ci} 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_cistatic void __exit exit_iso9660_fs(void) 159762306a36Sopenharmony_ci{ 159862306a36Sopenharmony_ci unregister_filesystem(&iso9660_fs_type); 159962306a36Sopenharmony_ci#ifdef CONFIG_ZISOFS 160062306a36Sopenharmony_ci zisofs_cleanup(); 160162306a36Sopenharmony_ci#endif 160262306a36Sopenharmony_ci destroy_inodecache(); 160362306a36Sopenharmony_ci} 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_cimodule_init(init_iso9660_fs) 160662306a36Sopenharmony_cimodule_exit(exit_iso9660_fs) 160762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1608