Changeset 69705 in vbox for trunk/src/VBox/Runtime/r3/nt
- Timestamp:
- Nov 15, 2017 4:42:59 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 119080
- Location:
- trunk/src/VBox/Runtime/r3/nt
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r3/nt/RTPathQueryInfo-nt.cpp
r69111 r69705 36 36 #include <iprt/time.h> 37 37 #include "internal/fs.h" 38 #include "internal/path.h" 39 40 41 /********************************************************************************************************************************* 42 * Defined Constants And Macros * 43 *********************************************************************************************************************************/ 44 /** Helper for comparing a UNICODE_STRING with a string litteral. */ 45 #define ARE_UNICODE_STRINGS_EQUAL(a_UniStr, a_wszType) \ 46 ( (a_UniStr)->Length == sizeof(a_wszType) - sizeof(RTUTF16) \ 47 && memcmp((a_UniStr)->Buffer, a_wszType, sizeof(a_wszType) - sizeof(RTUTF16)) == 0) 38 48 39 49 … … 55 65 56 66 57 RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs) 67 /** 68 * Splits up an NT path into directory and filename. 69 * 70 * @param pNtName The path to split. 71 * @param pNtParent Where to return the directory path. 72 * @param pNtFilename Where to return the filename part. 73 * @param fNoParentDirSlash Whether to make sure the directory path doesn't 74 * end with a slash (except root). 75 */ 76 static void ntPathNtSplitName(UNICODE_STRING const *pNtName, UNICODE_STRING *pNtParent, UNICODE_STRING *pNtFilename, 77 bool fNoParentDirSlash) 58 78 { 59 return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK); 79 PRTUTF16 pwszBuffer = pNtName->Buffer; 80 size_t off = pNtName->Length / sizeof(RTUTF16); 81 82 /* Skip trailing slash if present. */ 83 if ( off > 0 84 && pwszBuffer[off - 1] == '\\') 85 off--; 86 87 /* Find the slash before that. */ 88 RTUTF16 wc; 89 while ( off > 0 90 && (wc = pwszBuffer[off - 1]) != '\\' 91 && wc != '/') 92 off--; 93 if (off != 0) 94 { 95 pNtParent->Buffer = pwszBuffer; 96 pNtParent->MaximumLength = pNtParent->Length = (USHORT)(off * sizeof(RTUTF16)); 97 } 98 else 99 { 100 AssertFailed(); /* This is impossible and won't work (NT doesn't know '.' or '..'). */ 101 /** @todo query the whole path as it is possible relative. Use the buffer for 102 * temporary name storage. */ 103 pNtParent->Buffer = L"."; 104 pNtParent->Length = 1 * sizeof(RTUTF16); 105 pNtParent->MaximumLength = 2 * sizeof(RTUTF16); 106 } 107 108 pNtFilename->Buffer = &pwszBuffer[off]; 109 pNtFilename->Length = pNtName->Length - (USHORT)(off * sizeof(RTUTF16)); 110 pNtFilename->MaximumLength = pNtName->MaximumLength - (USHORT)(off * sizeof(RTUTF16)); 111 112 while ( fNoParentDirSlash 113 && pNtParent->Length > sizeof(RTUTF16) 114 && pNtParent->Buffer[pNtParent->Length / sizeof(RTUTF16) - 1] == '\\') 115 pNtParent->Length -= sizeof(RTUTF16); 60 116 } 61 117 62 #if 1 118 119 /** 120 * Deals with enmAddAttr != RTFSOBJATTRADD_UNIX. 121 * 122 * @returns IPRT status code (usually @a rc). 123 * @param rc The return code. 124 * @param pObjInfo The info to complete. 125 * @param enmAddAttr What to complete it with. Caller should fill in 126 * RTFSOBJATTRADD_UNIX. 127 */ 128 static int rtPathNtQueryInfoFillInDummyData(int rc, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr) 129 { 130 switch (enmAddAttr) 131 { 132 case RTFSOBJATTRADD_UNIX: 133 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX; 134 break; 135 136 case RTFSOBJATTRADD_NOTHING: 137 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; 138 break; 139 140 case RTFSOBJATTRADD_UNIX_OWNER: 141 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; 142 pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID; 143 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ 144 break; 145 146 case RTFSOBJATTRADD_UNIX_GROUP: 147 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; 148 pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID; 149 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; 150 break; 151 152 case RTFSOBJATTRADD_EASIZE: 153 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; 154 pObjInfo->Attr.u.EASize.cb = 0; 155 break; 156 157 default: 158 AssertMsgFailed(("Impossible!\n")); 159 rc = VERR_INTERNAL_ERROR; 160 } 161 return rc; 162 } 163 164 165 /** 166 * Deal with getting info about something that could be in a directory object. 167 * 168 * @returns IPRT status code 169 * @param pObjAttr The NT object attribute. 170 * @param pObjInfo Where to return the info. 171 * @param enmAddAttr Which extra attributes to get (/fake). 172 * @param fFlags The flags. 173 * @param pvBuf Query buffer space. 174 * @param cbBuf Size of the buffer. ASSUMES lots of space. 175 */ 176 static int rtPathNtQueryInfoInDirectoryObject(OBJECT_ATTRIBUTES *pObjAttr, PRTFSOBJINFO pObjInfo, 177 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags, 178 void *pvBuf, size_t cbBuf) 179 { 180 RT_NOREF(fFlags); 181 182 /* 183 * Special case: Root dir. 184 */ 185 if ( pObjAttr->RootDirectory == NULL 186 && pObjAttr->ObjectName->Length == sizeof(RTUTF16) 187 && pObjAttr->ObjectName->Buffer[0] == '\\') 188 { 189 pObjInfo->cbObject = 0; 190 pObjInfo->cbAllocated = 0; 191 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, 0); 192 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, 0); 193 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, 0); 194 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, 0); 195 pObjInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; 196 return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); 197 } 198 199 /* 200 * We must open and scan the parent directory object. 201 */ 202 UNICODE_STRING NtDirName; 203 UNICODE_STRING NtDirEntry; 204 ntPathNtSplitName(pObjAttr->ObjectName, &NtDirName, &NtDirEntry, true /*fNoParentDirSlash*/); 205 206 while ( NtDirEntry.Length > sizeof(RTUTF16) 207 && NtDirEntry.Buffer[NtDirEntry.Length / sizeof(RTUTF16) - 1] == '\\') 208 NtDirEntry.Length -= sizeof(RTUTF16); 209 210 pObjAttr->ObjectName = &NtDirName; 211 HANDLE hDir = RTNT_INVALID_HANDLE_VALUE; 212 NTSTATUS rcNt = NtOpenDirectoryObject(&hDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, pObjAttr); 213 if (NT_SUCCESS(rcNt)) 214 { 215 ULONG uObjDirCtx = 0; 216 for (;;) 217 { 218 ULONG cbReturned = 0; 219 rcNt = NtQueryDirectoryObject(hDir, 220 pvBuf, 221 (ULONG)cbBuf, 222 FALSE /*ReturnSingleEntry */, 223 FALSE /*RestartScan*/, 224 &uObjDirCtx, 225 &cbReturned); 226 if (!NT_SUCCESS(rcNt)) 227 break; 228 229 for (POBJECT_DIRECTORY_INFORMATION pObjDir = (POBJECT_DIRECTORY_INFORMATION)pvBuf; 230 pObjDir->Name.Length != 0; 231 pObjDir++) 232 { 233 if ( pObjDir->Name.Length == NtDirEntry.Length 234 && memcmp(pObjDir->Name.Buffer, NtDirEntry.Buffer, NtDirEntry.Length) == 0) 235 { 236 /* 237 * Find it. Fill in the info we've got and return (see similar code in direnum-r3-nt.cpp). 238 */ 239 NtClose(hDir); 240 241 pObjInfo->cbObject = 0; 242 pObjInfo->cbAllocated = 0; 243 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, 0); 244 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, 0); 245 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, 0); 246 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, 0); 247 248 if (ARE_UNICODE_STRINGS_EQUAL(&pObjDir->TypeName, L"Directory")) 249 pObjInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; 250 else if (ARE_UNICODE_STRINGS_EQUAL(&pObjDir->TypeName, L"SymbolicLink")) 251 pObjInfo->Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777; 252 else if (ARE_UNICODE_STRINGS_EQUAL(&pObjDir->TypeName, L"Device")) 253 pObjInfo->Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666; 254 else 255 pObjInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666; 256 257 pObjInfo->Attr.enmAdditional = enmAddAttr; 258 return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); 259 } 260 } 261 } 262 263 NtClose(hDir); 264 if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES || rcNt == STATUS_NO_SUCH_FILE) 265 return VERR_FILE_NOT_FOUND; 266 } 267 return RTErrConvertFromNtStatus(rcNt); 268 } 269 270 271 /** 272 * Queries information from a file or directory handle. 273 * 274 * This is shared between the RTPathQueryInfo, RTFileQueryInfo and 275 * RTDirQueryInfo code. 276 * 277 * @returns IPRT status code. 278 * @param hFile The handle to query information from. Must have 279 * the necessary privileges. 280 * @param pvBuf Pointer to a scratch buffer. 281 * @param cbBuf The size of the buffer. This must be large 282 * enough to hold a FILE_ALL_INFORMATION struct. 283 * @param pObjInfo Where to return information about the handle. 284 * @param enmAddAttr What extra info to return. 285 * @param pszPath The path if this is a file (for exe detect). 286 * @param uReparseTag The reparse tag number (0 if not applicable) for 287 * symlink detection/whatnot. 288 */ 289 DECLHIDDEN(int) rtPathNtQueryInfoFromHandle(HANDLE hFile, void *pvBuf, size_t cbBuf, PRTFSOBJINFO pObjInfo, 290 RTFSOBJATTRADD enmAddAttr, const char *pszPath, ULONG uReparseTag) 291 { 292 Assert(cbBuf >= sizeof(FILE_ALL_INFORMATION)); 293 294 /** @todo Try optimize this for when RTFSOBJATTRADD_UNIX isn't set? */ 295 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; 296 NTSTATUS rcNt = NtQueryInformationFile(hFile, &Ios, pvBuf, sizeof(FILE_ALL_INFORMATION), FileAllInformation); 297 if ( NT_SUCCESS(rcNt) 298 || rcNt == STATUS_BUFFER_OVERFLOW) 299 { 300 FILE_ALL_INFORMATION *pAllInfo = (FILE_ALL_INFORMATION *)pvBuf; 301 pObjInfo->cbObject = pAllInfo->StandardInformation.EndOfFile.QuadPart; 302 pObjInfo->cbAllocated = pAllInfo->StandardInformation.AllocationSize.QuadPart; 303 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, pAllInfo->BasicInformation.CreationTime.QuadPart); 304 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, pAllInfo->BasicInformation.LastAccessTime.QuadPart); 305 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, pAllInfo->BasicInformation.LastWriteTime.QuadPart); 306 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, pAllInfo->BasicInformation.ChangeTime.QuadPart); 307 pObjInfo->Attr.fMode = rtFsModeFromDos( (pAllInfo->BasicInformation.FileAttributes << RTFS_DOS_SHIFT) 308 & RTFS_DOS_MASK_NT, 309 pszPath, pszPath ? strlen(pszPath) : 0, uReparseTag); 310 pObjInfo->Attr.enmAdditional = enmAddAttr; 311 if (enmAddAttr == RTFSOBJATTRADD_UNIX) 312 { 313 pObjInfo->Attr.u.Unix.uid = ~0U; 314 pObjInfo->Attr.u.Unix.gid = ~0U; 315 pObjInfo->Attr.u.Unix.cHardlinks = RT_MAX(1, pAllInfo->StandardInformation.NumberOfLinks); 316 pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /* below */ 317 pObjInfo->Attr.u.Unix.INodeId = pAllInfo->InternalInformation.IndexNumber.QuadPart; 318 pObjInfo->Attr.u.Unix.fFlags = 0; 319 pObjInfo->Attr.u.Unix.GenerationId = 0; 320 pObjInfo->Attr.u.Unix.Device = 0; 321 322 /* Get the serial number. */ 323 rcNt = NtQueryVolumeInformationFile(hFile, &Ios, pvBuf, (ULONG)RT_MIN(cbBuf, _2K), FileFsVolumeInformation); 324 if (NT_SUCCESS(rcNt) || rcNt == STATUS_BUFFER_OVERFLOW) 325 { 326 FILE_FS_VOLUME_INFORMATION *pVolInfo = (FILE_FS_VOLUME_INFORMATION *)pvBuf; 327 pObjInfo->Attr.u.Unix.INodeIdDevice = pVolInfo->VolumeSerialNumber; 328 } 329 } 330 331 return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); 332 } 333 return RTErrConvertFromNtStatus(rcNt); 334 } 335 336 337 /** 338 * Worker for RTPathQueryInfoEx and RTDirRelPathQueryInfo. 339 * 340 * @returns IPRT status code. 341 * @param hRootDir The root directory that pNtName is relative to. 342 * @param pNtName The NT path which we want to query info for. 343 * @param pObjInfo Where to return the info. 344 * @param enmAddAttr What additional info to get/fake. 345 * @param fFlags Query flags (RTPATH_F_XXX). 346 * @param pszPath The path for detecting executables and such. 347 * Pass empty string if not applicable/available. 348 */ 349 DECLHIDDEN(int) rtPathNtQueryInfoWorker(HANDLE hRootDir, UNICODE_STRING *pNtName, PRTFSOBJINFO pObjInfo, 350 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags, const char *pszPath) 351 { 352 /* 353 * There are a three different ways of doing this: 354 * 1. Use NtQueryFullAttributesFile to the get basic file info. 355 * 2. Open whatever the path points to and use NtQueryInformationFile. 356 * 3. Open the parent directory and use NtQueryDirectoryFile like RTDirReadEx. 357 * 358 * The first two options may fail with sharing violations or access denied, 359 * in which case we must use the last one as fallback. 360 */ 361 HANDLE hFile = RTNT_INVALID_HANDLE_VALUE; 362 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; 363 NTSTATUS rcNt; 364 OBJECT_ATTRIBUTES ObjAttr; 365 union 366 { 367 FILE_NETWORK_OPEN_INFORMATION NetOpenInfo; 368 FILE_ALL_INFORMATION AllInfo; 369 FILE_FS_VOLUME_INFORMATION VolInfo; 370 FILE_BOTH_DIR_INFORMATION Both; 371 FILE_ID_BOTH_DIR_INFORMATION BothId; 372 uint8_t abPadding[sizeof(FILE_ID_BOTH_DIR_INFORMATION) + RTPATH_MAX * sizeof(wchar_t)]; 373 } uBuf; 374 375 /* 376 * We can only use the first option if no additional UNIX attribs are 377 * requested and it isn't a symbolic link. NT directory object 378 */ 379 int rc = VINF_TRY_AGAIN; 380 if (enmAddAttr != RTFSOBJATTRADD_UNIX) 381 { 382 InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); 383 rcNt = NtQueryFullAttributesFile(&ObjAttr, &uBuf.NetOpenInfo); 384 if (NT_SUCCESS(rcNt)) 385 { 386 if (!(uBuf.NetOpenInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) 387 { 388 pObjInfo->cbObject = uBuf.NetOpenInfo.EndOfFile.QuadPart; 389 pObjInfo->cbAllocated = uBuf.NetOpenInfo.AllocationSize.QuadPart; 390 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.NetOpenInfo.CreationTime.QuadPart); 391 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.NetOpenInfo.LastAccessTime.QuadPart); 392 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.NetOpenInfo.LastWriteTime.QuadPart); 393 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.NetOpenInfo.ChangeTime.QuadPart); 394 pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.NetOpenInfo.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, 395 pszPath, strlen(pszPath), 0 /*uReparseTag*/); 396 pObjInfo->Attr.enmAdditional = enmAddAttr; 397 398 return rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); 399 } 400 } 401 else if ( rcNt == STATUS_OBJECT_TYPE_MISMATCH 402 || rcNt == STATUS_OBJECT_NAME_INVALID 403 || rcNt == STATUS_INVALID_PARAMETER) 404 { 405 rc = rtPathNtQueryInfoInDirectoryObject(&ObjAttr, pObjInfo, enmAddAttr, fFlags, &uBuf, sizeof(uBuf)); 406 if (RT_SUCCESS(rc)) 407 return rc; 408 rc = RTErrConvertFromNtStatus(rcNt); 409 } 410 else if ( rcNt != STATUS_ACCESS_DENIED 411 && rcNt != STATUS_SHARING_VIOLATION) 412 rc = RTErrConvertFromNtStatus(rcNt); 413 else 414 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 415 } 416 417 /* 418 * Try the 2nd option. We might have to redo this if not following symbolic 419 * links and the reparse point isn't a symbolic link but a mount point or similar. 420 * We want to return information about the mounted root directory if we can, not 421 * the directory in which it was mounted. 422 */ 423 if (rc == VINF_TRY_AGAIN) 424 { 425 InitializeObjectAttributes(&ObjAttr, pNtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); 426 rcNt = NtCreateFile(&hFile, 427 FILE_READ_ATTRIBUTES | SYNCHRONIZE, 428 &ObjAttr, 429 &Ios, 430 NULL /*pcbFile*/, 431 FILE_ATTRIBUTE_NORMAL, 432 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 433 FILE_OPEN, 434 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT 435 | (fFlags & RTPATH_F_FOLLOW_LINK ? 0 : FILE_OPEN_REPARSE_POINT), 436 NULL /*pvEaBuffer*/, 437 0 /*cbEa*/); 438 if (NT_SUCCESS(rcNt)) 439 { 440 /* Query tag information first in order to try re-open non-symlink reparse points. */ 441 FILE_ATTRIBUTE_TAG_INFORMATION TagInfo; 442 rcNt = NtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), FileAttributeTagInformation); 443 if (!NT_SUCCESS(rcNt)) 444 TagInfo.FileAttributes = TagInfo.ReparseTag = 0; 445 if ( !(TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) 446 || TagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK 447 || (fFlags & RTPATH_F_FOLLOW_LINK)) 448 { /* likely */ } 449 else 450 { 451 /* Reparse point that isn't a symbolic link, try follow the reparsing. */ 452 HANDLE hFile2; 453 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 454 rcNt = NtCreateFile(&hFile2, 455 FILE_READ_ATTRIBUTES | SYNCHRONIZE, 456 &ObjAttr, 457 &Ios, 458 NULL /*pcbFile*/, 459 FILE_ATTRIBUTE_NORMAL, 460 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 461 FILE_OPEN, 462 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 463 NULL /*pvEaBuffer*/, 464 0 /*cbEa*/); 465 if (NT_SUCCESS(rcNt)) 466 { 467 NtClose(hFile); 468 hFile = hFile2; 469 TagInfo.FileAttributes = TagInfo.ReparseTag = 0; 470 } 471 } 472 473 /* 474 * Get the information we need and convert it. 475 */ 476 rc = rtPathNtQueryInfoFromHandle(hFile, &uBuf, sizeof(uBuf), pObjInfo, enmAddAttr, pszPath, TagInfo.ReparseTag); 477 NtClose(hFile); 478 if (RT_SUCCESS(rc)) 479 return rc; 480 481 if (RT_FAILURE(rc)) 482 rc = VERR_TRY_AGAIN; 483 } 484 else if ( rcNt != STATUS_ACCESS_DENIED 485 && rcNt != STATUS_SHARING_VIOLATION) 486 rc = RTErrConvertFromNtStatus(rcNt); 487 else 488 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 489 } 490 491 /* 492 * Try the 3rd option if none of the other worked. 493 * If none of the above worked, try open the directory and enumerate 494 * the file we're after. This 495 */ 496 if (rc == VINF_TRY_AGAIN) 497 { 498 /* Split up the name into parent directory path and filename. */ 499 UNICODE_STRING NtDirName; 500 UNICODE_STRING NtFilter; 501 ntPathNtSplitName(pNtName, &NtDirName, &NtFilter, false /*fNoParentDirSlash*/); 502 503 /* Try open the directory. */ 504 InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); 505 rcNt = NtCreateFile(&hFile, 506 FILE_LIST_DIRECTORY | SYNCHRONIZE, 507 &ObjAttr, 508 &Ios, 509 NULL /*pcbFile*/, 510 FILE_ATTRIBUTE_NORMAL, 511 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 512 FILE_OPEN, 513 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 514 NULL /*pvEaBuffer*/, 515 0 /*cbEa*/); 516 if (NT_SUCCESS(rcNt)) 517 { 518 FILE_INFORMATION_CLASS enmInfoClass; 519 if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */) 520 enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */ 521 else 522 enmInfoClass = FileBothDirectoryInformation; 523 rcNt = NtQueryDirectoryFile(hFile, 524 NULL /* Event */, 525 NULL /* ApcRoutine */, 526 NULL /* ApcContext */, 527 &Ios, 528 &uBuf, 529 RT_MIN(sizeof(uBuf), 0xfff0), 530 enmInfoClass, 531 TRUE /*ReturnSingleEntry */, 532 &NtFilter, 533 FALSE /*RestartScan */); 534 if (NT_SUCCESS(rcNt)) 535 { 536 pObjInfo->cbObject = uBuf.Both.EndOfFile.QuadPart; 537 pObjInfo->cbAllocated = uBuf.Both.AllocationSize.QuadPart; 538 539 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.Both.CreationTime.QuadPart); 540 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.Both.LastAccessTime.QuadPart); 541 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.Both.LastWriteTime.QuadPart); 542 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.Both.ChangeTime.QuadPart); 543 544 pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.Both.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, 545 pszPath, strlen(pszPath), uBuf.Both.EaSize); 546 547 pObjInfo->Attr.enmAdditional = enmAddAttr; 548 if (enmAddAttr == RTFSOBJATTRADD_UNIX) 549 { 550 pObjInfo->Attr.u.Unix.uid = ~0U; 551 pObjInfo->Attr.u.Unix.gid = ~0U; 552 pObjInfo->Attr.u.Unix.cHardlinks = 1; 553 pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /* below */ 554 pObjInfo->Attr.u.Unix.INodeId = enmInfoClass == FileIdBothDirectoryInformation 555 ? uBuf.BothId.FileId.QuadPart : 0; 556 pObjInfo->Attr.u.Unix.fFlags = 0; 557 pObjInfo->Attr.u.Unix.GenerationId = 0; 558 pObjInfo->Attr.u.Unix.Device = 0; 559 560 /* Get the serial number. */ 561 rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &uBuf, RT_MIN(sizeof(uBuf), _2K), 562 FileFsVolumeInformation); 563 if (NT_SUCCESS(rcNt)) 564 pObjInfo->Attr.u.Unix.INodeIdDevice = uBuf.VolInfo.VolumeSerialNumber; 565 } 566 567 rc = rtPathNtQueryInfoFillInDummyData(VINF_SUCCESS, pObjInfo, enmAddAttr); 568 } 569 else 570 rc = RTErrConvertFromNtStatus(rcNt); 571 572 NtClose(hFile); 573 } 574 else 575 rc = RTErrConvertFromNtStatus(rcNt); 576 } 577 578 return rc; 579 } 580 581 63 582 RTR3DECL(int) RTPathQueryInfoEx(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags) 64 583 { … … 77 596 78 597 /* 79 * Convert the input path .598 * Convert the input path and call common worker. 80 599 */ 81 600 HANDLE hRootDir; … … 84 603 if (RT_SUCCESS(rc)) 85 604 { 86 /* 87 * There are a three different ways of doing this: 88 * 1. Use NtQueryFullAttributesFile to the get basic file info. 89 * 2. Open whatever the path points to and use NtQueryInformationFile. 90 * 3. Open the parent directory and use NtQueryDirectoryFile like RTDirReadEx. 91 * 92 * The first two options may fail with sharing violations or access denied, 93 * in which case we must use the last one as fallback. 94 */ 95 HANDLE hFile = RTNT_INVALID_HANDLE_VALUE; 96 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER; 97 NTSTATUS rcNt; 98 OBJECT_ATTRIBUTES ObjAttr; 99 union 100 { 101 FILE_NETWORK_OPEN_INFORMATION NetOpenInfo; 102 FILE_ALL_INFORMATION AllInfo; 103 FILE_FS_VOLUME_INFORMATION VolInfo; 104 FILE_BOTH_DIR_INFORMATION Both; 105 FILE_ID_BOTH_DIR_INFORMATION BothId; 106 uint8_t abPadding[sizeof(FILE_ID_BOTH_DIR_INFORMATION) + RTPATH_MAX * sizeof(wchar_t)]; 107 } uBuf; 108 109 /* 110 * We can only use the first option if no additional UNIX attribs are 111 * requested and it isn't a symbolic link. 112 */ 113 rc = VINF_TRY_AGAIN; 114 if (enmAdditionalAttribs != RTFSOBJATTRADD_UNIX) 115 { 116 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); 117 rcNt = NtQueryFullAttributesFile(&ObjAttr, &uBuf.NetOpenInfo); 118 if (NT_SUCCESS(rcNt)) 119 { 120 if (!(uBuf.NetOpenInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) 121 { 122 pObjInfo->cbObject = uBuf.NetOpenInfo.EndOfFile.QuadPart; 123 pObjInfo->cbAllocated = uBuf.NetOpenInfo.AllocationSize.QuadPart; 124 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.NetOpenInfo.CreationTime.QuadPart); 125 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.NetOpenInfo.LastAccessTime.QuadPart); 126 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.NetOpenInfo.LastWriteTime.QuadPart); 127 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.NetOpenInfo.ChangeTime.QuadPart); 128 pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.NetOpenInfo.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, 129 pszPath, strlen(pszPath), 0 /*uReparseTag*/); 130 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs; 131 rc = VINF_SUCCESS; 132 } 133 } 134 else if ( rcNt != STATUS_ACCESS_DENIED 135 && rcNt != STATUS_SHARING_VIOLATION) 136 rc = RTErrConvertFromNtStatus(rcNt); 137 else 138 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 139 } 140 141 /* 142 * Try the 2nd option. We might have to redo this if not following symbolic 143 * links and the reparse point isn't a symbolic link but a mount point or similar. 144 * We want to return information about the mounted root directory if we can, not 145 * the directory in which it was mounted. 146 */ 147 if (rc == VINF_TRY_AGAIN) 148 { 149 InitializeObjectAttributes(&ObjAttr, &NtName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); 150 rcNt = NtCreateFile(&hFile, 151 FILE_READ_ATTRIBUTES | SYNCHRONIZE, 152 &ObjAttr, 153 &Ios, 154 NULL /*pcbFile*/, 155 FILE_ATTRIBUTE_NORMAL, 156 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 157 FILE_OPEN, 158 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT 159 | (fFlags & RTPATH_F_FOLLOW_LINK ? 0 : FILE_OPEN_REPARSE_POINT), 160 NULL /*pvEaBuffer*/, 161 0 /*cbEa*/); 162 if (NT_SUCCESS(rcNt)) 163 { 164 /* Query tag information first in order to try re-open non-symlink reparse points. */ 165 FILE_ATTRIBUTE_TAG_INFORMATION TagInfo; 166 rcNt = NtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), FileAttributeTagInformation); 167 if (!NT_SUCCESS(rcNt)) 168 TagInfo.FileAttributes = TagInfo.ReparseTag = 0; 169 if ( !(TagInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) 170 || TagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK 171 || (fFlags & RTPATH_F_FOLLOW_LINK)) 172 { /* likely */ } 173 else 174 { 175 /* Reparse point that isn't a symbolic link, try follow the reparsing. */ 176 HANDLE hFile2; 177 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 178 rcNt = NtCreateFile(&hFile2, 179 FILE_READ_ATTRIBUTES | SYNCHRONIZE, 180 &ObjAttr, 181 &Ios, 182 NULL /*pcbFile*/, 183 FILE_ATTRIBUTE_NORMAL, 184 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 185 FILE_OPEN, 186 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 187 NULL /*pvEaBuffer*/, 188 0 /*cbEa*/); 189 if (NT_SUCCESS(rcNt)) 190 { 191 NtClose(hFile); 192 hFile = hFile2; 193 TagInfo.FileAttributes = TagInfo.ReparseTag = 0; 194 } 195 } 196 197 /* 198 * Get the information we need and convert it. 199 */ 200 /** @todo Try optimize this for when RTFSOBJATTRADD_UNIX isn't set? */ 201 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 202 rcNt = NtQueryInformationFile(hFile, &Ios, &uBuf.AllInfo, sizeof(uBuf.AllInfo), FileAllInformation); 203 if (NT_SUCCESS(rcNt) || rcNt == STATUS_BUFFER_OVERFLOW) 204 { 205 pObjInfo->cbObject = uBuf.AllInfo.StandardInformation.EndOfFile.QuadPart; 206 pObjInfo->cbAllocated = uBuf.AllInfo.StandardInformation.AllocationSize.QuadPart; 207 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.AllInfo.BasicInformation.CreationTime.QuadPart); 208 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.AllInfo.BasicInformation.LastAccessTime.QuadPart); 209 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.AllInfo.BasicInformation.LastWriteTime.QuadPart); 210 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.AllInfo.BasicInformation.ChangeTime.QuadPart); 211 pObjInfo->Attr.fMode = rtFsModeFromDos( (uBuf.AllInfo.BasicInformation.FileAttributes << RTFS_DOS_SHIFT) 212 & RTFS_DOS_MASK_NT, 213 pszPath, strlen(pszPath), TagInfo.ReparseTag); 214 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs; 215 if (enmAdditionalAttribs == RTFSOBJATTRADD_UNIX) 216 { 217 pObjInfo->Attr.u.Unix.uid = ~0U; 218 pObjInfo->Attr.u.Unix.gid = ~0U; 219 pObjInfo->Attr.u.Unix.cHardlinks = RT_MAX(1, uBuf.AllInfo.StandardInformation.NumberOfLinks); 220 pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /* below */ 221 pObjInfo->Attr.u.Unix.INodeId = uBuf.AllInfo.InternalInformation.IndexNumber.QuadPart; 222 pObjInfo->Attr.u.Unix.fFlags = 0; 223 pObjInfo->Attr.u.Unix.GenerationId = 0; 224 pObjInfo->Attr.u.Unix.Device = 0; 225 226 /* Get the serial number. */ 227 rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &uBuf, RT_MIN(sizeof(uBuf), _2K), 228 FileFsVolumeInformation); 229 if (NT_SUCCESS(rcNt) || rcNt == STATUS_BUFFER_OVERFLOW) 230 pObjInfo->Attr.u.Unix.INodeIdDevice = uBuf.VolInfo.VolumeSerialNumber; 231 } 232 233 rc = VINF_SUCCESS; 234 } 235 236 NtClose(hFile); 237 } 238 else if ( rcNt != STATUS_ACCESS_DENIED 239 && rcNt != STATUS_SHARING_VIOLATION) 240 rc = RTErrConvertFromNtStatus(rcNt); 241 else 242 RTNT_IO_STATUS_BLOCK_REINIT(&Ios); 243 } 244 245 /* 246 * Try the 3rd option if none of the other worked. 247 * If none of the above worked, try open the directory and enumerate 248 * the file we're after. This 249 */ 250 if (rc == VINF_TRY_AGAIN) 251 { 252 /* Drop the name from NtPath. */ 253 UNICODE_STRING NtDirName = NtName; 254 size_t off = NtName.Length / sizeof(NtName.Buffer[0]); 255 wchar_t wc; 256 while ( off > 0 257 && (wc = NtName.Buffer[off - 1]) != '\\' 258 && wc != '/') 259 off--; 260 if (off != 0) 261 NtDirName.Length = (USHORT)(off * sizeof(NtName.Buffer[0])); 262 else 263 { 264 AssertFailed(); /* This is impossible and won't work (NT doesn't know '.' or '..'). */ 265 NtDirName.Buffer = L"."; 266 NtDirName.Length = sizeof(NtName.Buffer[0]); 267 NtDirName.MaximumLength = 2 * sizeof(NtName.Buffer[0]); 268 } 269 270 UNICODE_STRING NtFilter; 271 NtFilter.Buffer = &NtName.Buffer[off]; 272 NtFilter.Length = NtName.Length - (USHORT)(off * sizeof(NtName.Buffer[0])); 273 NtFilter.MaximumLength = NtName.MaximumLength - (USHORT)(off * sizeof(NtName.Buffer[0])); 274 275 /* Try open the directory. */ 276 InitializeObjectAttributes(&ObjAttr, &NtDirName, OBJ_CASE_INSENSITIVE, hRootDir, NULL); 277 rcNt = NtCreateFile(&hFile, 278 FILE_LIST_DIRECTORY | SYNCHRONIZE, 279 &ObjAttr, 280 &Ios, 281 NULL /*pcbFile*/, 282 FILE_ATTRIBUTE_NORMAL, 283 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 284 FILE_OPEN, 285 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 286 NULL /*pvEaBuffer*/, 287 0 /*cbEa*/); 288 if (NT_SUCCESS(rcNt)) 289 { 290 FILE_INFORMATION_CLASS enmInfoClass; 291 if (RT_MAKE_U64(RTNtCurrentPeb()->OSMinorVersion, RTNtCurrentPeb()->OSMajorVersion) > RT_MAKE_U64(0,5) /* > W2K */) 292 enmInfoClass = FileIdBothDirectoryInformation; /* Introduced in XP, from I can tell. */ 293 else 294 enmInfoClass = FileBothDirectoryInformation; 295 rcNt = NtQueryDirectoryFile(hFile, 296 NULL /* Event */, 297 NULL /* ApcRoutine */, 298 NULL /* ApcContext */, 299 &Ios, 300 &uBuf, 301 RT_MIN(sizeof(uBuf), 0xfff0), 302 enmInfoClass, 303 TRUE /*ReturnSingleEntry */, 304 &NtFilter, 305 FALSE /*RestartScan */); 306 if (NT_SUCCESS(rcNt)) 307 { 308 pObjInfo->cbObject = uBuf.Both.EndOfFile.QuadPart; 309 pObjInfo->cbAllocated = uBuf.Both.AllocationSize.QuadPart; 310 311 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, uBuf.Both.CreationTime.QuadPart); 312 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, uBuf.Both.LastAccessTime.QuadPart); 313 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, uBuf.Both.LastWriteTime.QuadPart); 314 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, uBuf.Both.ChangeTime.QuadPart); 315 316 pObjInfo->Attr.fMode = rtFsModeFromDos((uBuf.Both.FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT, 317 pszPath, strlen(pszPath), uBuf.Both.EaSize); 318 319 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs; 320 if (enmAdditionalAttribs == RTFSOBJATTRADD_UNIX) 321 { 322 pObjInfo->Attr.u.Unix.uid = ~0U; 323 pObjInfo->Attr.u.Unix.gid = ~0U; 324 pObjInfo->Attr.u.Unix.cHardlinks = 1; 325 pObjInfo->Attr.u.Unix.INodeIdDevice = 0; /* below */ 326 pObjInfo->Attr.u.Unix.INodeId = enmInfoClass == FileIdBothDirectoryInformation 327 ? uBuf.BothId.FileId.QuadPart : 0; 328 pObjInfo->Attr.u.Unix.fFlags = 0; 329 pObjInfo->Attr.u.Unix.GenerationId = 0; 330 pObjInfo->Attr.u.Unix.Device = 0; 331 332 /* Get the serial number. */ 333 rcNt = NtQueryVolumeInformationFile(hFile, &Ios, &uBuf, RT_MIN(sizeof(uBuf), _2K), 334 FileFsVolumeInformation); 335 if (NT_SUCCESS(rcNt)) 336 pObjInfo->Attr.u.Unix.INodeIdDevice = uBuf.VolInfo.VolumeSerialNumber; 337 } 338 339 rc = VINF_SUCCESS; 340 341 } 342 else 343 rc = RTErrConvertFromNtStatus(rcNt); 344 345 NtClose(hFile); 346 } 347 else 348 rc = RTErrConvertFromNtStatus(rcNt); 349 } 350 351 /* 352 * Fill in dummy additional attributes for the non-UNIX requests. 353 */ 354 switch (enmAdditionalAttribs) 355 { 356 case RTFSOBJATTRADD_UNIX: 357 break; 358 359 case RTFSOBJATTRADD_NOTHING: 360 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING; 361 break; 362 363 case RTFSOBJATTRADD_UNIX_OWNER: 364 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; 365 pObjInfo->Attr.u.UnixOwner.uid = ~0U; 366 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ 367 break; 368 369 case RTFSOBJATTRADD_UNIX_GROUP: 370 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; 371 pObjInfo->Attr.u.UnixGroup.gid = ~0U; 372 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; 373 break; 374 375 case RTFSOBJATTRADD_EASIZE: 376 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE; 377 pObjInfo->Attr.u.EASize.cb = 0; 378 break; 379 380 default: 381 AssertMsgFailed(("Impossible!\n")); 382 rc = VERR_INTERNAL_ERROR; 383 } 384 605 rc = rtPathNtQueryInfoWorker(hRootDir, &NtName, pObjInfo, enmAdditionalAttribs, fFlags, pszPath); 385 606 RTNtPathFree(&NtName, &hRootDir); 386 607 } 387 388 608 return rc; 389 609 } 390 #endif 391 610 611 612 RTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs) 613 { 614 return RTPathQueryInfoEx(pszPath, pObjInfo, enmAdditionalAttribs, RTPATH_F_ON_LINK); 615 } 616 -
trunk/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp
r69691 r69705 42 42 #include "internal/fs.h" 43 43 #include "internal/dir.h" 44 #include "internal/path.h" 44 45 45 46 … … 107 108 if (pvNativeRelative == NULL) 108 109 rc = RTNtPathOpenDir(pszPathBuf, 109 FILE_LIST_DIRECTORY | FILE_ TRAVERSE | SYNCHRONIZE,110 FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE, 110 111 FILE_SHARE_READ | FILE_SHARE_WRITE, 111 112 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, … … 121 122 rc = RTNtPathOpenDirEx((HANDLE)hRelativeDir, 122 123 (struct _UNICODE_STRING *)pvNativeRelative, 123 FILE_LIST_DIRECTORY | FILE_ TRAVERSE | SYNCHRONIZE,124 FILE_LIST_DIRECTORY | FILE_READ_ATTRIBUTES | FILE_TRAVERSE | SYNCHRONIZE, 124 125 FILE_SHARE_READ | FILE_SHARE_WRITE, 125 126 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT, 126 127 OBJ_CASE_INSENSITIVE, 127 128 &pDir->hDir, 128 NULL); 129 #ifdef IPRT_WITH_NT_PATH_PASSTHRU 130 &fObjDir 131 #else 132 NULL 133 #endif 134 135 ); 129 136 if (RT_SUCCESS(rc)) 130 137 { … … 759 766 case RTFSOBJATTRADD_UNIX: 760 767 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX; 761 pDirEntry->Info.Attr.u.Unix.uid = ~0U;762 pDirEntry->Info.Attr.u.Unix.gid = ~0U;768 pDirEntry->Info.Attr.u.Unix.uid = NIL_RTUID; 769 pDirEntry->Info.Attr.u.Unix.gid = NIL_RTGID; 763 770 pDirEntry->Info.Attr.u.Unix.cHardlinks = 1; 764 771 pDirEntry->Info.Attr.u.Unix.INodeIdDevice = pDir->uDirDev; … … 778 785 case RTFSOBJATTRADD_UNIX_OWNER: 779 786 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; 780 pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;787 pDirEntry->Info.Attr.u.UnixOwner.uid = NIL_RTUID; 781 788 pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ 782 789 break; … … 784 791 case RTFSOBJATTRADD_UNIX_GROUP: 785 792 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; 786 pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;793 pDirEntry->Info.Attr.u.UnixGroup.gid = NIL_RTGID; 787 794 pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0'; 788 795 break; … … 809 816 } 810 817 818 819 820 RTR3DECL(int) RTDirQueryInfo(PRTDIR pDir, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs) 821 { 822 AssertPtrReturn(pDir, VERR_INVALID_POINTER); 823 AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE); 824 AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST, 825 VERR_INVALID_PARAMETER); 826 827 if (pDir->enmInfoClass == FileMaximumInformation) 828 { 829 /* 830 * Directory object (see similar code above and rtPathNtQueryInfoInDirectoryObject). 831 */ 832 pObjInfo->cbObject = 0; 833 pObjInfo->cbAllocated = 0; 834 RTTimeSpecSetNtTime(&pObjInfo->BirthTime, 0); 835 RTTimeSpecSetNtTime(&pObjInfo->AccessTime, 0); 836 RTTimeSpecSetNtTime(&pObjInfo->ModificationTime, 0); 837 RTTimeSpecSetNtTime(&pObjInfo->ChangeTime, 0); 838 pObjInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777; 839 pObjInfo->Attr.enmAdditional = enmAdditionalAttribs; 840 switch (enmAdditionalAttribs) 841 { 842 case RTFSOBJATTRADD_NOTHING: 843 case RTFSOBJATTRADD_UNIX: 844 pObjInfo->Attr.u.Unix.uid = NIL_RTUID; 845 pObjInfo->Attr.u.Unix.gid = NIL_RTGID; 846 pObjInfo->Attr.u.Unix.cHardlinks = 1; 847 pObjInfo->Attr.u.Unix.INodeIdDevice = pDir->uDirDev; 848 pObjInfo->Attr.u.Unix.INodeId = 0; 849 pObjInfo->Attr.u.Unix.fFlags = 0; 850 pObjInfo->Attr.u.Unix.GenerationId = 0; 851 pObjInfo->Attr.u.Unix.Device = 0; 852 break; 853 854 case RTFSOBJATTRADD_EASIZE: 855 pObjInfo->Attr.u.EASize.cb = 0; 856 break; 857 858 case RTFSOBJATTRADD_UNIX_OWNER: 859 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER; 860 pObjInfo->Attr.u.UnixOwner.uid = NIL_RTUID; 861 pObjInfo->Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */ 862 break; 863 864 case RTFSOBJATTRADD_UNIX_GROUP: 865 pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP; 866 pObjInfo->Attr.u.UnixGroup.gid = NIL_RTGID; 867 pObjInfo->Attr.u.UnixGroup.szName[0] = '\0'; 868 break; 869 870 default: 871 AssertMsgFailed(("Impossible!\n")); 872 return VERR_INTERNAL_ERROR_2; 873 } 874 return VINF_SUCCESS; 875 } 876 877 /* 878 * Regular directory file. 879 */ 880 uint8_t abBuf[_2K]; 881 return rtPathNtQueryInfoFromHandle(pDir->hDir, abBuf, sizeof(abBuf), pObjInfo, enmAdditionalAttribs, "", 0); 882 } 883 -
trunk/src/VBox/Runtime/r3/nt/dirrel-r3-nt.cpp
r69694 r69705 42 42 #include "internal/file.h" 43 43 #include "internal/fs.h" 44 #include "internal/path.h" 44 45 45 46 … … 139 140 UNICODE_STRING NtName; 140 141 HANDLE hRoot = pThis->hDir; 141 rc = RTNtPathRelativeFromUtf8(&NtName, &hRoot, pszRelFilename, RTDIRREL_NT_GET_ASCENT(pThis)); 142 rc = RTNtPathRelativeFromUtf8(&NtName, &hRoot, pszRelFilename, RTDIRREL_NT_GET_ASCENT(pThis), 143 pThis->enmInfoClass == FileMaximumInformation); 142 144 if (RT_SUCCESS(rc)) 143 145 { … … 204 206 UNICODE_STRING NtName; 205 207 HANDLE hRoot = pThis->hDir; 206 int rc = RTNtPathRelativeFromUtf8(&NtName, &hRoot, pszDirAndFilter, RTDIRREL_NT_GET_ASCENT(pThis)); 208 int rc = RTNtPathRelativeFromUtf8(&NtName, &hRoot, pszDirAndFilter, RTDIRREL_NT_GET_ASCENT(pThis), 209 pThis->enmInfoClass == FileMaximumInformation); 207 210 if (RT_SUCCESS(rc)) 208 211 { … … 234 237 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath); 235 238 if (RT_SUCCESS(rc)) 239 { 240 RTAssertMsg2("DBG: RTDirRelDirCreate(%s)...\n", szPath); 236 241 rc = RTDirCreate(szPath, fMode, fCreate); 242 } 237 243 return rc; 238 244 } … … 257 263 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath); 258 264 if (RT_SUCCESS(rc)) 265 { 266 RTAssertMsg2("DBG: RTDirRelDirRemove(%s)...\n", szPath); 259 267 rc = RTDirRemove(szPath); 268 } 260 269 return rc; 261 270 } … … 272 281 273 282 274 /**275 * Query information about a file system object relative to @a hDir.276 *277 * @returns IPRT status code.278 * @retval VINF_SUCCESS if the object exists, information returned.279 * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified280 * path was not found or was not a directory.281 * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the282 * parent directory exists).283 *284 * @param hDir The directory @a pszRelPath is relative to.285 * @param pszRelPath The relative path to the file system object.286 * @param pObjInfo Object information structure to be filled on successful287 * return.288 * @param enmAddAttr Which set of additional attributes to request.289 * Use RTFSOBJATTRADD_NOTHING if this doesn't matter.290 * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.291 *292 * @sa RTPathQueryInfoEx293 */294 283 RTDECL(int) RTDirRelPathQueryInfo(PRTDIR hDir, const char *pszRelPath, PRTFSOBJINFO pObjInfo, 295 284 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags) … … 299 288 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE); 300 289 301 char szPath[RTPATH_MAX]; 302 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath); 303 if (RT_SUCCESS(rc)) 304 rc = RTPathQueryInfoEx(szPath, pObjInfo, enmAddAttr, fFlags); 290 /* 291 * Validate and convert flags. 292 */ 293 UNICODE_STRING NtName; 294 HANDLE hRoot = pThis->hDir; 295 int rc = RTNtPathRelativeFromUtf8(&NtName, &hRoot, pszRelPath, RTDIRREL_NT_GET_ASCENT(pThis), 296 pThis->enmInfoClass == FileMaximumInformation); 297 if (RT_SUCCESS(rc)) 298 { 299 rc = rtPathNtQueryInfoWorker(hRoot, &NtName, pObjInfo, enmAddAttr, fFlags, pszRelPath); 300 RTNtPathFree(&NtName, NULL); 301 } 305 302 return rc; 306 303 } … … 332 329 if (RT_SUCCESS(rc)) 333 330 { 331 RTAssertMsg2("DBG: RTDirRelPathSetMode(%s)...\n", szPath); 334 332 #ifndef RT_OS_WINDOWS 335 333 rc = RTPathSetMode(szPath, fMode); /** @todo fFlags is currently ignored. */ … … 379 377 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath); 380 378 if (RT_SUCCESS(rc)) 379 { 380 RTAssertMsg2("DBG: RTDirRelPathSetTimes(%s)...\n", szPath); 381 381 rc = RTPathSetTimesEx(szPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, fFlags); 382 } 382 383 return rc; 383 384 } … … 408 409 if (RT_SUCCESS(rc)) 409 410 { 411 RTAssertMsg2("DBG: RTDirRelPathSetOwner(%s)...\n", szPath); 410 412 #ifndef RT_OS_WINDOWS 411 413 rc = RTPathSetOwnerEx(szPath, uid, gid, fFlags); … … 454 456 rc = rtDirRelBuildFullPath(pThis, szDstPath, sizeof(szDstPath), pszDst); 455 457 if (RT_SUCCESS(rc)) 456 rc = RTPathRename(pszSrc, pszDst, fRename); 458 { 459 RTAssertMsg2("DBG: RTDirRelPathRename(%s,%s)...\n", szSrcPath, szDstPath); 460 rc = RTPathRename(szSrcPath, szDstPath, fRename); 461 } 457 462 } 458 463 return rc; … … 479 484 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath); 480 485 if (RT_SUCCESS(rc)) 486 { 487 RTAssertMsg2("DBG: RTDirRelPathUnlink(%s)...\n", szPath); 481 488 rc = RTPathUnlink(szPath, fUnlink); 489 } 482 490 return rc; 483 491 } … … 522 530 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszSymlink); 523 531 if (RT_SUCCESS(rc)) 532 { 533 RTAssertMsg2("DBG: RTDirRelSymlinkCreate(%s)...\n", szPath); 524 534 rc = RTSymlinkCreate(szPath, pszTarget, enmType, fCreate); 535 } 525 536 return rc; 526 537 } … … 554 565 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszSymlink); 555 566 if (RT_SUCCESS(rc)) 567 { 568 RTAssertMsg2("DBG: RTDirRelSymlinkRead(%s)...\n", szPath); 556 569 rc = RTSymlinkRead(szPath, pszTarget, cbTarget, fRead); 557 return rc; 558 } 559 570 } 571 return rc; 572 } 573 -
trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp
r69691 r69705 447 447 * Copy the result into the return string. 448 448 */ 449 size_t cbNeeded = cwcExtra * sizeof(RTUTF16) + p NtName->Length + sizeof(RTUTF16);449 size_t cbNeeded = cwcExtra * sizeof(RTUTF16) + pUniStrBuf->Length + sizeof(RTUTF16); 450 450 if (cbNeeded < _64K) 451 451 { … … 471 471 } 472 472 473 static int rtNtPathRelativeToAbs(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir) 474 { 475 int rc; 476 if (pNtName->Length == 0) 477 { 478 RTUtf16Free(pNtName->Buffer); 479 rc = rtNtPathFromHandle(pNtName, *phRootDir, pNtName->Length / sizeof(RTUTF16) + 2); 480 if (RT_SUCCESS(rc)) 481 { 482 *phRootDir = NULL; 483 return VINF_SUCCESS; 484 } 485 } 486 else 487 { 488 489 UNICODE_STRING RootDir; 490 size_t const cwcAppend = pNtName->Length / sizeof(RTUTF16); 491 rc = rtNtPathFromHandle(&RootDir, *phRootDir, cwcAppend + 2); 492 if (RT_SUCCESS(rc)) 493 { 494 size_t cwcRoot = RootDir.Length / sizeof(RTUTF16); 495 if (RootDir.Buffer[cwcRoot - 1] != '\\') 496 RootDir.Buffer[cwcRoot++] = '\\'; 497 memcpy(&RootDir.Buffer[cwcRoot], pNtName->Buffer, cwcAppend * sizeof(RTUTF16)); 498 RTUtf16Free(pNtName->Buffer); 499 pNtName->Length = (uint16_t)((cwcRoot + cwcAppend) * sizeof(RTUTF16)); 500 pNtName->MaximumLength = RootDir.MaximumLength; 501 pNtName->Buffer = RootDir.Buffer; 502 503 *phRootDir = NULL; 504 return VINF_SUCCESS; 505 } 506 RTUtf16Free(pNtName->Buffer); 507 } 508 pNtName->Length = 0; 509 pNtName->MaximumLength = 0; 510 pNtName->Buffer = NULL; 511 return rc; 512 } 513 473 514 474 515 /** … … 514 555 * @param pszPath The relative UTF-8 path. 515 556 * @param enmAscent How to handle ascent. 557 * @param fMustReturnAbsolute Must convert to an absolute path. This 558 * is necessary if the root dir is a NT directory 559 * object (e.g. /Devices) since they cannot parse 560 * relative paths it seems. 516 561 */ 517 562 RTDECL(int) RTNtPathRelativeFromUtf8(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath, 518 RTNTPATHRELATIVEASCENT enmAscent )563 RTNTPATHRELATIVEASCENT enmAscent, bool fMustReturnAbsolute) 519 564 { 520 565 size_t cwcMax; … … 543 588 { 544 589 default: 545 pwszDstCur = RTUtf16PutCp(pwszDst , uc);590 pwszDstCur = RTUtf16PutCp(pwszDstCur, uc); 546 591 break; 547 592 … … 566 611 pwszDstCur--; 567 612 *pwszDstCur = '\0'; 568 pNtName->Length = (uint16_t)(pwszDstCur - pwszDst); 569 return VINF_SUCCESS; 613 pNtName->Length = (uint16_t)((uintptr_t)pwszDstCur - (uintptr_t)pwszDst); 614 if (!fMustReturnAbsolute || *phRootDir == NULL) 615 return VINF_SUCCESS; 616 return rtNtPathRelativeToAbs(pNtName, phRootDir); 570 617 } 571 618 … … 595 642 { 596 643 case kRTNtPathRelativeAscent_Allow: 597 if (*phRootDir != RTNT_INVALID_HANDLE_VALUE)644 if (*phRootDir != NULL) 598 645 { 599 646 RTUtf16Free(pwszDst); … … 602 649 return rc; 603 650 604 *phRootDir = RTNT_INVALID_HANDLE_VALUE;651 *phRootDir = NULL; 605 652 pwszDst = pNtName->Buffer; 606 653 pwszDstCur = &pwszDst[pNtName->Length / sizeof(RTUTF16)]; … … 627 674 { 628 675 *pwszDstCur = '\0'; 629 pNtName->Length = (uint16_t)(pwszDstCur - pwszDst); 630 return VINF_SUCCESS; 676 pNtName->Length = (uint16_t)((uintptr_t)pwszDstCur - (uintptr_t)pwszDst); 677 if (!fMustReturnAbsolute || *phRootDir == NULL) 678 return VINF_SUCCESS; 679 return rtNtPathRelativeToAbs(pNtName, phRootDir); 631 680 } 632 681 pszPath += 2; … … 642 691 case '\0': 643 692 *pwszDstCur = '\0'; 644 pNtName->Length = (uint16_t)(pwszDstCur - pwszDst); 645 return VINF_SUCCESS; 693 pNtName->Length = (uint16_t)((uintptr_t)pwszDstCur - (uintptr_t)pwszDst); 694 if (!fMustReturnAbsolute || *phRootDir == NULL) 695 return VINF_SUCCESS; 696 return rtNtPathRelativeToAbs(pNtName, phRootDir); 646 697 } 647 698 } … … 829 880 } 830 881 882 /* 883 * Try add a slash in case this is a device object with a file system attached. 884 */ 885 if ( rcNt == STATUS_INVALID_PARAMETER 886 && pNtName->Length < _64K - 4 887 && ( pNtName->Length == 0 888 || pNtName->Buffer[pNtName->Length / sizeof(RTUTF16)] != '\\') ) 889 { 890 UNICODE_STRING NtTmp; 891 NtTmp.Length = pNtName->Length + 2; 892 NtTmp.MaximumLength = NtTmp.Length + 2; 893 NtTmp.Buffer = (PRTUTF16)RTMemTmpAlloc(NtTmp.MaximumLength); 894 if (NtTmp.Buffer) 895 { 896 memcpy(NtTmp.Buffer, pNtName->Buffer, pNtName->Length); 897 NtTmp.Buffer[pNtName->Length / sizeof(RTUTF16)] = '\\'; 898 NtTmp.Buffer[pNtName->Length / sizeof(RTUTF16) + 1] = '\0'; 899 900 hFile = RTNT_INVALID_HANDLE_VALUE; 901 Ios.Status = -1; 902 Ios.Information = 0; 903 ObjAttr.ObjectName = &NtTmp; 904 905 rcNt = NtCreateFile(&hFile, 906 fDesiredAccess, 907 &ObjAttr, 908 &Ios, 909 NULL /* AllocationSize*/, 910 FILE_ATTRIBUTE_NORMAL, 911 fShareAccess, 912 FILE_OPEN, 913 fCreateOptions, 914 NULL /*EaBuffer*/, 915 0 /*EaLength*/); 916 RTMemTmpFree(NtTmp.Buffer); 917 if (NT_SUCCESS(rcNt)) 918 { 919 if (pfObjDir) 920 *pfObjDir = false; 921 *phHandle = hFile; 922 return VINF_SUCCESS; 923 } 924 ObjAttr.ObjectName = pNtName; 925 } 926 } 927 928 /* 929 * Try open it as a directory object if it makes sense. 930 */ 831 931 if ( pfObjDir 832 && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH)) 932 && ( rcNt == STATUS_OBJECT_NAME_INVALID 933 || rcNt == STATUS_OBJECT_TYPE_MISMATCH )) 833 934 { 834 935 /* Strip trailing slash. */
Note:
See TracChangeset
for help on using the changeset viewer.