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