Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dir.c
Go to the documentation of this file.
1 /*
2  * dir.c
3  *
4  * PURPOSE
5  * Directory handling routines for the OSTA-UDF(tm) filesystem.
6  *
7  * COPYRIGHT
8  * This file is distributed under the terms of the GNU General Public
9  * License (GPL). Copies of the GPL can be obtained from:
10  * ftp://prep.ai.mit.edu/pub/gnu/GPL
11  * Each contributing author retains all rights to their own work.
12  *
13  * (C) 1998-2004 Ben Fennema
14  *
15  * HISTORY
16  *
17  * 10/05/98 dgb Split directory operations into its own file
18  * Implemented directory reads via do_udf_readdir
19  * 10/06/98 Made directory operations work!
20  * 11/17/98 Rewrote directory to support ICBTAG_FLAG_AD_LONG
21  * 11/25/98 blf Rewrote directory handling (readdir+lookup) to support reading
22  * across blocks.
23  * 12/12/98 Split out the lookup code to namei.c. bulk of directory
24  * code now in directory.c:udf_fileident_read.
25  */
26 
27 #include "udfdecl.h"
28 
29 #include <linux/string.h>
30 #include <linux/errno.h>
31 #include <linux/mm.h>
32 #include <linux/slab.h>
33 #include <linux/buffer_head.h>
34 
35 #include "udf_i.h"
36 #include "udf_sb.h"
37 
38 static int do_udf_readdir(struct inode *dir, struct file *filp,
39  filldir_t filldir, void *dirent)
40 {
41  struct udf_fileident_bh fibh = { .sbh = NULL, .ebh = NULL};
42  struct fileIdentDesc *fi = NULL;
43  struct fileIdentDesc cfi;
44  int block, iblock;
45  loff_t nf_pos = (filp->f_pos - 1) << 2;
46  int flen;
47  unsigned char *fname = NULL;
48  unsigned char *nameptr;
49  uint16_t liu;
50  uint8_t lfi;
51  loff_t size = udf_ext0_offset(dir) + dir->i_size;
52  struct buffer_head *tmp, *bha[16];
53  struct kernel_lb_addr eloc;
54  uint32_t elen;
56  int i, num, ret = 0;
57  unsigned int dt_type;
58  struct extent_position epos = { NULL, 0, {0, 0} };
59  struct udf_inode_info *iinfo;
60 
61  if (nf_pos >= size)
62  goto out;
63 
64  fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
65  if (!fname) {
66  ret = -ENOMEM;
67  goto out;
68  }
69 
70  if (nf_pos == 0)
71  nf_pos = udf_ext0_offset(dir);
72 
73  fibh.soffset = fibh.eoffset = nf_pos & (dir->i_sb->s_blocksize - 1);
74  iinfo = UDF_I(dir);
75  if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
76  if (inode_bmap(dir, nf_pos >> dir->i_sb->s_blocksize_bits,
77  &epos, &eloc, &elen, &offset)
78  != (EXT_RECORDED_ALLOCATED >> 30)) {
79  ret = -ENOENT;
80  goto out;
81  }
82  block = udf_get_lb_pblock(dir->i_sb, &eloc, offset);
83  if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
84  if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
85  epos.offset -= sizeof(struct short_ad);
86  else if (iinfo->i_alloc_type ==
88  epos.offset -= sizeof(struct long_ad);
89  } else {
90  offset = 0;
91  }
92 
93  if (!(fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block))) {
94  ret = -EIO;
95  goto out;
96  }
97 
98  if (!(offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9)) - 1))) {
99  i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
100  if (i + offset > (elen >> dir->i_sb->s_blocksize_bits))
101  i = (elen >> dir->i_sb->s_blocksize_bits) - offset;
102  for (num = 0; i > 0; i--) {
103  block = udf_get_lb_pblock(dir->i_sb, &eloc, offset + i);
104  tmp = udf_tgetblk(dir->i_sb, block);
105  if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
106  bha[num++] = tmp;
107  else
108  brelse(tmp);
109  }
110  if (num) {
111  ll_rw_block(READA, num, bha);
112  for (i = 0; i < num; i++)
113  brelse(bha[i]);
114  }
115  }
116  }
117 
118  while (nf_pos < size) {
119  filp->f_pos = (nf_pos >> 2) + 1;
120 
121  fi = udf_fileident_read(dir, &nf_pos, &fibh, &cfi, &epos, &eloc,
122  &elen, &offset);
123  if (!fi)
124  goto out;
125 
126  liu = le16_to_cpu(cfi.lengthOfImpUse);
127  lfi = cfi.lengthFileIdent;
128 
129  if (fibh.sbh == fibh.ebh) {
130  nameptr = fi->fileIdent + liu;
131  } else {
132  int poffset; /* Unpaded ending offset */
133 
134  poffset = fibh.soffset + sizeof(struct fileIdentDesc) + liu + lfi;
135 
136  if (poffset >= lfi) {
137  nameptr = (char *)(fibh.ebh->b_data + poffset - lfi);
138  } else {
139  nameptr = fname;
140  memcpy(nameptr, fi->fileIdent + liu,
141  lfi - poffset);
142  memcpy(nameptr + lfi - poffset,
143  fibh.ebh->b_data, poffset);
144  }
145  }
146 
147  if ((cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
148  if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
149  continue;
150  }
151 
152  if ((cfi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
153  if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
154  continue;
155  }
156 
157  if (cfi.fileCharacteristics & FID_FILE_CHAR_PARENT) {
158  iblock = parent_ino(filp->f_path.dentry);
159  flen = 2;
160  memcpy(fname, "..", flen);
161  dt_type = DT_DIR;
162  } else {
163  struct kernel_lb_addr tloc = lelb_to_cpu(cfi.icb.extLocation);
164 
165  iblock = udf_get_lb_pblock(dir->i_sb, &tloc, 0);
166  flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
167  dt_type = DT_UNKNOWN;
168  }
169 
170  if (flen && filldir(dirent, fname, flen, filp->f_pos,
171  iblock, dt_type) < 0)
172  goto out;
173  } /* end while */
174 
175  filp->f_pos = (nf_pos >> 2) + 1;
176 
177 out:
178  if (fibh.sbh != fibh.ebh)
179  brelse(fibh.ebh);
180  brelse(fibh.sbh);
181  brelse(epos.bh);
182  kfree(fname);
183 
184  return ret;
185 }
186 
187 static int udf_readdir(struct file *filp, void *dirent, filldir_t filldir)
188 {
189  struct inode *dir = filp->f_path.dentry->d_inode;
190  int result;
191 
192  if (filp->f_pos == 0) {
193  if (filldir(dirent, ".", 1, filp->f_pos, dir->i_ino, DT_DIR) < 0) {
194  return 0;
195  }
196  filp->f_pos++;
197  }
198 
199  result = do_udf_readdir(dir, filp, filldir, dirent);
200  return result;
201 }
202 
203 /* readdir and lookup functions */
205  .llseek = generic_file_llseek,
206  .read = generic_read_dir,
207  .readdir = udf_readdir,
208  .unlocked_ioctl = udf_ioctl,
209  .fsync = generic_file_fsync,
210 };