VirtualBox

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

Last change on this file since 76563 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette