b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 3) * linux/fs/isofs/namei.c
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * (C) 1992 Eric Youngdale Modified for ISO 9660 filesystem.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * (C) 1991 Linus Torvalds - minix filesystem
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9)
5a0e3ad6af866 (Tejun Heo 2010-03-24 17:04:11 +0900 10) #include <linux/gfp.h>
94f2f715771d0 (Al Viro 2005-04-25 18:32:12 -0700 11) #include "isofs.h"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 14) * ok, we cannot use strncmp, as the name is not in our data space.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) * Thus we'll have to use isofs_match. No big problem. Match also makes
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) * some sanity tests.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) static int
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 19) isofs_cmp(struct dentry *dentry, const char *compare, int dlen)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) struct qstr qstr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 22) qstr.name = compare;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) qstr.len = dlen;
b0afd8e5db7b1 (Al Viro 2014-10-28 18:40:11 -0400 24) if (likely(!dentry->d_op))
b0afd8e5db7b1 (Al Viro 2014-10-28 18:40:11 -0400 25) return dentry->d_name.len != dlen || memcmp(dentry->d_name.name, compare, dlen);
6fa67e7075593 (Al Viro 2016-07-31 16:37:25 -0400 26) return dentry->d_op->d_compare(NULL, dentry->d_name.len, dentry->d_name.name, &qstr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 27) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) * isofs_find_entry()
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) * finds an entry in the specified directory with the wanted name. It
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) * returns the inode number of the found entry, or 0 on error.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) static unsigned long
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36) isofs_find_entry(struct inode *dir, struct dentry *dentry,
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 37) unsigned long *block_rv, unsigned long *offset_rv,
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 38) char *tmpname, struct iso_directory_record *tmpde)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 40) unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42) unsigned long block, f_pos, offset, block_saved, offset_saved;
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 43) struct buffer_head *bh = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 44) struct isofs_sb_info *sbi = ISOFS_SB(dir->i_sb);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 45)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) if (!ISOFS_I(dir)->i_first_extent)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 47) return 0;
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 48)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 49) f_pos = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 50) offset = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 51) block = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 52)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 53) while (f_pos < dir->i_size) {
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 54) struct iso_directory_record *de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) int de_len, match, i, dlen;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56) char *dpnt;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 57)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 58) if (!bh) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) bh = isofs_bread(dir, block);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 60) if (!bh)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 61) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 62) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) de = (struct iso_directory_record *) (bh->b_data + offset);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66) de_len = *(unsigned char *) de;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 67) if (!de_len) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 68) brelse(bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 69) bh = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 70) f_pos = (f_pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 71) block = f_pos >> bufbits;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72) offset = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 73) continue;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 74) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 76) block_saved = bh->b_blocknr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77) offset_saved = offset;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78) offset += de_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 79) f_pos += de_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 80)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 81) /* Make sure we have a full directory entry */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82) if (offset >= bufsize) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 83) int slop = bufsize - offset + de_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 84) memcpy(tmpde, de, slop);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85) offset &= bufsize - 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) block++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87) brelse(bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88) bh = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89) if (offset) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) bh = isofs_bread(dir, block);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91) if (!bh)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) memcpy((void *) tmpde + slop, bh->b_data, offset);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) de = tmpde;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) dlen = de->name_len[0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) dpnt = de->name;
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 100) /* Basic sanity check, whether name doesn't exceed dir entry */
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 101) if (de_len < dlen + sizeof(struct iso_directory_record)) {
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 102) printk(KERN_NOTICE "iso9660: Corrupted directory entry"
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 103) " in block %lu of inode %lu\n", block,
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 104) dir->i_ino);
0a6dc67a6aa45 (Pan Bian 2021-01-18 04:04:55 -0800 105) brelse(bh);
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 106) return 0;
2deb1acc653cb (Jan Kara 2008-04-30 00:52:33 -0700 107) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 108)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 109) if (sbi->s_rock &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110) ((i = get_rock_ridge_filename(de, tmpname, dir)))) {
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 111) dlen = i; /* possibly -1 */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) dpnt = tmpname;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113) #ifdef CONFIG_JOLIET
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114) } else if (sbi->s_joliet_level) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 115) dlen = get_joliet_filename(de, tmpname, dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 116) dpnt = tmpname;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118) } else if (sbi->s_mapping == 'a') {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 119) dlen = get_acorn_filename(de, tmpname, dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 120) dpnt = tmpname;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 121) } else if (sbi->s_mapping == 'n') {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 122) dlen = isofs_name_translate(de, tmpname, dir);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 123) dpnt = tmpname;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 124) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 125)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 126) /*
9769f4eb3fad2 (Jeremy White 2005-06-21 17:16:53 -0700 127) * Skip hidden or associated files unless hide or showassoc,
9769f4eb3fad2 (Jeremy White 2005-06-21 17:16:53 -0700 128) * respectively, is set
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130) match = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) if (dlen > 0 &&
5404ac8e4418a (Jan Kara 2009-06-17 16:26:27 -0700 132) (!sbi->s_hide ||
9769f4eb3fad2 (Jeremy White 2005-06-21 17:16:53 -0700 133) (!(de->flags[-sbi->s_high_sierra] & 1))) &&
5404ac8e4418a (Jan Kara 2009-06-17 16:26:27 -0700 134) (sbi->s_showassoc ||
9769f4eb3fad2 (Jeremy White 2005-06-21 17:16:53 -0700 135) (!(de->flags[-sbi->s_high_sierra] & 4)))) {
f643ff550afbc (Al Viro 2014-10-28 18:37:40 -0400 136) if (dpnt && (dlen > 1 || dpnt[0] > 1))
f643ff550afbc (Al Viro 2014-10-28 18:37:40 -0400 137) match = (isofs_cmp(dentry, dpnt, dlen) == 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 139) if (match) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 140) isofs_normalize_block_and_offset(de,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) &block_saved,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) &offset_saved);
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 143) *block_rv = block_saved;
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 144) *offset_rv = offset_saved;
9769f4eb3fad2 (Jeremy White 2005-06-21 17:16:53 -0700 145) brelse(bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 146) return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) }
9769f4eb3fad2 (Jeremy White 2005-06-21 17:16:53 -0700 149) brelse(bh);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 152)
00cd8dd3bf95f (Al Viro 2012-06-10 17:13:09 -0400 153) struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 154) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 155) int found;
3f649ab728cda (Kees Cook 2020-06-03 13:09:38 -0700 156) unsigned long block;
3f649ab728cda (Kees Cook 2020-06-03 13:09:38 -0700 157) unsigned long offset;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 158) struct inode *inode;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 159) struct page *page;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 160)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 161) page = alloc_page(GFP_USER);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) if (!page)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 163) return ERR_PTR(-ENOMEM);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) found = isofs_find_entry(dir, dentry,
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 166) &block, &offset,
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 167) page_address(page),
c3ed85a36ff5b (Dave Jones 2007-07-15 23:40:03 -0700 168) 1024 + page_address(page));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) __free_page(page);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 170)
a9049376ee05b (Al Viro 2011-07-08 21:20:11 -0400 171) inode = found ? isofs_iget(dir->i_sb, block, offset) : NULL;
a9049376ee05b (Al Viro 2011-07-08 21:20:11 -0400 172)
2ff6b1c2575f1 (Pekka Enberg 2006-01-14 13:21:09 -0800 173) return d_splice_alias(inode, dentry);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 174) }