xref: /openbmc/linux/fs/udf/dir.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1*5ce34554SBagas Sanjaya // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * dir.c
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * PURPOSE
61da177e4SLinus Torvalds  *  Directory handling routines for the OSTA-UDF(tm) filesystem.
71da177e4SLinus Torvalds  *
81da177e4SLinus Torvalds  * COPYRIGHT
91da177e4SLinus Torvalds  *  (C) 1998-2004 Ben Fennema
101da177e4SLinus Torvalds  *
111da177e4SLinus Torvalds  * HISTORY
121da177e4SLinus Torvalds  *
131da177e4SLinus Torvalds  *  10/05/98 dgb  Split directory operations into its own file
141da177e4SLinus Torvalds  *                Implemented directory reads via do_udf_readdir
151da177e4SLinus Torvalds  *  10/06/98      Made directory operations work!
161da177e4SLinus Torvalds  *  11/17/98      Rewrote directory to support ICBTAG_FLAG_AD_LONG
171da177e4SLinus Torvalds  *  11/25/98 blf  Rewrote directory handling (readdir+lookup) to support reading
181da177e4SLinus Torvalds  *                across blocks.
191da177e4SLinus Torvalds  *  12/12/98      Split out the lookup code to namei.c. bulk of directory
201da177e4SLinus Torvalds  *                code now in directory.c:udf_fileident_read.
211da177e4SLinus Torvalds  */
221da177e4SLinus Torvalds 
231da177e4SLinus Torvalds #include "udfdecl.h"
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds #include <linux/string.h>
261da177e4SLinus Torvalds #include <linux/errno.h>
271da177e4SLinus Torvalds #include <linux/mm.h>
281da177e4SLinus Torvalds #include <linux/slab.h>
292f8b5444SChristoph Hellwig #include <linux/bio.h>
30a48fc69fSJan Kara #include <linux/iversion.h>
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds #include "udf_i.h"
331da177e4SLinus Torvalds #include "udf_sb.h"
341da177e4SLinus Torvalds 
udf_readdir(struct file * file,struct dir_context * ctx)355add2ee1SAl Viro static int udf_readdir(struct file *file, struct dir_context *ctx)
361da177e4SLinus Torvalds {
375add2ee1SAl Viro 	struct inode *dir = file_inode(file);
38a48fc69fSJan Kara 	loff_t nf_pos, emit_pos = 0;
391da177e4SLinus Torvalds 	int flen;
407cd7a36aSJan Kara 	unsigned char *fname = NULL;
417cd7a36aSJan Kara 	int ret = 0;
423ee3039cSJan Kara 	struct super_block *sb = dir->i_sb;
43a48fc69fSJan Kara 	bool pos_valid = false;
447cd7a36aSJan Kara 	struct udf_fileident_iter iter;
451da177e4SLinus Torvalds 
465add2ee1SAl Viro 	if (ctx->pos == 0) {
475add2ee1SAl Viro 		if (!dir_emit_dot(file, ctx))
485add2ee1SAl Viro 			return 0;
495add2ee1SAl Viro 		ctx->pos = 1;
505add2ee1SAl Viro 	}
515add2ee1SAl Viro 	nf_pos = (ctx->pos - 1) << 2;
527cd7a36aSJan Kara 	if (nf_pos >= dir->i_size)
53b80697c1SJan Kara 		goto out;
54b80697c1SJan Kara 
55a48fc69fSJan Kara 	/*
56a48fc69fSJan Kara 	 * Something changed since last readdir (either lseek was called or dir
57a48fc69fSJan Kara 	 * changed)?  We need to verify the position correctly points at the
58a48fc69fSJan Kara 	 * beginning of some dir entry so that the directory parsing code does
59a48fc69fSJan Kara 	 * not get confused. Since UDF does not have any reliable way of
60a48fc69fSJan Kara 	 * identifying beginning of dir entry (names are under user control),
61a48fc69fSJan Kara 	 * we need to scan the directory from the beginning.
62a48fc69fSJan Kara 	 */
63a48fc69fSJan Kara 	if (!inode_eq_iversion(dir, file->f_version)) {
64a48fc69fSJan Kara 		emit_pos = nf_pos;
65a48fc69fSJan Kara 		nf_pos = 0;
66a48fc69fSJan Kara 	} else {
67a48fc69fSJan Kara 		pos_valid = true;
68a48fc69fSJan Kara 	}
69a48fc69fSJan Kara 
70b80697c1SJan Kara 	fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
71b80697c1SJan Kara 	if (!fname) {
72b80697c1SJan Kara 		ret = -ENOMEM;
73b80697c1SJan Kara 		goto out;
74b80697c1SJan Kara 	}
751da177e4SLinus Torvalds 
767cd7a36aSJan Kara 	for (ret = udf_fiiter_init(&iter, dir, nf_pos);
777cd7a36aSJan Kara 	     !ret && iter.pos < dir->i_size;
787cd7a36aSJan Kara 	     ret = udf_fiiter_advance(&iter)) {
795add2ee1SAl Viro 		struct kernel_lb_addr tloc;
807cd7a36aSJan Kara 		udf_pblk_t iblock;
815add2ee1SAl Viro 
82a48fc69fSJan Kara 		/* Still not at offset where user asked us to read from? */
837cd7a36aSJan Kara 		if (iter.pos < emit_pos)
84a48fc69fSJan Kara 			continue;
851da177e4SLinus Torvalds 
867cd7a36aSJan Kara 		/* Update file position only if we got past the current one */
877cd7a36aSJan Kara 		pos_valid = true;
887cd7a36aSJan Kara 		ctx->pos = (iter.pos >> 2) + 1;
891da177e4SLinus Torvalds 
907cd7a36aSJan Kara 		if (iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
913ee3039cSJan Kara 			if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
921da177e4SLinus Torvalds 				continue;
931da177e4SLinus Torvalds 		}
941da177e4SLinus Torvalds 
957cd7a36aSJan Kara 		if (iter.fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) {
963ee3039cSJan Kara 			if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
971da177e4SLinus Torvalds 				continue;
981da177e4SLinus Torvalds 		}
991da177e4SLinus Torvalds 
1007cd7a36aSJan Kara 		if (iter.fi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
1015add2ee1SAl Viro 			if (!dir_emit_dotdot(file, ctx))
1027cd7a36aSJan Kara 				goto out_iter;
1035add2ee1SAl Viro 			continue;
1041da177e4SLinus Torvalds 		}
1051da177e4SLinus Torvalds 
1067cd7a36aSJan Kara 		flen = udf_get_filename(sb, iter.name,
1077cd7a36aSJan Kara 				iter.fi.lengthFileIdent, fname, UDF_NAME_LEN);
1086ce63836SFabian Frederick 		if (flen < 0)
1095add2ee1SAl Viro 			continue;
1105add2ee1SAl Viro 
1117cd7a36aSJan Kara 		tloc = lelb_to_cpu(iter.fi.icb.extLocation);
1123ee3039cSJan Kara 		iblock = udf_get_lb_pblock(sb, &tloc, 0);
1135add2ee1SAl Viro 		if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
1147cd7a36aSJan Kara 			goto out_iter;
1157cd7a36aSJan Kara 	}
1161da177e4SLinus Torvalds 
1177cd7a36aSJan Kara 	if (!ret) {
1187cd7a36aSJan Kara 		ctx->pos = (iter.pos >> 2) + 1;
119a48fc69fSJan Kara 		pos_valid = true;
1207cd7a36aSJan Kara 	}
1217cd7a36aSJan Kara out_iter:
1227cd7a36aSJan Kara 	udf_fiiter_release(&iter);
123b80697c1SJan Kara out:
124a48fc69fSJan Kara 	if (pos_valid)
125a48fc69fSJan Kara 		file->f_version = inode_query_iversion(dir);
126b80697c1SJan Kara 	kfree(fname);
1271da177e4SLinus Torvalds 
128b80697c1SJan Kara 	return ret;
1291da177e4SLinus Torvalds }
130934c5e60SMarcin Slusarz 
131934c5e60SMarcin Slusarz /* readdir and lookup functions */
132934c5e60SMarcin Slusarz const struct file_operations udf_dir_operations = {
133ca572727Sjan Blunck 	.llseek			= generic_file_llseek,
134934c5e60SMarcin Slusarz 	.read			= generic_read_dir,
135c51da20cSAl Viro 	.iterate_shared		= udf_readdir,
1362f07a88bSJohn Kacur 	.unlocked_ioctl		= udf_ioctl,
1371b061d92SChristoph Hellwig 	.fsync			= generic_file_fsync,
138934c5e60SMarcin Slusarz };
139