VirtualBox

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

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

compile fix

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