VirtualBox

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

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

linux/vboxsf: More small cleanups. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.8 KB
Line 
1/* $Id: dirops.c 77864 2019-03-24 14:50:02Z 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
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#include "vfsmod.h"
36#include <iprt/err.h>
37
38#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
39# define d_in_lookup(a_pDirEntry) (d_unhashed(a_pDirEntry))
40#endif
41
42
43
44/**
45 * Open a directory (implements file_operations::open).
46 *
47 * @returns 0 on success, negative errno otherwise.
48 * @param inode inode
49 * @param file file
50 */
51static int vbsf_dir_open(struct inode *inode, struct file *file)
52{
53 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(inode->i_sb);
54 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(inode);
55 struct dentry *dentry = VBSF_GET_F_DENTRY(file);
56 struct vbsf_dir_info *sf_d;
57 int rc;
58
59 SFLOGFLOW(("vbsf_dir_open: inode=%p file=%p %s\n", inode, file, sf_i && sf_i->path ? sf_i->path->String.ach : NULL));
60 AssertReturn(sf_g, -EINVAL);
61 AssertReturn(sf_i, -EINVAL);
62 AssertReturn(!file->private_data, 0);
63
64 /*
65 * Allocate and initialize our directory info structure.
66 * We delay buffer allocation until vbsf_getdent is actually used.
67 */
68 sf_d = kmalloc(sizeof(*sf_d), GFP_KERNEL);
69 if (sf_d) {
70 VBOXSFCREATEREQ *pReq;
71 RT_ZERO(*sf_d);
72 sf_d->u32Magic = VBSF_DIR_INFO_MAGIC;
73 sema_init(&sf_d->Lock, 1);
74
75 /*
76 * Try open the directory.
77 */
78 pReq = (VBOXSFCREATEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size);
79 if (pReq) {
80 memcpy(&pReq->StrPath, sf_i->path, SHFLSTRING_HEADER_SIZE + sf_i->path->u16Size);
81 RT_ZERO(pReq->CreateParms);
82 pReq->CreateParms.Handle = SHFL_HANDLE_NIL;
83 pReq->CreateParms.CreateFlags = SHFL_CF_DIRECTORY
84 | SHFL_CF_ACT_OPEN_IF_EXISTS
85 | SHFL_CF_ACT_FAIL_IF_NEW
86 | SHFL_CF_ACCESS_READ;
87
88 LogFunc(("calling VbglR0SfHostReqCreate on folder %s, flags %#x\n",
89 sf_i->path->String.utf8, pReq->CreateParms.CreateFlags));
90 rc = VbglR0SfHostReqCreate(sf_g->map.root, pReq);
91 if (RT_SUCCESS(rc)) {
92 if (pReq->CreateParms.Result == SHFL_FILE_EXISTS) {
93 Assert(pReq->CreateParms.Handle != SHFL_HANDLE_NIL);
94
95 /*
96 * Update the inode info with fresh stats and increase the TTL for the
97 * dentry cache chain that got us here.
98 */
99 vbsf_update_inode(inode, sf_i, &pReq->CreateParms.Info, sf_g, true /*fLocked*/ /** @todo inode locking */);
100 vbsf_dentry_chain_increase_ttl(dentry);
101
102 sf_d->Handle.hHost = pReq->CreateParms.Handle;
103 sf_d->Handle.cRefs = 1;
104 sf_d->Handle.fFlags = VBSF_HANDLE_F_READ | VBSF_HANDLE_F_DIR | VBSF_HANDLE_F_MAGIC;
105 vbsf_handle_append(sf_i, &sf_d->Handle);
106
107 file->private_data = sf_d;
108 VbglR0PhysHeapFree(pReq);
109 SFLOGFLOW(("vbsf_dir_open(%p,%p): returns 0; hHost=%#llx\n", inode, file, sf_d->Handle.hHost));
110 return 0;
111
112 }
113 Assert(pReq->CreateParms.Handle == SHFL_HANDLE_NIL);
114
115 /*
116 * Directory does not exist, so we probably got some invalid
117 * dir cache and inode info.
118 */
119 /** @todo do more to invalidate dentry and inode here. */
120 vbsf_dentry_set_update_jiffies(dentry, jiffies + INT_MAX / 2);
121 sf_i->force_restat = true;
122 rc = -ENOENT;
123 } else
124 rc = -EPERM;
125 VbglR0PhysHeapFree(pReq);
126 } else {
127 LogRelMaxFunc(64, ("failed to allocate %zu bytes for '%s'\n",
128 RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + sf_i->path->u16Size, sf_i->path->String.ach));
129 rc = -ENOMEM;
130 }
131 sf_d->u32Magic = VBSF_DIR_INFO_MAGIC_DEAD;
132 kfree(sf_d);
133 } else
134 rc = -ENOMEM;
135 SFLOGFLOW(("vbsf_dir_open(%p,%p): returns %d\n", inode, file, rc));
136 return rc;
137}
138
139
140/**
141 * This is called when reference count of [file] goes to zero. Notify
142 * the host that it can free whatever is associated with this directory
143 * and deallocate our own internal buffers
144 *
145 * @param inode inode
146 * @param file file
147 * returns 0 on success, Linux error code otherwise
148 */
149static int vbsf_dir_release(struct inode *inode, struct file *file)
150{
151 struct vbsf_dir_info *sf_d = (struct vbsf_dir_info *)file->private_data;
152
153 SFLOGFLOW(("vbsf_dir_release(%p,%p): sf_d=%p hHost=%#llx\n", inode, file, sf_d, sf_d ? sf_d->Handle.hHost : SHFL_HANDLE_NIL));
154
155 if (sf_d) {
156 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(inode->i_sb);
157
158 /* Invalidate the non-handle part. */
159 sf_d->u32Magic = VBSF_DIR_INFO_MAGIC_DEAD;
160 sf_d->cEntriesLeft = 0;
161 sf_d->cbValid = 0;
162 sf_d->pEntry = NULL;
163 sf_d->fNoMoreFiles = false;
164 if (sf_d->pBuf) {
165 kfree(sf_d->pBuf);
166 sf_d->pBuf = NULL;
167 }
168
169 /* Closes the handle and frees the structure when the last reference is released. */
170 vbsf_handle_release(&sf_d->Handle, sf_g, "vbsf_dir_release");
171 }
172
173 return 0;
174}
175
176
177/**
178 * Translate RTFMODE into DT_xxx (in conjunction to rtDirType()).
179 * returns d_type
180 * @param fMode file mode
181 */
182DECLINLINE(int) vbsf_get_d_type(RTFMODE fMode)
183{
184 switch (fMode & RTFS_TYPE_MASK) {
185 case RTFS_TYPE_FIFO: return DT_FIFO;
186 case RTFS_TYPE_DEV_CHAR: return DT_CHR;
187 case RTFS_TYPE_DIRECTORY: return DT_DIR;
188 case RTFS_TYPE_DEV_BLOCK: return DT_BLK;
189 case RTFS_TYPE_FILE: return DT_REG;
190 case RTFS_TYPE_SYMLINK: return DT_LNK;
191 case RTFS_TYPE_SOCKET: return DT_SOCK;
192 case RTFS_TYPE_WHITEOUT: return DT_WHT;
193 }
194 return DT_UNKNOWN;
195}
196
197
198/**
199 * Refills the buffer with more entries.
200 *
201 * @returns 0 on success, negative errno on error,
202 */
203static int vbsf_dir_read_more(struct vbsf_dir_info *sf_d, struct vbsf_super_info *sf_g, bool fRestart)
204{
205 int rc;
206 VBOXSFLISTDIRREQ *pReq;
207
208 /*
209 * Don't call the host again if we've reached the end of the
210 * directory entries already.
211 */
212 if (sf_d->fNoMoreFiles) {
213 if (!fRestart) {
214 SFLOGFLOW(("vbsf_dir_read_more: no more files\n"));
215 return 0;
216 }
217 sf_d->fNoMoreFiles = false;
218 }
219
220 /*
221 * Make sure we've got some kind of buffers.
222 */
223 if (sf_d->pBuf) {
224 /* Likely, except for the first time. */
225 } else {
226 sf_d->pBuf = (PSHFLDIRINFO)kmalloc(sf_g->cbDirBuf, GFP_KERNEL);
227 if (sf_d->pBuf)
228 sf_d->cbBuf = sf_g->cbDirBuf;
229 else {
230 sf_d->pBuf = (PSHFLDIRINFO)kmalloc(_4K, GFP_KERNEL);
231 if (!sf_d->pBuf) {
232 LogRelMax(10, ("vbsf_dir_read_more: Failed to allocate buffer!\n"));
233 return -ENOMEM;
234 }
235 sf_d->cbBuf = _4K;
236 }
237 }
238
239 /*
240 * Allocate a request buffer.
241 */
242 pReq = (VBOXSFLISTDIRREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
243 if (pReq) {
244 rc = VbglR0SfHostReqListDirContig2x(sf_g->map.root, pReq, sf_d->Handle.hHost, NULL, NIL_RTGCPHYS64,
245 fRestart ? SHFL_LIST_RESTART : SHFL_LIST_NONE,
246 sf_d->pBuf, virt_to_phys(sf_d->pBuf), sf_d->cbBuf);
247 if (RT_SUCCESS(rc)) {
248 sf_d->pEntry = sf_d->pBuf;
249 sf_d->cbValid = pReq->Parms.cb32Buffer.u.value32;
250 sf_d->cEntriesLeft = pReq->Parms.c32Entries.u.value32;
251 sf_d->fNoMoreFiles = pReq->Parms.f32More.u.value32 == 0;
252 } else {
253 sf_d->pEntry = sf_d->pBuf;
254 sf_d->cbValid = 0;
255 sf_d->cEntriesLeft = 0;
256 if (rc == VERR_NO_MORE_FILES) {
257 sf_d->fNoMoreFiles = true;
258 rc = 0;
259 } else {
260 /* In theory we could end up here with a buffer overflow, but
261 with a 4KB minimum buffer size that's very unlikely with the
262 typical filename length of today's file systems (2019). */
263 LogRelMax(16, ("vbsf_dir_read_more: VbglR0SfHostReqListDirContig2x -> %Rrc\n", rc));
264 rc = -EPROTO;
265 }
266 }
267 VbglR0PhysHeapFree(pReq);
268 } else
269 rc = -ENOMEM;
270 SFLOGFLOW(("vbsf_dir_read_more: returns %d; cbValid=%#x cEntriesLeft=%#x fNoMoreFiles=%d\n",
271 rc, sf_d->cbValid, sf_d->cEntriesLeft, sf_d->fNoMoreFiles));
272 return rc;
273}
274
275
276/**
277 * Helper function for when we need to convert the name, avoids wasting stack in
278 * the UTF-8 code path.
279 */
280DECL_NO_INLINE(static, bool) vbsf_dir_emit_nls(
281# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
282 struct dir_context *ctx,
283# else
284 void *opaque, filldir_t filldir, loff_t offPos,
285# endif
286 const char *pszSrcName, uint16_t cchSrcName, ino_t d_ino, int d_type,
287 struct vbsf_super_info *sf_g)
288{
289 char szDstName[NAME_MAX];
290 int rc = vbsf_nlscpy(sf_g, szDstName, sizeof(szDstName), pszSrcName, cchSrcName);
291 if (rc == 0) {
292#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
293 return dir_emit(ctx, szDstName, strlen(szDstName), d_ino, d_type);
294#else
295 return filldir(opaque, szDstName, strlen(szDstName), offPos, d_ino, d_type) == 0;
296#endif
297 }
298
299 /* Assuming this is a buffer overflow issue, just silently skip it. */
300 SFLOGFLOW(("vbsf_dir_emit_nls: vbsf_nlscopy failed with %d for '%s'\n", rc, pszSrcName));
301 return true;
302}
303
304
305/**
306 * This is called when vfs wants to populate internal buffers with
307 * directory [dir]s contents. [opaque] is an argument to the
308 * [filldir]. [filldir] magically modifies it's argument - [opaque]
309 * and takes following additional arguments (which i in turn get from
310 * the host via vbsf_getdent):
311 *
312 * name : name of the entry (i must also supply it's length huh?)
313 * type : type of the entry (FILE | DIR | etc) (i ellect to use DT_UNKNOWN)
314 * pos : position/index of the entry
315 * ino : inode number of the entry (i fake those)
316 *
317 * [dir] contains:
318 * f_pos : cursor into the directory listing
319 * private_data : mean of communication with the host side
320 *
321 * Extract elements from the directory listing (incrementing f_pos
322 * along the way) and feed them to [filldir] until:
323 *
324 * a. there are no more entries (i.e. vbsf_getdent set done to 1)
325 * b. failure to compute fake inode number
326 * c. filldir returns an error (see comment on that)
327 */
328#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
329static int vbsf_dir_iterate(struct file *dir, struct dir_context *ctx)
330#else
331static int vbsf_dir_read(struct file *dir, void *opaque, filldir_t filldir)
332#endif
333{
334#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
335 loff_t offPos = ctx->pos;
336#else
337 loff_t offPos = dir->f_pos;
338#endif
339 struct vbsf_dir_info *sf_d = (struct vbsf_dir_info *)dir->private_data;
340 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(VBSF_GET_F_DENTRY(dir)->d_sb);
341 int rc;
342
343 /*
344 * Lock the directory info structures.
345 */
346 if (RT_LIKELY(down_interruptible(&sf_d->Lock) == 0)) {
347 /* likely */
348 } else
349 return -ERESTARTSYS;
350
351 /*
352 * Any seek performed in the mean time?
353 */
354 if (offPos == sf_d->offPos) {
355 /* likely */
356 } else {
357 /* Restart the search if iPos is lower than the current buffer position. */
358 loff_t offCurEntry = sf_d->offPos;
359 if (offPos < offCurEntry) {
360 rc = vbsf_dir_read_more(sf_d, sf_g, true /*fRestart*/);
361 if (rc == 0)
362 offCurEntry = 0;
363 else {
364 up(&sf_d->Lock);
365 return rc;
366 }
367 }
368
369 /* Skip ahead to offPos. */
370 while (offCurEntry < offPos) {
371 uint32_t cEntriesLeft = sf_d->cEntriesLeft;
372 if ((uint64_t)(offPos - offCurEntry) >= cEntriesLeft) {
373 /* Skip the current buffer and read the next: */
374 offCurEntry += cEntriesLeft;
375 sf_d->offPos = offCurEntry;
376 sf_d->cEntriesLeft = 0;
377 rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
378 if (rc != 0 || sf_d->cEntriesLeft == 0) {
379 up(&sf_d->Lock);
380 return rc;
381 }
382 } else {
383 do
384 {
385 PSHFLDIRINFO pEntry = sf_d->pEntry;
386 pEntry = (PSHFLDIRINFO)&pEntry->name.String.utf8[pEntry->name.u16Length];
387 AssertLogRelBreakStmt( cEntriesLeft == 1
388 || (uintptr_t)pEntry - (uintptr_t)sf_d->pBuf
389 <= sf_d->cbValid - RT_UOFFSETOF(SHFLDIRINFO, name.String),
390 sf_d->cEntriesLeft = 0);
391 sf_d->cEntriesLeft = --cEntriesLeft;
392 sf_d->offPos = ++offCurEntry;
393 } while (offPos < sf_d->offPos);
394 }
395 }
396 }
397
398 /*
399 * Handle '.' and '..' specially so we get the inode numbers right.
400 * We'll skip any '.' or '..' returned by the host (included in pos,
401 * however, to simplify the above skipping code).
402 */
403 if (offPos < 2) {
404#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
405 if (offPos == 0) {
406 if (dir_emit_dot(dir, ctx))
407 dir->f_pos = ctx->pos = sf_d->offPos = offPos = 1;
408 else {
409 up(&sf_d->Lock);
410 return 0;
411 }
412 }
413 if (offPos == 1) {
414 if (dir_emit_dotdot(dir, ctx))
415 dir->f_pos = ctx->pos = sf_d->offPos = offPos = 2;
416 else {
417 up(&sf_d->Lock);
418 return 0;
419 }
420 }
421#else
422 if (offPos == 0) {
423 rc = filldir(opaque, ".", 1, 0, VBSF_GET_F_DENTRY(dir)->d_inode->i_ino, DT_DIR);
424 if (!rc)
425 dir->f_pos = sf_d->offPos = offPos = 1;
426 else {
427 up(&sf_d->Lock);
428 return 0;
429 }
430 }
431 if (offPos == 1) {
432# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5)
433 rc = filldir(opaque, "..", 2, 1, parent_ino(VBSF_GET_F_DENTRY(dir)), DT_DIR);
434# else
435 rc = filldir(opaque, "..", 2, 1, VBSF_GET_F_DENTRY(dir)->d_parent->d_inode->i_ino, DT_DIR);
436# endif
437 if (!rc)
438 dir->f_pos = sf_d->offPos = offPos = 2;
439 else {
440 up(&sf_d->Lock);
441 return 0;
442 }
443 }
444#endif
445 }
446
447 /*
448 * Produce stuff.
449 */
450 Assert(offPos == sf_d->offPos);
451 for (;;) {
452 PSHFLDIRINFO pBuf;
453 PSHFLDIRINFO pEntry;
454
455 /*
456 * Do we need to read more?
457 */
458 uint32_t cbValid = sf_d->cbValid;
459 uint32_t cEntriesLeft = sf_d->cEntriesLeft;
460 if (!cEntriesLeft) {
461 rc = vbsf_dir_read_more(sf_d, sf_g, false /*fRestart*/);
462 if (rc == 0) {
463 cEntriesLeft = sf_d->cEntriesLeft;
464 if (!cEntriesLeft) {
465 up(&sf_d->Lock);
466 return 0;
467 }
468 cbValid = sf_d->cbValid;
469 } else {
470 up(&sf_d->Lock);
471 return rc;
472 }
473 }
474
475 /*
476 * Feed entries to the caller.
477 */
478 pBuf = sf_d->pBuf;
479 pEntry = sf_d->pEntry;
480 do {
481 /*
482 * Validate the entry in case the host is messing with us.
483 * We're ASSUMING the host gives us a zero terminated string (UTF-8) here.
484 */
485 uintptr_t const offEntryInBuf = (uintptr_t)pEntry - (uintptr_t)pBuf;
486 uint16_t cbSrcName;
487 uint16_t cchSrcName;
488 AssertLogRelMsgBreak(offEntryInBuf + RT_UOFFSETOF(SHFLDIRINFO, name.String) <= cbValid,
489 ("%#llx + %#x vs %#x\n", offEntryInBuf, RT_UOFFSETOF(SHFLDIRINFO, name.String), cbValid));
490 cbSrcName = pEntry->name.u16Size;
491 cchSrcName = pEntry->name.u16Length;
492 AssertLogRelBreak(offEntryInBuf + RT_UOFFSETOF(SHFLDIRINFO, name.String) + cbSrcName <= cbValid);
493 AssertLogRelBreak(cchSrcName < cbSrcName);
494 AssertLogRelBreak(pEntry->name.String.ach[cchSrcName] == '\0');
495
496 /*
497 * Filter out '.' and '..' entires.
498 */
499 if ( cchSrcName > 2
500 || pEntry->name.String.ach[0] != '.'
501 || ( cchSrcName == 2
502 && pEntry->name.String.ach[1] != '.')) {
503 int const d_type = vbsf_get_d_type(pEntry->Info.Attr.fMode);
504 ino_t const d_ino = (ino_t)offPos + 0xbeef; /* very fake */
505 bool fContinue;
506 if (sf_g->fNlsIsUtf8) {
507#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
508 fContinue = dir_emit(ctx, pEntry->name.String.ach, cchSrcName, d_ino, d_type);
509#else
510 fContinue = filldir(opaque, pEntry->name.String.ach, cchSrcName, offPos, d_ino, d_type) == 0;
511#endif
512 } else {
513#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
514 fContinue = vbsf_dir_emit_nls(ctx, pEntry->name.String.ach, cchSrcName, d_ino, d_type, sf_g);
515#else
516 fContinue = vbsf_dir_emit_nls(opaque, filldir, offPos, pEntry->name.String.ach, cchSrcName,
517 d_ino, d_type, sf_g);
518#endif
519 }
520 if (fContinue) {
521 /* likely */
522 } else {
523 sf_d->cEntriesLeft = cEntriesLeft;
524 sf_d->pEntry = pEntry;
525 sf_d->offPos = offPos;
526 up(&sf_d->Lock);
527 return 0;
528 }
529 }
530
531 /*
532 * Advance to the next entry.
533 */
534 pEntry = (PSHFLDIRINFO)((uintptr_t)pEntry + RT_UOFFSETOF(SHFLDIRINFO, name.String) + cbSrcName);
535 offPos += 1;
536 dir->f_pos = offPos;
537#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
538 ctx->pos = offPos;
539#endif
540 cEntriesLeft -= 1;
541 } while (cEntriesLeft > 0);
542
543 /* Done with all available entries. */
544 sf_d->offPos = offPos + cEntriesLeft;
545 sf_d->pEntry = pBuf;
546 sf_d->cEntriesLeft = 0;
547 }
548}
549
550
551/**
552 * Directory file operations.
553 */
554struct file_operations vbsf_dir_fops = {
555 .open = vbsf_dir_open,
556#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
557 .iterate_shared = vbsf_dir_iterate,
558#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 11, 0)
559 .iterate = vbsf_dir_iterate,
560#else
561 .readdir = vbsf_dir_read,
562#endif
563 .release = vbsf_dir_release,
564 .read = generic_read_dir,
565#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37)
566 .llseek = generic_file_llseek
567#endif
568};
569
570
571
572/*********************************************************************************************************************************
573* Directory Inode Operations *
574*********************************************************************************************************************************/
575
576/**
577 * Worker for vbsf_inode_lookup(), vbsf_create_worker() and
578 * vbsf_inode_instantiate().
579 */
580static struct inode *vbsf_create_inode(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
581 PSHFLFSOBJINFO pObjInfo, struct vbsf_super_info *sf_g, bool fInstantiate)
582{
583 /*
584 * Allocate memory for our additional inode info and create an inode.
585 */
586 struct vbsf_inode_info *sf_new_i = (struct vbsf_inode_info *)kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
587 if (sf_new_i) {
588 ino_t iNodeNo = iunique(parent->i_sb, 16);
589#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
590 struct inode *pInode = iget_locked(parent->i_sb, iNodeNo);
591#else
592 struct inode *pInode = iget(parent->i_sb, iNodeNo);
593#endif
594 if (pInode) {
595 /*
596 * Initialize the two structures.
597 */
598#ifdef VBOX_STRICT
599 sf_new_i->u32Magic = SF_INODE_INFO_MAGIC;
600#endif
601 sf_new_i->path = path;
602 sf_new_i->force_restat = false;
603 sf_new_i->ts_up_to_date = jiffies;
604 RTListInit(&sf_new_i->HandleList);
605 sf_new_i->handle = SHFL_HANDLE_NIL;
606
607 VBSF_SET_INODE_INFO(pInode, sf_new_i);
608 vbsf_init_inode(pInode, sf_new_i, pObjInfo, sf_g);
609
610 /*
611 * Before we unlock the new inode, we may need to call d_instantiate.
612 */
613 if (fInstantiate)
614 d_instantiate(dentry, pInode);
615#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 25)
616 unlock_new_inode(pInode);
617#endif
618 return pInode;
619
620 }
621 LogFunc(("iget failed\n"));
622 kfree(sf_new_i);
623 } else
624 LogRelFunc(("could not allocate memory for new inode info\n"));
625 return NULL;
626}
627
628
629/** Helper for vbsf_create_worker() and vbsf_inode_lookup() that wraps
630 * d_add() and setting d_op. */
631DECLINLINE(void) vbsf_d_add_inode(struct dentry *dentry, struct inode *pNewInode)
632{
633#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 38)
634 Assert(dentry->d_op == &vbsf_dentry_ops); /* (taken from the superblock) */
635#else
636 dentry->d_op = &vbsf_dentry_ops;
637#endif
638 d_add(dentry, pNewInode);
639}
640
641
642/**
643 * This is called when vfs failed to locate dentry in the cache. The
644 * job of this function is to allocate inode and link it to dentry.
645 * [dentry] contains the name to be looked in the [parent] directory.
646 * Failure to locate the name is not a "hard" error, in this case NULL
647 * inode is added to [dentry] and vfs should proceed trying to create
648 * the entry via other means. NULL(or "positive" pointer) ought to be
649 * returned in case of success and "negative" pointer on error
650 */
651static struct dentry *vbsf_inode_lookup(struct inode *parent, struct dentry *dentry
652#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
653 , unsigned int flags
654#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
655 , struct nameidata *nd
656#endif
657 )
658{
659 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
660 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(parent);
661 SHFLSTRING *path;
662 struct dentry *dret;
663 int rc;
664
665#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
666 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p flags=%#x\n", parent, dentry, flags));
667#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
668 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p nd=%p{.flags=%#x}\n", parent, dentry, nd, nd ? nd->flags : 0));
669#else
670 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p\n", parent, dentry));
671#endif
672
673 Assert(sf_g);
674 Assert(sf_i && sf_i->u32Magic == SF_INODE_INFO_MAGIC);
675
676 /*
677 * Build the path. We'll associate the path with dret's inode on success.
678 */
679 rc = vbsf_path_from_dentry(sf_g, sf_i, dentry, &path, __func__);
680 if (rc == 0) {
681 /*
682 * Do a lookup on the host side.
683 */
684 VBOXSFCREATEREQ *pReq = (VBOXSFCREATEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq) + path->u16Size);
685 if (pReq) {
686 struct inode *pInode = NULL;
687
688 RT_ZERO(*pReq);
689 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
690 pReq->CreateParms.Handle = SHFL_HANDLE_NIL;
691 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
692
693 LogFunc(("Calling VbglR0SfHostReqCreate on %s\n", path->String.utf8));
694 rc = VbglR0SfHostReqCreate(sf_g->map.root, pReq);
695 if (RT_SUCCESS(rc)) {
696 if (pReq->CreateParms.Result == SHFL_FILE_EXISTS) {
697 /*
698 * Create an inode for the result. Since this also confirms
699 * the existence of all parent dentries, we increase their TTL.
700 */
701 pInode = vbsf_create_inode(parent, dentry, path, &pReq->CreateParms.Info, sf_g, false /*fInstantiate*/);
702 if (rc == 0) {
703 path = NULL; /* given to the inode */
704 dret = dentry;
705 } else
706 dret = (struct dentry *)ERR_PTR(-ENOMEM);
707 vbsf_dentry_chain_increase_parent_ttl(dentry);
708 } else if ( pReq->CreateParms.Result == SHFL_FILE_NOT_FOUND
709 || pReq->CreateParms.Result == SHFL_PATH_NOT_FOUND /*this probably should happen*/) {
710 dret = dentry;
711 } else {
712 AssertMsgFailed(("%d\n", pReq->CreateParms.Result));
713 dret = (struct dentry *)ERR_PTR(-EPROTO);
714 }
715 } else if (rc == VERR_INVALID_NAME) {
716 dret = dentry; /* this can happen for names like 'foo*' on a Windows host */
717 } else {
718 LogFunc(("VbglR0SfHostReqCreate failed on %s: %Rrc\n", path->String.utf8, rc));
719 dret = (struct dentry *)ERR_PTR(-EPROTO);
720 }
721 VbglR0PhysHeapFree(pReq);
722
723 /*
724 * When dret is set to dentry we got something to insert,
725 * though it may be negative (pInode == NULL).
726 */
727 if (dret == dentry) {
728 vbsf_dentry_set_update_jiffies(dentry, jiffies);
729 vbsf_d_add_inode(dentry, pInode);
730 dret = NULL;
731 }
732 } else
733 dret = (struct dentry *)ERR_PTR(-ENOMEM);
734 if (path)
735 kfree(path);
736 } else
737 dret = (struct dentry *)ERR_PTR(rc);
738 return dret;
739}
740
741
742/**
743 * This should allocate memory for vbsf_inode_info, compute a unique inode
744 * number, get an inode from vfs, initialize inode info, instantiate
745 * dentry.
746 *
747 * @param parent inode entry of the directory
748 * @param dentry directory cache entry
749 * @param path path name. Consumed on success.
750 * @param info file information
751 * @param handle handle
752 * @returns 0 on success, Linux error code otherwise
753 */
754static int vbsf_inode_instantiate(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
755 PSHFLFSOBJINFO info, SHFLHANDLE handle)
756{
757 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
758 struct inode *pInode = vbsf_create_inode(parent, dentry, path, info, sf_g, true /*fInstantiate*/);
759 if (pInode) {
760 /* Store this handle if we leave the handle open. */
761 struct vbsf_inode_info *sf_new_i = VBSF_GET_INODE_INFO(pInode);
762 sf_new_i->handle = handle;
763 return 0;
764 }
765 return -ENOMEM;
766}
767
768
769/**
770 * Create a new regular file / directory.
771 *
772 * @param parent inode of the directory
773 * @param dentry directory cache entry
774 * @param mode file mode
775 * @param fCreateFlags SHFL_CF_XXX.
776 * @param fStashHandle Whether the resulting handle should be stashed in
777 * the inode for a subsequent open call.
778 * @param fDoLookup Whether we're doing a lookup and need to d_add the
779 * inode we create to dentry.
780 * @param phHostFile Where to return the handle to the create file/dir.
781 * @param pfCreated Where to indicate whether the file/dir was created
782 * or not. Optional.
783 * @returns 0 on success, Linux error code otherwise
784 */
785static int vbsf_create_worker(struct inode *parent, struct dentry *dentry, umode_t mode, uint32_t fCreateFlags,
786 bool fStashHandle, bool fDoLookup, SHFLHANDLE *phHostFile, bool *pfCreated)
787
788{
789#ifdef SFLOG_ENABLED
790 const char * const pszPrefix = S_ISDIR(mode) ? "vbsf_create_worker/dir:" : "vbsf_create_worker/file:";
791#endif
792 struct vbsf_inode_info *sf_parent_i = VBSF_GET_INODE_INFO(parent);
793 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
794 PSHFLSTRING path;
795 int rc;
796
797 AssertReturn(sf_parent_i, -EINVAL);
798 AssertReturn(sf_g, -EINVAL);
799
800 /*
801 * Build a path. We'll donate this to the inode on success.
802 */
803 rc = vbsf_path_from_dentry(sf_g, sf_parent_i, dentry, &path, __func__);
804 if (rc == 0) {
805 /*
806 * Allocate, initialize and issue the SHFL_CREATE request.
807 */
808 /** @todo combine with vbsf_path_from_dentry? */
809 union CreateAuxReq
810 {
811 VBOXSFCREATEREQ Create;
812 VBOXSFCLOSEREQ Close;
813 } *pReq = (union CreateAuxReq *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + path->u16Size);
814 if (pReq) {
815 memcpy(&pReq->Create.StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
816 RT_ZERO(pReq->Create.CreateParms);
817 pReq->Create.CreateParms.Handle = SHFL_HANDLE_NIL;
818 pReq->Create.CreateParms.CreateFlags = fCreateFlags;
819 pReq->Create.CreateParms.Info.Attr.fMode = (S_ISDIR(mode) ? RTFS_TYPE_DIRECTORY : RTFS_TYPE_FILE)
820 | sf_access_permissions_to_vbox(mode);
821 pReq->Create.CreateParms.Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
822
823 SFLOGFLOW(("%s calling VbglR0SfHostReqCreate(%s, %#x)\n", pszPrefix, path->String.ach, pReq->Create.CreateParms.CreateFlags));
824 rc = VbglR0SfHostReqCreate(sf_g->map.root, &pReq->Create);
825 if (RT_SUCCESS(rc)) {
826 SFLOGFLOW(("%s VbglR0SfHostReqCreate returned %Rrc Result=%d Handle=%#llx\n",
827 pszPrefix, rc, pReq->Create.CreateParms.Result, pReq->Create.CreateParms.Handle));
828
829 /*
830 * Work the dentry cache and inode restatting.
831 */
832 if ( pReq->Create.CreateParms.Result == SHFL_FILE_CREATED
833 || pReq->Create.CreateParms.Result == SHFL_FILE_REPLACED) {
834 vbsf_dentry_chain_increase_parent_ttl(dentry);
835 sf_parent_i->force_restat = 1;
836 } else if ( pReq->Create.CreateParms.Result == SHFL_FILE_EXISTS
837 || pReq->Create.CreateParms.Result == SHFL_FILE_NOT_FOUND)
838 vbsf_dentry_chain_increase_parent_ttl(dentry);
839
840 /*
841 * If we got a handle back, we're good. Create an inode for it and return.
842 */
843 if (pReq->Create.CreateParms.Handle != SHFL_HANDLE_NIL) {
844 struct inode *pNewInode = vbsf_create_inode(parent, dentry, path, &pReq->Create.CreateParms.Info, sf_g,
845 !fDoLookup /*fInstantiate*/);
846 if (pNewInode) {
847 struct vbsf_inode_info *sf_new_i = VBSF_GET_INODE_INFO(pNewInode);
848 if (phHostFile) {
849 *phHostFile = pReq->Create.CreateParms.Handle;
850 pReq->Create.CreateParms.Handle = SHFL_HANDLE_NIL;
851 } else if (fStashHandle) {
852 sf_new_i->handle = pReq->Create.CreateParms.Handle;
853 pReq->Create.CreateParms.Handle = SHFL_HANDLE_NIL;
854 }
855 if (fDoLookup)
856 vbsf_d_add_inode(dentry, pNewInode);
857 path = NULL;
858 } else {
859 SFLOGFLOW(("%s vbsf_create_inode failed: -ENOMEM (path %s)\n", pszPrefix, rc, path->String.ach));
860 rc = -ENOMEM;
861 }
862 } else if (pReq->Create.CreateParms.Result == SHFL_FILE_EXISTS) {
863 /*
864 * For atomic_open (at least), we should create an inode and
865 * convert the dentry from a negative to a positive one.
866 */
867 SFLOGFLOW(("%s SHFL_FILE_EXISTS for %s\n", pszPrefix, sf_parent_i->path->String.ach));
868 if (fDoLookup) {
869 struct inode *pNewInode = vbsf_create_inode(parent, dentry, path, &pReq->Create.CreateParms.Info,
870 sf_g, false /*fInstantiate*/);
871 if (pNewInode)
872 vbsf_d_add_inode(dentry, pNewInode);
873 path = NULL;
874 }
875 rc = -EEXIST;
876 } else if (pReq->Create.CreateParms.Result == SHFL_FILE_NOT_FOUND) {
877 SFLOGFLOW(("%s SHFL_FILE_NOT_FOUND for %s\n", pszPrefix, sf_parent_i->path->String.ach));
878 rc = -ENOENT;
879 } else if (pReq->Create.CreateParms.Result == SHFL_PATH_NOT_FOUND) {
880 SFLOGFLOW(("%s SHFL_PATH_NOT_FOUND for %s\n", pszPrefix, sf_parent_i->path->String.ach));
881 rc = -ENOENT;
882 } else {
883 AssertMsgFailed(("result=%d creating '%s'\n", pReq->Create.CreateParms.Result, sf_parent_i->path->String.ach));
884 rc = -EPERM;
885 }
886 } else {
887 int const vrc = rc;
888 rc = -RTErrConvertToErrno(vrc);
889 SFLOGFLOW(("%s SHFL_FN_CREATE(%s) failed vrc=%Rrc rc=%d\n", pszPrefix, path->String.ach, vrc, rc));
890 }
891
892 /* Cleanups. */
893 if (pReq->Create.CreateParms.Handle != SHFL_HANDLE_NIL) {
894 AssertCompile(RTASSERT_OFFSET_OF(VBOXSFCREATEREQ, CreateParms.Handle) > sizeof(VBOXSFCLOSEREQ)); /* no aliasing issues */
895 int rc2 = VbglR0SfHostReqClose(sf_g->map.root, &pReq->Close, pReq->Create.CreateParms.Handle);
896 if (RT_FAILURE(rc2))
897 SFLOGFLOW(("%s VbglR0SfHostReqCloseSimple failed rc=%Rrc\n", pszPrefix, rc2));
898 }
899 VbglR0PhysHeapFree(pReq);
900 } else
901 rc = -ENOMEM;
902 if (path)
903 kfree(path);
904 }
905 return rc;
906}
907
908
909#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
910/**
911 * More atomic way of handling creation.
912 *
913 * Older kernels would first to a lookup that created the file, followed by
914 * an open call. We've got this horrid vbsf_inode_info::handle member because
915 * of that approach. The call combines the lookup and open.
916 */
917static int vbsf_inode_atomic_open(struct inode *pDirInode, struct dentry *dentry, struct file *file, unsigned fOpen,
918 umode_t fMode
919# if LINUX_VERSION_CODE < KERNEL_VERSION(4, 19, 0)
920 , int *opened
921# endif
922 )
923{
924 SFLOGFLOW(("vbsf_inode_atomic_open: pDirInode=%p dentry=%p file=%p fOpen=%#x, fMode=%#x\n", pDirInode, dentry, file, fOpen, fMode));
925 int rc;
926
927 /* Code assumes negative dentry. */
928 Assert(dentry->d_inode == NULL);
929
930 /** @todo see if we can do this for non-create calls too, as it may save us a
931 * host call to revalidate the dentry. (Can't see anyone else doing
932 * this, so playing it safe for now.) */
933 if (fOpen & O_CREAT) {
934 /*
935 * Prepare our file info structure.
936 */
937 struct vbsf_reg_info *sf_r = kmalloc(sizeof(*sf_r), GFP_KERNEL);
938 if (sf_r) {
939 bool fCreated = false;
940 uint32_t fCreateFlags;
941
942 RTListInit(&sf_r->Handle.Entry);
943 sf_r->Handle.cRefs = 1;
944 sf_r->Handle.fFlags = !(fOpen & O_DIRECTORY)
945 ? VBSF_HANDLE_F_FILE | VBSF_HANDLE_F_MAGIC
946 : VBSF_HANDLE_F_DIR | VBSF_HANDLE_F_MAGIC;
947 sf_r->Handle.hHost = SHFL_HANDLE_NIL;
948
949 /*
950 * Try create it.
951 */
952 /* vbsf_create_worker uses the type from fMode, so match it up to O_DIRECTORY. */
953 AssertMsg(!(fMode & S_IFMT) || (fMode & S_IFMT) == (fOpen & O_DIRECTORY ? S_IFDIR : S_IFREG), ("0%o\n", fMode));
954 if (!(fOpen & O_DIRECTORY))
955 fMode = (fMode & ~S_IFMT) | S_IFREG;
956 else
957 fMode = (fMode & ~S_IFMT) | S_IFDIR;
958
959 fCreateFlags = vbsf_linux_oflags_to_vbox(fOpen, &sf_r->Handle.fFlags, __FUNCTION__);
960
961 rc = vbsf_create_worker(pDirInode, dentry, fMode, fCreateFlags, false /*fStashHandle*/, true /*fDoLookup*/,
962 &sf_r->Handle.hHost, &fCreated);
963 if (rc == 0) {
964 struct inode *inode = dentry->d_inode;
965 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(inode);
966
967 /*
968 * Set FMODE_CREATED according to the action taken by SHFL_CREATE
969 * and call finish_open() to do the remaining open() work.
970 */
971# if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
972 if (fCreated)
973 file->f_mode |= FMODE_CREATED;
974 rc = finish_open(file, dentry, generic_file_open);
975# else
976 if (fCreated)
977 *opened |= FILE_CREATED;
978 rc = finish_open(file, dentry, generic_file_open, opened);
979# endif
980 if (rc == 0) {
981 /*
982 * Now that the file is fully opened, associate sf_r with it
983 * and link the handle to the inode.
984 */
985 vbsf_handle_append(sf_i, &sf_r->Handle);
986 file->private_data = sf_r;
987 SFLOGFLOW(("vbsf_inode_atomic_open: create succeeded; hHost=%#llx path='%s'\n",
988 rc, sf_r->Handle.hHost, sf_i->path->String.ach));
989 sf_r = NULL; /* don't free it */
990 } else {
991 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(pDirInode->i_sb);
992 SFLOGFLOW(("vbsf_inode_atomic_open: finish_open failed: %d (path='%s'\n", rc, sf_i->path->String.ach));
993 VbglR0SfHostReqCloseSimple(sf_g->map.root, sf_r->Handle.hHost);
994 sf_r->Handle.hHost = SHFL_HANDLE_NIL;
995 }
996 } else
997 SFLOGFLOW(("vbsf_inode_atomic_open: vbsf_create_worker failed: %d\n", rc));
998 if (sf_r)
999 kfree(sf_r);
1000 } else {
1001 LogRelMaxFunc(64, ("could not allocate reg info\n"));
1002 rc = -ENOMEM;
1003 }
1004 }
1005 /*
1006 * Not creating anything.
1007 * Do we need to do a lookup or should we just fail?
1008 */
1009 else if (d_in_lookup(dentry)) {
1010 struct dentry *pResult = vbsf_inode_lookup(pDirInode, dentry, 0 /*fFlags*/);
1011 if (!IS_ERR(pResult))
1012 rc = finish_no_open(file, pResult);
1013 else
1014 rc = PTR_ERR(pResult);
1015 SFLOGFLOW(("vbsf_inode_atomic_open: open -> %d (%p)\n", rc, pResult));
1016 } else {
1017 SFLOGFLOW(("vbsf_inode_atomic_open: open -> -ENOENT\n"));
1018 rc = -ENOENT;
1019 }
1020 return rc;
1021}
1022#endif /* 3.6.0 */
1023
1024
1025/**
1026 * Create a new regular file.
1027 *
1028 * @param parent inode of the directory
1029 * @param dentry directory cache entry
1030 * @param mode file mode
1031 * @param excl Possible O_EXCL...
1032 * @returns 0 on success, Linux error code otherwise
1033 */
1034#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0) || defined(DOXYGEN_RUNNING)
1035static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
1036#elif LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
1037static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, umode_t mode, struct nameidata *nd)
1038#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
1039static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, int mode, struct nameidata *nd)
1040#else
1041static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, int mode)
1042#endif
1043{
1044 uint32_t fCreateFlags = SHFL_CF_ACT_CREATE_IF_NEW
1045 | SHFL_CF_ACT_FAIL_IF_EXISTS
1046 | SHFL_CF_ACCESS_READWRITE;
1047#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75)
1048 /* Clear the RD flag if write-only access requested. Otherwise assume we
1049 need write access to create stuff. */
1050 if (!(nd->intent.open.flags & 1) ) {
1051 fCreateFlags &= SHFL_CF_ACCESS_READWRITE;
1052 fCreateFlags |= SHFL_CF_ACCESS_WRITE;
1053 }
1054 /* (file since 2.6.15) */
1055#endif
1056 TRACE();
1057 AssertMsg(!(mode & S_IFMT) || (mode & S_IFMT) == S_IFREG, ("0%o\n", mode));
1058 return vbsf_create_worker(parent, dentry, (mode & ~S_IFMT) | S_IFREG, fCreateFlags,
1059 true /*fStashHandle*/, false /*fDoLookup*/, NULL /*phHandle*/, NULL /*fCreated*/);
1060}
1061
1062
1063/**
1064 * Create a new directory.
1065 *
1066 * @param parent inode of the directory
1067 * @param dentry directory cache entry
1068 * @param mode file mode
1069 * @returns 0 on success, Linux error code otherwise
1070 */
1071#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
1072static int vbsf_inode_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
1073#else
1074static int vbsf_inode_mkdir(struct inode *parent, struct dentry *dentry, int mode)
1075#endif
1076{
1077 TRACE();
1078 AssertMsg(!(mode & S_IFMT) || (mode & S_IFMT) == S_IFDIR, ("0%o\n", mode));
1079 return vbsf_create_worker(parent, dentry, (mode & ~S_IFMT) | S_IFDIR,
1080 SHFL_CF_ACT_CREATE_IF_NEW
1081 | SHFL_CF_ACT_FAIL_IF_EXISTS
1082 | SHFL_CF_ACCESS_READWRITE
1083 | SHFL_CF_DIRECTORY,
1084 false /*fStashHandle*/, false /*fDoLookup*/, NULL /*phHandle*/, NULL /*fCreated*/);
1085}
1086
1087
1088/**
1089 * Remove a regular file / directory.
1090 *
1091 * @param parent inode of the directory
1092 * @param dentry directory cache entry
1093 * @param fDirectory true if directory, false otherwise
1094 * @returns 0 on success, Linux error code otherwise
1095 */
1096static int vbsf_unlink_worker(struct inode *parent, struct dentry *dentry, int fDirectory)
1097{
1098 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
1099 struct vbsf_inode_info *sf_parent_i = VBSF_GET_INODE_INFO(parent);
1100 SHFLSTRING *path;
1101 int rc;
1102
1103 TRACE();
1104
1105 rc = vbsf_path_from_dentry(sf_g, sf_parent_i, dentry, &path, __func__);
1106 if (!rc) {
1107 VBOXSFREMOVEREQ *pReq = (VBOXSFREMOVEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String)
1108 + path->u16Size);
1109 if (pReq) {
1110 memcpy(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
1111 uint32_t fFlags = fDirectory ? SHFL_REMOVE_DIR : SHFL_REMOVE_FILE;
1112 if (dentry->d_inode && ((dentry->d_inode->i_mode & S_IFLNK) == S_IFLNK))
1113 fFlags |= SHFL_REMOVE_SYMLINK;
1114
1115 rc = VbglR0SfHostReqRemove(sf_g->map.root, pReq, fFlags);
1116
1117 if (dentry->d_inode) {
1118 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(dentry->d_inode);
1119 sf_i->force_restat = true;
1120 }
1121
1122 if (RT_SUCCESS(rc)) {
1123 sf_parent_i->force_restat = true; /* directory access/change time changed */
1124 rc = 0;
1125 } else if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) {
1126 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc; calling d_drop on %p\n",
1127 fDirectory, path->String.ach, rc, dentry));
1128 d_drop(dentry);
1129 rc = 0; /** @todo ??? */
1130 } else {
1131 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc\n", fDirectory, path->String.ach, rc));
1132 rc = -RTErrConvertToErrno(rc);
1133 }
1134 VbglR0PhysHeapFree(pReq);
1135 } else
1136 rc = -ENOMEM;
1137 kfree(path);
1138 }
1139 return rc;
1140}
1141
1142
1143/**
1144 * Remove a regular file.
1145 *
1146 * @param parent inode of the directory
1147 * @param dentry directory cache entry
1148 * @returns 0 on success, Linux error code otherwise
1149 */
1150static int vbsf_inode_unlink(struct inode *parent, struct dentry *dentry)
1151{
1152 TRACE();
1153 return vbsf_unlink_worker(parent, dentry, false /*fDirectory*/);
1154}
1155
1156
1157/**
1158 * Remove a directory.
1159 *
1160 * @param parent inode of the directory
1161 * @param dentry directory cache entry
1162 * @returns 0 on success, Linux error code otherwise
1163 */
1164static int vbsf_inode_rmdir(struct inode *parent, struct dentry *dentry)
1165{
1166 TRACE();
1167 return vbsf_unlink_worker(parent, dentry, true /*fDirectory*/);
1168}
1169
1170
1171/**
1172 * Rename a regular file / directory.
1173 *
1174 * @param old_parent inode of the old parent directory
1175 * @param old_dentry old directory cache entry
1176 * @param new_parent inode of the new parent directory
1177 * @param new_dentry new directory cache entry
1178 * @param flags flags
1179 * @returns 0 on success, Linux error code otherwise
1180 */
1181static int vbsf_inode_rename(struct inode *old_parent, struct dentry *old_dentry,
1182 struct inode *new_parent, struct dentry *new_dentry, unsigned flags)
1183{
1184 /*
1185 * Deal with flags.
1186 */
1187 int rc;
1188 uint32_t fRename = (old_dentry->d_inode->i_mode & S_IFDIR ? SHFL_RENAME_DIR : SHFL_RENAME_FILE)
1189 | SHFL_RENAME_REPLACE_IF_EXISTS;
1190#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
1191 if (!(flags & ~RENAME_NOREPLACE)) {
1192 if (flags & RENAME_NOREPLACE)
1193 fRename &= ~SHFL_RENAME_REPLACE_IF_EXISTS;
1194#endif
1195 /*
1196 * Check that they are on the same mount.
1197 */
1198 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(old_parent->i_sb);
1199 if (sf_g == VBSF_GET_SUPER_INFO(new_parent->i_sb)) {
1200 /*
1201 * Build the new path.
1202 */
1203 struct vbsf_inode_info *sf_new_parent_i = VBSF_GET_INODE_INFO(new_parent);
1204 PSHFLSTRING pNewPath;
1205 rc = vbsf_path_from_dentry(sf_g, sf_new_parent_i, new_dentry, &pNewPath, __func__);
1206 if (rc == 0) {
1207 /*
1208 * Create and issue the rename request.
1209 */
1210 VBOXSFRENAMEWITHSRCBUFREQ *pReq;
1211 pReq = (VBOXSFRENAMEWITHSRCBUFREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String)
1212 + pNewPath->u16Size);
1213 if (pReq) {
1214 struct vbsf_inode_info *sf_file_i = VBSF_GET_INODE_INFO(old_dentry->d_inode);
1215 PSHFLSTRING pOldPath = sf_file_i->path;
1216
1217 memcpy(&pReq->StrDstPath, pNewPath, SHFLSTRING_HEADER_SIZE + pNewPath->u16Size);
1218 rc = VbglR0SfHostReqRenameWithSrcContig(sf_g->map.root, pReq, pOldPath, virt_to_phys(pOldPath), fRename);
1219 VbglR0PhysHeapFree(pReq);
1220 if (RT_SUCCESS(rc)) {
1221 /*
1222 * On success we replace the path in the inode and trigger
1223 * restatting of both parent directories.
1224 */
1225 struct vbsf_inode_info *sf_old_parent_i = VBSF_GET_INODE_INFO(old_parent);
1226 SFLOGFLOW(("vbsf_inode_rename: %s -> %s (%#x)\n", pOldPath->String.ach, pNewPath->String.ach, fRename));
1227
1228 sf_file_i->path = pNewPath;
1229 kfree(pOldPath);
1230 pNewPath = NULL;
1231
1232 sf_new_parent_i->force_restat = 1;
1233 sf_old_parent_i->force_restat = 1;
1234
1235 vbsf_dentry_chain_increase_parent_ttl(old_dentry);
1236 vbsf_dentry_chain_increase_parent_ttl(new_dentry);
1237
1238 rc = 0;
1239 } else {
1240 SFLOGFLOW(("vbsf_inode_rename: VbglR0SfHostReqRenameWithSrcContig(%s,%s,%#x) failed -> %d\n",
1241 pOldPath->String.ach, pNewPath->String.ach, fRename, rc));
1242 if (rc == VERR_IS_A_DIRECTORY || rc == VERR_IS_A_FILE)
1243 vbsf_dentry_set_update_jiffies(old_dentry, jiffies + INT_MAX / 2);
1244 rc = -RTErrConvertToErrno(rc);
1245 }
1246 } else {
1247 SFLOGFLOW(("vbsf_inode_rename: failed to allocate request (%#x bytes)\n",
1248 RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String) + pNewPath->u16Size));
1249 rc = -ENOMEM;
1250 }
1251 if (pNewPath)
1252 kfree(pNewPath);
1253 } else
1254 SFLOGFLOW(("vbsf_inode_rename: vbsf_path_from_dentry failed: %d\n", rc));
1255 } else {
1256 SFLOGFLOW(("vbsf_inode_rename: rename with different roots (%#x vs %#x)\n",
1257 sf_g->map.root, VBSF_GET_SUPER_INFO(new_parent->i_sb)->map.root));
1258 rc = -EXDEV;
1259 }
1260#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
1261 } else {
1262 SFLOGFLOW(("vbsf_inode_rename: Unsupported flags: %#x\n", flags));
1263 rc = -EINVAL;
1264 }
1265#else
1266 RT_NOREF(flags);
1267#endif
1268 return rc;
1269}
1270
1271
1272#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
1273/**
1274 * The traditional rename interface without any flags.
1275 */
1276static int vbsf_inode_rename_no_flags(struct inode *old_parent, struct dentry *old_dentry,
1277 struct inode *new_parent, struct dentry *new_dentry)
1278{
1279 return vbsf_inode_rename(old_parent, old_dentry, new_parent, new_dentry, 0);
1280}
1281#endif
1282
1283
1284/**
1285 * Create a symbolic link.
1286 */
1287static int vbsf_inode_symlink(struct inode *parent, struct dentry *dentry, const char *target)
1288{
1289 /*
1290 * Turn the target into a string (contiguous physcial memory).
1291 */
1292 /** @todo we can save a kmalloc here if we switch to embedding the target rather
1293 * than the symlink path into the request. Will require more NLS helpers. */
1294 struct vbsf_super_info *sf_g = VBSF_GET_SUPER_INFO(parent->i_sb);
1295 PSHFLSTRING pTarget = NULL;
1296 int rc = vbsf_nls_to_shflstring(sf_g, target, &pTarget);
1297 if (rc == 0) {
1298 /*
1299 * Create a full path for the symlink name.
1300 */
1301 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(parent);
1302 PSHFLSTRING pPath = NULL;
1303 rc = vbsf_path_from_dentry(sf_g, sf_i, dentry, &pPath, __func__);
1304 if (rc == 0) {
1305 /*
1306 * Create the request and issue it.
1307 */
1308 uint32_t const cbReq = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath.String) + pPath->u16Size;
1309 VBOXSFCREATESYMLINKREQ *pReq = (VBOXSFCREATESYMLINKREQ *)VbglR0PhysHeapAlloc(cbReq);
1310 if (pReq) {
1311 RT_ZERO(*pReq);
1312 memcpy(&pReq->StrSymlinkPath, pPath, SHFLSTRING_HEADER_SIZE + pPath->u16Size);
1313
1314 rc = VbglR0SfHostReqCreateSymlinkContig(sf_g->map.root, pTarget, virt_to_phys(pTarget), pReq);
1315 if (RT_SUCCESS(rc)) {
1316 sf_i->force_restat = 1;
1317
1318 /*
1319 * Instantiate a new inode for the symlink.
1320 */
1321 rc = vbsf_inode_instantiate(parent, dentry, pPath, &pReq->ObjInfo, SHFL_HANDLE_NIL);
1322 if (rc == 0) {
1323 SFLOGFLOW(("vbsf_inode_symlink: Successfully created '%s' -> '%s'\n", pPath->String.ach, pTarget->String.ach));
1324 pPath = NULL; /* consumed by inode */
1325 } else {
1326 SFLOGFLOW(("vbsf_inode_symlink: Failed to create inode for '%s': %d\n", pPath->String.ach, rc));
1327 }
1328 } else {
1329 int const vrc = rc;
1330 if (vrc == VERR_WRITE_PROTECT)
1331 rc = -EPERM; /* EPERM: Symlink creation not supported according to the linux manpage as of 2017-09-15.
1332 "VBoxInternal2/SharedFoldersEnableSymlinksCreate/<share>" is not 1. */
1333 else
1334 rc = -RTErrConvertToErrno(vrc);
1335 SFLOGFLOW(("vbsf_inode_symlink: VbglR0SfHostReqCreateSymlinkContig failed for '%s' -> '%s': %Rrc (-> %d)\n",
1336 pPath->String.ach, pTarget->String.ach, vrc, rc));
1337 }
1338 VbglR0PhysHeapFree(pReq);
1339 } else {
1340 SFLOGFLOW(("vbsf_inode_symlink: failed to allocate %u phys heap for the request!\n", cbReq));
1341 rc = -ENOMEM;
1342 }
1343 if (pPath)
1344 kfree(pPath);
1345 }
1346 kfree(pTarget);
1347 }
1348 return rc;
1349}
1350
1351
1352/**
1353 * Directory inode operations.
1354 */
1355struct inode_operations vbsf_dir_iops = {
1356 .lookup = vbsf_inode_lookup,
1357#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
1358 .atomic_open = vbsf_inode_atomic_open,
1359#endif
1360 .create = vbsf_inode_create,
1361 .symlink = vbsf_inode_symlink,
1362 .mkdir = vbsf_inode_mkdir,
1363 .rmdir = vbsf_inode_rmdir,
1364 .unlink = vbsf_inode_unlink,
1365#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
1366 .rename = vbsf_inode_rename,
1367#else
1368 .rename = vbsf_inode_rename_no_flags,
1369# if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
1370 .rename2 = vbsf_inode_rename,
1371# endif
1372#endif
1373#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 18)
1374 .getattr = vbsf_inode_getattr,
1375#else
1376 .revalidate = vbsf_inode_revalidate,
1377#endif
1378 .setattr = vbsf_inode_setattr,
1379};
1380
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