VirtualBox

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

Last change on this file since 104344 was 104344, checked in by vboxsync, 7 months ago

Additions: Linux: UBSAN: make r161313 less ugly, 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 104344 2024-04-17 13:19:20Z 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 char *ach = pEntry->name.String.ach;
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);
496 AssertLogRelBreak(ach[cchSrcName] == '\0');
497
498 /*
499 * Filter out '.' and '..' entires.
500 */
501 if ( cchSrcName > 2
502 || pEntry->name.String.ach[0] != '.'
503 || ( cchSrcName == 2
504 && ach[1] != '.')) {
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;
508 if (pSuperInfo->fNlsIsUtf8) {
509#if RTLNX_VER_MIN(3,11,0)
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 {
515#if RTLNX_VER_MIN(3,11,0)
516 fContinue = vbsf_dir_emit_nls(ctx, pEntry->name.String.ach, cchSrcName, d_ino, d_type, pSuperInfo);
517#else
518 fContinue = vbsf_dir_emit_nls(opaque, filldir, offPos, pEntry->name.String.ach, cchSrcName,
519 d_ino, d_type, pSuperInfo);
520#endif
521 }
522 if (fContinue) {
523 /* likely */
524 } else {
525 sf_d->cEntriesLeft = cEntriesLeft;
526 sf_d->pEntry = pEntry;
527 sf_d->offPos = offPos;
528 up(&sf_d->Lock);
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;
539#if RTLNX_VER_MIN(3,11,0)
540 ctx->pos = offPos;
541#endif
542 cEntriesLeft -= 1;
543 } while (cEntriesLeft > 0);
544
545 /* Done with all available entries. */
546 sf_d->offPos = offPos + cEntriesLeft;
547 sf_d->pEntry = pBuf;
548 sf_d->cEntriesLeft = 0;
549 }
550}
551
552
553/**
554 * Directory file operations.
555 */
556struct file_operations vbsf_dir_fops = {
557 .open = vbsf_dir_open,
558#if RTLNX_VER_MIN(4,7,0)
559 .iterate_shared = vbsf_dir_iterate,
560#elif RTLNX_VER_MIN(3,11,0)
561 .iterate = vbsf_dir_iterate,
562#else
563 .readdir = vbsf_dir_read,
564#endif
565 .release = vbsf_dir_release,
566 .read = generic_read_dir,
567#if RTLNX_VER_MIN(2,6,37)
568 .llseek = generic_file_llseek
569#endif
570};
571
572
573
574/*********************************************************************************************************************************
575* Directory Inode Operations *
576*********************************************************************************************************************************/
577
578/**
579 * Worker for vbsf_inode_lookup(), vbsf_create_worker() and
580 * vbsf_inode_instantiate().
581 */
582static struct inode *vbsf_create_inode(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
583 PSHFLFSOBJINFO pObjInfo, struct vbsf_super_info *pSuperInfo, bool fInstantiate)
584{
585 /*
586 * Allocate memory for our additional inode info and create an inode.
587 */
588 struct vbsf_inode_info *sf_new_i = (struct vbsf_inode_info *)kmalloc(sizeof(*sf_new_i), GFP_KERNEL);
589 if (sf_new_i) {
590 ino_t iNodeNo = iunique(parent->i_sb, 16);
591#if RTLNX_VER_MIN(2,4,25)
592 struct inode *pInode = iget_locked(parent->i_sb, iNodeNo);
593#else
594 struct inode *pInode = iget(parent->i_sb, iNodeNo);
595#endif
596 if (pInode) {
597 /*
598 * Initialize the two structures.
599 */
600#ifdef VBOX_STRICT
601 sf_new_i->u32Magic = SF_INODE_INFO_MAGIC;
602#endif
603 sf_new_i->path = path;
604 sf_new_i->force_restat = false;
605 sf_new_i->ts_up_to_date = jiffies;
606 RTListInit(&sf_new_i->HandleList);
607 sf_new_i->handle = SHFL_HANDLE_NIL;
608
609 VBSF_SET_INODE_INFO(pInode, sf_new_i);
610 vbsf_init_inode(pInode, sf_new_i, pObjInfo, pSuperInfo);
611
612 /*
613 * Before we unlock the new inode, we may need to call d_instantiate.
614 */
615 if (fInstantiate)
616 d_instantiate(dentry, pInode);
617#if RTLNX_VER_MIN(2,4,25)
618 unlock_new_inode(pInode);
619#endif
620 return pInode;
621
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;
628}
629
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{
635#if RTLNX_VER_MIN(2,6,38)
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
644/**
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
651 * returned in case of success and "negative" pointer on error
652 */
653static struct dentry *vbsf_inode_lookup(struct inode *parent, struct dentry *dentry
654#if RTLNX_VER_MIN(3,6,0)
655 , unsigned int flags
656#elif RTLNX_VER_MIN(2,6,0)
657 , struct nameidata *nd
658#endif
659 )
660{
661 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(parent->i_sb);
662 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(parent);
663 SHFLSTRING *path;
664 struct dentry *dret;
665 int rc;
666
667#if RTLNX_VER_MIN(3,6,0)
668 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p flags=%#x\n", parent, dentry, flags));
669#elif RTLNX_VER_MIN(2,6,0)
670 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p nd=%p{.flags=%#x}\n", parent, dentry, nd, nd ? nd->flags : 0));
671#else
672 SFLOGFLOW(("vbsf_inode_lookup: parent=%p dentry=%p\n", parent, dentry));
673#endif
674
675 Assert(pSuperInfo);
676 Assert(sf_i && sf_i->u32Magic == SF_INODE_INFO_MAGIC);
677
678 /*
679 * Build the path. We'll associate the path with dret's inode on success.
680 */
681 rc = vbsf_path_from_dentry(pSuperInfo, sf_i, dentry, &path, __func__);
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;
689
690 RT_ZERO(*pReq);
691 RT_BCOPY_UNFORTIFIED(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
692 pReq->CreateParms.Handle = SHFL_HANDLE_NIL;
693 pReq->CreateParms.CreateFlags = SHFL_CF_LOOKUP | SHFL_CF_ACT_FAIL_IF_NEW;
694
695 SFLOG2(("vbsf_inode_lookup: Calling VbglR0SfHostReqCreate on %s\n", path->String.utf8));
696 rc = VbglR0SfHostReqCreate(pSuperInfo->map.root, pReq);
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 */
703 pInode = vbsf_create_inode(parent, dentry, path, &pReq->CreateParms.Info, pSuperInfo, false /*fInstantiate*/);
704 if (rc == 0) {
705 path = NULL; /* given to the inode */
706 dret = dentry;
707 } else
708 dret = (struct dentry *)ERR_PTR(-ENOMEM);
709 vbsf_dentry_chain_increase_parent_ttl(dentry);
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) {
718 SFLOGFLOW(("vbsf_inode_lookup: VERR_INVALID_NAME\n"));
719 dret = dentry; /* this can happen for names like 'foo*' on a Windows host */
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);
723 } else {
724 SFLOG(("vbsf_inode_lookup: VbglR0SfHostReqCreate failed on %s: %Rrc\n", path->String.utf8, rc));
725 dret = (struct dentry *)ERR_PTR(-EPROTO);
726 }
727 VbglR0PhysHeapFree(pReq);
728
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) {
734 vbsf_dentry_set_update_jiffies(dentry, jiffies);
735 vbsf_d_add_inode(dentry, pInode);
736 dret = NULL;
737 }
738 } else {
739 SFLOGFLOW(("vbsf_inode_lookup: -ENOMEM (phys heap)\n"));
740 dret = (struct dentry *)ERR_PTR(-ENOMEM);
741 }
742 if (path)
743 kfree(path);
744 } else {
745 SFLOG(("vbsf_inode_lookup: vbsf_path_from_dentry failed: %d\n", rc));
746 dret = (struct dentry *)ERR_PTR(rc);
747 }
748 return dret;
749}
750
751
752/**
753 * This should allocate memory for vbsf_inode_info, compute a unique inode
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
759 * @param path path name. Consumed on success.
760 * @param info file information
761 * @param handle handle
762 * @returns 0 on success, Linux error code otherwise
763 */
764static int vbsf_inode_instantiate(struct inode *parent, struct dentry *dentry, PSHFLSTRING path,
765 PSHFLFSOBJINFO info, SHFLHANDLE handle)
766{
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*/);
769 if (pInode) {
770 /* Store this handle if we leave the handle open. */
771 struct vbsf_inode_info *sf_new_i = VBSF_GET_INODE_INFO(pInode);
772 sf_new_i->handle = handle;
773 return 0;
774 }
775 return -ENOMEM;
776}
777
778
779/**
780 * Create a new regular file / directory.
781 *
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.
793 * @returns 0 on success, Linux error code otherwise
794 */
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
798{
799#ifdef SFLOG_ENABLED
800 const char * const pszPrefix = S_ISDIR(mode) ? "vbsf_create_worker/dir:" : "vbsf_create_worker/file:";
801#endif
802 struct vbsf_inode_info *sf_parent_i = VBSF_GET_INODE_INFO(parent);
803 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(parent->i_sb);
804 PSHFLSTRING path;
805 int rc;
806
807 if (pfCreated)
808 *pfCreated = false;
809 AssertReturn(sf_parent_i, -EINVAL);
810 AssertReturn(pSuperInfo, -EINVAL);
811
812 /*
813 * Build a path. We'll donate this to the inode on success.
814 */
815 rc = vbsf_path_from_dentry(pSuperInfo, sf_parent_i, dentry, &path, __func__);
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) {
827 RT_BCOPY_UNFORTIFIED(&pReq->Create.StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
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);
833 pReq->Create.CreateParms.Info.Attr.enmAdditional = SHFLFSOBJATTRADD_NOTHING;
834
835 SFLOGFLOW(("%s calling VbglR0SfHostReqCreate(%s, %#x)\n", pszPrefix, path->String.ach, pReq->Create.CreateParms.CreateFlags));
836 rc = VbglR0SfHostReqCreate(pSuperInfo->map.root, &pReq->Create);
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));
840
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);
851
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) {
856 struct inode *pNewInode = vbsf_create_inode(parent, dentry, path, &pReq->Create.CreateParms.Info, pSuperInfo,
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 }
867 if (pfCreated)
868 *pfCreated = pReq->Create.CreateParms.Result == SHFL_FILE_CREATED;
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,
884 pSuperInfo, false /*fInstantiate*/);
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 */
909 int rc2 = VbglR0SfHostReqClose(pSuperInfo->map.root, &pReq->Close, pReq->Create.CreateParms.Handle);
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);
918 }
919 return rc;
920}
921
922
923#if RTLNX_VER_MIN(3,16,0)
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 */
931static int vbsf_inode_atomic_open(struct inode *pDirInode, struct dentry *dentry, struct file *file, unsigned fOpen,
932 umode_t fMode
933# if RTLNX_VER_MAX(4,19,0)
934 , int *opened
935# endif
936 )
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)
959 ? VBSF_HANDLE_F_FILE | VBSF_HANDLE_F_MAGIC
960 : VBSF_HANDLE_F_DIR | VBSF_HANDLE_F_MAGIC;
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 */
985# if RTLNX_VER_MIN(4,19,0)
986 if (fCreated)
987 file->f_mode |= FMODE_CREATED;
988 rc = finish_open(file, dentry, generic_file_open);
989# else
990 if (fCreated)
991 *opened |= FILE_CREATED;
992 rc = finish_open(file, dentry, generic_file_open, opened);
993# endif
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 {
1005 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(pDirInode->i_sb);
1006 SFLOGFLOW(("vbsf_inode_atomic_open: finish_open failed: %d (path='%s'\n", rc, sf_i->path->String.ach));
1007 VbglR0SfHostReqCloseSimple(pSuperInfo->map.root, sf_r->Handle.hHost);
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 }
1018 }
1019 /*
1020 * Not creating anything.
1021 * Do we need to do a lookup or should we just fail?
1022 */
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;
1033 }
1034 return rc;
1035}
1036#endif /* 3.6.0 */
1037
1038
1039/**
1040 * Create a new regular file.
1041 *
1042 * @param idmap idmap of the mount.
1043 * @param parent inode of the directory
1044 * @param dentry directory cache entry
1045 * @param mode file mode
1046 * @param excl Possible O_EXCL...
1047 * @returns 0 on success, Linux error code otherwise
1048 */
1049#if RTLNX_VER_MIN(6,3,0) || defined(DOXYGEN_RUNNING)
1050static int vbsf_inode_create(struct mnt_idmap *idmap, struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
1051#elif RTLNX_VER_MIN(5,12,0)
1052static int vbsf_inode_create(struct user_namespace *ns, struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
1053#elif RTLNX_VER_MIN(3,6,0)
1054static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, umode_t mode, bool excl)
1055#elif RTLNX_VER_MIN(3,3,0)
1056static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, umode_t mode, struct nameidata *nd)
1057#elif RTLNX_VER_MIN(2,5,75)
1058static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, int mode, struct nameidata *nd)
1059#else
1060static int vbsf_inode_create(struct inode *parent, struct dentry *dentry, int mode)
1061#endif
1062{
1063 uint32_t fCreateFlags = SHFL_CF_ACT_CREATE_IF_NEW
1064 | SHFL_CF_ACT_FAIL_IF_EXISTS
1065 | SHFL_CF_ACCESS_READWRITE;
1066#if RTLNX_VER_RANGE(2,5,75, 3,6,0)
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
1075 TRACE();
1076 AssertMsg(!(mode & S_IFMT) || (mode & S_IFMT) == S_IFREG, ("0%o\n", mode));
1077 return vbsf_create_worker(parent, dentry, (mode & ~S_IFMT) | S_IFREG, fCreateFlags,
1078 true /*fStashHandle*/, false /*fDoLookup*/, NULL /*phHandle*/, NULL /*fCreated*/);
1079}
1080
1081
1082/**
1083 * Create a new directory.
1084 *
1085 * @param idmap idmap of the mount.
1086 * @param parent inode of the directory
1087 * @param dentry directory cache entry
1088 * @param mode file mode
1089 * @returns 0 on success, Linux error code otherwise
1090 */
1091#if RTLNX_VER_MIN(6,3,0) || defined(DOXYGEN_RUNNING)
1092static int vbsf_inode_mkdir(struct mnt_idmap *idmap, struct inode *parent, struct dentry *dentry, umode_t mode)
1093#elif RTLNX_VER_MIN(5,12,0)
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)
1096static int vbsf_inode_mkdir(struct inode *parent, struct dentry *dentry, umode_t mode)
1097#else
1098static int vbsf_inode_mkdir(struct inode *parent, struct dentry *dentry, int mode)
1099#endif
1100{
1101 TRACE();
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*/);
1109}
1110
1111
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 */
1120static int vbsf_unlink_worker(struct inode *parent, struct dentry *dentry, int fDirectory)
1121{
1122 struct vbsf_super_info *pSuperInfo = VBSF_GET_SUPER_INFO(parent->i_sb);
1123 struct vbsf_inode_info *sf_parent_i = VBSF_GET_INODE_INFO(parent);
1124 SHFLSTRING *path;
1125 int rc;
1126
1127 TRACE();
1128
1129 rc = vbsf_path_from_dentry(pSuperInfo, sf_parent_i, dentry, &path, __func__);
1130 if (!rc) {
1131 VBOXSFREMOVEREQ *pReq = (VBOXSFREMOVEREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String)
1132 + path->u16Size);
1133 if (pReq) {
1134 RT_BCOPY_UNFORTIFIED(&pReq->StrPath, path, SHFLSTRING_HEADER_SIZE + path->u16Size);
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;
1138
1139 rc = VbglR0SfHostReqRemove(pSuperInfo->map.root, pReq, fFlags);
1140
1141 if (dentry->d_inode) {
1142 struct vbsf_inode_info *sf_i = VBSF_GET_INODE_INFO(dentry->d_inode);
1143 sf_i->force_restat = true;
1144 }
1145
1146 if (RT_SUCCESS(rc)) {
1147 sf_parent_i->force_restat = true; /* directory access/change time changed */
1148 rc = 0;
1149 } else if (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND) {
1150 /* Probably deleted on the host while the guest had it cached, so don't complain: */
1151 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc; calling d_drop on %p\n",
1152 fDirectory, path->String.ach, rc, dentry));
1153 sf_parent_i->force_restat = true;
1154 d_drop(dentry);
1155 rc = 0;
1156 } else {
1157 LogFunc(("(%d): VbglR0SfRemove(%s) failed rc=%Rrc\n", fDirectory, path->String.ach, rc));
1158 rc = -RTErrConvertToErrno(rc);
1159 }
1160 VbglR0PhysHeapFree(pReq);
1161 } else
1162 rc = -ENOMEM;
1163 kfree(path);
1164 }
1165 return rc;
1166}
1167
1168
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 */
1176static int vbsf_inode_unlink(struct inode *parent, struct dentry *dentry)
1177{
1178 TRACE();
1179 return vbsf_unlink_worker(parent, dentry, false /*fDirectory*/);
1180}
1181
1182
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 */
1190static int vbsf_inode_rmdir(struct inode *parent, struct dentry *dentry)
1191{
1192 TRACE();
1193 return vbsf_unlink_worker(parent, dentry, true /*fDirectory*/);
1194}
1195
1196
1197/**
1198 * Rename a regular file / directory.
1199 *
1200 * @param idmap idmap of the mount.
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
1206 * @returns 0 on success, Linux error code otherwise
1207 */
1208#if RTLNX_VER_MIN(6,3,0) || defined(DOXYGEN_RUNNING)
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)
1212#elif RTLNX_VER_MIN(5,12,0)
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
1217static int vbsf_inode_rename(struct inode *old_parent, struct dentry *old_dentry,
1218 struct inode *new_parent, struct dentry *new_dentry, unsigned flags)
1219#endif
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;
1227#if RTLNX_VER_MIN(3,15,0)
1228 if (!(flags & ~RENAME_NOREPLACE)) {
1229 if (flags & RENAME_NOREPLACE)
1230 fRename &= ~SHFL_RENAME_REPLACE_IF_EXISTS;
1231#endif
1232 /*
1233 * Check that they are on the same mount.
1234 */
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)) {
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;
1242 rc = vbsf_path_from_dentry(pSuperInfo, sf_new_parent_i, new_dentry, &pNewPath, __func__);
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;
1253
1254 RT_BCOPY_UNFORTIFIED(&pReq->StrDstPath, pNewPath, SHFLSTRING_HEADER_SIZE + pNewPath->u16Size);
1255 rc = VbglR0SfHostReqRenameWithSrcContig(pSuperInfo->map.root, pReq, pOldPath, virt_to_phys(pOldPath), fRename);
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));
1264
1265 sf_file_i->path = pNewPath;
1266 kfree(pOldPath);
1267 pNewPath = NULL;
1268
1269 sf_new_parent_i->force_restat = 1;
1270 sf_old_parent_i->force_restat = 1;
1271
1272 vbsf_dentry_chain_increase_parent_ttl(old_dentry);
1273 vbsf_dentry_chain_increase_parent_ttl(new_dentry);
1274
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)
1280 vbsf_dentry_invalidate_ttl(old_dentry);
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);
1290 } else
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",
1294 pSuperInfo->map.root, VBSF_GET_SUPER_INFO(new_parent->i_sb)->map.root));
1295 rc = -EXDEV;
1296 }
1297#if RTLNX_VER_MIN(3,15,0)
1298 } else {
1299 SFLOGFLOW(("vbsf_inode_rename: Unsupported flags: %#x\n", flags));
1300 rc = -EINVAL;
1301 }
1302#else
1303 RT_NOREF(flags);
1304#endif
1305 return rc;
1306}
1307
1308
1309#if RTLNX_VER_MAX(4,9,0)
1310/**
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/**
1322 * Create a symbolic link.
1323 */
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)
1327static int vbsf_inode_symlink(struct user_namespace *ns, struct inode *parent, struct dentry *dentry, const char *target)
1328#else
1329static int vbsf_inode_symlink(struct inode *parent, struct dentry *dentry, const char *target)
1330#endif
1331{
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. */
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);
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;
1346 rc = vbsf_path_from_dentry(pSuperInfo, sf_i, dentry, &pPath, __func__);
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);
1355 RT_BCOPY_UNFORTIFIED(&pReq->StrSymlinkPath, pPath, SHFLSTRING_HEADER_SIZE + pPath->u16Size);
1356
1357 rc = VbglR0SfHostReqCreateSymlinkContig(pSuperInfo->map.root, pTarget, virt_to_phys(pTarget), pReq);
1358 if (RT_SUCCESS(rc)) {
1359 sf_i->force_restat = 1;
1360
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 */
1368 vbsf_dentry_chain_increase_ttl(dentry);
1369 } else {
1370 SFLOGFLOW(("vbsf_inode_symlink: Failed to create inode for '%s': %d\n", pPath->String.ach, rc));
1371 vbsf_dentry_chain_increase_parent_ttl(dentry);
1372 vbsf_dentry_invalidate_ttl(dentry);
1373 }
1374 } else {
1375 int const vrc = rc;
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);
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);
1393 }
1394 return rc;
1395}
1396
1397
1398/**
1399 * Directory inode operations.
1400 */
1401struct inode_operations vbsf_dir_iops = {
1402 .lookup = vbsf_inode_lookup,
1403#if RTLNX_VER_MIN(3,16,0)
1404 .atomic_open = vbsf_inode_atomic_open,
1405#endif
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,
1411#if RTLNX_VER_MIN(4,9,0)
1412 .rename = vbsf_inode_rename,
1413#else
1414# if RTLNX_VER_MAX(3,17,0)
1415 .rename = vbsf_inode_rename_no_flags,
1416# endif
1417# if RTLNX_VER_MIN(3,15,0)
1418 .rename2 = vbsf_inode_rename,
1419# endif
1420#endif
1421#if RTLNX_VER_MIN(2,5,18)
1422 .getattr = vbsf_inode_getattr,
1423#else
1424 .revalidate = vbsf_inode_revalidate,
1425#endif
1426 .setattr = vbsf_inode_setattr,
1427};
1428
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette