VirtualBox

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

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

style

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