VirtualBox

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

Last change on this file since 3004 was 3003, checked in by bird, 8 years ago

ntstat.c: bugfix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.8 KB
Line 
1/* $Id: ntstat.c 3003 2016-11-05 23:18:25Z 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 switch (pszExt[0])
49 {
50 default:
51 return 0;
52
53 case 'e': /* exe */
54 return pszExt[1] == 'x' && pszExt[2] == 'e' && pszExt[3] == '\0';
55
56 case 'b': /* bat */
57 return pszExt[1] == 'a' && pszExt[2] == 't' && pszExt[3] == '\0';
58
59 case 'v': /* vbs */
60 return pszExt[1] == 'v' && pszExt[2] == 's' && pszExt[3] == '\0';
61
62 case 'c': /* com and cmd */
63 return (pszExt[1] == 'o' && pszExt[2] == 'm' && pszExt[3] == '\0')
64 || (pszExt[1] == 'm' && pszExt[2] == 'd' && pszExt[3] == '\0');
65 }
66}
67
68
69static int birdIsFileExecutable(const char *pszName)
70{
71 const char *pszExt = NULL;
72 char szExt[8];
73 size_t cchExt;
74 unsigned i;
75 char ch;
76
77 /* Look for a 3 char extension. */
78 ch = *pszName++;
79 if (!ch)
80 return 0;
81
82 while ((ch = *pszName++) != '\0')
83 if (ch == '.')
84 pszExt = pszName;
85
86 if (!pszExt)
87 return 0;
88 pszExt++;
89 cchExt = pszName - pszExt;
90 if (cchExt != 3)
91 return 0;
92
93 /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */
94 for (i = 0; i < cchExt; i++, pszExt++)
95 {
96 ch = *pszExt;
97 if (ch >= 'a' && ch <= 'z')
98 { /* likely */ }
99 else if (ch >= 'A' && ch <= 'Z')
100 ch += 'a' - 'A';
101 else
102 return 0;
103 szExt[i] = ch;
104 }
105 szExt[i] = '\0';
106
107 return birdIsExecutableExtension(szExt);
108}
109
110
111/**
112 * @a pwcName could be the full path.
113 */
114static int birdIsFileExecutableW(WCHAR const *pwcName, size_t cwcName)
115{
116 char szExt[8];
117 unsigned cchExt;
118 unsigned i;
119 WCHAR const *pwc;
120
121 /* Look for a 3 char extension. */
122 if (cwcName > 2 && pwcName[cwcName - 2] == '.')
123 return 0;
124 else if (cwcName > 3 && pwcName[cwcName - 3] == '.')
125 return 0;
126 else if (cwcName > 4 && pwcName[cwcName - 4] == '.')
127 cchExt = 3;
128 else
129 return 0;
130
131 /* Copy the extension out and lower case it. Fail immediately on non-alpha chars. */
132 pwc = &pwcName[cwcName - cchExt];
133 for (i = 0; i < cchExt; i++, pwc++)
134 {
135 WCHAR wc = *pwc;
136 if (wc >= 'a' && wc <= 'z')
137 { /* likely */ }
138 else if (wc >= 'A' && wc <= 'Z')
139 wc += 'a' - 'A';
140 else
141 return 0;
142 szExt[i] = (char)wc;
143 }
144 szExt[i] = '\0';
145
146 return birdIsExecutableExtension(szExt);
147}
148
149
150static unsigned short birdFileInfoToMode(HANDLE hFile, ULONG fAttribs, const char *pszName,
151 const wchar_t *pwszName, size_t cbNameW, __int16 *pfIsDirSymlink)
152{
153 unsigned short fMode;
154
155 /* File type. */
156 if ( (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
157 && hFile != INVALID_HANDLE_VALUE)
158 {
159 MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
160 MY_IO_STATUS_BLOCK Ios;
161 MY_NTSTATUS rcNt;
162 Ios.Information = 0;
163 Ios.u.Status = -1;
164 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
165 if ( !MY_NT_SUCCESS(rcNt)
166 || !MY_NT_SUCCESS(Ios.u.Status)
167 || TagInfo.ReparseTag != IO_REPARSE_TAG_SYMLINK)
168 fAttribs &= ~FILE_ATTRIBUTE_REPARSE_POINT;
169 }
170
171 if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
172 {
173 *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
174 fMode = S_IFLNK;
175 }
176 else
177 {
178 *pfIsDirSymlink = 0;
179 if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
180 fMode = S_IFDIR;
181 else
182 fMode = S_IFREG;
183 }
184
185 /* Access mask. */
186 fMode |= S_IROTH | S_IRGRP | S_IRUSR;
187 if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
188 fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
189 if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
190 || (pwszName
191 ? birdIsFileExecutableW(pwszName, cbNameW / sizeof(wchar_t))
192 : birdIsFileExecutable(pszName)) )
193 fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
194
195 return fMode;
196}
197
198
199/**
200 * Fills in a stat structure from an MY_FILE_ID_FULL_DIR_INFORMATION entry.
201 *
202 * @param pStat The stat structure.
203 * @param pBuf The MY_FILE_ID_FULL_DIR_INFORMATION entry.
204 * @param pszPath Optionally, the path for X bit checks.
205 * @remarks Caller sets st_dev.
206 */
207void birdStatFillFromFileIdFullDirInfo(BirdStat_T *pStat, MY_FILE_ID_FULL_DIR_INFORMATION const *pBuf, const char *pszPath)
208{
209 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
210 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
211 pStat->st_padding0[0] = 0;
212 pStat->st_padding0[1] = 0;
213 pStat->st_size = pBuf->EndOfFile.QuadPart;
214 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
215 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
216 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
217 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
218 pStat->st_ino = pBuf->FileId.QuadPart;
219 pStat->st_nlink = 1;
220 pStat->st_rdev = 0;
221 pStat->st_uid = 0;
222 pStat->st_gid = 0;
223 pStat->st_padding1 = 0;
224 pStat->st_attribs = pBuf->FileAttributes;
225 pStat->st_blksize = 65536;
226 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
227 / BIRD_STAT_BLOCK_SIZE;
228}
229
230
231/**
232 * Fills in a stat structure from an MY_FILE_ID_BOTH_DIR_INFORMATION entry.
233 *
234 * @param pStat The stat structure.
235 * @param pBuf The MY_FILE_ID_BOTH_DIR_INFORMATION entry.
236 * @param pszPath Optionally, the path for X bit checks.
237 * @remarks Caller sets st_dev.
238 */
239void birdStatFillFromFileIdBothDirInfo(BirdStat_T *pStat, MY_FILE_ID_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
240{
241 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
242 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
243 pStat->st_padding0[0] = 0;
244 pStat->st_padding0[1] = 0;
245 pStat->st_size = pBuf->EndOfFile.QuadPart;
246 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
247 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
248 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
249 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
250 pStat->st_ino = pBuf->FileId.QuadPart;
251 pStat->st_nlink = 1;
252 pStat->st_rdev = 0;
253 pStat->st_uid = 0;
254 pStat->st_gid = 0;
255 pStat->st_padding1 = 0;
256 pStat->st_attribs = pBuf->FileAttributes;
257 pStat->st_blksize = 65536;
258 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
259 / BIRD_STAT_BLOCK_SIZE;
260}
261
262
263/**
264 * Fills in a stat structure from an MY_FILE_BOTH_DIR_INFORMATION entry.
265 *
266 * @param pStat The stat structure.
267 * @param pBuf The MY_FILE_BOTH_DIR_INFORMATION entry.
268 * @param pszPath Optionally, the path for X bit checks.
269 * @remarks Caller sets st_dev.
270 */
271void birdStatFillFromFileBothDirInfo(BirdStat_T *pStat, MY_FILE_BOTH_DIR_INFORMATION const *pBuf, const char *pszPath)
272{
273 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes,
274 pszPath, pBuf->FileName, pBuf->FileNameLength, &pStat->st_dirsymlink);
275 pStat->st_padding0[0] = 0;
276 pStat->st_padding0[1] = 0;
277 pStat->st_size = pBuf->EndOfFile.QuadPart;
278 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
279 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
280 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
281 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
282 pStat->st_ino = 0;
283 pStat->st_nlink = 1;
284 pStat->st_rdev = 0;
285 pStat->st_uid = 0;
286 pStat->st_gid = 0;
287 pStat->st_padding1 = 0;
288 pStat->st_attribs = pBuf->FileAttributes;
289 pStat->st_blksize = 65536;
290 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
291 / BIRD_STAT_BLOCK_SIZE;
292}
293
294
295int birdStatHandle2(HANDLE hFile, BirdStat_T *pStat, const char *pszPath, const wchar_t *pwszPath)
296{
297 int rc;
298 MY_NTSTATUS rcNt;
299#if 0
300 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
301 MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
302 if (pAll)
303 {
304 MY_IO_STATUS_BLOCK Ios;
305 Ios.Information = 0;
306 Ios.u.Status = -1;
307 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
308 if (MY_NT_SUCCESS(rcNt))
309 rcNt = Ios.u.Status;
310 if (MY_NT_SUCCESS(rcNt))
311 {
312 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
313 pAll->NameInformation.FileNamepAll->NameInformation.FileNameLength,
314 &pStat->st_dirsymlink);
315 pStat->st_padding0[0] = 0;
316 pStat->st_padding0[1] = 0;
317 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
318 birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim);
319 birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim);
320 birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim);
321 birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
322 pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart;
323 pStat->st_nlink = pAll->StandardInformation.NumberOfLinks;
324 pStat->st_rdev = 0;
325 pStat->st_uid = 0;
326 pStat->st_gid = 0;
327 pStat->st_padding1 = 0;
328 pStat->st_attribs = pAll->StandardInformation.FileAttributes;
329 pStat->st_blksize = 65536;
330 pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
331 / BIRD_STAT_BLOCK_SIZE;
332
333 /* Get the serial number, reusing the buffer from above. */
334 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
335 if (MY_NT_SUCCESS(rcNt))
336 rcNt = Ios.u.Status;
337 if (MY_NT_SUCCESS(rcNt))
338 {
339 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
340 pStat->st_dev = pVolInfo->VolumeSerialNumber
341 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
342 rc = 0;
343 }
344 else
345 {
346 pStat->st_dev = 0;
347 rc = birdSetErrnoFromNt(rcNt);
348 }
349 }
350 else
351 rc = birdSetErrnoFromNt(rcNt);
352 }
353 else
354 rc = birdSetErrnoToNoMem();
355#else
356 ULONG cbNameInfo = 0;
357 MY_FILE_NAME_INFORMATION *pNameInfo = NULL;
358 MY_FILE_STANDARD_INFORMATION StdInfo;
359 MY_FILE_BASIC_INFORMATION BasicInfo;
360 MY_FILE_INTERNAL_INFORMATION InternalInfo;
361 MY_IO_STATUS_BLOCK Ios;
362
363 Ios.Information = 0;
364 Ios.u.Status = -1;
365 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
366 if (MY_NT_SUCCESS(rcNt))
367 rcNt = Ios.u.Status;
368 if (MY_NT_SUCCESS(rcNt))
369 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
370 if (MY_NT_SUCCESS(rcNt))
371 rcNt = Ios.u.Status;
372 if (MY_NT_SUCCESS(rcNt))
373 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
374 if (MY_NT_SUCCESS(rcNt))
375 rcNt = Ios.u.Status;
376 if (MY_NT_SUCCESS(rcNt) && !pszPath && !pwszPath)
377 {
378 cbNameInfo = 0x10020;
379 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
380 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
381 if (MY_NT_SUCCESS(rcNt))
382 rcNt = Ios.u.Status;
383 }
384
385 if (MY_NT_SUCCESS(rcNt))
386 {
387 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
388 pNameInfo ? pNameInfo->FileName : pwszPath,
389 pNameInfo ? pNameInfo->FileNameLength
390 : pwszPath ? wcslen(pwszPath) * sizeof(wchar_t) : 0,
391 &pStat->st_dirsymlink);
392 pStat->st_padding0[0] = 0;
393 pStat->st_padding0[1] = 0;
394 pStat->st_size = StdInfo.EndOfFile.QuadPart;
395 birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim);
396 birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim);
397 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim);
398 birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
399 pStat->st_ino = InternalInfo.IndexNumber.QuadPart;
400 pStat->st_nlink = StdInfo.NumberOfLinks;
401 pStat->st_rdev = 0;
402 pStat->st_uid = 0;
403 pStat->st_gid = 0;
404 pStat->st_padding1 = 0;
405 pStat->st_attribs = BasicInfo.FileAttributes;
406 pStat->st_blksize = 65536;
407 pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
408 / BIRD_STAT_BLOCK_SIZE;
409
410 /* Get the serial number, reusing the buffer from above. */
411 if (!cbNameInfo)
412 {
413 cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
414 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
415 }
416 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
417 if (MY_NT_SUCCESS(rcNt))
418 rcNt = Ios.u.Status;
419 if (MY_NT_SUCCESS(rcNt))
420 {
421 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
422 pStat->st_dev = pVolInfo->VolumeSerialNumber
423 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
424 rc = 0;
425 }
426 else
427 {
428 pStat->st_dev = 0;
429 rc = birdSetErrnoFromNt(rcNt);
430 }
431 }
432 else
433 rc = birdSetErrnoFromNt(rcNt);
434
435#endif
436 return rc;
437}
438
439
440int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
441{
442 return birdStatHandle2(hFile, pStat, pszPath, NULL);
443}
444
445
446/**
447 * Generates a device number from the volume information.
448 *
449 * @returns Device number.
450 * @param pVolInfo Volume information.
451 */
452unsigned __int64 birdVolumeInfoToDeviceNumber(const MY_FILE_FS_VOLUME_INFORMATION *pVolInfo)
453{
454 return pVolInfo->VolumeSerialNumber
455 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
456}
457
458
459/**
460 * Quries the volume information and generates a device number from it.
461 *
462 * @returns NT status code.
463 * @param hFile The file/dir/whatever to query the volume info
464 * and device number for.
465 * @param pVolInfo User provided buffer for volume information.
466 * @param cbVolInfo The size of the buffer.
467 * @param puDevNo Where to return the device number. This is set
468 * to zero on failure.
469 */
470MY_NTSTATUS birdQueryVolumeDeviceNumber(HANDLE hFile, MY_FILE_FS_VOLUME_INFORMATION *pVolInfo, size_t cbVolInfo,
471 unsigned __int64 *puDevNo)
472{
473 MY_IO_STATUS_BLOCK Ios;
474 MY_NTSTATUS rcNt;
475
476 Ios.u.Status = -1;
477 Ios.Information = -1;
478
479 pVolInfo->VolumeSerialNumber = 0;
480 pVolInfo->VolumeCreationTime.QuadPart = 0;
481
482 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pVolInfo, (LONG)cbVolInfo, MyFileFsVolumeInformation);
483 if (MY_NT_SUCCESS(rcNt))
484 {
485 *puDevNo = birdVolumeInfoToDeviceNumber(pVolInfo);
486 return Ios.u.Status;
487 }
488 *puDevNo = 0;
489 return rcNt;
490}
491
492
493static int birdStatInternal(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollow)
494{
495 int rc;
496 HANDLE hFile = birdOpenFileEx(hRoot, pszPath,
497 FILE_READ_ATTRIBUTES,
498 FILE_ATTRIBUTE_NORMAL,
499 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
500 FILE_OPEN,
501 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
502 OBJ_CASE_INSENSITIVE);
503 if (hFile != INVALID_HANDLE_VALUE)
504 {
505 rc = birdStatHandle2(hFile, pStat, pszPath, NULL);
506 birdCloseFile(hFile);
507
508#if 0
509 {
510 static char s_szPrev[256];
511 size_t cchPath = strlen(pszPath);
512 if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
513 fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
514 else
515 memcpy(s_szPrev, pszPath, cchPath + 1);
516 }
517#endif
518 //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
519 }
520 else
521 {
522 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
523
524 /*
525 * On things like pagefile.sys we may get sharing violation. We fall
526 * back on directory enumeration for dealing with that.
527 */
528 if ( errno == ETXTBSY
529 && strchr(pszPath, '*') == NULL /* Serious paranoia... */
530 && strchr(pszPath, '?') == NULL)
531 {
532 MY_UNICODE_STRING NameUniStr;
533 hFile = birdOpenParentDir(hRoot, pszPath,
534 FILE_READ_DATA | SYNCHRONIZE,
535 FILE_ATTRIBUTE_NORMAL,
536 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
537 FILE_OPEN,
538 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
539 OBJ_CASE_INSENSITIVE,
540 &NameUniStr);
541 if (hFile != INVALID_HANDLE_VALUE)
542 {
543 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
544 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
545 MY_IO_STATUS_BLOCK Ios;
546 MY_NTSTATUS rcNt;
547
548 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
549 Ios.u.Status = -1;
550 Ios.Information = -1;
551 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
552 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
553 if (MY_NT_SUCCESS(rcNt))
554 rcNt = Ios.u.Status;
555 if (MY_NT_SUCCESS(rcNt))
556 {
557 /*
558 * Convert the data.
559 */
560 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, pszPath);
561
562 /* Get the serial number, reusing the buffer from above. */
563 rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
564 if (MY_NT_SUCCESS(rcNt))
565 rc = 0;
566 else
567 rc = birdSetErrnoFromNt(rcNt);
568 }
569
570 birdFreeNtPath(&NameUniStr);
571 birdCloseFile(hFile);
572
573 if (MY_NT_SUCCESS(rcNt))
574 return 0;
575 birdSetErrnoFromNt(rcNt);
576 }
577 }
578 rc = -1;
579 }
580
581 return rc;
582}
583
584
585static int birdStatInternalW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollow)
586{
587 int rc;
588 HANDLE hFile = birdOpenFileExW(hRoot, pwszPath,
589 FILE_READ_ATTRIBUTES,
590 FILE_ATTRIBUTE_NORMAL,
591 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
592 FILE_OPEN,
593 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
594 OBJ_CASE_INSENSITIVE);
595 if (hFile != INVALID_HANDLE_VALUE)
596 {
597 rc = birdStatHandle2(hFile, pStat, NULL, pwszPath);
598 birdCloseFile(hFile);
599 }
600 else
601 {
602 /*
603 * On things like pagefile.sys we may get sharing violation. We fall
604 * back on directory enumeration for dealing with that.
605 */
606 if ( errno == ETXTBSY
607 && wcschr(pwszPath, '*') == NULL /* Serious paranoia... */
608 && wcschr(pwszPath, '?') == NULL)
609 {
610 MY_UNICODE_STRING NameUniStr;
611 hFile = birdOpenParentDirW(hRoot, pwszPath,
612 FILE_READ_DATA | SYNCHRONIZE,
613 FILE_ATTRIBUTE_NORMAL,
614 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
615 FILE_OPEN,
616 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
617 OBJ_CASE_INSENSITIVE,
618 &NameUniStr);
619 if (hFile != INVALID_HANDLE_VALUE)
620 {
621 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
622 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
623 MY_IO_STATUS_BLOCK Ios;
624 MY_NTSTATUS rcNt;
625
626 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
627 Ios.u.Status = -1;
628 Ios.Information = -1;
629 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
630 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
631 if (MY_NT_SUCCESS(rcNt))
632 rcNt = Ios.u.Status;
633 if (MY_NT_SUCCESS(rcNt))
634 {
635 /*
636 * Convert the data.
637 */
638 birdStatFillFromFileIdFullDirInfo(pStat, pBuf, NULL);
639
640 /* Get the serial number, reusing the buffer from above. */
641 rcNt = birdQueryVolumeDeviceNumber(hFile, (MY_FILE_FS_VOLUME_INFORMATION *)pBuf, cbBuf, &pStat->st_dev);
642 if (MY_NT_SUCCESS(rcNt))
643 rc = 0;
644 else
645 rc = birdSetErrnoFromNt(rcNt);
646 }
647
648 birdFreeNtPath(&NameUniStr);
649 birdCloseFile(hFile);
650
651 if (MY_NT_SUCCESS(rcNt))
652 return 0;
653 birdSetErrnoFromNt(rcNt);
654 }
655 }
656 rc = -1;
657 }
658
659 return rc;
660}
661
662
663/**
664 * Implements UNIX fstat().
665 */
666int birdStatOnFd(int fd, BirdStat_T *pStat)
667{
668 int rc;
669 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
670 if (hFile != INVALID_HANDLE_VALUE)
671 {
672 DWORD fFileType;
673
674 birdResolveImports();
675
676 SetLastError(NO_ERROR);
677 fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE;
678 switch (fFileType)
679 {
680 case FILE_TYPE_DISK:
681 rc = birdStatHandle2(hFile, pStat, NULL, NULL);
682 break;
683
684 case FILE_TYPE_CHAR:
685 case FILE_TYPE_PIPE:
686 if (fFileType == FILE_TYPE_PIPE)
687 pStat->st_mode = S_IFIFO | 0666;
688 else
689 pStat->st_mode = S_IFCHR | 0666;
690 pStat->st_padding0[0] = 0;
691 pStat->st_padding0[1] = 0;
692 pStat->st_size = 0;
693 pStat->st_atim.tv_sec = 0;
694 pStat->st_atim.tv_nsec = 0;
695 pStat->st_mtim.tv_sec = 0;
696 pStat->st_mtim.tv_nsec = 0;
697 pStat->st_ctim.tv_sec = 0;
698 pStat->st_ctim.tv_nsec = 0;
699 pStat->st_birthtim.tv_sec = 0;
700 pStat->st_birthtim.tv_nsec = 0;
701 pStat->st_ino = 0;
702 pStat->st_dev = 0;
703 pStat->st_rdev = 0;
704 pStat->st_uid = 0;
705 pStat->st_gid = 0;
706 pStat->st_padding1 = 0;
707 pStat->st_attribs = fFileType == FILE_TYPE_PIPE ? FILE_ATTRIBUTE_NORMAL : FILE_ATTRIBUTE_DEVICE;
708 pStat->st_blksize = 512;
709 pStat->st_blocks = 0;
710 if (fFileType == FILE_TYPE_PIPE)
711 {
712 DWORD cbAvail;
713 if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL))
714 pStat->st_size = cbAvail;
715 }
716 rc = 0;
717 break;
718
719 case FILE_TYPE_UNKNOWN:
720 default:
721 if (GetLastError() == NO_ERROR)
722 rc = birdSetErrnoToBadFileNo();
723 else
724 rc = birdSetErrnoFromWin32(GetLastError());
725 break;
726 }
727 }
728 else
729 rc = -1;
730 return rc;
731}
732
733
734/**
735 * Special case that only gets the file size and nothing else.
736 */
737int birdStatOnFdJustSize(int fd, __int64 *pcbFile)
738{
739 int rc;
740 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
741 if (hFile != INVALID_HANDLE_VALUE)
742 {
743 LARGE_INTEGER cbLocal;
744 if (GetFileSizeEx(hFile, &cbLocal))
745 {
746 *pcbFile = cbLocal.QuadPart;
747 rc = 0;
748 }
749 else
750 {
751 BirdStat_T Stat;
752 rc = birdStatOnFd(fd, &Stat);
753 if (rc == 0)
754 *pcbFile = Stat.st_size;
755 }
756 }
757 else
758 rc = -1;
759 return rc;
760}
761
762
763/**
764 * Implements UNIX stat().
765 */
766int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
767{
768 return birdStatInternal(NULL, pszPath, pStat, 1 /*fFollow*/);
769}
770
771
772/**
773 * Implements UNIX stat().
774 */
775int birdStatFollowLinkW(const wchar_t *pwszPath, BirdStat_T *pStat)
776{
777 return birdStatInternalW(NULL, pwszPath, pStat, 1 /*fFollow*/);
778}
779
780
781/**
782 * Implements UNIX lstat().
783 */
784int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
785{
786 return birdStatInternal(NULL, pszPath, pStat, 0 /*fFollow*/);
787}
788
789
790/**
791 * Implements UNIX lstat().
792 */
793int birdStatOnLinkW(const wchar_t *pwszPath, BirdStat_T *pStat)
794{
795 return birdStatInternalW(NULL, pwszPath, pStat, 0 /*fFollow*/);
796}
797
798
799/**
800 * Implements an API like UNIX fstatat().
801 *
802 * @returns 0 on success, -1 and errno on failure.
803 * @param hRoot NT handle pwszPath is relative to.
804 * @param pszPath The path.
805 * @param pStat Where to return stats.
806 * @param fFollowLink Whether to follow links.
807 */
808int birdStatAt(HANDLE hRoot, const char *pszPath, BirdStat_T *pStat, int fFollowLink)
809{
810 return birdStatInternal(hRoot, pszPath, pStat, fFollowLink != 0);
811}
812
813
814/**
815 * Implements an API like UNIX fstatat().
816 *
817 * @returns 0 on success, -1 and errno on failure.
818 * @param hRoot NT handle pwszPath is relative to.
819 * @param pwszPath The path.
820 * @param pStat Where to return stats.
821 * @param fFollowLink Whether to follow links.
822 */
823int birdStatAtW(HANDLE hRoot, const wchar_t *pwszPath, BirdStat_T *pStat, int fFollowLink)
824{
825 return birdStatInternalW(hRoot, pwszPath, pStat, fFollowLink != 0);
826}
827
828
829/**
830 * Internal worker for birdStatModTimeOnly.
831 */
832static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
833{
834 int rc;
835 HANDLE hFile = birdOpenFile(pszPath,
836 FILE_READ_ATTRIBUTES,
837 FILE_ATTRIBUTE_NORMAL,
838 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
839 FILE_OPEN,
840 FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
841 OBJ_CASE_INSENSITIVE);
842 if (hFile != INVALID_HANDLE_VALUE)
843 {
844 MY_NTSTATUS rcNt = 0;
845 MY_IO_STATUS_BLOCK Ios;
846 Ios.Information = 0;
847 Ios.u.Status = -1;
848
849 if (pBasicInfo)
850 {
851 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
852 if (MY_NT_SUCCESS(rcNt))
853 rcNt = Ios.u.Status;
854 }
855 birdCloseFile(hFile);
856
857 if (MY_NT_SUCCESS(rcNt))
858 rc = 0;
859 else
860 {
861 birdSetErrnoFromNt(rcNt);
862 rc = -1;
863 }
864 }
865 else
866 {
867 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
868
869 /* On things like pagefile.sys we may get sharing violation. */
870 if (GetLastError() == ERROR_SHARING_VIOLATION)
871 {
872 /** @todo Fall back on the parent directory enum if we run into a sharing
873 * violation. */
874 }
875 rc = -1;
876 }
877 return rc;
878}
879
880
881/**
882 * Special function for getting the modification time.
883 */
884int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
885{
886 MY_FILE_BASIC_INFORMATION BasicInfo;
887 int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
888 if (!rc)
889 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
890 return rc;
891}
892
893
894
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