VirtualBox

source: vbox/trunk/src/VBox/Additions/linux/sharedfolders/dirops.c@ 2614

Last change on this file since 2614 was 2614, checked in by vboxsync, 18 years ago

export sharedfolders and xclient to OSE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.1 KB
Line 
1/** @file
2 *
3 * vboxvfs -- VirtualBox Guest Additions for Linux:
4 * Directory inode and file operations
5 */
6
7/*
8 * Copyright (C) 2006 InnoTek Systemberatung GmbH
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License as published by the Free Software Foundation,
14 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
15 * distribution. VirtualBox OSE is distributed in the hope that it will
16 * be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * If you received this file as part of a commercial VirtualBox
19 * distribution, then only the terms of your commercial VirtualBox
20 * license agreement apply instead of the previous paragraph.
21 */
22
23static int
24sf_dir_open (struct inode *inode, struct file *file)
25{
26 int rc;
27 int err;
28 struct sf_glob_info *sf_g = GET_GLOB_INFO (inode->i_sb);
29 struct sf_dir_info *sf_d;
30 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
31 SHFLCREATEPARMS params;
32
33 TRACE ();
34 BUG_ON (!sf_g);
35 BUG_ON (!sf_i);
36
37 if (file->private_data) {
38 elog ("dir_open called on already opened directory %s\n",
39 sf_i->path->String.utf8);
40 return 0;
41 }
42
43 sf_d = sf_dir_info_alloc ();
44
45 if (!sf_d) {
46 elog ("could not allocate directory info for %s\n",
47 sf_i->path->String.utf8);
48 return -ENOMEM;
49 }
50
51 params.CreateFlags = 0
52 | SHFL_CF_DIRECTORY
53 | SHFL_CF_ACT_OPEN_IF_EXISTS
54 | SHFL_CF_ACCESS_READ
55 ;
56
57 rc = vboxCallCreate (&client_handle, &sf_g->map, sf_i->path, &params);
58 if (VBOX_FAILURE (rc)) {
59 elog ("vboxCallCreate(%s) failed rc=%d\n",
60 sf_i->path->String.utf8, rc);
61 sf_dir_info_free (sf_d);
62 return -EPERM;
63 }
64
65 if (params.Result != SHFL_FILE_EXISTS) {
66 elog ("directory %s does not exist\n", sf_i->path->String.utf8);
67 sf_dir_info_free (sf_d);
68 return -ENOENT;
69 }
70
71 err = sf_dir_read_all (sf_g, sf_i, sf_d, params.Handle);
72 if (err) {
73 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
74 if (VBOX_FAILURE (rc)) {
75 elog ("vboxCallClose(%s) after err=%d failed rc=%d\n",
76 sf_i->path->String.utf8, err, rc);
77 }
78 sf_dir_info_free (sf_d);
79 return err;
80 }
81
82
83 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
84 if (VBOX_FAILURE (rc)) {
85 elog ("vboxCallClose(%s) failed rc=%d\n",
86 sf_i->path->String.utf8, rc);
87 }
88
89 file->private_data = sf_d;
90 return 0;
91}
92
93/* This is called when reference count of [file] goes to zero. Notify
94 the host that it can free whatever is associated with this
95 directory and deallocate our own internal buffers */
96static int
97sf_dir_release (struct inode *inode, struct file *file)
98{
99 struct sf_inode_info *sf_i = GET_INODE_INFO (inode);
100
101 TRACE ();
102 BUG_ON (!sf_i);
103
104 if (file->private_data) {
105 sf_dir_info_free (file->private_data);
106 }
107 return 0;
108}
109
110/* Extract element ([dir]->f_pos) from the directory [dir] into
111 [d_name], return:
112 0 all ok
113 1 end reached
114 -errno some form of error*/
115int
116sf_getdent (struct file *dir, char d_name[NAME_MAX])
117{
118 loff_t cur;
119 struct sf_glob_info *sf_g;
120 struct sf_dir_info *sf_d;
121 struct list_head *pos, *list;
122
123 TRACE ();
124 sf_g = GET_GLOB_INFO (dir->f_dentry->d_inode->i_sb);
125 sf_d = dir->private_data;
126
127 BUG_ON (!sf_g);
128 BUG_ON (!sf_d);
129
130 cur = 0;
131 list = &sf_d->info_list;
132 list_for_each (pos, list) {
133 struct sf_dir_buf *b;
134 SHFLDIRINFO *info;
135 loff_t i;
136 size_t name_len;
137 char *name_ptr;
138
139 b = list_entry (pos, struct sf_dir_buf, head);
140 if (dir->f_pos >= cur + b->nb_entries) {
141 cur += b->nb_entries;
142 continue;
143 }
144
145 for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i) {
146 size_t size;
147
148 size = offsetof (SHFLDIRINFO, name.String) + info->name.u16Size;
149 info = (SHFLDIRINFO *) ((uintptr_t) info + size);
150 }
151
152 name_ptr = info->name.String.utf8;
153 name_len = info->name.u16Length;
154
155 return sf_nlscpy (sf_g, d_name, NAME_MAX, name_ptr, name_len);
156 }
157 return 1;
158}
159
160/* This is called when vfs wants to populate internal buffers with
161 directory [dir]s contents. [opaque] is an argument to the
162 [filldir]. [filldir] magically modifies it's argument - [opaque]
163 and takes following additional arguments (which i in turn get from
164 the host via sf_getdent):
165
166 name : name of the entry (i must also supply it's length huh?)
167 type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
168 pos : position/index of the entry
169 ino : inode number of the entry (i fake those)
170
171 [dir] contains:
172 f_pos : cursor into the directory listing
173 private_data : mean of communcation with the host side
174
175 Extract elements from the directory listing (incrementing f_pos
176 along the way) and feed them to [filldir] until:
177
178 a. there are no more entries (i.e. sf_getdent set done to 1)
179 b. failure to compute fake inode number
180 c. filldir returns an error (see comment on that) */
181static int
182sf_dir_read (struct file *dir, void *opaque, filldir_t filldir)
183{
184 TRACE ();
185 for (;;) {
186 int err;
187 ino_t fake_ino;
188 loff_t sanity;
189 char d_name[NAME_MAX];
190
191 err = sf_getdent (dir, d_name);
192 switch (err) {
193 case 1:
194 return 0;
195
196 case 0:
197 break;
198
199 case -1:
200 default:
201 /* skip erroneous entry and proceed */
202 elog ("sf_getdent error %d\n", err);
203 dir->f_pos += 1;
204 continue;
205 }
206
207 /* d_name now contains valid entry name */
208
209 sanity = dir->f_pos + 0xbeef;
210 fake_ino = sanity;
211 if (sanity - fake_ino) {
212 elog2 ("can not compute ino\n");
213 return -EINVAL;
214 }
215
216 err = filldir (opaque, d_name, strlen (d_name),
217 dir->f_pos, fake_ino, DT_UNKNOWN);
218 if (err) {
219 DBGC elog ("filldir returned error %d\n", err);
220 /* Rely on the fact that filldir returns error
221 only when it runs out of space in opaque */
222 return 0;
223 }
224
225 dir->f_pos += 1;
226 }
227
228 BUG ();
229}
230
231static struct file_operations sf_dir_fops = {
232 .open = sf_dir_open,
233 .readdir = sf_dir_read,
234 .release = sf_dir_release,
235 .read = generic_read_dir
236};
237
238
239/* iops */
240
241/* This is called when vfs failed to locate dentry in the cache. The
242 job of this function is to allocate inode and link it to dentry.
243 [dentry] contains the name to be looked in the [parent] directory.
244 Failure to locate the name is not a "hard" error, in this case NULL
245 inode is added to [dentry] and vfs should proceed trying to create
246 the entry via other means. NULL(or "positive" pointer) ought to be
247 returned in case of succes and "negative" pointer on error */
248static struct dentry *
249sf_lookup (struct inode *parent, struct dentry *dentry
250#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
251 , struct nameidata *nd
252#endif
253 )
254{
255 int err;
256 struct sf_inode_info *sf_i, *sf_new_i;
257 struct sf_glob_info *sf_g;
258 SHFLSTRING *path;
259 struct inode *inode;
260 ino_t ino;
261 RTFSOBJINFO fsinfo;
262
263 TRACE ();
264 sf_g = GET_GLOB_INFO (parent->i_sb);
265 sf_i = GET_INODE_INFO (parent);
266
267 BUG_ON (!sf_g);
268 BUG_ON (!sf_i);
269
270 err = sf_path_from_dentry (__func__, sf_g, sf_i, dentry, &path);
271 if (err) {
272 goto fail0;
273 }
274
275 err = sf_stat (__func__, sf_g, path, &fsinfo, 1);
276 if (err) {
277 if (err == -ENOENT) {
278 /* -ENOENT add NULL inode to dentry so it later can be
279 created via call to create/mkdir/open */
280 inode = NULL;
281 }
282 else goto fail1;
283 }
284 else {
285 sf_new_i = kmalloc (sizeof (*sf_new_i), GFP_KERNEL);
286 if (!sf_new_i) {
287 elog2 ("could not allocate memory for new inode info\n");
288 err = -ENOMEM;
289 goto fail1;
290 }
291
292 ino = iunique (parent->i_sb, 1);
293 inode = iget (parent->i_sb, ino);
294 if (!inode) {
295 elog2 ("iget failed\n");
296 err = -ENOMEM; /* XXX: ??? */
297 goto fail2;
298 }
299
300 SET_INODE_INFO (inode, sf_new_i);
301 sf_init_inode (sf_g, inode, &fsinfo);
302 sf_new_i->path = path;
303 }
304
305 sf_i->force_restat = 0;
306 dentry->d_time = jiffies;
307 dentry->d_op = &sf_dentry_ops;
308 d_add (dentry, inode);
309 return NULL;
310
311 fail2:
312 kfree (sf_new_i);
313 fail1:
314 kfree (path);
315 fail0:
316 return ERR_PTR (err);
317}
318
319/* This should allocate memory for sf_inode_info, compute unique inode
320 number, get an inode from vfs, initialize inode info, instantiate
321 dentry */
322static int
323sf_instantiate (const char *caller, struct inode *parent,
324 struct dentry *dentry, SHFLSTRING *path,
325 RTFSOBJINFO *info)
326{
327 int err;
328 ino_t ino;
329 struct inode *inode;
330 struct sf_inode_info *sf_new_i;
331 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
332
333 TRACE ();
334 BUG_ON (!sf_g);
335
336 sf_new_i = kmalloc (sizeof (*sf_new_i), GFP_KERNEL);
337 if (!sf_new_i) {
338 elog3 ("%s: %s: could not allocate inode info\n",
339 caller, __func__);
340 err = -ENOMEM;
341 goto fail0;
342 }
343
344 ino = iunique (parent->i_sb, 1);
345 inode = iget (parent->i_sb, ino);
346 if (!inode) {
347 elog3 ("%s: %s: iget failed\n", caller, __func__);
348 err = -ENOMEM;
349 goto fail1;
350 }
351
352 sf_init_inode (sf_g, inode, info);
353 sf_new_i->path = path;
354 SET_INODE_INFO (inode, sf_new_i);
355
356 dentry->d_time = jiffies;
357 dentry->d_op = &sf_dentry_ops;
358 sf_new_i->force_restat = 1;
359
360 d_instantiate (dentry, inode);
361 return 0;
362
363 fail1:
364 kfree (sf_new_i);
365 fail0:
366 return err;
367
368}
369
370static int
371sf_create_aux (struct inode *parent, struct dentry *dentry, int dirop)
372{
373 int rc, err;
374 SHFLCREATEPARMS params;
375 SHFLSTRING *path;
376 struct sf_inode_info *sf_i = GET_INODE_INFO (parent);
377 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
378
379 TRACE ();
380 BUG_ON (!sf_i);
381 BUG_ON (!sf_g);
382
383#if 0
384 printk ("create_aux %s/%s\n", sf_i->path->String.utf8,
385 dentry->d_name.name);
386#endif
387
388 params.CreateFlags = 0
389 | SHFL_CF_ACT_CREATE_IF_NEW
390 | SHFL_CF_ACT_OVERWRITE_IF_EXISTS
391 | SHFL_CF_ACCESS_READWRITE
392 | (dirop ? SHFL_CF_DIRECTORY : 0)
393 ;
394
395 params.Info.Attr.fMode = 0
396 | (dirop ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
397 | RTFS_UNIX_IRUSR
398 | RTFS_UNIX_IWUSR
399 | RTFS_UNIX_IXUSR
400 ;
401
402 params.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
403
404 err = sf_path_from_dentry (__func__, sf_g, sf_i, dentry, &path);
405 if (err) {
406 goto fail0;
407 }
408
409 rc = vboxCallCreate (&client_handle, &sf_g->map, path, &params);
410 if (VBOX_FAILURE (rc)) {
411 err = -EPROTO;
412 elog ("(%d): vboxCallCreate(%s) failed rc=%d\n", dirop,
413 sf_i->path->String.utf8, rc);
414 goto fail0;
415 }
416
417 if (params.Result != SHFL_FILE_CREATED) {
418 err = -EPERM;
419 elog ("(%d): could not create file %s result=%d\n", dirop,
420 sf_i->path->String.utf8, params.Result);
421 goto fail0;
422 }
423
424 err = sf_instantiate (__func__, parent, dentry, path, &params.Info);
425 if (err) {
426 elog ("(%d): could not instantiate dentry for %s err=%d\n",
427 dirop, sf_i->path->String.utf8, err);
428 goto fail1;
429 }
430
431 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
432 if (VBOX_FAILURE (rc)) {
433 elog ("(%d): vboxCallClose failed rc=%d\n", dirop, rc);
434 }
435
436 sf_i->force_restat = 1;
437 return 0;
438
439 fail1:
440 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
441 if (VBOX_FAILURE (rc)) {
442 elog ("(%d): vboxCallClose failed rc=%d\n", dirop, rc);
443 }
444
445 fail0:
446 kfree (path);
447 return err;
448}
449
450static int
451sf_create (struct inode *parent, struct dentry *dentry, int mode
452#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
453 , struct nameidata *nd
454#endif
455 )
456{
457 TRACE ();
458 return sf_create_aux (parent, dentry, 0);
459}
460
461static int
462sf_mkdir (struct inode *parent, struct dentry *dentry, int mode)
463{
464 TRACE ();
465 return sf_create_aux (parent, dentry, 1);
466}
467
468static int
469sf_unlink_aux (struct inode *parent, struct dentry *dentry, int dirop)
470{
471 int rc, err;
472 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
473 struct sf_inode_info *sf_i = GET_INODE_INFO (parent);
474 SHFLSTRING *path;
475
476 TRACE ();
477 BUG_ON (!sf_g);
478
479 err = sf_path_from_dentry (__func__, sf_g, sf_i, dentry, &path);
480 if (err) {
481 goto fail0;
482 }
483
484 rc = vboxCallRemove (&client_handle, &sf_g->map, path,
485 dirop ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE);
486 if (VBOX_FAILURE (rc)) {
487 DBGC elog ("(%d): vboxCallRemove(%s) failed rc=%d\n", dirop,
488 path->String.utf8, rc);
489
490 switch (rc) {
491 case VERR_PATH_NOT_FOUND:
492 err = -ENOENT;
493 break;
494
495 case VERR_DIR_NOT_EMPTY:
496 err = -ENOTEMPTY;
497 break;
498
499 default:
500 err = -EPROTO;
501 elog ("(%d): vboxCallRemove(%s) failed rc=%d\n", dirop,
502 path->String.utf8, rc);
503 break;
504 }
505 goto fail1;
506 }
507
508 kfree (path);
509 return 0;
510
511 fail1:
512 kfree (path);
513 fail0:
514 return err;
515}
516
517static int
518sf_unlink (struct inode *parent, struct dentry *dentry)
519{
520 TRACE ();
521 return sf_unlink_aux (parent, dentry, 0);
522}
523
524static int
525sf_rmdir (struct inode *parent, struct dentry *dentry)
526{
527 TRACE ();
528 return sf_unlink_aux (parent, dentry, 1);
529}
530
531static int
532sf_rename (struct inode *old_parent, struct dentry *old_dentry,
533 struct inode *new_parent, struct dentry *new_dentry)
534{
535 int err, rc;
536 struct sf_glob_info *sf_g = GET_GLOB_INFO (old_parent->i_sb);
537 struct sf_inode_info *sf_old_i = GET_INODE_INFO (old_parent);
538 struct sf_inode_info *sf_new_i = GET_INODE_INFO (new_parent);
539 SHFLSTRING *old_path;
540 SHFLSTRING *new_path;
541
542 TRACE ();
543 BUG_ON (!sf_old_i);
544 BUG_ON (!sf_new_i);
545
546 if (sf_g != GET_GLOB_INFO (new_parent->i_sb)) {
547 elog2 ("rename with different roots\n");
548 return -EINVAL;
549 }
550
551 err = sf_path_from_dentry (__func__, sf_g, sf_old_i,
552 old_dentry, &old_path);
553 if (err) {
554 elog2 ("failed to create old path\n");
555 return err;
556 }
557
558 err = sf_path_from_dentry (__func__, sf_g, sf_new_i,
559 new_dentry, &new_path);
560 if (err) {
561 elog2 ("failed to create new path\n");
562 goto fail0;
563 }
564
565 rc = vboxCallRename (&client_handle, &sf_g->map, old_path,
566 new_path, SHFL_RENAME_FILE);
567 if (VBOX_FAILURE (rc)) {
568 switch (rc) {
569 case VERR_FILE_NOT_FOUND:
570 case VERR_PATH_NOT_FOUND:
571 err = -ENOENT;
572 goto fail1;
573
574 default:
575 err = -EPROTO;
576 elog ("vboxCallRename failed rc=%d\n", rc);
577 goto fail1;
578 }
579 }
580
581 err = 0;
582
583 sf_new_i->force_restat = 1;
584 sf_old_i->force_restat = 1; /* XXX: needed? */
585 fail1:
586 kfree (old_path);
587 fail0:
588 kfree (new_path);
589 return err;
590}
591
592static struct inode_operations sf_dir_iops = {
593 .lookup = sf_lookup,
594 .create = sf_create,
595 .mkdir = sf_mkdir,
596 .rmdir = sf_rmdir,
597 .unlink = sf_unlink,
598 .rename = sf_rename,
599#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
600 .revalidate = sf_inode_revalidate
601#else
602 .getattr = sf_getattr
603#endif
604};
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