File Index
Files and directories
Sign in
FILE

dir.c

File preview with syntax highlighting.

linux-6.19.14/fs/isofs/dir.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 *  linux/fs/isofs/dir.c
  4 *
  5 *  (C) 1992, 1993, 1994  Eric Youngdale Modified for ISO 9660 filesystem.
  6 *
  7 *  (C) 1991  Linus Torvalds - minix filesystem
  8 *
  9 *  Steve Beynon		       : Missing last directory entries fixed
 10 *  (stephen@askone.demon.co.uk)      : 21st June 1996
 11 *
 12 *  isofs directory handling functions
 13 */
 14#include <linux/gfp.h>
 15#include "isofs.h"
 16
 17int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
 18{
 19	char * old = de->name;
 20	int len = de->name_len[0];
 21	int i;
 22
 23	for (i = 0; i < len; i++) {
 24		unsigned char c = old[i];
 25		if (!c)
 26			break;
 27
 28		if (c >= 'A' && c <= 'Z')
 29			c |= 0x20;	/* lower case */
 30
 31		/* Drop trailing '.;1' (ISO 9660:1988 7.5.1 requires period) */
 32		if (c == '.' && i == len - 3 && old[i + 1] == ';' && old[i + 2] == '1')
 33			break;
 34
 35		/* Drop trailing ';1' */
 36		if (c == ';' && i == len - 2 && old[i + 1] == '1')
 37			break;
 38
 39		/* Convert remaining ';' to '.' */
 40		/* Also '/' to '.' (broken Acorn-generated ISO9660 images) */
 41		if (c == ';' || c == '/')
 42			c = '.';
 43
 44		new[i] = c;
 45	}
 46	return i;
 47}
 48
 49/* Acorn extensions written by Matthew Wilcox <willy@infradead.org> 1998 */
 50int get_acorn_filename(struct iso_directory_record *de,
 51			    char *retname, struct inode *inode)
 52{
 53	int std;
 54	unsigned char *chr;
 55	int retnamlen = isofs_name_translate(de, retname, inode);
 56
 57	if (retnamlen == 0)
 58		return 0;
 59	std = sizeof(struct iso_directory_record) + de->name_len[0];
 60	if (std & 1)
 61		std++;
 62	if (de->length[0] - std != 32)
 63		return retnamlen;
 64	chr = ((unsigned char *) de) + std;
 65	if (strncmp(chr, "ARCHIMEDES", 10))
 66		return retnamlen;
 67	if ((*retname == '_') && ((chr[19] & 1) == 1))
 68		*retname = '!';
 69	if (((de->flags[0] & 2) == 0) && (chr[13] == 0xff)
 70		&& ((chr[12] & 0xf0) == 0xf0)) {
 71		retname[retnamlen] = ',';
 72		sprintf(retname+retnamlen+1, "%3.3x",
 73			((chr[12] & 0xf) << 8) | chr[11]);
 74		retnamlen += 4;
 75	}
 76	return retnamlen;
 77}
 78
 79/*
 80 * This should _really_ be cleaned up some day..
 81 */
 82static int do_isofs_readdir(struct inode *inode, struct file *file,
 83		struct dir_context *ctx,
 84		char *tmpname, struct iso_directory_record *tmpde)
 85{
 86	unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
 87	unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
 88	unsigned long block, offset, block_saved, offset_saved;
 89	unsigned long inode_number = 0;	/* Quiet GCC */
 90	struct buffer_head *bh = NULL;
 91	int len;
 92	int map;
 93	int first_de = 1;
 94	char *p = NULL;		/* Quiet GCC */
 95	struct iso_directory_record *de;
 96	struct isofs_sb_info *sbi = ISOFS_SB(inode->i_sb);
 97
 98	offset = ctx->pos & (bufsize - 1);
 99	block = ctx->pos >> bufbits;
100
101	while (ctx->pos < inode->i_size) {
102		int de_len;
103
104		if (!bh) {
105			bh = isofs_bread(inode, block);
106			if (!bh)
107				return 0;
108		}
109
110		de = (struct iso_directory_record *) (bh->b_data + offset);
111
112		de_len = *(unsigned char *)de;
113
114		/*
115		 * If the length byte is zero, we should move on to the next
116		 * CDROM sector.  If we are at the end of the directory, we
117		 * kick out of the while loop.
118		 */
119
120		if (de_len == 0) {
121			brelse(bh);
122			bh = NULL;
123			ctx->pos = (ctx->pos + ISOFS_BLOCK_SIZE) & ~(ISOFS_BLOCK_SIZE - 1);
124			block = ctx->pos >> bufbits;
125			offset = 0;
126			continue;
127		}
128
129		block_saved = block;
130		offset_saved = offset;
131		offset += de_len;
132
133		/* Make sure we have a full directory entry */
134		if (offset >= bufsize) {
135			int slop = bufsize - offset + de_len;
136			memcpy(tmpde, de, slop);
137			offset &= bufsize - 1;
138			block++;
139			brelse(bh);
140			bh = NULL;
141			if (offset) {
142				bh = isofs_bread(inode, block);
143				if (!bh)
144					return 0;
145				memcpy((void *) tmpde + slop, bh->b_data, offset);
146			}
147			de = tmpde;
148		}
149		/* Basic sanity check, whether name doesn't exceed dir entry */
150		if (de_len < sizeof(struct iso_directory_record) ||
151		    de_len < de->name_len[0] +
152					sizeof(struct iso_directory_record)) {
153			printk(KERN_NOTICE "iso9660: Corrupted directory entry"
154			       " in block %lu of inode %lu\n", block,
155			       inode->i_ino);
156			brelse(bh);
157			return -EIO;
158		}
159
160		if (first_de) {
161			isofs_normalize_block_and_offset(de,
162							&block_saved,
163							&offset_saved);
164			inode_number = isofs_get_ino(block_saved,
165							offset_saved, bufbits);
166		}
167
168		if (de->flags[-sbi->s_high_sierra] & 0x80) {
169			first_de = 0;
170			ctx->pos += de_len;
171			continue;
172		}
173		first_de = 1;
174
175		/* Handle the case of the '.' directory */
176		if (de->name_len[0] == 1 && de->name[0] == 0) {
177			if (!dir_emit_dot(file, ctx))
178				break;
179			ctx->pos += de_len;
180			continue;
181		}
182
183		len = 0;
184
185		/* Handle the case of the '..' directory */
186		if (de->name_len[0] == 1 && de->name[0] == 1) {
187			if (!dir_emit_dotdot(file, ctx))
188				break;
189			ctx->pos += de_len;
190			continue;
191		}
192
193		/* Handle everything else.  Do name translation if there
194		   is no Rock Ridge NM field. */
195
196		/*
197		 * Do not report hidden files if so instructed, or associated
198		 * files unless instructed to do so
199		 */
200		if ((sbi->s_hide && (de->flags[-sbi->s_high_sierra] & 1)) ||
201		    (!sbi->s_showassoc &&
202				(de->flags[-sbi->s_high_sierra] & 4))) {
203			ctx->pos += de_len;
204			continue;
205		}
206
207		map = 1;
208		if (sbi->s_rock) {
209			len = get_rock_ridge_filename(de, tmpname, inode);
210			if (len != 0) {		/* may be -1 */
211				p = tmpname;
212				map = 0;
213			}
214		}
215		if (map) {
216#ifdef CONFIG_JOLIET
217			if (sbi->s_joliet_level) {
218				len = get_joliet_filename(de, tmpname, inode);
219				p = tmpname;
220			} else
221#endif
222			if (sbi->s_mapping == 'a') {
223				len = get_acorn_filename(de, tmpname, inode);
224				p = tmpname;
225			} else
226			if (sbi->s_mapping == 'n') {
227				len = isofs_name_translate(de, tmpname, inode);
228				p = tmpname;
229			} else {
230				p = de->name;
231				len = de->name_len[0];
232			}
233		}
234		if (len > 0) {
235			if (!dir_emit(ctx, p, len, inode_number, DT_UNKNOWN))
236				break;
237		}
238		ctx->pos += de_len;
239	}
240	if (bh)
241		brelse(bh);
242	return 0;
243}
244
245/*
246 * Handle allocation of temporary space for name translation and
247 * handling split directory entries.. The real work is done by
248 * "do_isofs_readdir()".
249 */
250static int isofs_readdir(struct file *file, struct dir_context *ctx)
251{
252	int result;
253	char *tmpname;
254	struct iso_directory_record *tmpde;
255	struct inode *inode = file_inode(file);
256
257	tmpname = (char *)__get_free_page(GFP_KERNEL);
258	if (tmpname == NULL)
259		return -ENOMEM;
260
261	tmpde = (struct iso_directory_record *) (tmpname+1024);
262
263	result = do_isofs_readdir(inode, file, ctx, tmpname, tmpde);
264
265	free_page((unsigned long) tmpname);
266	return result;
267}
268
269const struct file_operations isofs_dir_operations =
270{
271	.llseek = generic_file_llseek,
272	.read = generic_read_dir,
273	.iterate_shared = isofs_readdir,
274};
275
276/*
277 * directories can handle most operations...
278 */
279const struct inode_operations isofs_dir_inode_operations =
280{
281	.lookup = isofs_lookup,
282};
283
284
~/ Read-only file preview.