VirtualBox

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

Last change on this file since 32394 was 31719, checked in by vboxsync, 14 years ago

Linux additions: Linux 2.6.36 compile fixes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.6 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 int fRoot = 0;
389
390 TRACE();
391 p_len = sf_i->path->u16Length;
392 p_name = sf_i->path->String.utf8;
393
394 if (p_len == 1 && *p_name == '/')
395 {
396 path_len = d_len + 1;
397 fRoot = 1;
398 }
399 else
400 {
401 /* lengths of constituents plus terminating zero plus slash */
402 path_len = p_len + d_len + 2;
403 if (path_len > 0xffff)
404 {
405 LogFunc(("path too long. caller=%s, path_len=%zu\n", caller, path_len));
406 return -ENAMETOOLONG;
407 }
408 }
409
410 shflstring_len = offsetof(SHFLSTRING, String.utf8) + path_len;
411 tmp = kmalloc(shflstring_len, GFP_KERNEL);
412 if (!tmp)
413 {
414 LogRelFunc(("kmalloc failed, caller=%s\n", caller));
415 return -ENOMEM;
416 }
417 tmp->u16Length = path_len - 1;
418 tmp->u16Size = path_len;
419
420 if (fRoot)
421 memcpy(&tmp->String.utf8[0], d_name, d_len + 1);
422 else
423 {
424 memcpy(&tmp->String.utf8[0], p_name, p_len);
425 tmp->String.utf8[p_len] = '/';
426 memcpy(&tmp->String.utf8[p_len + 1], d_name, d_len);
427 tmp->String.utf8[p_len + 1 + d_len] = '\0';
428 }
429
430 *result = tmp;
431 return 0;
432}
433
434/**
435 * [dentry] contains string encoded in coding system that corresponds
436 * to [sf_g]->nls, we must convert it to UTF8 here and pass down to
437 * [sf_make_path] which will allocate SHFLSTRING and fill it in
438 */
439int sf_path_from_dentry(const char *caller, struct sf_glob_info *sf_g,
440 struct sf_inode_info *sf_i, struct dentry *dentry,
441 SHFLSTRING **result)
442{
443 int err;
444 const char *d_name;
445 size_t d_len;
446 const char *name;
447 size_t len = 0;
448
449 TRACE();
450 d_name = dentry->d_name.name;
451 d_len = dentry->d_name.len;
452
453 if (sf_g->nls)
454 {
455 size_t in_len, i, out_bound_len;
456 const char *in;
457 char *out;
458
459 in = d_name;
460 in_len = d_len;
461
462 out_bound_len = PATH_MAX;
463 out = kmalloc(out_bound_len, GFP_KERNEL);
464 name = out;
465
466 for (i = 0; i < d_len; ++i)
467 {
468 /* We renamed the linux kernel wchar_t type to linux_wchar_t in
469 the-linux-kernel.h, as it conflicts with the C++ type of that name. */
470 linux_wchar_t uni;
471 int nb;
472
473 nb = sf_g->nls->char2uni(in, in_len, &uni);
474 if (nb < 0)
475 {
476 LogFunc(("nls->char2uni failed %x %d\n",
477 *in, in_len));
478 err = -EINVAL;
479 goto fail1;
480 }
481 in_len -= nb;
482 in += nb;
483
484#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
485 nb = utf32_to_utf8(uni, out, out_bound_len);
486#else
487 nb = utf8_wctomb(out, uni, out_bound_len);
488#endif
489 if (nb < 0)
490 {
491 LogFunc(("nls->uni2char failed %x %d\n",
492 uni, out_bound_len));
493 err = -EINVAL;
494 goto fail1;
495 }
496 out_bound_len -= nb;
497 out += nb;
498 len += nb;
499 }
500 if (len >= PATH_MAX - 1)
501 {
502 err = -ENAMETOOLONG;
503 goto fail1;
504 }
505
506 LogFunc(("result(%d) = %.*s\n", len, len, name));
507 *out = 0;
508 }
509 else
510 {
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
521fail1:
522 kfree(name);
523 return err;
524}
525
526int sf_nlscpy(struct sf_glob_info *sf_g,
527 char *name, size_t name_bound_len,
528 const unsigned char *utf8_name, size_t utf8_len)
529{
530 if (sf_g->nls)
531 {
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 {
547 int nb;
548 wchar_t uni;
549
550#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 31)
551 nb = utf8_to_utf32(in, in_bound_len, &uni);
552#else
553 nb = utf8_mbtowc(&uni, in, in_bound_len);
554#endif
555 if (nb < 0)
556 {
557 LogFunc(("utf8_mbtowc failed(%s) %x:%d\n",
558 (const char *) utf8_name, *in, in_bound_len));
559 return -EINVAL;
560 }
561 in += nb;
562 in_bound_len -= nb;
563
564 nb = sf_g->nls->uni2char(uni, out, out_bound_len);
565 if (nb < 0)
566 {
567 LogFunc(("nls->uni2char failed(%s) %x:%d\n",
568 utf8_name, uni, out_bound_len));
569 return nb;
570 }
571 out += nb;
572 out_bound_len -= nb;
573 out_len += nb;
574 }
575
576 *out = 0;
577 }
578 else
579 {
580 if (utf8_len + 1 > name_bound_len)
581 return -ENAMETOOLONG;
582
583 memcpy(name, utf8_name, utf8_len + 1);
584 }
585 return 0;
586}
587
588static struct sf_dir_buf *sf_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 {
596 LogRelFunc(("could not alloc directory buffer\n"));
597 return NULL;
598 }
599
600#ifdef USE_VMALLOC
601 b->buf = vmalloc(DIR_BUFFER_SIZE);
602#else
603 b->buf = kmalloc(DIR_BUFFER_SIZE, GFP_KERNEL);
604#endif
605 if (!b->buf)
606 {
607 kfree(b);
608 LogRelFunc(("could not alloc directory buffer storage\n"));
609 return NULL;
610 }
611
612 INIT_LIST_HEAD(&b->head);
613 b->cEntries = 0;
614 b->cbUsed = 0;
615 b->cbFree = DIR_BUFFER_SIZE;
616 return b;
617}
618
619static void sf_dir_buf_free(struct sf_dir_buf *b)
620{
621 BUG_ON(!b || !b->buf);
622
623 TRACE();
624 list_del(&b->head);
625#ifdef USE_VMALLOC
626 vfree(b->buf);
627#else
628 kfree(b->buf);
629#endif
630 kfree(b);
631}
632
633/**
634 * Free the directory buffer.
635 */
636void sf_dir_info_free(struct sf_dir_info *p)
637{
638 struct list_head *list, *pos, *tmp;
639
640 TRACE();
641 list = &p->info_list;
642 list_for_each_safe(pos, tmp, list)
643 {
644 struct sf_dir_buf *b;
645
646 b = list_entry(pos, struct sf_dir_buf, head);
647 sf_dir_buf_free(b);
648 }
649 kfree(p);
650}
651
652/**
653 * Empty (but not free) the directory buffer.
654 */
655void sf_dir_info_empty(struct sf_dir_info *p)
656{
657 struct list_head *list, *pos, *tmp;
658 TRACE();
659 list = &p->info_list;
660 list_for_each_safe(pos, tmp, list)
661 {
662 struct sf_dir_buf *b;
663 b = list_entry(pos, struct sf_dir_buf, head);
664 b->cEntries = 0;
665 b->cbUsed = 0;
666 b->cbFree = DIR_BUFFER_SIZE;
667 }
668}
669
670/**
671 * Create a new directory buffer descriptor.
672 */
673struct sf_dir_info *sf_dir_info_alloc(void)
674{
675 struct sf_dir_info *p;
676
677 TRACE();
678 p = kmalloc(sizeof(*p), GFP_KERNEL);
679 if (!p)
680 {
681 LogRelFunc(("could not alloc directory info\n"));
682 return NULL;
683 }
684
685 INIT_LIST_HEAD(&p->info_list);
686 return p;
687}
688
689/**
690 * Search for an empty directory content buffer.
691 */
692static struct sf_dir_buf *sf_get_empty_dir_buf(struct sf_dir_info *sf_d)
693{
694 struct list_head *list, *pos;
695
696 list = &sf_d->info_list;
697 list_for_each(pos, list)
698 {
699 struct sf_dir_buf *b;
700
701 b = list_entry(pos, struct sf_dir_buf, head);
702 if (!b)
703 return NULL;
704 else
705 {
706 if (b->cbUsed == 0)
707 return b;
708 }
709 }
710
711 return NULL;
712}
713
714int sf_dir_read_all(struct sf_glob_info *sf_g, struct sf_inode_info *sf_i,
715 struct sf_dir_info *sf_d, SHFLHANDLE handle)
716{
717 int err;
718 SHFLSTRING *mask;
719 struct sf_dir_buf *b;
720
721 TRACE();
722 err = sf_make_path(__func__, sf_i, "*", 1, &mask);
723 if (err)
724 goto fail0;
725
726 for (;;)
727 {
728 int rc;
729 void *buf;
730 uint32_t cbSize;
731 uint32_t cEntries;
732
733 b = sf_get_empty_dir_buf(sf_d);
734 if (!b)
735 {
736 b = sf_dir_buf_alloc();
737 if (!b)
738 {
739 err = -ENOMEM;
740 LogRelFunc(("could not alloc directory buffer\n"));
741 goto fail1;
742 }
743 list_add(&b->head, &sf_d->info_list);
744 }
745
746 buf = b->buf;
747 cbSize = b->cbFree;
748
749 rc = vboxCallDirInfo(&client_handle, &sf_g->map, handle, mask,
750 0, 0, &cbSize, buf, &cEntries);
751 switch (rc)
752 {
753 case VINF_SUCCESS:
754 /* fallthrough */
755 case VERR_NO_MORE_FILES:
756 break;
757 case VERR_NO_TRANSLATION:
758 LogFunc(("host could not translate entry\n"));
759 /* XXX */
760 break;
761 default:
762 err = -RTErrConvertToErrno(rc);
763 LogFunc(("vboxCallDirInfo failed rc=%Rrc\n", rc));
764 goto fail1;
765 }
766
767 b->cEntries += cEntries;
768 b->cbFree -= cbSize;
769 b->cbUsed += cbSize;
770
771 if (RT_FAILURE(rc))
772 break;
773 }
774 err = 0;
775
776fail1:
777 kfree(mask);
778
779fail0:
780 return err;
781}
782
783int sf_get_volume_info(struct super_block *sb, STRUCT_STATFS *stat)
784{
785 struct sf_glob_info *sf_g;
786 SHFLVOLINFO SHFLVolumeInfo;
787 uint32_t cbBuffer;
788 int rc;
789
790 sf_g = GET_GLOB_INFO(sb);
791 cbBuffer = sizeof(SHFLVolumeInfo);
792 rc = vboxCallFSInfo(&client_handle, &sf_g->map, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
793 &cbBuffer, (PSHFLDIRINFO)&SHFLVolumeInfo);
794 if (RT_FAILURE(rc))
795 return -RTErrConvertToErrno(rc);
796
797 stat->f_type = NFS_SUPER_MAGIC; /* XXX vboxsf type? */
798 stat->f_bsize = SHFLVolumeInfo.ulBytesPerAllocationUnit;
799 stat->f_blocks = SHFLVolumeInfo.ullTotalAllocationBytes
800 / SHFLVolumeInfo.ulBytesPerAllocationUnit;
801 stat->f_bfree = SHFLVolumeInfo.ullAvailableAllocationBytes
802 / SHFLVolumeInfo.ulBytesPerAllocationUnit;
803 stat->f_bavail = SHFLVolumeInfo.ullAvailableAllocationBytes
804 / SHFLVolumeInfo.ulBytesPerAllocationUnit;
805 stat->f_files = 1000;
806 stat->f_ffree = 1000; /* don't return 0 here since the guest may think
807 * that it is not possible to create any more files */
808 stat->f_fsid.val[0] = 0;
809 stat->f_fsid.val[1] = 0;
810 stat->f_namelen = 255;
811 return 0;
812}
813
814struct dentry_operations sf_dentry_ops =
815{
816 .d_revalidate = sf_dentry_revalidate
817};
818
819int sf_init_backing_dev(struct sf_glob_info *sf_g, const char *name)
820{
821 int rc = 0;
822
823#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
824 sf_g->bdi.ra_pages = 0; /* No readahead */
825# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)
826 sf_g->bdi.capabilities = BDI_CAP_MAP_DIRECT /* MAP_SHARED */
827 | BDI_CAP_MAP_COPY /* MAP_PRIVATE */
828 | BDI_CAP_READ_MAP /* can be mapped for reading */
829 | BDI_CAP_WRITE_MAP /* can be mapped for writing */
830 | BDI_CAP_EXEC_MAP; /* can be mapped for execution */
831# endif /* >= 2.6.12 */
832# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
833 rc = bdi_init(&sf_g->bdi);
834# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
835 if (!rc)
836 rc = bdi_register(&sf_g->bdi, NULL, "vboxsf-%s", name);
837# endif /* >= 2.6.26 */
838# endif /* >= 2.6.24 */
839#endif /* >= 2.6.0 */
840 return rc;
841}
842
843void sf_done_backing_dev(struct sf_glob_info *sf_g)
844{
845#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
846 bdi_destroy(&sf_g->bdi); /* includes bdi_unregister() */
847#endif
848}
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