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