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