VirtualBox

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

Last change on this file since 28253 was 28253, checked in by vboxsync, 15 years ago

SharedFolders/linux: Don't close an inode for a regular file after it was created with sf_create(). We assume that this inode will be opened with sf_reg_open() and later closed with sf_reg_close(). Fixes copying of read-only files on shared folders.

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