VirtualBox

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

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

Additions: relicence components needed for Linux shared folders to MIT.
bugref:9109: Shared folders: update to match in-kernel code more closely
This change makes the code on which the Linux kernel shared folder patch is
based MIT-licenced, so that the version in the Linux kernel can be too. This
would make it easier to move code back and forth.

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