VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/nt/direnum-r3-nt.cpp@ 48248

Last change on this file since 48248 was 47535, checked in by vboxsync, 11 years ago

IPRT: Wrote native NT directory enumeration - not enabled by default. Provides ChangeTime and later file ID (inode no). Can also enumerate object directories, just for the fun of it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 24.9 KB
Line 
1/* $Id: direnum-r3-nt.cpp 47535 2013-08-05 01:54:25Z vboxsync $ */
2/** @file
3 * IPRT - Directory Enumeration, Native NT.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP RTLOGGROUP_DIR
32#include "internal-r3-nt.h"
33
34#include <iprt/dir.h>
35#include <iprt/path.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38#include <iprt/assert.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/log.h>
42#include "internal/fs.h"
43#include "internal/dir.h"
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49/** Whether to return a single record (TRUE) or multiple (FALSE)o. */
50#define RTDIR_NT_SINGLE_RECORD FALSE
51
52/** Go hard on record chaining (has slight performance impact). */
53#ifdef RT_STRICT
54# define RTDIR_NT_STRICT
55#endif
56
57
58/* ASSUMES FileID comes after ShortName and the structus are identical up to that point. */
59AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, NextEntryOffset, FILE_ID_BOTH_DIR_INFORMATION, NextEntryOffset);
60AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileIndex , FILE_ID_BOTH_DIR_INFORMATION, FileIndex );
61AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, CreationTime , FILE_ID_BOTH_DIR_INFORMATION, CreationTime );
62AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastAccessTime , FILE_ID_BOTH_DIR_INFORMATION, LastAccessTime );
63AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, LastWriteTime , FILE_ID_BOTH_DIR_INFORMATION, LastWriteTime );
64AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ChangeTime , FILE_ID_BOTH_DIR_INFORMATION, ChangeTime );
65AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EndOfFile , FILE_ID_BOTH_DIR_INFORMATION, EndOfFile );
66AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, AllocationSize , FILE_ID_BOTH_DIR_INFORMATION, AllocationSize );
67AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileAttributes , FILE_ID_BOTH_DIR_INFORMATION, FileAttributes );
68AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, FileNameLength , FILE_ID_BOTH_DIR_INFORMATION, FileNameLength );
69AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, EaSize , FILE_ID_BOTH_DIR_INFORMATION, EaSize );
70AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortNameLength, FILE_ID_BOTH_DIR_INFORMATION, ShortNameLength);
71AssertCompileMembersSameSizeAndOffset(FILE_BOTH_DIR_INFORMATION, ShortName , FILE_ID_BOTH_DIR_INFORMATION, ShortName );
72
73
74
75size_t rtDirNativeGetStructSize(const char *pszPath)
76{
77 NOREF(pszPath);
78 return sizeof(RTDIR);
79}
80
81
82int rtDirNativeOpen(PRTDIR pDir, char *pszPathBuf)
83{
84 /*
85 * Convert the filter to UTF-16.
86 */
87 int rc;
88 pDir->pNtFilterStr = NULL;
89 if ( pDir->cchFilter > 0
90 && pDir->enmFilter == RTDIRFILTER_WINNT)
91 {
92 PRTUTF16 pwszTmp;
93 rc = RTStrToUtf16(pDir->pszFilter, &pwszTmp);
94 if (RT_FAILURE(rc))
95 return rc;
96 pDir->NtFilterStr.Buffer = pwszTmp;
97 pDir->NtFilterStr.Length = pDir->NtFilterStr.MaximumLength = (uint16_t)(RTUtf16Len(pwszTmp) * sizeof(RTUTF16));
98 pDir->pNtFilterStr = &pDir->NtFilterStr;
99 }
100
101 /*
102 * Try open the directory
103 */
104#ifdef IPRT_WITH_NT_PATH_PASSTHRU
105 bool fObjDir;
106#endif
107 rc = rtNtPathOpenDir(pszPathBuf,
108 FILE_READ_DATA | SYNCHRONIZE,
109 FILE_SHARE_READ | FILE_SHARE_WRITE,
110 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
111 OBJ_CASE_INSENSITIVE,
112 &pDir->hDir,
113#ifdef IPRT_WITH_NT_PATH_PASSTHRU
114 &fObjDir
115#else
116 NULL
117#endif
118 );
119 if (RT_SUCCESS(rc))
120 {
121 /*
122 * Init data.
123 */
124 pDir->fDataUnread = false; /* spelling it out */
125#ifdef IPRT_WITH_NT_PATH_PASSTHRU
126 if (fObjDir)
127 pDir->enmInfoClass = FileMaximumInformation; /* object directory. */
128#endif
129 }
130 return rc;
131}
132
133
134RTDECL(int) RTDirClose(PRTDIR pDir)
135{
136 /*
137 * Validate input.
138 */
139 if (!pDir)
140 return VERR_INVALID_PARAMETER;
141 if (pDir->u32Magic != RTDIR_MAGIC)
142 {
143 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
144 return VERR_INVALID_PARAMETER;
145 }
146
147 /*
148 * Close the handle.
149 */
150 pDir->u32Magic = ~RTDIR_MAGIC;
151 if (pDir->hDir != MY_INVALID_HANDLE_VALUE)
152 {
153 int rc = rtNtPathClose(pDir->hDir);
154 AssertRC(rc);
155 pDir->hDir = MY_INVALID_HANDLE_VALUE;
156 }
157 RTStrFree(pDir->pszName);
158 pDir->pszName = NULL;
159 RTUtf16Free(pDir->NtFilterStr.Buffer);
160 pDir->NtFilterStr.Buffer = NULL;
161 RTMemFree(pDir->pabBuffer);
162 pDir->pabBuffer = NULL;
163 RTMemFree(pDir);
164
165 return VINF_SUCCESS;
166}
167
168
169/**
170 * Checks the validity of the current record.
171 *
172 * @returns IPRT status code
173 * @param pThis The directory instance data.
174 */
175static int rtDirNtCheckRecord(PRTDIR pThis)
176{
177#ifdef RTDIR_NT_STRICT
178# ifdef IPRT_WITH_NT_PATH_PASSTHRU
179 if (pThis->enmInfoClass != FileMaximumInformation)
180# endif
181 {
182 uintptr_t uEndAddr;
183 if (pThis->enmInfoClass == FileIdBothDirectoryInformation)
184 uEndAddr = (uintptr_t)&pThis->uCurData.pBothId->FileName[0];
185 else
186 uEndAddr = (uintptr_t)&pThis->uCurData.pBoth->FileName[0];
187 AssertReturn(uEndAddr < (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE);
188
189 AssertReturn(pThis->uCurData.pBoth->FileNameLength < _64K, VERR_FILENAME_TOO_LONG);
190 AssertReturn((pThis->uCurData.pBoth->FileNameLength & 1) == 0, VERR_IO_GEN_FAILURE);
191
192 uEndAddr += pThis->uCurData.pBoth->FileNameLength;
193 AssertReturn(uEndAddr <= (uintptr_t)&pThis->pabBuffer[pThis->cbBuffer], VERR_IO_GEN_FAILURE);
194
195 AssertReturn((unsigned)pThis->uCurData.pBoth->ShortNameLength <= sizeof(pThis->uCurData.pBoth->ShortName),
196 VERR_IO_GEN_FAILURE);
197 }
198#endif
199
200 return VINF_SUCCESS;
201}
202
203
204/**
205 * Advances the buffer pointer.
206 *
207 * @param pThis The directory instance data.
208 */
209static int rtDirNtAdvanceBuffer(PRTDIR pThis)
210{
211 int rc;
212
213#ifdef IPRT_WITH_NT_PATH_PASSTHRU
214 if (pThis->enmInfoClass == FileMaximumInformation)
215 {
216 pThis->uCurData.pObjDir++;
217 pThis->fDataUnread = pThis->uCurData.pObjDir->Name.Length != 0;
218 return VINF_SUCCESS;
219 }
220#endif
221
222 pThis->fDataUnread = false;
223
224 uint32_t const offNext = pThis->uCurData.pBoth->NextEntryOffset;
225 if (offNext == 0)
226 return VINF_SUCCESS;
227
228#ifdef RTDIR_NT_STRICT
229 /* Make sure the next-record offset is beyond the current record. */
230 size_t cbRec;
231 if (pThis->enmInfoClass == FileIdBothDirectoryInformation)
232 cbRec = RT_UOFFSETOF(FILE_ID_BOTH_DIR_INFORMATION, FileName);
233 else
234 cbRec = RT_UOFFSETOF(FILE_BOTH_DIR_INFORMATION, FileName);
235 cbRec += pThis->uCurData.pBoth->FileNameLength;
236 AssertReturn(offNext >= cbRec, VERR_IO_GEN_FAILURE);
237#endif
238 pThis->uCurData.u += offNext;
239
240 rc = rtDirNtCheckRecord(pThis);
241 pThis->fDataUnread = RT_SUCCESS(rc);
242 return rc;
243}
244
245
246/**
247 * Fetches more data from the file system.
248 *
249 * @returns IPRT status code
250 * @param pThis The directory instance data.
251 */
252static int rtDirNtFetchMore(PRTDIR pThis)
253{
254 Assert(!pThis->fDataUnread);
255
256 /*
257 * Allocate the buffer the first time around.
258 * We do this in lazy fashion as some users of RTDirOpen will not actually
259 * list any files, just open it for various reasons.
260 */
261 bool fFirst = false;
262 if (!pThis->pabBuffer)
263 {
264 fFirst = false;
265 pThis->cbBufferAlloc = _256K;
266 pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
267 if (!pThis->pabBuffer)
268 {
269 do
270 {
271 pThis->cbBufferAlloc /= 4;
272 pThis->pabBuffer = (uint8_t *)RTMemAlloc(pThis->cbBufferAlloc);
273 } while (pThis->pabBuffer == NULL && pThis->cbBufferAlloc > _4K);
274 if (!pThis->pabBuffer)
275 return VERR_NO_MEMORY;
276 }
277 }
278
279 /*
280 * Read more.
281 */
282 NTSTATUS rcNt;
283 IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
284 if (pThis->enmInfoClass != (FILE_INFORMATION_CLASS)0)
285 {
286#ifdef IPRT_WITH_NT_PATH_PASSTHRU
287 if (pThis->enmInfoClass == FileMaximumInformation)
288 {
289 Ios.Information = 0;
290 Ios.Status = rcNt = NtQueryDirectoryObject(pThis->hDir,
291 pThis->pabBuffer,
292 pThis->cbBufferAlloc,
293 RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
294 FALSE /*RestartScan*/,
295 &pThis->uObjDirCtx,
296 (PULONG)&Ios.Information);
297 }
298 else
299#endif
300 rcNt = NtQueryDirectoryFile(pThis->hDir,
301 NULL /* Event */,
302 NULL /* ApcRoutine */,
303 NULL /* ApcContext */,
304 &Ios,
305 pThis->pabBuffer,
306 pThis->cbBufferAlloc,
307 pThis->enmInfoClass,
308 RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
309 pThis->pNtFilterStr,
310 FALSE /*RestartScan */);
311 }
312 else
313 {
314 /*
315 * The first time around we have figure which info class we can use.
316 * We prefer one which gives us file IDs, but we'll settle for less.
317 */
318 pThis->enmInfoClass = FileIdBothDirectoryInformation;
319 rcNt = NtQueryDirectoryFile(pThis->hDir,
320 NULL /* Event */,
321 NULL /* ApcRoutine */,
322 NULL /* ApcContext */,
323 &Ios,
324 pThis->pabBuffer,
325 pThis->cbBufferAlloc,
326 pThis->enmInfoClass,
327 RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
328 pThis->pNtFilterStr,
329 FALSE /*RestartScan */);
330 if (!NT_SUCCESS(rcNt))
331 {
332 pThis->enmInfoClass = FileBothDirectoryInformation;
333 rcNt = NtQueryDirectoryFile(pThis->hDir,
334 NULL /* Event */,
335 NULL /* ApcRoutine */,
336 NULL /* ApcContext */,
337 &Ios,
338 pThis->pabBuffer,
339 pThis->cbBufferAlloc,
340 pThis->enmInfoClass,
341 RTDIR_NT_SINGLE_RECORD /*ReturnSingleEntry */,
342 pThis->pNtFilterStr,
343 FALSE /*RestartScan */);
344 }
345 }
346 if (!NT_SUCCESS(rcNt))
347 {
348 if (rcNt == STATUS_NO_MORE_FILES || rcNt == STATUS_NO_MORE_ENTRIES)
349 return VERR_NO_MORE_FILES;
350 return RTErrConvertFromNtStatus(rcNt);
351 }
352 Assert(Ios.Information > sizeof(*pThis->uCurData.pBoth));
353
354 /*
355 * Set up the data members.
356 */
357 pThis->uCurData.u = (uintptr_t)pThis->pabBuffer;
358 pThis->cbBuffer = Ios.Information;
359
360 int rc = rtDirNtCheckRecord(pThis);
361 pThis->fDataUnread = RT_SUCCESS(rc);
362
363 return rc;
364}
365
366
367/**
368 * Converts the name from UTF-16 to UTF-8.
369 *
370 * Fortunately, the names are relative to the directory, so we won't have to do
371 * any sweaty path style coversion. :-)
372 *
373 * @returns IPRT status code
374 * @param pThis The directory instance data.
375 * @param cbName The file name length in bytes.
376 * @param pwsName The file name, not terminated.
377 */
378static int rtDirNtConvertName(PRTDIR pThis, uint32_t cbName, PCRTUTF16 pwsName)
379{
380 int rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName);
381 if (RT_SUCCESS(rc))
382 {
383 if (!pThis->cbNameAlloc)
384 pThis->cbNameAlloc = pThis->cchName + 1;
385 }
386 else if (rc == VERR_BUFFER_OVERFLOW)
387 {
388 RTStrFree(pThis->pszName);
389 pThis->pszName = NULL;
390 pThis->cbNameAlloc = 0;
391
392 rc = RTUtf16ToUtf8Ex(pwsName, cbName / 2, &pThis->pszName, pThis->cbNameAlloc, &pThis->cchName);
393 if (RT_SUCCESS(rc))
394 pThis->cbNameAlloc = pThis->cchName + 1;
395 }
396 Assert(RT_SUCCESS(rc) ? pThis->pszName != NULL : pThis->pszName == NULL);
397 return rc;
398}
399
400
401/**
402 * Converts the name of the current record.
403 *
404 * @returns IPRT status code.
405 * @param pThis The directory instance data.
406 */
407static int rtDirNtConvertCurName(PRTDIR pThis)
408{
409 switch (pThis->enmInfoClass)
410 {
411 case FileIdBothDirectoryInformation:
412 return rtDirNtConvertName(pThis, pThis->uCurData.pBothId->FileNameLength, pThis->uCurData.pBothId->FileName);
413 case FileBothDirectoryInformation:
414 return rtDirNtConvertName(pThis, pThis->uCurData.pBoth->FileNameLength, pThis->uCurData.pBoth->FileName);
415#ifdef IPRT_WITH_NT_PATH_PASSTHRU
416 case FileMaximumInformation:
417 return rtDirNtConvertName(pThis, pThis->uCurData.pObjDir->Name.Length, pThis->uCurData.pObjDir->Name.Buffer);
418#endif
419
420 default:
421 AssertFailedReturn(VERR_INTERNAL_ERROR_3);
422 }
423}
424
425
426RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
427{
428 int rc;
429
430 /*
431 * Validate input.
432 */
433 AssertPtrReturn(pDir, VERR_INVALID_POINTER);
434 AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
435 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
436 size_t cbDirEntry = sizeof(*pDirEntry);
437 if (pcbDirEntry)
438 {
439 cbDirEntry = *pcbDirEntry;
440 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]),
441 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])),
442 VERR_INVALID_PARAMETER);
443 }
444
445 /*
446 * Fetch data?
447 */
448 if (!pDir->fDataUnread)
449 {
450 rc = rtDirNtFetchMore(pDir);
451 if (RT_FAILURE(rc))
452 return rc;
453 }
454
455 /*
456 * Convert the filename to UTF-8.
457 */
458 rc = rtDirNtConvertCurName(pDir);
459 if (RT_FAILURE(rc))
460 return rc;
461
462 /*
463 * Check if we've got enough space to return the data.
464 */
465 const char *pszName = pDir->pszName;
466 const size_t cchName = pDir->cchName;
467 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
468 if (pcbDirEntry)
469 *pcbDirEntry = cbRequired;
470 if (cbRequired > cbDirEntry)
471 return VERR_BUFFER_OVERFLOW;
472
473 /*
474 * Setup the returned data.
475 */
476 pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName);
477 memcpy(pDirEntry->szName, pszName, cchName + 1);
478
479 pDirEntry->INodeId = pDir->enmInfoClass == FileIdBothDirectoryInformation
480 ? pDir->uCurData.pBothId->FileId.QuadPart : 0;
481
482#ifdef IPRT_WITH_NT_PATH_PASSTHRU
483 if (pDir->enmInfoClass != FileMaximumInformation)
484#endif
485 {
486 switch ( pDir->uCurData.pBoth->FileAttributes
487 & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
488 {
489 default:
490 AssertFailed();
491 case 0:
492 pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
493 break;
494
495 case FILE_ATTRIBUTE_DIRECTORY:
496 pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
497 break;
498
499 case FILE_ATTRIBUTE_REPARSE_POINT:
500 case FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY:
501 pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
502 break;
503 }
504 }
505#ifdef IPRT_WITH_NT_PATH_PASSTHRU
506 else
507 {
508 pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN;
509 if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
510 RT_STR_TUPLE("Directory")))
511 pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
512 else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
513 RT_STR_TUPLE("SymbolicLink")))
514 pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
515 }
516#endif
517
518 return rtDirNtAdvanceBuffer(pDir);
519}
520
521
522RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
523 RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
524{
525 int rc;
526
527 /*
528 * Validate input.
529 */
530 AssertPtrReturn(pDir, VERR_INVALID_POINTER);
531 AssertReturn(pDir->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
532 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
533
534 AssertReturn(enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
535 VERR_INVALID_PARAMETER);
536 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
537
538 size_t cbDirEntry = sizeof(*pDirEntry);
539 if (pcbDirEntry)
540 {
541 cbDirEntry = *pcbDirEntry;
542 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
543 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
544 VERR_INVALID_PARAMETER);
545 }
546
547 /*
548 * Fetch data?
549 */
550 if (!pDir->fDataUnread)
551 {
552 rc = rtDirNtFetchMore(pDir);
553 if (RT_FAILURE(rc))
554 return rc;
555 }
556
557 /*
558 * Convert the filename to UTF-8.
559 */
560 rc = rtDirNtConvertCurName(pDir);
561 if (RT_FAILURE(rc))
562 return rc;
563
564 /*
565 * Check if we've got enough space to return the data.
566 */
567 const char *pszName = pDir->pszName;
568 const size_t cchName = pDir->cchName;
569 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
570 if (pcbDirEntry)
571 *pcbDirEntry = cbRequired;
572 if (cbRequired > cbDirEntry)
573 return VERR_BUFFER_OVERFLOW;
574
575 /*
576 * Setup the returned data.
577 */
578 PFILE_BOTH_DIR_INFORMATION pBoth = pDir->uCurData.pBoth;
579
580 pDirEntry->cbName = (uint16_t)cchName; Assert(pDirEntry->cbName == cchName);
581 memcpy(pDirEntry->szName, pszName, cchName + 1);
582 memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
583#ifdef IPRT_WITH_NT_PATH_PASSTHRU
584 if (pDir->enmInfoClass != FileMaximumInformation)
585#endif
586 {
587 uint8_t cbShort = pBoth->ShortNameLength;
588 if (cbShort > 0)
589 {
590 AssertStmt(cbShort < sizeof(pDirEntry->wszShortName), cbShort = sizeof(pDirEntry->wszShortName) - 2);
591 memcpy(pDirEntry->wszShortName, pBoth->ShortName, cbShort);
592 pDirEntry->cwcShortName = cbShort / 2;
593 }
594 else
595 pDirEntry->cwcShortName = 0;
596
597 pDirEntry->Info.cbObject = pBoth->EndOfFile.QuadPart;
598 pDirEntry->Info.cbAllocated = pBoth->AllocationSize.QuadPart;
599
600 Assert(sizeof(uint64_t) == sizeof(pBoth->CreationTime));
601 RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, pBoth->CreationTime.QuadPart);
602 RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, pBoth->LastAccessTime.QuadPart);
603 RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, pBoth->LastWriteTime.QuadPart);
604 RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, pBoth->ChangeTime.QuadPart);
605
606 pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pBoth->FileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
607 pszName, cchName);
608 }
609#ifdef IPRT_WITH_NT_PATH_PASSTHRU
610 else
611 {
612 pDirEntry->cwcShortName = 0;
613 pDirEntry->Info.cbObject = 0;
614 pDirEntry->Info.cbAllocated = 0;
615 RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, 0);
616 RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, 0);
617 RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, 0);
618 RTTimeSpecSetNtTime(&pDirEntry->Info.ChangeTime, 0);
619
620 if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
621 RT_STR_TUPLE("Directory")))
622 pDirEntry->Info.Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY | 0777;
623 else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
624 RT_STR_TUPLE("SymbolicLink")))
625 pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_REPARSE_POINT | RTFS_TYPE_SYMLINK | 0777;
626 else if (rtNtCompWideStrAndAscii(pDir->uCurData.pObjDir->TypeName.Buffer, pDir->uCurData.pObjDir->TypeName.Length,
627 RT_STR_TUPLE("Device")))
628 pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_DEVICE | RTFS_TYPE_DEV_CHAR | 0666;
629 else
630 pDirEntry->Info.Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE | 0666;
631 }
632#endif
633
634 /*
635 * Requested attributes (we cannot provide anything actually).
636 */
637 switch (enmAdditionalAttribs)
638 {
639 case RTFSOBJATTRADD_EASIZE:
640 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
641#ifdef IPRT_WITH_NT_PATH_PASSTHRU
642 if (pDir->enmInfoClass == FileMaximumInformation)
643 pDirEntry->Info.Attr.u.EASize.cb = 0;
644 else
645#endif
646 pDirEntry->Info.Attr.u.EASize.cb = pBoth->EaSize;
647 break;
648
649 case RTFSOBJATTRADD_UNIX:
650 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
651 pDirEntry->Info.Attr.u.Unix.uid = ~0U;
652 pDirEntry->Info.Attr.u.Unix.gid = ~0U;
653 pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
654 pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
655 pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
656 pDirEntry->Info.Attr.u.Unix.fFlags = 0;
657 pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
658 pDirEntry->Info.Attr.u.Unix.Device = 0;
659 break;
660
661 case RTFSOBJATTRADD_NOTHING:
662 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
663 break;
664
665 case RTFSOBJATTRADD_UNIX_OWNER:
666 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
667 pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;
668 pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
669 break;
670
671 case RTFSOBJATTRADD_UNIX_GROUP:
672 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
673 pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;
674 pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
675 break;
676
677 default:
678 AssertMsgFailed(("Impossible!\n"));
679 return VERR_INTERNAL_ERROR;
680 }
681
682 /*
683 * Follow links if requested.
684 */
685 if ( (fFlags & RTPATH_F_FOLLOW_LINK)
686 && RTFS_IS_SYMLINK(fFlags))
687 {
688 /** @todo Symlinks: Find[First|Next]FileW will return info about
689 the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
690 }
691
692 /*
693 * Finally advance the buffer.
694 */
695 return rtDirNtAdvanceBuffer(pDir);
696}
697
Note: See TracBrowser for help on using the repository browser.

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