xref: /linux/fs/qnx6/dir.c (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * QNX6 file system, Linux implementation.
4  *
5  * Version : 1.0.0
6  *
7  * History :
8  *
9  * 01-02-2012 by Kai Bankett (chaosman@ontika.net) : first release.
10  * 16-02-2012 pagemap extension by Al Viro
11  *
12  */
13 
14 #include <linux/filelock.h>
15 #include "qnx6.h"
16 
17 static unsigned qnx6_lfile_checksum(char *name, unsigned size)
18 {
19 	unsigned crc = 0;
20 	char *end = name + size;
21 	while (name < end) {
22 		crc = ((crc >> 1) + *(name++)) ^
23 			((crc & 0x00000001) ? 0x80000000 : 0);
24 	}
25 	return crc;
26 }
27 
28 static void *qnx6_get_folio(struct inode *dir, unsigned long n,
29 		struct folio **foliop)
30 {
31 	struct folio *folio = read_mapping_folio(dir->i_mapping, n, NULL);
32 
33 	if (IS_ERR(folio))
34 		return folio;
35 	*foliop = folio;
36 	return kmap_local_folio(folio, 0);
37 }
38 
39 static unsigned last_entry(struct inode *inode, unsigned long page_nr)
40 {
41 	unsigned long last_byte = inode->i_size;
42 	last_byte -= page_nr << PAGE_SHIFT;
43 	if (last_byte > PAGE_SIZE)
44 		last_byte = PAGE_SIZE;
45 	return last_byte / QNX6_DIR_ENTRY_SIZE;
46 }
47 
48 static struct qnx6_long_filename *qnx6_longname(struct super_block *sb,
49 					 struct qnx6_long_dir_entry *de,
50 					 struct folio **foliop)
51 {
52 	struct qnx6_sb_info *sbi = QNX6_SB(sb);
53 	u32 s = fs32_to_cpu(sbi, de->de_long_inode); /* in block units */
54 	u32 n = s >> (PAGE_SHIFT - sb->s_blocksize_bits); /* in pages */
55 	u32 offs;
56 	struct address_space *mapping = sbi->longfile->i_mapping;
57 	struct folio *folio = read_mapping_folio(mapping, n, NULL);
58 
59 	if (IS_ERR(folio))
60 		return ERR_CAST(folio);
61 	offs = offset_in_folio(folio, s << sb->s_blocksize_bits);
62 	*foliop = folio;
63 	return kmap_local_folio(folio, offs);
64 }
65 
66 static int qnx6_dir_longfilename(struct inode *inode,
67 			struct qnx6_long_dir_entry *de,
68 			struct dir_context *ctx,
69 			unsigned de_inode)
70 {
71 	struct qnx6_long_filename *lf;
72 	struct super_block *s = inode->i_sb;
73 	struct qnx6_sb_info *sbi = QNX6_SB(s);
74 	struct folio *folio;
75 	int lf_size;
76 
77 	if (de->de_size != 0xff) {
78 		/* error - long filename entries always have size 0xff
79 		   in direntry */
80 		pr_err("invalid direntry size (%i).\n", de->de_size);
81 		return 0;
82 	}
83 	lf = qnx6_longname(s, de, &folio);
84 	if (IS_ERR(lf)) {
85 		pr_err("Error reading longname\n");
86 		return 0;
87 	}
88 
89 	lf_size = fs16_to_cpu(sbi, lf->lf_size);
90 
91 	if (lf_size > QNX6_LONG_NAME_MAX) {
92 		pr_debug("file %s\n", lf->lf_fname);
93 		pr_err("Filename too long (%i)\n", lf_size);
94 		folio_release_kmap(folio, lf);
95 		return 0;
96 	}
97 
98 	/* calc & validate longfilename checksum
99 	   mmi 3g filesystem does not have that checksum */
100 	if (!test_opt(s, MMI_FS) && fs32_to_cpu(sbi, de->de_checksum) !=
101 			qnx6_lfile_checksum(lf->lf_fname, lf_size))
102 		pr_info("long filename checksum error.\n");
103 
104 	pr_debug("qnx6_readdir:%.*s inode:%u\n",
105 		 lf_size, lf->lf_fname, de_inode);
106 	if (!dir_emit(ctx, lf->lf_fname, lf_size, de_inode, DT_UNKNOWN)) {
107 		folio_release_kmap(folio, lf);
108 		return 0;
109 	}
110 
111 	folio_release_kmap(folio, lf);
112 	/* success */
113 	return 1;
114 }
115 
116 static int qnx6_readdir(struct file *file, struct dir_context *ctx)
117 {
118 	struct inode *inode = file_inode(file);
119 	struct super_block *s = inode->i_sb;
120 	struct qnx6_sb_info *sbi = QNX6_SB(s);
121 	loff_t pos = ctx->pos & ~(QNX6_DIR_ENTRY_SIZE - 1);
122 	unsigned long npages = dir_pages(inode);
123 	unsigned long n = pos >> PAGE_SHIFT;
124 	unsigned offset = (pos & ~PAGE_MASK) / QNX6_DIR_ENTRY_SIZE;
125 	bool done = false;
126 
127 	ctx->pos = pos;
128 	if (ctx->pos >= inode->i_size)
129 		return 0;
130 
131 	for ( ; !done && n < npages; n++, offset = 0) {
132 		struct qnx6_dir_entry *de;
133 		struct folio *folio;
134 		char *kaddr = qnx6_get_folio(inode, n, &folio);
135 		char *limit;
136 
137 		if (IS_ERR(kaddr)) {
138 			pr_err("%s(): read failed\n", __func__);
139 			ctx->pos = (n + 1) << PAGE_SHIFT;
140 			return PTR_ERR(kaddr);
141 		}
142 		de = (struct qnx6_dir_entry *)(kaddr + offset);
143 		limit = kaddr + last_entry(inode, n);
144 		for (; (char *)de < limit; de++, ctx->pos += QNX6_DIR_ENTRY_SIZE) {
145 			int size = de->de_size;
146 			u32 no_inode = fs32_to_cpu(sbi, de->de_inode);
147 
148 			if (!no_inode || !size)
149 				continue;
150 
151 			if (size > QNX6_SHORT_NAME_MAX) {
152 				/* long filename detected
153 				   get the filename from long filename
154 				   structure / block */
155 				if (!qnx6_dir_longfilename(inode,
156 					(struct qnx6_long_dir_entry *)de,
157 					ctx, no_inode)) {
158 					done = true;
159 					break;
160 				}
161 			} else {
162 				pr_debug("%s():%.*s inode:%u\n",
163 					 __func__, size, de->de_fname,
164 					 no_inode);
165 				if (!dir_emit(ctx, de->de_fname, size,
166 				      no_inode, DT_UNKNOWN)) {
167 					done = true;
168 					break;
169 				}
170 			}
171 		}
172 		folio_release_kmap(folio, kaddr);
173 	}
174 	return 0;
175 }
176 
177 /*
178  * check if the long filename is correct.
179  */
180 static unsigned qnx6_long_match(int len, const char *name,
181 			struct qnx6_long_dir_entry *de, struct inode *dir)
182 {
183 	struct super_block *s = dir->i_sb;
184 	struct qnx6_sb_info *sbi = QNX6_SB(s);
185 	struct folio *folio;
186 	int thislen;
187 	struct qnx6_long_filename *lf = qnx6_longname(s, de, &folio);
188 
189 	if (IS_ERR(lf))
190 		return 0;
191 
192 	thislen = fs16_to_cpu(sbi, lf->lf_size);
193 	if (len != thislen) {
194 		folio_release_kmap(folio, lf);
195 		return 0;
196 	}
197 	if (memcmp(name, lf->lf_fname, len) == 0) {
198 		folio_release_kmap(folio, lf);
199 		return fs32_to_cpu(sbi, de->de_inode);
200 	}
201 	folio_release_kmap(folio, lf);
202 	return 0;
203 }
204 
205 /*
206  * check if the filename is correct.
207  */
208 static unsigned qnx6_match(struct super_block *s, int len, const char *name,
209 			struct qnx6_dir_entry *de)
210 {
211 	struct qnx6_sb_info *sbi = QNX6_SB(s);
212 	if (memcmp(name, de->de_fname, len) == 0)
213 		return fs32_to_cpu(sbi, de->de_inode);
214 	return 0;
215 }
216 
217 
218 unsigned qnx6_find_ino(int len, struct inode *dir, const char *name)
219 {
220 	struct super_block *s = dir->i_sb;
221 	struct qnx6_inode_info *ei = QNX6_I(dir);
222 	struct folio *folio;
223 	unsigned long start, n;
224 	unsigned long npages = dir_pages(dir);
225 	unsigned ino;
226 	struct qnx6_dir_entry *de;
227 	struct qnx6_long_dir_entry *lde;
228 
229 	if (npages == 0)
230 		return 0;
231 	start = ei->i_dir_start_lookup;
232 	if (start >= npages)
233 		start = 0;
234 	n = start;
235 
236 	do {
237 		de = qnx6_get_folio(dir, n, &folio);
238 		if (!IS_ERR(de)) {
239 			int limit = last_entry(dir, n);
240 			int i;
241 
242 			for (i = 0; i < limit; i++, de++) {
243 				if (len <= QNX6_SHORT_NAME_MAX) {
244 					/* short filename */
245 					if (len != de->de_size)
246 						continue;
247 					ino = qnx6_match(s, len, name, de);
248 					if (ino)
249 						goto found;
250 				} else if (de->de_size == 0xff) {
251 					/* deal with long filename */
252 					lde = (struct qnx6_long_dir_entry *)de;
253 					ino = qnx6_long_match(len,
254 								name, lde, dir);
255 					if (ino)
256 						goto found;
257 				} else
258 					pr_err("undefined filename size in inode.\n");
259 			}
260 			folio_release_kmap(folio, de - i);
261 		}
262 
263 		if (++n >= npages)
264 			n = 0;
265 	} while (n != start);
266 	return 0;
267 
268 found:
269 	ei->i_dir_start_lookup = n;
270 	folio_release_kmap(folio, de);
271 	return ino;
272 }
273 
274 const struct file_operations qnx6_dir_operations = {
275 	.llseek		= generic_file_llseek,
276 	.read		= generic_read_dir,
277 	.iterate_shared	= qnx6_readdir,
278 	.fsync		= generic_file_fsync,
279 	.setlease	= generic_setlease,
280 };
281 
282 const struct inode_operations qnx6_dir_inode_operations = {
283 	.lookup		= qnx6_lookup,
284 };
285