Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/hpfs/namei.c | |
3 | * | |
4 | * Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999 | |
5 | * | |
6 | * adding & removing files & directories | |
7 | */ | |
e8edc6e0 | 8 | #include <linux/sched.h> |
1da177e4 LT |
9 | #include "hpfs_fn.h" |
10 | ||
11 | static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |
12 | { | |
7e7742ee | 13 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
14 | unsigned len = dentry->d_name.len; |
15 | struct quad_buffer_head qbh0; | |
16 | struct buffer_head *bh; | |
17 | struct hpfs_dirent *de; | |
18 | struct fnode *fnode; | |
19 | struct dnode *dnode; | |
20 | struct inode *result; | |
21 | fnode_secno fno; | |
22 | dnode_secno dno; | |
23 | int r; | |
24 | struct hpfs_dirent dee; | |
25 | int err; | |
7e7742ee | 26 | if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; |
9a311b96 | 27 | hpfs_lock(dir->i_sb); |
1da177e4 LT |
28 | err = -ENOSPC; |
29 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | |
30 | if (!fnode) | |
31 | goto bail; | |
7d23ce36 | 32 | dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0); |
1da177e4 LT |
33 | if (!dnode) |
34 | goto bail1; | |
35 | memset(&dee, 0, sizeof dee); | |
36 | dee.directory = 1; | |
37 | if (!(mode & 0222)) dee.read_only = 1; | |
38 | /*dee.archive = 0;*/ | |
39 | dee.hidden = name[0] == '.'; | |
40 | dee.fnode = fno; | |
41 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | |
42 | result = new_inode(dir->i_sb); | |
43 | if (!result) | |
44 | goto bail2; | |
45 | hpfs_init_inode(result); | |
46 | result->i_ino = fno; | |
47 | hpfs_i(result)->i_parent_dir = dir->i_ino; | |
48 | hpfs_i(result)->i_dno = dno; | |
49 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | |
50 | result->i_ctime.tv_nsec = 0; | |
51 | result->i_mtime.tv_nsec = 0; | |
52 | result->i_atime.tv_nsec = 0; | |
53 | hpfs_i(result)->i_ea_size = 0; | |
54 | result->i_mode |= S_IFDIR; | |
55 | result->i_op = &hpfs_dir_iops; | |
56 | result->i_fop = &hpfs_dir_ops; | |
57 | result->i_blocks = 4; | |
58 | result->i_size = 2048; | |
59 | result->i_nlink = 2; | |
60 | if (dee.read_only) | |
61 | result->i_mode &= ~0222; | |
62 | ||
7d23ce36 | 63 | r = hpfs_add_dirent(dir, name, len, &dee); |
1da177e4 LT |
64 | if (r == 1) |
65 | goto bail3; | |
66 | if (r == -1) { | |
67 | err = -EEXIST; | |
68 | goto bail3; | |
69 | } | |
70 | fnode->len = len; | |
71 | memcpy(fnode->name, name, len > 15 ? 15 : len); | |
72 | fnode->up = dir->i_ino; | |
73 | fnode->dirflag = 1; | |
74 | fnode->btree.n_free_nodes = 7; | |
75 | fnode->btree.n_used_nodes = 1; | |
76 | fnode->btree.first_free = 0x14; | |
77 | fnode->u.external[0].disk_secno = dno; | |
78 | fnode->u.external[0].file_secno = -1; | |
79 | dnode->root_dnode = 1; | |
80 | dnode->up = fno; | |
81 | de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); | |
82 | de->creation_date = de->write_date = de->read_date = gmt_to_local(dir->i_sb, get_seconds()); | |
83 | if (!(mode & 0222)) de->read_only = 1; | |
84 | de->first = de->directory = 1; | |
85 | /*de->hidden = de->system = 0;*/ | |
86 | de->fnode = fno; | |
87 | mark_buffer_dirty(bh); | |
88 | brelse(bh); | |
89 | hpfs_mark_4buffers_dirty(&qbh0); | |
90 | hpfs_brelse4(&qbh0); | |
d8c76e6f | 91 | inc_nlink(dir); |
1da177e4 LT |
92 | insert_inode_hash(result); |
93 | ||
de395b8a DH |
94 | if (result->i_uid != current_fsuid() || |
95 | result->i_gid != current_fsgid() || | |
1da177e4 | 96 | result->i_mode != (mode | S_IFDIR)) { |
de395b8a DH |
97 | result->i_uid = current_fsuid(); |
98 | result->i_gid = current_fsgid(); | |
1da177e4 LT |
99 | result->i_mode = mode | S_IFDIR; |
100 | hpfs_write_inode_nolock(result); | |
101 | } | |
102 | d_instantiate(dentry, result); | |
9a311b96 | 103 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
104 | return 0; |
105 | bail3: | |
1da177e4 LT |
106 | iput(result); |
107 | bail2: | |
108 | hpfs_brelse4(&qbh0); | |
109 | hpfs_free_dnode(dir->i_sb, dno); | |
110 | bail1: | |
111 | brelse(bh); | |
112 | hpfs_free_sectors(dir->i_sb, fno, 1); | |
113 | bail: | |
9a311b96 | 114 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
115 | return err; |
116 | } | |
117 | ||
118 | static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) | |
119 | { | |
7e7742ee | 120 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
121 | unsigned len = dentry->d_name.len; |
122 | struct inode *result = NULL; | |
123 | struct buffer_head *bh; | |
124 | struct fnode *fnode; | |
125 | fnode_secno fno; | |
126 | int r; | |
127 | struct hpfs_dirent dee; | |
128 | int err; | |
7e7742ee | 129 | if ((err = hpfs_chk_name(name, &len))) |
1da177e4 | 130 | return err==-ENOENT ? -EINVAL : err; |
9a311b96 | 131 | hpfs_lock(dir->i_sb); |
1da177e4 LT |
132 | err = -ENOSPC; |
133 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | |
134 | if (!fnode) | |
135 | goto bail; | |
136 | memset(&dee, 0, sizeof dee); | |
137 | if (!(mode & 0222)) dee.read_only = 1; | |
138 | dee.archive = 1; | |
139 | dee.hidden = name[0] == '.'; | |
140 | dee.fnode = fno; | |
141 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | |
142 | ||
143 | result = new_inode(dir->i_sb); | |
144 | if (!result) | |
145 | goto bail1; | |
146 | ||
147 | hpfs_init_inode(result); | |
148 | result->i_ino = fno; | |
149 | result->i_mode |= S_IFREG; | |
150 | result->i_mode &= ~0111; | |
151 | result->i_op = &hpfs_file_iops; | |
152 | result->i_fop = &hpfs_file_ops; | |
153 | result->i_nlink = 1; | |
1da177e4 LT |
154 | hpfs_i(result)->i_parent_dir = dir->i_ino; |
155 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | |
156 | result->i_ctime.tv_nsec = 0; | |
157 | result->i_mtime.tv_nsec = 0; | |
158 | result->i_atime.tv_nsec = 0; | |
159 | hpfs_i(result)->i_ea_size = 0; | |
160 | if (dee.read_only) | |
161 | result->i_mode &= ~0222; | |
162 | result->i_blocks = 1; | |
163 | result->i_size = 0; | |
164 | result->i_data.a_ops = &hpfs_aops; | |
165 | hpfs_i(result)->mmu_private = 0; | |
166 | ||
7d23ce36 | 167 | r = hpfs_add_dirent(dir, name, len, &dee); |
1da177e4 LT |
168 | if (r == 1) |
169 | goto bail2; | |
170 | if (r == -1) { | |
171 | err = -EEXIST; | |
172 | goto bail2; | |
173 | } | |
174 | fnode->len = len; | |
175 | memcpy(fnode->name, name, len > 15 ? 15 : len); | |
176 | fnode->up = dir->i_ino; | |
177 | mark_buffer_dirty(bh); | |
178 | brelse(bh); | |
179 | ||
180 | insert_inode_hash(result); | |
181 | ||
de395b8a DH |
182 | if (result->i_uid != current_fsuid() || |
183 | result->i_gid != current_fsgid() || | |
1da177e4 | 184 | result->i_mode != (mode | S_IFREG)) { |
de395b8a DH |
185 | result->i_uid = current_fsuid(); |
186 | result->i_gid = current_fsgid(); | |
1da177e4 LT |
187 | result->i_mode = mode | S_IFREG; |
188 | hpfs_write_inode_nolock(result); | |
189 | } | |
190 | d_instantiate(dentry, result); | |
9a311b96 | 191 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
192 | return 0; |
193 | ||
194 | bail2: | |
1da177e4 LT |
195 | iput(result); |
196 | bail1: | |
197 | brelse(bh); | |
198 | hpfs_free_sectors(dir->i_sb, fno, 1); | |
199 | bail: | |
9a311b96 | 200 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
201 | return err; |
202 | } | |
203 | ||
204 | static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |
205 | { | |
7e7742ee | 206 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
207 | unsigned len = dentry->d_name.len; |
208 | struct buffer_head *bh; | |
209 | struct fnode *fnode; | |
210 | fnode_secno fno; | |
211 | int r; | |
212 | struct hpfs_dirent dee; | |
213 | struct inode *result = NULL; | |
214 | int err; | |
7e7742ee | 215 | if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; |
1da177e4 LT |
216 | if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; |
217 | if (!new_valid_dev(rdev)) | |
218 | return -EINVAL; | |
9a311b96 | 219 | hpfs_lock(dir->i_sb); |
1da177e4 LT |
220 | err = -ENOSPC; |
221 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | |
222 | if (!fnode) | |
223 | goto bail; | |
224 | memset(&dee, 0, sizeof dee); | |
225 | if (!(mode & 0222)) dee.read_only = 1; | |
226 | dee.archive = 1; | |
227 | dee.hidden = name[0] == '.'; | |
228 | dee.fnode = fno; | |
229 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | |
230 | ||
231 | result = new_inode(dir->i_sb); | |
232 | if (!result) | |
233 | goto bail1; | |
234 | ||
235 | hpfs_init_inode(result); | |
236 | result->i_ino = fno; | |
237 | hpfs_i(result)->i_parent_dir = dir->i_ino; | |
238 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | |
239 | result->i_ctime.tv_nsec = 0; | |
240 | result->i_mtime.tv_nsec = 0; | |
241 | result->i_atime.tv_nsec = 0; | |
242 | hpfs_i(result)->i_ea_size = 0; | |
de395b8a DH |
243 | result->i_uid = current_fsuid(); |
244 | result->i_gid = current_fsgid(); | |
1da177e4 LT |
245 | result->i_nlink = 1; |
246 | result->i_size = 0; | |
247 | result->i_blocks = 1; | |
248 | init_special_inode(result, mode, rdev); | |
249 | ||
7d23ce36 | 250 | r = hpfs_add_dirent(dir, name, len, &dee); |
1da177e4 LT |
251 | if (r == 1) |
252 | goto bail2; | |
253 | if (r == -1) { | |
254 | err = -EEXIST; | |
255 | goto bail2; | |
256 | } | |
257 | fnode->len = len; | |
258 | memcpy(fnode->name, name, len > 15 ? 15 : len); | |
259 | fnode->up = dir->i_ino; | |
260 | mark_buffer_dirty(bh); | |
261 | ||
262 | insert_inode_hash(result); | |
263 | ||
264 | hpfs_write_inode_nolock(result); | |
265 | d_instantiate(dentry, result); | |
1da177e4 | 266 | brelse(bh); |
9a311b96 | 267 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
268 | return 0; |
269 | bail2: | |
1da177e4 LT |
270 | iput(result); |
271 | bail1: | |
272 | brelse(bh); | |
273 | hpfs_free_sectors(dir->i_sb, fno, 1); | |
274 | bail: | |
9a311b96 | 275 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
276 | return err; |
277 | } | |
278 | ||
279 | static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) | |
280 | { | |
7e7742ee | 281 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
282 | unsigned len = dentry->d_name.len; |
283 | struct buffer_head *bh; | |
284 | struct fnode *fnode; | |
285 | fnode_secno fno; | |
286 | int r; | |
287 | struct hpfs_dirent dee; | |
288 | struct inode *result; | |
289 | int err; | |
7e7742ee | 290 | if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err; |
9a311b96 | 291 | hpfs_lock(dir->i_sb); |
1da177e4 | 292 | if (hpfs_sb(dir->i_sb)->sb_eas < 2) { |
9a311b96 | 293 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
294 | return -EPERM; |
295 | } | |
296 | err = -ENOSPC; | |
297 | fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); | |
298 | if (!fnode) | |
299 | goto bail; | |
300 | memset(&dee, 0, sizeof dee); | |
301 | dee.archive = 1; | |
302 | dee.hidden = name[0] == '.'; | |
303 | dee.fnode = fno; | |
304 | dee.creation_date = dee.write_date = dee.read_date = gmt_to_local(dir->i_sb, get_seconds()); | |
305 | ||
306 | result = new_inode(dir->i_sb); | |
307 | if (!result) | |
308 | goto bail1; | |
309 | result->i_ino = fno; | |
310 | hpfs_init_inode(result); | |
311 | hpfs_i(result)->i_parent_dir = dir->i_ino; | |
312 | result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); | |
313 | result->i_ctime.tv_nsec = 0; | |
314 | result->i_mtime.tv_nsec = 0; | |
315 | result->i_atime.tv_nsec = 0; | |
316 | hpfs_i(result)->i_ea_size = 0; | |
317 | result->i_mode = S_IFLNK | 0777; | |
de395b8a DH |
318 | result->i_uid = current_fsuid(); |
319 | result->i_gid = current_fsgid(); | |
1da177e4 LT |
320 | result->i_blocks = 1; |
321 | result->i_nlink = 1; | |
322 | result->i_size = strlen(symlink); | |
323 | result->i_op = &page_symlink_inode_operations; | |
324 | result->i_data.a_ops = &hpfs_symlink_aops; | |
325 | ||
7d23ce36 | 326 | r = hpfs_add_dirent(dir, name, len, &dee); |
1da177e4 LT |
327 | if (r == 1) |
328 | goto bail2; | |
329 | if (r == -1) { | |
330 | err = -EEXIST; | |
331 | goto bail2; | |
332 | } | |
333 | fnode->len = len; | |
334 | memcpy(fnode->name, name, len > 15 ? 15 : len); | |
335 | fnode->up = dir->i_ino; | |
7e7742ee | 336 | hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink)); |
1da177e4 LT |
337 | mark_buffer_dirty(bh); |
338 | brelse(bh); | |
339 | ||
340 | insert_inode_hash(result); | |
341 | ||
342 | hpfs_write_inode_nolock(result); | |
343 | d_instantiate(dentry, result); | |
9a311b96 | 344 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
345 | return 0; |
346 | bail2: | |
1da177e4 LT |
347 | iput(result); |
348 | bail1: | |
349 | brelse(bh); | |
350 | hpfs_free_sectors(dir->i_sb, fno, 1); | |
351 | bail: | |
9a311b96 | 352 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
353 | return err; |
354 | } | |
355 | ||
356 | static int hpfs_unlink(struct inode *dir, struct dentry *dentry) | |
357 | { | |
7e7742ee | 358 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
359 | unsigned len = dentry->d_name.len; |
360 | struct quad_buffer_head qbh; | |
361 | struct hpfs_dirent *de; | |
362 | struct inode *inode = dentry->d_inode; | |
363 | dnode_secno dno; | |
364 | fnode_secno fno; | |
365 | int r; | |
366 | int rep = 0; | |
367 | int err; | |
368 | ||
9a311b96 | 369 | hpfs_lock(dir->i_sb); |
7e7742ee | 370 | hpfs_adjust_length(name, &len); |
1da177e4 | 371 | again: |
1da177e4 | 372 | err = -ENOENT; |
7e7742ee | 373 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); |
1da177e4 LT |
374 | if (!de) |
375 | goto out; | |
376 | ||
377 | err = -EPERM; | |
378 | if (de->first) | |
379 | goto out1; | |
380 | ||
381 | err = -EISDIR; | |
382 | if (de->directory) | |
383 | goto out1; | |
384 | ||
385 | fno = de->fnode; | |
386 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); | |
387 | switch (r) { | |
388 | case 1: | |
389 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | |
390 | err = -EFSERROR; | |
391 | break; | |
392 | case 2: /* no space for deleting, try to truncate file */ | |
393 | ||
394 | err = -ENOSPC; | |
395 | if (rep++) | |
396 | break; | |
397 | ||
e21e7095 AV |
398 | dentry_unhash(dentry); |
399 | if (!d_unhashed(dentry)) { | |
400 | dput(dentry); | |
9a311b96 | 401 | hpfs_unlock(dir->i_sb); |
e21e7095 AV |
402 | return -ENOSPC; |
403 | } | |
b74c79e9 | 404 | if (generic_permission(inode, MAY_WRITE, 0, NULL) || |
1da177e4 LT |
405 | !S_ISREG(inode->i_mode) || |
406 | get_write_access(inode)) { | |
1da177e4 | 407 | d_rehash(dentry); |
e21e7095 | 408 | dput(dentry); |
1da177e4 LT |
409 | } else { |
410 | struct iattr newattrs; | |
1da177e4 LT |
411 | /*printk("HPFS: truncating file before delete.\n");*/ |
412 | newattrs.ia_size = 0; | |
413 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | |
414 | err = notify_change(dentry, &newattrs); | |
415 | put_write_access(inode); | |
e21e7095 | 416 | dput(dentry); |
1da177e4 LT |
417 | if (!err) |
418 | goto again; | |
419 | } | |
9a311b96 | 420 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
421 | return -ENOSPC; |
422 | default: | |
9a53c3a7 | 423 | drop_nlink(inode); |
1da177e4 LT |
424 | err = 0; |
425 | } | |
426 | goto out; | |
427 | ||
428 | out1: | |
429 | hpfs_brelse4(&qbh); | |
430 | out: | |
9a311b96 | 431 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
432 | return err; |
433 | } | |
434 | ||
435 | static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) | |
436 | { | |
7e7742ee | 437 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
438 | unsigned len = dentry->d_name.len; |
439 | struct quad_buffer_head qbh; | |
440 | struct hpfs_dirent *de; | |
441 | struct inode *inode = dentry->d_inode; | |
442 | dnode_secno dno; | |
443 | fnode_secno fno; | |
444 | int n_items = 0; | |
445 | int err; | |
446 | int r; | |
447 | ||
7e7742ee | 448 | hpfs_adjust_length(name, &len); |
9a311b96 | 449 | hpfs_lock(dir->i_sb); |
1da177e4 | 450 | err = -ENOENT; |
7e7742ee | 451 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); |
1da177e4 LT |
452 | if (!de) |
453 | goto out; | |
454 | ||
455 | err = -EPERM; | |
456 | if (de->first) | |
457 | goto out1; | |
458 | ||
459 | err = -ENOTDIR; | |
460 | if (!de->directory) | |
461 | goto out1; | |
462 | ||
463 | hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items); | |
464 | err = -ENOTEMPTY; | |
465 | if (n_items) | |
466 | goto out1; | |
467 | ||
468 | fno = de->fnode; | |
469 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); | |
470 | switch (r) { | |
471 | case 1: | |
472 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | |
473 | err = -EFSERROR; | |
474 | break; | |
475 | case 2: | |
476 | err = -ENOSPC; | |
477 | break; | |
478 | default: | |
9a53c3a7 | 479 | drop_nlink(dir); |
ce71ec36 | 480 | clear_nlink(inode); |
1da177e4 LT |
481 | err = 0; |
482 | } | |
483 | goto out; | |
484 | out1: | |
485 | hpfs_brelse4(&qbh); | |
486 | out: | |
9a311b96 | 487 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
488 | return err; |
489 | } | |
490 | ||
491 | static int hpfs_symlink_readpage(struct file *file, struct page *page) | |
492 | { | |
493 | char *link = kmap(page); | |
494 | struct inode *i = page->mapping->host; | |
495 | struct fnode *fnode; | |
496 | struct buffer_head *bh; | |
497 | int err; | |
498 | ||
499 | err = -EIO; | |
9a311b96 | 500 | hpfs_lock(i->i_sb); |
1da177e4 LT |
501 | if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) |
502 | goto fail; | |
503 | err = hpfs_read_ea(i->i_sb, fnode, "SYMLINK", link, PAGE_SIZE); | |
504 | brelse(bh); | |
505 | if (err) | |
506 | goto fail; | |
9a311b96 | 507 | hpfs_unlock(i->i_sb); |
1da177e4 LT |
508 | SetPageUptodate(page); |
509 | kunmap(page); | |
510 | unlock_page(page); | |
511 | return 0; | |
512 | ||
513 | fail: | |
9a311b96 | 514 | hpfs_unlock(i->i_sb); |
1da177e4 LT |
515 | SetPageError(page); |
516 | kunmap(page); | |
517 | unlock_page(page); | |
518 | return err; | |
519 | } | |
520 | ||
f5e54d6e | 521 | const struct address_space_operations hpfs_symlink_aops = { |
1da177e4 LT |
522 | .readpage = hpfs_symlink_readpage |
523 | }; | |
524 | ||
525 | static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |
526 | struct inode *new_dir, struct dentry *new_dentry) | |
527 | { | |
7e7742ee AV |
528 | const unsigned char *old_name = old_dentry->d_name.name; |
529 | unsigned old_len = old_dentry->d_name.len; | |
530 | const unsigned char *new_name = new_dentry->d_name.name; | |
531 | unsigned new_len = new_dentry->d_name.len; | |
1da177e4 LT |
532 | struct inode *i = old_dentry->d_inode; |
533 | struct inode *new_inode = new_dentry->d_inode; | |
534 | struct quad_buffer_head qbh, qbh1; | |
535 | struct hpfs_dirent *dep, *nde; | |
536 | struct hpfs_dirent de; | |
537 | dnode_secno dno; | |
538 | int r; | |
539 | struct buffer_head *bh; | |
540 | struct fnode *fnode; | |
541 | int err; | |
7e7742ee | 542 | if ((err = hpfs_chk_name(new_name, &new_len))) return err; |
1da177e4 | 543 | err = 0; |
7e7742ee | 544 | hpfs_adjust_length(old_name, &old_len); |
1da177e4 | 545 | |
9a311b96 | 546 | hpfs_lock(i->i_sb); |
1da177e4 | 547 | /* order doesn't matter, due to VFS exclusion */ |
1da177e4 LT |
548 | |
549 | /* Erm? Moving over the empty non-busy directory is perfectly legal */ | |
550 | if (new_inode && S_ISDIR(new_inode->i_mode)) { | |
551 | err = -EINVAL; | |
552 | goto end1; | |
553 | } | |
554 | ||
7e7742ee | 555 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { |
1da177e4 LT |
556 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); |
557 | err = -ENOENT; | |
558 | goto end1; | |
559 | } | |
560 | copy_de(&de, dep); | |
561 | de.hidden = new_name[0] == '.'; | |
562 | ||
563 | if (new_inode) { | |
564 | int r; | |
565 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { | |
7e7742ee | 566 | if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) { |
ce71ec36 | 567 | clear_nlink(new_inode); |
1da177e4 LT |
568 | copy_de(nde, &de); |
569 | memcpy(nde->name, new_name, new_len); | |
570 | hpfs_mark_4buffers_dirty(&qbh1); | |
571 | hpfs_brelse4(&qbh1); | |
572 | goto end; | |
573 | } | |
574 | hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent"); | |
575 | err = -EFSERROR; | |
576 | goto end1; | |
577 | } | |
578 | err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; | |
579 | goto end1; | |
580 | } | |
581 | ||
582 | if (new_dir == old_dir) hpfs_brelse4(&qbh); | |
583 | ||
7d23ce36 | 584 | if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) { |
1da177e4 LT |
585 | if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); |
586 | err = r == 1 ? -ENOSPC : -EFSERROR; | |
587 | if (new_dir != old_dir) hpfs_brelse4(&qbh); | |
588 | goto end1; | |
589 | } | |
590 | ||
591 | if (new_dir == old_dir) | |
7e7742ee | 592 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { |
1da177e4 LT |
593 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); |
594 | err = -ENOENT; | |
595 | goto end1; | |
596 | } | |
597 | ||
598 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { | |
1da177e4 LT |
599 | hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); |
600 | err = r == 2 ? -ENOSPC : -EFSERROR; | |
601 | goto end1; | |
602 | } | |
7d23ce36 | 603 | |
1da177e4 LT |
604 | end: |
605 | hpfs_i(i)->i_parent_dir = new_dir->i_ino; | |
606 | if (S_ISDIR(i->i_mode)) { | |
d8c76e6f | 607 | inc_nlink(new_dir); |
9a53c3a7 | 608 | drop_nlink(old_dir); |
1da177e4 LT |
609 | } |
610 | if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { | |
611 | fnode->up = new_dir->i_ino; | |
612 | fnode->len = new_len; | |
613 | memcpy(fnode->name, new_name, new_len>15?15:new_len); | |
614 | if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); | |
615 | mark_buffer_dirty(bh); | |
616 | brelse(bh); | |
617 | } | |
1da177e4 | 618 | end1: |
9a311b96 | 619 | hpfs_unlock(i->i_sb); |
1da177e4 LT |
620 | return err; |
621 | } | |
622 | ||
92e1d5be | 623 | const struct inode_operations hpfs_dir_iops = |
1da177e4 LT |
624 | { |
625 | .create = hpfs_create, | |
626 | .lookup = hpfs_lookup, | |
627 | .unlink = hpfs_unlink, | |
628 | .symlink = hpfs_symlink, | |
629 | .mkdir = hpfs_mkdir, | |
630 | .rmdir = hpfs_rmdir, | |
631 | .mknod = hpfs_mknod, | |
632 | .rename = hpfs_rename, | |
ca30bc99 | 633 | .setattr = hpfs_setattr, |
1da177e4 | 634 | }; |