]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/fs/hpfs/namei.c | |
3 | * | |
4 | * Mikulas Patocka ([email protected]), 1998-1999 | |
5 | * | |
6 | * adding & removing files & directories | |
7 | */ | |
e8edc6e0 | 8 | #include <linux/sched.h> |
1da177e4 LT |
9 | #include "hpfs_fn.h" |
10 | ||
18bb1db3 | 11 | static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) |
1da177e4 | 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] == '.'; | |
0b69760b MP |
40 | dee.fnode = cpu_to_le32(fno); |
41 | dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); | |
1da177e4 LT |
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; | |
0b69760b | 49 | 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)); |
1da177e4 LT |
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; | |
bfe86848 | 59 | set_nlink(result, 2); |
1da177e4 LT |
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); | |
0b69760b | 72 | fnode->up = cpu_to_le32(dir->i_ino); |
c4c99543 | 73 | fnode->flags |= FNODE_dir; |
1da177e4 LT |
74 | fnode->btree.n_free_nodes = 7; |
75 | fnode->btree.n_used_nodes = 1; | |
0b69760b MP |
76 | fnode->btree.first_free = cpu_to_le16(0x14); |
77 | fnode->u.external[0].disk_secno = cpu_to_le32(dno); | |
78 | fnode->u.external[0].file_secno = cpu_to_le32(-1); | |
1da177e4 | 79 | dnode->root_dnode = 1; |
0b69760b | 80 | dnode->up = cpu_to_le32(fno); |
1da177e4 | 81 | de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0); |
0b69760b | 82 | de->creation_date = de->write_date = de->read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); |
1da177e4 LT |
83 | if (!(mode & 0222)) de->read_only = 1; |
84 | de->first = de->directory = 1; | |
85 | /*de->hidden = de->system = 0;*/ | |
0b69760b | 86 | de->fnode = cpu_to_le32(fno); |
1da177e4 LT |
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 | ||
0e1a43c7 EB |
94 | if (!uid_eq(result->i_uid, current_fsuid()) || |
95 | !gid_eq(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 | ||
ebfc3b49 | 118 | static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) |
1da177e4 | 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] == '.'; | |
0b69760b MP |
140 | dee.fnode = cpu_to_le32(fno); |
141 | dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); | |
1da177e4 LT |
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; | |
bfe86848 | 153 | set_nlink(result, 1); |
1da177e4 | 154 | hpfs_i(result)->i_parent_dir = dir->i_ino; |
0b69760b | 155 | 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)); |
1da177e4 LT |
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); | |
0b69760b | 176 | fnode->up = cpu_to_le32(dir->i_ino); |
1da177e4 LT |
177 | mark_buffer_dirty(bh); |
178 | brelse(bh); | |
179 | ||
180 | insert_inode_hash(result); | |
181 | ||
0e1a43c7 EB |
182 | if (!uid_eq(result->i_uid, current_fsuid()) || |
183 | !gid_eq(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 | ||
1a67aafb | 204 | static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev) |
1da177e4 | 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] == '.'; | |
0b69760b MP |
228 | dee.fnode = cpu_to_le32(fno); |
229 | dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); | |
1da177e4 LT |
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; | |
0b69760b | 238 | 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)); |
1da177e4 LT |
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(); | |
bfe86848 | 245 | set_nlink(result, 1); |
1da177e4 LT |
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); | |
0b69760b | 259 | fnode->up = cpu_to_le32(dir->i_ino); |
1da177e4 LT |
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] == '.'; | |
0b69760b MP |
303 | dee.fnode = cpu_to_le32(fno); |
304 | dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds())); | |
1da177e4 LT |
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; | |
0b69760b | 312 | 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)); |
1da177e4 LT |
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 | 320 | result->i_blocks = 1; |
bfe86848 | 321 | set_nlink(result, 1); |
1da177e4 LT |
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); | |
0b69760b | 335 | fnode->up = cpu_to_le32(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; | |
1da177e4 LT |
364 | int r; |
365 | int rep = 0; | |
366 | int err; | |
367 | ||
9a311b96 | 368 | hpfs_lock(dir->i_sb); |
7e7742ee | 369 | hpfs_adjust_length(name, &len); |
1da177e4 | 370 | again: |
1da177e4 | 371 | err = -ENOENT; |
7e7742ee | 372 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); |
1da177e4 LT |
373 | if (!de) |
374 | goto out; | |
375 | ||
376 | err = -EPERM; | |
377 | if (de->first) | |
378 | goto out1; | |
379 | ||
380 | err = -EISDIR; | |
381 | if (de->directory) | |
382 | goto out1; | |
383 | ||
1da177e4 LT |
384 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); |
385 | switch (r) { | |
386 | case 1: | |
387 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | |
388 | err = -EFSERROR; | |
389 | break; | |
390 | case 2: /* no space for deleting, try to truncate file */ | |
391 | ||
392 | err = -ENOSPC; | |
393 | if (rep++) | |
394 | break; | |
395 | ||
e21e7095 AV |
396 | dentry_unhash(dentry); |
397 | if (!d_unhashed(dentry)) { | |
9a311b96 | 398 | hpfs_unlock(dir->i_sb); |
e21e7095 AV |
399 | return -ENOSPC; |
400 | } | |
2830ba7f | 401 | if (generic_permission(inode, MAY_WRITE) || |
1da177e4 LT |
402 | !S_ISREG(inode->i_mode) || |
403 | get_write_access(inode)) { | |
1da177e4 LT |
404 | d_rehash(dentry); |
405 | } else { | |
406 | struct iattr newattrs; | |
14da17f9 | 407 | /*pr_info("truncating file before delete.\n");*/ |
1da177e4 LT |
408 | newattrs.ia_size = 0; |
409 | newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; | |
27ac0ffe | 410 | err = notify_change(dentry, &newattrs, NULL); |
1da177e4 LT |
411 | put_write_access(inode); |
412 | if (!err) | |
413 | goto again; | |
414 | } | |
9a311b96 | 415 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
416 | return -ENOSPC; |
417 | default: | |
9a53c3a7 | 418 | drop_nlink(inode); |
1da177e4 LT |
419 | err = 0; |
420 | } | |
421 | goto out; | |
422 | ||
423 | out1: | |
424 | hpfs_brelse4(&qbh); | |
425 | out: | |
9a311b96 | 426 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
427 | return err; |
428 | } | |
429 | ||
430 | static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) | |
431 | { | |
7e7742ee | 432 | const unsigned char *name = dentry->d_name.name; |
1da177e4 LT |
433 | unsigned len = dentry->d_name.len; |
434 | struct quad_buffer_head qbh; | |
435 | struct hpfs_dirent *de; | |
436 | struct inode *inode = dentry->d_inode; | |
437 | dnode_secno dno; | |
1da177e4 LT |
438 | int n_items = 0; |
439 | int err; | |
440 | int r; | |
441 | ||
7e7742ee | 442 | hpfs_adjust_length(name, &len); |
9a311b96 | 443 | hpfs_lock(dir->i_sb); |
1da177e4 | 444 | err = -ENOENT; |
7e7742ee | 445 | de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh); |
1da177e4 LT |
446 | if (!de) |
447 | goto out; | |
448 | ||
449 | err = -EPERM; | |
450 | if (de->first) | |
451 | goto out1; | |
452 | ||
453 | err = -ENOTDIR; | |
454 | if (!de->directory) | |
455 | goto out1; | |
456 | ||
457 | hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items); | |
458 | err = -ENOTEMPTY; | |
459 | if (n_items) | |
460 | goto out1; | |
461 | ||
1da177e4 LT |
462 | r = hpfs_remove_dirent(dir, dno, de, &qbh, 1); |
463 | switch (r) { | |
464 | case 1: | |
465 | hpfs_error(dir->i_sb, "there was error when removing dirent"); | |
466 | err = -EFSERROR; | |
467 | break; | |
468 | case 2: | |
469 | err = -ENOSPC; | |
470 | break; | |
471 | default: | |
9a53c3a7 | 472 | drop_nlink(dir); |
ce71ec36 | 473 | clear_nlink(inode); |
1da177e4 LT |
474 | err = 0; |
475 | } | |
476 | goto out; | |
477 | out1: | |
478 | hpfs_brelse4(&qbh); | |
479 | out: | |
9a311b96 | 480 | hpfs_unlock(dir->i_sb); |
1da177e4 LT |
481 | return err; |
482 | } | |
483 | ||
484 | static int hpfs_symlink_readpage(struct file *file, struct page *page) | |
485 | { | |
486 | char *link = kmap(page); | |
487 | struct inode *i = page->mapping->host; | |
488 | struct fnode *fnode; | |
489 | struct buffer_head *bh; | |
490 | int err; | |
491 | ||
492 | err = -EIO; | |
9a311b96 | 493 | hpfs_lock(i->i_sb); |
1da177e4 LT |
494 | if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) |
495 | goto fail; | |
496 | err = hpfs_read_ea(i->i_sb, fnode, "SYMLINK", link, PAGE_SIZE); | |
497 | brelse(bh); | |
498 | if (err) | |
499 | goto fail; | |
9a311b96 | 500 | hpfs_unlock(i->i_sb); |
1da177e4 LT |
501 | SetPageUptodate(page); |
502 | kunmap(page); | |
503 | unlock_page(page); | |
504 | return 0; | |
505 | ||
506 | fail: | |
9a311b96 | 507 | hpfs_unlock(i->i_sb); |
1da177e4 LT |
508 | SetPageError(page); |
509 | kunmap(page); | |
510 | unlock_page(page); | |
511 | return err; | |
512 | } | |
513 | ||
f5e54d6e | 514 | const struct address_space_operations hpfs_symlink_aops = { |
1da177e4 LT |
515 | .readpage = hpfs_symlink_readpage |
516 | }; | |
517 | ||
518 | static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |
519 | struct inode *new_dir, struct dentry *new_dentry) | |
520 | { | |
7e7742ee AV |
521 | const unsigned char *old_name = old_dentry->d_name.name; |
522 | unsigned old_len = old_dentry->d_name.len; | |
523 | const unsigned char *new_name = new_dentry->d_name.name; | |
524 | unsigned new_len = new_dentry->d_name.len; | |
1da177e4 LT |
525 | struct inode *i = old_dentry->d_inode; |
526 | struct inode *new_inode = new_dentry->d_inode; | |
527 | struct quad_buffer_head qbh, qbh1; | |
528 | struct hpfs_dirent *dep, *nde; | |
529 | struct hpfs_dirent de; | |
530 | dnode_secno dno; | |
531 | int r; | |
532 | struct buffer_head *bh; | |
533 | struct fnode *fnode; | |
534 | int err; | |
e4eaac06 | 535 | |
7e7742ee | 536 | if ((err = hpfs_chk_name(new_name, &new_len))) return err; |
1da177e4 | 537 | err = 0; |
7e7742ee | 538 | hpfs_adjust_length(old_name, &old_len); |
1da177e4 | 539 | |
9a311b96 | 540 | hpfs_lock(i->i_sb); |
1da177e4 | 541 | /* order doesn't matter, due to VFS exclusion */ |
1da177e4 LT |
542 | |
543 | /* Erm? Moving over the empty non-busy directory is perfectly legal */ | |
544 | if (new_inode && S_ISDIR(new_inode->i_mode)) { | |
545 | err = -EINVAL; | |
546 | goto end1; | |
547 | } | |
548 | ||
7e7742ee | 549 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { |
1da177e4 LT |
550 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); |
551 | err = -ENOENT; | |
552 | goto end1; | |
553 | } | |
554 | copy_de(&de, dep); | |
555 | de.hidden = new_name[0] == '.'; | |
556 | ||
557 | if (new_inode) { | |
558 | int r; | |
559 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { | |
7e7742ee | 560 | if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) { |
ce71ec36 | 561 | clear_nlink(new_inode); |
1da177e4 LT |
562 | copy_de(nde, &de); |
563 | memcpy(nde->name, new_name, new_len); | |
564 | hpfs_mark_4buffers_dirty(&qbh1); | |
565 | hpfs_brelse4(&qbh1); | |
566 | goto end; | |
567 | } | |
568 | hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent"); | |
569 | err = -EFSERROR; | |
570 | goto end1; | |
571 | } | |
572 | err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0; | |
573 | goto end1; | |
574 | } | |
575 | ||
576 | if (new_dir == old_dir) hpfs_brelse4(&qbh); | |
577 | ||
7d23ce36 | 578 | if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) { |
1da177e4 LT |
579 | if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!"); |
580 | err = r == 1 ? -ENOSPC : -EFSERROR; | |
581 | if (new_dir != old_dir) hpfs_brelse4(&qbh); | |
582 | goto end1; | |
583 | } | |
584 | ||
585 | if (new_dir == old_dir) | |
7e7742ee | 586 | if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) { |
1da177e4 LT |
587 | hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); |
588 | err = -ENOENT; | |
589 | goto end1; | |
590 | } | |
591 | ||
592 | if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) { | |
1da177e4 LT |
593 | hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent"); |
594 | err = r == 2 ? -ENOSPC : -EFSERROR; | |
595 | goto end1; | |
596 | } | |
7d23ce36 | 597 | |
1da177e4 LT |
598 | end: |
599 | hpfs_i(i)->i_parent_dir = new_dir->i_ino; | |
600 | if (S_ISDIR(i->i_mode)) { | |
d8c76e6f | 601 | inc_nlink(new_dir); |
9a53c3a7 | 602 | drop_nlink(old_dir); |
1da177e4 LT |
603 | } |
604 | if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) { | |
0b69760b | 605 | fnode->up = cpu_to_le32(new_dir->i_ino); |
1da177e4 LT |
606 | fnode->len = new_len; |
607 | memcpy(fnode->name, new_name, new_len>15?15:new_len); | |
608 | if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len); | |
609 | mark_buffer_dirty(bh); | |
610 | brelse(bh); | |
611 | } | |
1da177e4 | 612 | end1: |
9a311b96 | 613 | hpfs_unlock(i->i_sb); |
1da177e4 LT |
614 | return err; |
615 | } | |
616 | ||
92e1d5be | 617 | const struct inode_operations hpfs_dir_iops = |
1da177e4 LT |
618 | { |
619 | .create = hpfs_create, | |
620 | .lookup = hpfs_lookup, | |
621 | .unlink = hpfs_unlink, | |
622 | .symlink = hpfs_symlink, | |
623 | .mkdir = hpfs_mkdir, | |
624 | .rmdir = hpfs_rmdir, | |
625 | .mknod = hpfs_mknod, | |
626 | .rename = hpfs_rename, | |
ca30bc99 | 627 | .setattr = hpfs_setattr, |
1da177e4 | 628 | }; |