Linux Audio

Check our new training course

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/pagemap.h>
 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] */
 49int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
 50		       const struct shfl_fsobjinfo *info, bool reinit)
 51{
 52	const struct shfl_fsobjattr *attr;
 53	s64 allocated;
 54	umode_t mode;
 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)) {
 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;
 94	} else if (SHFL_IS_SYMLINK(attr->mode)) {
 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;
105	} else {
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;
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);
135	return 0;
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;
219	err = vboxsf_init_inode(sbi, inode, &info, true);
220	if (err)
221		return err;
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
234int vboxsf_getattr(struct user_namespace *mnt_userns, const struct path *path,
235		   struct kstat *kstat, u32 request_mask, unsigned int flags)
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;
248		fallthrough;
249	default:
250		err = vboxsf_inode_revalidate(dentry);
251	}
252	if (err)
253		return err;
254
255	generic_fillattr(&init_user_ns, d_inode(dentry), kstat);
256	return 0;
257}
258
259int vboxsf_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
260		   struct iattr *iattr)
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}