VirtualBox

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

Last change on this file since 48226 was 47588, checked in by vboxsync, 12 years ago

Additions/linux/sharefolders: fix for Linux 3.11+ (thanks Azat Khuzhin)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.6 KB
Line 
1/** @file
2 *
3 * vboxsf -- VirtualBox Guest Additions for Linux:
4 * Directory inode and file operations
5 */
6
7/*
8 * Copyright (C) 2006-2012 Oracle Corporation
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
21/**
22 * Open a directory. Read the complete content into a buffer.
23 *
24 * @param inode inode
25 * @param file file
26 * @returns 0 on success, Linux error code otherwise
27 */
28static int sf_dir_open(struct inode *inode, struct file *file)
29{
30 int rc;
31 int err;
32 struct sf_glob_info *sf_g = GET_GLOB_INFO(inode->i_sb);
33 struct sf_dir_info *sf_d;
34 struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
35 SHFLCREATEPARMS params;
36
37 TRACE();
38 BUG_ON(!sf_g);
39 BUG_ON(!sf_i);
40
41 if (file->private_data)
42 {
43 LogFunc(("sf_dir_open() called on already opened directory '%s'\n",
44 sf_i->path->String.utf8));
45 return 0;
46 }
47
48 sf_d = sf_dir_info_alloc();
49 if (!sf_d)
50 {
51 LogRelFunc(("could not allocate directory info for '%s'\n",
52 sf_i->path->String.utf8));
53 return -ENOMEM;
54 }
55
56 RT_ZERO(params);
57 params.Handle = SHFL_HANDLE_NIL;
58 params.CreateFlags = 0
59 | SHFL_CF_DIRECTORY
60 | SHFL_CF_ACT_OPEN_IF_EXISTS
61 | SHFL_CF_ACT_FAIL_IF_NEW
62 | SHFL_CF_ACCESS_READ
63 ;
64
65 LogFunc(("sf_dir_open(): calling vboxCallCreate, folder %s, flags %#x\n",
66 sf_i->path->String.utf8, params.CreateFlags));
67 rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, &params);
68 if (RT_SUCCESS(rc))
69 {
70 if (params.Result == SHFL_FILE_EXISTS)
71 {
72 err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle);
73 if (!err)
74 file->private_data = sf_d;
75 }
76 else
77 err = -ENOENT;
78
79 rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
80 if (RT_FAILURE(rc))
81 LogFunc(("sf_dir_open(): vboxCallClose(%s) after err=%d failed rc=%Rrc\n",
82 sf_i->path->String.utf8, err, rc));
83 }
84 else
85 err = -EPERM;
86
87 if (err)
88 sf_dir_info_free(sf_d);
89
90 return err;
91}
92
93
94/**
95 * This is called when reference count of [file] goes to zero. Notify
96 * the host that it can free whatever is associated with this directory
97 * and deallocate our own internal buffers
98 *
99 * @param inode inode
100 * @param file file
101 * returns 0 on success, Linux error code otherwise
102 */
103static int sf_dir_release(struct inode *inode, struct file *file)
104{
105 TRACE();
106
107 if (file->private_data)
108 sf_dir_info_free(file->private_data);
109
110 return 0;
111}
112
113/**
114 * Extract element ([dir]->f_pos) from the directory [dir] into [d_name].
115 *
116 * @returns 0 for success, 1 for end reached, Linux error code otherwise.
117 */
118static int sf_getdent(struct file *dir, char d_name[NAME_MAX])
119{
120 loff_t cur;
121 struct sf_glob_info *sf_g;
122 struct sf_dir_info *sf_d;
123 struct sf_inode_info *sf_i;
124 struct inode *inode;
125 struct list_head *pos, *list;
126
127 TRACE();
128
129 sf_g = GET_GLOB_INFO(dir->f_dentry->d_inode->i_sb);
130 sf_d = dir->private_data;
131
132 BUG_ON(!sf_g);
133 BUG_ON(!sf_d);
134
135 inode = dir->f_dentry->d_inode;
136 sf_i = GET_INODE_INFO(inode);
137
138 BUG_ON(!sf_i);
139
140 if (sf_i->force_reread)
141 {
142 int rc;
143 int err;
144 SHFLCREATEPARMS params;
145
146 RT_ZERO(params);
147 params.Handle = SHFL_HANDLE_NIL;
148 params.CreateFlags = 0
149 | SHFL_CF_DIRECTORY
150 | SHFL_CF_ACT_OPEN_IF_EXISTS
151 | SHFL_CF_ACT_FAIL_IF_NEW
152 | SHFL_CF_ACCESS_READ
153 ;
154
155 LogFunc(("sf_getdent: calling vboxCallCreate, folder %s, flags %#x\n",
156 sf_i->path->String.utf8, params.CreateFlags));
157 rc = vboxCallCreate(&client_handle, &sf_g->map, sf_i->path, &params);
158 if (RT_FAILURE(rc))
159 {
160 LogFunc(("vboxCallCreate(%s) failed rc=%Rrc\n",
161 sf_i->path->String.utf8, rc));
162 return -EPERM;
163 }
164
165 if (params.Result != SHFL_FILE_EXISTS)
166 {
167 LogFunc(("directory %s does not exist\n", sf_i->path->String.utf8));
168 sf_dir_info_free(sf_d);
169 return -ENOENT;
170 }
171
172 sf_dir_info_empty(sf_d);
173 err = sf_dir_read_all(sf_g, sf_i, sf_d, params.Handle);
174 rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
175 if (RT_FAILURE(rc))
176 LogFunc(("vboxCallClose(%s) failed rc=%Rrc\n", sf_i->path->String.utf8, rc));
177 if (err)
178 return err;
179
180 sf_i->force_reread = 0;
181 }
182
183 cur = 0;
184 list = &sf_d->info_list;
185 list_for_each(pos, list)
186 {
187 struct sf_dir_buf *b;
188 SHFLDIRINFO *info;
189 loff_t i;
190
191 b = list_entry(pos, struct sf_dir_buf, head);
192 if (dir->f_pos >= cur + b->cEntries)
193 {
194 cur += b->cEntries;
195 continue;
196 }
197
198 for (i = 0, info = b->buf; i < dir->f_pos - cur; ++i)
199 {
200 size_t size;
201
202 size = offsetof(SHFLDIRINFO, name.String) + info->name.u16Size;
203 info = (SHFLDIRINFO *) ((uintptr_t) info + size);
204 }
205
206 return sf_nlscpy(sf_g, d_name, NAME_MAX,
207 info->name.String.utf8, info->name.u16Length);
208 }
209
210 return 1;
211}
212
213/**
214 * This is called when vfs wants to populate internal buffers with
215 * directory [dir]s contents. [opaque] is an argument to the
216 * [filldir]. [filldir] magically modifies it's argument - [opaque]
217 * and takes following additional arguments (which i in turn get from
218 * the host via sf_getdent):
219 *
220 * name : name of the entry (i must also supply it's length huh?)
221 * type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
222 * pos : position/index of the entry
223 * ino : inode number of the entry (i fake those)
224 *
225 * [dir] contains:
226 * f_pos : cursor into the directory listing
227 * private_data : mean of communication with the host side
228 *
229 * Extract elements from the directory listing (incrementing f_pos
230 * along the way) and feed them to [filldir] until:
231 *
232 * a. there are no more entries (i.e. sf_getdent set done to 1)
233 * b. failure to compute fake inode number
234 * c. filldir returns an error (see comment on that)
235 */
236#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
237static int sf_dir_iterate(struct file *dir, struct dir_context *ctx)
238#else
239static int sf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
240#endif
241{
242 TRACE();
243 for (;;)
244 {
245 int err;
246 ino_t fake_ino;
247 loff_t sanity;
248 char d_name[NAME_MAX];
249
250 err = sf_getdent(dir, d_name);
251 switch (err)
252 {
253 case 1:
254 return 0;
255
256 case 0:
257 break;
258
259 case -1:
260 default:
261 /* skip erroneous entry and proceed */
262 LogFunc(("sf_getdent error %d\n", err));
263 dir->f_pos += 1;
264#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
265 ctx->pos += 1;
266#endif
267 continue;
268 }
269
270 /* d_name now contains a valid entry name */
271
272#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
273 sanity = ctx->pos + 0xbeef;
274#else
275 sanity = dir->f_pos + 0xbeef;
276#endif
277 fake_ino = sanity;
278 if (sanity - fake_ino)
279 {
280 LogRelFunc(("can not compute ino\n"));
281 return -EINVAL;
282 }
283
284#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
285 err = dir_emit(ctx, d_name, strlen(d_name), fake_ino, DT_UNKNOWN);
286#else
287 err = filldir(opaque, d_name, strlen(d_name), dir->f_pos, fake_ino, DT_UNKNOWN);
288#endif
289 if (err)
290 {
291 LogFunc(("filldir returned error %d\n", err));
292 /* Rely on the fact that filldir returns error
293 only when it runs out of space in opaque */
294 return 0;
295 }
296
297 dir->f_pos += 1;
298#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
299 ctx->pos += 1;
300#endif
301 }
302
303 BUG();
304}
305
306struct file_operations sf_dir_fops =
307{
308 .open = sf_dir_open,
309#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
310 .iterate = sf_dir_iterate,
311#else
312 .readdir = sf_dir_read,
313#endif
314 .release = sf_dir_release,
315 .read = generic_read_dir
316#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
317 , .llseek = generic_file_llseek
318#endif
319};
320
321
322/* iops */
323
324/**
325 * This is called when vfs failed to locate dentry in the cache. The
326 * job of this function is to allocate inode and link it to dentry.
327 * [dentry] contains the name to be looked in the [parent] directory.
328 * Failure to locate the name is not a "hard" error, in this case NULL
329 * inode is added to [dentry] and vfs should proceed trying to create
330 * the entry via other means. NULL(or "positive" pointer) ought to be
331 * returned in case of success and "negative" pointer on error
332 */
333static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry
334#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
335 , unsigned int flags
336#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
337 , struct nameidata *nd
338#endif
339 )
340{
341 int err;
342 struct sf_inode_info *sf_i, *sf_new_i;
343 struct sf_glob_info *sf_g;
344 SHFLSTRING *path;
345 struct inode *inode;
346 ino_t ino;
347 SHFLFSOBJINFO fsinfo;
348
349 TRACE();
350 sf_g = GET_GLOB_INFO(parent->i_sb);
351 sf_i = GET_INODE_INFO(parent);
352
353 BUG_ON(!sf_g);
354 BUG_ON(!sf_i);
355
356 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
357 if (err)
358 goto fail0;
359
360 err = sf_stat(__func__, sf_g, path, &fsinfo, 1);
361 if (err)
362 {
363 if (err == -ENOENT)
364 {
365 /* -ENOENT: add NULL inode to dentry so it later can be
366 created via call to create/mkdir/open */
367 kfree(path);
368 inode = NULL;
369 }
370 else
371 goto fail1;
372 }
373 else
374 {
375 sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
376 if (!sf_new_i)
377 {
378 LogRelFunc(("could not allocate memory for new inode info\n"));
379 err = -ENOMEM;
380 goto fail1;
381 }
382 sf_new_i->handle = SHFL_HANDLE_NIL;
383 sf_new_i->force_reread = 0;
384
385 ino = iunique(parent->i_sb, 1);
386#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
387 inode = iget_locked(parent->i_sb, ino);
388#else
389 inode = iget(parent->i_sb, ino);
390#endif
391 if (!inode)
392 {
393 LogFunc(("iget failed\n"));
394 err = -ENOMEM; /* XXX: ??? */
395 goto fail2;
396 }
397
398 SET_INODE_INFO(inode, sf_new_i);
399 sf_init_inode(sf_g, inode, &fsinfo);
400 sf_new_i->path = path;
401
402#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
403 unlock_new_inode(inode);
404#endif
405 }
406
407 sf_i->force_restat = 0;
408 dentry->d_time = jiffies;
409#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
410 d_set_d_op(dentry, &sf_dentry_ops);
411#else
412 dentry->d_op = &sf_dentry_ops;
413#endif
414 d_add(dentry, inode);
415 return NULL;
416
417fail2:
418 kfree(sf_new_i);
419
420fail1:
421 kfree(path);
422
423fail0:
424 return ERR_PTR(err);
425}
426
427/**
428 * This should allocate memory for sf_inode_info, compute a unique inode
429 * number, get an inode from vfs, initialize inode info, instantiate
430 * dentry.
431 *
432 * @param parent inode entry of the directory
433 * @param dentry directory cache entry
434 * @param path path name
435 * @param info file information
436 * @param handle handle
437 * @returns 0 on success, Linux error code otherwise
438 */
439static int sf_instantiate(struct inode *parent, struct dentry *dentry,
440 SHFLSTRING *path, PSHFLFSOBJINFO info, SHFLHANDLE handle)
441{
442 int err;
443 ino_t ino;
444 struct inode *inode;
445 struct sf_inode_info *sf_new_i;
446 struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
447
448 TRACE();
449 BUG_ON(!sf_g);
450
451 sf_new_i = kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
452 if (!sf_new_i)
453 {
454 LogRelFunc(("could not allocate inode info.\n"));
455 err = -ENOMEM;
456 goto fail0;
457 }
458
459 ino = iunique(parent->i_sb, 1);
460#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
461 inode = iget_locked(parent->i_sb, ino);
462#else
463 inode = iget(parent->i_sb, ino);
464#endif
465 if (!inode)
466 {
467 LogFunc(("iget failed\n"));
468 err = -ENOMEM;
469 goto fail1;
470 }
471
472 sf_init_inode(sf_g, inode, info);
473 sf_new_i->path = path;
474 SET_INODE_INFO(inode, sf_new_i);
475 sf_new_i->force_restat = 1;
476 sf_new_i->force_reread = 0;
477
478 d_instantiate(dentry, inode);
479
480#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
481 unlock_new_inode(inode);
482#endif
483
484 /* Store this handle if we leave the handle open. */
485 sf_new_i->handle = handle;
486 return 0;
487
488fail1:
489 kfree(sf_new_i);
490
491fail0:
492 return err;
493
494}
495
496/**
497 * Create a new regular file / directory.
498 *
499 * @param parent inode of the directory
500 * @param dentry directory cache entry
501 * @param mode file mode
502 * @param fDirectory true if directory, false otherwise
503 * @returns 0 on success, Linux error code otherwise
504 */
505static int sf_create_aux(struct inode *parent, struct dentry *dentry,
506 umode_t mode, int fDirectory)
507{
508 int rc, err;
509 SHFLCREATEPARMS params;
510 SHFLSTRING *path;
511 struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
512 struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
513
514 TRACE();
515 BUG_ON(!sf_i);
516 BUG_ON(!sf_g);
517
518 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
519 if (err)
520 goto fail0;
521
522 RT_ZERO(params);
523 params.Handle = SHFL_HANDLE_NIL;
524 params.CreateFlags = 0
525 | SHFL_CF_ACT_CREATE_IF_NEW
526 | SHFL_CF_ACT_FAIL_IF_EXISTS
527 | SHFL_CF_ACCESS_READWRITE
528 | (fDirectory ? SHFL_CF_DIRECTORY : 0)
529 ;
530 params.Info.Attr.fMode = 0
531 | (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
532 | (mode & S_IRWXUGO)
533 ;
534 params.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
535
536 LogFunc(("sf_create_aux: calling vboxCallCreate, folder %s, flags %#x\n",
537 path->String.utf8, params.CreateFlags));
538 rc = vboxCallCreate(&client_handle, &sf_g->map, path, &params);
539 if (RT_FAILURE(rc))
540 {
541 if (rc == VERR_WRITE_PROTECT)
542 {
543 err = -EROFS;
544 goto fail1;
545 }
546 err = -EPROTO;
547 LogFunc(("(%d): vboxCallCreate(%s) failed rc=%Rrc\n",
548 fDirectory, sf_i->path->String.utf8, rc));
549 goto fail1;
550 }
551
552 if (params.Result != SHFL_FILE_CREATED)
553 {
554 err = -EPERM;
555 LogFunc(("(%d): could not create file %s result=%d\n",
556 fDirectory, sf_i->path->String.utf8, params.Result));
557 goto fail1;
558 }
559
560 err = sf_instantiate(parent, dentry, path, &params.Info,
561 fDirectory ? SHFL_HANDLE_NIL : params.Handle);
562 if (err)
563 {
564 LogFunc(("(%d): could not instantiate dentry for %s err=%d\n",
565 fDirectory, sf_i->path->String.utf8, err));
566 goto fail2;
567 }
568
569 /*
570 * Don't close this handle right now. We assume that the same file is
571 * opened with sf_reg_open() and later closed with sf_reg_close(). Save
572 * the handle in between. Does not apply to directories. True?
573 */
574 if (fDirectory)
575 {
576 rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
577 if (RT_FAILURE(rc))
578 LogFunc(("(%d): vboxCallClose failed rc=%Rrc\n", fDirectory, rc));
579 }
580
581 sf_i->force_restat = 1;
582 return 0;
583
584fail2:
585 rc = vboxCallClose(&client_handle, &sf_g->map, params.Handle);
586 if (RT_FAILURE(rc))
587 LogFunc(("(%d): vboxCallClose failed rc=%Rrc\n", fDirectory, rc));
588
589fail1:
590 kfree(path);
591
592fail0:
593 return err;
594}
595
596/**
597 * Create a new regular file.
598 *
599 * @param parent inode of the directory
600 * @param dentry directory cache entry
601 * @param mode file mode
602 * @returns 0 on success, Linux error code otherwise
603 */
604#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
605static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
606#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
607static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode, struct nameidata *nd)
608#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
609static int sf_create(struct inode *parent, struct dentry *dentry, int mode, struct nameidata *nd)
610#else
611static int sf_create(struct inode *parent, struct dentry *dentry, int mode)
612#endif
613{
614 TRACE();
615 return sf_create_aux(parent, dentry, mode, 0);
616}
617
618/**
619 * Create a new directory.
620 *
621 * @param parent inode of the directory
622 * @param dentry directory cache entry
623 * @param mode file mode
624 * @returns 0 on success, Linux error code otherwise
625 */
626#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
627static int sf_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
628#else
629static int sf_mkdir(struct inode *parent, struct dentry *dentry, int mode)
630#endif
631{
632 TRACE();
633 return sf_create_aux(parent, dentry, mode, 1);
634}
635
636/**
637 * Remove a regular file / directory.
638 *
639 * @param parent inode of the directory
640 * @param dentry directory cache entry
641 * @param fDirectory true if directory, false otherwise
642 * @returns 0 on success, Linux error code otherwise
643 */
644static int sf_unlink_aux(struct inode *parent, struct dentry *dentry, int fDirectory)
645{
646 int rc, err;
647 struct sf_glob_info *sf_g = GET_GLOB_INFO(parent->i_sb);
648 struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
649 SHFLSTRING *path;
650 uint32_t fFlags;
651
652 TRACE();
653 BUG_ON(!sf_g);
654
655 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
656 if (err)
657 goto fail0;
658
659 fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
660 if ( dentry
661 && dentry->d_inode
662 && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
663 fFlags |= SHFL_REMOVE_SYMLINK;
664 rc = vboxCallRemove(&client_handle, &sf_g->map, path, fFlags);
665 if (RT_FAILURE(rc))
666 {
667 LogFunc(("(%d): vboxCallRemove(%s) failed rc=%Rrc\n", fDirectory,
668 path->String.utf8, rc));
669 err = -RTErrConvertToErrno(rc);
670 goto fail1;
671 }
672
673 /* directory access/change time changed */
674 sf_i->force_restat = 1;
675 /* directory content changed */
676 sf_i->force_reread = 1;
677
678 err = 0;
679
680fail1:
681 kfree(path);
682
683fail0:
684 return err;
685}
686
687/**
688 * Remove a regular file.
689 *
690 * @param parent inode of the directory
691 * @param dentry directory cache entry
692 * @returns 0 on success, Linux error code otherwise
693 */
694static int sf_unlink(struct inode *parent, struct dentry *dentry)
695{
696 TRACE();
697 return sf_unlink_aux(parent, dentry, 0);
698}
699
700/**
701 * Remove a directory.
702 *
703 * @param parent inode of the directory
704 * @param dentry directory cache entry
705 * @returns 0 on success, Linux error code otherwise
706 */
707static int sf_rmdir(struct inode *parent, struct dentry *dentry)
708{
709 TRACE();
710 return sf_unlink_aux(parent, dentry, 1);
711}
712
713/**
714 * Rename a regular file / directory.
715 *
716 * @param old_parent inode of the old parent directory
717 * @param old_dentry old directory cache entry
718 * @param new_parent inode of the new parent directory
719 * @param new_dentry new directory cache entry
720 * @returns 0 on success, Linux error code otherwise
721 */
722static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
723 struct inode *new_parent, struct dentry *new_dentry)
724{
725 int err = 0, rc = VINF_SUCCESS;
726 struct sf_glob_info *sf_g = GET_GLOB_INFO(old_parent->i_sb);
727
728 TRACE();
729
730 if (sf_g != GET_GLOB_INFO(new_parent->i_sb))
731 {
732 LogFunc(("rename with different roots\n"));
733 err = -EINVAL;
734 }
735 else
736 {
737 struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent);
738 struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent);
739 /* As we save the relative path inside the inode structure, we need to change
740 this if the rename is successful. */
741 struct sf_inode_info *sf_file_i = GET_INODE_INFO(old_dentry->d_inode);
742 SHFLSTRING *old_path;
743 SHFLSTRING *new_path;
744
745 BUG_ON(!sf_old_i);
746 BUG_ON(!sf_new_i);
747 BUG_ON(!sf_file_i);
748
749 old_path = sf_file_i->path;
750 err = sf_path_from_dentry(__func__, sf_g, sf_new_i,
751 new_dentry, &new_path);
752 if (err)
753 LogFunc(("failed to create new path\n"));
754 else
755 {
756 int fDir = ((old_dentry->d_inode->i_mode & S_IFDIR) != 0);
757
758 rc = vboxCallRename(&client_handle, &sf_g->map, old_path,
759 new_path, fDir ? 0 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
760 if (RT_SUCCESS(rc))
761 {
762 kfree(old_path);
763 sf_new_i->force_restat = 1;
764 sf_old_i->force_restat = 1; /* XXX: needed? */
765 /* Set the new relative path in the inode. */
766 sf_file_i->path = new_path;
767 }
768 else
769 {
770 LogFunc(("vboxCallRename failed rc=%Rrc\n", rc));
771 err = -RTErrConvertToErrno(rc);
772 kfree(new_path);
773 }
774 }
775 }
776 return err;
777}
778
779#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
780static int sf_symlink(struct inode *parent, struct dentry *dentry, const char *symname)
781{
782 int err;
783 int rc;
784 struct sf_inode_info *sf_i;
785 struct sf_glob_info *sf_g;
786 SHFLSTRING *path, *ssymname;
787 SHFLFSOBJINFO info;
788 int symname_len = strlen(symname) + 1;
789
790 TRACE();
791 sf_g = GET_GLOB_INFO(parent->i_sb);
792 sf_i = GET_INODE_INFO(parent);
793
794 BUG_ON(!sf_g);
795 BUG_ON(!sf_i);
796
797 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
798 if (err)
799 goto fail0;
800
801 ssymname = kmalloc(offsetof(SHFLSTRING, String.utf8) + symname_len, GFP_KERNEL);
802 if (!ssymname)
803 {
804 LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
805 err = -ENOMEM;
806 goto fail1;
807 }
808
809 ssymname->u16Length = symname_len - 1;
810 ssymname->u16Size = symname_len;
811 memcpy(ssymname->String.utf8, symname, symname_len);
812
813 rc = vboxCallSymlink(&client_handle, &sf_g->map, path, ssymname, &info);
814 kfree(ssymname);
815
816 if (RT_FAILURE(rc))
817 {
818 if (rc == VERR_WRITE_PROTECT)
819 {
820 err = -EROFS;
821 goto fail1;
822 }
823 LogFunc(("vboxCallSymlink(%s) failed rc=%Rrc\n",
824 sf_i->path->String.utf8, rc));
825 err = -EPROTO;
826 goto fail1;
827 }
828
829 err = sf_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
830 if (err)
831 {
832 LogFunc(("could not instantiate dentry for %s err=%d\n",
833 sf_i->path->String.utf8, err));
834 goto fail1;
835 }
836
837 sf_i->force_restat = 1;
838 return 0;
839
840fail1:
841 kfree(path);
842fail0:
843 return err;
844}
845#endif
846
847struct inode_operations sf_dir_iops =
848{
849 .lookup = sf_lookup,
850 .create = sf_create,
851 .mkdir = sf_mkdir,
852 .rmdir = sf_rmdir,
853 .unlink = sf_unlink,
854 .rename = sf_rename,
855#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
856 .revalidate = sf_inode_revalidate
857#else
858 .getattr = sf_getattr,
859 .setattr = sf_setattr,
860 .symlink = sf_symlink
861#endif
862};
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