Blame view

fs/hpfs/namei.c 15.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   *  linux/fs/hpfs/namei.c
   *
   *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
   *
   *  adding & removing files & directories
   */
e8edc6e03   Alexey Dobriyan   Detach sched.h fr...
8
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include "hpfs_fn.h"
18bb1db3e   Al Viro   switch vfs_mkdir(...
10
  static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  {
7e7742ee0   Al Viro   sanitize signedne...
12
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
15
16
17
18
19
20
21
22
23
24
  	unsigned len = dentry->d_name.len;
  	struct quad_buffer_head qbh0;
  	struct buffer_head *bh;
  	struct hpfs_dirent *de;
  	struct fnode *fnode;
  	struct dnode *dnode;
  	struct inode *result;
  	fnode_secno fno;
  	dnode_secno dno;
  	int r;
  	struct hpfs_dirent dee;
  	int err;
7e7742ee0   Al Viro   sanitize signedne...
25
  	if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
26
  	hpfs_lock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
30
  	err = -ENOSPC;
  	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
  	if (!fnode)
  		goto bail;
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
31
  	dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
  	if (!dnode)
  		goto bail1;
  	memset(&dee, 0, sizeof dee);
  	dee.directory = 1;
  	if (!(mode & 0222)) dee.read_only = 1;
  	/*dee.archive = 0;*/
  	dee.hidden = name[0] == '.';
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
39
40
  	dee.fnode = cpu_to_le32(fno);
  	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
46
47
  	result = new_inode(dir->i_sb);
  	if (!result)
  		goto bail2;
  	hpfs_init_inode(result);
  	result->i_ino = fno;
  	hpfs_i(result)->i_parent_dir = dir->i_ino;
  	hpfs_i(result)->i_dno = dno;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
48
  	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
56
57
  	result->i_ctime.tv_nsec = 0; 
  	result->i_mtime.tv_nsec = 0; 
  	result->i_atime.tv_nsec = 0; 
  	hpfs_i(result)->i_ea_size = 0;
  	result->i_mode |= S_IFDIR;
  	result->i_op = &hpfs_dir_iops;
  	result->i_fop = &hpfs_dir_ops;
  	result->i_blocks = 4;
  	result->i_size = 2048;
bfe868486   Miklos Szeredi   filesystems: add ...
58
  	set_nlink(result, 2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
  	if (dee.read_only)
  		result->i_mode &= ~0222;
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
61
  	r = hpfs_add_dirent(dir, name, len, &dee);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
  	if (r == 1)
  		goto bail3;
  	if (r == -1) {
  		err = -EEXIST;
  		goto bail3;
  	}
  	fnode->len = len;
  	memcpy(fnode->name, name, len > 15 ? 15 : len);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
70
  	fnode->up = cpu_to_le32(dir->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
  	fnode->dirflag = 1;
  	fnode->btree.n_free_nodes = 7;
  	fnode->btree.n_used_nodes = 1;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
74
75
76
  	fnode->btree.first_free = cpu_to_le16(0x14);
  	fnode->u.external[0].disk_secno = cpu_to_le32(dno);
  	fnode->u.external[0].file_secno = cpu_to_le32(-1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
  	dnode->root_dnode = 1;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
78
  	dnode->up = cpu_to_le32(fno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  	de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
80
  	de->creation_date = de->write_date = de->read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
81
82
83
  	if (!(mode & 0222)) de->read_only = 1;
  	de->first = de->directory = 1;
  	/*de->hidden = de->system = 0;*/
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
84
  	de->fnode = cpu_to_le32(fno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
88
  	mark_buffer_dirty(bh);
  	brelse(bh);
  	hpfs_mark_4buffers_dirty(&qbh0);
  	hpfs_brelse4(&qbh0);
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
89
  	inc_nlink(dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  	insert_inode_hash(result);
de395b8ac   David Howells   CRED: Wrap task c...
91
92
  	if (result->i_uid != current_fsuid() ||
  	    result->i_gid != current_fsgid() ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  	    result->i_mode != (mode | S_IFDIR)) {
de395b8ac   David Howells   CRED: Wrap task c...
94
95
  		result->i_uid = current_fsuid();
  		result->i_gid = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
  		result->i_mode = mode | S_IFDIR;
  		hpfs_write_inode_nolock(result);
  	}
  	d_instantiate(dentry, result);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
100
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
  	return 0;
  bail3:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
104
105
106
107
108
109
110
  	iput(result);
  bail2:
  	hpfs_brelse4(&qbh0);
  	hpfs_free_dnode(dir->i_sb, dno);
  bail1:
  	brelse(bh);
  	hpfs_free_sectors(dir->i_sb, fno, 1);
  bail:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
111
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  	return err;
  }
4acdaf27e   Al Viro   switch ->create()...
114
  static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct nameidata *nd)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
  {
7e7742ee0   Al Viro   sanitize signedne...
116
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
120
121
122
123
124
  	unsigned len = dentry->d_name.len;
  	struct inode *result = NULL;
  	struct buffer_head *bh;
  	struct fnode *fnode;
  	fnode_secno fno;
  	int r;
  	struct hpfs_dirent dee;
  	int err;
7e7742ee0   Al Viro   sanitize signedne...
125
  	if ((err = hpfs_chk_name(name, &len)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  		return err==-ENOENT ? -EINVAL : err;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
127
  	hpfs_lock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
130
131
132
133
134
135
  	err = -ENOSPC;
  	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
  	if (!fnode)
  		goto bail;
  	memset(&dee, 0, sizeof dee);
  	if (!(mode & 0222)) dee.read_only = 1;
  	dee.archive = 1;
  	dee.hidden = name[0] == '.';
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
136
137
  	dee.fnode = cpu_to_le32(fno);
  	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
141
142
143
144
145
146
147
148
  
  	result = new_inode(dir->i_sb);
  	if (!result)
  		goto bail1;
  	
  	hpfs_init_inode(result);
  	result->i_ino = fno;
  	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 ...
149
  	set_nlink(result, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
  	hpfs_i(result)->i_parent_dir = dir->i_ino;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
151
  	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
155
156
157
158
159
160
161
  	result->i_ctime.tv_nsec = 0;
  	result->i_mtime.tv_nsec = 0;
  	result->i_atime.tv_nsec = 0;
  	hpfs_i(result)->i_ea_size = 0;
  	if (dee.read_only)
  		result->i_mode &= ~0222;
  	result->i_blocks = 1;
  	result->i_size = 0;
  	result->i_data.a_ops = &hpfs_aops;
  	hpfs_i(result)->mmu_private = 0;
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
162
  	r = hpfs_add_dirent(dir, name, len, &dee);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
164
165
166
167
168
169
170
  	if (r == 1)
  		goto bail2;
  	if (r == -1) {
  		err = -EEXIST;
  		goto bail2;
  	}
  	fnode->len = len;
  	memcpy(fnode->name, name, len > 15 ? 15 : len);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
171
  	fnode->up = cpu_to_le32(dir->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
173
174
175
  	mark_buffer_dirty(bh);
  	brelse(bh);
  
  	insert_inode_hash(result);
de395b8ac   David Howells   CRED: Wrap task c...
176
177
  	if (result->i_uid != current_fsuid() ||
  	    result->i_gid != current_fsgid() ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
178
  	    result->i_mode != (mode | S_IFREG)) {
de395b8ac   David Howells   CRED: Wrap task c...
179
180
  		result->i_uid = current_fsuid();
  		result->i_gid = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
184
  		result->i_mode = mode | S_IFREG;
  		hpfs_write_inode_nolock(result);
  	}
  	d_instantiate(dentry, result);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
185
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
  	return 0;
  
  bail2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
189
190
191
192
193
  	iput(result);
  bail1:
  	brelse(bh);
  	hpfs_free_sectors(dir->i_sb, fno, 1);
  bail:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
194
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
  	return err;
  }
1a67aafb5   Al Viro   switch ->mknod() ...
197
  static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  {
7e7742ee0   Al Viro   sanitize signedne...
199
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
206
207
  	unsigned len = dentry->d_name.len;
  	struct buffer_head *bh;
  	struct fnode *fnode;
  	fnode_secno fno;
  	int r;
  	struct hpfs_dirent dee;
  	struct inode *result = NULL;
  	int err;
7e7742ee0   Al Viro   sanitize signedne...
208
  	if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
211
  	if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM;
  	if (!new_valid_dev(rdev))
  		return -EINVAL;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
212
  	hpfs_lock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
220
  	err = -ENOSPC;
  	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
  	if (!fnode)
  		goto bail;
  	memset(&dee, 0, sizeof dee);
  	if (!(mode & 0222)) dee.read_only = 1;
  	dee.archive = 1;
  	dee.hidden = name[0] == '.';
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
221
222
  	dee.fnode = cpu_to_le32(fno);
  	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
226
227
228
229
230
  
  	result = new_inode(dir->i_sb);
  	if (!result)
  		goto bail1;
  
  	hpfs_init_inode(result);
  	result->i_ino = fno;
  	hpfs_i(result)->i_parent_dir = dir->i_ino;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
231
  	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232
233
234
235
  	result->i_ctime.tv_nsec = 0;
  	result->i_mtime.tv_nsec = 0;
  	result->i_atime.tv_nsec = 0;
  	hpfs_i(result)->i_ea_size = 0;
de395b8ac   David Howells   CRED: Wrap task c...
236
237
  	result->i_uid = current_fsuid();
  	result->i_gid = current_fsgid();
bfe868486   Miklos Szeredi   filesystems: add ...
238
  	set_nlink(result, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
  	result->i_size = 0;
  	result->i_blocks = 1;
  	init_special_inode(result, mode, rdev);
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
242
  	r = hpfs_add_dirent(dir, name, len, &dee);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
248
249
250
  	if (r == 1)
  		goto bail2;
  	if (r == -1) {
  		err = -EEXIST;
  		goto bail2;
  	}
  	fnode->len = len;
  	memcpy(fnode->name, name, len > 15 ? 15 : len);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
251
  	fnode->up = cpu_to_le32(dir->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
252
253
254
255
256
257
  	mark_buffer_dirty(bh);
  
  	insert_inode_hash(result);
  
  	hpfs_write_inode_nolock(result);
  	d_instantiate(dentry, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
  	brelse(bh);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
259
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
260
261
  	return 0;
  bail2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
  	iput(result);
  bail1:
  	brelse(bh);
  	hpfs_free_sectors(dir->i_sb, fno, 1);
  bail:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
267
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
271
272
  	return err;
  }
  
  static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
  {
7e7742ee0   Al Viro   sanitize signedne...
273
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
276
277
278
279
280
281
  	unsigned len = dentry->d_name.len;
  	struct buffer_head *bh;
  	struct fnode *fnode;
  	fnode_secno fno;
  	int r;
  	struct hpfs_dirent dee;
  	struct inode *result;
  	int err;
7e7742ee0   Al Viro   sanitize signedne...
282
  	if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
283
  	hpfs_lock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
284
  	if (hpfs_sb(dir->i_sb)->sb_eas < 2) {
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
285
  		hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286
287
288
289
290
291
292
293
294
  		return -EPERM;
  	}
  	err = -ENOSPC;
  	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
  	if (!fnode)
  		goto bail;
  	memset(&dee, 0, sizeof dee);
  	dee.archive = 1;
  	dee.hidden = name[0] == '.';
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
295
296
  	dee.fnode = cpu_to_le32(fno);
  	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
297
298
299
300
301
302
303
  
  	result = new_inode(dir->i_sb);
  	if (!result)
  		goto bail1;
  	result->i_ino = fno;
  	hpfs_init_inode(result);
  	hpfs_i(result)->i_parent_dir = dir->i_ino;
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
304
  	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
305
306
307
308
309
  	result->i_ctime.tv_nsec = 0;
  	result->i_mtime.tv_nsec = 0;
  	result->i_atime.tv_nsec = 0;
  	hpfs_i(result)->i_ea_size = 0;
  	result->i_mode = S_IFLNK | 0777;
de395b8ac   David Howells   CRED: Wrap task c...
310
311
  	result->i_uid = current_fsuid();
  	result->i_gid = current_fsgid();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  	result->i_blocks = 1;
bfe868486   Miklos Szeredi   filesystems: add ...
313
  	set_nlink(result, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
316
  	result->i_size = strlen(symlink);
  	result->i_op = &page_symlink_inode_operations;
  	result->i_data.a_ops = &hpfs_symlink_aops;
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
317
  	r = hpfs_add_dirent(dir, name, len, &dee);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
320
321
322
323
324
325
  	if (r == 1)
  		goto bail2;
  	if (r == -1) {
  		err = -EEXIST;
  		goto bail2;
  	}
  	fnode->len = len;
  	memcpy(fnode->name, name, len > 15 ? 15 : len);
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
326
  	fnode->up = cpu_to_le32(dir->i_ino);
7e7742ee0   Al Viro   sanitize signedne...
327
  	hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
  	mark_buffer_dirty(bh);
  	brelse(bh);
  
  	insert_inode_hash(result);
  
  	hpfs_write_inode_nolock(result);
  	d_instantiate(dentry, result);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
335
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
336
337
  	return 0;
  bail2:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
338
339
340
341
342
  	iput(result);
  bail1:
  	brelse(bh);
  	hpfs_free_sectors(dir->i_sb, fno, 1);
  bail:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
343
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
  	return err;
  }
  
  static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
  {
7e7742ee0   Al Viro   sanitize signedne...
349
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
  	unsigned len = dentry->d_name.len;
  	struct quad_buffer_head qbh;
  	struct hpfs_dirent *de;
  	struct inode *inode = dentry->d_inode;
  	dnode_secno dno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
355
356
357
  	int r;
  	int rep = 0;
  	int err;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
358
  	hpfs_lock(dir->i_sb);
7e7742ee0   Al Viro   sanitize signedne...
359
  	hpfs_adjust_length(name, &len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
  again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  	err = -ENOENT;
7e7742ee0   Al Viro   sanitize signedne...
362
  	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
367
368
369
370
371
372
  	if (!de)
  		goto out;
  
  	err = -EPERM;
  	if (de->first)
  		goto out1;
  
  	err = -EISDIR;
  	if (de->directory)
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
378
379
380
381
382
383
  	r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
  	switch (r) {
  	case 1:
  		hpfs_error(dir->i_sb, "there was error when removing dirent");
  		err = -EFSERROR;
  		break;
  	case 2:		/* no space for deleting, try to truncate file */
  
  		err = -ENOSPC;
  		if (rep++)
  			break;
e21e7095a   Al Viro   Don't mess with g...
384
385
  		dentry_unhash(dentry);
  		if (!d_unhashed(dentry)) {
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
386
  			hpfs_unlock(dir->i_sb);
e21e7095a   Al Viro   Don't mess with g...
387
388
  			return -ENOSPC;
  		}
2830ba7f3   Al Viro   ->permission() sa...
389
  		if (generic_permission(inode, MAY_WRITE) ||
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
  		    !S_ISREG(inode->i_mode) ||
  		    get_write_access(inode)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
  			d_rehash(dentry);
  		} else {
  			struct iattr newattrs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
396
397
398
399
400
401
402
403
  			/*printk("HPFS: truncating file before delete.
  ");*/
  			newattrs.ia_size = 0;
  			newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
  			err = notify_change(dentry, &newattrs);
  			put_write_access(inode);
  			if (!err)
  				goto again;
  		}
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
404
  		hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
405
406
  		return -ENOSPC;
  	default:
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
407
  		drop_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
412
413
414
  		err = 0;
  	}
  	goto out;
  
  out1:
  	hpfs_brelse4(&qbh);
  out:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
415
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
417
418
419
420
  	return err;
  }
  
  static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
  {
7e7742ee0   Al Viro   sanitize signedne...
421
  	const unsigned char *name = dentry->d_name.name;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
425
426
  	unsigned len = dentry->d_name.len;
  	struct quad_buffer_head qbh;
  	struct hpfs_dirent *de;
  	struct inode *inode = dentry->d_inode;
  	dnode_secno dno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427
428
429
  	int n_items = 0;
  	int err;
  	int r;
7e7742ee0   Al Viro   sanitize signedne...
430
  	hpfs_adjust_length(name, &len);
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
431
  	hpfs_lock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  	err = -ENOENT;
7e7742ee0   Al Viro   sanitize signedne...
433
  	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  	if (!de)
  		goto out;
  
  	err = -EPERM;
  	if (de->first)
  		goto out1;
  
  	err = -ENOTDIR;
  	if (!de->directory)
  		goto out1;
  
  	hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items);
  	err = -ENOTEMPTY;
  	if (n_items)
  		goto out1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
449
450
451
452
453
454
455
456
457
458
  	r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
  	switch (r) {
  	case 1:
  		hpfs_error(dir->i_sb, "there was error when removing dirent");
  		err = -EFSERROR;
  		break;
  	case 2:
  		err = -ENOSPC;
  		break;
  	default:
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
459
  		drop_nlink(dir);
ce71ec368   Dave Hansen   [PATCH] r/o bind ...
460
  		clear_nlink(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
462
463
464
465
466
  		err = 0;
  	}
  	goto out;
  out1:
  	hpfs_brelse4(&qbh);
  out:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
467
  	hpfs_unlock(dir->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
469
470
471
472
473
474
475
476
477
478
479
  	return err;
  }
  
  static int hpfs_symlink_readpage(struct file *file, struct page *page)
  {
  	char *link = kmap(page);
  	struct inode *i = page->mapping->host;
  	struct fnode *fnode;
  	struct buffer_head *bh;
  	int err;
  
  	err = -EIO;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
480
  	hpfs_lock(i->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
  	if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh)))
  		goto fail;
  	err = hpfs_read_ea(i->i_sb, fnode, "SYMLINK", link, PAGE_SIZE);
  	brelse(bh);
  	if (err)
  		goto fail;
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
487
  	hpfs_unlock(i->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
489
490
491
492
493
  	SetPageUptodate(page);
  	kunmap(page);
  	unlock_page(page);
  	return 0;
  
  fail:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
494
  	hpfs_unlock(i->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
499
  	SetPageError(page);
  	kunmap(page);
  	unlock_page(page);
  	return err;
  }
f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
500
  const struct address_space_operations hpfs_symlink_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
503
504
505
506
  	.readpage	= hpfs_symlink_readpage
  };
  	
  static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
  		struct inode *new_dir, struct dentry *new_dentry)
  {
7e7742ee0   Al Viro   sanitize signedne...
507
508
509
510
  	const unsigned char *old_name = old_dentry->d_name.name;
  	unsigned old_len = old_dentry->d_name.len;
  	const unsigned char *new_name = new_dentry->d_name.name;
  	unsigned new_len = new_dentry->d_name.len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
514
515
516
517
518
519
520
  	struct inode *i = old_dentry->d_inode;
  	struct inode *new_inode = new_dentry->d_inode;
  	struct quad_buffer_head qbh, qbh1;
  	struct hpfs_dirent *dep, *nde;
  	struct hpfs_dirent de;
  	dnode_secno dno;
  	int r;
  	struct buffer_head *bh;
  	struct fnode *fnode;
  	int err;
e4eaac06b   Sage Weil   vfs: push dentry_...
521

7e7742ee0   Al Viro   sanitize signedne...
522
  	if ((err = hpfs_chk_name(new_name, &new_len))) return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
  	err = 0;
7e7742ee0   Al Viro   sanitize signedne...
524
  	hpfs_adjust_length(old_name, &old_len);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525

9a311b96c   Arnd Bergmann   hpfs: remove the BKL
526
  	hpfs_lock(i->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  	/* order doesn't matter, due to VFS exclusion */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
  	
  	/* Erm? Moving over the empty non-busy directory is perfectly legal */
  	if (new_inode && S_ISDIR(new_inode->i_mode)) {
  		err = -EINVAL;
  		goto end1;
  	}
7e7742ee0   Al Viro   sanitize signedne...
534
  	if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
538
539
540
541
542
543
544
  		hpfs_error(i->i_sb, "lookup succeeded but map dirent failed");
  		err = -ENOENT;
  		goto end1;
  	}
  	copy_de(&de, dep);
  	de.hidden = new_name[0] == '.';
  
  	if (new_inode) {
  		int r;
  		if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
7e7742ee0   Al Viro   sanitize signedne...
545
  			if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) {
ce71ec368   Dave Hansen   [PATCH] r/o bind ...
546
  				clear_nlink(new_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  				copy_de(nde, &de);
  				memcpy(nde->name, new_name, new_len);
  				hpfs_mark_4buffers_dirty(&qbh1);
  				hpfs_brelse4(&qbh1);
  				goto end;
  			}
  			hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent");
  			err = -EFSERROR;
  			goto end1;
  		}
  		err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
  		goto end1;
  	}
  
  	if (new_dir == old_dir) hpfs_brelse4(&qbh);
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
562
  	if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
564
565
566
567
568
569
  		if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!");
  		err = r == 1 ? -ENOSPC : -EFSERROR;
  		if (new_dir != old_dir) hpfs_brelse4(&qbh);
  		goto end1;
  	}
  	
  	if (new_dir == old_dir)
7e7742ee0   Al Viro   sanitize signedne...
570
  		if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
574
575
576
  			hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
  			err = -ENOENT;
  			goto end1;
  		}
  
  	if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
  		hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent");
  		err = r == 2 ? -ENOSPC : -EFSERROR;
  		goto end1;
  	}
7d23ce36e   Mikulas Patocka   HPFS: Remove rema...
581

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
  	end:
  	hpfs_i(i)->i_parent_dir = new_dir->i_ino;
  	if (S_ISDIR(i->i_mode)) {
d8c76e6f4   Dave Hansen   [PATCH] r/o bind ...
585
  		inc_nlink(new_dir);
9a53c3a78   Dave Hansen   [PATCH] r/o bind ...
586
  		drop_nlink(old_dir);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
588
  	}
  	if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
0b69760be   Mikulas Patocka   HPFS: Fix endiani...
589
  		fnode->up = cpu_to_le32(new_dir->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
591
592
593
594
595
  		fnode->len = new_len;
  		memcpy(fnode->name, new_name, new_len>15?15:new_len);
  		if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len);
  		mark_buffer_dirty(bh);
  		brelse(bh);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
596
  end1:
9a311b96c   Arnd Bergmann   hpfs: remove the BKL
597
  	hpfs_unlock(i->i_sb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
  	return err;
  }
92e1d5be9   Arjan van de Ven   [PATCH] mark stru...
600
  const struct inode_operations hpfs_dir_iops =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
602
603
604
605
606
607
608
609
  {
  	.create		= hpfs_create,
  	.lookup		= hpfs_lookup,
  	.unlink		= hpfs_unlink,
  	.symlink	= hpfs_symlink,
  	.mkdir		= hpfs_mkdir,
  	.rmdir		= hpfs_rmdir,
  	.mknod		= hpfs_mknod,
  	.rename		= hpfs_rename,
ca30bc995   Christoph Hellwig   [PATCH] hpfs: cle...
610
  	.setattr	= hpfs_setattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  };