VirtualBox

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

Last change on this file since 4485 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.8 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 innotek GmbH
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 as published by the Free Software Foundation,
15 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
16 * distribution. VirtualBox OSE is distributed in the hope that it will
17 * be useful, but WITHOUT ANY WARRANTY of any kind.
18 */
19
20/* #define USE_VMALLOC */
21
22#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
23static void
24sf_ftime_from_timespec (time_t *time, RTTIMESPEC *ts)
25{
26 int64_t t = RTTimeSpecGetNano (ts);
27
28 do_div (t, 1000000000);
29 *time = t;
30}
31#else
32static void
33sf_ftime_from_timespec (struct timespec *tv, RTTIMESPEC *ts)
34{
35 int64_t t = RTTimeSpecGetNano (ts);
36 int64_t nsec;
37
38 nsec = do_div (t, 1000000000);
39 tv->tv_sec = t;
40 tv->tv_nsec = nsec;
41}
42#endif
43
44/* set [inode] attributes based on [info], uid/gid based on [sf_g] */
45static void
46sf_init_inode (struct sf_glob_info *sf_g, struct inode *inode,
47 RTFSOBJINFO *info)
48{
49 int is_dir;
50 RTFSOBJATTR *attr;
51 int mode;
52
53 TRACE ();
54
55 attr = &info->Attr;
56 is_dir = RTFS_IS_DIRECTORY (attr->fMode);
57
58#define mode_set(r) attr->fMode & (RTFS_UNIX_##r) ? (S_##r) : 0;
59 mode = mode_set (ISUID);
60 mode |= mode_set (ISGID);
61
62 mode |= mode_set (IRUSR);
63 mode |= mode_set (IWUSR);
64 mode |= mode_set (IXUSR);
65
66 mode |= mode_set (IRGRP);
67 mode |= mode_set (IWGRP);
68 mode |= mode_set (IXGRP);
69
70 mode |= mode_set (IROTH);
71 mode |= mode_set (IWOTH);
72 mode |= mode_set (IXOTH);
73#undef mode_set
74
75 if (is_dir) {
76 inode->i_mode = S_IFDIR | mode;
77 inode->i_op = &sf_dir_iops;
78 inode->i_fop = &sf_dir_fops;
79 /* XXX: this probably should be set to the number of entries
80 in the directory plus two (. ..) */
81 inode->i_nlink = 1;
82 }
83 else {
84 inode->i_mode = S_IFREG | mode;
85 inode->i_op = &sf_reg_iops;
86 inode->i_fop = &sf_reg_fops;
87 inode->i_nlink = 1;
88 }
89
90 inode->i_uid = sf_g->uid;
91 inode->i_gid = sf_g->gid;
92 inode->i_size = info->cbObject;
93#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) && !defined(KERNEL_FC6)
94 inode->i_blksize = 4096;
95#endif
96 inode->i_blocks = (info->cbObject + 4095) / 4096;
97
98 sf_ftime_from_timespec (&inode->i_atime, &info->AccessTime);
99 sf_ftime_from_timespec (&inode->i_ctime, &info->ChangeTime);
100 sf_ftime_from_timespec (&inode->i_mtime, &info->ModificationTime);
101}
102
103static int
104sf_stat (const char *caller, struct sf_glob_info *sf_g,
105 SHFLSTRING *path, RTFSOBJINFO *result, int ok_to_fail)
106{
107 int rc;
108 SHFLCREATEPARMS params;
109
110 TRACE ();
111 params.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
112 rc = vboxCallCreate (&client_handle, &sf_g->map, path, &params);
113 if (VBOX_FAILURE (rc)) {
114 elog3 ("%s: %s: vboxCallCreate(%s) failed rc=%d\n",
115 caller, __func__, path->String.utf8, rc);
116 return -EPROTO;
117 }
118
119 if (params.Result != SHFL_FILE_EXISTS) {
120 if (!ok_to_fail) {
121 elog3 ("%s: %s: vboxCallCreate(%s)"
122 " file does not exist result=%d\n",
123 caller, __func__, path->String.utf8, params.Result);
124 }
125 return -ENOENT;
126 }
127
128 *result = params.Info;
129 return 0;
130}
131
132/* this is called directly as iop on 2.4, indirectly as dop
133 [sf_dentry_revalidate] on 2.4/2.6, indirectly as iop through
134 [sf_getattr] on 2.6. the job is to find out whether dentry/inode is
135 still valid. the test is failed if [dentry] does not have an inode
136 or [sf_stat] is unsuccessful, otherwise we return success and
137 update inode attributes */
138static int
139sf_inode_revalidate (struct dentry *dentry)
140{
141 int err;
142 struct sf_glob_info *sf_g;
143 struct sf_inode_info *sf_i;
144 RTFSOBJINFO info;
145
146 TRACE ();
147 if (!dentry || !dentry->d_inode) {
148 DBGC elog ("no dentry(%p) or inode(%p)\n", dentry, dentry->d_inode);
149 return -EINVAL;
150 }
151
152 sf_g = GET_GLOB_INFO (dentry->d_inode->i_sb);
153 sf_i = GET_INODE_INFO (dentry->d_inode);
154
155#if 0
156 printk ("%s called by %p:%p\n",
157 sf_i->path->String.utf8,
158 __builtin_return_address (0),
159 __builtin_return_address (1));
160#endif
161
162 BUG_ON (!sf_g);
163 BUG_ON (!sf_i);
164
165 if (!sf_i->force_restat) {
166 if (jiffies - dentry->d_time < sf_g->ttl) {
167 return 0;
168 }
169 }
170
171 err = sf_stat (__func__, sf_g, sf_i->path, &info, 1);
172 if (err) {
173 return err;
174 }
175
176 dentry->d_time = jiffies;
177 sf_init_inode (sf_g, dentry->d_inode, &info);
178 return 0;
179}
180
181/* this is called during name resolution/lookup to check if the
182 [dentry] in the cache is still valid. the job is handled by
183 [sf_inode_revalidate] */
184static int
185#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
186sf_dentry_revalidate (struct dentry *dentry, int flags)
187#else
188 sf_dentry_revalidate (struct dentry *dentry, struct nameidata *nd)
189#endif
190{
191 TRACE ();
192 if (sf_inode_revalidate (dentry)) {
193 return 0;
194 }
195 return 1;
196}
197
198/* on 2.6 this is a proxy for [sf_inode_revalidate] which (as a side
199 effect) updates inode attributes for [dentry] (given that [dentry]
200 has inode at all) from these new attributes we derive [kstat] via
201 [generic_fillattr] */
202#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
203static int
204sf_getattr (struct vfsmount *mnt, struct dentry *dentry, struct kstat *kstat)
205{
206 int err;
207
208 TRACE ();
209 err = sf_inode_revalidate (dentry);
210 if (err) {
211 return err;
212 }
213
214 generic_fillattr (dentry->d_inode, kstat);
215 return 0;
216}
217#endif
218
219static int
220sf_make_path (const char *caller, struct sf_inode_info *sf_i,
221 const char *d_name, size_t d_len, SHFLSTRING **result)
222{
223 size_t path_len, shflstring_len;
224 SHFLSTRING *tmp;
225 uint16_t p_len;
226 uint8_t *p_name;
227 uint8_t *dst;
228 int is_root = 0;
229
230 TRACE ();
231 p_len = sf_i->path->u16Length;
232 p_name = sf_i->path->String.utf8;
233
234 if (p_len == 1 && *p_name == '/') {
235 path_len = d_len + 1;
236 is_root = 1;
237 }
238 else {
239 /* lengths of constituents plus terminating zero plus slash */
240 path_len = p_len + d_len + 2;
241 if (path_len > 0xffff) {
242 elog ("%s: path to big %zu\n", caller, path_len);
243 return -ENAMETOOLONG;
244 }
245 }
246
247 shflstring_len = offsetof (SHFLSTRING, String.utf8) + path_len;
248 tmp = kmalloc (shflstring_len, GFP_KERNEL);
249 if (!tmp) {
250 elog ("%s: kmalloc failed\n", caller);
251 return -ENOMEM;
252 }
253 tmp->u16Length = path_len - 1;
254 tmp->u16Size = path_len;
255
256 if (is_root) {
257 memcpy (tmp->String.utf8, d_name, d_len + 1);
258 }
259 else {
260 dst = tmp->String.utf8;
261 memcpy (dst, p_name, p_len);
262 dst += p_len; *dst++ = '/';
263 memcpy (dst, d_name, d_len);
264 dst[d_len] = 0;
265 }
266
267 *result = tmp;
268 return 0;
269}
270
271/* [dentry] contains string encoded in coding system that corresponds
272 to [sf_g]->nls, we must convert it to UTF8 here and pass down to
273 [sf_make_path] which will allocate SHFLSTRING and fill it in */
274static int
275sf_path_from_dentry (const char *caller, struct sf_glob_info *sf_g,
276 struct sf_inode_info *sf_i, struct dentry *dentry,
277 SHFLSTRING **result)
278{
279 int err;
280 const char *d_name;
281 size_t d_len;
282 const char *name;
283 size_t len = 0;
284
285 TRACE ();
286 d_name = dentry->d_name.name;
287 d_len = dentry->d_name.len;
288
289 if (sf_g->nls) {
290 size_t in_len, i, out_bound_len;
291 const char *in;
292 char *out;
293
294 in = d_name;
295 in_len = d_len;
296
297 out_bound_len = PATH_MAX;
298 out = kmalloc (out_bound_len, GFP_KERNEL);
299 name = out;
300
301 for (i = 0; i < d_len; ++i) {
302 /* We renamed the linux kernel wchar_t type to linux_wchar_t in
303 the-linux-kernel.h, as it conflicts with the C++ type of that name. */
304 linux_wchar_t uni;
305 int nb;
306
307 nb = sf_g->nls->char2uni (in, in_len, &uni);
308 if (nb < 0) {
309 elog ("nls->char2uni failed %x %d\n",
310 *in, in_len);
311 err = -EINVAL;
312 goto fail1;
313 }
314 in_len -= nb;
315 in += nb;
316
317 nb = utf8_wctomb (out, uni, out_bound_len);
318 if (nb < 0) {
319 elog ("nls->uni2char failed %x %d\n",
320 uni, out_bound_len);
321 err = -EINVAL;
322 goto fail1;
323 }
324 out_bound_len -= nb;
325 out += nb;
326 len += nb;
327 }
328 if (len >= PATH_MAX - 1) {
329 err = -ENAMETOOLONG;
330 goto fail1;
331 }
332
333 DBGC printk (KERN_DEBUG "result(%d) = %.*s\n", len, len, name);
334 *out = 0;
335 }
336 else {
337 name = d_name;
338 len = d_len;
339 }
340
341 err = sf_make_path (caller, sf_i, name, len, result);
342 if (name != d_name) {
343 kfree (name);
344 }
345 return err;
346
347 fail1:
348 kfree (name);
349 return err;
350}
351
352static int
353sf_nlscpy (struct sf_glob_info *sf_g,
354 char *name, size_t name_bound_len,
355 const unsigned char *utf8_name, size_t utf8_len)
356{
357 if (sf_g->nls) {
358 const char *in;
359 char *out;
360 size_t out_len;
361 size_t out_bound_len;
362 size_t in_bound_len;
363
364 in = utf8_name;
365 in_bound_len = utf8_len;
366
367 out = name;
368 out_len = 0;
369 out_bound_len = name_bound_len;
370
371 while (in_bound_len) {
372 int nb;
373 wchar_t uni;
374
375 nb = utf8_mbtowc (&uni, in, in_bound_len);
376 if (nb < 0) {
377 elog ("utf8_mbtowc failed(%s) %x:%d\n",
378 utf8_name, *in, in_bound_len);
379 return -EINVAL;
380 }
381 in += nb;
382 in_bound_len -= nb;
383
384 nb = sf_g->nls->uni2char (uni, out, out_bound_len);
385 if (nb < 0) {
386 elog ("nls->uni2char failed(%s) %x:%d\n",
387 utf8_name, uni, out_bound_len);
388 return nb;
389 }
390 out += nb;
391 out_bound_len -= nb;
392 out_len += nb;
393 }
394
395 *out = 0;
396 return 0;
397 }
398 else {
399 if (utf8_len + 1 > name_bound_len) {
400 return -ENAMETOOLONG;
401 }
402 else {
403 memcpy (name, utf8_name, utf8_len + 1);
404 }
405 return 0;
406 }
407}
408
409static struct sf_dir_buf *
410sf_dir_buf_alloc (void)
411{
412 struct sf_dir_buf *b;
413
414 TRACE ();
415 b = kmalloc (sizeof (*b), GFP_KERNEL);
416 if (!b) {
417 elog2 ("could not alloc directory buffer\n");
418 return NULL;
419 }
420
421#ifdef USE_VMALLOC
422 b->buf = vmalloc (16384);
423#else
424 b->buf = kmalloc (16384, GFP_KERNEL);
425#endif
426 if (!b->buf) {
427 kfree (b);
428 elog2 ("could not alloc directory buffer storage\n");
429 return NULL;
430 }
431
432 INIT_LIST_HEAD (&b->head);
433 b->nb_entries = 0;
434 b->used_bytes = 0;
435 b->free_bytes = 16384;
436 return b;
437}
438
439static void
440sf_dir_buf_free (struct sf_dir_buf *b)
441{
442 BUG_ON (!b || !b->buf);
443
444 TRACE ();
445 list_del (&b->head);
446#ifdef USE_VMALLOC
447 vfree (b->buf);
448#else
449 kfree (b->buf);
450#endif
451 kfree (b);
452}
453
454static void
455sf_dir_info_free (struct sf_dir_info *p)
456{
457 struct list_head *list, *pos, *tmp;
458
459 TRACE ();
460 list = &p->info_list;
461 list_for_each_safe (pos, tmp, list) {
462 struct sf_dir_buf *b;
463
464 b = list_entry (pos, struct sf_dir_buf, head);
465 sf_dir_buf_free (b);
466 }
467 kfree (p);
468}
469
470static struct sf_dir_info *
471sf_dir_info_alloc (void)
472{
473 struct sf_dir_info *p;
474
475 TRACE ();
476 p = kmalloc (sizeof (*p), GFP_KERNEL);
477 if (!p) {
478 elog2 ("could not alloc directory info\n");
479 return NULL;
480 }
481
482 INIT_LIST_HEAD (&p->info_list);
483 return p;
484}
485
486static struct sf_dir_buf *
487sf_get_non_empty_dir_buf (struct sf_dir_info *sf_d)
488{
489 struct list_head *list, *pos;
490
491 list = &sf_d->info_list;
492 list_for_each (pos, list) {
493 struct sf_dir_buf *b;
494
495 b = list_entry (pos, struct sf_dir_buf, head);
496 if (!b) {
497 return NULL;
498 }
499 else {
500 if (b->free_bytes > 0) {
501 return b;
502 }
503 }
504 }
505
506 return NULL;
507}
508
509static int
510sf_dir_read_all (struct sf_glob_info *sf_g, struct sf_inode_info *sf_i,
511 struct sf_dir_info *sf_d, SHFLHANDLE handle)
512{
513 int err;
514 SHFLSTRING *mask;
515 struct sf_dir_buf *b;
516
517 TRACE ();
518 err = sf_make_path (__func__, sf_i, "*", 1, &mask);
519 if (err) {
520 goto fail0;
521 }
522
523 b = sf_get_non_empty_dir_buf (sf_d);
524 for (;;) {
525 int rc;
526 void *buf;
527 uint32_t buf_size;
528 uint32_t nb_ents;
529
530 if (!b) {
531 b = sf_dir_buf_alloc ();
532 if (!b) {
533 err = -ENOMEM;
534 elog2 ("could not alloc directory buffer\n");
535 goto fail1;
536 }
537 }
538
539 list_add (&b->head, &sf_d->info_list);
540
541 buf = b->buf;
542 buf_size = b->free_bytes;
543
544 rc = vboxCallDirInfo (
545 &client_handle,
546 &sf_g->map,
547 handle,
548 mask,
549 0,
550 0,
551 &buf_size,
552 buf,
553 &nb_ents
554 );
555 switch (rc) {
556 case VINF_SUCCESS:
557 /* fallthrough */
558 case VERR_NO_MORE_FILES:
559 break;
560
561 case VERR_NO_TRANSLATION:
562 elog2 ("host could not translte entry\n");
563 /* XXX */
564 break;
565
566 default:
567 err = -EPROTO;
568 elog ("vboxCallDirInfo failed rc=%d\n", rc);
569 goto fail1;
570 }
571
572 b->nb_entries += nb_ents;
573 b->free_bytes -= buf_size;
574 b->used_bytes += buf_size;
575 b = NULL;
576
577 if (VBOX_FAILURE (rc)) {
578 break;
579 }
580 }
581 return 0;
582
583 fail1:
584 kfree (mask);
585 fail0:
586 return err;
587}
588
589static struct dentry_operations sf_dentry_ops = {
590 .d_revalidate = sf_dentry_revalidate
591};
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