source: trunk/src/lib/nt/ntstat.c@ 2707

Last change on this file since 2707 was 2707, checked in by bird, 12 years ago

ntstat.c: Fixed fstat()'ing console handles and pipes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.4 KB
Line 
1/* $Id: ntstat.c 2707 2013-11-21 02:25:00Z bird $ */
2/** @file
3 * MSC + NT stat, lstat and fstat.
4 */
5
6/*
7 * Copyright (c) 2005-2013 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
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 && hFile != INVALID_HANDLE_VALUE)
137 {
138 MY_FILE_ATTRIBUTE_TAG_INFORMATION TagInfo;
139 MY_IO_STATUS_BLOCK Ios;
140 MY_NTSTATUS rcNt;
141 Ios.Information = 0;
142 Ios.u.Status = -1;
143 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &TagInfo, sizeof(TagInfo), MyFileAttributeTagInformation);
144 if ( !MY_NT_SUCCESS(rcNt)
145 || !MY_NT_SUCCESS(Ios.u.Status)
146 || TagInfo.ReparseTag != IO_REPARSE_TAG_SYMLINK)
147 fAttribs &= ~FILE_ATTRIBUTE_REPARSE_POINT;
148 }
149
150 if (fAttribs & FILE_ATTRIBUTE_REPARSE_POINT)
151 {
152 *pfIsDirSymlink = !!(fAttribs & FILE_ATTRIBUTE_DIRECTORY);
153 fMode = S_IFLNK;
154 }
155 else
156 {
157 *pfIsDirSymlink = 0;
158 if (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
159 fMode = S_IFDIR;
160 else
161 fMode = S_IFREG;
162 }
163
164 /* Access mask. */
165 fMode |= S_IROTH | S_IRGRP | S_IRUSR;
166 if (!(fAttribs & FILE_ATTRIBUTE_READONLY))
167 fMode |= S_IWOTH | S_IWGRP | S_IWUSR;
168 if ( (fAttribs & FILE_ATTRIBUTE_DIRECTORY)
169 || (pszName
170 ? birdIsFileExecutable(pszName)
171 : birdIsFileExecutableW(pNameInfo->FileName, pNameInfo->FileNameLength)) )
172 fMode |= S_IXOTH | S_IXGRP | S_IXUSR;
173
174 return fMode;
175}
176
177
178static void birdNtTimeToTimeSpec(__int64 iNtTime, BirdTimeSpec_T *pTimeSpec)
179{
180 iNtTime -= BIRD_NT_EPOCH_OFFSET_UNIX_100NS;
181 pTimeSpec->tv_sec = iNtTime / 10000000;
182 pTimeSpec->tv_nsec = (iNtTime % 10000000) * 100;
183}
184
185
186int birdStatHandle(HANDLE hFile, BirdStat_T *pStat, const char *pszPath)
187{
188 int rc;
189 MY_NTSTATUS rcNt;
190#if 0
191 ULONG cbAll = sizeof(MY_FILE_ALL_INFORMATION) + 0x10000;
192 MY_FILE_ALL_INFORMATION *pAll = (MY_FILE_ALL_INFORMATION *)birdTmpAlloc(cbAll);
193 if (pAll)
194 {
195 MY_IO_STATUS_BLOCK Ios;
196 Ios.Information = 0;
197 Ios.u.Status = -1;
198 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pAll, cbAll, MyFileAllInformation);
199 if (MY_NT_SUCCESS(rcNt))
200 rcNt = Ios.u.Status;
201 if (MY_NT_SUCCESS(rcNt))
202 {
203 pStat->st_mode = birdFileInfoToMode(hFile, pAll->BasicInformation.FileAttributes, pszPath,
204 &pAll->NameInformation, &pStat->st_dirsymlink);
205 pStat->st_padding0[0] = 0;
206 pStat->st_padding0[1] = 0;
207 pStat->st_size = pAll->StandardInformation.EndOfFile.QuadPart;
208 birdNtTimeToTimeSpec(pAll->BasicInformation.CreationTime.QuadPart, &pStat->st_birthtim);
209 birdNtTimeToTimeSpec(pAll->BasicInformation.ChangeTime.QuadPart, &pStat->st_ctim);
210 birdNtTimeToTimeSpec(pAll->BasicInformation.LastWriteTime.QuadPart, &pStat->st_mtim);
211 birdNtTimeToTimeSpec(pAll->BasicInformation.LastAccessTime.QuadPart, &pStat->st_atim);
212 pStat->st_ino = pAll->InternalInformation.IndexNumber.QuadPart;
213 pStat->st_nlink = pAll->StandardInformation.NumberOfLinks;
214 pStat->st_rdev = 0;
215 pStat->st_uid = 0;
216 pStat->st_gid = 0;
217 pStat->st_padding1[0] = 0;
218 pStat->st_padding1[1] = 0;
219 pStat->st_padding1[2] = 0;
220 pStat->st_blksize = 65536;
221 pStat->st_blocks = (pAll->StandardInformation.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
222 / BIRD_STAT_BLOCK_SIZE;
223
224 /* Get the serial number, reusing the buffer from above. */
225 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pAll, cbAll, MyFileFsVolumeInformation);
226 if (MY_NT_SUCCESS(rcNt))
227 rcNt = Ios.u.Status;
228 if (MY_NT_SUCCESS(rcNt))
229 {
230 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pAll;
231 pStat->st_dev = pVolInfo->VolumeSerialNumber
232 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
233 rc = 0;
234 }
235 else
236 {
237 pStat->st_dev = 0;
238 rc = birdSetErrnoFromNt(rcNt);
239 }
240 }
241 else
242 rc = birdSetErrnoFromNt(rcNt);
243 }
244 else
245 rc = birdSetErrnoToNoMem();
246#else
247 ULONG cbNameInfo = 0;
248 MY_FILE_NAME_INFORMATION *pNameInfo = NULL;
249 MY_FILE_STANDARD_INFORMATION StdInfo;
250 MY_FILE_BASIC_INFORMATION BasicInfo;
251 MY_FILE_INTERNAL_INFORMATION InternalInfo;
252 MY_IO_STATUS_BLOCK Ios;
253
254 Ios.Information = 0;
255 Ios.u.Status = -1;
256 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &StdInfo, sizeof(StdInfo), MyFileStandardInformation);
257 if (MY_NT_SUCCESS(rcNt))
258 rcNt = Ios.u.Status;
259 if (MY_NT_SUCCESS(rcNt))
260 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &BasicInfo, sizeof(BasicInfo), MyFileBasicInformation);
261 if (MY_NT_SUCCESS(rcNt))
262 rcNt = Ios.u.Status;
263 if (MY_NT_SUCCESS(rcNt))
264 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, &InternalInfo, sizeof(InternalInfo), MyFileInternalInformation);
265 if (MY_NT_SUCCESS(rcNt))
266 rcNt = Ios.u.Status;
267 if (MY_NT_SUCCESS(rcNt) && !pszPath)
268 {
269 cbNameInfo = 0x10020;
270 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
271 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileNameInformation);
272 if (MY_NT_SUCCESS(rcNt))
273 rcNt = Ios.u.Status;
274 }
275
276 if (MY_NT_SUCCESS(rcNt))
277 {
278 pStat->st_mode = birdFileInfoToMode(hFile, BasicInfo.FileAttributes, pszPath,
279 pNameInfo, &pStat->st_dirsymlink);
280 pStat->st_padding0[0] = 0;
281 pStat->st_padding0[1] = 0;
282 pStat->st_size = StdInfo.EndOfFile.QuadPart;
283 birdNtTimeToTimeSpec(BasicInfo.CreationTime.QuadPart, &pStat->st_birthtim);
284 birdNtTimeToTimeSpec(BasicInfo.ChangeTime.QuadPart, &pStat->st_ctim);
285 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, &pStat->st_mtim);
286 birdNtTimeToTimeSpec(BasicInfo.LastAccessTime.QuadPart, &pStat->st_atim);
287 pStat->st_ino = InternalInfo.IndexNumber.QuadPart;
288 pStat->st_nlink = StdInfo.NumberOfLinks;
289 pStat->st_rdev = 0;
290 pStat->st_uid = 0;
291 pStat->st_gid = 0;
292 pStat->st_padding1[0] = 0;
293 pStat->st_padding1[1] = 0;
294 pStat->st_padding1[2] = 0;
295 pStat->st_blksize = 65536;
296 pStat->st_blocks = (StdInfo.AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
297 / BIRD_STAT_BLOCK_SIZE;
298
299 /* Get the serial number, reusing the buffer from above. */
300 if (!cbNameInfo)
301 {
302 cbNameInfo = sizeof(MY_FILE_FS_VOLUME_INFORMATION) + 1024;
303 pNameInfo = (MY_FILE_NAME_INFORMATION *)alloca(cbNameInfo);
304 }
305 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pNameInfo, cbNameInfo, MyFileFsVolumeInformation);
306 if (MY_NT_SUCCESS(rcNt))
307 rcNt = Ios.u.Status;
308 if (MY_NT_SUCCESS(rcNt))
309 {
310 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pNameInfo;
311 pStat->st_dev = pVolInfo->VolumeSerialNumber
312 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
313 rc = 0;
314 }
315 else
316 {
317 pStat->st_dev = 0;
318 rc = birdSetErrnoFromNt(rcNt);
319 }
320 }
321 else
322 rc = birdSetErrnoFromNt(rcNt);
323
324#endif
325 return rc;
326}
327
328
329static int birdStatInternal(const char *pszPath, BirdStat_T *pStat, int fFollow)
330{
331 int rc;
332 HANDLE hFile = birdOpenFile(pszPath,
333 FILE_READ_ATTRIBUTES,
334 FILE_ATTRIBUTE_NORMAL,
335 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
336 FILE_OPEN,
337 FILE_OPEN_FOR_BACKUP_INTENT | (fFollow ? 0 : FILE_OPEN_REPARSE_POINT),
338 OBJ_CASE_INSENSITIVE);
339 if (hFile != INVALID_HANDLE_VALUE)
340 {
341 rc = birdStatHandle(hFile, pStat, pszPath);
342 birdCloseFile(hFile);
343
344#if 0
345 {
346 static char s_szPrev[256];
347 size_t cchPath = strlen(pszPath);
348 if (memcmp(s_szPrev, pszPath, cchPath >= 255 ? 255 : cchPath + 1) == 0)
349 fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
350 else
351 memcpy(s_szPrev, pszPath, cchPath + 1);
352 }
353#endif
354 //fprintf(stderr, "stat: %s -> rc/errno=%d/%u\n", pszPath, rc, errno);
355 }
356 else
357 {
358 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
359
360 /*
361 * On things like pagefile.sys we may get sharing violation. We fall
362 * back on directory enumeration for dealing with that.
363 */
364 if ( errno == ETXTBSY
365 && strchr(pszPath, '*') == NULL /* Serious paranoia... */
366 && strchr(pszPath, '?') == NULL)
367 {
368 MY_UNICODE_STRING NameUniStr;
369 hFile = birdOpenParentDir(pszPath,
370 FILE_READ_DATA | SYNCHRONIZE,
371 FILE_ATTRIBUTE_NORMAL,
372 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
373 FILE_OPEN,
374 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
375 OBJ_CASE_INSENSITIVE,
376 &NameUniStr);
377 if (hFile != INVALID_HANDLE_VALUE)
378 {
379 MY_FILE_ID_FULL_DIR_INFORMATION *pBuf;
380 ULONG cbBuf = sizeof(*pBuf) + NameUniStr.MaximumLength + 1024;
381 MY_IO_STATUS_BLOCK Ios;
382 MY_NTSTATUS rcNt;
383
384 pBuf = (MY_FILE_ID_FULL_DIR_INFORMATION *)alloca(cbBuf);
385 Ios.u.Status = -1;
386 Ios.Information = -1;
387 rcNt = g_pfnNtQueryDirectoryFile(hFile, NULL, NULL, NULL, &Ios, pBuf, cbBuf,
388 MyFileIdFullDirectoryInformation, FALSE, &NameUniStr, TRUE);
389 if (MY_NT_SUCCESS(rcNt))
390 rcNt = Ios.u.Status;
391 if (MY_NT_SUCCESS(rcNt))
392 {
393 /*
394 * Convert the data.
395 */
396 pStat->st_mode = birdFileInfoToMode(INVALID_HANDLE_VALUE, pBuf->FileAttributes, pszPath,
397 NULL, &pStat->st_dirsymlink);
398 pStat->st_padding0[0] = 0;
399 pStat->st_padding0[1] = 0;
400 pStat->st_size = pBuf->EndOfFile.QuadPart;
401 birdNtTimeToTimeSpec(pBuf->CreationTime.QuadPart, &pStat->st_birthtim);
402 birdNtTimeToTimeSpec(pBuf->ChangeTime.QuadPart, &pStat->st_ctim);
403 birdNtTimeToTimeSpec(pBuf->LastWriteTime.QuadPart, &pStat->st_mtim);
404 birdNtTimeToTimeSpec(pBuf->LastAccessTime.QuadPart, &pStat->st_atim);
405 pStat->st_ino = pBuf->FileId.QuadPart;
406 pStat->st_nlink = 1;
407 pStat->st_rdev = 0;
408 pStat->st_uid = 0;
409 pStat->st_gid = 0;
410 pStat->st_padding1[0] = 0;
411 pStat->st_padding1[1] = 0;
412 pStat->st_padding1[2] = 0;
413 pStat->st_blksize = 65536;
414 pStat->st_blocks = (pBuf->AllocationSize.QuadPart + BIRD_STAT_BLOCK_SIZE - 1)
415 / BIRD_STAT_BLOCK_SIZE;
416
417 /* Get the serial number, reusing the buffer from above. */
418 rcNt = g_pfnNtQueryVolumeInformationFile(hFile, &Ios, pBuf, cbBuf, MyFileFsVolumeInformation);
419 if (MY_NT_SUCCESS(rcNt))
420 rcNt = Ios.u.Status;
421 if (MY_NT_SUCCESS(rcNt))
422 {
423 MY_FILE_FS_VOLUME_INFORMATION const *pVolInfo = (MY_FILE_FS_VOLUME_INFORMATION const *)pBuf;
424 pStat->st_dev = pVolInfo->VolumeSerialNumber
425 | (pVolInfo->VolumeCreationTime.QuadPart << 32);
426 rc = 0;
427 }
428 else
429 {
430 pStat->st_dev = 0;
431 rc = birdSetErrnoFromNt(rcNt);
432 }
433 }
434
435 birdFreeNtPath(&NameUniStr);
436 birdCloseFile(hFile);
437
438 if (MY_NT_SUCCESS(rcNt))
439 return 0;
440 birdSetErrnoFromNt(rcNt);
441 }
442 }
443 rc = -1;
444 }
445
446 return rc;
447}
448
449
450/**
451 * Implements UNIX fstat().
452 */
453int birdStatOnFd(int fd, BirdStat_T *pStat)
454{
455 int rc;
456 HANDLE hFile = (HANDLE)_get_osfhandle(fd);
457 if (hFile != INVALID_HANDLE_VALUE)
458 {
459 DWORD fFileType;
460
461 SetLastError(NO_ERROR);
462 fFileType = GetFileType(hFile) & ~FILE_TYPE_REMOTE;
463 switch (fFileType)
464 {
465 case FILE_TYPE_DISK:
466 rc = birdStatHandle(hFile, pStat, NULL);
467 break;
468
469 case FILE_TYPE_CHAR:
470 case FILE_TYPE_PIPE:
471 if (fFileType == FILE_TYPE_PIPE)
472 pStat->st_mode = S_IFIFO | 0666;
473 else
474 pStat->st_mode = S_IFCHR | 0666;
475 pStat->st_padding0[0] = 0;
476 pStat->st_padding0[1] = 0;
477 pStat->st_size = 0;
478 pStat->st_atim.tv_sec = 0;
479 pStat->st_atim.tv_nsec = 0;
480 pStat->st_mtim.tv_sec = 0;
481 pStat->st_mtim.tv_nsec = 0;
482 pStat->st_ctim.tv_sec = 0;
483 pStat->st_ctim.tv_nsec = 0;
484 pStat->st_birthtim.tv_sec = 0;
485 pStat->st_birthtim.tv_nsec = 0;
486 pStat->st_ino = 0;
487 pStat->st_dev = 0;
488 pStat->st_rdev = 0;
489 pStat->st_uid = 0;
490 pStat->st_gid = 0;
491 pStat->st_padding1[0] = 0;
492 pStat->st_padding1[1] = 0;
493 pStat->st_padding1[2] = 0;
494 pStat->st_blksize = 512;
495 pStat->st_blocks = 0;
496 if (fFileType == FILE_TYPE_PIPE)
497 {
498 DWORD cbAvail;
499 if (PeekNamedPipe(hFile, NULL, 0, NULL, &cbAvail, NULL))
500 pStat->st_size = cbAvail;
501 }
502 rc = 0;
503 break;
504
505 case FILE_TYPE_UNKNOWN:
506 default:
507 if (GetLastError() == NO_ERROR)
508 rc = birdSetErrnoToBadFileNo();
509 else
510 rc = birdSetErrnoFromWin32(GetLastError());
511 break;
512 }
513 }
514 else
515 rc = -1;
516 return rc;
517}
518
519
520/**
521 * Implements UNIX stat().
522 */
523int birdStatFollowLink(const char *pszPath, BirdStat_T *pStat)
524{
525 return birdStatInternal(pszPath, pStat, 1 /*fFollow*/);
526}
527
528
529/**
530 * Implements UNIX lstat().
531 */
532int birdStatOnLink(const char *pszPath, BirdStat_T *pStat)
533{
534 return birdStatInternal(pszPath, pStat, 0 /*fFollow*/);
535}
536
537
538/**
539 * Internal worker for birdStatModTimeOnly.
540 */
541static int birdStatOnlyInternal(const char *pszPath, int fFollowLink, MY_FILE_BASIC_INFORMATION *pBasicInfo)
542{
543 int rc;
544 HANDLE hFile = birdOpenFile(pszPath,
545 FILE_READ_ATTRIBUTES,
546 FILE_ATTRIBUTE_NORMAL,
547 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
548 FILE_OPEN,
549 FILE_OPEN_FOR_BACKUP_INTENT | (fFollowLink ? 0 : FILE_OPEN_REPARSE_POINT),
550 OBJ_CASE_INSENSITIVE);
551 if (hFile != INVALID_HANDLE_VALUE)
552 {
553 MY_NTSTATUS rcNt = 0;
554 MY_IO_STATUS_BLOCK Ios;
555 Ios.Information = 0;
556 Ios.u.Status = -1;
557
558 if (pBasicInfo)
559 {
560 rcNt = g_pfnNtQueryInformationFile(hFile, &Ios, pBasicInfo, sizeof(*pBasicInfo), MyFileBasicInformation);
561 if (MY_NT_SUCCESS(rcNt))
562 rcNt = Ios.u.Status;
563 }
564 birdCloseFile(hFile);
565
566 if (!MY_NT_SUCCESS(rcNt))
567 birdSetErrnoFromNt(rcNt);
568 }
569 else
570 {
571 //fprintf(stderr, "stat: %s -> %u\n", pszPath, GetLastError());
572
573 /* On things like pagefile.sys we may get sharing violation. */
574 if (GetLastError() == ERROR_SHARING_VIOLATION)
575 {
576 /** @todo Fall back on the parent directory enum if we run into a sharing
577 * violation. */
578 }
579 rc = -1;
580 }
581 return rc;
582}
583
584
585/**
586 * Special function for getting the modification time.
587 */
588int birdStatModTimeOnly(const char *pszPath, BirdTimeSpec_T *pTimeSpec, int fFollowLink)
589{
590 MY_FILE_BASIC_INFORMATION BasicInfo;
591 int rc = birdStatOnlyInternal(pszPath, fFollowLink, &BasicInfo);
592 if (!rc)
593 birdNtTimeToTimeSpec(BasicInfo.LastWriteTime.QuadPart, pTimeSpec);
594 return rc;
595}
596
597
598
Note: See TracBrowser for help on using the repository browser.