VirtualBox

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

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

Activated the full backdoor logger in release builds of the Linux Guest Additions kernel modules

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