VirtualBox

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

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

attempt to fix vfsmod for Linux >= 2.6.25

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.7 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#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 4, 25)
295 inode = iget_locked (parent->i_sb, ino);
296#else
297 inode = iget (parent->i_sb, ino);
298#endif
299 if (!inode) {
300 LogFunc(("iget failed\n"));
301 err = -ENOMEM; /* XXX: ??? */
302 goto fail2;
303 }
304
305 SET_INODE_INFO (inode, sf_new_i);
306 sf_init_inode (sf_g, inode, &fsinfo);
307 sf_new_i->path = path;
308
309#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 4, 25)
310 unlock_new_inode(inode);
311#endif
312 }
313
314 sf_i->force_restat = 0;
315 dentry->d_time = jiffies;
316 dentry->d_op = &sf_dentry_ops;
317 d_add (dentry, inode);
318 return NULL;
319
320 fail2:
321 kfree (sf_new_i);
322 fail1:
323 kfree (path);
324 fail0:
325 return ERR_PTR (err);
326}
327
328/* This should allocate memory for sf_inode_info, compute unique inode
329 number, get an inode from vfs, initialize inode info, instantiate
330 dentry */
331static int
332sf_instantiate (const char *caller, struct inode *parent,
333 struct dentry *dentry, SHFLSTRING *path,
334 RTFSOBJINFO *info)
335{
336 int err;
337 ino_t ino;
338 struct inode *inode;
339 struct sf_inode_info *sf_new_i;
340 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
341
342 TRACE ();
343 BUG_ON (!sf_g);
344
345 sf_new_i = kmalloc (sizeof (*sf_new_i), GFP_KERNEL);
346 if (!sf_new_i) {
347 LogRelFunc(("could not allocate inode info. caller=%s\n", caller));
348 err = -ENOMEM;
349 goto fail0;
350 }
351
352 ino = iunique (parent->i_sb, 1);
353#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 4, 25)
354 inode = iget_locked (parent->i_sb, ino);
355#else
356 inode = iget (parent->i_sb, ino);
357#endif
358 if (!inode) {
359 LogFunc(("iget failed. caller=%s\n", caller));
360 err = -ENOMEM;
361 goto fail1;
362 }
363
364 sf_init_inode (sf_g, inode, info);
365 sf_new_i->path = path;
366 SET_INODE_INFO (inode, sf_new_i);
367
368 dentry->d_time = jiffies;
369 dentry->d_op = &sf_dentry_ops;
370 sf_new_i->force_restat = 1;
371
372 d_instantiate (dentry, inode);
373
374#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 4, 25)
375 unlock_new_inode(inode);
376#endif
377
378 return 0;
379
380 fail1:
381 kfree (sf_new_i);
382 fail0:
383 return err;
384
385}
386
387static int
388sf_create_aux (struct inode *parent, struct dentry *dentry, int dirop)
389{
390 int rc, err;
391 SHFLCREATEPARMS params;
392 SHFLSTRING *path;
393 struct sf_inode_info *sf_i = GET_INODE_INFO (parent);
394 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
395
396 TRACE ();
397 BUG_ON (!sf_i);
398 BUG_ON (!sf_g);
399
400#if 0
401 printk ("create_aux %s/%s\n", sf_i->path->String.utf8,
402 dentry->d_name.name);
403#endif
404
405 params.CreateFlags = 0
406 | SHFL_CF_ACT_CREATE_IF_NEW
407 | SHFL_CF_ACT_FAIL_IF_EXISTS
408 | SHFL_CF_ACCESS_READWRITE
409 | (dirop ? SHFL_CF_DIRECTORY : 0)
410 ;
411
412 params.Info.Attr.fMode = 0
413 | (dirop ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
414 | RTFS_UNIX_IRUSR
415 | RTFS_UNIX_IWUSR
416 | RTFS_UNIX_IXUSR
417 ;
418
419 params.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
420
421 err = sf_path_from_dentry (__func__, sf_g, sf_i, dentry, &path);
422 if (err) {
423 goto fail0;
424 }
425
426 LogFunc(("calling vboxCallCreate, folder %s, flags %#x\n",
427 path->String.utf8, params.CreateFlags));
428 rc = vboxCallCreate (&client_handle, &sf_g->map, path, &params);
429 if (VBOX_FAILURE (rc)) {
430 if (rc == VERR_WRITE_PROTECT) {
431 err = -EROFS;
432 goto fail0;
433 }
434 err = -EPROTO;
435 LogFunc(("(%d): vboxCallCreate(%s) failed rc=%Vrc\n", dirop,
436 sf_i->path->String.utf8, rc));
437 goto fail0;
438 }
439
440 if (params.Result != SHFL_FILE_CREATED) {
441 err = -EPERM;
442 LogFunc(("(%d): could not create file %s result=%d\n", dirop,
443 sf_i->path->String.utf8, params.Result));
444 goto fail0;
445 }
446
447 err = sf_instantiate (__func__, parent, dentry, path, &params.Info);
448 if (err) {
449 LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
450 dirop, sf_i->path->String.utf8, err));
451 goto fail1;
452 }
453
454 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
455 if (VBOX_FAILURE (rc)) {
456 LogFunc(("(%d): vboxCallClose failed rc=%Vrc\n", dirop, rc));
457 }
458
459 sf_i->force_restat = 1;
460 return 0;
461
462 fail1:
463 rc = vboxCallClose (&client_handle, &sf_g->map, params.Handle);
464 if (VBOX_FAILURE (rc)) {
465 LogFunc(("(%d): vboxCallClose failed rc=%Vrc\n", dirop, rc));
466 }
467
468 fail0:
469 kfree (path);
470 return err;
471}
472
473static int
474sf_create (struct inode *parent, struct dentry *dentry, int mode
475#if LINUX_VERSION_CODE >= KERNEL_VERSION (2, 6, 0)
476 , struct nameidata *nd
477#endif
478 )
479{
480 TRACE ();
481 return sf_create_aux (parent, dentry, 0);
482}
483
484static int
485sf_mkdir (struct inode *parent, struct dentry *dentry, int mode)
486{
487 TRACE ();
488 return sf_create_aux (parent, dentry, 1);
489}
490
491static int
492sf_unlink_aux (struct inode *parent, struct dentry *dentry, int dirop)
493{
494 int rc, err;
495 struct sf_glob_info *sf_g = GET_GLOB_INFO (parent->i_sb);
496 struct sf_inode_info *sf_i = GET_INODE_INFO (parent);
497 SHFLSTRING *path;
498
499 TRACE ();
500 BUG_ON (!sf_g);
501
502 err = sf_path_from_dentry (__func__, sf_g, sf_i, dentry, &path);
503 if (err) {
504 goto fail0;
505 }
506
507 rc = vboxCallRemove (&client_handle, &sf_g->map, path,
508 dirop ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE);
509 if (VBOX_FAILURE (rc)) {
510 LogFunc(("(%d): vboxCallRemove(%s) failed rc=%Vrc\n", dirop,
511 path->String.utf8, rc));
512 err = -RTErrConvertToErrno (rc);
513 goto fail1;
514 }
515
516 kfree (path);
517 return 0;
518
519 fail1:
520 kfree (path);
521 fail0:
522 return err;
523}
524
525static int
526sf_unlink (struct inode *parent, struct dentry *dentry)
527{
528 TRACE ();
529 return sf_unlink_aux (parent, dentry, 0);
530}
531
532static int
533sf_rmdir (struct inode *parent, struct dentry *dentry)
534{
535 TRACE ();
536 return sf_unlink_aux (parent, dentry, 1);
537}
538
539static int
540sf_rename (struct inode *old_parent, struct dentry *old_dentry,
541 struct inode *new_parent, struct dentry *new_dentry)
542{
543 int err = 0, rc = VINF_SUCCESS;
544 struct sf_glob_info *sf_g = GET_GLOB_INFO (old_parent->i_sb);
545
546 TRACE ();
547
548 if (sf_g != GET_GLOB_INFO (new_parent->i_sb)) {
549 LogFunc(("rename with different roots\n"));
550 err = -EINVAL;
551 } else {
552 struct sf_inode_info *sf_old_i = GET_INODE_INFO (old_parent);
553 struct sf_inode_info *sf_new_i = GET_INODE_INFO (new_parent);
554 /* As we save the relative path inside the inode structure, we need to change
555 this if the rename is successful. */
556 struct sf_inode_info *sf_file_i = GET_INODE_INFO (old_dentry->d_inode);
557 SHFLSTRING *old_path;
558 SHFLSTRING *new_path;
559
560 BUG_ON (!sf_old_i);
561 BUG_ON (!sf_new_i);
562 BUG_ON (!sf_file_i);
563
564 old_path = sf_file_i->path;
565 err = sf_path_from_dentry (__func__, sf_g, sf_new_i,
566 new_dentry, &new_path);
567 if (err) {
568 LogFunc(("failed to create new path\n"));
569 } else {
570 int is_dir = ((old_dentry->d_inode->i_mode & S_IFDIR) != 0);
571
572 rc = vboxCallRename (&client_handle, &sf_g->map, old_path,
573 new_path, is_dir ? 0 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
574 if (RT_SUCCESS(rc)) {
575 kfree (old_path);
576 sf_new_i->force_restat = 1;
577 sf_old_i->force_restat = 1; /* XXX: needed? */
578 /* Set the new relative path in the inode. */
579 sf_file_i->path = new_path;
580 } else {
581 LogFunc(("vboxCallRename failed rc=%Vrc\n", rc));
582 err = -RTErrConvertToErrno (rc);
583 }
584 if (0 != err)
585 kfree (new_path);
586 }
587 }
588 return err;
589}
590
591struct inode_operations sf_dir_iops = {
592 .lookup = sf_lookup,
593 .create = sf_create,
594 .mkdir = sf_mkdir,
595 .rmdir = sf_rmdir,
596 .unlink = sf_unlink,
597 .rename = sf_rename,
598#if LINUX_VERSION_CODE < KERNEL_VERSION (2, 6, 0)
599 .revalidate = sf_inode_revalidate
600#else
601 .getattr = sf_getattr
602#endif
603};
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