VirtualBox

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

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

linux/vboxsf: Cleaned out the VBOXSF_USE_DEPRECATED_VBGL_INTERFACE #ifdefs. bugref:9172

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