VirtualBox

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

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

Small fix for file open parameter translation from Linux guest shared folders

  • 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-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 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
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 err = -EPROTO;
414 LogFunc(("(%d): vboxCallCreate(%s) failed rc=%Vrc\n", dirop,
415 sf_i->path->String.utf8, rc));
416 goto fail0;
417 }
418
419 if (params.Result != SHFL_FILE_CREATED) {
420 err = -EPERM;
421 LogFunc(("(%d): could not create file %s result=%d\n", dirop,
422 sf_i->path->String.utf8, params.Result));
423 goto fail0;
424 }
425
426 err = sf_instantiate (__func__, parent, dentry, path, &params.Info);
427 if (err) {
428 LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
429 dirop, sf_i->path->String.utf8, err));
430 goto fail1;
431 }
432
433 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
434 if (VBOX_FAILURE (rc)) {
435 LogFunc(("(%d): vboxCallClose failed rc=%Vrc\n", dirop, rc));
436 }
437
438 sf_i->force_restat = 1;
439 return 0;
440
441 fail1:
442 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
443 if (VBOX_FAILURE (rc)) {
444 LogFunc(("(%d): vboxCallClose failed rc=%Vrc\n", dirop, rc));
445 }
446
447 fail0:
448 kfree (path);
449 return err;
450}
451
452static int
453sf_create (struct inode *parent, struct dentry *dentry, int mode
454#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
455 , struct nameidata *nd
456#endif
457 )
458{
459 TRACE ();
460 return sf_create_aux (parent, dentry, 0);
461}
462
463static int
464sf_mkdir (struct inode *parent, struct dentry *dentry, int mode)
465{
466 TRACE ();
467 return sf_create_aux (parent, dentry, 1);
468}
469
470static int
471sf_unlink_aux (struct inode *parent, struct dentry *dentry, int dirop)
472{
473 int rc, err;
474 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
475 struct sf_inode_info *sf_i = GET_INODE_INFO (parent);
476 SHFLSTRING *path;
477
478 TRACE ();
479 BUG_ON (!sf_g);
480
481 err = sf_path_from_dentry (__func__, sf_g, sf_i, dentry, &path);
482 if (err) {
483 goto fail0;
484 }
485
486 rc = vboxCallRemove (&client_handle, &sf_g->map, path,
487 dirop ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE);
488 if (VBOX_FAILURE (rc)) {
489 LogFunc(("(%d): vboxCallRemove(%s) failed rc=%Vrc\n", dirop,
490 path->String.utf8, rc));
491 err = -RTErrConvertToErrno (rc);
492 goto fail1;
493 }
494
495 kfree (path);
496 return 0;
497
498 fail1:
499 kfree (path);
500 fail0:
501 return err;
502}
503
504static int
505sf_unlink (struct inode *parent, struct dentry *dentry)
506{
507 TRACE ();
508 return sf_unlink_aux (parent, dentry, 0);
509}
510
511static int
512sf_rmdir (struct inode *parent, struct dentry *dentry)
513{
514 TRACE ();
515 return sf_unlink_aux (parent, dentry, 1);
516}
517
518static int
519sf_rename (struct inode *old_parent, struct dentry *old_dentry,
520 struct inode *new_parent, struct dentry *new_dentry)
521{
522 int err = 0, rc = VINF_SUCCESS;
523 struct sf_glob_info *sf_g = GET_GLOB_INFO (old_parent->i_sb);
524
525 TRACE ();
526
527 if (sf_g != GET_GLOB_INFO (new_parent->i_sb)) {
528 LogFunc(("rename with different roots\n"));
529 err = -EINVAL;
530 } else {
531 struct sf_inode_info *sf_old_i = GET_INODE_INFO (old_parent);
532 struct sf_inode_info *sf_new_i = GET_INODE_INFO (new_parent);
533 /* As we save the relative path inside the inode structure, we need to change
534 this if the rename is successful. */
535 struct sf_inode_info *sf_file_i = GET_INODE_INFO (old_dentry->d_inode);
536 SHFLSTRING *old_path;
537 SHFLSTRING *new_path;
538
539 BUG_ON (!sf_old_i);
540 BUG_ON (!sf_new_i);
541 BUG_ON (!sf_file_i);
542
543 old_path = sf_file_i->path;
544 err = sf_path_from_dentry (__func__, sf_g, sf_new_i,
545 new_dentry, &new_path);
546 if (err) {
547 LogFunc(("failed to create new path\n"));
548 } else {
549 int is_dir = ((old_dentry->d_inode->i_mode & S_IFDIR) != 0);
550
551 rc = vboxCallRename (&client_handle, &sf_g->map, old_path,
552 new_path, is_dir ? 0 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
553 if (RT_SUCCESS(rc)) {
554 kfree (old_path);
555 sf_new_i->force_restat = 1;
556 sf_old_i->force_restat = 1; /* XXX: needed? */
557 /* Set the new relative path in the inode. */
558 sf_file_i->path = new_path;
559 } else {
560 LogFunc(("vboxCallRename failed rc=%Vrc\n", rc));
561 err = -RTErrConvertToErrno (err);
562 }
563 if (0 != err) {
564 kfree (new_path);
565 }
566 }
567 }
568 return err;
569}
570
571struct inode_operations sf_dir_iops = {
572 .lookup = sf_lookup,
573 .create = sf_create,
574 .mkdir = sf_mkdir,
575 .rmdir = sf_rmdir,
576 .unlink = sf_unlink,
577 .rename = sf_rename,
578#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
579 .revalidate = sf_inode_revalidate
580#else
581 .getattr = sf_getattr
582#endif
583};
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