VirtualBox

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

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

Biggest check-in ever. New source code headers for all (C) innotek files.

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