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