Blame view

fs/hpfs/dir.c 8.66 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
  /*
   *  linux/fs/hpfs/dir.c
   *
   *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
   *
   *  directory VFS functions
   */
5a0e3ad6a   Tejun Heo   include cleanup: ...
9
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
  #include "hpfs_fn.h"
  
  static int hpfs_dir_release(struct inode *inode, struct file *filp)
  {
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
14
  	hpfs_lock(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
  	hpfs_del_pos(inode, &filp->f_pos);
  	/*hpfs_write_if_changed(inode);*/
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
17
  	hpfs_unlock(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
20
21
22
23
24
25
26
27
  	return 0;
  }
  
  /* This is slow, but it's not used often */
  
  static loff_t hpfs_dir_lseek(struct file *filp, loff_t off, int whence)
  {
  	loff_t new_off = off + (whence == 1 ? filp->f_pos : 0);
  	loff_t pos;
  	struct quad_buffer_head qbh;
496ad9aa8   Al Viro   new helper: file_...
28
  	struct inode *i = file_inode(filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
  	struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
  	struct super_block *s = i->i_sb;
06222e491   Josef Bacik   fs: handle SEEK_H...
31
32
33
  	/* Somebody else will have to figure out what to do here */
  	if (whence == SEEK_DATA || whence == SEEK_HOLE)
  		return -EINVAL;
5955102c9   Al Viro   wrappers for ->i_...
34
  	inode_lock(i);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
35
  	hpfs_lock(s);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

b7cb1ce22   Fabian Frederick   fs/hpfs: convert ...
37
38
  	/*pr_info("dir lseek
  ");*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  	if (new_off == 0 || new_off == 1 || new_off == 11 || new_off == 12 || new_off == 13) goto ok;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
  	pos = ((loff_t) hpfs_de_as_down_as_possible(s, hpfs_inode->i_dno) << 4) + 1;
  	while (pos != new_off) {
  		if (map_pos_dirent(i, &pos, &qbh)) hpfs_brelse4(&qbh);
  		else goto fail;
  		if (pos == 12) goto fail;
  	}
e82c31475   Al Viro   hpfs: handle allo...
46
47
48
49
50
  	if (unlikely(hpfs_add_pos(i, &filp->f_pos) < 0)) {
  		hpfs_unlock(s);
  		inode_unlock(i);
  		return -ENOMEM;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
  ok:
31abdab9c   Al Viro   hpfs: deadlock an...
52
  	filp->f_pos = new_off;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
53
  	hpfs_unlock(s);
5955102c9   Al Viro   wrappers for ->i_...
54
  	inode_unlock(i);
31abdab9c   Al Viro   hpfs: deadlock an...
55
56
  	return new_off;
  fail:
b7cb1ce22   Fabian Frederick   fs/hpfs: convert ...
57
58
  	/*pr_warn("illegal lseek: %016llx
  ", new_off);*/
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
59
  	hpfs_unlock(s);
5955102c9   Al Viro   wrappers for ->i_...
60
  	inode_unlock(i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
62
  	return -ESPIPE;
  }
568f8f5ec   Al Viro   [readdir] convert...
63
  static int hpfs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
  {
568f8f5ec   Al Viro   [readdir] convert...
65
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
66
67
68
69
  	struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
  	struct quad_buffer_head qbh;
  	struct hpfs_dirent *de;
  	int lc;
568f8f5ec   Al Viro   [readdir] convert...
70
  	loff_t next_pos;
7e7742ee0   Al Viro   sanitize signedne...
71
  	unsigned char *tempname;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
72
73
  	int c1, c2 = 0;
  	int ret = 0;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
74
  	hpfs_lock(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  
  	if (hpfs_sb(inode->i_sb)->sb_chk) {
  		if (hpfs_chk_sectors(inode->i_sb, inode->i_ino, 1, "dir_fnode")) {
  			ret = -EFSERROR;
  			goto out;
  		}
  		if (hpfs_chk_sectors(inode->i_sb, hpfs_inode->i_dno, 4, "dir_dnode")) {
  			ret = -EFSERROR;
  			goto out;
  		}
  	}
  	if (hpfs_sb(inode->i_sb)->sb_chk >= 2) {
  		struct buffer_head *bh;
  		struct fnode *fno;
  		int e = 0;
  		if (!(fno = hpfs_map_fnode(inode->i_sb, inode->i_ino, &bh))) {
  			ret = -EIOERROR;
  			goto out;
  		}
c4c995430   Al Viro   hpfs: get rid of ...
94
  		if (!fnode_is_dir(fno)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
  			e = 1;
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
96
97
  			hpfs_error(inode->i_sb, "not a directory, fnode %08lx",
  					(unsigned long)inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
  		}
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
99
  		if (hpfs_inode->i_dno != le32_to_cpu(fno->u.external[0].disk_secno)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  			e = 1;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
101
  			hpfs_error(inode->i_sb, "corrupted inode: i_dno == %08x, fnode -> dnode == %08x", hpfs_inode->i_dno, le32_to_cpu(fno->u.external[0].disk_secno));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
103
104
105
106
107
108
109
  		}
  		brelse(bh);
  		if (e) {
  			ret = -EFSERROR;
  			goto out;
  		}
  	}
  	lc = hpfs_sb(inode->i_sb)->sb_lowercase;
568f8f5ec   Al Viro   [readdir] convert...
110
111
  	if (ctx->pos == 12) { /* diff -r requires this (note, that diff -r */
  		ctx->pos = 13; /* also fails on msdos filesystem in 2.0) */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  		goto out;
  	}
568f8f5ec   Al Viro   [readdir] convert...
114
  	if (ctx->pos == 13) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
  		ret = -ENOENT;
  		goto out;
  	}
  	
  	while (1) {
  		again:
  		/* This won't work when cycle is longer than number of dirents
  		   accepted by filldir, but what can I do?
  		   maybe killall -9 ls helps */
  		if (hpfs_sb(inode->i_sb)->sb_chk)
568f8f5ec   Al Viro   [readdir] convert...
125
  			if (hpfs_stop_cycles(inode->i_sb, ctx->pos, &c1, &c2, "hpfs_readdir")) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
  				ret = -EFSERROR;
  				goto out;
  			}
568f8f5ec   Al Viro   [readdir] convert...
129
  		if (ctx->pos == 12)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
  			goto out;
568f8f5ec   Al Viro   [readdir] convert...
131
  		if (ctx->pos == 3 || ctx->pos == 4 || ctx->pos == 5) {
a19189e55   Fabian Frederick   fs/hpfs: increase...
132
133
  			pr_err("pos==%d
  ", (int)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
134
135
  			goto out;
  		}
568f8f5ec   Al Viro   [readdir] convert...
136
137
  		if (ctx->pos == 0) {
  			if (!dir_emit_dot(file, ctx))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  				goto out;
568f8f5ec   Al Viro   [readdir] convert...
139
  			ctx->pos = 11;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140
  		}
568f8f5ec   Al Viro   [readdir] convert...
141
142
  		if (ctx->pos == 11) {
  			if (!dir_emit(ctx, "..", 2, hpfs_inode->i_parent_dir, DT_DIR))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  				goto out;
568f8f5ec   Al Viro   [readdir] convert...
144
  			ctx->pos = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  		}
568f8f5ec   Al Viro   [readdir] convert...
146
  		if (ctx->pos == 1) {
e82c31475   Al Viro   hpfs: handle allo...
147
148
149
  			ret = hpfs_add_pos(inode, &file->f_pos);
  			if (unlikely(ret < 0))
  				goto out;
568f8f5ec   Al Viro   [readdir] convert...
150
  			ctx->pos = ((loff_t) hpfs_de_as_down_as_possible(inode->i_sb, hpfs_inode->i_dno) << 4) + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
  		}
568f8f5ec   Al Viro   [readdir] convert...
152
153
154
  		next_pos = ctx->pos;
  		if (!(de = map_pos_dirent(inode, &next_pos, &qbh))) {
  			ctx->pos = next_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
155
156
157
158
159
  			ret = -EIOERROR;
  			goto out;
  		}
  		if (de->first || de->last) {
  			if (hpfs_sb(inode->i_sb)->sb_chk) {
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
160
161
  				if (de->first && !de->last && (de->namelen != 2
  				    || de ->name[0] != 1 || de->name[1] != 1))
568f8f5ec   Al Viro   [readdir] convert...
162
  					hpfs_error(inode->i_sb, "hpfs_readdir: bad ^A^A entry; pos = %08lx", (unsigned long)ctx->pos);
18debbbcc   Randy Dunlap   [PATCH] hpfs: fix...
163
  				if (de->last && (de->namelen != 1 || de ->name[0] != 255))
568f8f5ec   Al Viro   [readdir] convert...
164
  					hpfs_error(inode->i_sb, "hpfs_readdir: bad \\377 entry; pos = %08lx", (unsigned long)ctx->pos);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165
166
  			}
  			hpfs_brelse4(&qbh);
568f8f5ec   Al Viro   [readdir] convert...
167
  			ctx->pos = next_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
  			goto again;
  		}
  		tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
568f8f5ec   Al Viro   [readdir] convert...
171
  		if (!dir_emit(ctx, tempname, de->namelen, le32_to_cpu(de->fnode), DT_UNKNOWN)) {
7e7742ee0   Al Viro   sanitize signedne...
172
  			if (tempname != de->name) kfree(tempname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
175
  			hpfs_brelse4(&qbh);
  			goto out;
  		}
568f8f5ec   Al Viro   [readdir] convert...
176
  		ctx->pos = next_pos;
7e7742ee0   Al Viro   sanitize signedne...
177
  		if (tempname != de->name) kfree(tempname);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
179
180
  		hpfs_brelse4(&qbh);
  	}
  out:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
181
  	hpfs_unlock(inode->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
  	return ret;
  }
  
  /*
   * lookup.  Search the specified directory for the specified name, set
   * *result to the corresponding inode.
   *
   * lookup uses the inode number to tell read_inode whether it is reading
   * the inode of a directory or a file -- file ino's are odd, directory
   * ino's are even.  read_inode avoids i/o for file inodes; everything
   * needed is up here in the directory.  (And file fnodes are out in
   * the boondocks.)
   *
   *    - M.P.: this is over, sometimes we've got to read file's fnode for eas
   *	      inode numbers are just fnode sector numbers; iget lock is used
   *	      to tell read_inode to read fnode or not.
   */
00cd8dd3b   Al Viro   stop passing name...
199
  struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  {
7e7742ee0   Al Viro   sanitize signedne...
201
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202
203
204
205
206
207
208
  	unsigned len = dentry->d_name.len;
  	struct quad_buffer_head qbh;
  	struct hpfs_dirent *de;
  	ino_t ino;
  	int err;
  	struct inode *result = NULL;
  	struct hpfs_inode_info *hpfs_result;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
209
  	hpfs_lock(dir->i_sb);
7e7742ee0   Al Viro   sanitize signedne...
210
  	if ((err = hpfs_chk_name(name, &len))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
  		if (err == -ENAMETOOLONG) {
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
212
  			hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
220
  			return ERR_PTR(-ENAMETOOLONG);
  		}
  		goto end_add;
  	}
  
  	/*
  	 * '.' and '..' will never be passed here.
  	 */
7e7742ee0   Al Viro   sanitize signedne...
221
  	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, NULL, &qbh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
229
230
231
  
  	/*
  	 * This is not really a bailout, just means file not found.
  	 */
  
  	if (!de) goto end;
  
  	/*
  	 * Get inode number, what we're after.
  	 */
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
232
  	ino = le32_to_cpu(de->fnode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
237
238
239
240
  
  	/*
  	 * Go find or make an inode.
  	 */
  
  	result = iget_locked(dir->i_sb, ino);
  	if (!result) {
  		hpfs_error(dir->i_sb, "hpfs_lookup: can't get inode");
e876c445d   Al Viro   hpfs: fix an inod...
241
  		result = ERR_PTR(-ENOMEM);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
246
247
  		goto bail1;
  	}
  	if (result->i_state & I_NEW) {
  		hpfs_init_inode(result);
  		if (de->directory)
  			hpfs_read_inode(result);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
248
  		else if (le32_to_cpu(de->ea_size) && hpfs_sb(dir->i_sb)->sb_eas)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
252
253
254
  			hpfs_read_inode(result);
  		else {
  			result->i_mode |= S_IFREG;
  			result->i_mode &= ~0111;
  			result->i_op = &hpfs_file_iops;
  			result->i_fop = &hpfs_file_ops;
bfe868486   Miklos Szeredi   filesystems: add ...
255
  			set_nlink(result, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
260
  		}
  		unlock_new_inode(result);
  	}
  	hpfs_result = hpfs_i(result);
  	if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
bc98a42c1   David Howells   VFS: Convert sb->...
261
  	if (de->has_acl || de->has_xtd_perm) if (!sb_rdonly(dir->i_sb)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
  		hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");
e876c445d   Al Viro   hpfs: fix an inod...
263
264
  		iput(result);
  		result = ERR_PTR(-EINVAL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
268
269
270
271
272
273
  		goto bail1;
  	}
  
  	/*
  	 * Fill in the info from the directory if this is a newly created
  	 * inode.
  	 */
  
  	if (!result->i_ctime.tv_sec) {
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
274
  		if (!(result->i_ctime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->creation_date))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
  			result->i_ctime.tv_sec = 1;
  		result->i_ctime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
277
  		result->i_mtime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->write_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
  		result->i_mtime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
279
  		result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(de->read_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  		result->i_atime.tv_nsec = 0;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
281
  		hpfs_result->i_ea_size = le32_to_cpu(de->ea_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
  		if (!hpfs_result->i_ea_mode && de->read_only)
  			result->i_mode &= ~0222;
  		if (!de->directory) {
  			if (result->i_size == -1) {
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
286
  				result->i_size = le32_to_cpu(de->file_size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
293
294
295
296
297
298
  				result->i_data.a_ops = &hpfs_aops;
  				hpfs_i(result)->mmu_private = result->i_size;
  			/*
  			 * i_blocks should count the fnode and any anodes.
  			 * We count 1 for the fnode and don't bother about
  			 * anodes -- the disk heads are on the directory band
  			 * and we want them to stay there.
  			 */
  				result->i_blocks = 1 + ((result->i_size + 511) >> 9);
  			}
  		}
  	}
e876c445d   Al Viro   hpfs: fix an inod...
299
  bail1:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
302
303
304
  	hpfs_brelse4(&qbh);
  
  	/*
  	 * Made it.
  	 */
e876c445d   Al Viro   hpfs: fix an inod...
305
306
  end:
  end_add:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
307
  	hpfs_unlock(dir->i_sb);
e876c445d   Al Viro   hpfs: fix an inod...
308
  	return d_splice_alias(result, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
310
  const struct file_operations hpfs_dir_ops =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
  {
  	.llseek		= hpfs_dir_lseek,
  	.read		= generic_read_dir,
7d674b319   Al Viro   hpfs: switch to -...
314
  	.iterate_shared	= hpfs_readdir,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  	.release	= hpfs_dir_release,
  	.fsync		= hpfs_file_fsync,
a27b5b97d   Mikulas Patocka   hpfs: add fstrim ...
317
  	.unlocked_ioctl	= hpfs_ioctl,
314999dcb   Arnd Bergmann   fs: compat_ioctl:...
318
  	.compat_ioctl	= compat_ptr_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  };