VirtualBox

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

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

Linux shared folders: coding style

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