Blame view

fs/adfs/dir.c 5.94 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
  /*
   *  linux/fs/adfs/dir.c
   *
   *  Copyright (C) 1999-2000 Russell King
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
7
8
   *  Common directory handling for ADFS
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
13
14
  #include "adfs.h"
  
  /*
   * For future.  This should probably be per-directory.
   */
  static DEFINE_RWLOCK(adfs_dir_lock);
411c49bcf   Russell King   fs/adfs: factor o...
15
16
  void adfs_object_fixup(struct adfs_dir *dir, struct object_info *obj)
  {
fc722a042   Russell King   fs/adfs: fix file...
17
  	unsigned int dots, i;
adb514a4e   Russell King   fs/adfs: factor o...
18
19
20
21
22
23
  
  	/*
  	 * RISC OS allows the use of '/' in directory entry names, so we need
  	 * to fix these up.  '/' is typically used for FAT compatibility to
  	 * represent '.', so do the same conversion here.  In any case, '.'
  	 * will never be in a RISC OS name since it is used as the pathname
fc722a042   Russell King   fs/adfs: fix file...
24
25
26
  	 * separator.  Handle the case where we may generate a '.' or '..'
  	 * name, replacing the first character with '^' (the RISC OS "parent
  	 * directory" character.)
adb514a4e   Russell King   fs/adfs: factor o...
27
  	 */
fc722a042   Russell King   fs/adfs: fix file...
28
29
  	for (i = dots = 0; i < obj->name_len; i++)
  		if (obj->name[i] == '/') {
adb514a4e   Russell King   fs/adfs: factor o...
30
  			obj->name[i] = '.';
fc722a042   Russell King   fs/adfs: fix file...
31
32
33
34
35
  			dots++;
  		}
  
  	if (obj->name_len <= 2 && dots == obj->name_len)
  		obj->name[0] = '^';
adb514a4e   Russell King   fs/adfs: factor o...
36

411c49bcf   Russell King   fs/adfs: factor o...
37
  	/*
b4ed8f75c   Russell King   fs/adfs: add time...
38
39
  	 * If the object is a file, and the user requested the ,xyz hex
  	 * filetype suffix to the name, check the filetype and append.
411c49bcf   Russell King   fs/adfs: factor o...
40
  	 */
b4ed8f75c   Russell King   fs/adfs: add time...
41
42
  	if (!(obj->attr & ADFS_NDA_DIRECTORY) && ADFS_SB(dir->sb)->s_ftsuffix) {
  		u16 filetype = adfs_filetype(obj->loadaddr);
5f8de4875   Russell King   fs/adfs: move app...
43

b4ed8f75c   Russell King   fs/adfs: add time...
44
  		if (filetype != ADFS_FILETYPE_NONE) {
5f8de4875   Russell King   fs/adfs: move app...
45
46
47
48
49
  			obj->name[obj->name_len++] = ',';
  			obj->name[obj->name_len++] = hex_asc_lo(filetype >> 8);
  			obj->name[obj->name_len++] = hex_asc_lo(filetype >> 4);
  			obj->name[obj->name_len++] = hex_asc_lo(filetype >> 0);
  		}
411c49bcf   Russell King   fs/adfs: factor o...
50
51
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  static int
2638ffbac   Al Viro   [readdir] convert...
53
  adfs_readdir(struct file *file, struct dir_context *ctx)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  {
2638ffbac   Al Viro   [readdir] convert...
55
  	struct inode *inode = file_inode(file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  	struct super_block *sb = inode->i_sb;
0125f504e   Julia Lawall   adfs: constify ad...
57
  	const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  	struct object_info obj;
  	struct adfs_dir dir;
  	int ret = 0;
2638ffbac   Al Viro   [readdir] convert...
61
62
  	if (ctx->pos >> 32)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
65
  
  	ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
  	if (ret)
2638ffbac   Al Viro   [readdir] convert...
66
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67

2638ffbac   Al Viro   [readdir] convert...
68
69
  	if (ctx->pos == 0) {
  		if (!dir_emit_dot(file, ctx))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
70
  			goto free_out;
2638ffbac   Al Viro   [readdir] convert...
71
72
73
74
  		ctx->pos = 1;
  	}
  	if (ctx->pos == 1) {
  		if (!dir_emit(ctx, "..", 2, dir.parent_id, DT_DIR))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
  			goto free_out;
2638ffbac   Al Viro   [readdir] convert...
76
  		ctx->pos = 2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
79
  	}
  
  	read_lock(&adfs_dir_lock);
2638ffbac   Al Viro   [readdir] convert...
80
  	ret = ops->setpos(&dir, ctx->pos - 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  	if (ret)
  		goto unlock_out;
  	while (ops->getnext(&dir, &obj) == 0) {
2638ffbac   Al Viro   [readdir] convert...
84
  		if (!dir_emit(ctx, obj.name, obj.name_len,
5ed70bb47   Russell King   fs/adfs: clean up...
85
  			      obj.indaddr, DT_UNKNOWN))
2638ffbac   Al Viro   [readdir] convert...
86
87
  			break;
  		ctx->pos++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
92
93
94
  	}
  
  unlock_out:
  	read_unlock(&adfs_dir_lock);
  
  free_out:
  	ops->free(&dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
  	return ret;
  }
  
  int
ffdc9064f   Al Viro   repair adfs ->wri...
99
  adfs_dir_update(struct super_block *sb, struct object_info *obj, int wait)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
101
102
  {
  	int ret = -EINVAL;
  #ifdef CONFIG_ADFS_FS_RW
0125f504e   Julia Lawall   adfs: constify ad...
103
  	const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  	struct adfs_dir dir;
5ed70bb47   Russell King   fs/adfs: clean up...
105
106
107
  	printk(KERN_INFO "adfs_dir_update: object %06x in dir %06x
  ",
  		 obj->indaddr, obj->parent_id);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108
109
110
111
112
113
114
115
116
117
118
119
120
  
  	if (!ops->update) {
  		ret = -EINVAL;
  		goto out;
  	}
  
  	ret = ops->read(sb, obj->parent_id, 0, &dir);
  	if (ret)
  		goto out;
  
  	write_lock(&adfs_dir_lock);
  	ret = ops->update(&dir, obj);
  	write_unlock(&adfs_dir_lock);
ffdc9064f   Al Viro   repair adfs ->wri...
121
122
123
124
125
  	if (wait) {
  		int err = ops->sync(&dir);
  		if (!ret)
  			ret = err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
130
  	ops->free(&dir);
  out:
  #endif
  	return ret;
  }
525715d01   Russell King   fs/adfs: factor o...
131
132
133
134
135
136
  static unsigned char adfs_tolower(unsigned char c)
  {
  	if (c >= 'A' && c <= 'Z')
  		c += 'a' - 'A';
  	return c;
  }
1e504cf85   Russell King   fs/adfs: factor o...
137
138
  static int __adfs_compare(const unsigned char *qstr, u32 qlen,
  			  const char *str, u32 len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
  {
1e504cf85   Russell King   fs/adfs: factor o...
140
  	u32 i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141

1e504cf85   Russell King   fs/adfs: factor o...
142
143
  	if (qlen != len)
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144

525715d01   Russell King   fs/adfs: factor o...
145
146
  	for (i = 0; i < qlen; i++)
  		if (adfs_tolower(qstr[i]) != adfs_tolower(str[i]))
1e504cf85   Russell King   fs/adfs: factor o...
147
  			return 1;
525715d01   Russell King   fs/adfs: factor o...
148

1e504cf85   Russell King   fs/adfs: factor o...
149
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  }
1e504cf85   Russell King   fs/adfs: factor o...
151
152
  static int adfs_dir_lookup_byname(struct inode *inode, const struct qstr *qstr,
  				  struct object_info *obj)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
  {
  	struct super_block *sb = inode->i_sb;
0125f504e   Julia Lawall   adfs: constify ad...
155
  	const struct adfs_dir_ops *ops = ADFS_SB(sb)->s_dir;
1e504cf85   Russell King   fs/adfs: factor o...
156
  	const unsigned char *name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  	struct adfs_dir dir;
1e504cf85   Russell King   fs/adfs: factor o...
158
  	u32 name_len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
163
164
165
  	int ret;
  
  	ret = ops->read(sb, inode->i_ino, inode->i_size, &dir);
  	if (ret)
  		goto out;
  
  	if (ADFS_I(inode)->parent_id != dir.parent_id) {
5ed70bb47   Russell King   fs/adfs: clean up...
166
167
168
  		adfs_error(sb,
  			   "parent directory changed under me! (%06x but got %06x)
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
170
171
172
173
174
  			   ADFS_I(inode)->parent_id, dir.parent_id);
  		ret = -EIO;
  		goto free_out;
  	}
  
  	obj->parent_id = inode->i_ino;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
179
180
181
  	read_lock(&adfs_dir_lock);
  
  	ret = ops->setpos(&dir, 0);
  	if (ret)
  		goto unlock_out;
  
  	ret = -ENOENT;
1e504cf85   Russell King   fs/adfs: factor o...
182
183
  	name = qstr->name;
  	name_len = qstr->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
  	while (ops->getnext(&dir, obj) == 0) {
1e504cf85   Russell King   fs/adfs: factor o...
185
  		if (!__adfs_compare(name, name_len, obj->name, obj->name_len)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
191
192
193
194
195
196
197
198
  			ret = 0;
  			break;
  		}
  	}
  
  unlock_out:
  	read_unlock(&adfs_dir_lock);
  
  free_out:
  	ops->free(&dir);
  out:
  	return ret;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
199
  const struct file_operations adfs_dir_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  	.read		= generic_read_dir,
59af1584b   Al Viro   [PATCH] fix ->lls...
201
  	.llseek		= generic_file_llseek,
2638ffbac   Al Viro   [readdir] convert...
202
  	.iterate	= adfs_readdir,
1b061d924   Christoph Hellwig   rename the generi...
203
  	.fsync		= generic_file_fsync,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
  };
  
  static int
da53be12b   Linus Torvalds   Don't pass inode ...
207
  adfs_hash(const struct dentry *parent, struct qstr *qstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  	const unsigned char *name;
  	unsigned long hash;
2eb0684f9   Russell King   fs/adfs: remove t...
211
  	u32 len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212

2eb0684f9   Russell King   fs/adfs: remove t...
213
214
  	if (qstr->len > ADFS_SB(parent->d_sb)->s_namelen)
  		return -ENAMETOOLONG;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215

2eb0684f9   Russell King   fs/adfs: remove t...
216
  	len = qstr->len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
  	name = qstr->name;
8387ff257   Linus Torvalds   vfs: make the str...
218
  	hash = init_name_hash(parent);
2eb0684f9   Russell King   fs/adfs: remove t...
219
  	while (len--)
525715d01   Russell King   fs/adfs: factor o...
220
  		hash = partial_name_hash(adfs_tolower(*name++), hash);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
224
225
226
227
228
229
  	qstr->hash = end_name_hash(hash);
  
  	return 0;
  }
  
  /*
   * Compare two names, taking note of the name length
   * requirements of the underlying filesystem.
   */
1e504cf85   Russell King   fs/adfs: factor o...
230
231
  static int adfs_compare(const struct dentry *dentry, unsigned int len,
  			const char *str, const struct qstr *qstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
  {
1e504cf85   Russell King   fs/adfs: factor o...
233
  	return __adfs_compare(qstr->name, qstr->len, str, len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
  }
e16404ed0   Al Viro   constify dentry_o...
235
  const struct dentry_operations adfs_dentry_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
236
237
238
239
240
  	.d_hash		= adfs_hash,
  	.d_compare	= adfs_compare,
  };
  
  static struct dentry *
00cd8dd3b   Al Viro   stop passing name...
241
  adfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
242
243
244
245
  {
  	struct inode *inode = NULL;
  	struct object_info obj;
  	int error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
  	error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj);
  	if (error == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
252
  		/*
  		 * This only returns NULL if get_empty_inode
  		 * fails.
  		 */
  		inode = adfs_iget(dir->i_sb, &obj);
9a7dddcaf   Al Viro   adfs_lookup: do n...
253
254
255
256
  		if (!inode)
  			inode = ERR_PTR(-EACCES);
  	} else if (error != -ENOENT) {
  		inode = ERR_PTR(error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  	}
9a7dddcaf   Al Viro   adfs_lookup: do n...
258
  	return d_splice_alias(inode, dentry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
261
262
263
  }
  
  /*
   * directories can handle most operations...
   */
754661f14   Arjan van de Ven   [PATCH] mark stru...
264
  const struct inode_operations adfs_dir_inode_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
267
  	.lookup		= adfs_lookup,
  	.setattr	= adfs_notify_change,
  };