1*1da177e4SLinus Torvalds /* 2*1da177e4SLinus Torvalds * linux/fs/isofs/namei.c 3*1da177e4SLinus Torvalds * 4*1da177e4SLinus Torvalds * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem. 5*1da177e4SLinus Torvalds * 6*1da177e4SLinus Torvalds * (C) 1991 Linus Torvalds - minix filesystem 7*1da177e4SLinus Torvalds */ 8*1da177e4SLinus Torvalds 9*1da177e4SLinus Torvalds #include <linux/time.h> 10*1da177e4SLinus Torvalds #include <linux/iso_fs.h> 11*1da177e4SLinus Torvalds #include <linux/kernel.h> 12*1da177e4SLinus Torvalds #include <linux/string.h> 13*1da177e4SLinus Torvalds #include <linux/stat.h> 14*1da177e4SLinus Torvalds #include <linux/fcntl.h> 15*1da177e4SLinus Torvalds #include <linux/mm.h> 16*1da177e4SLinus Torvalds #include <linux/errno.h> 17*1da177e4SLinus Torvalds #include <linux/config.h> /* Joliet? */ 18*1da177e4SLinus Torvalds #include <linux/smp_lock.h> 19*1da177e4SLinus Torvalds #include <linux/buffer_head.h> 20*1da177e4SLinus Torvalds #include <linux/dcache.h> 21*1da177e4SLinus Torvalds 22*1da177e4SLinus Torvalds #include <asm/uaccess.h> 23*1da177e4SLinus Torvalds 24*1da177e4SLinus Torvalds /* 25*1da177e4SLinus Torvalds * ok, we cannot use strncmp, as the name is not in our data space. 26*1da177e4SLinus Torvalds * Thus we'll have to use isofs_match. No big problem. Match also makes 27*1da177e4SLinus Torvalds * some sanity tests. 28*1da177e4SLinus Torvalds */ 29*1da177e4SLinus Torvalds static int 30*1da177e4SLinus Torvalds isofs_cmp(struct dentry * dentry, const char * compare, int dlen) 31*1da177e4SLinus Torvalds { 32*1da177e4SLinus Torvalds struct qstr qstr; 33*1da177e4SLinus Torvalds 34*1da177e4SLinus Torvalds if (!compare) 35*1da177e4SLinus Torvalds return 1; 36*1da177e4SLinus Torvalds 37*1da177e4SLinus Torvalds /* check special "." and ".." files */ 38*1da177e4SLinus Torvalds if (dlen == 1) { 39*1da177e4SLinus Torvalds /* "." */ 40*1da177e4SLinus Torvalds if (compare[0] == 0) { 41*1da177e4SLinus Torvalds if (!dentry->d_name.len) 42*1da177e4SLinus Torvalds return 0; 43*1da177e4SLinus Torvalds compare = "."; 44*1da177e4SLinus Torvalds } else if (compare[0] == 1) { 45*1da177e4SLinus Torvalds compare = ".."; 46*1da177e4SLinus Torvalds dlen = 2; 47*1da177e4SLinus Torvalds } 48*1da177e4SLinus Torvalds } 49*1da177e4SLinus Torvalds 50*1da177e4SLinus Torvalds qstr.name = compare; 51*1da177e4SLinus Torvalds qstr.len = dlen; 52*1da177e4SLinus Torvalds return dentry->d_op->d_compare(dentry, &dentry->d_name, &qstr); 53*1da177e4SLinus Torvalds } 54*1da177e4SLinus Torvalds 55*1da177e4SLinus Torvalds /* 56*1da177e4SLinus Torvalds * isofs_find_entry() 57*1da177e4SLinus Torvalds * 58*1da177e4SLinus Torvalds * finds an entry in the specified directory with the wanted name. It 59*1da177e4SLinus Torvalds * returns the inode number of the found entry, or 0 on error. 60*1da177e4SLinus Torvalds */ 61*1da177e4SLinus Torvalds static unsigned long 62*1da177e4SLinus Torvalds isofs_find_entry(struct inode *dir, struct dentry *dentry, 63*1da177e4SLinus Torvalds unsigned long *block_rv, unsigned long* offset_rv, 64*1da177e4SLinus Torvalds char * tmpname, struct iso_directory_record * tmpde) 65*1da177e4SLinus Torvalds { 66*1da177e4SLinus Torvalds unsigned long bufsize = ISOFS_BUFFER_SIZE(dir); 67*1da177e4SLinus Torvalds unsigned char bufbits = ISOFS_BUFFER_BITS(dir); 68*1da177e4SLinus Torvalds unsigned long block, f_pos, offset, block_saved, offset_saved; 69*1da177e4SLinus Torvalds struct buffer_head * bh = NULL; 70*1da177e4SLinus Torvalds struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb); 71*1da177e4SLinus Torvalds 72*1da177e4SLinus Torvalds if (!ISOFS_I(dir)->i_first_extent) 73*1da177e4SLinus Torvalds return 0; 74*1da177e4SLinus Torvalds 75*1da177e4SLinus Torvalds f_pos = 0; 76*1da177e4SLinus Torvalds offset = 0; 77*1da177e4SLinus Torvalds block = 0; 78*1da177e4SLinus Torvalds 79*1da177e4SLinus Torvalds while (f_pos < dir->i_size) { 80*1da177e4SLinus Torvalds struct iso_directory_record * de; 81*1da177e4SLinus Torvalds int de_len, match, i, dlen; 82*1da177e4SLinus Torvalds char *dpnt; 83*1da177e4SLinus Torvalds 84*1da177e4SLinus Torvalds if (!bh) { 85*1da177e4SLinus Torvalds bh = isofs_bread(dir, block); 86*1da177e4SLinus Torvalds if (!bh) 87*1da177e4SLinus Torvalds return 0; 88*1da177e4SLinus Torvalds } 89*1da177e4SLinus Torvalds 90*1da177e4SLinus Torvalds de = (struct iso_directory_record *) (bh->b_data + offset); 91*1da177e4SLinus Torvalds 92*1da177e4SLinus Torvalds de_len = *(unsigned char *) de; 93*1da177e4SLinus Torvalds if (!de_len) { 94*1da177e4SLinus Torvalds brelse(bh); 95*1da177e4SLinus Torvalds bh = NULL; 96*1da177e4SLinus Torvalds f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1); 97*1da177e4SLinus Torvalds block = f_pos >> bufbits; 98*1da177e4SLinus Torvalds offset = 0; 99*1da177e4SLinus Torvalds continue; 100*1da177e4SLinus Torvalds } 101*1da177e4SLinus Torvalds 102*1da177e4SLinus Torvalds block_saved = bh->b_blocknr; 103*1da177e4SLinus Torvalds offset_saved = offset; 104*1da177e4SLinus Torvalds offset += de_len; 105*1da177e4SLinus Torvalds f_pos += de_len; 106*1da177e4SLinus Torvalds 107*1da177e4SLinus Torvalds /* Make sure we have a full directory entry */ 108*1da177e4SLinus Torvalds if (offset >= bufsize) { 109*1da177e4SLinus Torvalds int slop = bufsize - offset + de_len; 110*1da177e4SLinus Torvalds memcpy(tmpde, de, slop); 111*1da177e4SLinus Torvalds offset &= bufsize - 1; 112*1da177e4SLinus Torvalds block++; 113*1da177e4SLinus Torvalds brelse(bh); 114*1da177e4SLinus Torvalds bh = NULL; 115*1da177e4SLinus Torvalds if (offset) { 116*1da177e4SLinus Torvalds bh = isofs_bread(dir, block); 117*1da177e4SLinus Torvalds if (!bh) 118*1da177e4SLinus Torvalds return 0; 119*1da177e4SLinus Torvalds memcpy((void *) tmpde + slop, bh->b_data, offset); 120*1da177e4SLinus Torvalds } 121*1da177e4SLinus Torvalds de = tmpde; 122*1da177e4SLinus Torvalds } 123*1da177e4SLinus Torvalds 124*1da177e4SLinus Torvalds dlen = de->name_len[0]; 125*1da177e4SLinus Torvalds dpnt = de->name; 126*1da177e4SLinus Torvalds 127*1da177e4SLinus Torvalds if (sbi->s_rock && 128*1da177e4SLinus Torvalds ((i = get_rock_ridge_filename(de, tmpname, dir)))) { 129*1da177e4SLinus Torvalds dlen = i; /* possibly -1 */ 130*1da177e4SLinus Torvalds dpnt = tmpname; 131*1da177e4SLinus Torvalds #ifdef CONFIG_JOLIET 132*1da177e4SLinus Torvalds } else if (sbi->s_joliet_level) { 133*1da177e4SLinus Torvalds dlen = get_joliet_filename(de, tmpname, dir); 134*1da177e4SLinus Torvalds dpnt = tmpname; 135*1da177e4SLinus Torvalds #endif 136*1da177e4SLinus Torvalds } else if (sbi->s_mapping == 'a') { 137*1da177e4SLinus Torvalds dlen = get_acorn_filename(de, tmpname, dir); 138*1da177e4SLinus Torvalds dpnt = tmpname; 139*1da177e4SLinus Torvalds } else if (sbi->s_mapping == 'n') { 140*1da177e4SLinus Torvalds dlen = isofs_name_translate(de, tmpname, dir); 141*1da177e4SLinus Torvalds dpnt = tmpname; 142*1da177e4SLinus Torvalds } 143*1da177e4SLinus Torvalds 144*1da177e4SLinus Torvalds /* 145*1da177e4SLinus Torvalds * Skip hidden or associated files unless unhide is set 146*1da177e4SLinus Torvalds */ 147*1da177e4SLinus Torvalds match = 0; 148*1da177e4SLinus Torvalds if (dlen > 0 && 149*1da177e4SLinus Torvalds (!(de->flags[-sbi->s_high_sierra] & 5) 150*1da177e4SLinus Torvalds || sbi->s_unhide == 'y')) 151*1da177e4SLinus Torvalds { 152*1da177e4SLinus Torvalds match = (isofs_cmp(dentry,dpnt,dlen) == 0); 153*1da177e4SLinus Torvalds } 154*1da177e4SLinus Torvalds if (match) { 155*1da177e4SLinus Torvalds isofs_normalize_block_and_offset(de, 156*1da177e4SLinus Torvalds &block_saved, 157*1da177e4SLinus Torvalds &offset_saved); 158*1da177e4SLinus Torvalds *block_rv = block_saved; 159*1da177e4SLinus Torvalds *offset_rv = offset_saved; 160*1da177e4SLinus Torvalds if (bh) brelse(bh); 161*1da177e4SLinus Torvalds return 1; 162*1da177e4SLinus Torvalds } 163*1da177e4SLinus Torvalds } 164*1da177e4SLinus Torvalds if (bh) brelse(bh); 165*1da177e4SLinus Torvalds return 0; 166*1da177e4SLinus Torvalds } 167*1da177e4SLinus Torvalds 168*1da177e4SLinus Torvalds struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry, struct nameidata *nd) 169*1da177e4SLinus Torvalds { 170*1da177e4SLinus Torvalds int found; 171*1da177e4SLinus Torvalds unsigned long block, offset; 172*1da177e4SLinus Torvalds struct inode *inode; 173*1da177e4SLinus Torvalds struct page *page; 174*1da177e4SLinus Torvalds 175*1da177e4SLinus Torvalds dentry->d_op = dir->i_sb->s_root->d_op; 176*1da177e4SLinus Torvalds 177*1da177e4SLinus Torvalds page = alloc_page(GFP_USER); 178*1da177e4SLinus Torvalds if (!page) 179*1da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 180*1da177e4SLinus Torvalds 181*1da177e4SLinus Torvalds lock_kernel(); 182*1da177e4SLinus Torvalds found = isofs_find_entry(dir, dentry, 183*1da177e4SLinus Torvalds &block, &offset, 184*1da177e4SLinus Torvalds page_address(page), 185*1da177e4SLinus Torvalds 1024 + page_address(page)); 186*1da177e4SLinus Torvalds __free_page(page); 187*1da177e4SLinus Torvalds 188*1da177e4SLinus Torvalds inode = NULL; 189*1da177e4SLinus Torvalds if (found) { 190*1da177e4SLinus Torvalds inode = isofs_iget(dir->i_sb, block, offset); 191*1da177e4SLinus Torvalds if (!inode) { 192*1da177e4SLinus Torvalds unlock_kernel(); 193*1da177e4SLinus Torvalds return ERR_PTR(-EACCES); 194*1da177e4SLinus Torvalds } 195*1da177e4SLinus Torvalds } 196*1da177e4SLinus Torvalds unlock_kernel(); 197*1da177e4SLinus Torvalds if (inode) 198*1da177e4SLinus Torvalds return d_splice_alias(inode, dentry); 199*1da177e4SLinus Torvalds d_add(dentry, inode); 200*1da177e4SLinus Torvalds return NULL; 201*1da177e4SLinus Torvalds } 202