VirtualBox

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

Last change on this file since 69564 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

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

© 2023 Oracle
ContactPrivacy policyTerms of Use