]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - fs/vboxsf/utils.c
afs: Fix updating of i_mode due to 3rd party change
[mirror_ubuntu-jammy-kernel.git] / fs / vboxsf / utils.c
CommitLineData
0fd16957
HG
1// SPDX-License-Identifier: MIT
2/*
3 * VirtualBox Guest Shared Folders support: Utility functions.
4 * Mainly conversion from/to VirtualBox/Linux data structures.
5 *
6 * Copyright (C) 2006-2018 Oracle Corporation
7 */
8
9#include <linux/namei.h>
10#include <linux/nls.h>
11#include <linux/sizes.h>
12#include <linux/vfs.h>
13#include "vfsmod.h"
14
15struct inode *vboxsf_new_inode(struct super_block *sb)
16{
17 struct vboxsf_sbi *sbi = VBOXSF_SBI(sb);
18 struct inode *inode;
19 unsigned long flags;
20 int cursor, ret;
21 u32 gen;
22
23 inode = new_inode(sb);
24 if (!inode)
25 return ERR_PTR(-ENOMEM);
26
27 idr_preload(GFP_KERNEL);
28 spin_lock_irqsave(&sbi->ino_idr_lock, flags);
29 cursor = idr_get_cursor(&sbi->ino_idr);
30 ret = idr_alloc_cyclic(&sbi->ino_idr, inode, 1, 0, GFP_ATOMIC);
31 if (ret >= 0 && ret < cursor)
32 sbi->next_generation++;
33 gen = sbi->next_generation;
34 spin_unlock_irqrestore(&sbi->ino_idr_lock, flags);
35 idr_preload_end();
36
37 if (ret < 0) {
38 iput(inode);
39 return ERR_PTR(ret);
40 }
41
42 inode->i_ino = ret;
43 inode->i_generation = gen;
44 return inode;
45}
46
47/* set [inode] attributes based on [info], uid/gid based on [sbi] */
48void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
49 const struct shfl_fsobjinfo *info)
50{
51 const struct shfl_fsobjattr *attr;
52 s64 allocated;
53 int mode;
54
55 attr = &info->attr;
56
57#define mode_set(r) ((attr->mode & (SHFL_UNIX_##r)) ? (S_##r) : 0)
58
59 mode = mode_set(IRUSR);
60 mode |= mode_set(IWUSR);
61 mode |= mode_set(IXUSR);
62
63 mode |= mode_set(IRGRP);
64 mode |= mode_set(IWGRP);
65 mode |= mode_set(IXGRP);
66
67 mode |= mode_set(IROTH);
68 mode |= mode_set(IWOTH);
69 mode |= mode_set(IXOTH);
70
71#undef mode_set
72
73 /* We use the host-side values for these */
74 inode->i_flags |= S_NOATIME | S_NOCMTIME;
75 inode->i_mapping->a_ops = &vboxsf_reg_aops;
76
77 if (SHFL_IS_DIRECTORY(attr->mode)) {
78 inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode;
79 inode->i_mode &= ~sbi->o.dmask;
80 inode->i_mode |= S_IFDIR;
81 inode->i_op = &vboxsf_dir_iops;
82 inode->i_fop = &vboxsf_dir_fops;
83 /*
84 * XXX: this probably should be set to the number of entries
85 * in the directory plus two (. ..)
86 */
87 set_nlink(inode, 1);
88 } else if (SHFL_IS_SYMLINK(attr->mode)) {
89 inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode;
90 inode->i_mode &= ~sbi->o.fmask;
91 inode->i_mode |= S_IFLNK;
92 inode->i_op = &vboxsf_lnk_iops;
93 set_nlink(inode, 1);
94 } else {
95 inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode;
96 inode->i_mode &= ~sbi->o.fmask;
97 inode->i_mode |= S_IFREG;
98 inode->i_op = &vboxsf_reg_iops;
99 inode->i_fop = &vboxsf_reg_fops;
100 set_nlink(inode, 1);
101 }
102
103 inode->i_uid = sbi->o.uid;
104 inode->i_gid = sbi->o.gid;
105
106 inode->i_size = info->size;
107 inode->i_blkbits = 12;
108 /* i_blocks always in units of 512 bytes! */
109 allocated = info->allocated + 511;
110 do_div(allocated, 512);
111 inode->i_blocks = allocated;
112
113 inode->i_atime = ns_to_timespec64(
114 info->access_time.ns_relative_to_unix_epoch);
115 inode->i_ctime = ns_to_timespec64(
116 info->change_time.ns_relative_to_unix_epoch);
117 inode->i_mtime = ns_to_timespec64(
118 info->modification_time.ns_relative_to_unix_epoch);
119}
120
121int vboxsf_create_at_dentry(struct dentry *dentry,
122 struct shfl_createparms *params)
123{
124 struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
125 struct shfl_string *path;
126 int err;
127
128 path = vboxsf_path_from_dentry(sbi, dentry);
129 if (IS_ERR(path))
130 return PTR_ERR(path);
131
132 err = vboxsf_create(sbi->root, path, params);
133 __putname(path);
134
135 return err;
136}
137
138int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path,
139 struct shfl_fsobjinfo *info)
140{
141 struct shfl_createparms params = {};
142 int err;
143
144 params.handle = SHFL_HANDLE_NIL;
145 params.create_flags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
146
147 err = vboxsf_create(sbi->root, path, &params);
148 if (err)
149 return err;
150
151 if (params.result != SHFL_FILE_EXISTS)
152 return -ENOENT;
153
154 if (info)
155 *info = params.info;
156
157 return 0;
158}
159
160int vboxsf_stat_dentry(struct dentry *dentry, struct shfl_fsobjinfo *info)
161{
162 struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
163 struct shfl_string *path;
164 int err;
165
166 path = vboxsf_path_from_dentry(sbi, dentry);
167 if (IS_ERR(path))
168 return PTR_ERR(path);
169
170 err = vboxsf_stat(sbi, path, info);
171 __putname(path);
172 return err;
173}
174
175int vboxsf_inode_revalidate(struct dentry *dentry)
176{
177 struct vboxsf_sbi *sbi;
178 struct vboxsf_inode *sf_i;
179 struct shfl_fsobjinfo info;
180 struct timespec64 prev_mtime;
181 struct inode *inode;
182 int err;
183
184 if (!dentry || !d_really_is_positive(dentry))
185 return -EINVAL;
186
187 inode = d_inode(dentry);
188 prev_mtime = inode->i_mtime;
189 sf_i = VBOXSF_I(inode);
190 sbi = VBOXSF_SBI(dentry->d_sb);
191 if (!sf_i->force_restat) {
192 if (time_before(jiffies, dentry->d_time + sbi->o.ttl))
193 return 0;
194 }
195
196 err = vboxsf_stat_dentry(dentry, &info);
197 if (err)
198 return err;
199
200 dentry->d_time = jiffies;
201 sf_i->force_restat = 0;
202 vboxsf_init_inode(sbi, inode, &info);
203
204 /*
205 * If the file was changed on the host side we need to invalidate the
206 * page-cache for it. Note this also gets triggered by our own writes,
207 * this is unavoidable.
208 */
209 if (timespec64_compare(&inode->i_mtime, &prev_mtime) > 0)
210 invalidate_inode_pages2(inode->i_mapping);
211
212 return 0;
213}
214
549c7297
CB
215int vboxsf_getattr(struct user_namespace *mnt_userns, const struct path *path,
216 struct kstat *kstat, u32 request_mask, unsigned int flags)
0fd16957
HG
217{
218 int err;
219 struct dentry *dentry = path->dentry;
220 struct inode *inode = d_inode(dentry);
221 struct vboxsf_inode *sf_i = VBOXSF_I(inode);
222
223 switch (flags & AT_STATX_SYNC_TYPE) {
224 case AT_STATX_DONT_SYNC:
225 err = 0;
226 break;
227 case AT_STATX_FORCE_SYNC:
228 sf_i->force_restat = 1;
df561f66 229 fallthrough;
0fd16957
HG
230 default:
231 err = vboxsf_inode_revalidate(dentry);
232 }
233 if (err)
234 return err;
235
0d56a451 236 generic_fillattr(&init_user_ns, d_inode(dentry), kstat);
0fd16957
HG
237 return 0;
238}
239
549c7297
CB
240int vboxsf_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
241 struct iattr *iattr)
0fd16957
HG
242{
243 struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry));
244 struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
245 struct shfl_createparms params = {};
246 struct shfl_fsobjinfo info = {};
247 u32 buf_len;
248 int err;
249
250 params.handle = SHFL_HANDLE_NIL;
251 params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS |
252 SHFL_CF_ACT_FAIL_IF_NEW |
253 SHFL_CF_ACCESS_ATTR_WRITE;
254
255 /* this is at least required for Posix hosts */
256 if (iattr->ia_valid & ATTR_SIZE)
257 params.create_flags |= SHFL_CF_ACCESS_WRITE;
258
259 err = vboxsf_create_at_dentry(dentry, &params);
260 if (err || params.result != SHFL_FILE_EXISTS)
261 return err ? err : -ENOENT;
262
263#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0)
264
265 /*
266 * Setting the file size and setting the other attributes has to
267 * be handled separately.
268 */
269 if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) {
270 if (iattr->ia_valid & ATTR_MODE) {
271 info.attr.mode = mode_set(IRUSR);
272 info.attr.mode |= mode_set(IWUSR);
273 info.attr.mode |= mode_set(IXUSR);
274 info.attr.mode |= mode_set(IRGRP);
275 info.attr.mode |= mode_set(IWGRP);
276 info.attr.mode |= mode_set(IXGRP);
277 info.attr.mode |= mode_set(IROTH);
278 info.attr.mode |= mode_set(IWOTH);
279 info.attr.mode |= mode_set(IXOTH);
280
281 if (iattr->ia_mode & S_IFDIR)
282 info.attr.mode |= SHFL_TYPE_DIRECTORY;
283 else
284 info.attr.mode |= SHFL_TYPE_FILE;
285 }
286
287 if (iattr->ia_valid & ATTR_ATIME)
288 info.access_time.ns_relative_to_unix_epoch =
289 timespec64_to_ns(&iattr->ia_atime);
290
291 if (iattr->ia_valid & ATTR_MTIME)
292 info.modification_time.ns_relative_to_unix_epoch =
293 timespec64_to_ns(&iattr->ia_mtime);
294
295 /*
296 * Ignore ctime (inode change time) as it can't be set
297 * from userland anyway.
298 */
299
300 buf_len = sizeof(info);
301 err = vboxsf_fsinfo(sbi->root, params.handle,
302 SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len,
303 &info);
304 if (err) {
305 vboxsf_close(sbi->root, params.handle);
306 return err;
307 }
308
309 /* the host may have given us different attr then requested */
310 sf_i->force_restat = 1;
311 }
312
313#undef mode_set
314
315 if (iattr->ia_valid & ATTR_SIZE) {
316 memset(&info, 0, sizeof(info));
317 info.size = iattr->ia_size;
318 buf_len = sizeof(info);
319 err = vboxsf_fsinfo(sbi->root, params.handle,
320 SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len,
321 &info);
322 if (err) {
323 vboxsf_close(sbi->root, params.handle);
324 return err;
325 }
326
327 /* the host may have given us different attr then requested */
328 sf_i->force_restat = 1;
329 }
330
331 vboxsf_close(sbi->root, params.handle);
332
333 /* Update the inode with what the host has actually given us. */
334 if (sf_i->force_restat)
335 vboxsf_inode_revalidate(dentry);
336
337 return 0;
338}
339
340/*
341 * [dentry] contains string encoded in coding system that corresponds
342 * to [sbi]->nls, we must convert it to UTF8 here.
343 * Returns a shfl_string allocated through __getname (must be freed using
344 * __putname), or an ERR_PTR on error.
345 */
346struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi,
347 struct dentry *dentry)
348{
349 struct shfl_string *shfl_path;
350 int path_len, out_len, nb;
351 char *buf, *path;
352 wchar_t uni;
353 u8 *out;
354
355 buf = __getname();
356 if (!buf)
357 return ERR_PTR(-ENOMEM);
358
359 path = dentry_path_raw(dentry, buf, PATH_MAX);
360 if (IS_ERR(path)) {
361 __putname(buf);
362 return ERR_CAST(path);
363 }
364 path_len = strlen(path);
365
366 if (sbi->nls) {
367 shfl_path = __getname();
368 if (!shfl_path) {
369 __putname(buf);
370 return ERR_PTR(-ENOMEM);
371 }
372
373 out = shfl_path->string.utf8;
374 out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1;
375
376 while (path_len) {
377 nb = sbi->nls->char2uni(path, path_len, &uni);
378 if (nb < 0) {
379 __putname(shfl_path);
380 __putname(buf);
381 return ERR_PTR(-EINVAL);
382 }
383 path += nb;
384 path_len -= nb;
385
386 nb = utf32_to_utf8(uni, out, out_len);
387 if (nb < 0) {
388 __putname(shfl_path);
389 __putname(buf);
390 return ERR_PTR(-ENAMETOOLONG);
391 }
392 out += nb;
393 out_len -= nb;
394 }
395 *out = 0;
396 shfl_path->length = out - shfl_path->string.utf8;
397 shfl_path->size = shfl_path->length + 1;
398 __putname(buf);
399 } else {
400 if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) {
401 __putname(buf);
402 return ERR_PTR(-ENAMETOOLONG);
403 }
404 /*
405 * dentry_path stores the name at the end of buf, but the
406 * shfl_string string we return must be properly aligned.
407 */
408 shfl_path = (struct shfl_string *)buf;
409 memmove(shfl_path->string.utf8, path, path_len);
410 shfl_path->string.utf8[path_len] = 0;
411 shfl_path->length = path_len;
412 shfl_path->size = path_len + 1;
413 }
414
415 return shfl_path;
416}
417
418int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len,
419 const unsigned char *utf8_name, size_t utf8_len)
420{
421 const char *in;
422 char *out;
423 size_t out_len;
424 size_t out_bound_len;
425 size_t in_bound_len;
426
427 in = utf8_name;
428 in_bound_len = utf8_len;
429
430 out = name;
431 out_len = 0;
432 /* Reserve space for terminating 0 */
433 out_bound_len = name_bound_len - 1;
434
435 while (in_bound_len) {
436 int nb;
437 unicode_t uni;
438
439 nb = utf8_to_utf32(in, in_bound_len, &uni);
440 if (nb < 0)
441 return -EINVAL;
442
443 in += nb;
444 in_bound_len -= nb;
445
446 nb = sbi->nls->uni2char(uni, out, out_bound_len);
447 if (nb < 0)
448 return nb;
449
450 out += nb;
451 out_bound_len -= nb;
452 out_len += nb;
453 }
454
455 *out = 0;
456
457 return 0;
458}
459
460static struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list)
461{
462 struct vboxsf_dir_buf *b;
463
464 b = kmalloc(sizeof(*b), GFP_KERNEL);
465 if (!b)
466 return NULL;
467
468 b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
469 if (!b->buf) {
470 kfree(b);
471 return NULL;
472 }
473
474 b->entries = 0;
475 b->used = 0;
476 b->free = DIR_BUFFER_SIZE;
477 list_add(&b->head, list);
478
479 return b;
480}
481
482static void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b)
483{
484 list_del(&b->head);
485 kfree(b->buf);
486 kfree(b);
487}
488
489struct vboxsf_dir_info *vboxsf_dir_info_alloc(void)
490{
491 struct vboxsf_dir_info *p;
492
493 p = kmalloc(sizeof(*p), GFP_KERNEL);
494 if (!p)
495 return NULL;
496
497 INIT_LIST_HEAD(&p->info_list);
498 return p;
499}
500
501void vboxsf_dir_info_free(struct vboxsf_dir_info *p)
502{
503 struct list_head *list, *pos, *tmp;
504
505 list = &p->info_list;
506 list_for_each_safe(pos, tmp, list) {
507 struct vboxsf_dir_buf *b;
508
509 b = list_entry(pos, struct vboxsf_dir_buf, head);
510 vboxsf_dir_buf_free(b);
511 }
512 kfree(p);
513}
514
515int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
516 u64 handle)
517{
518 struct vboxsf_dir_buf *b;
519 u32 entries, size;
520 int err = 0;
521 void *buf;
522
523 /* vboxsf_dirinfo returns 1 on end of dir */
524 while (err == 0) {
525 b = vboxsf_dir_buf_alloc(&sf_d->info_list);
526 if (!b) {
527 err = -ENOMEM;
528 break;
529 }
530
531 buf = b->buf;
532 size = b->free;
533
534 err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0,
535 &size, buf, &entries);
536 if (err < 0)
537 break;
538
539 b->entries += entries;
540 b->free -= size;
541 b->used += size;
542 }
543
544 if (b && b->used == 0)
545 vboxsf_dir_buf_free(b);
546
547 /* -EILSEQ means the host could not translate a filename, ignore */
548 if (err > 0 || err == -EILSEQ)
549 err = 0;
550
551 return err;
552}