VirtualBox

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

Last change on this file since 103067 was 103067, checked in by vboxsync, 5 months ago

Additions: Linux: vboxsf: Prevent array-index-out-of-bounds UBSAN warnings, bugref:10585.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use