VirtualBox

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

Last change on this file since 20298 was 20298, checked in by vboxsync, 16 years ago

Linux shared folders: properly initialize the whole params !VBoxCall() structure including the attributes

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