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