Linux Audio

Check our new training course

Linux kernel drivers training

May 6-19, 2025
Register
Loading...
Note: File does not exist in v3.1.
  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] */
 48int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
 49		       const struct shfl_fsobjinfo *info, bool reinit)
 50{
 51	const struct shfl_fsobjattr *attr;
 52	s64 allocated;
 53	umode_t 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		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;
 93	} else if (SHFL_IS_SYMLINK(attr->mode)) {
 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;
104	} else {
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;
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);
134	return 0;
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;
218	err = vboxsf_init_inode(sbi, inode, &info, true);
219	if (err)
220		return err;
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
233int vboxsf_getattr(struct user_namespace *mnt_userns, const struct path *path,
234		   struct kstat *kstat, u32 request_mask, unsigned int flags)
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;
247		fallthrough;
248	default:
249		err = vboxsf_inode_revalidate(dentry);
250	}
251	if (err)
252		return err;
253
254	generic_fillattr(&init_user_ns, d_inode(dentry), kstat);
255	return 0;
256}
257
258int vboxsf_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
259		   struct iattr *iattr)
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}