VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/utils.c@ 76458

Last change on this file since 76458 was 76458, checked in by vboxsync, 6 years ago

err.h fixes for linux shared folders. bugref:9344

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/** @file
2 *
3 * vboxsf -- VirtualBox Guest Additions for Linux:
4 * Utility functions.
5 * Mainly conversion from/to VirtualBox/Linux data structures
6 */
7
8/*
9 * Copyright (C) 2006-2018 Oracle Corporation
10 *
11 * Permission is hereby granted, free of charge, to any person
12 * obtaining a copy of this software and associated documentation
13 * files (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use,
15 * copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following
18 * conditions:
19 *
20 * The above copyright notice and this permission notice shall be
21 * included in all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
25 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
30 * OTHER DEALINGS IN THE SOFTWARE.
31 */
32
33#include "vfsmod.h"
34#include <iprt/asm.h>
35#include <iprt/err.h>
36#include <linux/nfs_fs.h>
37#include <linux/vfs.h>
38
39/* #define USE_VMALLOC */
40
41/*
42 * sf_reg_aops and sf_backing_dev_info are just quick implementations to make
43 * sendfile work. For more information have a look at
44 *
45 * http://us1.samba.org/samba/ftp/cifs-cvs/ols2006-fs-tutorial-smf.odp
46 *
47 * and the sample implementation
48 *
49 * http://pserver.samba.org/samba/ftp/cifs-cvs/samplefs.tar.gz
50 */
51
52#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
53static void sf_ftime_from_timespec(time_t * time, RTTIMESPEC * ts)
54{
55 int64_t t = RTTimeSpecGetNano(ts);
56
57 do_div(t, 1000000000);
58 *time = t;
59}
60
61static void sf_timespec_from_ftime(RTTIMESPEC * ts, time_t * time)
62{
63 int64_t t = 1000000000 * *time;
64 RTTimeSpecSetNano(ts, t);
65}
66#else /* >= 2.6.0 */
67#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
68static void sf_ftime_from_timespec(struct timespec *tv, RTTIMESPEC *ts)
69#else
70static void sf_ftime_from_timespec(struct timespec64 *tv, RTTIMESPEC *ts)
71#endif
72{
73 int64_t t = RTTimeSpecGetNano(ts);
74 int64_t nsec;
75
76 nsec = do_div(t, 1000000000);
77 tv->tv_sec = t;
78 tv->tv_nsec = nsec;
79}
80
81#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
82static void sf_timespec_from_ftime(RTTIMESPEC *ts, struct timespec *tv)
83#else
84static void sf_timespec_from_ftime(RTTIMESPEC *ts, struct timespec64 *tv)
85#endif
86{
87 int64_t t = (int64_t) tv->tv_nsec + (int64_t) tv->tv_sec * 1000000000;
88 RTTimeSpecSetNano(ts, t);
89}
90#endif /* >= 2.6.0 */
91
92/* set [inode] attributes based on [info], uid/gid based on [sf_g] */
93void sf_init_inode(struct sf_glob_info *sf_g, struct inode *inode,
94 PSHFLFSOBJINFO info)
95{
96 PSHFLFSOBJATTR attr;
97 int mode;
98
99 TRACE();
100
101 attr = &info->Attr;
102
103#define mode_set(r) attr->fMode & (RTFS_UNIX_##r) ? (S_##r) : 0;
104 mode = mode_set(IRUSR);
105 mode |= mode_set(IWUSR);
106 mode |= mode_set(IXUSR);
107
108 mode |= mode_set(IRGRP);
109 mode |= mode_set(IWGRP);
110 mode |= mode_set(IXGRP);
111
112 mode |= mode_set(IROTH);
113 mode |= mode_set(IWOTH);
114 mode |= mode_set(IXOTH);
115
116#undef mode_set
117
118#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
119 inode->i_mapping->a_ops = &sf_reg_aops;
120#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19, 0)
121 /* XXX Was this ever necessary? */
122 inode->i_mapping->backing_dev_info = &sf_g->bdi;
123#endif
124#endif
125
126 if (RTFS_IS_DIRECTORY(attr->fMode)) {
127 inode->i_mode = sf_g->dmode != ~0 ? (sf_g->dmode & 0777) : mode;
128 inode->i_mode &= ~sf_g->dmask;
129 inode->i_mode |= S_IFDIR;
130 inode->i_op = &sf_dir_iops;
131 inode->i_fop = &sf_dir_fops;
132 /* XXX: this probably should be set to the number of entries
133 in the directory plus two (. ..) */
134#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
135 set_nlink(inode, 1);
136#else
137 inode->i_nlink = 1;
138#endif
139 }
140#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
141 else if (RTFS_IS_SYMLINK(attr->fMode)) {
142 inode->i_mode = sf_g->fmode != ~0 ? (sf_g->fmode & 0777) : mode;
143 inode->i_mode &= ~sf_g->fmask;
144 inode->i_mode |= S_IFLNK;
145 inode->i_op = &sf_lnk_iops;
146#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
147 set_nlink(inode, 1);
148#else
149 inode->i_nlink = 1;
150#endif
151 }
152#endif
153 else {
154 inode->i_mode = sf_g->fmode != ~0 ? (sf_g->fmode & 0777) : mode;
155 inode->i_mode &= ~sf_g->fmask;
156 inode->i_mode |= S_IFREG;
157 inode->i_op = &sf_reg_iops;
158 inode->i_fop = &sf_reg_fops;
159#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 2, 0)
160 set_nlink(inode, 1);
161#else
162 inode->i_nlink = 1;
163#endif
164 }
165
166#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
167 inode->i_uid = make_kuid(current_user_ns(), sf_g->uid);
168 inode->i_gid = make_kgid(current_user_ns(), sf_g->gid);
169#else
170 inode->i_uid = sf_g->uid;
171 inode->i_gid = sf_g->gid;
172#endif
173
174 inode->i_size = info->cbObject;
175#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) && !defined(KERNEL_FC6)
176 inode->i_blksize = 4096;
177#endif
178#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 11)
179 inode->i_blkbits = 12;
180#endif
181 /* i_blocks always in units of 512 bytes! */
182 inode->i_blocks = (info->cbAllocated + 511) / 512;
183
184 sf_ftime_from_timespec(&inode->i_atime, &info->AccessTime);
185 sf_ftime_from_timespec(&inode->i_ctime, &info->ChangeTime);
186 sf_ftime_from_timespec(&inode->i_mtime, &info->ModificationTime);
187}
188
189int sf_stat(const char *caller, struct sf_glob_info *sf_g,
190 SHFLSTRING * path, PSHFLFSOBJINFO result, int ok_to_fail)
191{
192 int rc;
193 SHFLCREATEPARMS params;
194 NOREF(caller);
195
196 TRACE();
197
198 RT_ZERO(params);
199 params.Handle = SHFL_HANDLE_NIL;
200 params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
201 LogFunc(("sf_stat: calling VbglR0SfCreate, file %s, flags %#x\n",
202 path->String.utf8, params.CreateFlags));
203 rc = VbglR0SfCreate(&client_handle, &sf_g->map, path, &params);
204 if (rc == VERR_INVALID_NAME) {
205 /* this can happen for names like 'foo*' on a Windows host */
206 return -ENOENT;
207 }
208 if (RT_FAILURE(rc)) {
209 LogFunc(("VbglR0SfCreate(%s) failed. caller=%s, rc=%Rrc\n",
210 path->String.utf8, rc, caller));
211 return -EPROTO;
212 }
213 if (params.Result != SHFL_FILE_EXISTS) {
214 if (!ok_to_fail)
215 LogFunc(("VbglR0SfCreate(%s) file does not exist. caller=%s, result=%d\n", path->String.utf8, params.Result, caller));
216 return -ENOENT;
217 }
218
219 *result = params.Info;
220 return 0;
221}
222
223/* this is called directly as iop on 2.4, indirectly as dop
224 [sf_dentry_revalidate] on 2.4/2.6, indirectly as iop through
225 [sf_getattr] on 2.6. the job is to find out whether dentry/inode is
226 still valid. the test is failed if [dentry] does not have an inode
227 or [sf_stat] is unsuccessful, otherwise we return success and
228 update inode attributes */
229int sf_inode_revalidate(struct dentry *dentry)
230{
231 int err;
232 struct sf_glob_info *sf_g;
233 struct sf_inode_info *sf_i;
234 SHFLFSOBJINFO info;
235
236 TRACE();
237 if (!dentry || !dentry->d_inode) {
238 LogFunc(("no dentry(%p) or inode(%p)\n", dentry,
239 dentry->d_inode));
240 return -EINVAL;
241 }
242
243 sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
244 sf_i = GET_INODE_INFO(dentry->d_inode);
245
246#if 0
247 printk("%s called by %p:%p\n",
248 sf_i->path->String.utf8,
249 __builtin_return_address(0), __builtin_return_address(1));
250#endif
251
252 BUG_ON(!sf_g);
253 BUG_ON(!sf_i);
254
255 if (!sf_i->force_restat) {
256 if (jiffies - dentry->d_time < sf_g->ttl)
257 return 0;
258 }
259
260 err = sf_stat(__func__, sf_g, sf_i->path, &info, 1);
261 if (err)
262 return err;
263
264 dentry->d_time = jiffies;
265 sf_init_inode(sf_g, dentry->d_inode, &info);
266 return 0;
267}
268
269/* this is called during name resolution/lookup to check if the
270 [dentry] in the cache is still valid. the job is handled by
271 [sf_inode_revalidate] */
272static int
273#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
274sf_dentry_revalidate(struct dentry *dentry, unsigned flags)
275#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
276sf_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
277#else
278sf_dentry_revalidate(struct dentry *dentry, int flags)
279#endif
280{
281 TRACE();
282
283#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
284 if (flags & LOOKUP_RCU)
285 return -ECHILD;
286#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
287 /* see Documentation/filesystems/vfs.txt */
288 if (nd && nd->flags & LOOKUP_RCU)
289 return -ECHILD;
290#endif
291
292 if (sf_inode_revalidate(dentry))
293 return 0;
294
295 return 1;
296}
297
298/* on 2.6 this is a proxy for [sf_inode_revalidate] which (as a side
299 effect) updates inode attributes for [dentry] (given that [dentry]
300 has inode at all) from these new attributes we derive [kstat] via
301 [generic_fillattr] */
302#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
303#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
304int sf_getattr(const struct path *path, struct kstat *kstat, u32 request_mask,
305 unsigned int flags)
306#else
307int sf_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *kstat)
308#endif
309{
310 int err;
311#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
312 struct dentry *dentry = path->dentry;
313#endif
314
315 TRACE();
316 err = sf_inode_revalidate(dentry);
317 if (err)
318 return err;
319
320 generic_fillattr(dentry->d_inode, kstat);
321 return 0;
322}
323
324int sf_setattr(struct dentry *dentry, struct iattr *iattr)
325{
326 struct sf_glob_info *sf_g;
327 struct sf_inode_info *sf_i;
328 SHFLCREATEPARMS params;
329 SHFLFSOBJINFO info;
330 uint32_t cbBuffer;
331 int rc, err;
332
333 TRACE();
334
335 sf_g = GET_GLOB_INFO(dentry->d_inode->i_sb);
336 sf_i = GET_INODE_INFO(dentry->d_inode);
337 err = 0;
338
339 RT_ZERO(params);
340 params.Handle = SHFL_HANDLE_NIL;
341 params.CreateFlags = SHFL_CF_ACT_OPEN_IF_EXISTS
342 | SHFL_CF_ACT_FAIL_IF_NEW | SHFL_CF_ACCESS_ATTR_WRITE;
343
344 /* this is at least required for Posix hosts */
345 if (iattr->ia_valid & ATTR_SIZE)
346 params.CreateFlags |= SHFL_CF_ACCESS_WRITE;
347
348 rc = VbglR0SfCreate(&client_handle, &sf_g->map, sf_i->path, &params);
349 if (RT_FAILURE(rc)) {
350 LogFunc(("VbglR0SfCreate(%s) failed rc=%Rrc\n",
351 sf_i->path->String.utf8, rc));
352 err = -RTErrConvertToErrno(rc);
353 goto fail2;
354 }
355 if (params.Result != SHFL_FILE_EXISTS) {
356 LogFunc(("file %s does not exist\n", sf_i->path->String.utf8));
357 err = -ENOENT;
358 goto fail1;
359 }
360
361 /* Setting the file size and setting the other attributes has to be
362 * handled separately, see implementation of vbsfSetFSInfo() in
363 * vbsf.cpp */
364 if (iattr->ia_valid & (ATTR_MODE | ATTR_ATIME | ATTR_MTIME)) {
365#define mode_set(r) ((iattr->ia_mode & (S_##r)) ? RTFS_UNIX_##r : 0)
366
367 RT_ZERO(info);
368 if (iattr->ia_valid & ATTR_MODE) {
369 info.Attr.fMode = mode_set(IRUSR);
370 info.Attr.fMode |= mode_set(IWUSR);
371 info.Attr.fMode |= mode_set(IXUSR);
372 info.Attr.fMode |= mode_set(IRGRP);
373 info.Attr.fMode |= mode_set(IWGRP);
374 info.Attr.fMode |= mode_set(IXGRP);
375 info.Attr.fMode |= mode_set(IROTH);
376 info.Attr.fMode |= mode_set(IWOTH);
377 info.Attr.fMode |= mode_set(IXOTH);
378
379 if (iattr->ia_mode & S_IFDIR)
380 info.Attr.fMode |= RTFS_TYPE_DIRECTORY;
381 else
382 info.Attr.fMode |= RTFS_TYPE_FILE;
383 }
384
385 if (iattr->ia_valid & ATTR_ATIME)
386 sf_timespec_from_ftime(&info.AccessTime,
387 &iattr->ia_atime);
388 if (iattr->ia_valid & ATTR_MTIME)
389 sf_timespec_from_ftime(&info.ModificationTime,
390 &iattr->ia_mtime);
391 /* ignore ctime (inode change time) as it can't be set from userland anyway */
392
393 cbBuffer = sizeof(info);
394 rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle,
395 SHFL_INFO_SET | SHFL_INFO_FILE, &cbBuffer,
396 (PSHFLDIRINFO) & info);
397 if (RT_FAILURE(rc)) {
398 LogFunc(("VbglR0SfFsInfo(%s, FILE) failed rc=%Rrc\n",
399 sf_i->path->String.utf8, rc));
400 err = -RTErrConvertToErrno(rc);
401 goto fail1;
402 }
403 }
404
405 if (iattr->ia_valid & ATTR_SIZE) {
406 RT_ZERO(info);
407 info.cbObject = iattr->ia_size;
408 cbBuffer = sizeof(info);
409 rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, params.Handle,
410 SHFL_INFO_SET | SHFL_INFO_SIZE, &cbBuffer,
411 (PSHFLDIRINFO) & info);
412 if (RT_FAILURE(rc)) {
413 LogFunc(("VbglR0SfFsInfo(%s, SIZE) failed rc=%Rrc\n",
414 sf_i->path->String.utf8, rc));
415 err = -RTErrConvertToErrno(rc);
416 goto fail1;
417 }
418 }
419
420 rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
421 if (RT_FAILURE(rc))
422 LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n",
423 sf_i->path->String.utf8, rc));
424
425 return sf_inode_revalidate(dentry);
426
427 fail1:
428 rc = VbglR0SfClose(&client_handle, &sf_g->map, params.Handle);
429 if (RT_FAILURE(rc))
430 LogFunc(("VbglR0SfClose(%s) failed rc=%Rrc\n",
431 sf_i->path->String.utf8, rc));
432
433 fail2:
434 return err;
435}
436#endif /* >= 2.6.0 */
437
438static int sf_make_path(const char *caller, struct sf_inode_info *sf_i,
439 const char *d_name, size_t d_len, SHFLSTRING ** result)
440{
441 size_t path_len, shflstring_len;
442 SHFLSTRING *tmp;
443 uint16_t p_len;
444 uint8_t *p_name;
445 int fRoot = 0;
446
447 TRACE();
448 p_len = sf_i->path->u16Length;
449 p_name = sf_i->path->String.utf8;
450
451 if (p_len == 1 && *p_name == '/') {
452 path_len = d_len + 1;
453 fRoot = 1;
454 } else {
455 /* lengths of constituents plus terminating zero plus slash */
456 path_len = p_len + d_len + 2;
457 if (path_len > 0xffff) {
458 LogFunc(("path too long. caller=%s, path_len=%zu\n",
459 caller, path_len));
460 return -ENAMETOOLONG;
461 }
462 }
463
464 shflstring_len = offsetof(SHFLSTRING, String.utf8) + path_len;
465 tmp = kmalloc(shflstring_len, GFP_KERNEL);
466 if (!tmp) {
467 LogRelFunc(("kmalloc failed, caller=%s\n", caller));
468 return -ENOMEM;
469 }
470 tmp->u16Length = path_len - 1;
471 tmp->u16Size = path_len;
472
473 if (fRoot)
474 memcpy(&tmp->String.utf8[0], d_name, d_len + 1);
475 else {
476 memcpy(&tmp->String.utf8[0], p_name, p_len);
477 tmp->String.utf8[p_len] = '/';
478 memcpy(&tmp->String.utf8[p_len + 1], d_name, d_len);
479 tmp->String.utf8[p_len + 1 + d_len] = '\0';
480 }
481
482 *result = tmp;
483 return 0;
484}
485
486/**
487 * [dentry] contains string encoded in coding system that corresponds
488 * to [sf_g]->nls, we must convert it to UTF8 here and pass down to
489 * [sf_make_path] which will allocate SHFLSTRING and fill it in
490 */
491int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
492 struct sf_inode_info *sf_i, struct dentry *dentry,
493 SHFLSTRING ** result)
494{
495 int err;
496 const char *d_name;
497 size_t d_len;
498 const char *name;
499 size_t len = 0;
500
501 TRACE();
502 d_name = dentry->d_name.name;
503 d_len = dentry->d_name.len;
504
505 if (sf_g->nls) {
506 size_t in_len, i, out_bound_len;
507 const char *in;
508 char *out;
509
510 in = d_name;
511 in_len = d_len;
512
513 out_bound_len = PATH_MAX;
514 out = kmalloc(out_bound_len, GFP_KERNEL);
515 name = out;
516
517 for (i = 0; i < d_len; ++i) {
518 /* We renamed the linux kernel wchar_t type to linux_wchar_t in
519 the-linux-kernel.h, as it conflicts with the C++ type of that name. */
520 linux_wchar_t uni;
521 int nb;
522
523 nb = sf_g->nls->char2uni(in, in_len, &uni);
524 if (nb < 0) {
525 LogFunc(("nls->char2uni failed %x %d\n",
526 *in, in_len));
527 err = -EINVAL;
528 goto fail1;
529 }
530 in_len -= nb;
531 in += nb;
532
533#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
534 nb = utf32_to_utf8(uni, out, out_bound_len);
535#else
536 nb = utf8_wctomb(out, uni, out_bound_len);
537#endif
538 if (nb < 0) {
539 LogFunc(("nls->uni2char failed %x %d\n",
540 uni, out_bound_len));
541 err = -EINVAL;
542 goto fail1;
543 }
544 out_bound_len -= nb;
545 out += nb;
546 len += nb;
547 }
548 if (len >= PATH_MAX - 1) {
549 err = -ENAMETOOLONG;
550 goto fail1;
551 }
552
553 LogFunc(("result(%d) = %.*s\n", len, len, name));
554 *out = 0;
555 } else {
556 name = d_name;
557 len = d_len;
558 }
559
560 err = sf_make_path(caller, sf_i, name, len, result);
561 if (name != d_name)
562 kfree(name);
563
564 return err;
565
566 fail1:
567 kfree(name);
568 return err;
569}
570
571int sf_nlscpy(struct sf_glob_info *sf_g,
572 char *name, size_t name_bound_len,
573 const unsigned char *utf8_name, size_t utf8_len)
574{
575 if (sf_g->nls) {
576 const char *in;
577 char *out;
578 size_t out_len;
579 size_t out_bound_len;
580 size_t in_bound_len;
581
582 in = utf8_name;
583 in_bound_len = utf8_len;
584
585 out = name;
586 out_len = 0;
587 out_bound_len = name_bound_len;
588
589 while (in_bound_len) {
590 int nb;
591#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
592 unicode_t uni;
593
594 nb = utf8_to_utf32(in, in_bound_len, &uni);
595#else
596 linux_wchar_t uni;
597
598 nb = utf8_mbtowc(&uni, in, in_bound_len);
599#endif
600 if (nb < 0) {
601 LogFunc(("utf8_mbtowc failed(%s) %x:%d\n",
602 (const char *)utf8_name, *in,
603 in_bound_len));
604 return -EINVAL;
605 }
606 in += nb;
607 in_bound_len -= nb;
608
609 nb = sf_g->nls->uni2char(uni, out, out_bound_len);
610 if (nb < 0) {
611 LogFunc(("nls->uni2char failed(%s) %x:%d\n",
612 utf8_name, uni, out_bound_len));
613 return nb;
614 }
615 out += nb;
616 out_bound_len -= nb;
617 out_len += nb;
618 }
619
620 *out = 0;
621 } else {
622 if (utf8_len + 1 > name_bound_len)
623 return -ENAMETOOLONG;
624
625 memcpy(name, utf8_name, utf8_len + 1);
626 }
627 return 0;
628}
629
630static struct sf_dir_buf *sf_dir_buf_alloc(void)
631{
632 struct sf_dir_buf *b;
633
634 TRACE();
635 b = kmalloc(sizeof(*b), GFP_KERNEL);
636 if (!b) {
637 LogRelFunc(("could not alloc directory buffer\n"));
638 return NULL;
639 }
640#ifdef USE_VMALLOC
641 b->buf = vmalloc(DIR_BUFFER_SIZE);
642#else
643 b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
644#endif
645 if (!b->buf) {
646 kfree(b);
647 LogRelFunc(("could not alloc directory buffer storage\n"));
648 return NULL;
649 }
650
651 INIT_LIST_HEAD(&b->head);
652 b->cEntries = 0;
653 b->cbUsed = 0;
654 b->cbFree = DIR_BUFFER_SIZE;
655 return b;
656}
657
658static void sf_dir_buf_free(struct sf_dir_buf *b)
659{
660 BUG_ON(!b || !b->buf);
661
662 TRACE();
663 list_del(&b->head);
664#ifdef USE_VMALLOC
665 vfree(b->buf);
666#else
667 kfree(b->buf);
668#endif
669 kfree(b);
670}
671
672/**
673 * Free the directory buffer.
674 */
675void sf_dir_info_free(struct sf_dir_info *p)
676{
677 struct list_head *list, *pos, *tmp;
678
679 TRACE();
680 list = &p->info_list;
681 list_for_each_safe(pos, tmp, list) {
682 struct sf_dir_buf *b;
683
684 b = list_entry(pos, struct sf_dir_buf, head);
685 sf_dir_buf_free(b);
686 }
687 kfree(p);
688}
689
690/**
691 * Empty (but not free) the directory buffer.
692 */
693void sf_dir_info_empty(struct sf_dir_info *p)
694{
695 struct list_head *list, *pos, *tmp;
696 TRACE();
697 list = &p->info_list;
698 list_for_each_safe(pos, tmp, list) {
699 struct sf_dir_buf *b;
700 b = list_entry(pos, struct sf_dir_buf, head);
701 b->cEntries = 0;
702 b->cbUsed = 0;
703 b->cbFree = DIR_BUFFER_SIZE;
704 }
705}
706
707/**
708 * Create a new directory buffer descriptor.
709 */
710struct sf_dir_info *sf_dir_info_alloc(void)
711{
712 struct sf_dir_info *p;
713
714 TRACE();
715 p = kmalloc(sizeof(*p), GFP_KERNEL);
716 if (!p) {
717 LogRelFunc(("could not alloc directory info\n"));
718 return NULL;
719 }
720
721 INIT_LIST_HEAD(&p->info_list);
722 return p;
723}
724
725/**
726 * Search for an empty directory content buffer.
727 */
728static struct sf_dir_buf *sf_get_empty_dir_buf(struct sf_dir_info *sf_d)
729{
730 struct list_head *list, *pos;
731
732 list = &sf_d->info_list;
733 list_for_each(pos, list) {
734 struct sf_dir_buf *b;
735
736 b = list_entry(pos, struct sf_dir_buf, head);
737 if (!b)
738 return NULL;
739 else {
740 if (b->cbUsed == 0)
741 return b;
742 }
743 }
744
745 return NULL;
746}
747
748int sf_dir_read_all(struct sf_glob_info *sf_g, struct sf_inode_info *sf_i,
749 struct sf_dir_info *sf_d, SHFLHANDLE handle)
750{
751 int err;
752 SHFLSTRING *mask;
753 struct sf_dir_buf *b;
754
755 TRACE();
756 err = sf_make_path(__func__, sf_i, "*", 1, &mask);
757 if (err)
758 goto fail0;
759
760 for (;;) {
761 int rc;
762 void *buf;
763 uint32_t cbSize;
764 uint32_t cEntries;
765
766 b = sf_get_empty_dir_buf(sf_d);
767 if (!b) {
768 b = sf_dir_buf_alloc();
769 if (!b) {
770 err = -ENOMEM;
771 LogRelFunc(("could not alloc directory buffer\n"));
772 goto fail1;
773 }
774 list_add(&b->head, &sf_d->info_list);
775 }
776
777 buf = b->buf;
778 cbSize = b->cbFree;
779
780 rc = VbglR0SfDirInfo(&client_handle, &sf_g->map, handle, mask,
781 0, 0, &cbSize, buf, &cEntries);
782 switch (rc) {
783 case VINF_SUCCESS:
784 RT_FALL_THRU();
785 case VERR_NO_MORE_FILES:
786 break;
787 case VERR_NO_TRANSLATION:
788 LogFunc(("host could not translate entry\n"));
789 /* XXX */
790 break;
791 default:
792 err = -RTErrConvertToErrno(rc);
793 LogFunc(("VbglR0SfDirInfo failed rc=%Rrc\n", rc));
794 goto fail1;
795 }
796
797 b->cEntries += cEntries;
798 b->cbFree -= cbSize;
799 b->cbUsed += cbSize;
800
801 if (RT_FAILURE(rc))
802 break;
803 }
804 err = 0;
805
806 fail1:
807 kfree(mask);
808
809 fail0:
810 return err;
811}
812
813int sf_get_volume_info(struct super_block *sb, STRUCT_STATFS * stat)
814{
815 struct sf_glob_info *sf_g;
816 SHFLVOLINFO SHFLVolumeInfo;
817 uint32_t cbBuffer;
818 int rc;
819
820 sf_g = GET_GLOB_INFO(sb);
821 cbBuffer = sizeof(SHFLVolumeInfo);
822 rc = VbglR0SfFsInfo(&client_handle, &sf_g->map, 0,
823 SHFL_INFO_GET | SHFL_INFO_VOLUME, &cbBuffer,
824 (PSHFLDIRINFO) & SHFLVolumeInfo);
825 if (RT_FAILURE(rc))
826 return -RTErrConvertToErrno(rc);
827
828 stat->f_type = NFS_SUPER_MAGIC; /* XXX vboxsf type? */
829 stat->f_bsize = SHFLVolumeInfo.ulBytesPerAllocationUnit;
830 stat->f_blocks = SHFLVolumeInfo.ullTotalAllocationBytes
831 / SHFLVolumeInfo.ulBytesPerAllocationUnit;
832 stat->f_bfree = SHFLVolumeInfo.ullAvailableAllocationBytes
833 / SHFLVolumeInfo.ulBytesPerAllocationUnit;
834 stat->f_bavail = SHFLVolumeInfo.ullAvailableAllocationBytes
835 / SHFLVolumeInfo.ulBytesPerAllocationUnit;
836 stat->f_files = 1000;
837 stat->f_ffree = 1000; /* don't return 0 here since the guest may think
838 * that it is not possible to create any more files */
839 stat->f_fsid.val[0] = 0;
840 stat->f_fsid.val[1] = 0;
841 stat->f_namelen = 255;
842 return 0;
843}
844
845struct dentry_operations sf_dentry_ops = {
846 .d_revalidate = sf_dentry_revalidate
847};
848
849int sf_init_backing_dev(struct sf_glob_info *sf_g)
850{
851 int rc = 0;
852#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) && LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19, 0)
853 /* Each new shared folder map gets a new uint64_t identifier,
854 * allocated in sequence. We ASSUME the sequence will not wrap. */
855 static uint64_t s_u64Sequence = 0;
856 uint64_t u64CurrentSequence = ASMAtomicIncU64(&s_u64Sequence);
857
858 sf_g->bdi.ra_pages = 0; /* No readahead */
859#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)
860 sf_g->bdi.capabilities = BDI_CAP_MAP_DIRECT /* MAP_SHARED */
861 | BDI_CAP_MAP_COPY /* MAP_PRIVATE */
862 | BDI_CAP_READ_MAP /* can be mapped for reading */
863 | BDI_CAP_WRITE_MAP /* can be mapped for writing */
864 | BDI_CAP_EXEC_MAP; /* can be mapped for execution */
865#endif /* >= 2.6.12 */
866#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
867 rc = bdi_init(&sf_g->bdi);
868#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
869 if (!rc)
870 rc = bdi_register(&sf_g->bdi, NULL, "vboxsf-%llu",
871 (unsigned long long)u64CurrentSequence);
872#endif /* >= 2.6.26 */
873#endif /* >= 2.6.24 */
874#endif /* >= 2.6.0 && <= 3.19.0 */
875 return rc;
876}
877
878void sf_done_backing_dev(struct sf_glob_info *sf_g)
879{
880#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24) && LINUX_VERSION_CODE <= KERNEL_VERSION(3, 19, 0)
881 bdi_destroy(&sf_g->bdi); /* includes bdi_unregister() */
882#endif
883}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette