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

Last change on this file since 2985 was 2985, checked in by bird, 9 years ago

lib/nt: Got fts-nt halfways working, quite a few NT interface changes.

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