xref: /openbmc/linux/fs/vboxsf/utils.c (revision 3a35093a)
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 
15 struct 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] */
48 void 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 
121 int 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 
138 int 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 
160 int 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 
175 int 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 
215 int vboxsf_getattr(const struct path *path, struct kstat *kstat,
216 		   u32 request_mask, unsigned int flags)
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;
229 		fallthrough;
230 	default:
231 		err = vboxsf_inode_revalidate(dentry);
232 	}
233 	if (err)
234 		return err;
235 
236 	generic_fillattr(d_inode(dentry), kstat);
237 	return 0;
238 }
239 
240 int vboxsf_setattr(struct dentry *dentry, struct iattr *iattr)
241 {
242 	struct vboxsf_inode *sf_i = VBOXSF_I(d_inode(dentry));
243 	struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
244 	struct shfl_createparms params = {};
245 	struct shfl_fsobjinfo info = {};
246 	u32 buf_len;
247 	int err;
248 
249 	params.handle = SHFL_HANDLE_NIL;
250 	params.create_flags = SHFL_CF_ACT_OPEN_IF_EXISTS |
251 			      SHFL_CF_ACT_FAIL_IF_NEW |
252 			      SHFL_CF_ACCESS_ATTR_WRITE;
253 
254 	/* this is at least required for Posix hosts */
255 	if (iattr->ia_valid & ATTR_SIZE)
256 		params.create_flags |= SHFL_CF_ACCESS_WRITE;
257 
258 	err = vboxsf_create_at_dentry(dentry, &params);
259 	if (err || params.result != SHFL_FILE_EXISTS)
260 		return err ? err : -ENOENT;
261 
262 #define mode_set(r) ((iattr->ia_mode & (S_##r)) ? SHFL_UNIX_##r : 0)
263 
264 	/*
265 	 * Setting the file size and setting the other attributes has to
266 	 * be handled separately.
267 	 */
268 	if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) {
269 		if (iattr->ia_valid & ATTR_MODE) {
270 			info.attr.mode = mode_set(IRUSR);
271 			info.attr.mode |= mode_set(IWUSR);
272 			info.attr.mode |= mode_set(IXUSR);
273 			info.attr.mode |= mode_set(IRGRP);
274 			info.attr.mode |= mode_set(IWGRP);
275 			info.attr.mode |= mode_set(IXGRP);
276 			info.attr.mode |= mode_set(IROTH);
277 			info.attr.mode |= mode_set(IWOTH);
278 			info.attr.mode |= mode_set(IXOTH);
279 
280 			if (iattr->ia_mode & S_IFDIR)
281 				info.attr.mode |= SHFL_TYPE_DIRECTORY;
282 			else
283 				info.attr.mode |= SHFL_TYPE_FILE;
284 		}
285 
286 		if (iattr->ia_valid & ATTR_ATIME)
287 			info.access_time.ns_relative_to_unix_epoch =
288 					    timespec64_to_ns(&iattr->ia_atime);
289 
290 		if (iattr->ia_valid & ATTR_MTIME)
291 			info.modification_time.ns_relative_to_unix_epoch =
292 					    timespec64_to_ns(&iattr->ia_mtime);
293 
294 		/*
295 		 * Ignore ctime (inode change time) as it can't be set
296 		 * from userland anyway.
297 		 */
298 
299 		buf_len = sizeof(info);
300 		err = vboxsf_fsinfo(sbi->root, params.handle,
301 				    SHFL_INFO_SET | SHFL_INFO_FILE, &buf_len,
302 				    &info);
303 		if (err) {
304 			vboxsf_close(sbi->root, params.handle);
305 			return err;
306 		}
307 
308 		/* the host may have given us different attr then requested */
309 		sf_i->force_restat = 1;
310 	}
311 
312 #undef mode_set
313 
314 	if (iattr->ia_valid & ATTR_SIZE) {
315 		memset(&info, 0, sizeof(info));
316 		info.size = iattr->ia_size;
317 		buf_len = sizeof(info);
318 		err = vboxsf_fsinfo(sbi->root, params.handle,
319 				    SHFL_INFO_SET | SHFL_INFO_SIZE, &buf_len,
320 				    &info);
321 		if (err) {
322 			vboxsf_close(sbi->root, params.handle);
323 			return err;
324 		}
325 
326 		/* the host may have given us different attr then requested */
327 		sf_i->force_restat = 1;
328 	}
329 
330 	vboxsf_close(sbi->root, params.handle);
331 
332 	/* Update the inode with what the host has actually given us. */
333 	if (sf_i->force_restat)
334 		vboxsf_inode_revalidate(dentry);
335 
336 	return 0;
337 }
338 
339 /*
340  * [dentry] contains string encoded in coding system that corresponds
341  * to [sbi]->nls, we must convert it to UTF8 here.
342  * Returns a shfl_string allocated through __getname (must be freed using
343  * __putname), or an ERR_PTR on error.
344  */
345 struct shfl_string *vboxsf_path_from_dentry(struct vboxsf_sbi *sbi,
346 					    struct dentry *dentry)
347 {
348 	struct shfl_string *shfl_path;
349 	int path_len, out_len, nb;
350 	char *buf, *path;
351 	wchar_t uni;
352 	u8 *out;
353 
354 	buf = __getname();
355 	if (!buf)
356 		return ERR_PTR(-ENOMEM);
357 
358 	path = dentry_path_raw(dentry, buf, PATH_MAX);
359 	if (IS_ERR(path)) {
360 		__putname(buf);
361 		return ERR_CAST(path);
362 	}
363 	path_len = strlen(path);
364 
365 	if (sbi->nls) {
366 		shfl_path = __getname();
367 		if (!shfl_path) {
368 			__putname(buf);
369 			return ERR_PTR(-ENOMEM);
370 		}
371 
372 		out = shfl_path->string.utf8;
373 		out_len = PATH_MAX - SHFLSTRING_HEADER_SIZE - 1;
374 
375 		while (path_len) {
376 			nb = sbi->nls->char2uni(path, path_len, &uni);
377 			if (nb < 0) {
378 				__putname(shfl_path);
379 				__putname(buf);
380 				return ERR_PTR(-EINVAL);
381 			}
382 			path += nb;
383 			path_len -= nb;
384 
385 			nb = utf32_to_utf8(uni, out, out_len);
386 			if (nb < 0) {
387 				__putname(shfl_path);
388 				__putname(buf);
389 				return ERR_PTR(-ENAMETOOLONG);
390 			}
391 			out += nb;
392 			out_len -= nb;
393 		}
394 		*out = 0;
395 		shfl_path->length = out - shfl_path->string.utf8;
396 		shfl_path->size = shfl_path->length + 1;
397 		__putname(buf);
398 	} else {
399 		if ((SHFLSTRING_HEADER_SIZE + path_len + 1) > PATH_MAX) {
400 			__putname(buf);
401 			return ERR_PTR(-ENAMETOOLONG);
402 		}
403 		/*
404 		 * dentry_path stores the name at the end of buf, but the
405 		 * shfl_string string we return must be properly aligned.
406 		 */
407 		shfl_path = (struct shfl_string *)buf;
408 		memmove(shfl_path->string.utf8, path, path_len);
409 		shfl_path->string.utf8[path_len] = 0;
410 		shfl_path->length = path_len;
411 		shfl_path->size = path_len + 1;
412 	}
413 
414 	return shfl_path;
415 }
416 
417 int vboxsf_nlscpy(struct vboxsf_sbi *sbi, char *name, size_t name_bound_len,
418 		  const unsigned char *utf8_name, size_t utf8_len)
419 {
420 	const char *in;
421 	char *out;
422 	size_t out_len;
423 	size_t out_bound_len;
424 	size_t in_bound_len;
425 
426 	in = utf8_name;
427 	in_bound_len = utf8_len;
428 
429 	out = name;
430 	out_len = 0;
431 	/* Reserve space for terminating 0 */
432 	out_bound_len = name_bound_len - 1;
433 
434 	while (in_bound_len) {
435 		int nb;
436 		unicode_t uni;
437 
438 		nb = utf8_to_utf32(in, in_bound_len, &uni);
439 		if (nb < 0)
440 			return -EINVAL;
441 
442 		in += nb;
443 		in_bound_len -= nb;
444 
445 		nb = sbi->nls->uni2char(uni, out, out_bound_len);
446 		if (nb < 0)
447 			return nb;
448 
449 		out += nb;
450 		out_bound_len -= nb;
451 		out_len += nb;
452 	}
453 
454 	*out = 0;
455 
456 	return 0;
457 }
458 
459 static struct vboxsf_dir_buf *vboxsf_dir_buf_alloc(struct list_head *list)
460 {
461 	struct vboxsf_dir_buf *b;
462 
463 	b = kmalloc(sizeof(*b), GFP_KERNEL);
464 	if (!b)
465 		return NULL;
466 
467 	b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
468 	if (!b->buf) {
469 		kfree(b);
470 		return NULL;
471 	}
472 
473 	b->entries = 0;
474 	b->used = 0;
475 	b->free = DIR_BUFFER_SIZE;
476 	list_add(&b->head, list);
477 
478 	return b;
479 }
480 
481 static void vboxsf_dir_buf_free(struct vboxsf_dir_buf *b)
482 {
483 	list_del(&b->head);
484 	kfree(b->buf);
485 	kfree(b);
486 }
487 
488 struct vboxsf_dir_info *vboxsf_dir_info_alloc(void)
489 {
490 	struct vboxsf_dir_info *p;
491 
492 	p = kmalloc(sizeof(*p), GFP_KERNEL);
493 	if (!p)
494 		return NULL;
495 
496 	INIT_LIST_HEAD(&p->info_list);
497 	return p;
498 }
499 
500 void vboxsf_dir_info_free(struct vboxsf_dir_info *p)
501 {
502 	struct list_head *list, *pos, *tmp;
503 
504 	list = &p->info_list;
505 	list_for_each_safe(pos, tmp, list) {
506 		struct vboxsf_dir_buf *b;
507 
508 		b = list_entry(pos, struct vboxsf_dir_buf, head);
509 		vboxsf_dir_buf_free(b);
510 	}
511 	kfree(p);
512 }
513 
514 int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
515 			u64 handle)
516 {
517 	struct vboxsf_dir_buf *b;
518 	u32 entries, size;
519 	int err = 0;
520 	void *buf;
521 
522 	/* vboxsf_dirinfo returns 1 on end of dir */
523 	while (err == 0) {
524 		b = vboxsf_dir_buf_alloc(&sf_d->info_list);
525 		if (!b) {
526 			err = -ENOMEM;
527 			break;
528 		}
529 
530 		buf = b->buf;
531 		size = b->free;
532 
533 		err = vboxsf_dirinfo(sbi->root, handle, NULL, 0, 0,
534 				     &size, buf, &entries);
535 		if (err < 0)
536 			break;
537 
538 		b->entries += entries;
539 		b->free -= size;
540 		b->used += size;
541 	}
542 
543 	if (b && b->used == 0)
544 		vboxsf_dir_buf_free(b);
545 
546 	/* -EILSEQ means the host could not translate a filename, ignore */
547 	if (err > 0 || err == -EILSEQ)
548 		err = 0;
549 
550 	return err;
551 }
552