VirtualBox

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

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

linux/vboxsf: Code cleanups in the super block info area. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 27.8 KB
Line 
1/* $Id: dirops.c 77524 2019-03-01 11:58:24Z 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 vbsf_super_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 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(inode->i_sb);
116 struct sf_inode_info *sf_i = GET_INODE_INFO(inode);
117 struct sf_dir_info *sf_d;
118 int err;
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 vbsf_super_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 = VBSF_GET_SUPER_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 * Worker for sf_lookup() and sf_instantiate().
382 */
383static struct inode *sf_create_inode(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
384 PSHFLFSOBJINFO pObjInfo, struct vbsf_super_info *sf_g, bool fInstantiate)
385{
386 /*
387 * Allocate memory for our additional inode info and create an inode.
388 */
389 struct sf_inode_info *sf_new_i = (struct sf_inode_info *)kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
390 if (sf_new_i) {
391 ino_t iNodeNo = iunique(parent->i_sb, 1);
392#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
393 struct inode *pInode = iget_locked(parent->i_sb, iNodeNo);
394#else
395 struct inode *pInode = iget(parent->i_sb, iNodeNo);
396#endif
397 if (pInode) {
398 /*
399 * Initialize the two structures.
400 */
401#ifdef VBOX_STRICT
402 sf_new_i->u32Magic = SF_INODE_INFO_MAGIC;
403#endif
404 sf_new_i->path = path;
405 sf_new_i->force_reread = 0;
406 sf_new_i->force_restat = 0;
407 sf_new_i->ts_up_to_date = jiffies;
408 RTListInit(&sf_new_i->HandleList);
409 sf_new_i->handle = SHFL_HANDLE_NIL;
410
411 SET_INODE_INFO(pInode, sf_new_i);
412 sf_init_inode(pInode, sf_new_i, pObjInfo, sf_g);
413
414 /*
415 * Before we unlock the new inode, we may need to call d_instantiate.
416 */
417 if (fInstantiate)
418 d_instantiate(dentry, pInode);
419#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
420 unlock_new_inode(pInode);
421#endif
422 return pInode;
423
424 }
425 LogFunc(("iget failed\n"));
426 kfree(sf_new_i);
427 } else
428 LogRelFunc(("could not allocate memory for new inode info\n"));
429 return NULL;
430}
431
432/**
433 * This is called when vfs failed to locate dentry in the cache. The
434 * job of this function is to allocate inode and link it to dentry.
435 * [dentry] contains the name to be looked in the [parent] directory.
436 * Failure to locate the name is not a "hard" error, in this case NULL
437 * inode is added to [dentry] and vfs should proceed trying to create
438 * the entry via other means. NULL(or "positive" pointer) ought to be
439 * returned in case of success and "negative" pointer on error
440 */
441static struct dentry *sf_lookup(struct inode *parent, struct dentry *dentry
442#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
443 , unsigned int flags
444#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
445 , struct nameidata *nd
446#endif
447 )
448{
449 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
450 struct sf_inode_info *sf_i = GET_INODE_INFO(parent);
451 SHFLSTRING *path;
452 struct dentry *dret;
453 int rc;
454
455#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
456 SFLOGFLOW(("sf_lookup: parent=%p dentry=%p flags=%#x\n", parent, dentry, flags));
457#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
458 SFLOGFLOW(("sf_lookup: parent=%p dentry=%p nd=%p{.flags=%#x}\n", parent, dentry, nd, nd ? nd->flags : 0));
459#else
460 SFLOGFLOW(("sf_lookup: parent=%p dentry=%p\n", parent, dentry));
461#endif
462
463 Assert(sf_g);
464 Assert(sf_i && sf_i->u32Magic == SF_INODE_INFO_MAGIC);
465
466 /*
467 * Build the path. We'll associate the path with dret's inode on success.
468 */
469 rc = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
470 if (rc == 0) {
471 /*
472 * Do a lookup on the host side.
473 */
474 VBOXSFCREATEREQ *pReq = (VBOXSFCREATEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq) + path->u16Size);
475 if (pReq) {
476 struct inode *pInode = NULL;
477
478 RT_ZERO(*pReq);
479 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
480 pReq->CreateParms.Handle = SHFL_HANDLE_NIL;
481 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
482
483 LogFunc(("Calling VbglR0SfHostReqCreate on %s\n", path->String.utf8));
484 rc = VbglR0SfHostReqCreate(sf_g->map.root, pReq);
485 if (RT_SUCCESS(rc)) {
486 if (pReq->CreateParms.Result == SHFL_FILE_EXISTS) {
487 /*
488 * Create an inode for the result. Since this also confirms
489 * the existence of all parent dentries, we increase their TTL.
490 */
491 pInode = sf_create_inode(parent, dentry, path, &pReq->CreateParms.Info,
492 sf_g, false /*fInstantiate*/);
493 if (rc == 0) {
494 path = NULL; /* given to the inode */
495 dret = dentry;
496 } else
497 dret = (struct dentry *)ERR_PTR(-ENOMEM);
498 sf_dentry_chain_increase_parent_ttl(dentry);
499 } else if ( pReq->CreateParms.Result == SHFL_FILE_NOT_FOUND
500 || pReq->CreateParms.Result == SHFL_PATH_NOT_FOUND /*this probably should happen*/) {
501 dret = dentry;
502 } else {
503 AssertMsgFailed(("%d\n", pReq->CreateParms.Result));
504 dret = (struct dentry *)ERR_PTR(-EPROTO);
505 }
506 } else if (rc == VERR_INVALID_NAME) {
507 dret = dentry; /* this can happen for names like 'foo*' on a Windows host */
508 } else {
509 LogFunc(("VbglR0SfHostReqCreate failed on %s: %Rrc\n", path->String.utf8, rc));
510 dret = (struct dentry *)ERR_PTR(-EPROTO);
511 }
512 VbglR0PhysHeapFree(pReq);
513
514 /*
515 * When dret is set to dentry we got something to insert,
516 * though it may be negative (pInode == NULL).
517 */
518 if (dret == dentry) {
519 sf_dentry_set_update_jiffies(dentry, jiffies);
520#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
521 Assert(dentry->d_op == &sf_dentry_ops); /* (taken from the superblock) */
522#else
523 dentry->d_op = &sf_dentry_ops;
524#endif
525 d_add(dentry, pInode);
526 dret = NULL;
527 }
528 } else
529 dret = (struct dentry *)ERR_PTR(-ENOMEM);
530 if (path)
531 kfree(path);
532 } else
533 dret = (struct dentry *)ERR_PTR(rc);
534 return dret;
535}
536
537/**
538 * This should allocate memory for sf_inode_info, compute a unique inode
539 * number, get an inode from vfs, initialize inode info, instantiate
540 * dentry.
541 *
542 * @param parent inode entry of the directory
543 * @param dentry directory cache entry
544 * @param path path name. Consumed on success.
545 * @param info file information
546 * @param handle handle
547 * @returns 0 on success, Linux error code otherwise
548 */
549static int sf_instantiate(struct inode *parent, struct dentry *dentry,
550 PSHFLSTRING path, PSHFLFSOBJINFO info,
551 SHFLHANDLE handle)
552{
553 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
554 struct inode *pInode = sf_create_inode(parent, dentry, path, info, sf_g, true /*fInstantiate*/);
555 if (pInode) {
556 /* Store this handle if we leave the handle open. */
557 struct sf_inode_info *sf_new_i = GET_INODE_INFO(pInode);
558 sf_new_i->handle = handle;
559 return 0;
560 }
561 return -ENOMEM;
562}
563
564/**
565 * Create a new regular file / directory.
566 *
567 * @param parent inode of the directory
568 * @param dentry directory cache entry
569 * @param mode file mode
570 * @param fDirectory true if directory, false otherwise
571 * @returns 0 on success, Linux error code otherwise
572 */
573static int sf_create_aux(struct inode *parent, struct dentry *dentry,
574 umode_t mode, int fDirectory)
575{
576 int rc, err;
577 struct sf_inode_info *sf_parent_i = GET_INODE_INFO(parent);
578 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
579 SHFLSTRING *path;
580 union CreateAuxReq
581 {
582 VBOXSFCREATEREQ Create;
583 VBOXSFCLOSEREQ Close;
584 } *pReq;
585 SHFLCREATEPARMS *pCreateParms;
586
587 TRACE();
588 BUG_ON(!sf_parent_i);
589 BUG_ON(!sf_g);
590
591 err = sf_path_from_dentry(__func__, sf_g, sf_parent_i, dentry, &path);
592 if (err)
593 goto fail0;
594
595 /** @todo combine with sf_path_from_dentry? */
596 pReq = (union CreateAuxReq *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + path->u16Size);
597 if (pReq) {
598 memcpy(&pReq->Create.StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
599 pCreateParms = &pReq->Create.CreateParms;
600 } else {
601 err = -ENOMEM;
602 goto fail1;
603 }
604
605 RT_ZERO(*pCreateParms);
606 pCreateParms->Handle = SHFL_HANDLE_NIL;
607 pCreateParms->CreateFlags = SHFL_CF_ACT_CREATE_IF_NEW
608 | SHFL_CF_ACT_FAIL_IF_EXISTS
609 | SHFL_CF_ACCESS_READWRITE
610 | (fDirectory ? SHFL_CF_DIRECTORY : 0);
611 pCreateParms->Info.Attr.fMode = (fDirectory ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
612 | (mode & S_IRWXUGO);
613 pCreateParms->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
614
615 LogFunc(("calling VbglR0SfHostReqCreate, folder %s, flags %#x\n", path->String.ach, pCreateParms->CreateFlags));
616 rc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
617 if (RT_FAILURE(rc)) {
618 if (rc == VERR_WRITE_PROTECT) {
619 err = -EROFS;
620 goto fail2;
621 }
622 err = -EPROTO;
623 LogFunc(("(%d): SHFL_FN_CREATE(%s) failed rc=%Rrc\n",
624 fDirectory, sf_parent_i->path->String.utf8, rc));
625 goto fail2;
626 }
627
628 if (pCreateParms->Result != SHFL_FILE_CREATED) {
629 err = -EPERM;
630 LogFunc(("(%d): could not create file %s result=%d\n",
631 fDirectory, sf_parent_i->path->String.utf8, pCreateParms->Result));
632 goto fail2;
633 }
634
635 sf_dentry_chain_increase_parent_ttl(dentry);
636
637 err = sf_instantiate(parent, dentry, path, &pCreateParms->Info,
638 fDirectory ? SHFL_HANDLE_NIL : pCreateParms->Handle);
639 if (err) {
640 LogFunc(("(%d): could not instantiate dentry for %s err=%d\n", fDirectory, path->String.utf8, err));
641 goto fail3;
642 }
643
644 /*
645 * Don't close this handle right now. We assume that the same file is
646 * opened with sf_reg_open() and later closed with sf_reg_close(). Save
647 * the handle in between. Does not apply to directories. True?
648 */
649 if (fDirectory) {
650 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
651 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pCreateParms->Handle);
652 if (RT_FAILURE(rc))
653 LogFunc(("(%d): VbglR0SfHostReqClose failed rc=%Rrc\n", fDirectory, rc));
654 }
655
656 sf_parent_i->force_restat = 1;
657 VbglR0PhysHeapFree(pReq);
658 return 0;
659
660 fail3:
661 rc = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pCreateParms->Handle);
662 if (RT_FAILURE(rc))
663 LogFunc(("(%d): VbglR0SfHostReqCloseSimple failed rc=%Rrc\n", fDirectory, rc));
664 fail2:
665 VbglR0PhysHeapFree(pReq);
666 fail1:
667 kfree(path);
668
669 fail0:
670 return err;
671}
672
673/**
674 * Create a new regular file.
675 *
676 * @param parent inode of the directory
677 * @param dentry directory cache entry
678 * @param mode file mode
679 * @param excl Possible O_EXCL...
680 * @returns 0 on success, Linux error code otherwise
681 */
682#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(DOXYGEN_RUNNING)
683static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode,
684 bool excl)
685#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
686static int sf_create(struct inode *parent, struct dentry *dentry, umode_t mode,
687 struct nameidata *nd)
688#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
689static int sf_create(struct inode *parent, struct dentry *dentry, int mode,
690 struct nameidata *nd)
691#else
692static int sf_create(struct inode *parent, struct dentry *dentry, int mode)
693#endif
694{
695/** @todo @a nd (struct nameidata) contains intent with partial open flags for
696 * 2.6.0-3.5.999. In 3.6.0 atomic_open was introduced and stuff
697 * changed (investigate)... */
698 TRACE();
699 return sf_create_aux(parent, dentry, mode, 0 /*fDirectory*/);
700}
701
702/**
703 * Create a new directory.
704 *
705 * @param parent inode of the directory
706 * @param dentry directory cache entry
707 * @param mode file mode
708 * @returns 0 on success, Linux error code otherwise
709 */
710#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
711static int sf_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
712#else
713static int sf_mkdir(struct inode *parent, struct dentry *dentry, int mode)
714#endif
715{
716 TRACE();
717 return sf_create_aux(parent, dentry, mode, 1 /*fDirectory*/);
718}
719
720/**
721 * Remove a regular file / directory.
722 *
723 * @param parent inode of the directory
724 * @param dentry directory cache entry
725 * @param fDirectory true if directory, false otherwise
726 * @returns 0 on success, Linux error code otherwise
727 */
728static int sf_unlink_aux(struct inode *parent, struct dentry *dentry,
729 int fDirectory)
730{
731 int rc, err;
732 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
733 struct sf_inode_info *sf_parent_i = GET_INODE_INFO(parent);
734 SHFLSTRING *path;
735
736 TRACE();
737 BUG_ON(!sf_g);
738
739 err = sf_path_from_dentry(__func__, sf_g, sf_parent_i, dentry, &path);
740 if (!err) {
741 VBOXSFREMOVEREQ *pReq = (VBOXSFREMOVEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String)
742 + path->u16Size);
743 if (pReq) {
744 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
745 uint32_t fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
746 if (dentry->d_inode && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
747 fFlags |= SHFL_REMOVE_SYMLINK;
748
749 rc = VbglR0SfHostReqRemove(sf_g->map.root, pReq, fFlags);
750
751 if (dentry->d_inode) {
752 struct sf_inode_info *sf_i = GET_INODE_INFO(dentry->d_inode);
753 sf_i->force_restat = 1;
754 sf_i->force_reread = 1;
755 }
756
757 if (RT_SUCCESS(rc)) {
758 /* directory access/change time changed */
759 sf_parent_i->force_restat = 1;
760 /* directory content changed */
761 sf_parent_i->force_reread = 1;
762
763 err = 0;
764 } else if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) {
765 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc; calling d_drop on %p\n",
766 fDirectory, path->String.utf8, rc, dentry));
767 d_drop(dentry);
768 } else {
769 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc\n", fDirectory, path->String.utf8, rc));
770 err = -RTErrConvertToErrno(rc);
771 }
772 VbglR0PhysHeapFree(pReq);
773 } else
774 err = -ENOMEM;
775 kfree(path);
776 }
777 return err;
778}
779
780/**
781 * Remove a regular file.
782 *
783 * @param parent inode of the directory
784 * @param dentry directory cache entry
785 * @returns 0 on success, Linux error code otherwise
786 */
787static int sf_unlink(struct inode *parent, struct dentry *dentry)
788{
789 TRACE();
790 return sf_unlink_aux(parent, dentry, 0 /*fDirectory*/);
791}
792
793/**
794 * Remove a directory.
795 *
796 * @param parent inode of the directory
797 * @param dentry directory cache entry
798 * @returns 0 on success, Linux error code otherwise
799 */
800static int sf_rmdir(struct inode *parent, struct dentry *dentry)
801{
802 TRACE();
803 return sf_unlink_aux(parent, dentry, 1 /*fDirectory*/);
804}
805
806/**
807 * Rename a regular file / directory.
808 *
809 * @param old_parent inode of the old parent directory
810 * @param old_dentry old directory cache entry
811 * @param new_parent inode of the new parent directory
812 * @param new_dentry new directory cache entry
813 * @param flags flags
814 * @returns 0 on success, Linux error code otherwise
815 */
816static int sf_rename(struct inode *old_parent, struct dentry *old_dentry,
817 struct inode *new_parent, struct dentry *new_dentry
818#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
819 , unsigned flags
820#endif
821 )
822{
823 int err = 0, rc = VINF_SUCCESS;
824 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(old_parent->i_sb);
825
826 TRACE();
827
828#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
829 if (flags) {
830 LogFunc(("rename with flags=%x\n", flags));
831 return -EINVAL;
832 }
833#endif
834
835 if (sf_g != VBSF_GET_SUPER_INFO(new_parent->i_sb)) {
836 LogFunc(("rename with different roots\n"));
837 err = -EINVAL;
838 } else {
839 struct sf_inode_info *sf_old_i = GET_INODE_INFO(old_parent);
840 struct sf_inode_info *sf_new_i = GET_INODE_INFO(new_parent);
841 /* As we save the relative path inside the inode structure, we need to change
842 this if the rename is successful. */
843 struct sf_inode_info *sf_file_i =
844 GET_INODE_INFO(old_dentry->d_inode);
845 SHFLSTRING *old_path;
846 SHFLSTRING *new_path;
847
848 BUG_ON(!sf_old_i);
849 BUG_ON(!sf_new_i);
850 BUG_ON(!sf_file_i);
851
852 old_path = sf_file_i->path;
853 err = sf_path_from_dentry(__func__, sf_g, sf_new_i,
854 new_dentry, &new_path);
855 if (err)
856 LogFunc(("failed to create new path\n"));
857 else {
858 VBOXSFRENAMEWITHSRCBUFREQ *pReq;
859 pReq = (VBOXSFRENAMEWITHSRCBUFREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ,
860 StrDstPath.String)
861 + new_path->u16Size);
862 if (pReq) {
863 memcpy(&pReq->StrDstPath, new_path, SHFLSTRING_HEADER_SIZE + new_path->u16Size);
864 rc = VbglR0SfHostReqRenameWithSrcContig(sf_g->map.root, pReq,
865 old_path, virt_to_phys(old_path),
866 old_dentry->d_inode->i_mode & S_IFDIR ? SHFL_RENAME_DIR
867 : SHFL_RENAME_FILE | SHFL_RENAME_REPLACE_IF_EXISTS);
868 VbglR0PhysHeapFree(pReq);
869 } else
870 rc = VERR_NO_MEMORY;
871 if (RT_SUCCESS(rc)) {
872 kfree(old_path);
873 sf_new_i->force_restat = 1;
874 sf_old_i->force_restat = 1; /* XXX: needed? */
875
876 /* Set the new relative path in the inode. */
877 sf_file_i->path = new_path;
878
879 } else {
880 LogFunc(("VbglR0SfRename failed rc=%Rrc\n",
881 rc));
882 err = -RTErrConvertToErrno(rc);
883 kfree(new_path);
884 }
885 }
886 }
887 return err;
888}
889
890#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
891static int sf_symlink(struct inode *parent, struct dentry *dentry,
892 const char *symname)
893{
894 int err;
895 int rc;
896 struct sf_inode_info *sf_i;
897 struct vbsf_super_info *sf_g;
898 SHFLSTRING *path, *ssymname;
899 SHFLFSOBJINFO info;
900 int symname_len = strlen(symname) + 1;
901
902 TRACE();
903 sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
904 sf_i = GET_INODE_INFO(parent);
905
906 BUG_ON(!sf_g);
907 BUG_ON(!sf_i);
908
909 err = sf_path_from_dentry(__func__, sf_g, sf_i, dentry, &path);
910 if (err)
911 goto fail0;
912
913 ssymname =
914 kmalloc(offsetof(SHFLSTRING, String.utf8) + symname_len,
915 GFP_KERNEL);
916 if (!ssymname) {
917 LogRelFunc(("kmalloc failed, caller=sf_symlink\n"));
918 err = -ENOMEM;
919 goto fail1;
920 }
921
922 ssymname->u16Length = symname_len - 1;
923 ssymname->u16Size = symname_len;
924 memcpy(ssymname->String.utf8, symname, symname_len);
925
926 rc = VbglR0SfSymlink(&client_handle, &sf_g->map, path, ssymname, &info);
927 kfree(ssymname);
928
929 if (RT_FAILURE(rc)) {
930 if (rc == VERR_WRITE_PROTECT) {
931 err = -EROFS;
932 goto fail1;
933 }
934 LogFunc(("VbglR0SfSymlink(%s) failed rc=%Rrc\n",
935 sf_i->path->String.utf8, rc));
936 err = -EPROTO;
937 goto fail1;
938 }
939
940 err = sf_instantiate(parent, dentry, path, &info, SHFL_HANDLE_NIL);
941 if (err) {
942 LogFunc(("could not instantiate dentry for %s err=%d\n",
943 sf_i->path->String.utf8, err));
944 goto fail1;
945 }
946
947 sf_i->force_restat = 1;
948 return 0;
949
950 fail1:
951 kfree(path);
952 fail0:
953 return err;
954}
955#endif /* LINUX_VERSION_CODE >= 2.6.0 */
956
957struct inode_operations sf_dir_iops = {
958 .lookup = sf_lookup,
959 .create = sf_create,
960 .mkdir = sf_mkdir,
961 .rmdir = sf_rmdir,
962 .unlink = sf_unlink,
963 .rename = sf_rename,
964#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
965 .revalidate = sf_inode_revalidate
966#else
967 .getattr = sf_getattr,
968 .setattr = sf_setattr,
969 .symlink = sf_symlink
970#endif
971};
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