VirtualBox

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

Last change on this file since 54171 was 53757, checked in by vboxsync, 10 years ago

Linux Additions / sharedfolders: Linux 3.19 adaptions

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