VirtualBox

source: kBuild/trunk/src/lib/nt/ntdir.c@ 2903

Last change on this file since 2903 was 2708, checked in by bird, 11 years ago

Optimized ftsfake.c for windows (similar things can be done for OS/2, if we care).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.1 KB
Line 
1/* $Id: ntdir.c 2708 2013-11-21 10:26:40Z bird $ */
2/** @file
3 * MSC + NT opendir, readdir, telldir, seekdir, and closedir.
4 */
5
6/*
7 * Copyright (c) 2005-2013 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * IN THE SOFTWARE.
26 *
27 * Alternatively, the content of this file may be used under the terms of the
28 * GPL version 2 or later, or LGPL version 2.1 or later.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <stdio.h>
36#include <errno.h>
37#include <malloc.h>
38
39#include "ntstuff.h"
40#include "nthlp.h"
41#include "ntdir.h"
42
43
44/**
45 * Internal worker for birdStatModTimeOnly.
46 */
47static BirdDir_T *birdDirOpenInternal(const char *pszPath, const char *pszFilter, int fMinimalInfo)
48{
49 HANDLE hFile = birdOpenFile(pszPath,
50 FILE_READ_DATA | SYNCHRONIZE,
51 FILE_ATTRIBUTE_NORMAL,
52 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
53 FILE_OPEN,
54 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
55 OBJ_CASE_INSENSITIVE);
56 if (hFile != INVALID_HANDLE_VALUE)
57 {
58 /*
59 * Allocate a handle.
60 */
61 BirdDir_T *pDir = (BirdDir_T *)birdMemAlloc(sizeof(*pDir));
62 if (pDir)
63 {
64 pDir->uMagic = BIRD_DIR_MAGIC;
65 pDir->pvHandle = (void *)hFile;
66 pDir->uDev = 0;
67 pDir->offPos = 0;
68 pDir->fHaveData = 0;
69 pDir->fFirst = 1;
70 pDir->iInfoClass = fMinimalInfo ? MyFileNamesInformation : MyFileIdFullDirectoryInformation;
71 pDir->offBuf = 0;
72 pDir->cbBuf = 0;
73 pDir->pabBuf = NULL;
74 return pDir;
75 }
76
77 birdCloseFile(hFile);
78 birdSetErrnoToNoMem();
79 }
80
81 return NULL;
82}
83
84
85/**
86 * Implements opendir.
87 */
88BirdDir_T *birdDirOpen(const char *pszPath)
89{
90 return birdDirOpenInternal(pszPath, NULL, 1 /*fMinimalInfo*/);
91}
92
93
94/**
95 * Alternative opendir, with extra stat() info returned by readdir().
96 */
97BirdDir_T *birdDirOpenExtraInfo(const char *pszPath)
98{
99 return birdDirOpenInternal(pszPath, NULL, 0 /*fMinimalInfo*/);
100}
101
102
103static int birdDirReadMore(BirdDir_T *pDir)
104{
105 MY_NTSTATUS rcNt;
106 MY_IO_STATUS_BLOCK Ios;
107 int fFirst;
108
109 /*
110 * Retrieve the volume serial number + creation time and create the
111 * device number the first time around. Also allocate a buffer.
112 */
113 fFirst = pDir->fFirst;
114 if (fFirst)
115 {
116 union
117 {
118 MY_FILE_FS_VOLUME_INFORMATION VolInfo;
119 unsigned char abBuf[1024];
120 } uBuf;
121
122 Ios.Information = 0;
123 Ios.u.Status = -1;
124 rcNt = g_pfnNtQueryVolumeInformationFile((HANDLE)pDir->pvHandle, &Ios, &uBuf, sizeof(uBuf), MyFileFsVolumeInformation);
125 if (MY_NT_SUCCESS(rcNt))
126 rcNt = Ios.u.Status;
127 if (MY_NT_SUCCESS(rcNt))
128 pDir->uDev = uBuf.VolInfo.VolumeSerialNumber
129 | (uBuf.VolInfo.VolumeCreationTime.QuadPart << 32);
130 else
131 pDir->uDev = 0;
132
133 /*
134 * Allocate a buffer.
135 */
136 pDir->cbBuf = 0x20000;
137 pDir->pabBuf = birdMemAlloc(pDir->cbBuf);
138 if (!pDir->pabBuf)
139 return birdSetErrnoToNoMem();
140
141 pDir->fFirst = 0;
142 }
143
144 /*
145 * Read another buffer full.
146 */
147 Ios.Information = 0;
148 Ios.u.Status = -1;
149
150 rcNt = g_pfnNtQueryDirectoryFile((HANDLE)pDir->pvHandle,
151 NULL, /* hEvent */
152 NULL, /* pfnApcComplete */
153 NULL, /* pvApcCompleteCtx */
154 &Ios,
155 pDir->pabBuf,
156 pDir->cbBuf,
157 (MY_FILE_INFORMATION_CLASS)pDir->iInfoClass,
158 FALSE, /* fReturnSingleEntry */
159 NULL, /* Filter / restart pos. */
160 FALSE); /* fRestartScan */
161 if (!MY_NT_SUCCESS(rcNt))
162 {
163 int rc;
164 if (rcNt == MY_STATUS_NO_MORE_FILES)
165 rc = 0;
166 else
167 rc = birdSetErrnoFromNt(rcNt);
168 pDir->fHaveData = 0;
169 pDir->offBuf = pDir->cbBuf;
170 return rc;
171 }
172
173 pDir->offBuf = 0;
174 pDir->fHaveData = 1;
175
176 return 0;
177}
178
179
180static int birdDirCopyNameToEntry(WCHAR const *pwcName, ULONG cbName, BirdDirEntry_T *pEntry)
181{
182 int cchOut = WideCharToMultiByte(CP_ACP, 0,
183 pwcName, cbName / sizeof(WCHAR),
184 pEntry->d_name, sizeof(pEntry->d_name) - 1,
185 NULL, NULL);
186 if (cchOut > 0)
187 {
188 pEntry->d_name[cchOut] = '\0';
189 pEntry->d_namlen = (unsigned __int16)cchOut;
190 pEntry->d_reclen = (unsigned __int16)((size_t)&pEntry->d_name[cchOut + 1] - (size_t)pEntry);
191 return 0;
192 }
193 return -1;
194}
195
196
197
198/**
199 * Implements readdir_r().
200 */
201int birdDirReadReentrant(BirdDir_T *pDir, BirdDirEntry_T *pEntry, BirdDirEntry_T **ppResult)
202{
203 int fSkipEntry;
204
205 *ppResult = NULL;
206
207 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
208 return birdSetErrnoToBadFileNo();
209
210 do
211 {
212 ULONG offNext;
213 ULONG cbMinCur;
214
215 /*
216 * Read more?
217 */
218 if (!pDir->fHaveData)
219 {
220 if (birdDirReadMore(pDir) != 0)
221 return -1;
222 if (!pDir->fHaveData)
223 return 0;
224 }
225
226 /*
227 * Convert the NT data to the unixy output structure.
228 */
229 fSkipEntry = 0;
230 switch (pDir->iInfoClass)
231 {
232 case MyFileNamesInformation:
233 {
234 MY_FILE_NAMES_INFORMATION *pInfo = (MY_FILE_NAMES_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
235 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_NAMES_INFORMATION
236 || pInfo->FileNameLength >= pDir->cbBuf
237 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_NAMES_INFORMATION > pDir->cbBuf)
238 {
239 fSkipEntry = 1;
240 pDir->fHaveData = 0;
241 continue;
242 }
243
244 memset(&pEntry->d_stat, 0, sizeof(pEntry->d_stat));
245 pEntry->d_stat.st_mode = S_IFMT;
246 pEntry->d_type = DT_UNKNOWN;
247 pEntry->d_reclen = 0;
248 pEntry->d_namlen = 0;
249 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
250 fSkipEntry = 1;
251
252 cbMinCur = MIN_SIZEOF_MY_FILE_NAMES_INFORMATION + pInfo->FileNameLength;
253 offNext = pInfo->NextEntryOffset;
254 break;
255 }
256
257 case MyFileIdFullDirectoryInformation:
258 {
259 MY_FILE_ID_FULL_DIR_INFORMATION *pInfo = (MY_FILE_ID_FULL_DIR_INFORMATION *)&pDir->pabBuf[pDir->offBuf];
260 if ( pDir->offBuf >= pDir->cbBuf - MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION
261 || pInfo->FileNameLength >= pDir->cbBuf
262 || pDir->offBuf + pInfo->FileNameLength + MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION > pDir->cbBuf)
263 {
264 fSkipEntry = 1;
265 pDir->fHaveData = 0;
266 continue;
267 }
268
269 pEntry->d_type = DT_UNKNOWN;
270 pEntry->d_reclen = 0;
271 pEntry->d_namlen = 0;
272 if (birdDirCopyNameToEntry(pInfo->FileName, pInfo->FileNameLength, pEntry) != 0)
273 fSkipEntry = 1;
274 birdStatFillFromFileIdFullDirInfo(&pEntry->d_stat, pInfo, pEntry->d_name);
275 pEntry->d_stat.st_dev = pDir->uDev;
276 switch (pEntry->d_stat.st_mode & S_IFMT)
277 {
278 case S_IFREG: pEntry->d_type = DT_REG; break;
279 case S_IFDIR: pEntry->d_type = DT_DIR; break;
280 case S_IFLNK: pEntry->d_type = DT_LNK; break;
281 case S_IFIFO: pEntry->d_type = DT_FIFO; break;
282 case S_IFCHR: pEntry->d_type = DT_CHR; break;
283 default:
284#ifndef NDEBUG
285 __debugbreak();
286#endif
287 pEntry->d_type = DT_UNKNOWN;
288 break;
289 }
290
291 cbMinCur = MIN_SIZEOF_MY_FILE_ID_FULL_DIR_INFORMATION + pInfo->FileNameLength;
292 offNext = pInfo->NextEntryOffset;
293 break;
294 }
295
296 default:
297 return birdSetErrnoToBadFileNo();
298 }
299
300 /*
301 * Advance.
302 */
303 if ( offNext >= cbMinCur
304 && offNext < pDir->cbBuf)
305 pDir->offBuf += offNext;
306 else
307 {
308 pDir->fHaveData = 0;
309 pDir->offBuf = pDir->cbBuf;
310 }
311 pDir->offPos++;
312 } while (fSkipEntry);
313
314
315 /*
316 * Successful return.
317 */
318 *ppResult = pEntry;
319 return 0;
320}
321
322
323/**
324 * Implements readdir().
325 */
326BirdDirEntry_T *birdDirRead(BirdDir_T *pDir)
327{
328 BirdDirEntry_T *pRet = NULL;
329 birdDirReadReentrant(pDir, &pDir->DirEntry, &pRet);
330 return pRet;
331}
332
333
334/**
335 * Implements telldir().
336 */
337long birdDirTell(BirdDir_T *pDir)
338{
339 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
340 return birdSetErrnoToBadFileNo();
341 return pDir->offPos;
342}
343
344
345void birdDirSeek(BirdDir_T *pDir, long offDir);
346
347
348/**
349 * Implements closedir().
350 */
351int birdDirClose(BirdDir_T *pDir)
352{
353 if (!pDir || pDir->uMagic != BIRD_DIR_MAGIC)
354 return birdSetErrnoToBadFileNo();
355
356 pDir->uMagic++;
357 birdCloseFile((HANDLE)pDir->pvHandle);
358 pDir->pvHandle = (void *)INVALID_HANDLE_VALUE;
359 birdMemFree(pDir->pabBuf);
360 pDir->pabBuf = NULL;
361 birdMemFree(pDir);
362
363 return 0;
364}
Note: See TracBrowser for help on using the repository browser.

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