OSDN Git Service

Merge tag 'backlight-next-6.6' of git://git.kernel.org/pub/scm/linux/kernel/git/lee...
[tomoyo/tomoyo-test1.git] / fs / udf / dir.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * dir.c
4  *
5  * PURPOSE
6  *  Directory handling routines for the OSTA-UDF(tm) filesystem.
7  *
8  * COPYRIGHT
9  *  (C) 1998-2004 Ben Fennema
10  *
11  * HISTORY
12  *
13  *  10/05/98 dgb  Split directory operations into its own file
14  *                Implemented directory reads via do_udf_readdir
15  *  10/06/98      Made directory operations work!
16  *  11/17/98      Rewrote directory to support ICBTAG_FLAG_AD_LONG
17  *  11/25/98 blf  Rewrote directory handling (readdir+lookup) to support reading
18  *                across blocks.
19  *  12/12/98      Split out the lookup code to namei.c. bulk of directory
20  *                code now in directory.c:udf_fileident_read.
21  */
22
23 #include "udfdecl.h"
24
25 #include <linux/string.h>
26 #include <linux/errno.h>
27 #include <linux/mm.h>
28 #include <linux/slab.h>
29 #include <linux/bio.h>
30 #include <linux/iversion.h>
31
32 #include "udf_i.h"
33 #include "udf_sb.h"
34
35 static int udf_readdir(struct file *file, struct dir_context *ctx)
36 {
37         struct inode *dir = file_inode(file);
38         loff_t nf_pos, emit_pos = 0;
39         int flen;
40         unsigned char *fname = NULL;
41         int ret = 0;
42         struct super_block *sb = dir->i_sb;
43         bool pos_valid = false;
44         struct udf_fileident_iter iter;
45
46         if (ctx->pos == 0) {
47                 if (!dir_emit_dot(file, ctx))
48                         return 0;
49                 ctx->pos = 1;
50         }
51         nf_pos = (ctx->pos - 1) << 2;
52         if (nf_pos >= dir->i_size)
53                 goto out;
54
55         /*
56          * Something changed since last readdir (either lseek was called or dir
57          * changed)?  We need to verify the position correctly points at the
58          * beginning of some dir entry so that the directory parsing code does
59          * not get confused. Since UDF does not have any reliable way of
60          * identifying beginning of dir entry (names are under user control),
61          * we need to scan the directory from the beginning.
62          */
63         if (!inode_eq_iversion(dir, file->f_version)) {
64                 emit_pos = nf_pos;
65                 nf_pos = 0;
66         } else {
67                 pos_valid = true;
68         }
69
70         fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
71         if (!fname) {
72                 ret = -ENOMEM;
73                 goto out;
74         }
75
76         for (ret = udf_fiiter_init(&iter, dir, nf_pos);
77              !ret && iter.pos < dir->i_size;
78              ret = udf_fiiter_advance(&iter)) {
79                 struct kernel_lb_addr tloc;
80                 udf_pblk_t iblock;
81
82                 /* Still not at offset where user asked us to read from? */
83                 if (iter.pos < emit_pos)
84                         continue;
85
86                 /* Update file position only if we got past the current one */
87                 pos_valid = true;
88                 ctx->pos = (iter.pos >> 2) + 1;
89
90                 if (iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
91                         if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
92                                 continue;
93                 }
94
95                 if (iter.fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) {
96                         if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
97                                 continue;
98                 }
99
100                 if (iter.fi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
101                         if (!dir_emit_dotdot(file, ctx))
102                                 goto out_iter;
103                         continue;
104                 }
105
106                 flen = udf_get_filename(sb, iter.name,
107                                 iter.fi.lengthFileIdent, fname, UDF_NAME_LEN);
108                 if (flen < 0)
109                         continue;
110
111                 tloc = lelb_to_cpu(iter.fi.icb.extLocation);
112                 iblock = udf_get_lb_pblock(sb, &tloc, 0);
113                 if (!dir_emit(ctx, fname, flen, iblock, DT_UNKNOWN))
114                         goto out_iter;
115         }
116
117         if (!ret) {
118                 ctx->pos = (iter.pos >> 2) + 1;
119                 pos_valid = true;
120         }
121 out_iter:
122         udf_fiiter_release(&iter);
123 out:
124         if (pos_valid)
125                 file->f_version = inode_query_iversion(dir);
126         kfree(fname);
127
128         return ret;
129 }
130
131 /* readdir and lookup functions */
132 const struct file_operations udf_dir_operations = {
133         .llseek                 = generic_file_llseek,
134         .read                   = generic_read_dir,
135         .iterate_shared         = udf_readdir,
136         .unlocked_ioctl         = udf_ioctl,
137         .fsync                  = generic_file_fsync,
138 };