[38736] | 1 | /* $Id: vbsf.cpp 100220 2023-06-19 19:14:10Z vboxsync $ */
|
---|
[3338] | 2 | /** @file
|
---|
[38736] | 3 | * Shared Folders - VBox Shared Folders.
|
---|
[3338] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2006-2023 Oracle and/or its affiliates.
|
---|
[3338] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[3338] | 26 | */
|
---|
| 27 |
|
---|
[75506] | 28 |
|
---|
[75498] | 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
| 32 | #define LOG_GROUP LOG_GROUP_SHARED_FOLDERS
|
---|
[39540] | 33 | #ifdef UNITTEST
|
---|
| 34 | # include "testcase/tstSharedFolderService.h"
|
---|
| 35 | #endif
|
---|
| 36 |
|
---|
[56962] | 37 | #include "vbsfpath.h"
|
---|
[3338] | 38 | #include "mappings.h"
|
---|
| 39 | #include "vbsf.h"
|
---|
| 40 | #include "shflhandle.h"
|
---|
| 41 |
|
---|
[76143] | 42 | #include <VBox/AssertGuest.h>
|
---|
[77243] | 43 | #include <VBox/param.h>
|
---|
[100220] | 44 | #include <VBox/VMMDev.h>
|
---|
[3338] | 45 | #include <iprt/alloc.h>
|
---|
| 46 | #include <iprt/assert.h>
|
---|
[56962] | 47 | #include <iprt/asm.h>
|
---|
[3338] | 48 | #include <iprt/fs.h>
|
---|
| 49 | #include <iprt/dir.h>
|
---|
| 50 | #include <iprt/file.h>
|
---|
| 51 | #include <iprt/path.h>
|
---|
| 52 | #include <iprt/string.h>
|
---|
[33439] | 53 | #include <iprt/symlink.h>
|
---|
[3338] | 54 | #include <iprt/uni.h>
|
---|
[20346] | 55 | #include <iprt/stream.h>
|
---|
[9880] | 56 | #ifdef RT_OS_DARWIN
|
---|
[38736] | 57 | # include <Carbon/Carbon.h>
|
---|
[9880] | 58 | #endif
|
---|
[3338] | 59 |
|
---|
[39542] | 60 | #ifdef UNITTEST
|
---|
| 61 | # include "teststubs.h"
|
---|
| 62 | #endif
|
---|
| 63 |
|
---|
[75498] | 64 |
|
---|
| 65 | /*********************************************************************************************************************************
|
---|
| 66 | * Defined Constants And Macros *
|
---|
| 67 | *********************************************************************************************************************************/
|
---|
[39643] | 68 | #define SHFL_RT_LINK(pClient) ((pClient)->fu32Flags & SHFL_CF_SYMLINKS ? RTPATH_F_ON_LINK : RTPATH_F_FOLLOW_LINK)
|
---|
[39627] | 69 |
|
---|
[78704] | 70 | /**
|
---|
| 71 | * @todo find a better solution for supporting the execute bit for non-windows
|
---|
| 72 | * guests on windows host. Search for "0111" to find all the relevant places.
|
---|
| 73 | */
|
---|
[75498] | 74 |
|
---|
[78704] | 75 |
|
---|
[78703] | 76 | #ifndef RT_OS_WINDOWS
|
---|
[78704] | 77 |
|
---|
[19171] | 78 | /**
|
---|
[78703] | 79 | * Helps to check if pszPath deserves a VERR_PATH_NOT_FOUND status when catering
|
---|
| 80 | * to windows guests.
|
---|
| 81 | */
|
---|
| 82 | static bool vbsfErrorStyleIsWindowsPathNotFound(char *pszPath)
|
---|
| 83 | {
|
---|
| 84 | /*
|
---|
| 85 | * Check if the parent directory actually exists. We temporarily modify the path here.
|
---|
| 86 | */
|
---|
| 87 | size_t cchParent = RTPathParentLength(pszPath);
|
---|
| 88 | char chSaved = pszPath[cchParent];
|
---|
| 89 | pszPath[cchParent] = '\0';
|
---|
| 90 | RTFSOBJINFO ObjInfo;
|
---|
| 91 | int vrc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
|
---|
| 92 | pszPath[cchParent] = chSaved;
|
---|
| 93 | if (RT_SUCCESS(vrc))
|
---|
| 94 | {
|
---|
| 95 | if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 96 | return false;
|
---|
| 97 | return true;
|
---|
| 98 | }
|
---|
| 99 | if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND)
|
---|
| 100 | return true;
|
---|
| 101 | return false;
|
---|
| 102 | }
|
---|
| 103 |
|
---|
[78704] | 104 | /**
|
---|
| 105 | * Helps to check if pszPath deserves a VERR_PATH_NOT_FOUND status when catering
|
---|
| 106 | * to windows guests.
|
---|
| 107 | */
|
---|
| 108 | static bool vbsfErrorStyleIsWindowsPathNotFound2(char *pszSrcPath, char *pszDstPath)
|
---|
| 109 | {
|
---|
| 110 | /*
|
---|
| 111 | * Do the source parent first.
|
---|
| 112 | */
|
---|
| 113 | size_t cchParent = RTPathParentLength(pszSrcPath);
|
---|
| 114 | char chSaved = pszSrcPath[cchParent];
|
---|
| 115 | pszSrcPath[cchParent] = '\0';
|
---|
| 116 | RTFSOBJINFO ObjInfo;
|
---|
| 117 | int vrc = RTPathQueryInfoEx(pszSrcPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
|
---|
| 118 | pszSrcPath[cchParent] = chSaved;
|
---|
| 119 | if ( (RT_SUCCESS(vrc) && !RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 120 | || vrc == VERR_FILE_NOT_FOUND
|
---|
| 121 | || vrc == VERR_PATH_NOT_FOUND)
|
---|
| 122 | return true;
|
---|
| 123 | if (RT_FAILURE(vrc))
|
---|
| 124 | return false;
|
---|
[78703] | 125 |
|
---|
[78704] | 126 | /*
|
---|
| 127 | * The source itself.
|
---|
| 128 | */
|
---|
| 129 | vrc = RTPathQueryInfoEx(pszSrcPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
|
---|
| 130 | if (RT_SUCCESS(vrc))
|
---|
| 131 | {
|
---|
| 132 | /*
|
---|
| 133 | * The source is fine, continue with the destination.
|
---|
| 134 | */
|
---|
| 135 | cchParent = RTPathParentLength(pszDstPath);
|
---|
| 136 | chSaved = pszDstPath[cchParent];
|
---|
| 137 | pszDstPath[cchParent] = '\0';
|
---|
| 138 | vrc = RTPathQueryInfoEx(pszDstPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
|
---|
| 139 | pszDstPath[cchParent] = chSaved;
|
---|
| 140 | if ( (RT_SUCCESS(vrc) && !RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 141 | || vrc == VERR_FILE_NOT_FOUND
|
---|
| 142 | || vrc == VERR_PATH_NOT_FOUND)
|
---|
| 143 | return true;
|
---|
| 144 | }
|
---|
| 145 | return false;
|
---|
| 146 | }
|
---|
| 147 |
|
---|
[78703] | 148 | /**
|
---|
[78704] | 149 | * Helps checking if the specified path happens to exist but not be a directory.
|
---|
[19171] | 150 | */
|
---|
[78704] | 151 | static bool vbsfErrorStyleIsWindowsNotADirectory(const char *pszPath)
|
---|
| 152 | {
|
---|
| 153 | RTFSOBJINFO ObjInfo;
|
---|
| 154 | int vrc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
|
---|
| 155 | if (RT_SUCCESS(vrc))
|
---|
| 156 | {
|
---|
| 157 | if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 158 | return false;
|
---|
| 159 | return true;
|
---|
| 160 | }
|
---|
| 161 | return false;
|
---|
| 162 | }
|
---|
[19171] | 163 |
|
---|
[78704] | 164 | /**
|
---|
| 165 | * Helps to check if pszPath deserves a VERR_INVALID_NAME status when catering
|
---|
| 166 | * to windows guests.
|
---|
| 167 | */
|
---|
| 168 | static bool vbsfErrorStyleIsWindowsInvalidNameForNonDir(char *pszPath)
|
---|
| 169 | {
|
---|
| 170 | /*
|
---|
| 171 | * This only applies to paths with trailing slashes.
|
---|
| 172 | */
|
---|
| 173 | size_t const cchPath = strlen(pszPath);
|
---|
| 174 | if (cchPath > 0 && RTPATH_IS_SLASH(pszPath[cchPath - 1]))
|
---|
| 175 | {
|
---|
| 176 | /*
|
---|
| 177 | * However it doesn't if an earlier path component is missing or not a file.
|
---|
| 178 | */
|
---|
| 179 | size_t cchParent = RTPathParentLength(pszPath);
|
---|
| 180 | char chSaved = pszPath[cchParent];
|
---|
| 181 | pszPath[cchParent] = '\0';
|
---|
| 182 | RTFSOBJINFO ObjInfo;
|
---|
| 183 | int vrc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
|
---|
| 184 | pszPath[cchParent] = chSaved;
|
---|
| 185 | if (RT_SUCCESS(vrc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 186 | return true;
|
---|
| 187 | }
|
---|
| 188 | return false;
|
---|
| 189 | }
|
---|
| 190 |
|
---|
| 191 | #endif /* RT_OS_WINDOWS */
|
---|
| 192 |
|
---|
[99775] | 193 | static void vbsfStripLastComponent(char *pszFullPath, uint32_t cbFullPathRoot)
|
---|
[3338] | 194 | {
|
---|
| 195 | RTUNICP cp;
|
---|
| 196 |
|
---|
| 197 | /* Do not strip root. */
|
---|
| 198 | char *s = pszFullPath + cbFullPathRoot;
|
---|
| 199 | char *delimSecondLast = NULL;
|
---|
| 200 | char *delimLast = NULL;
|
---|
| 201 |
|
---|
| 202 | LogFlowFunc(("%s -> %s\n", pszFullPath, s));
|
---|
| 203 |
|
---|
| 204 | for (;;)
|
---|
| 205 | {
|
---|
| 206 | cp = RTStrGetCp(s);
|
---|
| 207 |
|
---|
| 208 | if (cp == RTUNICP_INVALID || cp == 0)
|
---|
| 209 | {
|
---|
| 210 | break;
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | if (cp == RTPATH_DELIMITER)
|
---|
| 214 | {
|
---|
| 215 | if (delimLast != NULL)
|
---|
| 216 | {
|
---|
| 217 | delimSecondLast = delimLast;
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | delimLast = s;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
[39594] | 223 | s = RTStrNextCp(s);
|
---|
[3338] | 224 | }
|
---|
| 225 |
|
---|
| 226 | if (cp == 0)
|
---|
| 227 | {
|
---|
| 228 | if (delimLast + 1 == s)
|
---|
| 229 | {
|
---|
| 230 | if (delimSecondLast)
|
---|
| 231 | {
|
---|
| 232 | *delimSecondLast = 0;
|
---|
| 233 | }
|
---|
| 234 | else if (delimLast)
|
---|
| 235 | {
|
---|
| 236 | *delimLast = 0;
|
---|
| 237 | }
|
---|
| 238 | }
|
---|
| 239 | else
|
---|
| 240 | {
|
---|
| 241 | if (delimLast)
|
---|
| 242 | {
|
---|
| 243 | *delimLast = 0;
|
---|
| 244 | }
|
---|
| 245 | }
|
---|
| 246 | }
|
---|
| 247 |
|
---|
| 248 | LogFlowFunc(("%s, %s, %s\n", pszFullPath, delimLast, delimSecondLast));
|
---|
| 249 | }
|
---|
[3960] | 250 |
|
---|
[77848] | 251 | static int vbsfBuildFullPath(SHFLCLIENTDATA *pClient, SHFLROOT root, PCSHFLSTRING pPath,
|
---|
[39594] | 252 | uint32_t cbPath, char **ppszFullPath, uint32_t *pcbFullPathRoot,
|
---|
| 253 | bool fWildCard = false, bool fPreserveLastComponent = false)
|
---|
[3338] | 254 | {
|
---|
[56962] | 255 | char *pszHostPath = NULL;
|
---|
| 256 | uint32_t fu32PathFlags = 0;
|
---|
[57782] | 257 | uint32_t fu32Options = VBSF_O_PATH_CHECK_ROOT_ESCAPE
|
---|
| 258 | | (fWildCard? VBSF_O_PATH_WILDCARD: 0)
|
---|
| 259 | | (fPreserveLastComponent? VBSF_O_PATH_PRESERVE_LAST_COMPONENT: 0);
|
---|
| 260 |
|
---|
[56962] | 261 | int rc = vbsfPathGuestToHost(pClient, root, pPath, cbPath,
|
---|
[57782] | 262 | &pszHostPath, pcbFullPathRoot, fu32Options, &fu32PathFlags);
|
---|
[56962] | 263 | if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
|
---|
[3338] | 264 | {
|
---|
[56962] | 265 | LogRel2(("SharedFolders: GuestToHost 0x%RX32 [%.*s]->[%s] %Rrc\n", fu32PathFlags, pPath->u16Length, &pPath->String.utf8[0], pszHostPath, rc));
|
---|
[3338] | 266 | }
|
---|
[56962] | 267 | else
|
---|
[3338] | 268 | {
|
---|
[99802] | 269 | LogRel2(("SharedFolders: GuestToHost 0x%RX32 [%.*ls]->[%s] %Rrc\n", fu32PathFlags, pPath->u16Length / 2, &pPath->String.utf16[0], pszHostPath, rc));
|
---|
[3338] | 270 | }
|
---|
[9927] | 271 |
|
---|
[39594] | 272 | if (RT_SUCCESS(rc))
|
---|
[3338] | 273 | {
|
---|
[56962] | 274 | if (ppszFullPath)
|
---|
| 275 | *ppszFullPath = pszHostPath;
|
---|
[3338] | 276 | }
|
---|
| 277 | return rc;
|
---|
| 278 | }
|
---|
| 279 |
|
---|
[39594] | 280 | static void vbsfFreeFullPath(char *pszFullPath)
|
---|
[3338] | 281 | {
|
---|
[56962] | 282 | vbsfFreeHostPath(pszFullPath);
|
---|
[3338] | 283 | }
|
---|
| 284 |
|
---|
[65288] | 285 | typedef enum VBSFCHECKACCESS
|
---|
| 286 | {
|
---|
| 287 | VBSF_CHECK_ACCESS_READ = 0,
|
---|
| 288 | VBSF_CHECK_ACCESS_WRITE = 1
|
---|
| 289 | } VBSFCHECKACCESS;
|
---|
| 290 |
|
---|
[5258] | 291 | /**
|
---|
[65288] | 292 | * Check if the handle data is valid and the operation is allowed on the shared folder.
|
---|
| 293 | *
|
---|
| 294 | * @returns IPRT status code
|
---|
| 295 | * @param pClient Data structure describing the client accessing the shared folder
|
---|
| 296 | * @param root The index of the shared folder in the table of mappings.
|
---|
| 297 | * @param pHandle Information about the file or directory object.
|
---|
| 298 | * @param enmCheckAccess Whether the operation needs read only or write access.
|
---|
| 299 | */
|
---|
| 300 | static int vbsfCheckHandleAccess(SHFLCLIENTDATA *pClient, SHFLROOT root,
|
---|
| 301 | SHFLFILEHANDLE *pHandle, VBSFCHECKACCESS enmCheckAccess)
|
---|
| 302 | {
|
---|
| 303 | /* Handle from the same 'root' index? */
|
---|
| 304 | if (RT_LIKELY(RT_VALID_PTR(pHandle) && root == pHandle->root))
|
---|
| 305 | { /* likely */ }
|
---|
| 306 | else
|
---|
| 307 | return VERR_INVALID_HANDLE;
|
---|
| 308 |
|
---|
| 309 | /* Check if the guest is still allowed to access this share.
|
---|
| 310 | * vbsfMappingsQueryWritable returns error if the shared folder has been removed from the VM settings.
|
---|
| 311 | */
|
---|
| 312 | bool fWritable;
|
---|
| 313 | int rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
|
---|
| 314 | if (RT_SUCCESS(rc))
|
---|
| 315 | { /* likely */ }
|
---|
| 316 | else
|
---|
| 317 | return VERR_ACCESS_DENIED;
|
---|
| 318 |
|
---|
| 319 | if (enmCheckAccess == VBSF_CHECK_ACCESS_WRITE)
|
---|
| 320 | {
|
---|
| 321 | /* Operation requires write access. Check if the shared folder is writable too. */
|
---|
| 322 | if (RT_LIKELY(fWritable))
|
---|
| 323 | { /* likely */ }
|
---|
| 324 | else
|
---|
| 325 | return VERR_WRITE_PROTECT;
|
---|
| 326 | }
|
---|
| 327 |
|
---|
| 328 | return VINF_SUCCESS;
|
---|
| 329 | }
|
---|
| 330 |
|
---|
| 331 | /**
|
---|
[5258] | 332 | * Convert shared folder create flags (see include/iprt/shflsvc.h) into iprt create flags.
|
---|
| 333 | *
|
---|
| 334 | * @returns iprt status code
|
---|
[65279] | 335 | * @param fWritable whether the shared folder is writable
|
---|
[5258] | 336 | * @param fShflFlags shared folder create flags
|
---|
[33540] | 337 | * @param fMode file attributes
|
---|
[65123] | 338 | * @param handleInitial initial handle
|
---|
[81369] | 339 | * @param pfOpen Where to return iprt create flags
|
---|
[5258] | 340 | */
|
---|
[77685] | 341 | static int vbsfConvertFileOpenFlags(bool fWritable, unsigned fShflFlags, RTFMODE fMode, SHFLHANDLE handleInitial, uint64_t *pfOpen)
|
---|
[3338] | 342 | {
|
---|
[77685] | 343 | uint64_t fOpen = 0;
|
---|
[3338] | 344 | int rc = VINF_SUCCESS;
|
---|
| 345 |
|
---|
[20279] | 346 | if ( (fMode & RTFS_DOS_MASK) != 0
|
---|
| 347 | && (fMode & RTFS_UNIX_MASK) == 0)
|
---|
| 348 | {
|
---|
| 349 | /* A DOS/Windows guest, make RTFS_UNIX_* from RTFS_DOS_*.
|
---|
| 350 | * @todo this is based on rtFsModeNormalize/rtFsModeFromDos.
|
---|
| 351 | * May be better to use RTFsModeNormalize here.
|
---|
| 352 | */
|
---|
| 353 | fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IRGRP | RTFS_UNIX_IROTH;
|
---|
| 354 | /* x for directories. */
|
---|
| 355 | if (fMode & RTFS_DOS_DIRECTORY)
|
---|
| 356 | fMode |= RTFS_TYPE_DIRECTORY | RTFS_UNIX_IXUSR | RTFS_UNIX_IXGRP | RTFS_UNIX_IXOTH;
|
---|
| 357 | /* writable? */
|
---|
| 358 | if (!(fMode & RTFS_DOS_READONLY))
|
---|
| 359 | fMode |= RTFS_UNIX_IWUSR | RTFS_UNIX_IWGRP | RTFS_UNIX_IWOTH;
|
---|
[20316] | 360 |
|
---|
| 361 | /* Set the requested mode using only allowed bits. */
|
---|
| 362 | fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
|
---|
[20279] | 363 | }
|
---|
[20316] | 364 | else
|
---|
| 365 | {
|
---|
| 366 | /* Old linux and solaris additions did not initialize the Info.Attr.fMode field
|
---|
| 367 | * and it contained random bits from stack. Detect this using the handle field value
|
---|
| 368 | * passed from the guest: old additions set it (incorrectly) to 0, new additions
|
---|
| 369 | * set it to SHFL_HANDLE_NIL(~0).
|
---|
| 370 | */
|
---|
| 371 | if (handleInitial == 0)
|
---|
| 372 | {
|
---|
| 373 | /* Old additions. Do nothing, use default mode. */
|
---|
| 374 | }
|
---|
| 375 | else
|
---|
| 376 | {
|
---|
| 377 | /* New additions or Windows additions. Set the requested mode using only allowed bits.
|
---|
| 378 | * Note: Windows guest set RTFS_UNIX_MASK bits to 0, which means a default mode
|
---|
| 379 | * will be set in fOpen.
|
---|
| 380 | */
|
---|
| 381 | fOpen |= ((fMode & RTFS_UNIX_MASK) << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK;
|
---|
| 382 | }
|
---|
| 383 | }
|
---|
[20279] | 384 |
|
---|
[5258] | 385 | switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_RW))
|
---|
[3338] | 386 | {
|
---|
| 387 | default:
|
---|
| 388 | case SHFL_CF_ACCESS_NONE:
|
---|
| 389 | {
|
---|
[58770] | 390 | #ifdef RT_OS_WINDOWS
|
---|
| 391 | if (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_ATTR) != SHFL_CF_ACCESS_ATTR_NONE)
|
---|
| 392 | fOpen |= RTFILE_O_ATTR_ONLY;
|
---|
| 393 | else
|
---|
| 394 | #endif
|
---|
| 395 | fOpen |= RTFILE_O_READ;
|
---|
[3338] | 396 | Log(("FLAG: SHFL_CF_ACCESS_NONE\n"));
|
---|
| 397 | break;
|
---|
| 398 | }
|
---|
| 399 |
|
---|
| 400 | case SHFL_CF_ACCESS_READ:
|
---|
| 401 | {
|
---|
| 402 | fOpen |= RTFILE_O_READ;
|
---|
| 403 | Log(("FLAG: SHFL_CF_ACCESS_READ\n"));
|
---|
| 404 | break;
|
---|
| 405 | }
|
---|
| 406 |
|
---|
| 407 | case SHFL_CF_ACCESS_WRITE:
|
---|
| 408 | {
|
---|
| 409 | fOpen |= RTFILE_O_WRITE;
|
---|
| 410 | Log(("FLAG: SHFL_CF_ACCESS_WRITE\n"));
|
---|
| 411 | break;
|
---|
| 412 | }
|
---|
| 413 |
|
---|
| 414 | case SHFL_CF_ACCESS_READWRITE:
|
---|
| 415 | {
|
---|
| 416 | fOpen |= RTFILE_O_READWRITE;
|
---|
| 417 | Log(("FLAG: SHFL_CF_ACCESS_READWRITE\n"));
|
---|
| 418 | break;
|
---|
| 419 | }
|
---|
| 420 | }
|
---|
| 421 |
|
---|
[24350] | 422 | if (fShflFlags & SHFL_CF_ACCESS_APPEND)
|
---|
| 423 | {
|
---|
| 424 | fOpen |= RTFILE_O_APPEND;
|
---|
| 425 | }
|
---|
| 426 |
|
---|
[18128] | 427 | switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_ATTR))
|
---|
| 428 | {
|
---|
| 429 | default:
|
---|
| 430 | case SHFL_CF_ACCESS_ATTR_NONE:
|
---|
| 431 | {
|
---|
| 432 | fOpen |= RTFILE_O_ACCESS_ATTR_DEFAULT;
|
---|
| 433 | Log(("FLAG: SHFL_CF_ACCESS_ATTR_NONE\n"));
|
---|
| 434 | break;
|
---|
| 435 | }
|
---|
| 436 |
|
---|
| 437 | case SHFL_CF_ACCESS_ATTR_READ:
|
---|
| 438 | {
|
---|
| 439 | fOpen |= RTFILE_O_ACCESS_ATTR_READ;
|
---|
| 440 | Log(("FLAG: SHFL_CF_ACCESS_ATTR_READ\n"));
|
---|
| 441 | break;
|
---|
| 442 | }
|
---|
| 443 |
|
---|
| 444 | case SHFL_CF_ACCESS_ATTR_WRITE:
|
---|
| 445 | {
|
---|
| 446 | fOpen |= RTFILE_O_ACCESS_ATTR_WRITE;
|
---|
| 447 | Log(("FLAG: SHFL_CF_ACCESS_ATTR_WRITE\n"));
|
---|
| 448 | break;
|
---|
| 449 | }
|
---|
| 450 |
|
---|
| 451 | case SHFL_CF_ACCESS_ATTR_READWRITE:
|
---|
| 452 | {
|
---|
| 453 | fOpen |= RTFILE_O_ACCESS_ATTR_READWRITE;
|
---|
| 454 | Log(("FLAG: SHFL_CF_ACCESS_ATTR_READWRITE\n"));
|
---|
| 455 | break;
|
---|
| 456 | }
|
---|
| 457 | }
|
---|
| 458 |
|
---|
[3338] | 459 | /* Sharing mask */
|
---|
[5258] | 460 | switch (BIT_FLAG(fShflFlags, SHFL_CF_ACCESS_MASK_DENY))
|
---|
[3338] | 461 | {
|
---|
[77685] | 462 | default:
|
---|
| 463 | case SHFL_CF_ACCESS_DENYNONE:
|
---|
| 464 | fOpen |= RTFILE_O_DENY_NONE;
|
---|
| 465 | Log(("FLAG: SHFL_CF_ACCESS_DENYNONE\n"));
|
---|
| 466 | break;
|
---|
[3338] | 467 |
|
---|
[77685] | 468 | case SHFL_CF_ACCESS_DENYREAD:
|
---|
| 469 | fOpen |= RTFILE_O_DENY_READ;
|
---|
| 470 | Log(("FLAG: SHFL_CF_ACCESS_DENYREAD\n"));
|
---|
| 471 | break;
|
---|
[3338] | 472 |
|
---|
[77685] | 473 | case SHFL_CF_ACCESS_DENYWRITE:
|
---|
| 474 | fOpen |= RTFILE_O_DENY_WRITE;
|
---|
| 475 | Log(("FLAG: SHFL_CF_ACCESS_DENYWRITE\n"));
|
---|
| 476 | break;
|
---|
[3338] | 477 |
|
---|
[77685] | 478 | case SHFL_CF_ACCESS_DENYALL:
|
---|
| 479 | fOpen |= RTFILE_O_DENY_ALL;
|
---|
| 480 | Log(("FLAG: SHFL_CF_ACCESS_DENYALL\n"));
|
---|
| 481 | break;
|
---|
[3338] | 482 | }
|
---|
| 483 |
|
---|
[5258] | 484 | /* Open/Create action mask */
|
---|
| 485 | switch (BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
|
---|
[3338] | 486 | {
|
---|
[77685] | 487 | case SHFL_CF_ACT_OPEN_IF_EXISTS:
|
---|
| 488 | if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 489 | {
|
---|
| 490 | fOpen |= RTFILE_O_OPEN_CREATE;
|
---|
| 491 | Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
|
---|
| 492 | }
|
---|
| 493 | else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 494 | {
|
---|
| 495 | fOpen |= RTFILE_O_OPEN;
|
---|
| 496 | Log(("FLAGS: SHFL_CF_ACT_OPEN_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
|
---|
| 497 | }
|
---|
| 498 | else
|
---|
| 499 | {
|
---|
| 500 | Log(("FLAGS: invalid open/create action combination\n"));
|
---|
| 501 | rc = VERR_INVALID_PARAMETER;
|
---|
| 502 | }
|
---|
| 503 | break;
|
---|
| 504 | case SHFL_CF_ACT_FAIL_IF_EXISTS:
|
---|
| 505 | if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 506 | {
|
---|
| 507 | fOpen |= RTFILE_O_CREATE;
|
---|
| 508 | Log(("FLAGS: SHFL_CF_ACT_FAIL_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
|
---|
| 509 | }
|
---|
| 510 | else
|
---|
| 511 | {
|
---|
| 512 | Log(("FLAGS: invalid open/create action combination\n"));
|
---|
| 513 | rc = VERR_INVALID_PARAMETER;
|
---|
| 514 | }
|
---|
| 515 | break;
|
---|
| 516 | case SHFL_CF_ACT_REPLACE_IF_EXISTS:
|
---|
| 517 | if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 518 | {
|
---|
| 519 | fOpen |= RTFILE_O_CREATE_REPLACE;
|
---|
| 520 | Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
|
---|
| 521 | }
|
---|
| 522 | else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 523 | {
|
---|
| 524 | fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
|
---|
| 525 | Log(("FLAGS: SHFL_CF_ACT_REPLACE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
|
---|
| 526 | }
|
---|
| 527 | else
|
---|
| 528 | {
|
---|
| 529 | Log(("FLAGS: invalid open/create action combination\n"));
|
---|
| 530 | rc = VERR_INVALID_PARAMETER;
|
---|
| 531 | }
|
---|
| 532 | break;
|
---|
| 533 | case SHFL_CF_ACT_OVERWRITE_IF_EXISTS:
|
---|
| 534 | if (SHFL_CF_ACT_CREATE_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 535 | {
|
---|
| 536 | fOpen |= RTFILE_O_CREATE_REPLACE;
|
---|
| 537 | Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_CREATE_IF_NEW\n"));
|
---|
| 538 | }
|
---|
| 539 | else if (SHFL_CF_ACT_FAIL_IF_NEW == BIT_FLAG(fShflFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 540 | {
|
---|
| 541 | fOpen |= RTFILE_O_OPEN | RTFILE_O_TRUNCATE;
|
---|
| 542 | Log(("FLAGS: SHFL_CF_ACT_OVERWRITE_IF_EXISTS and SHFL_CF_ACT_FAIL_IF_NEW\n"));
|
---|
| 543 | }
|
---|
| 544 | else
|
---|
| 545 | {
|
---|
| 546 | Log(("FLAGS: invalid open/create action combination\n"));
|
---|
| 547 | rc = VERR_INVALID_PARAMETER;
|
---|
| 548 | }
|
---|
| 549 | break;
|
---|
| 550 | default:
|
---|
[5258] | 551 | rc = VERR_INVALID_PARAMETER;
|
---|
[77685] | 552 | Log(("FLAG: SHFL_CF_ACT_MASK_IF_EXISTS - invalid parameter\n"));
|
---|
[3338] | 553 | }
|
---|
| 554 |
|
---|
[5258] | 555 | if (RT_SUCCESS(rc))
|
---|
[3338] | 556 | {
|
---|
[65279] | 557 | if (!fWritable)
|
---|
| 558 | fOpen &= ~RTFILE_O_WRITE;
|
---|
| 559 |
|
---|
[5258] | 560 | *pfOpen = fOpen;
|
---|
[3338] | 561 | }
|
---|
| 562 | return rc;
|
---|
| 563 | }
|
---|
| 564 |
|
---|
[5258] | 565 | /**
|
---|
| 566 | * Open a file or create and open a new one.
|
---|
| 567 | *
|
---|
| 568 | * @returns IPRT status code
|
---|
[81369] | 569 | * @param pClient Data structure describing the client accessing the shared folder
|
---|
| 570 | * @param root The index of the shared folder in the table of mappings.
|
---|
| 571 | * @param pszPath Path to the file or folder on the host.
|
---|
| 572 | * @param pParms Input:
|
---|
| 573 | * - @a CreateFlags: Creation or open parameters, see include/VBox/shflsvc.h
|
---|
| 574 | * - @a Info: When a new file is created this specifies the initial parameters.
|
---|
| 575 | * When a file is created or overwritten, it also specifies the
|
---|
| 576 | * initial size.
|
---|
| 577 | * Output:
|
---|
| 578 | * - @a Result: Shared folder status code, see include/VBox/shflsvc.h
|
---|
| 579 | * - @a Handle: On success the (shared folder) handle of the file opened or
|
---|
| 580 | * created
|
---|
| 581 | * - @a Info: On success the parameters of the file opened or created
|
---|
[5258] | 582 | */
|
---|
[78703] | 583 | static int vbsfOpenFile(SHFLCLIENTDATA *pClient, SHFLROOT root, char *pszPath, SHFLCREATEPARMS *pParms)
|
---|
[3338] | 584 | {
|
---|
[5258] | 585 | LogFlow(("vbsfOpenFile: pszPath = %s, pParms = %p\n", pszPath, pParms));
|
---|
| 586 | Log(("SHFL create flags %08x\n", pParms->CreateFlags));
|
---|
[3338] | 587 |
|
---|
[77685] | 588 | RTFILEACTION enmActionTaken = RTFILEACTION_INVALID;
|
---|
| 589 | SHFLHANDLE handle = SHFL_HANDLE_NIL;
|
---|
| 590 | SHFLFILEHANDLE *pHandle = NULL;
|
---|
[6831] | 591 |
|
---|
[65279] | 592 | /* is the guest allowed to write to this share? */
|
---|
| 593 | bool fWritable;
|
---|
| 594 | int rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
|
---|
| 595 | if (RT_FAILURE(rc))
|
---|
| 596 | fWritable = false;
|
---|
| 597 |
|
---|
[77685] | 598 | uint64_t fOpen = 0;
|
---|
[65279] | 599 | rc = vbsfConvertFileOpenFlags(fWritable, pParms->CreateFlags, pParms->Info.Attr.fMode, pParms->Handle, &fOpen);
|
---|
[5258] | 600 | if (RT_SUCCESS(rc))
|
---|
[3338] | 601 | {
|
---|
[40109] | 602 | rc = VERR_NO_MEMORY; /* Default error. */
|
---|
[39544] | 603 | handle = vbsfAllocFileHandle(pClient);
|
---|
[40109] | 604 | if (handle != SHFL_HANDLE_NIL)
|
---|
| 605 | {
|
---|
| 606 | pHandle = vbsfQueryFileHandle(pClient, handle);
|
---|
| 607 | if (pHandle)
|
---|
| 608 | {
|
---|
[65288] | 609 | pHandle->root = root;
|
---|
[77243] | 610 | pHandle->file.fOpenFlags = fOpen;
|
---|
[77685] | 611 | rc = RTFileOpenEx(pszPath, fOpen, &pHandle->file.Handle, &enmActionTaken);
|
---|
[40109] | 612 | }
|
---|
| 613 | }
|
---|
[3338] | 614 | }
|
---|
[77685] | 615 | bool fNoError = false;
|
---|
[39594] | 616 | if (RT_FAILURE(rc))
|
---|
[5258] | 617 | {
|
---|
| 618 | switch (rc)
|
---|
[3338] | 619 | {
|
---|
[77685] | 620 | case VERR_FILE_NOT_FOUND:
|
---|
| 621 | pParms->Result = SHFL_FILE_NOT_FOUND;
|
---|
[78703] | 622 | #ifndef RT_OS_WINDOWS
|
---|
| 623 | if ( SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 624 | && vbsfErrorStyleIsWindowsPathNotFound(pszPath))
|
---|
| 625 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
| 626 | #endif
|
---|
[77685] | 627 | /* This actually isn't an error, so correct the rc before return later,
|
---|
| 628 | because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
|
---|
| 629 | fNoError = true;
|
---|
| 630 | break;
|
---|
[6838] | 631 |
|
---|
[77685] | 632 | case VERR_PATH_NOT_FOUND:
|
---|
[78704] | 633 | #ifndef RT_OS_WINDOWS
|
---|
| 634 | if ( SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 635 | && vbsfErrorStyleIsWindowsInvalidNameForNonDir(pszPath))
|
---|
| 636 | {
|
---|
| 637 | rc = VERR_INVALID_NAME;
|
---|
| 638 | pParms->Result = SHFL_NO_RESULT;
|
---|
| 639 | break;
|
---|
| 640 | }
|
---|
| 641 | #endif
|
---|
[77685] | 642 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
| 643 | fNoError = true; /* Not an error either (see above). */
|
---|
| 644 | break;
|
---|
[3338] | 645 |
|
---|
[77685] | 646 | case VERR_ALREADY_EXISTS:
|
---|
[3338] | 647 | {
|
---|
[77685] | 648 | RTFSOBJINFO info;
|
---|
| 649 |
|
---|
| 650 | /** @todo Possible race left here. */
|
---|
| 651 | if (RT_SUCCESS(RTPathQueryInfoEx(pszPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient))))
|
---|
| 652 | {
|
---|
[19171] | 653 | #ifdef RT_OS_WINDOWS
|
---|
[77685] | 654 | info.Attr.fMode |= 0111;
|
---|
[19171] | 655 | #endif
|
---|
[77685] | 656 | vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
|
---|
| 657 | }
|
---|
| 658 | pParms->Result = SHFL_FILE_EXISTS;
|
---|
| 659 |
|
---|
| 660 | /* This actually isn't an error, so correct the rc before return later,
|
---|
| 661 | because the driver (VBoxSF.sys) expects rc = VINF_SUCCESS and checks the result code. */
|
---|
| 662 | fNoError = true;
|
---|
| 663 | break;
|
---|
[3338] | 664 | }
|
---|
[6831] | 665 |
|
---|
[77685] | 666 | case VERR_TOO_MANY_OPEN_FILES:
|
---|
[16486] | 667 | {
|
---|
[77685] | 668 | static int s_cErrors;
|
---|
| 669 | if (s_cErrors < 32)
|
---|
| 670 | {
|
---|
| 671 | LogRel(("SharedFolders host service: Cannot open '%s' -- too many open files.\n", pszPath));
|
---|
[62788] | 672 | #if defined RT_OS_LINUX || defined(RT_OS_SOLARIS)
|
---|
[77685] | 673 | if (s_cErrors < 1)
|
---|
| 674 | LogRel(("SharedFolders host service: Try to increase the limit for open files (ulimit -n)\n"));
|
---|
[16486] | 675 | #endif
|
---|
[77685] | 676 | s_cErrors++;
|
---|
| 677 | }
|
---|
| 678 | pParms->Result = SHFL_NO_RESULT;
|
---|
| 679 | break;
|
---|
[16486] | 680 | }
|
---|
[77685] | 681 |
|
---|
| 682 | default:
|
---|
| 683 | pParms->Result = SHFL_NO_RESULT;
|
---|
[5258] | 684 | }
|
---|
| 685 | }
|
---|
[40109] | 686 | else
|
---|
[5258] | 687 | {
|
---|
[77685] | 688 | switch (enmActionTaken)
|
---|
[5258] | 689 | {
|
---|
[77685] | 690 | default:
|
---|
| 691 | AssertFailed();
|
---|
| 692 | RT_FALL_THRU();
|
---|
| 693 | case RTFILEACTION_OPENED:
|
---|
| 694 | pParms->Result = SHFL_FILE_EXISTS;
|
---|
| 695 | break;
|
---|
| 696 | case RTFILEACTION_CREATED:
|
---|
| 697 | pParms->Result = SHFL_FILE_CREATED;
|
---|
| 698 | break;
|
---|
| 699 | case RTFILEACTION_REPLACED:
|
---|
| 700 | case RTFILEACTION_TRUNCATED: /* not quite right */
|
---|
| 701 | pParms->Result = SHFL_FILE_REPLACED;
|
---|
| 702 | break;
|
---|
| 703 | }
|
---|
| 704 |
|
---|
| 705 | if ( (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_EXISTS) == SHFL_CF_ACT_REPLACE_IF_EXISTS
|
---|
| 706 | || (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_EXISTS) == SHFL_CF_ACT_OVERWRITE_IF_EXISTS)
|
---|
| 707 | {
|
---|
[5258] | 708 | /* For now, we do not treat a failure here as fatal. */
|
---|
[77685] | 709 | /** @todo Also set the size for SHFL_CF_ACT_CREATE_IF_NEW if SHFL_CF_ACT_FAIL_IF_EXISTS is set. */
|
---|
| 710 | /** @todo r=bird: Exactly document cbObject usage and see what we can get
|
---|
| 711 | * away with here. I suspect it is only needed for windows and only
|
---|
| 712 | * with SHFL_FILE_CREATED and SHFL_FILE_REPLACED, and only if
|
---|
| 713 | * cbObject is non-zero. */
|
---|
[5258] | 714 | RTFileSetSize(pHandle->file.Handle, pParms->Info.cbObject);
|
---|
| 715 | }
|
---|
[3338] | 716 | #if 0
|
---|
[63565] | 717 | /** @todo */
|
---|
[5258] | 718 | /* Set new attributes. */
|
---|
| 719 | if ( ( SHFL_CF_ACT_REPLACE_IF_EXISTS
|
---|
| 720 | == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS))
|
---|
| 721 | || ( SHFL_CF_ACT_CREATE_IF_NEW
|
---|
| 722 | == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW)))
|
---|
| 723 | {
|
---|
| 724 | RTFileSetTimes(pHandle->file.Handle,
|
---|
| 725 | &pParms->Info.AccessTime,
|
---|
| 726 | &pParms->Info.ModificationTime,
|
---|
| 727 | &pParms->Info.ChangeTime,
|
---|
| 728 | &pParms->Info.BirthTime
|
---|
| 729 | );
|
---|
[3338] | 730 |
|
---|
[5258] | 731 | RTFileSetMode (pHandle->file.Handle, pParms->Info.Attr.fMode);
|
---|
| 732 | }
|
---|
[3338] | 733 | #endif
|
---|
[5258] | 734 | RTFSOBJINFO info;
|
---|
[3338] | 735 |
|
---|
[5258] | 736 | /* Get file information */
|
---|
[39594] | 737 | rc = RTFileQueryInfo(pHandle->file.Handle, &info, RTFSOBJATTRADD_NOTHING);
|
---|
[5258] | 738 | if (RT_SUCCESS(rc))
|
---|
| 739 | {
|
---|
[19171] | 740 | #ifdef RT_OS_WINDOWS
|
---|
[19174] | 741 | info.Attr.fMode |= 0111;
|
---|
[19171] | 742 | #endif
|
---|
[33994] | 743 | vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
|
---|
[3338] | 744 | }
|
---|
| 745 | }
|
---|
[40109] | 746 | /* Free resources if any part of the function has failed. */
|
---|
[5258] | 747 | if (RT_FAILURE(rc))
|
---|
| 748 | {
|
---|
| 749 | if ( (0 != pHandle)
|
---|
| 750 | && (NIL_RTFILE != pHandle->file.Handle)
|
---|
| 751 | && (0 != pHandle->file.Handle))
|
---|
| 752 | {
|
---|
| 753 | RTFileClose(pHandle->file.Handle);
|
---|
| 754 | pHandle->file.Handle = NIL_RTFILE;
|
---|
| 755 | }
|
---|
| 756 | if (SHFL_HANDLE_NIL != handle)
|
---|
| 757 | {
|
---|
[39544] | 758 | vbsfFreeFileHandle(pClient, handle);
|
---|
[5258] | 759 | }
|
---|
[20329] | 760 | pParms->Handle = SHFL_HANDLE_NIL;
|
---|
[5258] | 761 | }
|
---|
| 762 | else
|
---|
| 763 | {
|
---|
| 764 | pParms->Handle = handle;
|
---|
| 765 | }
|
---|
[6831] | 766 |
|
---|
[6832] | 767 | /* Report the driver that all is okay, we're done here */
|
---|
[7418] | 768 | if (fNoError)
|
---|
[6832] | 769 | rc = VINF_SUCCESS;
|
---|
[6831] | 770 |
|
---|
[13837] | 771 | LogFlow(("vbsfOpenFile: rc = %Rrc\n", rc));
|
---|
[3338] | 772 | return rc;
|
---|
| 773 | }
|
---|
| 774 |
|
---|
[5258] | 775 | /**
|
---|
| 776 | * Open a folder or create and open a new one.
|
---|
| 777 | *
|
---|
| 778 | * @returns IPRT status code
|
---|
[81369] | 779 | * @param pClient Data structure describing the client accessing the shared
|
---|
| 780 | * folder
|
---|
| 781 | * @param root The index of the shared folder in the table of mappings.
|
---|
| 782 | * @param pszPath Path to the file or folder on the host.
|
---|
| 783 | * @param pParms Input: @a CreateFlags Creation or open parameters, see
|
---|
| 784 | * include/VBox/shflsvc.h
|
---|
| 785 | * Output:
|
---|
| 786 | * - @a Result: Shared folder status code, see include/VBox/shflsvc.h
|
---|
| 787 | * - @a Handle: On success the (shared folder) handle of the folder opened or
|
---|
| 788 | * created
|
---|
| 789 | * - @a Info: On success the parameters of the folder opened or created
|
---|
[5258] | 790 | *
|
---|
| 791 | * @note folders are created with fMode = 0777
|
---|
| 792 | */
|
---|
[78703] | 793 | static int vbsfOpenDir(SHFLCLIENTDATA *pClient, SHFLROOT root, char *pszPath,
|
---|
[39544] | 794 | SHFLCREATEPARMS *pParms)
|
---|
[3338] | 795 | {
|
---|
[5258] | 796 | LogFlow(("vbsfOpenDir: pszPath = %s, pParms = %p\n", pszPath, pParms));
|
---|
| 797 | Log(("SHFL create flags %08x\n", pParms->CreateFlags));
|
---|
[3338] | 798 |
|
---|
[5258] | 799 | int rc = VERR_NO_MEMORY;
|
---|
[39544] | 800 | SHFLHANDLE handle = vbsfAllocDirHandle(pClient);
|
---|
| 801 | SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, handle);
|
---|
[5258] | 802 | if (0 != pHandle)
|
---|
| 803 | {
|
---|
[65288] | 804 | pHandle->root = root;
|
---|
[5258] | 805 | pParms->Result = SHFL_FILE_EXISTS; /* May be overwritten with SHFL_FILE_CREATED. */
|
---|
| 806 | /** @todo Can anyone think of a sensible, race-less way to do this? Although
|
---|
| 807 | I suspect that the race is inherent, due to the API available... */
|
---|
| 808 | /* Try to create the folder first if "create if new" is specified. If this
|
---|
| 809 | fails, and "open if exists" is specified, then we ignore the failure and try
|
---|
| 810 | to open the folder anyway. */
|
---|
| 811 | if ( SHFL_CF_ACT_CREATE_IF_NEW
|
---|
| 812 | == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_NEW))
|
---|
| 813 | {
|
---|
| 814 | /** @todo render supplied attributes.
|
---|
| 815 | * bird: The guest should specify this. For windows guests RTFS_DOS_DIRECTORY should suffice. */
|
---|
| 816 | RTFMODE fMode = 0777;
|
---|
[3338] | 817 |
|
---|
[5258] | 818 | pParms->Result = SHFL_FILE_CREATED;
|
---|
[39643] | 819 | rc = RTDirCreate(pszPath, fMode, 0);
|
---|
[39594] | 820 | if (RT_FAILURE(rc))
|
---|
[5258] | 821 | {
|
---|
[78704] | 822 | /** @todo we still return 'rc' as failure here, so this is mostly pointless. */
|
---|
[5258] | 823 | switch (rc)
|
---|
| 824 | {
|
---|
[78704] | 825 | case VERR_ALREADY_EXISTS:
|
---|
| 826 | pParms->Result = SHFL_FILE_EXISTS;
|
---|
| 827 | break;
|
---|
| 828 | case VERR_PATH_NOT_FOUND:
|
---|
| 829 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
| 830 | break;
|
---|
| 831 | case VERR_FILE_NOT_FOUND: /* may happen on posix */
|
---|
| 832 | pParms->Result = SHFL_FILE_NOT_FOUND;
|
---|
| 833 | #ifndef RT_OS_WINDOWS
|
---|
| 834 | if ( SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 835 | && vbsfErrorStyleIsWindowsPathNotFound(pszPath))
|
---|
| 836 | {
|
---|
| 837 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
| 838 | rc = VERR_PATH_NOT_FOUND;
|
---|
| 839 | }
|
---|
| 840 | #endif
|
---|
| 841 | break;
|
---|
| 842 | default:
|
---|
| 843 | pParms->Result = SHFL_NO_RESULT;
|
---|
[5258] | 844 | }
|
---|
| 845 | }
|
---|
| 846 | }
|
---|
[78704] | 847 | else
|
---|
| 848 | rc = VINF_SUCCESS;
|
---|
[5258] | 849 | if ( RT_SUCCESS(rc)
|
---|
[6848] | 850 | || (SHFL_CF_ACT_OPEN_IF_EXISTS == BIT_FLAG(pParms->CreateFlags, SHFL_CF_ACT_MASK_IF_EXISTS)))
|
---|
[5258] | 851 | {
|
---|
| 852 | /* Open the directory now */
|
---|
[69674] | 853 | rc = RTDirOpenFiltered(&pHandle->dir.Handle, pszPath, RTDIRFILTER_NONE, 0 /*fFlags*/);
|
---|
[5258] | 854 | if (RT_SUCCESS(rc))
|
---|
| 855 | {
|
---|
| 856 | RTFSOBJINFO info;
|
---|
[3338] | 857 |
|
---|
[39594] | 858 | rc = RTDirQueryInfo(pHandle->dir.Handle, &info, RTFSOBJATTRADD_NOTHING);
|
---|
[5258] | 859 | if (RT_SUCCESS(rc))
|
---|
| 860 | {
|
---|
[33994] | 861 | vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
|
---|
[5258] | 862 | }
|
---|
| 863 | }
|
---|
| 864 | else
|
---|
| 865 | {
|
---|
[78703] | 866 | /** @todo we still return 'rc' as failure here, so this is mostly pointless. */
|
---|
[5258] | 867 | switch (rc)
|
---|
| 868 | {
|
---|
[78704] | 869 | case VERR_FILE_NOT_FOUND:
|
---|
| 870 | pParms->Result = SHFL_FILE_NOT_FOUND;
|
---|
[78703] | 871 | #ifndef RT_OS_WINDOWS
|
---|
[78704] | 872 | if ( SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 873 | && vbsfErrorStyleIsWindowsPathNotFound(pszPath))
|
---|
| 874 | {
|
---|
| 875 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
| 876 | rc = VERR_PATH_NOT_FOUND;
|
---|
| 877 | }
|
---|
| 878 | #endif
|
---|
| 879 | break;
|
---|
| 880 | case VERR_PATH_NOT_FOUND:
|
---|
[78703] | 881 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
[78704] | 882 | #ifndef RT_OS_WINDOWS
|
---|
| 883 | if ( SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 884 | && vbsfErrorStyleIsWindowsNotADirectory(pszPath))
|
---|
| 885 | {
|
---|
| 886 | pParms->Result = SHFL_FILE_EXISTS;
|
---|
| 887 | rc = VERR_NOT_A_DIRECTORY;
|
---|
| 888 | break;
|
---|
| 889 | }
|
---|
[78703] | 890 | #endif
|
---|
[78704] | 891 | break;
|
---|
| 892 | case VERR_ACCESS_DENIED:
|
---|
| 893 | pParms->Result = SHFL_FILE_EXISTS;
|
---|
| 894 | break;
|
---|
| 895 | default:
|
---|
| 896 | pParms->Result = SHFL_NO_RESULT;
|
---|
[5258] | 897 | }
|
---|
| 898 | }
|
---|
| 899 | }
|
---|
[3338] | 900 | }
|
---|
[5258] | 901 | if (RT_FAILURE(rc))
|
---|
[3338] | 902 | {
|
---|
[5258] | 903 | if ( (0 != pHandle)
|
---|
| 904 | && (0 != pHandle->dir.Handle))
|
---|
[3338] | 905 | {
|
---|
[5258] | 906 | RTDirClose(pHandle->dir.Handle);
|
---|
| 907 | pHandle->dir.Handle = 0;
|
---|
[3338] | 908 | }
|
---|
[5258] | 909 | if (SHFL_HANDLE_NIL != handle)
|
---|
| 910 | {
|
---|
[39544] | 911 | vbsfFreeFileHandle(pClient, handle);
|
---|
[5258] | 912 | }
|
---|
[20329] | 913 | pParms->Handle = SHFL_HANDLE_NIL;
|
---|
[5258] | 914 | }
|
---|
| 915 | else
|
---|
| 916 | {
|
---|
[3338] | 917 | pParms->Handle = handle;
|
---|
| 918 | }
|
---|
[13837] | 919 | LogFlow(("vbsfOpenDir: rc = %Rrc\n", rc));
|
---|
[3338] | 920 | return rc;
|
---|
| 921 | }
|
---|
| 922 |
|
---|
[39594] | 923 | static int vbsfCloseDir(SHFLFILEHANDLE *pHandle)
|
---|
[3338] | 924 | {
|
---|
| 925 | int rc = VINF_SUCCESS;
|
---|
| 926 |
|
---|
| 927 | LogFlow(("vbsfCloseDir: Handle = %08X Search Handle = %08X\n",
|
---|
| 928 | pHandle->dir.Handle, pHandle->dir.SearchHandle));
|
---|
| 929 |
|
---|
[39594] | 930 | RTDirClose(pHandle->dir.Handle);
|
---|
[3338] | 931 |
|
---|
| 932 | if (pHandle->dir.SearchHandle)
|
---|
| 933 | RTDirClose(pHandle->dir.SearchHandle);
|
---|
| 934 |
|
---|
| 935 | if (pHandle->dir.pLastValidEntry)
|
---|
| 936 | {
|
---|
| 937 | RTMemFree(pHandle->dir.pLastValidEntry);
|
---|
| 938 | pHandle->dir.pLastValidEntry = NULL;
|
---|
| 939 | }
|
---|
| 940 |
|
---|
| 941 | LogFlow(("vbsfCloseDir: rc = %d\n", rc));
|
---|
| 942 |
|
---|
| 943 | return rc;
|
---|
| 944 | }
|
---|
| 945 |
|
---|
| 946 |
|
---|
[39594] | 947 | static int vbsfCloseFile(SHFLFILEHANDLE *pHandle)
|
---|
[3338] | 948 | {
|
---|
| 949 | int rc = VINF_SUCCESS;
|
---|
| 950 |
|
---|
| 951 | LogFlow(("vbsfCloseFile: Handle = %08X\n",
|
---|
| 952 | pHandle->file.Handle));
|
---|
| 953 |
|
---|
[39594] | 954 | rc = RTFileClose(pHandle->file.Handle);
|
---|
[3338] | 955 |
|
---|
| 956 | LogFlow(("vbsfCloseFile: rc = %d\n", rc));
|
---|
| 957 |
|
---|
| 958 | return rc;
|
---|
| 959 | }
|
---|
| 960 |
|
---|
[5258] | 961 | /**
|
---|
| 962 | * Look up file or folder information by host path.
|
---|
| 963 | *
|
---|
| 964 | * @returns iprt status code (currently VINF_SUCCESS)
|
---|
[65123] | 965 | * @param pClient client data
|
---|
| 966 | * @param pszPath The path of the file to be looked up
|
---|
[81369] | 967 | * @param pParms Output:
|
---|
| 968 | * - @a Result: Status of the operation (success or error)
|
---|
| 969 | * - @a Info: On success, information returned about the
|
---|
| 970 | * file
|
---|
[5258] | 971 | */
|
---|
[39627] | 972 | static int vbsfLookupFile(SHFLCLIENTDATA *pClient, char *pszPath, SHFLCREATEPARMS *pParms)
|
---|
[5258] | 973 | {
|
---|
| 974 | RTFSOBJINFO info;
|
---|
| 975 | int rc;
|
---|
[3338] | 976 |
|
---|
[39643] | 977 | rc = RTPathQueryInfoEx(pszPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
|
---|
[5258] | 978 | LogFlow(("SHFL_CF_LOOKUP\n"));
|
---|
| 979 | /* Client just wants to know if the object exists. */
|
---|
| 980 | switch (rc)
|
---|
| 981 | {
|
---|
| 982 | case VINF_SUCCESS:
|
---|
| 983 | {
|
---|
[19171] | 984 | #ifdef RT_OS_WINDOWS
|
---|
[19174] | 985 | info.Attr.fMode |= 0111;
|
---|
[19171] | 986 | #endif
|
---|
[33994] | 987 | vbfsCopyFsObjInfoFromIprt(&pParms->Info, &info);
|
---|
[5258] | 988 | pParms->Result = SHFL_FILE_EXISTS;
|
---|
| 989 | break;
|
---|
| 990 | }
|
---|
| 991 |
|
---|
| 992 | case VERR_FILE_NOT_FOUND:
|
---|
| 993 | {
|
---|
| 994 | pParms->Result = SHFL_FILE_NOT_FOUND;
|
---|
| 995 | rc = VINF_SUCCESS;
|
---|
| 996 | break;
|
---|
| 997 | }
|
---|
| 998 |
|
---|
| 999 | case VERR_PATH_NOT_FOUND:
|
---|
| 1000 | {
|
---|
| 1001 | pParms->Result = SHFL_PATH_NOT_FOUND;
|
---|
| 1002 | rc = VINF_SUCCESS;
|
---|
| 1003 | break;
|
---|
| 1004 | }
|
---|
| 1005 | }
|
---|
[20329] | 1006 | pParms->Handle = SHFL_HANDLE_NIL;
|
---|
[5258] | 1007 | return rc;
|
---|
| 1008 | }
|
---|
| 1009 |
|
---|
[39540] | 1010 | #ifdef UNITTEST
|
---|
| 1011 | /** Unit test the SHFL_FN_CREATE API. Located here as a form of API
|
---|
| 1012 | * documentation. */
|
---|
| 1013 | void testCreate(RTTEST hTest)
|
---|
| 1014 | {
|
---|
| 1015 | /* Simple opening of an existing file. */
|
---|
| 1016 | testCreateFileSimple(hTest);
|
---|
[66038] | 1017 | testCreateFileSimpleCaseInsensitive(hTest);
|
---|
[39540] | 1018 | /* Simple opening of an existing directory. */
|
---|
[40108] | 1019 | /** @todo How do wildcards in the path name work? */
|
---|
[39540] | 1020 | testCreateDirSimple(hTest);
|
---|
| 1021 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 1022 | testCreateBadParameters(hTest);
|
---|
| 1023 | /* Add tests as required... */
|
---|
| 1024 | }
|
---|
| 1025 | #endif
|
---|
[65123] | 1026 |
|
---|
[5258] | 1027 | /**
|
---|
| 1028 | * Create or open a file or folder. Perform character set and case
|
---|
| 1029 | * conversion on the file name if necessary.
|
---|
| 1030 | *
|
---|
| 1031 | * @returns IPRT status code, but see note below
|
---|
[81369] | 1032 | * @param pClient Data structure describing the client accessing the
|
---|
| 1033 | * shared folder
|
---|
| 1034 | * @param root The index of the shared folder in the table of mappings.
|
---|
| 1035 | * The host path of the shared folder is found using this.
|
---|
| 1036 | * @param pPath The path of the file or folder relative to the host path
|
---|
| 1037 | * indexed by root.
|
---|
| 1038 | * @param cbPath Presumably the length of the path in pPath. Actually
|
---|
| 1039 | * ignored, as pPath contains a length parameter.
|
---|
| 1040 | * @param pParms Input: If a new file is created or an old one
|
---|
| 1041 | * overwritten, set the @a Info attribute.
|
---|
[5258] | 1042 | *
|
---|
[81369] | 1043 | * Output:
|
---|
| 1044 | * - @a Result Shared folder result code, see include/VBox/shflsvc.h
|
---|
| 1045 | * - @a Handle Shared folder handle to the newly opened file
|
---|
| 1046 | * - @a Info Attributes of the file or folder opened
|
---|
| 1047 | *
|
---|
[5258] | 1048 | * @note This function returns success if a "non-exceptional" error occurred,
|
---|
| 1049 | * such as "no such file". In this case, the caller should check the
|
---|
| 1050 | * pParms->Result return value and whether pParms->Handle is valid.
|
---|
| 1051 | */
|
---|
[39594] | 1052 | int vbsfCreate(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, SHFLCREATEPARMS *pParms)
|
---|
[3338] | 1053 | {
|
---|
| 1054 | int rc = VINF_SUCCESS;
|
---|
| 1055 |
|
---|
[4383] | 1056 | LogFlow(("vbsfCreate: pClient = %p, pPath = %p, cbPath = %d, pParms = %p CreateFlags=%x\n",
|
---|
| 1057 | pClient, pPath, cbPath, pParms, pParms->CreateFlags));
|
---|
[3338] | 1058 |
|
---|
| 1059 | /* Check the client access rights to the root. */
|
---|
| 1060 | /** @todo */
|
---|
| 1061 |
|
---|
[5258] | 1062 | /* Build a host full path for the given path, handle file name case issues (if the guest
|
---|
[99802] | 1063 | * expects case-insensitive paths but the host is case-sensitive) and convert utf16 to utf8 if
|
---|
[5258] | 1064 | * necessary.
|
---|
[3338] | 1065 | */
|
---|
| 1066 | char *pszFullPath = NULL;
|
---|
| 1067 | uint32_t cbFullPathRoot = 0;
|
---|
| 1068 |
|
---|
[39594] | 1069 | rc = vbsfBuildFullPath(pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
|
---|
| 1070 | if (RT_SUCCESS(rc))
|
---|
[3338] | 1071 | {
|
---|
[20329] | 1072 | /* Reset return value in case client forgot to do so.
|
---|
| 1073 | * pParms->Handle must not be reset here, as it is used
|
---|
| 1074 | * in vbsfOpenFile to detect old additions.
|
---|
| 1075 | */
|
---|
[3338] | 1076 | pParms->Result = SHFL_NO_RESULT;
|
---|
| 1077 |
|
---|
| 1078 | if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_LOOKUP))
|
---|
| 1079 | {
|
---|
[39627] | 1080 | rc = vbsfLookupFile(pClient, pszFullPath, pParms);
|
---|
[3338] | 1081 | }
|
---|
[5258] | 1082 | else
|
---|
[3338] | 1083 | {
|
---|
[5258] | 1084 | /* Query path information. */
|
---|
| 1085 | RTFSOBJINFO info;
|
---|
[3338] | 1086 |
|
---|
[39643] | 1087 | rc = RTPathQueryInfoEx(pszFullPath, &info, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
|
---|
[25695] | 1088 | LogFlow(("RTPathQueryInfoEx returned %Rrc\n", rc));
|
---|
[3338] | 1089 |
|
---|
[5258] | 1090 | if (RT_SUCCESS(rc))
|
---|
[3338] | 1091 | {
|
---|
[5258] | 1092 | /* Mark it as a directory in case the caller didn't. */
|
---|
| 1093 | /**
|
---|
| 1094 | * @todo I left this in in order not to change the behaviour of the
|
---|
| 1095 | * function too much. Is it really needed, and should it really be
|
---|
| 1096 | * here?
|
---|
| 1097 | */
|
---|
| 1098 | if (BIT_FLAG(info.Attr.fMode, RTFS_DOS_DIRECTORY))
|
---|
[3338] | 1099 | {
|
---|
[5258] | 1100 | pParms->CreateFlags |= SHFL_CF_DIRECTORY;
|
---|
[3338] | 1101 | }
|
---|
[6848] | 1102 |
|
---|
[5258] | 1103 | /**
|
---|
| 1104 | * @todo This should be in the Windows Guest Additions, as no-one else
|
---|
| 1105 | * needs it.
|
---|
| 1106 | */
|
---|
| 1107 | if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_OPEN_TARGET_DIRECTORY))
|
---|
[3338] | 1108 | {
|
---|
[39594] | 1109 | vbsfStripLastComponent(pszFullPath, cbFullPathRoot);
|
---|
[5258] | 1110 | pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_EXISTS;
|
---|
| 1111 | pParms->CreateFlags &= ~SHFL_CF_ACT_MASK_IF_NEW;
|
---|
| 1112 | pParms->CreateFlags |= SHFL_CF_DIRECTORY;
|
---|
| 1113 | pParms->CreateFlags |= SHFL_CF_ACT_OPEN_IF_EXISTS;
|
---|
| 1114 | pParms->CreateFlags |= SHFL_CF_ACT_FAIL_IF_NEW;
|
---|
[3338] | 1115 | }
|
---|
| 1116 | }
|
---|
[6384] | 1117 |
|
---|
[6402] | 1118 | rc = VINF_SUCCESS;
|
---|
| 1119 |
|
---|
[20292] | 1120 | /* Note: do not check the SHFL_CF_ACCESS_WRITE here, only check if the open operation
|
---|
| 1121 | * will cause changes.
|
---|
| 1122 | *
|
---|
| 1123 | * Actual operations (write, set attr, etc), which can write to a shared folder, have
|
---|
| 1124 | * the check and will return VERR_WRITE_PROTECT if the folder is not writable.
|
---|
| 1125 | */
|
---|
| 1126 | if ( (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_EXISTS) == SHFL_CF_ACT_REPLACE_IF_EXISTS
|
---|
| 1127 | || (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_EXISTS) == SHFL_CF_ACT_OVERWRITE_IF_EXISTS
|
---|
| 1128 | || (pParms->CreateFlags & SHFL_CF_ACT_MASK_IF_NEW) == SHFL_CF_ACT_CREATE_IF_NEW
|
---|
| 1129 | )
|
---|
[6384] | 1130 | {
|
---|
| 1131 | /* is the guest allowed to write to this share? */
|
---|
| 1132 | bool fWritable;
|
---|
[39594] | 1133 | rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
|
---|
[6384] | 1134 | if (RT_FAILURE(rc) || !fWritable)
|
---|
[6402] | 1135 | rc = VERR_WRITE_PROTECT;
|
---|
[6384] | 1136 | }
|
---|
| 1137 |
|
---|
[6402] | 1138 | if (RT_SUCCESS(rc))
|
---|
[3338] | 1139 | {
|
---|
[6896] | 1140 | if (BIT_FLAG(pParms->CreateFlags, SHFL_CF_DIRECTORY))
|
---|
[39627] | 1141 | {
|
---|
[65288] | 1142 | rc = vbsfOpenDir(pClient, root, pszFullPath, pParms);
|
---|
[39627] | 1143 | }
|
---|
[6402] | 1144 | else
|
---|
[39627] | 1145 | {
|
---|
[65279] | 1146 | rc = vbsfOpenFile(pClient, root, pszFullPath, pParms);
|
---|
[39627] | 1147 | }
|
---|
[3338] | 1148 | }
|
---|
[20329] | 1149 | else
|
---|
| 1150 | {
|
---|
| 1151 | pParms->Handle = SHFL_HANDLE_NIL;
|
---|
| 1152 | }
|
---|
[3338] | 1153 | }
|
---|
| 1154 |
|
---|
| 1155 | /* free the path string */
|
---|
| 1156 | vbsfFreeFullPath(pszFullPath);
|
---|
| 1157 | }
|
---|
| 1158 |
|
---|
[13837] | 1159 | Log(("vbsfCreate: handle = %RX64 rc = %Rrc result=%x\n", (uint64_t)pParms->Handle, rc, pParms->Result));
|
---|
[3338] | 1160 |
|
---|
| 1161 | return rc;
|
---|
| 1162 | }
|
---|
| 1163 |
|
---|
[39540] | 1164 | #ifdef UNITTEST
|
---|
| 1165 | /** Unit test the SHFL_FN_CLOSE API. Located here as a form of API
|
---|
| 1166 | * documentation. */
|
---|
| 1167 | void testClose(RTTEST hTest)
|
---|
| 1168 | {
|
---|
| 1169 | /* If the API parameters are invalid the API should fail. */
|
---|
| 1170 | testCloseBadParameters(hTest);
|
---|
| 1171 | /* Add tests as required... */
|
---|
| 1172 | }
|
---|
| 1173 | #endif
|
---|
[62789] | 1174 |
|
---|
[39594] | 1175 | int vbsfClose(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
|
---|
[3338] | 1176 | {
|
---|
[65288] | 1177 | LogFunc(("pClient = %p, root 0x%RX32, Handle = 0x%RX64\n",
|
---|
| 1178 | pClient, root, Handle));
|
---|
[3338] | 1179 |
|
---|
[65288] | 1180 | int rc = VERR_INVALID_HANDLE;
|
---|
[39544] | 1181 | uint32_t type = vbsfQueryHandleType(pClient, Handle);
|
---|
| 1182 | Assert((type & ~(SHFL_HF_TYPE_DIR | SHFL_HF_TYPE_FILE)) == 0);
|
---|
| 1183 | switch (type & (SHFL_HF_TYPE_DIR | SHFL_HF_TYPE_FILE))
|
---|
[3338] | 1184 | {
|
---|
| 1185 | case SHFL_HF_TYPE_DIR:
|
---|
| 1186 | {
|
---|
[65288] | 1187 | SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, Handle);
|
---|
| 1188 | if (RT_LIKELY(pHandle && root == pHandle->root))
|
---|
| 1189 | {
|
---|
| 1190 | rc = vbsfCloseDir(pHandle);
|
---|
| 1191 | vbsfFreeFileHandle(pClient, Handle);
|
---|
| 1192 | }
|
---|
[3338] | 1193 | break;
|
---|
| 1194 | }
|
---|
| 1195 | case SHFL_HF_TYPE_FILE:
|
---|
| 1196 | {
|
---|
[65288] | 1197 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
| 1198 | if (RT_LIKELY(pHandle && root == pHandle->root))
|
---|
| 1199 | {
|
---|
| 1200 | rc = vbsfCloseFile(pHandle);
|
---|
| 1201 | vbsfFreeFileHandle(pClient, Handle);
|
---|
| 1202 | }
|
---|
[3338] | 1203 | break;
|
---|
| 1204 | }
|
---|
[5635] | 1205 | default:
|
---|
[65288] | 1206 | break;
|
---|
[3338] | 1207 | }
|
---|
| 1208 |
|
---|
[65288] | 1209 | LogFunc(("rc = %Rrc\n", rc));
|
---|
[3338] | 1210 | return rc;
|
---|
| 1211 | }
|
---|
| 1212 |
|
---|
[77243] | 1213 | /**
|
---|
| 1214 | * Helper for vbsfReadPages and vbsfWritePages that creates a S/G buffer from a
|
---|
| 1215 | * pages parameter.
|
---|
| 1216 | */
|
---|
| 1217 | static int vbsfPagesToSgBuf(VBOXHGCMSVCPARMPAGES const *pPages, uint32_t cbLeft, PRTSGBUF pSgBuf)
|
---|
| 1218 | {
|
---|
| 1219 | PRTSGSEG paSegs = (PRTSGSEG)RTMemTmpAlloc(sizeof(paSegs[0]) * pPages->cPages);
|
---|
| 1220 | if (paSegs)
|
---|
| 1221 | {
|
---|
| 1222 | /*
|
---|
| 1223 | * Convert the pages to segments.
|
---|
| 1224 | */
|
---|
| 1225 | uint32_t iSeg = 0;
|
---|
| 1226 | uint32_t iPage = 0;
|
---|
| 1227 | for (;;)
|
---|
| 1228 | {
|
---|
| 1229 | Assert(iSeg < pPages->cPages);
|
---|
| 1230 | Assert(iPage < pPages->cPages);
|
---|
| 1231 |
|
---|
[100220] | 1232 | /** @todo r=aeichner This was just using PAGE_SIZE before which doesn't work if the host and guest use different
|
---|
| 1233 | * page sizes (think of 16KiB on macOS.arm64 vs linux.arm64) causing data corruption, yay! VMMDev now imposes a page size of 4KiB and
|
---|
| 1234 | * VBOXHGCMSVCPARMPAGES should really have a cbPage member to indicate the used page size instead of dragging
|
---|
| 1235 | * in VMMDev.h here. OTOH the size of VBOXHGCMSVCPARMPAGES can be part of a saved state which would mean increasing
|
---|
| 1236 | * the HGCM saved state version... */
|
---|
| 1237 |
|
---|
[77243] | 1238 | /* Current page. */
|
---|
| 1239 | void *pvSeg;
|
---|
| 1240 | paSegs[iSeg].pvSeg = pvSeg = pPages->papvPages[iPage];
|
---|
[100220] | 1241 | uint32_t cbSeg = VMMDEV_PAGE_SIZE - (uint32_t)((uintptr_t)pvSeg & VMMDEV_PAGE_OFFSET_MASK);
|
---|
[77243] | 1242 | iPage++;
|
---|
| 1243 |
|
---|
| 1244 | /* Adjacent to the next page? */
|
---|
| 1245 | while ( iPage < pPages->cPages
|
---|
| 1246 | && (uintptr_t)pvSeg + cbSeg == (uintptr_t)pPages->papvPages[iPage])
|
---|
| 1247 | {
|
---|
| 1248 | iPage++;
|
---|
[100220] | 1249 | cbSeg += VMMDEV_PAGE_SIZE;
|
---|
[77243] | 1250 | }
|
---|
| 1251 |
|
---|
| 1252 | /* Adjust for max size. */
|
---|
| 1253 | if (cbLeft <= cbSeg)
|
---|
| 1254 | {
|
---|
| 1255 | paSegs[iSeg++].cbSeg = cbLeft;
|
---|
| 1256 | break;
|
---|
| 1257 | }
|
---|
| 1258 | paSegs[iSeg++].cbSeg = cbSeg;
|
---|
| 1259 | cbLeft -= cbSeg;
|
---|
| 1260 | }
|
---|
| 1261 |
|
---|
| 1262 | /*
|
---|
| 1263 | * Initialize the s/g buffer and execute the read.
|
---|
| 1264 | */
|
---|
| 1265 | RTSgBufInit(pSgBuf, paSegs, iSeg);
|
---|
| 1266 | return VINF_SUCCESS;
|
---|
| 1267 | }
|
---|
| 1268 | pSgBuf->paSegs = NULL;
|
---|
| 1269 | return VERR_NO_TMP_MEMORY;
|
---|
| 1270 | }
|
---|
| 1271 |
|
---|
| 1272 |
|
---|
[39540] | 1273 | #ifdef UNITTEST
|
---|
| 1274 | /** Unit test the SHFL_FN_READ API. Located here as a form of API
|
---|
| 1275 | * documentation. */
|
---|
| 1276 | void testRead(RTTEST hTest)
|
---|
| 1277 | {
|
---|
| 1278 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 1279 | testReadBadParameters(hTest);
|
---|
| 1280 | /* Basic reading from a file. */
|
---|
| 1281 | testReadFileSimple(hTest);
|
---|
| 1282 | /* Add tests as required... */
|
---|
| 1283 | }
|
---|
| 1284 | #endif
|
---|
[65288] | 1285 | int vbsfRead(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
[3338] | 1286 | {
|
---|
[65288] | 1287 | LogFunc(("pClient %p, root 0x%RX32, Handle 0x%RX64, offset 0x%RX64, bytes 0x%RX32\n",
|
---|
| 1288 | pClient, root, Handle, offset, pcbBuffer? *pcbBuffer: 0));
|
---|
| 1289 |
|
---|
| 1290 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 1291 |
|
---|
[39544] | 1292 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[65288] | 1293 | int rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 1294 | if (RT_SUCCESS(rc))
|
---|
[3338] | 1295 | {
|
---|
[77248] | 1296 | size_t const cbToRead = *pcbBuffer;
|
---|
| 1297 | if (RT_LIKELY(cbToRead > 0))
|
---|
[65288] | 1298 | {
|
---|
[77248] | 1299 | size_t cbActual = 0;
|
---|
| 1300 | rc = RTFileReadAt(pHandle->file.Handle, offset, pBuffer, cbToRead, &cbActual);
|
---|
| 1301 | *pcbBuffer = (uint32_t)cbActual;
|
---|
[65288] | 1302 | }
|
---|
| 1303 | else
|
---|
[77248] | 1304 | {
|
---|
| 1305 | /* Reading zero bytes always succeeds. */
|
---|
| 1306 | rc = VINF_SUCCESS;
|
---|
| 1307 | }
|
---|
[3338] | 1308 | }
|
---|
[65288] | 1309 | else
|
---|
[77248] | 1310 | *pcbBuffer = 0;
|
---|
[3338] | 1311 |
|
---|
[65288] | 1312 | LogFunc(("%Rrc bytes read 0x%RX32\n", rc, *pcbBuffer));
|
---|
[3338] | 1313 | return rc;
|
---|
| 1314 | }
|
---|
| 1315 |
|
---|
[77243] | 1316 | /**
|
---|
| 1317 | * SHFL_FN_READ w/o bounce buffering.
|
---|
| 1318 | */
|
---|
| 1319 | int vbsfReadPages(SHFLCLIENTDATA *pClient, SHFLROOT idRoot, SHFLHANDLE hFile, uint64_t offFile,
|
---|
| 1320 | uint32_t *pcbRead, PVBOXHGCMSVCPARMPAGES pPages)
|
---|
| 1321 | {
|
---|
| 1322 | LogFunc(("pClient %p, idRoot %#RX32, hFile %#RX64, offFile %#RX64, cbRead %#RX32, cPages %#x\n",
|
---|
| 1323 | pClient, idRoot, hFile, offFile, *pcbRead, pPages->cPages));
|
---|
| 1324 |
|
---|
| 1325 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 1326 |
|
---|
| 1327 | size_t cbTotal = 0;
|
---|
| 1328 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, hFile);
|
---|
| 1329 | int rc = vbsfCheckHandleAccess(pClient, idRoot, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 1330 | if (RT_SUCCESS(rc))
|
---|
| 1331 | {
|
---|
| 1332 | uint32_t const cbToRead = *pcbRead;
|
---|
| 1333 | if (cbToRead > 0)
|
---|
| 1334 | {
|
---|
| 1335 | ASSERT_GUEST_RETURN(pPages->cPages > 0, VERR_INTERNAL_ERROR_3);
|
---|
| 1336 |
|
---|
| 1337 | /*
|
---|
| 1338 | * Convert to a scatter-gather buffer.
|
---|
| 1339 | *
|
---|
| 1340 | * We need not do any platform specific code here as the RTSGBUF
|
---|
| 1341 | * segment array maps directly onto the posix iovec structure.
|
---|
| 1342 | * Windows does currently benefit much from this conversion, but
|
---|
| 1343 | * so be it.
|
---|
| 1344 | */
|
---|
| 1345 | RTSGBUF SgBuf;
|
---|
| 1346 | rc = vbsfPagesToSgBuf(pPages, cbToRead, &SgBuf);
|
---|
| 1347 | if (RT_SUCCESS(rc))
|
---|
| 1348 | {
|
---|
| 1349 | rc = RTFileSgReadAt(pHandle->file.Handle, offFile, &SgBuf, cbToRead, &cbTotal);
|
---|
| 1350 | while (rc == VERR_INTERRUPTED)
|
---|
| 1351 | {
|
---|
| 1352 | RTSgBufReset(&SgBuf);
|
---|
| 1353 | rc = RTFileSgReadAt(pHandle->file.Handle, offFile, &SgBuf, cbToRead, &cbTotal);
|
---|
| 1354 | }
|
---|
| 1355 |
|
---|
| 1356 | RTMemTmpFree((void *)SgBuf.paSegs);
|
---|
| 1357 | }
|
---|
| 1358 | else
|
---|
| 1359 | rc = VERR_NO_TMP_MEMORY;
|
---|
| 1360 |
|
---|
| 1361 | *pcbRead = (uint32_t)cbTotal;
|
---|
| 1362 | }
|
---|
| 1363 | else
|
---|
| 1364 | {
|
---|
| 1365 | /* Reading zero bytes always succeeds. */
|
---|
| 1366 | rc = VINF_SUCCESS;
|
---|
| 1367 | }
|
---|
| 1368 | }
|
---|
| 1369 | else
|
---|
| 1370 | *pcbRead = 0;
|
---|
| 1371 |
|
---|
| 1372 | LogFunc(("%Rrc bytes read %#zx\n", rc, cbTotal));
|
---|
| 1373 | return rc;
|
---|
| 1374 | }
|
---|
| 1375 |
|
---|
| 1376 | /**
|
---|
| 1377 | * Helps with writes to RTFILE_O_APPEND files.
|
---|
| 1378 | */
|
---|
| 1379 | static uint64_t vbsfWriteCalcPostAppendFilePosition(RTFILE hFile, uint64_t offGuessed)
|
---|
| 1380 | {
|
---|
| 1381 | RTFSOBJINFO ObjInfo;
|
---|
| 1382 | int rc2 = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
|
---|
| 1383 | if (RT_SUCCESS(rc2) && (uint64_t)ObjInfo.cbObject >= offGuessed)
|
---|
| 1384 | return ObjInfo.cbObject;
|
---|
| 1385 | return offGuessed;
|
---|
| 1386 | }
|
---|
| 1387 |
|
---|
[39540] | 1388 | #ifdef UNITTEST
|
---|
| 1389 | /** Unit test the SHFL_FN_WRITE API. Located here as a form of API
|
---|
| 1390 | * documentation. */
|
---|
| 1391 | void testWrite(RTTEST hTest)
|
---|
| 1392 | {
|
---|
| 1393 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 1394 | testWriteBadParameters(hTest);
|
---|
| 1395 | /* Simple test of writing to a file. */
|
---|
| 1396 | testWriteFileSimple(hTest);
|
---|
| 1397 | /* Add tests as required... */
|
---|
| 1398 | }
|
---|
| 1399 | #endif
|
---|
[77243] | 1400 | int vbsfWrite(SHFLCLIENTDATA *pClient, SHFLROOT idRoot, SHFLHANDLE hFile, uint64_t *poffFile,
|
---|
| 1401 | uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
[3338] | 1402 | {
|
---|
[77243] | 1403 | uint64_t offFile = *poffFile;
|
---|
| 1404 | LogFunc(("pClient %p, root 0x%RX32, Handle 0x%RX64, offFile 0x%RX64, bytes 0x%RX32\n",
|
---|
| 1405 | pClient, idRoot, hFile, offFile, *pcbBuffer));
|
---|
[65288] | 1406 |
|
---|
| 1407 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 1408 |
|
---|
[77243] | 1409 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, hFile);
|
---|
| 1410 | int rc = vbsfCheckHandleAccess(pClient, idRoot, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
[65288] | 1411 | if (RT_SUCCESS(rc))
|
---|
[77243] | 1412 | {
|
---|
| 1413 | size_t const cbToWrite = *pcbBuffer;
|
---|
| 1414 | if (RT_LIKELY(cbToWrite != 0))
|
---|
| 1415 | {
|
---|
[77248] | 1416 | size_t cbWritten = 0;
|
---|
| 1417 | if (!(pHandle->file.fOpenFlags & RTFILE_O_APPEND))
|
---|
| 1418 | rc = RTFileWriteAt(pHandle->file.Handle, offFile, pBuffer, cbToWrite, &cbWritten);
|
---|
| 1419 | else
|
---|
[77243] | 1420 | {
|
---|
[77248] | 1421 | rc = RTFileSeek(pHandle->file.Handle, offFile, RTFILE_SEEK_BEGIN, NULL);
|
---|
| 1422 | AssertRC(rc);
|
---|
[77243] | 1423 | if (RT_SUCCESS(rc))
|
---|
| 1424 | {
|
---|
[77248] | 1425 | rc = RTFileWrite(pHandle->file.Handle, pBuffer, cbToWrite, &cbWritten);
|
---|
| 1426 | *pcbBuffer = (uint32_t)cbWritten;
|
---|
[77243] | 1427 | }
|
---|
| 1428 | }
|
---|
[77248] | 1429 |
|
---|
| 1430 | /* Update the file offset (mainly for RTFILE_O_APPEND), */
|
---|
| 1431 | if (RT_SUCCESS(rc))
|
---|
| 1432 | {
|
---|
| 1433 | offFile += cbWritten;
|
---|
| 1434 | if (!(pHandle->file.fOpenFlags & RTFILE_O_APPEND))
|
---|
| 1435 | *poffFile = offFile;
|
---|
| 1436 | else
|
---|
| 1437 | *poffFile = vbsfWriteCalcPostAppendFilePosition(pHandle->file.Handle, offFile);
|
---|
| 1438 | }
|
---|
[77243] | 1439 | }
|
---|
| 1440 | else
|
---|
| 1441 | {
|
---|
| 1442 | /** @todo What writing zero bytes should do? */
|
---|
| 1443 | rc = VINF_SUCCESS;
|
---|
| 1444 | }
|
---|
| 1445 | }
|
---|
[65288] | 1446 | else
|
---|
[77243] | 1447 | *pcbBuffer = 0;
|
---|
| 1448 | LogFunc(("%Rrc bytes written 0x%RX32\n", rc, *pcbBuffer));
|
---|
| 1449 | return rc;
|
---|
| 1450 | }
|
---|
[3338] | 1451 |
|
---|
[77243] | 1452 | /**
|
---|
| 1453 | * SHFL_FN_WRITE w/o bounce buffering.
|
---|
| 1454 | */
|
---|
| 1455 | int vbsfWritePages(SHFLCLIENTDATA *pClient, SHFLROOT idRoot, SHFLHANDLE hFile, uint64_t *poffFile,
|
---|
| 1456 | uint32_t *pcbWrite, PVBOXHGCMSVCPARMPAGES pPages)
|
---|
| 1457 | {
|
---|
| 1458 | uint64_t offFile = *poffFile;
|
---|
| 1459 | LogFunc(("pClient %p, idRoot %#RX32, hFile %#RX64, offFile %#RX64, cbWrite %#RX32, cPages %#x\n",
|
---|
| 1460 | pClient, idRoot, hFile, offFile, *pcbWrite, pPages->cPages));
|
---|
| 1461 |
|
---|
| 1462 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 1463 |
|
---|
| 1464 | size_t cbTotal = 0;
|
---|
| 1465 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, hFile);
|
---|
| 1466 | int rc = vbsfCheckHandleAccess(pClient, idRoot, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
| 1467 | if (RT_SUCCESS(rc))
|
---|
[3338] | 1468 | {
|
---|
[77243] | 1469 | uint32_t const cbToWrite = *pcbWrite;
|
---|
| 1470 | if (cbToWrite > 0)
|
---|
[65288] | 1471 | {
|
---|
[77243] | 1472 | ASSERT_GUEST_RETURN(pPages->cPages > 0, VERR_INTERNAL_ERROR_3);
|
---|
| 1473 |
|
---|
| 1474 | /*
|
---|
| 1475 | * Convert to a scatter-gather buffer.
|
---|
| 1476 | *
|
---|
| 1477 | * We need not do any platform specific code here as the RTSGBUF
|
---|
| 1478 | * segment array maps directly onto the posix iovec structure.
|
---|
| 1479 | * Windows does currently benefit much from this conversion, but
|
---|
| 1480 | * so be it.
|
---|
| 1481 | */
|
---|
| 1482 | RTSGBUF SgBuf;
|
---|
| 1483 | rc = vbsfPagesToSgBuf(pPages, cbToWrite, &SgBuf);
|
---|
| 1484 | if (RT_SUCCESS(rc))
|
---|
| 1485 | {
|
---|
[77248] | 1486 | #ifndef RT_OS_LINUX
|
---|
[77243] | 1487 | /* Cannot use RTFileSgWriteAt or RTFileWriteAt when opened with
|
---|
| 1488 | RTFILE_O_APPEND, except for on linux where the offset is
|
---|
| 1489 | then ignored by the low level kernel API. */
|
---|
| 1490 | if (pHandle->file.fOpenFlags & RTFILE_O_APPEND)
|
---|
| 1491 | {
|
---|
| 1492 | /* paranoia */
|
---|
| 1493 | RTFileSeek(pHandle->file.Handle, 0, RTFILE_SEEK_END, NULL);
|
---|
| 1494 |
|
---|
| 1495 | for (size_t iSeg = 0; iSeg < SgBuf.cSegs; iSeg++)
|
---|
| 1496 | {
|
---|
| 1497 | size_t cbWrittenNow = 0;
|
---|
| 1498 | do
|
---|
| 1499 | rc = RTFileWrite(pHandle->file.Handle, SgBuf.paSegs[iSeg].pvSeg,
|
---|
| 1500 | SgBuf.paSegs[iSeg].cbSeg, &cbWrittenNow);
|
---|
| 1501 | while (rc == VERR_INTERRUPTED);
|
---|
| 1502 | if (RT_SUCCESS(rc))
|
---|
| 1503 | {
|
---|
| 1504 | cbTotal += cbWrittenNow;
|
---|
| 1505 | if (cbWrittenNow < SgBuf.paSegs[iSeg].cbSeg)
|
---|
| 1506 | break;
|
---|
| 1507 | }
|
---|
| 1508 | else
|
---|
| 1509 | {
|
---|
| 1510 | if (cbTotal > 0)
|
---|
| 1511 | rc = VINF_SUCCESS;
|
---|
| 1512 | break;
|
---|
| 1513 | }
|
---|
| 1514 | }
|
---|
| 1515 | }
|
---|
| 1516 | else
|
---|
[77248] | 1517 | #endif
|
---|
[77243] | 1518 | {
|
---|
| 1519 | rc = RTFileSgWriteAt(pHandle->file.Handle, offFile, &SgBuf, cbToWrite, &cbTotal);
|
---|
| 1520 | while (rc == VERR_INTERRUPTED)
|
---|
| 1521 | {
|
---|
| 1522 | RTSgBufReset(&SgBuf);
|
---|
| 1523 | rc = RTFileSgWriteAt(pHandle->file.Handle, offFile, &SgBuf, cbToWrite, &cbTotal);
|
---|
| 1524 | }
|
---|
| 1525 | }
|
---|
| 1526 |
|
---|
| 1527 | RTMemTmpFree((void *)SgBuf.paSegs);
|
---|
| 1528 |
|
---|
| 1529 | /* Update the file offset (mainly for RTFILE_O_APPEND), */
|
---|
| 1530 | if (RT_SUCCESS(rc))
|
---|
| 1531 | {
|
---|
| 1532 | offFile += cbTotal;
|
---|
| 1533 | if (!(pHandle->file.fOpenFlags & RTFILE_O_APPEND))
|
---|
| 1534 | *poffFile = offFile;
|
---|
| 1535 | else
|
---|
| 1536 | *poffFile = vbsfWriteCalcPostAppendFilePosition(pHandle->file.Handle, offFile);
|
---|
| 1537 | }
|
---|
| 1538 | }
|
---|
| 1539 | else
|
---|
| 1540 | rc = VERR_NO_TMP_MEMORY;
|
---|
| 1541 |
|
---|
| 1542 | *pcbWrite = (uint32_t)cbTotal;
|
---|
[65288] | 1543 | }
|
---|
| 1544 | else
|
---|
[77243] | 1545 | {
|
---|
| 1546 | /* Writing zero bytes always succeeds. */
|
---|
| 1547 | rc = VINF_SUCCESS;
|
---|
| 1548 | }
|
---|
[3338] | 1549 | }
|
---|
[65288] | 1550 | else
|
---|
[77243] | 1551 | *pcbWrite = 0;
|
---|
[3338] | 1552 |
|
---|
[77243] | 1553 | LogFunc(("%Rrc bytes written %#zx\n", rc, cbTotal));
|
---|
[3338] | 1554 | return rc;
|
---|
| 1555 | }
|
---|
| 1556 |
|
---|
[77848] | 1557 | /**
|
---|
| 1558 | * Implements SHFL_FN_COPY_FILE_PART (wrapping RTFileCopyPart).
|
---|
| 1559 | */
|
---|
[77837] | 1560 | int vbsfCopyFilePart(SHFLCLIENTDATA *pClient, SHFLROOT idRootSrc, SHFLHANDLE hFileSrc, uint64_t offSrc,
|
---|
| 1561 | SHFLROOT idRootDst, SHFLHANDLE hFileDst, uint64_t offDst, uint64_t *pcbToCopy, uint32_t fFlags)
|
---|
| 1562 | {
|
---|
| 1563 | /*
|
---|
| 1564 | * Validate and translates handles.
|
---|
| 1565 | */
|
---|
| 1566 | uint64_t const cbToCopy = *pcbToCopy;
|
---|
| 1567 | *pcbToCopy = 0;
|
---|
| 1568 | LogFunc(("pClient %p, idRootSrc %#RX32, hFileSrc %#RX64, offSrc %#RX64, idRootSrc %#RX32, hFileSrc %#RX64, offSrc %#RX64, cbToCopy %#RX64, fFlags %#x\n",
|
---|
| 1569 | pClient, idRootSrc, hFileSrc, offSrc, idRootDst, hFileDst, offDst, cbToCopy, fFlags));
|
---|
[3338] | 1570 |
|
---|
[77837] | 1571 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 1572 |
|
---|
[77838] | 1573 | uint64_t cbTotal = 0;
|
---|
[77837] | 1574 |
|
---|
| 1575 | SHFLFILEHANDLE *pHandleSrc = vbsfQueryFileHandle(pClient, hFileSrc);
|
---|
| 1576 | int rc = vbsfCheckHandleAccess(pClient, idRootSrc, pHandleSrc, VBSF_CHECK_ACCESS_READ);
|
---|
| 1577 | if (RT_SUCCESS(rc))
|
---|
| 1578 | {
|
---|
| 1579 | SHFLFILEHANDLE *pHandleDst = vbsfQueryFileHandle(pClient, hFileDst);
|
---|
| 1580 | rc = vbsfCheckHandleAccess(pClient, idRootDst, pHandleDst, VBSF_CHECK_ACCESS_WRITE);
|
---|
| 1581 | if (RT_SUCCESS(rc))
|
---|
| 1582 | {
|
---|
[77848] | 1583 | /*
|
---|
| 1584 | * Do the job.
|
---|
| 1585 | */
|
---|
[77837] | 1586 | rc = RTFileCopyPart(pHandleSrc->file.Handle, offSrc, pHandleDst->file.Handle, offDst, cbToCopy, 0, &cbTotal);
|
---|
| 1587 | *pcbToCopy = cbTotal;
|
---|
| 1588 | }
|
---|
| 1589 | }
|
---|
| 1590 |
|
---|
| 1591 | RT_NOREF(fFlags);
|
---|
| 1592 | LogFunc(("%Rrc bytes written %#zx\n", rc, cbTotal));
|
---|
| 1593 | return rc;
|
---|
| 1594 | }
|
---|
| 1595 |
|
---|
[39540] | 1596 | #ifdef UNITTEST
|
---|
| 1597 | /** Unit test the SHFL_FN_FLUSH API. Located here as a form of API
|
---|
| 1598 | * documentation. */
|
---|
| 1599 | void testFlush(RTTEST hTest)
|
---|
| 1600 | {
|
---|
| 1601 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 1602 | testFlushBadParameters(hTest);
|
---|
| 1603 | /* Simple opening and flushing of a file. */
|
---|
| 1604 | testFlushFileSimple(hTest);
|
---|
| 1605 | /* Add tests as required... */
|
---|
| 1606 | }
|
---|
| 1607 | #endif
|
---|
[62789] | 1608 |
|
---|
[3338] | 1609 | int vbsfFlush(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle)
|
---|
| 1610 | {
|
---|
[65288] | 1611 | LogFunc(("pClient %p, root 0x%RX32, Handle 0x%RX64\n",
|
---|
| 1612 | pClient, root, Handle));
|
---|
| 1613 |
|
---|
| 1614 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 1615 |
|
---|
[39544] | 1616 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[65288] | 1617 | int rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
| 1618 | if (RT_SUCCESS(rc))
|
---|
| 1619 | { /* likely */ }
|
---|
| 1620 | else
|
---|
| 1621 | return rc;
|
---|
[3338] | 1622 |
|
---|
[65288] | 1623 | rc = RTFileFlush(pHandle->file.Handle);
|
---|
[3338] | 1624 |
|
---|
[65288] | 1625 | LogFunc(("%Rrc\n", rc));
|
---|
[3338] | 1626 | return rc;
|
---|
| 1627 | }
|
---|
| 1628 |
|
---|
[39540] | 1629 | #ifdef UNITTEST
|
---|
| 1630 | /** Unit test the SHFL_FN_LIST API. Located here as a form of API
|
---|
| 1631 | * documentation. */
|
---|
| 1632 | void testDirList(RTTEST hTest)
|
---|
| 1633 | {
|
---|
| 1634 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 1635 | testDirListBadParameters(hTest);
|
---|
| 1636 | /* Test listing an empty directory (simple edge case). */
|
---|
| 1637 | testDirListEmpty(hTest);
|
---|
| 1638 | /* Add tests as required... */
|
---|
| 1639 | }
|
---|
| 1640 | #endif
|
---|
[21485] | 1641 | int vbsfDirList(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, SHFLSTRING *pPath, uint32_t flags,
|
---|
| 1642 | uint32_t *pcbBuffer, uint8_t *pBuffer, uint32_t *pIndex, uint32_t *pcFiles)
|
---|
[3338] | 1643 | {
|
---|
| 1644 | PRTDIRENTRYEX pDirEntry = 0, pDirEntryOrg;
|
---|
| 1645 | uint32_t cbDirEntry, cbBufferOrg;
|
---|
| 1646 | PSHFLDIRINFO pSFDEntry;
|
---|
[7418] | 1647 | PRTUTF16 pwszString;
|
---|
[69753] | 1648 | RTDIR hDir;
|
---|
[65288] | 1649 | const bool fUtf8 = BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8) != 0;
|
---|
[39627] | 1650 |
|
---|
[65288] | 1651 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
[3338] | 1652 |
|
---|
[65288] | 1653 | SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, Handle);
|
---|
| 1654 | int rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 1655 | if (RT_SUCCESS(rc))
|
---|
| 1656 | { /* likely */ }
|
---|
| 1657 | else
|
---|
| 1658 | return rc;
|
---|
[59710] | 1659 |
|
---|
[65288] | 1660 | Assert(*pIndex == 0);
|
---|
[3338] | 1661 |
|
---|
| 1662 | cbDirEntry = 4096;
|
---|
| 1663 | pDirEntryOrg = pDirEntry = (PRTDIRENTRYEX)RTMemAlloc(cbDirEntry);
|
---|
| 1664 | if (pDirEntry == 0)
|
---|
| 1665 | {
|
---|
| 1666 | AssertFailed();
|
---|
| 1667 | return VERR_NO_MEMORY;
|
---|
| 1668 | }
|
---|
| 1669 |
|
---|
| 1670 | cbBufferOrg = *pcbBuffer;
|
---|
| 1671 | *pcbBuffer = 0;
|
---|
| 1672 | pSFDEntry = (PSHFLDIRINFO)pBuffer;
|
---|
| 1673 |
|
---|
| 1674 | *pIndex = 1; /* not yet complete */
|
---|
| 1675 | *pcFiles = 0;
|
---|
| 1676 |
|
---|
[75653] | 1677 | if (!pPath)
|
---|
| 1678 | hDir = pHandle->dir.Handle;
|
---|
| 1679 | else
|
---|
[3338] | 1680 | {
|
---|
| 1681 | if (pHandle->dir.SearchHandle == 0)
|
---|
| 1682 | {
|
---|
| 1683 | /* Build a host full path for the given path
|
---|
[99802] | 1684 | * and convert utf16 to utf8 if necessary.
|
---|
[3338] | 1685 | */
|
---|
| 1686 | char *pszFullPath = NULL;
|
---|
| 1687 |
|
---|
| 1688 | Assert(pHandle->dir.pLastValidEntry == 0);
|
---|
| 1689 |
|
---|
[56962] | 1690 | rc = vbsfBuildFullPath(pClient, root, pPath, pPath->u16Size + SHFLSTRING_HEADER_SIZE, &pszFullPath, NULL, true);
|
---|
[3338] | 1691 |
|
---|
[39594] | 1692 | if (RT_SUCCESS(rc))
|
---|
[3338] | 1693 | {
|
---|
[69674] | 1694 | rc = RTDirOpenFiltered(&pHandle->dir.SearchHandle, pszFullPath, RTDIRFILTER_WINNT, 0 /*fFlags*/);
|
---|
[3338] | 1695 |
|
---|
| 1696 | /* free the path string */
|
---|
| 1697 | vbsfFreeFullPath(pszFullPath);
|
---|
| 1698 |
|
---|
[39594] | 1699 | if (RT_FAILURE(rc))
|
---|
[3338] | 1700 | goto end;
|
---|
| 1701 | }
|
---|
| 1702 | else
|
---|
| 1703 | goto end;
|
---|
[75653] | 1704 | flags &= ~SHFL_LIST_RESTART;
|
---|
[3338] | 1705 | }
|
---|
| 1706 | Assert(pHandle->dir.SearchHandle);
|
---|
[69753] | 1707 | hDir = pHandle->dir.SearchHandle;
|
---|
[3338] | 1708 | }
|
---|
| 1709 |
|
---|
[75653] | 1710 | if (flags & SHFL_LIST_RESTART)
|
---|
| 1711 | {
|
---|
| 1712 | rc = RTDirRewind(hDir);
|
---|
| 1713 | if (RT_FAILURE(rc))
|
---|
| 1714 | goto end;
|
---|
| 1715 | }
|
---|
| 1716 |
|
---|
[39607] | 1717 | while (cbBufferOrg)
|
---|
[3338] | 1718 | {
|
---|
[14062] | 1719 | size_t cbDirEntrySize = cbDirEntry;
|
---|
[3338] | 1720 | uint32_t cbNeeded;
|
---|
| 1721 |
|
---|
| 1722 | /* Do we still have a valid last entry for the active search? If so, then return it here */
|
---|
| 1723 | if (pHandle->dir.pLastValidEntry)
|
---|
| 1724 | {
|
---|
| 1725 | pDirEntry = pHandle->dir.pLastValidEntry;
|
---|
| 1726 | }
|
---|
| 1727 | else
|
---|
| 1728 | {
|
---|
| 1729 | pDirEntry = pDirEntryOrg;
|
---|
| 1730 |
|
---|
[69753] | 1731 | rc = RTDirReadEx(hDir, pDirEntry, &cbDirEntrySize, RTFSOBJATTRADD_NOTHING, SHFL_RT_LINK(pClient));
|
---|
[3338] | 1732 | if (rc == VERR_NO_MORE_FILES)
|
---|
| 1733 | {
|
---|
| 1734 | *pIndex = 0; /* listing completed */
|
---|
| 1735 | break;
|
---|
| 1736 | }
|
---|
| 1737 |
|
---|
[32689] | 1738 | if ( rc != VINF_SUCCESS
|
---|
| 1739 | && rc != VWRN_NO_DIRENT_INFO)
|
---|
[3338] | 1740 | {
|
---|
[34051] | 1741 | //AssertFailed();
|
---|
[32689] | 1742 | if ( rc == VERR_NO_TRANSLATION
|
---|
| 1743 | || rc == VERR_INVALID_UTF8_ENCODING)
|
---|
[3338] | 1744 | continue;
|
---|
[32689] | 1745 | break;
|
---|
[3338] | 1746 | }
|
---|
| 1747 | }
|
---|
| 1748 |
|
---|
[39594] | 1749 | cbNeeded = RT_OFFSETOF(SHFLDIRINFO, name.String);
|
---|
[3338] | 1750 | if (fUtf8)
|
---|
| 1751 | cbNeeded += pDirEntry->cbName + 1;
|
---|
| 1752 | else
|
---|
| 1753 | /* Overestimating, but that's ok */
|
---|
| 1754 | cbNeeded += (pDirEntry->cbName + 1) * 2;
|
---|
| 1755 |
|
---|
| 1756 | if (cbBufferOrg < cbNeeded)
|
---|
| 1757 | {
|
---|
| 1758 | /* No room, so save this directory entry, or else it's lost forever */
|
---|
| 1759 | pHandle->dir.pLastValidEntry = pDirEntry;
|
---|
| 1760 |
|
---|
| 1761 | if (*pcFiles == 0)
|
---|
| 1762 | {
|
---|
| 1763 | AssertFailed();
|
---|
| 1764 | return VINF_BUFFER_OVERFLOW; /* Return directly and don't free pDirEntry */
|
---|
| 1765 | }
|
---|
| 1766 | return VINF_SUCCESS; /* Return directly and don't free pDirEntry */
|
---|
| 1767 | }
|
---|
| 1768 |
|
---|
[19171] | 1769 | #ifdef RT_OS_WINDOWS
|
---|
[19174] | 1770 | pDirEntry->Info.Attr.fMode |= 0111;
|
---|
[19171] | 1771 | #endif
|
---|
[33994] | 1772 | vbfsCopyFsObjInfoFromIprt(&pSFDEntry->Info, &pDirEntry->Info);
|
---|
[3338] | 1773 |
|
---|
[93075] | 1774 | /* The shortname (only used by OS/2 atm): */
|
---|
| 1775 | Assert(pDirEntry->cwcShortName < RT_ELEMENTS(pSFDEntry->uszShortName));
|
---|
| 1776 | Assert(pDirEntry->wszShortName[pDirEntry->cwcShortName] == '\0');
|
---|
| 1777 | pSFDEntry->cucShortName = pDirEntry->cwcShortName;
|
---|
| 1778 | if (pDirEntry->cwcShortName)
|
---|
| 1779 | memcpy(pSFDEntry->uszShortName, pDirEntry->wszShortName, sizeof(pSFDEntry->uszShortName));
|
---|
| 1780 |
|
---|
| 1781 | /* The name: */
|
---|
[3338] | 1782 | if (fUtf8)
|
---|
| 1783 | {
|
---|
| 1784 | void *src, *dst;
|
---|
| 1785 |
|
---|
| 1786 | src = &pDirEntry->szName[0];
|
---|
| 1787 | dst = &pSFDEntry->name.String.utf8[0];
|
---|
| 1788 |
|
---|
[39594] | 1789 | memcpy(dst, src, pDirEntry->cbName + 1);
|
---|
[3338] | 1790 |
|
---|
| 1791 | pSFDEntry->name.u16Size = pDirEntry->cbName + 1;
|
---|
| 1792 | pSFDEntry->name.u16Length = pDirEntry->cbName;
|
---|
| 1793 | }
|
---|
| 1794 | else
|
---|
| 1795 | {
|
---|
[99802] | 1796 | pSFDEntry->name.String.utf16[0] = 0;
|
---|
| 1797 | pwszString = pSFDEntry->name.String.utf16;
|
---|
[7418] | 1798 | int rc2 = RTStrToUtf16Ex(pDirEntry->szName, RTSTR_MAX, &pwszString, pDirEntry->cbName+1, NULL);
|
---|
[3338] | 1799 | AssertRC(rc2);
|
---|
| 1800 |
|
---|
[9880] | 1801 | #ifdef RT_OS_DARWIN
|
---|
[9927] | 1802 | /** @todo This belongs in rtPathToNative or in the windows shared folder file system driver...
|
---|
[33540] | 1803 | * The question is simply whether the NFD normalization is actually applied on a (virtual) file
|
---|
[9927] | 1804 | * system level in darwin, or just by the user mode application libs. */
|
---|
[26514] | 1805 | {
|
---|
| 1806 | // Convert to
|
---|
| 1807 | // Normalization Form C (composed Unicode). We need this because
|
---|
| 1808 | // Mac OS X file system uses NFD (Normalization Form D :decomposed Unicode)
|
---|
| 1809 | // while most other OS', server-side programs usually expect NFC.
|
---|
| 1810 | uint16_t ucs2Length;
|
---|
| 1811 | CFRange rangeCharacters;
|
---|
| 1812 | CFMutableStringRef inStr = ::CFStringCreateMutable(NULL, 0);
|
---|
[9927] | 1813 |
|
---|
[39594] | 1814 | ::CFStringAppendCharacters(inStr, (UniChar *)pwszString, RTUtf16Len(pwszString));
|
---|
[26514] | 1815 | ::CFStringNormalize(inStr, kCFStringNormalizationFormC);
|
---|
| 1816 | ucs2Length = ::CFStringGetLength(inStr);
|
---|
[9927] | 1817 |
|
---|
[26514] | 1818 | rangeCharacters.location = 0;
|
---|
| 1819 | rangeCharacters.length = ucs2Length;
|
---|
| 1820 | ::CFStringGetCharacters(inStr, rangeCharacters, pwszString);
|
---|
| 1821 | pwszString[ucs2Length] = 0x0000; // NULL terminated
|
---|
[9927] | 1822 |
|
---|
[26514] | 1823 | CFRelease(inStr);
|
---|
| 1824 | }
|
---|
[9880] | 1825 | #endif
|
---|
[99802] | 1826 | pSFDEntry->name.u16Length = (uint32_t)RTUtf16Len(pSFDEntry->name.String.utf16) * 2;
|
---|
[3338] | 1827 | pSFDEntry->name.u16Size = pSFDEntry->name.u16Length + 2;
|
---|
| 1828 |
|
---|
| 1829 | Log(("SHFL: File name size %d\n", pSFDEntry->name.u16Size));
|
---|
[99802] | 1830 | Log(("SHFL: File name %ls\n", &pSFDEntry->name.String.utf16));
|
---|
[3338] | 1831 |
|
---|
| 1832 | // adjust cbNeeded (it was overestimated before)
|
---|
[39594] | 1833 | cbNeeded = RT_OFFSETOF(SHFLDIRINFO, name.String) + pSFDEntry->name.u16Size;
|
---|
[3338] | 1834 | }
|
---|
| 1835 |
|
---|
[93075] | 1836 | /* Advance */
|
---|
[3338] | 1837 | pSFDEntry = (PSHFLDIRINFO)((uintptr_t)pSFDEntry + cbNeeded);
|
---|
| 1838 | *pcbBuffer += cbNeeded;
|
---|
| 1839 | cbBufferOrg-= cbNeeded;
|
---|
| 1840 |
|
---|
| 1841 | *pcFiles += 1;
|
---|
| 1842 |
|
---|
| 1843 | /* Free the saved last entry, that we've just returned */
|
---|
| 1844 | if (pHandle->dir.pLastValidEntry)
|
---|
| 1845 | {
|
---|
| 1846 | RTMemFree(pHandle->dir.pLastValidEntry);
|
---|
| 1847 | pHandle->dir.pLastValidEntry = NULL;
|
---|
[66520] | 1848 |
|
---|
| 1849 | /* And use the newly allocated buffer from now. */
|
---|
| 1850 | pDirEntry = pDirEntryOrg;
|
---|
[3338] | 1851 | }
|
---|
| 1852 |
|
---|
| 1853 | if (flags & SHFL_LIST_RETURN_ONE)
|
---|
| 1854 | break; /* we're done */
|
---|
| 1855 | }
|
---|
| 1856 | Assert(rc != VINF_SUCCESS || *pcbBuffer > 0);
|
---|
[9927] | 1857 |
|
---|
[3338] | 1858 | end:
|
---|
| 1859 | if (pDirEntry)
|
---|
| 1860 | RTMemFree(pDirEntry);
|
---|
| 1861 |
|
---|
| 1862 | return rc;
|
---|
| 1863 | }
|
---|
| 1864 |
|
---|
[39540] | 1865 | #ifdef UNITTEST
|
---|
| 1866 | /** Unit test the SHFL_FN_READLINK API. Located here as a form of API
|
---|
| 1867 | * documentation. */
|
---|
| 1868 | void testReadLink(RTTEST hTest)
|
---|
| 1869 | {
|
---|
| 1870 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 1871 | testReadLinkBadParameters(hTest);
|
---|
| 1872 | /* Add tests as required... */
|
---|
| 1873 | }
|
---|
| 1874 | #endif
|
---|
[33409] | 1875 | int vbsfReadLink(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pPath, uint32_t cbPath, uint8_t *pBuffer, uint32_t cbBuffer)
|
---|
| 1876 | {
|
---|
| 1877 | int rc = VINF_SUCCESS;
|
---|
| 1878 |
|
---|
| 1879 | if (pPath == 0 || pBuffer == 0)
|
---|
| 1880 | {
|
---|
| 1881 | AssertFailed();
|
---|
| 1882 | return VERR_INVALID_PARAMETER;
|
---|
| 1883 | }
|
---|
| 1884 |
|
---|
| 1885 | /* Build a host full path for the given path, handle file name case issues
|
---|
| 1886 | * (if the guest expects case-insensitive paths but the host is
|
---|
[99802] | 1887 | * case-sensitive) and convert utf16 to utf8 if necessary.
|
---|
[33409] | 1888 | */
|
---|
| 1889 | char *pszFullPath = NULL;
|
---|
| 1890 | uint32_t cbFullPathRoot = 0;
|
---|
| 1891 |
|
---|
[39594] | 1892 | rc = vbsfBuildFullPath(pClient, root, pPath, cbPath, &pszFullPath, &cbFullPathRoot);
|
---|
[33409] | 1893 |
|
---|
[39594] | 1894 | if (RT_SUCCESS(rc))
|
---|
[33409] | 1895 | {
|
---|
[39643] | 1896 | rc = RTSymlinkRead(pszFullPath, (char *) pBuffer, cbBuffer, 0);
|
---|
[57457] | 1897 | if (RT_SUCCESS(rc))
|
---|
| 1898 | {
|
---|
| 1899 | /* Convert the slashes in the link target to the guest path separator characters. */
|
---|
[77860] | 1900 | /** @todo r=bird: for some messed up reason, we return UTF-8 here rather than
|
---|
| 1901 | * the character set selected by the client. We also don't return the
|
---|
| 1902 | * length, so the clients are paranoid about the zero termination behavior. */
|
---|
| 1903 | char ch;
|
---|
[57457] | 1904 | char *psz = (char *)pBuffer;
|
---|
[77860] | 1905 | while ((ch = *psz) != '\0')
|
---|
[57457] | 1906 | {
|
---|
[77860] | 1907 | if (RTPATH_IS_SLASH(ch))
|
---|
[57457] | 1908 | *psz = pClient->PathDelimiter;
|
---|
| 1909 | psz++;
|
---|
| 1910 | }
|
---|
| 1911 | }
|
---|
[33409] | 1912 |
|
---|
| 1913 | /* free the path string */
|
---|
| 1914 | vbsfFreeFullPath(pszFullPath);
|
---|
| 1915 | }
|
---|
| 1916 |
|
---|
| 1917 | return rc;
|
---|
| 1918 | }
|
---|
| 1919 |
|
---|
[62789] | 1920 | int vbsfQueryFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags,
|
---|
| 1921 | uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
[3338] | 1922 | {
|
---|
[65288] | 1923 | RT_NOREF1(flags);
|
---|
[39544] | 1924 | uint32_t type = vbsfQueryHandleType(pClient, Handle);
|
---|
[3338] | 1925 | int rc = VINF_SUCCESS;
|
---|
[34051] | 1926 | SHFLFSOBJINFO *pObjInfo = (SHFLFSOBJINFO *)pBuffer;
|
---|
| 1927 | RTFSOBJINFO fileinfo;
|
---|
[3338] | 1928 |
|
---|
| 1929 |
|
---|
[65999] | 1930 | AssertReturn(type == SHFL_HF_TYPE_DIR || type == SHFL_HF_TYPE_FILE, VERR_INVALID_PARAMETER);
|
---|
| 1931 | AssertReturn(pcbBuffer != NULL, VERR_INVALID_PARAMETER);
|
---|
| 1932 | AssertReturn(pObjInfo != NULL, VERR_INVALID_PARAMETER);
|
---|
| 1933 | AssertReturn(*pcbBuffer >= sizeof(SHFLFSOBJINFO), VERR_INVALID_PARAMETER);
|
---|
[3338] | 1934 |
|
---|
[63565] | 1935 | /** @todo other options */
|
---|
[3338] | 1936 | Assert(flags == (SHFL_INFO_GET|SHFL_INFO_FILE));
|
---|
| 1937 |
|
---|
| 1938 | *pcbBuffer = 0;
|
---|
| 1939 |
|
---|
[39544] | 1940 | if (type == SHFL_HF_TYPE_DIR)
|
---|
[3338] | 1941 | {
|
---|
[39544] | 1942 | SHFLFILEHANDLE *pHandle = vbsfQueryDirHandle(pClient, Handle);
|
---|
[65288] | 1943 | rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 1944 | if (RT_SUCCESS(rc))
|
---|
| 1945 | rc = RTDirQueryInfo(pHandle->dir.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
|
---|
[3338] | 1946 | }
|
---|
| 1947 | else
|
---|
| 1948 | {
|
---|
[39544] | 1949 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[65288] | 1950 | rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 1951 | if (RT_SUCCESS(rc))
|
---|
| 1952 | rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
|
---|
[19171] | 1953 | #ifdef RT_OS_WINDOWS
|
---|
[19174] | 1954 | if (RT_SUCCESS(rc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
|
---|
| 1955 | pObjInfo->Attr.fMode |= 0111;
|
---|
[19171] | 1956 | #endif
|
---|
[3338] | 1957 | }
|
---|
| 1958 | if (rc == VINF_SUCCESS)
|
---|
| 1959 | {
|
---|
[34051] | 1960 | vbfsCopyFsObjInfoFromIprt(pObjInfo, &fileinfo);
|
---|
| 1961 | *pcbBuffer = sizeof(SHFLFSOBJINFO);
|
---|
[3338] | 1962 | }
|
---|
| 1963 | else
|
---|
| 1964 | AssertFailed();
|
---|
| 1965 |
|
---|
| 1966 | return rc;
|
---|
| 1967 | }
|
---|
| 1968 |
|
---|
[62789] | 1969 | static int vbsfSetFileInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags,
|
---|
| 1970 | uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
[3338] | 1971 | {
|
---|
[65288] | 1972 | RT_NOREF1(flags);
|
---|
[39544] | 1973 | uint32_t type = vbsfQueryHandleType(pClient, Handle);
|
---|
[3338] | 1974 | int rc = VINF_SUCCESS;
|
---|
[34051] | 1975 | SHFLFSOBJINFO *pSFDEntry;
|
---|
[3338] | 1976 |
|
---|
[39544] | 1977 | if ( !(type == SHFL_HF_TYPE_DIR || type == SHFL_HF_TYPE_FILE)
|
---|
| 1978 | || pcbBuffer == 0
|
---|
| 1979 | || pBuffer == 0
|
---|
| 1980 | || *pcbBuffer < sizeof(SHFLFSOBJINFO))
|
---|
[3338] | 1981 | {
|
---|
| 1982 | AssertFailed();
|
---|
| 1983 | return VERR_INVALID_PARAMETER;
|
---|
| 1984 | }
|
---|
| 1985 |
|
---|
| 1986 | *pcbBuffer = 0;
|
---|
[34051] | 1987 | pSFDEntry = (SHFLFSOBJINFO *)pBuffer;
|
---|
[3338] | 1988 |
|
---|
| 1989 | Assert(flags == (SHFL_INFO_SET | SHFL_INFO_FILE));
|
---|
| 1990 |
|
---|
[78947] | 1991 | /*
|
---|
| 1992 | * Get the handle.
|
---|
| 1993 | */
|
---|
| 1994 | SHFLFILEHANDLE *pHandle;
|
---|
| 1995 | if (type == SHFL_HF_TYPE_FILE)
|
---|
[3338] | 1996 | {
|
---|
[78947] | 1997 | pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[65288] | 1998 | rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
[3338] | 1999 | }
|
---|
| 2000 | else
|
---|
| 2001 | {
|
---|
[78947] | 2002 | Assert(type == SHFL_HF_TYPE_DIR);
|
---|
| 2003 | pHandle = vbsfQueryDirHandle(pClient, Handle);
|
---|
[65288] | 2004 | rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
[3338] | 2005 | }
|
---|
[78947] | 2006 | if (RT_SUCCESS(rc))
|
---|
[3338] | 2007 | {
|
---|
[78947] | 2008 | /*
|
---|
| 2009 | * Any times to set?
|
---|
| 2010 | */
|
---|
| 2011 | if ( RTTimeSpecGetNano(&pSFDEntry->AccessTime)
|
---|
| 2012 | || RTTimeSpecGetNano(&pSFDEntry->ModificationTime)
|
---|
| 2013 | || RTTimeSpecGetNano(&pSFDEntry->ChangeTime)
|
---|
| 2014 | || RTTimeSpecGetNano(&pSFDEntry->BirthTime))
|
---|
| 2015 | {
|
---|
[3338] | 2016 |
|
---|
[78947] | 2017 | /* Change only the time values that are not zero */
|
---|
| 2018 | if (type == SHFL_HF_TYPE_FILE)
|
---|
| 2019 | rc = RTFileSetTimes(pHandle->file.Handle,
|
---|
| 2020 | RTTimeSpecGetNano(&pSFDEntry->AccessTime) ? &pSFDEntry->AccessTime : NULL,
|
---|
| 2021 | RTTimeSpecGetNano(&pSFDEntry->ModificationTime) ? &pSFDEntry->ModificationTime : NULL,
|
---|
| 2022 | RTTimeSpecGetNano(&pSFDEntry->ChangeTime) ? &pSFDEntry->ChangeTime : NULL,
|
---|
| 2023 | RTTimeSpecGetNano(&pSFDEntry->BirthTime) ? &pSFDEntry->BirthTime : NULL);
|
---|
| 2024 | else
|
---|
| 2025 | rc = RTDirSetTimes( pHandle->dir.Handle,
|
---|
| 2026 | RTTimeSpecGetNano(&pSFDEntry->AccessTime) ? &pSFDEntry->AccessTime : NULL,
|
---|
| 2027 | RTTimeSpecGetNano(&pSFDEntry->ModificationTime) ? &pSFDEntry->ModificationTime : NULL,
|
---|
| 2028 | RTTimeSpecGetNano(&pSFDEntry->ChangeTime) ? &pSFDEntry->ChangeTime : NULL,
|
---|
| 2029 | RTTimeSpecGetNano(&pSFDEntry->BirthTime) ? &pSFDEntry->BirthTime : NULL);
|
---|
| 2030 | if (RT_FAILURE(rc))
|
---|
| 2031 | {
|
---|
| 2032 | Log(("RT%sSetTimes failed with %Rrc\n", type == SHFL_HF_TYPE_FILE ? "File" : "Dir", rc));
|
---|
| 2033 | Log(("AccessTime %#RX64\n", RTTimeSpecGetNano(&pSFDEntry->AccessTime)));
|
---|
| 2034 | Log(("ModificationTime %#RX64\n", RTTimeSpecGetNano(&pSFDEntry->ModificationTime)));
|
---|
| 2035 | Log(("ChangeTime %#RX64\n", RTTimeSpecGetNano(&pSFDEntry->ChangeTime)));
|
---|
| 2036 | Log(("BirthTime %#RX64\n", RTTimeSpecGetNano(&pSFDEntry->BirthTime)));
|
---|
| 2037 | /* "temporary" hack */
|
---|
| 2038 | rc = VINF_SUCCESS;
|
---|
| 2039 | }
|
---|
| 2040 | }
|
---|
| 2041 |
|
---|
| 2042 | /*
|
---|
| 2043 | * Any mode changes?
|
---|
| 2044 | */
|
---|
| 2045 | if (pSFDEntry->Attr.fMode)
|
---|
[3338] | 2046 | {
|
---|
[78947] | 2047 | RTFMODE fMode = pSFDEntry->Attr.fMode;
|
---|
| 2048 |
|
---|
| 2049 | if (type == SHFL_HF_TYPE_FILE)
|
---|
[65288] | 2050 | {
|
---|
[20346] | 2051 | #ifndef RT_OS_WINDOWS
|
---|
[78947] | 2052 | /* Don't allow the guest to clear the read own bit, otherwise the guest wouldn't
|
---|
| 2053 | * be able to access this file anymore. Only for guests, which set the UNIX mode.
|
---|
[70726] | 2054 | * Also, clear bits which we don't pass through for security reasons. */
|
---|
[65288] | 2055 | if (fMode & RTFS_UNIX_MASK)
|
---|
[70726] | 2056 | {
|
---|
[65288] | 2057 | fMode |= RTFS_UNIX_IRUSR;
|
---|
[70726] | 2058 | fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT);
|
---|
| 2059 | }
|
---|
[20346] | 2060 | #endif
|
---|
[65288] | 2061 | rc = RTFileSetMode(pHandle->file.Handle, fMode);
|
---|
[78947] | 2062 | }
|
---|
| 2063 | else
|
---|
| 2064 | {
|
---|
| 2065 | #ifndef RT_OS_WINDOWS
|
---|
| 2066 | /* Don't allow the guest to clear the read+execute own bits, otherwise the guest
|
---|
| 2067 | * wouldn't be able to access this directory anymore. Only for guests, which set
|
---|
| 2068 | * the UNIX mode. Also, clear bits which we don't pass through for security reasons. */
|
---|
| 2069 | if (fMode & RTFS_UNIX_MASK)
|
---|
[65288] | 2070 | {
|
---|
[78947] | 2071 | fMode |= RTFS_UNIX_IRUSR | RTFS_UNIX_IXUSR;
|
---|
| 2072 | fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT /*?*/);
|
---|
[65288] | 2073 | }
|
---|
[78947] | 2074 | #endif
|
---|
| 2075 | rc = RTDirSetMode(pHandle->dir.Handle, fMode);
|
---|
[3996] | 2076 | }
|
---|
[78947] | 2077 | if (RT_FAILURE(rc))
|
---|
| 2078 | {
|
---|
| 2079 | Log(("RT%sSetMode %#x (%#x) failed with %Rrc\n", type == SHFL_HF_TYPE_FILE ? "File" : "Dir",
|
---|
| 2080 | fMode, pSFDEntry->Attr.fMode, rc));
|
---|
| 2081 | /* silent failure, because this tends to fail with e.g. windows guest & linux host */
|
---|
| 2082 | rc = VINF_SUCCESS;
|
---|
| 2083 | }
|
---|
[3338] | 2084 | }
|
---|
| 2085 |
|
---|
[78947] | 2086 | /*
|
---|
| 2087 | * Return the current file info on success.
|
---|
| 2088 | */
|
---|
| 2089 | if (RT_SUCCESS(rc))
|
---|
[3338] | 2090 | {
|
---|
[78947] | 2091 | uint32_t bufsize = sizeof(*pSFDEntry);
|
---|
| 2092 | rc = vbsfQueryFileInfo(pClient, root, Handle, SHFL_INFO_GET | SHFL_INFO_FILE, &bufsize, (uint8_t *)pSFDEntry);
|
---|
| 2093 | if (RT_SUCCESS(rc))
|
---|
| 2094 | *pcbBuffer = sizeof(SHFLFSOBJINFO);
|
---|
| 2095 | else
|
---|
| 2096 | AssertFailed();
|
---|
[3338] | 2097 | }
|
---|
| 2098 | }
|
---|
| 2099 | return rc;
|
---|
| 2100 | }
|
---|
| 2101 |
|
---|
| 2102 |
|
---|
[76143] | 2103 | /**
|
---|
| 2104 | * Handles SHFL_FN_SET_FILE_SIZE.
|
---|
| 2105 | */
|
---|
| 2106 | int vbsfSetFileSize(SHFLCLIENTDATA *pClient, SHFLROOT idRoot, SHFLHANDLE hHandle, uint64_t cbNewSize)
|
---|
| 2107 | {
|
---|
| 2108 | /*
|
---|
| 2109 | * Resolve handle and validate write access.
|
---|
| 2110 | */
|
---|
| 2111 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, hHandle);
|
---|
| 2112 | ASSERT_GUEST_RETURN(pHandle, VERR_INVALID_HANDLE);
|
---|
| 2113 |
|
---|
| 2114 | int rc = vbsfCheckHandleAccess(pClient, idRoot, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
| 2115 | if (RT_SUCCESS(rc))
|
---|
| 2116 | {
|
---|
| 2117 | /*
|
---|
| 2118 | * Execute the request.
|
---|
| 2119 | */
|
---|
| 2120 | rc = RTFileSetSize(pHandle->file.Handle, cbNewSize);
|
---|
| 2121 | }
|
---|
| 2122 | return rc;
|
---|
| 2123 | }
|
---|
| 2124 |
|
---|
| 2125 |
|
---|
[62789] | 2126 | static int vbsfSetEndOfFile(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags,
|
---|
| 2127 | uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
[3338] | 2128 | {
|
---|
[65288] | 2129 | RT_NOREF1(flags);
|
---|
[39544] | 2130 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[34051] | 2131 | SHFLFSOBJINFO *pSFDEntry;
|
---|
[3338] | 2132 |
|
---|
[34078] | 2133 | if (pHandle == 0 || pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLFSOBJINFO))
|
---|
[3338] | 2134 | {
|
---|
| 2135 | AssertFailed();
|
---|
| 2136 | return VERR_INVALID_PARAMETER;
|
---|
| 2137 | }
|
---|
| 2138 |
|
---|
[65288] | 2139 | int rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_WRITE);
|
---|
| 2140 | if (RT_SUCCESS(rc))
|
---|
| 2141 | { /* likely */ }
|
---|
| 2142 | else
|
---|
| 2143 | return rc;
|
---|
| 2144 |
|
---|
[3338] | 2145 | *pcbBuffer = 0;
|
---|
[34051] | 2146 | pSFDEntry = (SHFLFSOBJINFO *)pBuffer;
|
---|
[3338] | 2147 |
|
---|
| 2148 | if (flags & SHFL_INFO_SIZE)
|
---|
| 2149 | {
|
---|
| 2150 | rc = RTFileSetSize(pHandle->file.Handle, pSFDEntry->cbObject);
|
---|
| 2151 | if (rc != VINF_SUCCESS)
|
---|
| 2152 | AssertFailed();
|
---|
| 2153 | }
|
---|
| 2154 | else
|
---|
| 2155 | AssertFailed();
|
---|
| 2156 |
|
---|
| 2157 | if (rc == VINF_SUCCESS)
|
---|
| 2158 | {
|
---|
| 2159 | RTFSOBJINFO fileinfo;
|
---|
| 2160 |
|
---|
| 2161 | /* Query the new object info and return it */
|
---|
| 2162 | rc = RTFileQueryInfo(pHandle->file.Handle, &fileinfo, RTFSOBJATTRADD_NOTHING);
|
---|
| 2163 | if (rc == VINF_SUCCESS)
|
---|
| 2164 | {
|
---|
[19171] | 2165 | #ifdef RT_OS_WINDOWS
|
---|
[19174] | 2166 | fileinfo.Attr.fMode |= 0111;
|
---|
[19171] | 2167 | #endif
|
---|
[34051] | 2168 | vbfsCopyFsObjInfoFromIprt(pSFDEntry, &fileinfo);
|
---|
| 2169 | *pcbBuffer = sizeof(SHFLFSOBJINFO);
|
---|
[3338] | 2170 | }
|
---|
| 2171 | else
|
---|
| 2172 | AssertFailed();
|
---|
| 2173 | }
|
---|
| 2174 |
|
---|
| 2175 | return rc;
|
---|
| 2176 | }
|
---|
| 2177 |
|
---|
[99775] | 2178 | static int vbsfQueryVolumeInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
[3338] | 2179 | {
|
---|
[62789] | 2180 | RT_NOREF2(root, flags);
|
---|
[3338] | 2181 | int rc = VINF_SUCCESS;
|
---|
| 2182 | SHFLVOLINFO *pSFDEntry;
|
---|
| 2183 | char *pszFullPath = NULL;
|
---|
[66099] | 2184 | union
|
---|
| 2185 | {
|
---|
| 2186 | SHFLSTRING Dummy;
|
---|
| 2187 | uint8_t abDummy[SHFLSTRING_HEADER_SIZE + sizeof(RTUTF16)];
|
---|
| 2188 | } Buf;
|
---|
[3338] | 2189 |
|
---|
[4926] | 2190 | if (pcbBuffer == 0 || pBuffer == 0 || *pcbBuffer < sizeof(SHFLVOLINFO))
|
---|
[3338] | 2191 | {
|
---|
| 2192 | AssertFailed();
|
---|
| 2193 | return VERR_INVALID_PARAMETER;
|
---|
| 2194 | }
|
---|
| 2195 |
|
---|
[63565] | 2196 | /** @todo other options */
|
---|
[3338] | 2197 | Assert(flags == (SHFL_INFO_GET|SHFL_INFO_VOLUME));
|
---|
| 2198 |
|
---|
| 2199 | *pcbBuffer = 0;
|
---|
| 2200 | pSFDEntry = (PSHFLVOLINFO)pBuffer;
|
---|
| 2201 |
|
---|
[66099] | 2202 | ShflStringInitBuffer(&Buf.Dummy, sizeof(Buf));
|
---|
[99802] | 2203 | Buf.Dummy.String.utf16[0] = '\0';
|
---|
[66099] | 2204 | rc = vbsfBuildFullPath(pClient, root, &Buf.Dummy, sizeof(Buf), &pszFullPath, NULL);
|
---|
[3338] | 2205 |
|
---|
[39594] | 2206 | if (RT_SUCCESS(rc))
|
---|
[3338] | 2207 | {
|
---|
| 2208 | rc = RTFsQuerySizes(pszFullPath, &pSFDEntry->ullTotalAllocationBytes, &pSFDEntry->ullAvailableAllocationBytes, &pSFDEntry->ulBytesPerAllocationUnit, &pSFDEntry->ulBytesPerSector);
|
---|
| 2209 | if (rc != VINF_SUCCESS)
|
---|
| 2210 | goto exit;
|
---|
| 2211 |
|
---|
| 2212 | rc = RTFsQuerySerial(pszFullPath, &pSFDEntry->ulSerial);
|
---|
| 2213 | if (rc != VINF_SUCCESS)
|
---|
| 2214 | goto exit;
|
---|
| 2215 |
|
---|
[33994] | 2216 | RTFSPROPERTIES FsProperties;
|
---|
| 2217 | rc = RTFsQueryProperties(pszFullPath, &FsProperties);
|
---|
[3338] | 2218 | if (rc != VINF_SUCCESS)
|
---|
| 2219 | goto exit;
|
---|
[33994] | 2220 | vbfsCopyFsPropertiesFromIprt(&pSFDEntry->fsProperties, &FsProperties);
|
---|
[3338] | 2221 |
|
---|
| 2222 | *pcbBuffer = sizeof(SHFLVOLINFO);
|
---|
| 2223 | }
|
---|
| 2224 | else AssertFailed();
|
---|
| 2225 |
|
---|
| 2226 | exit:
|
---|
[13837] | 2227 | AssertMsg(rc == VINF_SUCCESS, ("failure: rc = %Rrc\n", rc));
|
---|
[3338] | 2228 | /* free the path string */
|
---|
| 2229 | vbsfFreeFullPath(pszFullPath);
|
---|
| 2230 | return rc;
|
---|
| 2231 | }
|
---|
| 2232 |
|
---|
| 2233 | int vbsfQueryFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
| 2234 | {
|
---|
[4926] | 2235 | if (pcbBuffer == 0 || pBuffer == 0)
|
---|
[3338] | 2236 | {
|
---|
| 2237 | AssertFailed();
|
---|
| 2238 | return VERR_INVALID_PARAMETER;
|
---|
| 2239 | }
|
---|
| 2240 |
|
---|
| 2241 | if (flags & SHFL_INFO_FILE)
|
---|
| 2242 | return vbsfQueryFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
|
---|
| 2243 |
|
---|
| 2244 | if (flags & SHFL_INFO_VOLUME)
|
---|
[4926] | 2245 | return vbsfQueryVolumeInfo(pClient, root, flags, pcbBuffer, pBuffer);
|
---|
[3338] | 2246 |
|
---|
| 2247 | AssertFailed();
|
---|
| 2248 | return VERR_INVALID_PARAMETER;
|
---|
| 2249 | }
|
---|
| 2250 |
|
---|
[39540] | 2251 | #ifdef UNITTEST
|
---|
| 2252 | /** Unit test the SHFL_FN_INFORMATION API. Located here as a form of API
|
---|
| 2253 | * documentation. */
|
---|
| 2254 | void testFSInfo(RTTEST hTest)
|
---|
| 2255 | {
|
---|
| 2256 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 2257 | testFSInfoBadParameters(hTest);
|
---|
| 2258 | /* Basic get and set file size test. */
|
---|
| 2259 | testFSInfoQuerySetFMode(hTest);
|
---|
| 2260 | /* Basic get and set dir atime test. */
|
---|
| 2261 | testFSInfoQuerySetDirATime(hTest);
|
---|
| 2262 | /* Basic get and set file atime test. */
|
---|
| 2263 | testFSInfoQuerySetFileATime(hTest);
|
---|
| 2264 | /* Basic set end of file. */
|
---|
| 2265 | testFSInfoQuerySetEndOfFile(hTest);
|
---|
| 2266 | /* Add tests as required... */
|
---|
| 2267 | }
|
---|
| 2268 | #endif
|
---|
[3338] | 2269 | int vbsfSetFSInfo(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint32_t flags, uint32_t *pcbBuffer, uint8_t *pBuffer)
|
---|
| 2270 | {
|
---|
[39544] | 2271 | uint32_t type = vbsfQueryHandleType(pClient, Handle)
|
---|
| 2272 | & (SHFL_HF_TYPE_DIR|SHFL_HF_TYPE_FILE|SHFL_HF_TYPE_VOLUME);
|
---|
[3338] | 2273 |
|
---|
[39544] | 2274 | if (type == 0 || pcbBuffer == 0 || pBuffer == 0)
|
---|
[3338] | 2275 | {
|
---|
| 2276 | AssertFailed();
|
---|
| 2277 | return VERR_INVALID_PARAMETER;
|
---|
| 2278 | }
|
---|
[6413] | 2279 |
|
---|
[3338] | 2280 | if (flags & SHFL_INFO_FILE)
|
---|
| 2281 | return vbsfSetFileInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
|
---|
| 2282 |
|
---|
| 2283 | if (flags & SHFL_INFO_SIZE)
|
---|
| 2284 | return vbsfSetEndOfFile(pClient, root, Handle, flags, pcbBuffer, pBuffer);
|
---|
| 2285 |
|
---|
| 2286 | // if (flags & SHFL_INFO_VOLUME)
|
---|
| 2287 | // return vbsfVolumeInfo(pClient, root, Handle, flags, pcbBuffer, pBuffer);
|
---|
| 2288 | AssertFailed();
|
---|
| 2289 | return VERR_INVALID_PARAMETER;
|
---|
| 2290 | }
|
---|
| 2291 |
|
---|
[39540] | 2292 | #ifdef UNITTEST
|
---|
| 2293 | /** Unit test the SHFL_FN_LOCK API. Located here as a form of API
|
---|
| 2294 | * documentation. */
|
---|
| 2295 | void testLock(RTTEST hTest)
|
---|
| 2296 | {
|
---|
| 2297 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 2298 | testLockBadParameters(hTest);
|
---|
| 2299 | /* Simple file locking and unlocking test. */
|
---|
| 2300 | testLockFileSimple(hTest);
|
---|
| 2301 | /* Add tests as required... */
|
---|
| 2302 | }
|
---|
| 2303 | #endif
|
---|
[62789] | 2304 |
|
---|
[3338] | 2305 | int vbsfLock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
|
---|
| 2306 | {
|
---|
[39544] | 2307 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[3338] | 2308 | uint32_t fRTLock = 0;
|
---|
| 2309 |
|
---|
| 2310 | Assert((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL);
|
---|
| 2311 |
|
---|
[65288] | 2312 | int rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 2313 | if (RT_SUCCESS(rc))
|
---|
| 2314 | { /* likely */ }
|
---|
| 2315 | else
|
---|
| 2316 | return rc;
|
---|
| 2317 |
|
---|
[3338] | 2318 | if ( ((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL)
|
---|
| 2319 | || (flags & SHFL_LOCK_ENTIRE)
|
---|
| 2320 | )
|
---|
| 2321 | {
|
---|
| 2322 | AssertFailed();
|
---|
| 2323 | return VERR_INVALID_PARAMETER;
|
---|
| 2324 | }
|
---|
| 2325 |
|
---|
| 2326 | /* Lock type */
|
---|
| 2327 | switch(flags & SHFL_LOCK_MODE_MASK)
|
---|
| 2328 | {
|
---|
| 2329 | case SHFL_LOCK_SHARED:
|
---|
| 2330 | fRTLock = RTFILE_LOCK_READ;
|
---|
| 2331 | break;
|
---|
| 2332 |
|
---|
| 2333 | case SHFL_LOCK_EXCLUSIVE:
|
---|
| 2334 | fRTLock = RTFILE_LOCK_READ | RTFILE_LOCK_WRITE;
|
---|
| 2335 | break;
|
---|
| 2336 |
|
---|
| 2337 | default:
|
---|
| 2338 | AssertFailed();
|
---|
| 2339 | return VERR_INVALID_PARAMETER;
|
---|
| 2340 | }
|
---|
| 2341 |
|
---|
| 2342 | /* Lock wait type */
|
---|
| 2343 | if (flags & SHFL_LOCK_WAIT)
|
---|
| 2344 | fRTLock |= RTFILE_LOCK_WAIT;
|
---|
| 2345 | else
|
---|
| 2346 | fRTLock |= RTFILE_LOCK_IMMEDIATELY;
|
---|
| 2347 |
|
---|
[5090] | 2348 | #ifdef RT_OS_WINDOWS
|
---|
[3338] | 2349 | rc = RTFileLock(pHandle->file.Handle, fRTLock, offset, length);
|
---|
| 2350 | if (rc != VINF_SUCCESS)
|
---|
[5087] | 2351 | Log(("RTFileLock %RTfile %RX64 %RX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
|
---|
[5090] | 2352 | #else
|
---|
| 2353 | Log(("vbsfLock: Pretend success handle=%x\n", Handle));
|
---|
| 2354 | rc = VINF_SUCCESS;
|
---|
[62876] | 2355 | RT_NOREF2(offset, length);
|
---|
[5090] | 2356 | #endif
|
---|
[3338] | 2357 | return rc;
|
---|
| 2358 | }
|
---|
| 2359 |
|
---|
| 2360 | int vbsfUnlock(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLHANDLE Handle, uint64_t offset, uint64_t length, uint32_t flags)
|
---|
| 2361 | {
|
---|
[39544] | 2362 | SHFLFILEHANDLE *pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
[3338] | 2363 |
|
---|
| 2364 | Assert((flags & SHFL_LOCK_MODE_MASK) == SHFL_LOCK_CANCEL);
|
---|
| 2365 |
|
---|
[65288] | 2366 | int rc = vbsfCheckHandleAccess(pClient, root, pHandle, VBSF_CHECK_ACCESS_READ);
|
---|
| 2367 | if (RT_SUCCESS(rc))
|
---|
| 2368 | { /* likely */ }
|
---|
| 2369 | else
|
---|
| 2370 | return rc;
|
---|
| 2371 |
|
---|
[3338] | 2372 | if ( ((flags & SHFL_LOCK_MODE_MASK) != SHFL_LOCK_CANCEL)
|
---|
| 2373 | || (flags & SHFL_LOCK_ENTIRE)
|
---|
| 2374 | )
|
---|
| 2375 | {
|
---|
| 2376 | return VERR_INVALID_PARAMETER;
|
---|
| 2377 | }
|
---|
| 2378 |
|
---|
[5090] | 2379 | #ifdef RT_OS_WINDOWS
|
---|
[3338] | 2380 | rc = RTFileUnlock(pHandle->file.Handle, offset, length);
|
---|
| 2381 | if (rc != VINF_SUCCESS)
|
---|
| 2382 | Log(("RTFileUnlock %RTfile %RX64 %RTX64 failed with %Rrc\n", pHandle->file.Handle, offset, length, rc));
|
---|
[5090] | 2383 | #else
|
---|
| 2384 | Log(("vbsfUnlock: Pretend success handle=%x\n", Handle));
|
---|
| 2385 | rc = VINF_SUCCESS;
|
---|
[62876] | 2386 | RT_NOREF2(offset, length);
|
---|
[5090] | 2387 | #endif
|
---|
[3338] | 2388 |
|
---|
| 2389 | return rc;
|
---|
| 2390 | }
|
---|
| 2391 |
|
---|
| 2392 |
|
---|
[39540] | 2393 | #ifdef UNITTEST
|
---|
| 2394 | /** Unit test the SHFL_FN_REMOVE API. Located here as a form of API
|
---|
| 2395 | * documentation. */
|
---|
| 2396 | void testRemove(RTTEST hTest)
|
---|
| 2397 | {
|
---|
| 2398 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 2399 | testRemoveBadParameters(hTest);
|
---|
| 2400 | /* Add tests as required... */
|
---|
| 2401 | }
|
---|
| 2402 | #endif
|
---|
[78467] | 2403 | int vbsfRemove(SHFLCLIENTDATA *pClient, SHFLROOT root, PCSHFLSTRING pPath, uint32_t cbPath, uint32_t flags, SHFLHANDLE hToClose)
|
---|
[3338] | 2404 | {
|
---|
| 2405 |
|
---|
| 2406 | /* Validate input */
|
---|
[78467] | 2407 | Assert(pPath);
|
---|
| 2408 | AssertReturn(pPath->u16Size > 0, VERR_INVALID_PARAMETER);
|
---|
[3338] | 2409 |
|
---|
[78467] | 2410 | /*
|
---|
| 2411 | * Close the handle if specified.
|
---|
[3338] | 2412 | */
|
---|
[78467] | 2413 | int rc = VINF_SUCCESS;
|
---|
| 2414 | if (hToClose != SHFL_HANDLE_NIL)
|
---|
| 2415 | rc = vbsfClose(pClient, root, hToClose);
|
---|
[39594] | 2416 | if (RT_SUCCESS(rc))
|
---|
[3338] | 2417 | {
|
---|
[78467] | 2418 | /*
|
---|
[99802] | 2419 | * Build a host full path for the given path and convert utf16 to utf8 if necessary.
|
---|
[78467] | 2420 | */
|
---|
| 2421 | char *pszFullPath = NULL;
|
---|
| 2422 | rc = vbsfBuildFullPath(pClient, root, pPath, cbPath, &pszFullPath, NULL);
|
---|
[39594] | 2423 | if (RT_SUCCESS(rc))
|
---|
[6402] | 2424 | {
|
---|
[78467] | 2425 | /*
|
---|
| 2426 | * Is the guest allowed to write to this share?
|
---|
| 2427 | */
|
---|
| 2428 | bool fWritable;
|
---|
| 2429 | rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
|
---|
| 2430 | if (RT_SUCCESS(rc) && fWritable)
|
---|
| 2431 | {
|
---|
| 2432 | /*
|
---|
| 2433 | * Do the removal/deletion according to the type flags.
|
---|
| 2434 | */
|
---|
| 2435 | if (flags & SHFL_REMOVE_SYMLINK)
|
---|
| 2436 | rc = RTSymlinkDelete(pszFullPath, 0);
|
---|
| 2437 | else if (flags & SHFL_REMOVE_FILE)
|
---|
| 2438 | rc = RTFileDelete(pszFullPath);
|
---|
| 2439 | else
|
---|
| 2440 | rc = RTDirRemove(pszFullPath);
|
---|
[78704] | 2441 |
|
---|
| 2442 | #if 0 //ndef RT_OS_WINDOWS
|
---|
| 2443 | /* There are a few adjustments to be made here: */
|
---|
| 2444 | if ( rc == VERR_FILE_NOT_FOUND
|
---|
| 2445 | && SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 2446 | && vbsfErrorStyleIsWindowsPathNotFound(pszFullPath))
|
---|
| 2447 | rc = VERR_PATH_NOT_FOUND;
|
---|
| 2448 | else if ( rc == VERR_PATH_NOT_FOUND
|
---|
| 2449 | && SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient))
|
---|
| 2450 | {
|
---|
| 2451 | if (flags & (SHFL_REMOVE_FILE | SHFL_REMOVE_SYMLINK))
|
---|
| 2452 | {
|
---|
| 2453 | size_t cchFullPath = strlen(pszFullPath);
|
---|
| 2454 | if (cchFullPath > 0 && RTPATH_IS_SLASH(pszFullPath[cchFullPath - 1]))
|
---|
| 2455 | rc = VERR_INVALID_NAME;
|
---|
| 2456 | }
|
---|
| 2457 | else if (vbsfErrorStyleIsWindowsNotADirectory(pszFullPath))
|
---|
| 2458 | rc = VERR_NOT_A_DIRECTORY;
|
---|
| 2459 | }
|
---|
| 2460 | #endif
|
---|
[78467] | 2461 | }
|
---|
[6402] | 2462 | else
|
---|
[78467] | 2463 | rc = VERR_WRITE_PROTECT;
|
---|
| 2464 |
|
---|
| 2465 | /* free the path string */
|
---|
| 2466 | vbsfFreeFullPath(pszFullPath);
|
---|
[6402] | 2467 | }
|
---|
[3338] | 2468 | }
|
---|
| 2469 | return rc;
|
---|
| 2470 | }
|
---|
| 2471 |
|
---|
| 2472 |
|
---|
[39540] | 2473 | #ifdef UNITTEST
|
---|
| 2474 | /** Unit test the SHFL_FN_RENAME API. Located here as a form of API
|
---|
| 2475 | * documentation. */
|
---|
| 2476 | void testRename(RTTEST hTest)
|
---|
| 2477 | {
|
---|
| 2478 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 2479 | testRenameBadParameters(hTest);
|
---|
| 2480 | /* Add tests as required... */
|
---|
| 2481 | }
|
---|
| 2482 | #endif
|
---|
[3338] | 2483 | int vbsfRename(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pSrc, SHFLSTRING *pDest, uint32_t flags)
|
---|
| 2484 | {
|
---|
| 2485 | int rc = VINF_SUCCESS;
|
---|
| 2486 |
|
---|
| 2487 | /* Validate input */
|
---|
[75336] | 2488 | if ( flags & ~(SHFL_RENAME_FILE|SHFL_RENAME_DIR|SHFL_RENAME_REPLACE_IF_EXISTS)
|
---|
[3338] | 2489 | || pSrc == 0
|
---|
| 2490 | || pDest == 0)
|
---|
| 2491 | {
|
---|
| 2492 | AssertFailed();
|
---|
| 2493 | return VERR_INVALID_PARAMETER;
|
---|
| 2494 | }
|
---|
| 2495 |
|
---|
| 2496 | /* Build a host full path for the given path
|
---|
[99802] | 2497 | * and convert utf16 to utf8 if necessary.
|
---|
[3338] | 2498 | */
|
---|
| 2499 | char *pszFullPathSrc = NULL;
|
---|
| 2500 | char *pszFullPathDest = NULL;
|
---|
| 2501 |
|
---|
[56962] | 2502 | rc = vbsfBuildFullPath(pClient, root, pSrc, pSrc->u16Size + SHFLSTRING_HEADER_SIZE, &pszFullPathSrc, NULL);
|
---|
[3338] | 2503 | if (rc != VINF_SUCCESS)
|
---|
| 2504 | return rc;
|
---|
| 2505 |
|
---|
[56962] | 2506 | rc = vbsfBuildFullPath(pClient, root, pDest, pDest->u16Size + SHFLSTRING_HEADER_SIZE, &pszFullPathDest, NULL, false, true);
|
---|
[13835] | 2507 | if (RT_SUCCESS (rc))
|
---|
[3338] | 2508 | {
|
---|
| 2509 | Log(("Rename %s to %s\n", pszFullPathSrc, pszFullPathDest));
|
---|
[6402] | 2510 |
|
---|
| 2511 | /* is the guest allowed to write to this share? */
|
---|
| 2512 | bool fWritable;
|
---|
[39594] | 2513 | rc = vbsfMappingsQueryWritable(pClient, root, &fWritable);
|
---|
[6402] | 2514 | if (RT_FAILURE(rc) || !fWritable)
|
---|
| 2515 | rc = VERR_WRITE_PROTECT;
|
---|
| 2516 |
|
---|
[39594] | 2517 | if (RT_SUCCESS(rc))
|
---|
[3338] | 2518 | {
|
---|
[75336] | 2519 | if ((flags & (SHFL_RENAME_FILE | SHFL_RENAME_DIR)) == (SHFL_RENAME_FILE | SHFL_RENAME_DIR))
|
---|
[6402] | 2520 | {
|
---|
[75336] | 2521 | rc = RTPathRename(pszFullPathSrc, pszFullPathDest,
|
---|
| 2522 | flags & SHFL_RENAME_REPLACE_IF_EXISTS ? RTPATHRENAME_FLAGS_REPLACE : 0);
|
---|
| 2523 | }
|
---|
| 2524 | else if (flags & SHFL_RENAME_FILE)
|
---|
| 2525 | {
|
---|
[39612] | 2526 | rc = RTFileMove(pszFullPathSrc, pszFullPathDest,
|
---|
[78704] | 2527 | ((flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTFILEMOVE_FLAGS_REPLACE : 0));
|
---|
[6402] | 2528 | }
|
---|
| 2529 | else
|
---|
| 2530 | {
|
---|
| 2531 | /* NT ignores the REPLACE flag and simply return and already exists error. */
|
---|
[39612] | 2532 | rc = RTDirRename(pszFullPathSrc, pszFullPathDest,
|
---|
[78704] | 2533 | ((flags & SHFL_RENAME_REPLACE_IF_EXISTS) ? RTPATHRENAME_FLAGS_REPLACE : 0));
|
---|
[6402] | 2534 | }
|
---|
[78704] | 2535 | #ifndef RT_OS_WINDOWS
|
---|
| 2536 | if ( rc == VERR_FILE_NOT_FOUND
|
---|
| 2537 | && SHFL_CLIENT_NEED_WINDOWS_ERROR_STYLE_ADJUST_ON_POSIX(pClient)
|
---|
| 2538 | && vbsfErrorStyleIsWindowsPathNotFound2(pszFullPathSrc, pszFullPathDest))
|
---|
| 2539 | rc = VERR_PATH_NOT_FOUND;
|
---|
| 2540 | #endif
|
---|
[3338] | 2541 | }
|
---|
| 2542 |
|
---|
| 2543 | /* free the path string */
|
---|
| 2544 | vbsfFreeFullPath(pszFullPathDest);
|
---|
| 2545 | }
|
---|
| 2546 | /* free the path string */
|
---|
| 2547 | vbsfFreeFullPath(pszFullPathSrc);
|
---|
| 2548 | return rc;
|
---|
| 2549 | }
|
---|
| 2550 |
|
---|
[77848] | 2551 | /**
|
---|
| 2552 | * Implements SHFL_FN_COPY_FILE (wrapping RTFileCopy).
|
---|
| 2553 | */
|
---|
| 2554 | int vbsfCopyFile(SHFLCLIENTDATA *pClient, SHFLROOT idRootSrc, PCSHFLSTRING pStrPathSrc,
|
---|
| 2555 | SHFLROOT idRootDst, PCSHFLSTRING pStrPathDst, uint32_t fFlags)
|
---|
| 2556 | {
|
---|
| 2557 | AssertPtrReturn(pClient, VERR_INVALID_PARAMETER);
|
---|
| 2558 | if (pClient->fu32Flags & SHFL_CF_UTF8)
|
---|
| 2559 | LogFunc(("pClient %p, idRootSrc %#RX32, '%.*s', idRootSrc %#RX32, '%.*s', fFlags %#x\n", pClient, idRootSrc,
|
---|
| 2560 | pStrPathSrc->u16Length, pStrPathSrc->String.ach, idRootDst, pStrPathDst->u16Length, pStrPathDst->String.ach, fFlags));
|
---|
| 2561 | else
|
---|
| 2562 | LogFunc(("pClient %p, idRootSrc %#RX32, '%.*ls', idRootSrc %#RX32, '%.*ls', fFlags %#x\n", pClient,
|
---|
| 2563 | idRootSrc, pStrPathSrc->u16Length / sizeof(RTUTF16), pStrPathSrc->String.ach,
|
---|
| 2564 | idRootDst, pStrPathDst->u16Length / sizeof(RTUTF16), pStrPathDst->String.ach, fFlags));
|
---|
| 2565 |
|
---|
| 2566 | /*
|
---|
| 2567 | * Build host paths.
|
---|
| 2568 | */
|
---|
| 2569 | char *pszPathSrc = NULL;
|
---|
| 2570 | int rc = vbsfBuildFullPath(pClient, idRootSrc, pStrPathSrc, pStrPathSrc->u16Size + SHFLSTRING_HEADER_SIZE, &pszPathSrc, NULL);
|
---|
| 2571 | if (RT_SUCCESS(rc))
|
---|
| 2572 | {
|
---|
| 2573 | char *pszPathDst = NULL;
|
---|
| 2574 | rc = vbsfBuildFullPath(pClient, idRootDst, pStrPathDst, pStrPathDst->u16Size + SHFLSTRING_HEADER_SIZE, &pszPathDst, NULL);
|
---|
| 2575 | if (RT_SUCCESS(rc))
|
---|
| 2576 | {
|
---|
| 2577 | /*
|
---|
| 2578 | * Do the job.
|
---|
| 2579 | */
|
---|
| 2580 | rc = RTFileCopy(pszPathSrc, pszPathDst);
|
---|
| 2581 |
|
---|
| 2582 | vbsfFreeFullPath(pszPathDst);
|
---|
| 2583 | }
|
---|
| 2584 | vbsfFreeFullPath(pszPathSrc);
|
---|
| 2585 | }
|
---|
| 2586 |
|
---|
| 2587 | RT_NOREF(fFlags);
|
---|
| 2588 | LogFunc(("returns %Rrc\n", rc));
|
---|
| 2589 | return rc;
|
---|
| 2590 | }
|
---|
| 2591 |
|
---|
[39540] | 2592 | #ifdef UNITTEST
|
---|
| 2593 | /** Unit test the SHFL_FN_SYMLINK API. Located here as a form of API
|
---|
| 2594 | * documentation. */
|
---|
| 2595 | void testSymlink(RTTEST hTest)
|
---|
| 2596 | {
|
---|
| 2597 | /* If the number or types of parameters are wrong the API should fail. */
|
---|
| 2598 | testSymlinkBadParameters(hTest);
|
---|
| 2599 | /* Add tests as required... */
|
---|
| 2600 | }
|
---|
| 2601 | #endif
|
---|
[35482] | 2602 | int vbsfSymlink(SHFLCLIENTDATA *pClient, SHFLROOT root, SHFLSTRING *pNewPath, SHFLSTRING *pOldPath, SHFLFSOBJINFO *pInfo)
|
---|
[33409] | 2603 | {
|
---|
| 2604 | int rc = VINF_SUCCESS;
|
---|
| 2605 |
|
---|
| 2606 | char *pszFullNewPath = NULL;
|
---|
[57457] | 2607 | char *pszFullOldPath = NULL;
|
---|
[33409] | 2608 |
|
---|
| 2609 | /* XXX: no support for UCS2 at the moment. */
|
---|
| 2610 | if (!BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
|
---|
| 2611 | return VERR_NOT_IMPLEMENTED;
|
---|
| 2612 |
|
---|
[39643] | 2613 | bool fSymlinksCreate;
|
---|
| 2614 | rc = vbsfMappingsQuerySymlinksCreate(pClient, root, &fSymlinksCreate);
|
---|
[39629] | 2615 | AssertRCReturn(rc, rc);
|
---|
[39643] | 2616 | if (!fSymlinksCreate)
|
---|
| 2617 | return VERR_WRITE_PROTECT; /* XXX or VERR_TOO_MANY_SYMLINKS? */
|
---|
[39629] | 2618 |
|
---|
[56962] | 2619 | rc = vbsfBuildFullPath(pClient, root, pNewPath, pNewPath->u16Size + SHFLSTRING_HEADER_SIZE, &pszFullNewPath, NULL);
|
---|
[39629] | 2620 | AssertRCReturn(rc, rc);
|
---|
[33409] | 2621 |
|
---|
[57457] | 2622 | /* Verify that the link target can be a valid host path, i.e. does not contain invalid characters. */
|
---|
[57782] | 2623 | uint32_t fu32PathFlags = 0;
|
---|
| 2624 | uint32_t fu32Options = 0;
|
---|
| 2625 | rc = vbsfPathGuestToHost(pClient, root, pOldPath, pOldPath->u16Size + SHFLSTRING_HEADER_SIZE,
|
---|
| 2626 | &pszFullOldPath, NULL, fu32Options, &fu32PathFlags);
|
---|
[57457] | 2627 | if (RT_FAILURE(rc))
|
---|
| 2628 | {
|
---|
| 2629 | vbsfFreeFullPath(pszFullNewPath);
|
---|
| 2630 | return rc;
|
---|
| 2631 | }
|
---|
| 2632 |
|
---|
[77861] | 2633 | /** @todo r=bird: We _must_ perform slash conversion on the target (what this
|
---|
| 2634 | * code calls 'pOldPath' for some peculiar reason)! */
|
---|
| 2635 |
|
---|
[39612] | 2636 | rc = RTSymlinkCreate(pszFullNewPath, (const char *)pOldPath->String.utf8,
|
---|
[39643] | 2637 | RTSYMLINKTYPE_UNKNOWN, 0);
|
---|
[39594] | 2638 | if (RT_SUCCESS(rc))
|
---|
[35482] | 2639 | {
|
---|
| 2640 | RTFSOBJINFO info;
|
---|
[77860] | 2641 | rc = RTPathQueryInfoEx(pszFullNewPath, &info, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
[35482] | 2642 | if (RT_SUCCESS(rc))
|
---|
| 2643 | vbfsCopyFsObjInfoFromIprt(pInfo, &info);
|
---|
| 2644 | }
|
---|
[33409] | 2645 |
|
---|
[57457] | 2646 | vbsfFreeFullPath(pszFullOldPath);
|
---|
[33409] | 2647 | vbsfFreeFullPath(pszFullNewPath);
|
---|
| 2648 |
|
---|
| 2649 | return rc;
|
---|
| 2650 | }
|
---|
| 2651 |
|
---|
[3338] | 2652 | /*
|
---|
| 2653 | * Clean up our mess by freeing all handles that are still valid.
|
---|
| 2654 | *
|
---|
| 2655 | */
|
---|
| 2656 | int vbsfDisconnect(SHFLCLIENTDATA *pClient)
|
---|
| 2657 | {
|
---|
[65288] | 2658 | for (int i = 0; i < SHFLHANDLE_MAX; ++i)
|
---|
[3338] | 2659 | {
|
---|
[65288] | 2660 | SHFLFILEHANDLE *pHandle = NULL;
|
---|
[39544] | 2661 | SHFLHANDLE Handle = (SHFLHANDLE)i;
|
---|
[65288] | 2662 |
|
---|
| 2663 | uint32_t type = vbsfQueryHandleType(pClient, Handle);
|
---|
| 2664 | switch (type & (SHFL_HF_TYPE_DIR | SHFL_HF_TYPE_FILE))
|
---|
[3338] | 2665 | {
|
---|
[65288] | 2666 | case SHFL_HF_TYPE_DIR:
|
---|
| 2667 | {
|
---|
| 2668 | pHandle = vbsfQueryDirHandle(pClient, Handle);
|
---|
| 2669 | break;
|
---|
| 2670 | }
|
---|
| 2671 | case SHFL_HF_TYPE_FILE:
|
---|
| 2672 | {
|
---|
| 2673 | pHandle = vbsfQueryFileHandle(pClient, Handle);
|
---|
| 2674 | break;
|
---|
| 2675 | }
|
---|
| 2676 | default:
|
---|
| 2677 | break;
|
---|
[3338] | 2678 | }
|
---|
[65288] | 2679 |
|
---|
| 2680 | if (pHandle)
|
---|
| 2681 | {
|
---|
| 2682 | LogFunc(("Opened handle 0x%08x\n", i));
|
---|
| 2683 | vbsfClose(pClient, pHandle->root, Handle);
|
---|
| 2684 | }
|
---|
[3338] | 2685 | }
|
---|
[75993] | 2686 |
|
---|
| 2687 | for (uint32_t i = 0; i < RT_ELEMENTS(pClient->acMappings); i++)
|
---|
| 2688 | if (pClient->acMappings[i])
|
---|
| 2689 | {
|
---|
| 2690 | uint16_t cMappings = pClient->acMappings[i];
|
---|
| 2691 | while (cMappings-- > 0)
|
---|
| 2692 | vbsfUnmapFolder(pClient, i);
|
---|
| 2693 | }
|
---|
| 2694 |
|
---|
[3338] | 2695 | return VINF_SUCCESS;
|
---|
| 2696 | }
|
---|
[78704] | 2697 |
|
---|