VirtualBox

source: kBuild/trunk/src/lib/nt/ntstat.c@ 2703

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

NDEBUG and other adjustments.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.4 KB
Line 
1/* $Id: ntstat.c 2703 2013-11-21 00:26:35Z bird $ */
2/** @file
3 * MSC + NT stat, lstat and fstat.
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 "ntstat.h"
42
43
44#undef stat
45
46static int birdIsExecutableExtension(const char *pszExt)
47{
48 return !strcmp(pszExt, "exe")
49 || !strcmp(pszExt, "cmd")
50 || !strcmp(pszExt, "bat")
51 || !strcmp(pszExt, "vbs")
52 || !strcmp(pszExt, "com")
53 ;
54}
55
56
57static int birdIsFileExecutable(const char *pszName)
58{
59 const char *pszExt = NULL;
60 char szExt[8];
61 size_t cchExt;
62 unsigned i;
63 char ch;
64
65 /* Look for a 3 char extension. */
66 ch = *pszName++;
67 if (!ch)
68 return 0;
69
70 while ((ch = *pszName++) != '\0')
71 if (ch == '.')
72 pszExt = pszName;
73
74 if (!pszExt)
75 return 0;
76 pszExt++;
77 cchExt = pszName - pszExt;
78 if (cchExt != 3)
79 return 0;
80
81 /* Copy the extension out and lower case it. */
82 for (i = 0; i < cchExt; i++, pszExt++)
83 {
84 ch = *pszExt;
85 if (ch >= 'A' && ch <= 'Z')
86 ch += 'a' - 'A';
87 szExt[i] = ch;
88 }
89 szExt[i] = '\0';
90
91 return birdIsExecutableExtension(szExt);
92}
93
94
95static int birdIsFileExecutableW(WCHAR const *pwcName, ULONG cwcName)
96{
97 char szExt[8];
98 unsigned cchExt;
99 unsigned i;
100 WCHAR const *pwc;
101
102 /* Look for a 3 char extension. */
103 if (cwcName > 2 && pwcName[cwcName - 2] == '.')
104 return 0;
105 else if (cwcName > 3 && pwcName[cwcName - 3] == '.')
106 return 0;
107 else if (cwcName > 4 && pwcName[cwcName - 4] == '.')
108 cchExt = 3;
109 else
110 return 0;
111
112 /* Copy the extension out and lower case it. */
113 pwc = &pwcName[cwcName - cchExt];
114 for (i = 0; i < cchExt; i++, pwc++)
115 {
116 WCHAR wc = *pwc;
117 if (wc >= 'A' && wc <= 'Z')
118 wc += 'a' - 'A';
119 else if (wc > 255)
120 wc = 255;
121 szExt[i] = (char)wc;
122 }
123 szExt[i] = '\0';
124
125 return birdIsExecutableExtension(szExt);
126}
127
128
129static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
130 MY_FILE_NAME_INFORMATION *pNameInfo, __int16 *pfIsDirSymlink)
131{
132 unsigned short fMode;
133
134 /* File type. */
135 if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
136 {
137 MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
138 MY_IO_STATUS_BLOCK Ios;
139 MY_NTSTATUS rcNt;
140 Ios.Information = 0;
141 Ios.u.Status = -1;
142 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
143 if ( !MY_NT_SUCCESS(rcNt)
144 || !MY_NT_SUCCESS(Ios.u.Status)
145 || TagInfo.ReparseTag != IO_REPARSE_TAG_SYMLINK)
146 fAttribs &= ~FILE_ATTRIBUTE_REPARSE_POINT;
147 }
148
149 if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
150 {
151 *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
152 fMode = S_IFLNK;
153 }
154 else
155 {
156 *pfIsDirSymlink = 0;
157 if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
158 fMode = S_IFDIR;
159 else
160 fMode = S_IFREG;
161 }
162
163 /* Access mask. */
164 fMode |= S_IROTH | S_IRGRP | S_IRUSR;
165 if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
166 fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
167 if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
168 || (pszName
169 ? birdIsFileExecutable(pszName)
170 : birdIsFileExecutableW(pNameInfo->FileName, pNameInfo->FileNameLength)) )
171 fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
172
173 return fMode;
174}
175
176
177static void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec)
178{
179 iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS;
180 pTimeSpec->tv_sec = iNtTime / 10000000;
181 pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100;
182}
183
184
185int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
186{
187 int rc;
188 MY_NTSTATUS rcNt;
189#if 0
190 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
191 MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
192 if (pAll)
193 {
194 MY_IO_STATUS_BLOCK Ios;
195 Ios.Information = 0;
196 Ios.u.Status = -1;
197 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
198 if (MY_NT_SUCCESS(rcNt))
199 rcNt = Ios.u.Status;
200 if (MY_NT_SUCCESS(rcNt))
201 {
202 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
203 &pAll->NameInformation, &pStat->st_dirsymlink);
204 pStat->st_padding0[0] = 0;
205 pStat->st_padding0[1] = 0;
206 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
207 birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim);
208 birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim);
209 birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim);
210 birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
211 pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart;
212 pStat->st_nlink = pAll->StandardInformation.NumberOfLinks;
213 pStat->st_rdev = 0;
214 pStat->st_uid = 0;
215 pStat->st_gid = 0;
216 pStat->st_padding1[0] = 0;
217 pStat->st_padding1[1] = 0;
218 pStat->st_padding1[2] = 0;
219 pStat->st_blksize = 65536;
220 pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
221 / BIRD_STAT_BLOCK_SIZE;
222
223 /* Get the serial number, reusing the buffer from above. */
224 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
225 if (MY_NT_SUCCESS(rcNt))
226 rcNt = Ios.u.Status;
227 if (MY_NT_SUCCESS(rcNt))
228 {
229 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
230 pStat->st_dev = pVolInfo->VolumeSerialNumber
231 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
232 rc = 0;
233 }
234 else
235 {
236 pStat->st_dev = 0;
237 rc = birdSetErrnoFromNt(rcNt);
238 }
239 }
240 else
241 rc = birdSetErrnoFromNt(rcNt);
242 }
243 else
244 rc = birdSetErrnoToNoMem();
245#else
246 ULONG cbNameInfo = 0;
247 MY_FILE_NAME_INFORMATION *pNameInfo = NULL;
248 MY_FILE_STANDARD_INFORMATION StdInfo;
249 MY_FILE_BASIC_INFORMATION BasicInfo;
250 MY_FILE_INTERNAL_INFORMATION InternalInfo;
251 MY_IO_STATUS_BLOCK Ios;
252
253 Ios.Information = 0;
254 Ios.u.Status = -1;
255 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
256 if (MY_NT_SUCCESS(rcNt))
257 rcNt = Ios.u.Status;
258 if (MY_NT_SUCCESS(rcNt))
259 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
260 if (MY_NT_SUCCESS(rcNt))
261 rcNt = Ios.u.Status;
262 if (MY_NT_SUCCESS(rcNt))
263 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
264 if (MY_NT_SUCCESS(rcNt))
265 rcNt = Ios.u.Status;
266 if (MY_NT_SUCCESS(rcNt) && !pszPath)
267 {
268 cbNameInfo = 0x10020;
269 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
270 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
271 if (MY_NT_SUCCESS(rcNt))
272 rcNt = Ios.u.Status;
273 }
274
275 if (MY_NT_SUCCESS(rcNt))
276 {
277 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
278 pNameInfo, &pStat->st_dirsymlink);
279 pStat->st_padding0[0] = 0;
280 pStat->st_padding0[1] = 0;
281 pStat->st_size = StdInfo.EndOfFile.QuadPart;
282 birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim);
283 birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim);
284 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim);
285 birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
286 pStat->st_ino = InternalInfo.IndexNumber.QuadPart;
287 pStat->st_nlink = StdInfo.NumberOfLinks;
288 pStat->st_rdev = 0;
289 pStat->st_uid = 0;
290 pStat->st_gid = 0;
291 pStat->st_padding1[0] = 0;
292 pStat->st_padding1[1] = 0;
293 pStat->st_padding1[2] = 0;
294 pStat->st_blksize = 65536;
295 pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
296 / BIRD_STAT_BLOCK_SIZE;
297
298 /* Get the serial number, reusing the buffer from above. */
299 if (!cbNameInfo)
300 {
301 cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
302 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
303 }
304 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
305 if (MY_NT_SUCCESS(rcNt))
306 rcNt = Ios.u.Status;
307 if (MY_NT_SUCCESS(rcNt))
308 {
309 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
310 pStat->st_dev = pVolInfo->VolumeSerialNumber
311 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
312 rc = 0;
313 }
314 else
315 {
316 pStat->st_dev = 0;
317 rc = birdSetErrnoFromNt(rcNt);
318 }
319 }
320 else
321 rc = birdSetErrnoFromNt(rcNt);
322
323#endif
324 return rc;
325}
326
327
328static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
329{
330 int rc;
331 HANDLE hFile = birdOpenFile(pszPath,
332 FILE_READ_ATTRIBUTES,
333 FILE_ATTRIBUTE_NORMAL,
334 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
335 FILE_OPEN,
336 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
337 OBJ_CASE_INSENSITIVE);
338 if (hFile != INVALID_HANDLE_VALUE)
339 {
340 rc = birdStatHandle(hFile, pStat, pszPath);
341 birdCloseFile(hFile);
342
343#if 0
344 {
345 static char s_szPrev[256];
346 size_t cchPath = strlen(pszPath);
347 if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
348 fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
349 else
350 memcpy(s_szPrev, pszPath, cchPath + 1);
351 }
352#endif
353 //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
354 }
355 else
356 {
357 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
358
359 /* On things like pagefile.sys we may get sharing violation. */
360 if (errno == ETXTBSY)
361 {
362 /** @todo Fall back on the parent directory enum if we run into a sharing
363 * violation. */
364 }
365 rc = -1;
366 }
367
368 return rc;
369}
370
371
372/**
373 * Implements UNIX fstat().
374 */
375int birdStatOnFd(int fd, BirdStat_T *pStat)
376{
377 int rc;
378 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
379 if (hFile != INVALID_HANDLE_VALUE)
380 rc = birdStatHandle(hFile, pStat, NULL);
381 else
382 rc = -1;
383 return rc;
384}
385
386
387/**
388 * Implements UNIX stat().
389 */
390int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
391{
392 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
393}
394
395
396/**
397 * Implements UNIX lstat().
398 */
399int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
400{
401 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
402}
403
404
405/**
406 * Internal worker for birdStatModTimeOnly.
407 */
408static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
409{
410 int rc;
411 HANDLE hFile = birdOpenFile(pszPath,
412 FILE_READ_ATTRIBUTES,
413 FILE_ATTRIBUTE_NORMAL,
414 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
415 FILE_OPEN,
416 FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
417 OBJ_CASE_INSENSITIVE);
418 if (hFile != INVALID_HANDLE_VALUE)
419 {
420 MY_NTSTATUS rcNt = 0;
421 MY_IO_STATUS_BLOCK Ios;
422 Ios.Information = 0;
423 Ios.u.Status = -1;
424
425 if (pBasicInfo)
426 {
427 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
428 if (MY_NT_SUCCESS(rcNt))
429 rcNt = Ios.u.Status;
430 }
431 birdCloseFile(hFile);
432
433 if (!MY_NT_SUCCESS(rcNt))
434 birdSetErrnoFromNt(rcNt);
435 }
436 else
437 {
438 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
439
440 /* On things like pagefile.sys we may get sharing violation. */
441 if (GetLastError() == ERROR_SHARING_VIOLATION)
442 {
443 /** @todo Fall back on the parent directory enum if we run into a sharing
444 * violation. */
445 }
446 rc = -1;
447 }
448 return rc;
449}
450
451
452/**
453 * Special function for getting the modification time.
454 */
455int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
456{
457 MY_FILE_BASIC_INFORMATION BasicInfo;
458 int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
459 if (!rc)
460 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
461 return rc;
462}
463
464
465
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