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