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