VirtualBox

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

Last change on this file since 33944 was 33440, checked in by vboxsync, 14 years ago

Linux Additions: symlinks only for Linux 2.6 guests

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