Commit | Line | Data |
---|---|---|
96385742 KO |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | ||
3 | #include "bcachefs.h" | |
4 | #include "acl.h" | |
5 | #include "btree_update.h" | |
6 | #include "dirent.h" | |
7 | #include "fs-common.h" | |
8 | #include "inode.h" | |
9 | #include "xattr.h" | |
10 | ||
11 | #include <linux/posix_acl.h> | |
12 | ||
13 | int bch2_create_trans(struct btree_trans *trans, u64 dir_inum, | |
14 | struct bch_inode_unpacked *dir_u, | |
15 | struct bch_inode_unpacked *new_inode, | |
16 | const struct qstr *name, | |
17 | uid_t uid, gid_t gid, umode_t mode, dev_t rdev, | |
18 | struct posix_acl *default_acl, | |
19 | struct posix_acl *acl) | |
20 | { | |
21 | struct bch_fs *c = trans->c; | |
22 | struct btree_iter *dir_iter; | |
23 | struct bch_hash_info hash = bch2_hash_info_init(c, new_inode); | |
24 | u64 now = bch2_current_time(trans->c); | |
25 | int ret; | |
26 | ||
63fbf458 | 27 | dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT); |
96385742 KO |
28 | if (IS_ERR(dir_iter)) |
29 | return PTR_ERR(dir_iter); | |
30 | ||
31 | bch2_inode_init_late(new_inode, now, uid, gid, mode, rdev, dir_u); | |
32 | ||
33 | if (!name) | |
34 | new_inode->bi_flags |= BCH_INODE_UNLINKED; | |
35 | ||
36 | ret = bch2_inode_create(trans, new_inode, | |
37 | BLOCKDEV_INODE_MAX, 0, | |
38 | &c->unused_inode_hint); | |
39 | if (ret) | |
40 | return ret; | |
41 | ||
42 | if (default_acl) { | |
43 | ret = bch2_set_acl_trans(trans, new_inode, &hash, | |
44 | default_acl, ACL_TYPE_DEFAULT); | |
45 | if (ret) | |
46 | return ret; | |
47 | } | |
48 | ||
49 | if (acl) { | |
50 | ret = bch2_set_acl_trans(trans, new_inode, &hash, | |
51 | acl, ACL_TYPE_ACCESS); | |
52 | if (ret) | |
53 | return ret; | |
54 | } | |
55 | ||
56 | if (name) { | |
57 | struct bch_hash_info dir_hash = bch2_hash_info_init(c, dir_u); | |
58 | dir_u->bi_mtime = dir_u->bi_ctime = now; | |
59 | ||
60 | if (S_ISDIR(new_inode->bi_mode)) | |
61 | dir_u->bi_nlink++; | |
62 | ||
63 | ret = bch2_inode_write(trans, dir_iter, dir_u); | |
64 | if (ret) | |
65 | return ret; | |
66 | ||
67 | ret = bch2_dirent_create(trans, dir_inum, &dir_hash, | |
68 | mode_to_type(new_inode->bi_mode), | |
69 | name, new_inode->bi_inum, | |
70 | BCH_HASH_SET_MUST_CREATE); | |
71 | if (ret) | |
72 | return ret; | |
73 | } | |
74 | ||
75 | return 0; | |
76 | } | |
77 | ||
63fbf458 | 78 | int bch2_link_trans(struct btree_trans *trans, u64 dir_inum, |
96385742 KO |
79 | u64 inum, struct bch_inode_unpacked *inode_u, |
80 | const struct qstr *name) | |
81 | { | |
82 | struct btree_iter *dir_iter, *inode_iter; | |
83 | struct bch_inode_unpacked dir_u; | |
84 | struct bch_hash_info dir_hash; | |
85 | u64 now = bch2_current_time(trans->c); | |
86 | ||
96385742 KO |
87 | inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT); |
88 | if (IS_ERR(inode_iter)) | |
89 | return PTR_ERR(inode_iter); | |
90 | ||
96385742 KO |
91 | inode_u->bi_ctime = now; |
92 | bch2_inode_nlink_inc(inode_u); | |
93 | ||
63fbf458 KO |
94 | dir_iter = bch2_inode_peek(trans, &dir_u, dir_inum, 0); |
95 | if (IS_ERR(dir_iter)) | |
96 | return PTR_ERR(dir_iter); | |
97 | ||
98 | /* XXX: shouldn't we be updating mtime/ctime on the directory? */ | |
99 | ||
100 | dir_hash = bch2_hash_info_init(trans->c, &dir_u); | |
101 | bch2_trans_iter_put(trans, dir_iter); | |
102 | ||
96385742 KO |
103 | return bch2_dirent_create(trans, dir_inum, &dir_hash, |
104 | mode_to_type(inode_u->bi_mode), | |
105 | name, inum, BCH_HASH_SET_MUST_CREATE) ?: | |
106 | bch2_inode_write(trans, inode_iter, inode_u); | |
107 | } | |
108 | ||
109 | int bch2_unlink_trans(struct btree_trans *trans, | |
110 | u64 dir_inum, struct bch_inode_unpacked *dir_u, | |
111 | struct bch_inode_unpacked *inode_u, | |
112 | const struct qstr *name) | |
113 | { | |
114 | struct btree_iter *dir_iter, *dirent_iter, *inode_iter; | |
115 | struct bch_hash_info dir_hash; | |
116 | u64 inum, now = bch2_current_time(trans->c); | |
117 | struct bkey_s_c k; | |
118 | ||
119 | dir_iter = bch2_inode_peek(trans, dir_u, dir_inum, BTREE_ITER_INTENT); | |
120 | if (IS_ERR(dir_iter)) | |
121 | return PTR_ERR(dir_iter); | |
122 | ||
123 | dir_hash = bch2_hash_info_init(trans->c, dir_u); | |
124 | ||
63fbf458 KO |
125 | dirent_iter = __bch2_dirent_lookup_trans(trans, dir_inum, &dir_hash, |
126 | name, BTREE_ITER_INTENT); | |
96385742 KO |
127 | if (IS_ERR(dirent_iter)) |
128 | return PTR_ERR(dirent_iter); | |
129 | ||
130 | k = bch2_btree_iter_peek_slot(dirent_iter); | |
131 | inum = le64_to_cpu(bkey_s_c_to_dirent(k).v->d_inum); | |
132 | ||
133 | inode_iter = bch2_inode_peek(trans, inode_u, inum, BTREE_ITER_INTENT); | |
134 | if (IS_ERR(inode_iter)) | |
135 | return PTR_ERR(inode_iter); | |
136 | ||
137 | dir_u->bi_mtime = dir_u->bi_ctime = inode_u->bi_ctime = now; | |
138 | dir_u->bi_nlink -= S_ISDIR(inode_u->bi_mode); | |
139 | bch2_inode_nlink_dec(inode_u); | |
140 | ||
141 | return (S_ISDIR(inode_u->bi_mode) | |
142 | ? bch2_empty_dir_trans(trans, inum) | |
143 | : 0) ?: | |
144 | bch2_dirent_delete_at(trans, &dir_hash, dirent_iter) ?: | |
145 | bch2_inode_write(trans, dir_iter, dir_u) ?: | |
146 | bch2_inode_write(trans, inode_iter, inode_u); | |
147 | } | |
148 | ||
149 | bool bch2_reinherit_attrs(struct bch_inode_unpacked *dst_u, | |
150 | struct bch_inode_unpacked *src_u) | |
151 | { | |
152 | u64 src, dst; | |
153 | unsigned id; | |
154 | bool ret = false; | |
155 | ||
156 | for (id = 0; id < Inode_opt_nr; id++) { | |
157 | if (dst_u->bi_fields_set & (1 << id)) | |
158 | continue; | |
159 | ||
160 | src = bch2_inode_opt_get(src_u, id); | |
161 | dst = bch2_inode_opt_get(dst_u, id); | |
162 | ||
163 | if (src == dst) | |
164 | continue; | |
165 | ||
166 | bch2_inode_opt_set(dst_u, id, src); | |
167 | ret = true; | |
168 | } | |
169 | ||
170 | return ret; | |
171 | } | |
172 | ||
173 | int bch2_rename_trans(struct btree_trans *trans, | |
174 | u64 src_dir, struct bch_inode_unpacked *src_dir_u, | |
175 | u64 dst_dir, struct bch_inode_unpacked *dst_dir_u, | |
176 | struct bch_inode_unpacked *src_inode_u, | |
177 | struct bch_inode_unpacked *dst_inode_u, | |
178 | const struct qstr *src_name, | |
179 | const struct qstr *dst_name, | |
180 | enum bch_rename_mode mode) | |
181 | { | |
182 | struct btree_iter *src_dir_iter, *dst_dir_iter = NULL; | |
183 | struct btree_iter *src_inode_iter, *dst_inode_iter = NULL; | |
184 | struct bch_hash_info src_hash, dst_hash; | |
185 | u64 src_inode, dst_inode, now = bch2_current_time(trans->c); | |
186 | int ret; | |
187 | ||
188 | src_dir_iter = bch2_inode_peek(trans, src_dir_u, src_dir, | |
189 | BTREE_ITER_INTENT); | |
190 | if (IS_ERR(src_dir_iter)) | |
191 | return PTR_ERR(src_dir_iter); | |
192 | ||
193 | src_hash = bch2_hash_info_init(trans->c, src_dir_u); | |
194 | ||
195 | if (dst_dir != src_dir) { | |
196 | dst_dir_iter = bch2_inode_peek(trans, dst_dir_u, dst_dir, | |
197 | BTREE_ITER_INTENT); | |
198 | if (IS_ERR(dst_dir_iter)) | |
199 | return PTR_ERR(dst_dir_iter); | |
200 | ||
201 | dst_hash = bch2_hash_info_init(trans->c, dst_dir_u); | |
202 | } else { | |
203 | dst_dir_u = src_dir_u; | |
204 | dst_hash = src_hash; | |
205 | } | |
206 | ||
207 | ret = bch2_dirent_rename(trans, | |
208 | src_dir, &src_hash, | |
209 | dst_dir, &dst_hash, | |
210 | src_name, &src_inode, | |
211 | dst_name, &dst_inode, | |
212 | mode); | |
213 | if (ret) | |
214 | return ret; | |
215 | ||
216 | src_inode_iter = bch2_inode_peek(trans, src_inode_u, src_inode, | |
217 | BTREE_ITER_INTENT); | |
218 | if (IS_ERR(src_inode_iter)) | |
219 | return PTR_ERR(src_inode_iter); | |
220 | ||
221 | if (dst_inode) { | |
222 | dst_inode_iter = bch2_inode_peek(trans, dst_inode_u, dst_inode, | |
223 | BTREE_ITER_INTENT); | |
224 | if (IS_ERR(dst_inode_iter)) | |
225 | return PTR_ERR(dst_inode_iter); | |
226 | } | |
227 | ||
228 | if (mode == BCH_RENAME_OVERWRITE) { | |
229 | if (S_ISDIR(src_inode_u->bi_mode) != | |
230 | S_ISDIR(dst_inode_u->bi_mode)) | |
231 | return -ENOTDIR; | |
232 | ||
233 | if (S_ISDIR(dst_inode_u->bi_mode) && | |
234 | bch2_empty_dir_trans(trans, dst_inode)) | |
235 | return -ENOTEMPTY; | |
236 | } | |
237 | ||
238 | if (bch2_reinherit_attrs(src_inode_u, dst_dir_u) && | |
239 | S_ISDIR(src_inode_u->bi_mode)) | |
240 | return -EXDEV; | |
241 | ||
242 | if (mode == BCH_RENAME_EXCHANGE && | |
243 | bch2_reinherit_attrs(dst_inode_u, src_dir_u) && | |
244 | S_ISDIR(dst_inode_u->bi_mode)) | |
245 | return -EXDEV; | |
246 | ||
247 | if (S_ISDIR(src_inode_u->bi_mode)) { | |
248 | src_dir_u->bi_nlink--; | |
249 | dst_dir_u->bi_nlink++; | |
250 | } | |
251 | ||
252 | if (dst_inode && S_ISDIR(dst_inode_u->bi_mode)) { | |
253 | dst_dir_u->bi_nlink--; | |
254 | src_dir_u->bi_nlink += mode == BCH_RENAME_EXCHANGE; | |
255 | } | |
256 | ||
257 | if (mode == BCH_RENAME_OVERWRITE) | |
258 | bch2_inode_nlink_dec(dst_inode_u); | |
259 | ||
260 | src_dir_u->bi_mtime = now; | |
261 | src_dir_u->bi_ctime = now; | |
262 | ||
263 | if (src_dir != dst_dir) { | |
264 | dst_dir_u->bi_mtime = now; | |
265 | dst_dir_u->bi_ctime = now; | |
266 | } | |
267 | ||
268 | src_inode_u->bi_ctime = now; | |
269 | ||
270 | if (dst_inode) | |
271 | dst_inode_u->bi_ctime = now; | |
272 | ||
273 | return bch2_inode_write(trans, src_dir_iter, src_dir_u) ?: | |
274 | (src_dir != dst_dir | |
275 | ? bch2_inode_write(trans, dst_dir_iter, dst_dir_u) | |
276 | : 0 ) ?: | |
277 | bch2_inode_write(trans, src_inode_iter, src_inode_u) ?: | |
278 | (dst_inode | |
279 | ? bch2_inode_write(trans, dst_inode_iter, dst_inode_u) | |
280 | : 0 ); | |
281 | } |