3131#include <linux/mm.h>
3232#include <linux/slab.h>
3333#include <linux/bio.h>
34+ #include <linux/iversion.h>
3435
3536#include "udf_i.h"
3637#include "udf_sb.h"
@@ -43,7 +44,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
4344 struct fileIdentDesc * fi = NULL ;
4445 struct fileIdentDesc cfi ;
4546 udf_pblk_t block , iblock ;
46- loff_t nf_pos ;
47+ loff_t nf_pos , emit_pos = 0 ;
4748 int flen ;
4849 unsigned char * fname = NULL , * copy_name = NULL ;
4950 unsigned char * nameptr ;
@@ -57,6 +58,7 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
5758 int i , num , ret = 0 ;
5859 struct extent_position epos = { NULL , 0 , {0 , 0 } };
5960 struct super_block * sb = dir -> i_sb ;
61+ bool pos_valid = false;
6062
6163 if (ctx -> pos == 0 ) {
6264 if (!dir_emit_dot (file , ctx ))
@@ -67,6 +69,21 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
6769 if (nf_pos >= size )
6870 goto out ;
6971
72+ /*
73+ * Something changed since last readdir (either lseek was called or dir
74+ * changed)? We need to verify the position correctly points at the
75+ * beginning of some dir entry so that the directory parsing code does
76+ * not get confused. Since UDF does not have any reliable way of
77+ * identifying beginning of dir entry (names are under user control),
78+ * we need to scan the directory from the beginning.
79+ */
80+ if (!inode_eq_iversion (dir , file -> f_version )) {
81+ emit_pos = nf_pos ;
82+ nf_pos = 0 ;
83+ } else {
84+ pos_valid = true;
85+ }
86+
7087 fname = kmalloc (UDF_NAME_LEN , GFP_NOFS );
7188 if (!fname ) {
7289 ret = - ENOMEM ;
@@ -122,13 +139,21 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
122139
123140 while (nf_pos < size ) {
124141 struct kernel_lb_addr tloc ;
142+ loff_t cur_pos = nf_pos ;
125143
126- ctx -> pos = (nf_pos >> 2 ) + 1 ;
144+ /* Update file position only if we got past the current one */
145+ if (nf_pos >= emit_pos ) {
146+ ctx -> pos = (nf_pos >> 2 ) + 1 ;
147+ pos_valid = true;
148+ }
127149
128150 fi = udf_fileident_read (dir , & nf_pos , & fibh , & cfi , & epos , & eloc ,
129151 & elen , & offset );
130152 if (!fi )
131153 goto out ;
154+ /* Still not at offset where user asked us to read from? */
155+ if (cur_pos < emit_pos )
156+ continue ;
132157
133158 liu = le16_to_cpu (cfi .lengthOfImpUse );
134159 lfi = cfi .lengthFileIdent ;
@@ -186,8 +211,11 @@ static int udf_readdir(struct file *file, struct dir_context *ctx)
186211 } /* end while */
187212
188213 ctx -> pos = (nf_pos >> 2 ) + 1 ;
214+ pos_valid = true;
189215
190216out :
217+ if (pos_valid )
218+ file -> f_version = inode_query_iversion (dir );
191219 if (fibh .sbh != fibh .ebh )
192220 brelse (fibh .ebh );
193221 brelse (fibh .sbh );
0 commit comments