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