VirtualBox

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

Last change on this file was 104345, checked in by vboxsync, 4 weeks ago

Additions: Linux: UBSAN: vboxsf: update naming for r162827, bugref:10585.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use