Commit | Line | Data |
---|---|---|
4342306f KK |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * | |
4 | * Copyright (C) 2019-2021 Paragon Software GmbH, All rights reserved. | |
5 | * | |
6 | */ | |
7 | ||
4342306f | 8 | #include <linux/fs.h> |
4342306f KK |
9 | #include <linux/nls.h> |
10 | ||
11 | #include "debug.h" | |
12 | #include "ntfs.h" | |
13 | #include "ntfs_fs.h" | |
14 | ||
15 | /* | |
e8b8e97f | 16 | * fill_name_de - Format NTFS_DE in @buf. |
4342306f KK |
17 | */ |
18 | int fill_name_de(struct ntfs_sb_info *sbi, void *buf, const struct qstr *name, | |
19 | const struct cpu_str *uni) | |
20 | { | |
21 | int err; | |
22 | struct NTFS_DE *e = buf; | |
23 | u16 data_size; | |
24 | struct ATTR_FILE_NAME *fname = (struct ATTR_FILE_NAME *)(e + 1); | |
25 | ||
26 | #ifndef CONFIG_NTFS3_64BIT_CLUSTER | |
27 | e->ref.high = fname->home.high = 0; | |
28 | #endif | |
29 | if (uni) { | |
30 | #ifdef __BIG_ENDIAN | |
31 | int ulen = uni->len; | |
32 | __le16 *uname = fname->name; | |
33 | const u16 *name_cpu = uni->name; | |
34 | ||
35 | while (ulen--) | |
36 | *uname++ = cpu_to_le16(*name_cpu++); | |
37 | #else | |
38 | memcpy(fname->name, uni->name, uni->len * sizeof(u16)); | |
39 | #endif | |
40 | fname->name_len = uni->len; | |
41 | ||
42 | } else { | |
e8b8e97f | 43 | /* Convert input string to unicode. */ |
4342306f KK |
44 | err = ntfs_nls_to_utf16(sbi, name->name, name->len, |
45 | (struct cpu_str *)&fname->name_len, | |
46 | NTFS_NAME_LEN, UTF16_LITTLE_ENDIAN); | |
47 | if (err < 0) | |
48 | return err; | |
49 | } | |
50 | ||
51 | fname->type = FILE_NAME_POSIX; | |
52 | data_size = fname_full_size(fname); | |
53 | ||
fa3cacf5 | 54 | e->size = cpu_to_le16(ALIGN(data_size, 8) + sizeof(struct NTFS_DE)); |
4342306f KK |
55 | e->key_size = cpu_to_le16(data_size); |
56 | e->flags = 0; | |
57 | e->res = 0; | |
58 | ||
59 | return 0; | |
60 | } | |
61 | ||
62 | /* | |
e8b8e97f | 63 | * ntfs_lookup - inode_operations::lookup |
4342306f KK |
64 | */ |
65 | static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *dentry, | |
66 | u32 flags) | |
67 | { | |
68 | struct ntfs_inode *ni = ntfs_i(dir); | |
69 | struct cpu_str *uni = __getname(); | |
70 | struct inode *inode; | |
71 | int err; | |
72 | ||
73 | if (!uni) | |
74 | inode = ERR_PTR(-ENOMEM); | |
75 | else { | |
76 | err = ntfs_nls_to_utf16(ni->mi.sbi, dentry->d_name.name, | |
77 | dentry->d_name.len, uni, NTFS_NAME_LEN, | |
78 | UTF16_HOST_ENDIAN); | |
79 | if (err < 0) | |
80 | inode = ERR_PTR(err); | |
81 | else { | |
82 | ni_lock(ni); | |
83 | inode = dir_search_u(dir, uni, NULL); | |
84 | ni_unlock(ni); | |
85 | } | |
86 | __putname(uni); | |
87 | } | |
88 | ||
89 | return d_splice_alias(inode, dentry); | |
90 | } | |
91 | ||
92 | /* | |
e8b8e97f | 93 | * ntfs_create - inode_operations::create |
4342306f KK |
94 | */ |
95 | static int ntfs_create(struct user_namespace *mnt_userns, struct inode *dir, | |
96 | struct dentry *dentry, umode_t mode, bool excl) | |
97 | { | |
4342306f KK |
98 | struct inode *inode; |
99 | ||
4342306f KK |
100 | inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFREG | mode, |
101 | 0, NULL, 0, NULL); | |
102 | ||
4342306f KK |
103 | return IS_ERR(inode) ? PTR_ERR(inode) : 0; |
104 | } | |
105 | ||
106 | /* | |
107 | * ntfs_mknod | |
108 | * | |
109 | * inode_operations::mknod | |
110 | */ | |
111 | static int ntfs_mknod(struct user_namespace *mnt_userns, struct inode *dir, | |
112 | struct dentry *dentry, umode_t mode, dev_t rdev) | |
113 | { | |
4342306f KK |
114 | struct inode *inode; |
115 | ||
4342306f KK |
116 | inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, mode, rdev, |
117 | NULL, 0, NULL); | |
118 | ||
4342306f KK |
119 | return IS_ERR(inode) ? PTR_ERR(inode) : 0; |
120 | } | |
121 | ||
122 | /* | |
e8b8e97f | 123 | * ntfs_link - inode_operations::link |
4342306f KK |
124 | */ |
125 | static int ntfs_link(struct dentry *ode, struct inode *dir, struct dentry *de) | |
126 | { | |
127 | int err; | |
128 | struct inode *inode = d_inode(ode); | |
129 | struct ntfs_inode *ni = ntfs_i(inode); | |
130 | ||
131 | if (S_ISDIR(inode->i_mode)) | |
132 | return -EPERM; | |
133 | ||
134 | if (inode->i_nlink >= NTFS_LINK_MAX) | |
135 | return -EMLINK; | |
136 | ||
137 | ni_lock_dir(ntfs_i(dir)); | |
138 | if (inode != dir) | |
139 | ni_lock(ni); | |
140 | ||
4342306f KK |
141 | inc_nlink(inode); |
142 | ihold(inode); | |
143 | ||
144 | err = ntfs_link_inode(inode, de); | |
78ab59fe | 145 | |
4342306f | 146 | if (!err) { |
78ab59fe KK |
147 | dir->i_ctime = dir->i_mtime = inode->i_ctime = |
148 | current_time(dir); | |
4342306f KK |
149 | mark_inode_dirty(inode); |
150 | mark_inode_dirty(dir); | |
151 | d_instantiate(de, inode); | |
152 | } else { | |
153 | drop_nlink(inode); | |
154 | iput(inode); | |
155 | } | |
156 | ||
157 | if (inode != dir) | |
158 | ni_unlock(ni); | |
159 | ni_unlock(ntfs_i(dir)); | |
160 | ||
161 | return err; | |
162 | } | |
163 | ||
164 | /* | |
e8b8e97f | 165 | * ntfs_unlink - inode_operations::unlink |
4342306f KK |
166 | */ |
167 | static int ntfs_unlink(struct inode *dir, struct dentry *dentry) | |
168 | { | |
169 | struct ntfs_inode *ni = ntfs_i(dir); | |
170 | int err; | |
171 | ||
172 | ni_lock_dir(ni); | |
173 | ||
174 | err = ntfs_unlink_inode(dir, dentry); | |
175 | ||
176 | ni_unlock(ni); | |
177 | ||
178 | return err; | |
179 | } | |
180 | ||
181 | /* | |
e8b8e97f | 182 | * ntfs_symlink - inode_operations::symlink |
4342306f KK |
183 | */ |
184 | static int ntfs_symlink(struct user_namespace *mnt_userns, struct inode *dir, | |
185 | struct dentry *dentry, const char *symname) | |
186 | { | |
187 | u32 size = strlen(symname); | |
188 | struct inode *inode; | |
4342306f KK |
189 | |
190 | inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFLNK | 0777, | |
191 | 0, symname, size, NULL); | |
192 | ||
4342306f KK |
193 | return IS_ERR(inode) ? PTR_ERR(inode) : 0; |
194 | } | |
195 | ||
196 | /* | |
e8b8e97f | 197 | * ntfs_mkdir- inode_operations::mkdir |
4342306f KK |
198 | */ |
199 | static int ntfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir, | |
200 | struct dentry *dentry, umode_t mode) | |
201 | { | |
202 | struct inode *inode; | |
4342306f KK |
203 | |
204 | inode = ntfs_create_inode(mnt_userns, dir, dentry, NULL, S_IFDIR | mode, | |
205 | 0, NULL, 0, NULL); | |
206 | ||
4342306f KK |
207 | return IS_ERR(inode) ? PTR_ERR(inode) : 0; |
208 | } | |
209 | ||
210 | /* | |
e8b8e97f | 211 | * ntfs_rmdir - inode_operations::rm_dir |
4342306f KK |
212 | */ |
213 | static int ntfs_rmdir(struct inode *dir, struct dentry *dentry) | |
214 | { | |
215 | struct ntfs_inode *ni = ntfs_i(dir); | |
216 | int err; | |
217 | ||
218 | ni_lock_dir(ni); | |
219 | ||
220 | err = ntfs_unlink_inode(dir, dentry); | |
221 | ||
222 | ni_unlock(ni); | |
223 | ||
224 | return err; | |
225 | } | |
226 | ||
227 | /* | |
e8b8e97f | 228 | * ntfs_rename - inode_operations::rename |
4342306f | 229 | */ |
78ab59fe KK |
230 | static int ntfs_rename(struct user_namespace *mnt_userns, struct inode *dir, |
231 | struct dentry *dentry, struct inode *new_dir, | |
4342306f KK |
232 | struct dentry *new_dentry, u32 flags) |
233 | { | |
234 | int err; | |
78ab59fe | 235 | struct super_block *sb = dir->i_sb; |
4342306f | 236 | struct ntfs_sb_info *sbi = sb->s_fs_info; |
78ab59fe | 237 | struct ntfs_inode *dir_ni = ntfs_i(dir); |
4342306f | 238 | struct ntfs_inode *new_dir_ni = ntfs_i(new_dir); |
78ab59fe KK |
239 | struct inode *inode = d_inode(dentry); |
240 | struct ntfs_inode *ni = ntfs_i(inode); | |
241 | struct inode *new_inode = d_inode(new_dentry); | |
242 | struct NTFS_DE *de, *new_de; | |
243 | bool is_same, is_bad; | |
244 | /* | |
245 | * de - memory of PATH_MAX bytes: | |
246 | * [0-1024) - original name (dentry->d_name) | |
247 | * [1024-2048) - paired to original name, usually DOS variant of dentry->d_name | |
248 | * [2048-3072) - new name (new_dentry->d_name) | |
249 | */ | |
4342306f KK |
250 | static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + SIZEOF_RESIDENT < 1024); |
251 | static_assert(SIZEOF_ATTRIBUTE_FILENAME_MAX + sizeof(struct NTFS_DE) < | |
252 | 1024); | |
253 | static_assert(PATH_MAX >= 4 * 1024); | |
254 | ||
255 | if (flags & ~RENAME_NOREPLACE) | |
256 | return -EINVAL; | |
257 | ||
78ab59fe KK |
258 | is_same = dentry->d_name.len == new_dentry->d_name.len && |
259 | !memcmp(dentry->d_name.name, new_dentry->d_name.name, | |
260 | dentry->d_name.len); | |
4342306f | 261 | |
78ab59fe | 262 | if (is_same && dir == new_dir) { |
e8b8e97f | 263 | /* Nothing to do. */ |
78ab59fe | 264 | return 0; |
4342306f KK |
265 | } |
266 | ||
78ab59fe KK |
267 | if (ntfs_is_meta_file(sbi, inode->i_ino)) { |
268 | /* Should we print an error? */ | |
269 | return -EINVAL; | |
4342306f KK |
270 | } |
271 | ||
272 | if (new_inode) { | |
e8b8e97f | 273 | /* Target name exists. Unlink it. */ |
4342306f KK |
274 | dget(new_dentry); |
275 | ni_lock_dir(new_dir_ni); | |
276 | err = ntfs_unlink_inode(new_dir, new_dentry); | |
277 | ni_unlock(new_dir_ni); | |
278 | dput(new_dentry); | |
279 | if (err) | |
78ab59fe | 280 | return err; |
4342306f KK |
281 | } |
282 | ||
e8b8e97f | 283 | /* Allocate PATH_MAX bytes. */ |
78ab59fe KK |
284 | de = __getname(); |
285 | if (!de) | |
286 | return -ENOMEM; | |
4342306f | 287 | |
78ab59fe KK |
288 | /* Translate dentry->d_name into unicode form. */ |
289 | err = fill_name_de(sbi, de, &dentry->d_name, NULL); | |
4342306f | 290 | if (err < 0) |
78ab59fe | 291 | goto out; |
4342306f KK |
292 | |
293 | if (is_same) { | |
78ab59fe KK |
294 | /* Reuse 'de'. */ |
295 | new_de = de; | |
4342306f | 296 | } else { |
78ab59fe KK |
297 | /* Translate new_dentry->d_name into unicode form. */ |
298 | new_de = Add2Ptr(de, 2048); | |
4342306f KK |
299 | err = fill_name_de(sbi, new_de, &new_dentry->d_name, NULL); |
300 | if (err < 0) | |
78ab59fe | 301 | goto out; |
4342306f KK |
302 | } |
303 | ||
78ab59fe KK |
304 | ni_lock_dir(dir_ni); |
305 | ni_lock(ni); | |
306 | ||
307 | is_bad = false; | |
308 | err = ni_rename(dir_ni, new_dir_ni, ni, de, new_de, &is_bad); | |
309 | if (is_bad) { | |
310 | /* Restore after failed rename failed too. */ | |
311 | make_bad_inode(inode); | |
312 | ntfs_inode_err(inode, "failed to undo rename"); | |
313 | ntfs_set_state(sbi, NTFS_DIRTY_ERROR); | |
314 | } else if (!err) { | |
315 | inode->i_ctime = dir->i_ctime = dir->i_mtime = | |
316 | current_time(dir); | |
317 | mark_inode_dirty(inode); | |
318 | mark_inode_dirty(dir); | |
319 | if (dir != new_dir) { | |
320 | new_dir->i_mtime = new_dir->i_ctime = dir->i_ctime; | |
321 | mark_inode_dirty(new_dir); | |
4342306f | 322 | } |
4342306f | 323 | |
78ab59fe KK |
324 | if (IS_DIRSYNC(dir)) |
325 | ntfs_sync_inode(dir); | |
4342306f | 326 | |
78ab59fe KK |
327 | if (IS_DIRSYNC(new_dir)) |
328 | ntfs_sync_inode(inode); | |
4342306f KK |
329 | } |
330 | ||
78ab59fe KK |
331 | ni_unlock(ni); |
332 | ni_unlock(dir_ni); | |
4342306f | 333 | out: |
78ab59fe | 334 | __putname(de); |
4342306f KK |
335 | return err; |
336 | } | |
337 | ||
338 | struct dentry *ntfs3_get_parent(struct dentry *child) | |
339 | { | |
340 | struct inode *inode = d_inode(child); | |
341 | struct ntfs_inode *ni = ntfs_i(inode); | |
342 | ||
343 | struct ATTR_LIST_ENTRY *le = NULL; | |
344 | struct ATTRIB *attr = NULL; | |
345 | struct ATTR_FILE_NAME *fname; | |
346 | ||
347 | while ((attr = ni_find_attr(ni, attr, &le, ATTR_NAME, NULL, 0, NULL, | |
348 | NULL))) { | |
349 | fname = resident_data_ex(attr, SIZEOF_ATTRIBUTE_FILENAME); | |
350 | if (!fname) | |
351 | continue; | |
352 | ||
353 | return d_obtain_alias( | |
354 | ntfs_iget5(inode->i_sb, &fname->home, NULL)); | |
355 | } | |
356 | ||
357 | return ERR_PTR(-ENOENT); | |
358 | } | |
359 | ||
360 | // clang-format off | |
361 | const struct inode_operations ntfs_dir_inode_operations = { | |
362 | .lookup = ntfs_lookup, | |
363 | .create = ntfs_create, | |
364 | .link = ntfs_link, | |
365 | .unlink = ntfs_unlink, | |
366 | .symlink = ntfs_symlink, | |
367 | .mkdir = ntfs_mkdir, | |
368 | .rmdir = ntfs_rmdir, | |
369 | .mknod = ntfs_mknod, | |
370 | .rename = ntfs_rename, | |
371 | .permission = ntfs_permission, | |
372 | .get_acl = ntfs_get_acl, | |
373 | .set_acl = ntfs_set_acl, | |
374 | .setattr = ntfs3_setattr, | |
375 | .getattr = ntfs_getattr, | |
376 | .listxattr = ntfs_listxattr, | |
377 | .fiemap = ntfs_fiemap, | |
378 | }; | |
379 | ||
380 | const struct inode_operations ntfs_special_inode_operations = { | |
381 | .setattr = ntfs3_setattr, | |
382 | .getattr = ntfs_getattr, | |
383 | .listxattr = ntfs_listxattr, | |
384 | .get_acl = ntfs_get_acl, | |
385 | .set_acl = ntfs_set_acl, | |
386 | }; | |
387 | // clang-format on |