VirtualBox

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

Last change on this file since 70836 was 70786, checked in by vboxsync, 7 years ago

linux/shared folders: use indent to switch Linux-only files to kernel style.
bugref:9109: Shared folders: update to match in-kernel code more closely

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