VirtualBox

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

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

linux/vboxsf: Fixed nls conversion issue (don't try convert the zero terminator, at least not on 2.6.8). Hacked around missing invalidate_mapping_pages symbol in kernels before 2.6.21.

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