VirtualBox

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

Last change on this file since 26102 was 26102, checked in by vboxsync, 15 years ago

Another fix for public #5891. Thanks to Pax Team for the suggestion.

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