260 lines
8.1 KiB
C
260 lines
8.1 KiB
C
/***
|
|
*fstat64.c - return file status info
|
|
*
|
|
* Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
|
|
*
|
|
*Purpose:
|
|
* defines _fstat64() - return file status info
|
|
*
|
|
*Revision History:
|
|
* 06-02-98 GJF Created.
|
|
* 11-10-99 GB Made modifications to take care of DST.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
|
|
#include <cruntime.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <msdos.h>
|
|
#include <io.h>
|
|
#include <internal.h>
|
|
#include <stddef.h>
|
|
#include <oscalls.h>
|
|
#include <stdio.h>
|
|
#include <mtdll.h>
|
|
#include <time.h>
|
|
|
|
#define IO_DEVNBR 0x3f
|
|
|
|
/*
|
|
* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
|
|
*/
|
|
#define EPOCH_BIAS 116444736000000000i64
|
|
|
|
|
|
/***
|
|
*int _fstat64(fildes, buf) - fills supplied buffer with status info
|
|
*
|
|
*Purpose:
|
|
* Fills the supplied buffer with status information on the
|
|
* file represented by the specified file designator.
|
|
* WARNING: the dev/rdev fields are zero for files. This is
|
|
* incompatible with DOS 3 version of this routine.
|
|
*
|
|
* Note: Unlike fstat, _fstat64 uses the UTC time values returned in the
|
|
* BY_HANDLE_FILE_INFORMATION struct. This means the time values will
|
|
* always be correct on NTFS, but may be wrong on FAT file systems for
|
|
* file times whose DST state is different from the current DST state
|
|
* (this an NT bug).
|
|
*
|
|
*Entry:
|
|
* int fildes - file descriptor
|
|
* struct _stat64 *buf - buffer to store result in
|
|
*
|
|
*Exit:
|
|
* fills in buffer pointed to by buf
|
|
* returns 0 if successful
|
|
* returns -1 and sets errno if unsuccessful
|
|
*
|
|
*Exceptions:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
int __cdecl _fstat64 (
|
|
int fildes,
|
|
struct __stat64 *buf
|
|
)
|
|
{
|
|
int isdev; /* 0 for a file, 1 for a device */
|
|
int retval = 0; /* assume good return */
|
|
BY_HANDLE_FILE_INFORMATION bhfi;
|
|
FILETIME LocalFTime;
|
|
SYSTEMTIME SystemTime;
|
|
|
|
if ( ((unsigned)fildes >= (unsigned)_nhandle) ||
|
|
!(_osfile(fildes) & FOPEN) )
|
|
{
|
|
errno = EBADF;
|
|
return(-1);
|
|
}
|
|
|
|
#ifdef _MT
|
|
/* Lock the file */
|
|
_lock_fh(fildes);
|
|
__try {
|
|
if ( !(_osfile(fildes) & FOPEN) ) {
|
|
errno = EBADF;
|
|
retval = -1;
|
|
goto done;
|
|
}
|
|
#endif /* _MT */
|
|
|
|
/* Find out what kind of handle underlies filedes
|
|
*/
|
|
isdev = GetFileType((HANDLE)_osfhnd(fildes)) & ~FILE_TYPE_REMOTE;
|
|
|
|
if ( isdev != FILE_TYPE_DISK ) {
|
|
|
|
/* not a disk file. probably a device or pipe
|
|
*/
|
|
if ( (isdev == FILE_TYPE_CHAR) || (isdev == FILE_TYPE_PIPE) ) {
|
|
/* treat pipes and devices similarly. no further info is
|
|
* available from any API, so set the fields as reasonably
|
|
* as possible and return.
|
|
*/
|
|
if ( isdev == FILE_TYPE_CHAR )
|
|
buf->st_mode = _S_IFCHR;
|
|
else
|
|
buf->st_mode = _S_IFIFO;
|
|
|
|
buf->st_rdev = buf->st_dev = (_dev_t)fildes;
|
|
buf->st_nlink = 1;
|
|
buf->st_uid = buf->st_gid = buf->st_ino = 0;
|
|
buf->st_atime = buf->st_mtime = buf->st_ctime = 0;
|
|
if ( isdev == FILE_TYPE_CHAR ) {
|
|
buf->st_size = 0i64;
|
|
}
|
|
else {
|
|
unsigned long ulAvail;
|
|
int rc;
|
|
rc = PeekNamedPipe((HANDLE)_osfhnd(fildes),
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&ulAvail,
|
|
NULL);
|
|
|
|
if (rc) {
|
|
buf->st_size = (_off_t)ulAvail;
|
|
}
|
|
else {
|
|
buf->st_size = (_off_t)0;
|
|
}
|
|
}
|
|
|
|
goto done;
|
|
}
|
|
else if ( isdev == FILE_TYPE_UNKNOWN ) {
|
|
errno = EBADF;
|
|
retval = -1;
|
|
goto done; /* join common return code */
|
|
}
|
|
else {
|
|
/* according to the documentation, this cannot happen, but
|
|
* play it safe anyway.
|
|
*/
|
|
_dosmaperr(GetLastError());
|
|
retval = -1;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
|
|
/* set the common fields
|
|
*/
|
|
buf->st_ino = buf->st_uid = buf->st_gid = buf->st_mode = 0;
|
|
buf->st_nlink = 1;
|
|
|
|
/* use the file handle to get all the info about the file
|
|
*/
|
|
if ( !GetFileInformationByHandle((HANDLE)_osfhnd(fildes), &bhfi) ) {
|
|
_dosmaperr(GetLastError());
|
|
retval = -1;
|
|
goto done;
|
|
}
|
|
|
|
if ( bhfi.dwFileAttributes & FILE_ATTRIBUTE_READONLY )
|
|
buf->st_mode |= (_S_IREAD + (_S_IREAD >> 3) + (_S_IREAD >> 6));
|
|
else
|
|
buf->st_mode |= ((_S_IREAD|_S_IWRITE) + ((_S_IREAD|_S_IWRITE) >> 3)
|
|
+ ((_S_IREAD|_S_IWRITE) >> 6));
|
|
|
|
/* set file date fields
|
|
*/
|
|
if ( !FileTimeToLocalFileTime( &(bhfi.ftLastWriteTime), &LocalFTime )
|
|
|| !FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
|
|
{
|
|
retval = -1;
|
|
goto done;
|
|
}
|
|
|
|
buf->st_mtime = __loctotime64_t(SystemTime.wYear,
|
|
SystemTime.wMonth,
|
|
SystemTime.wDay,
|
|
SystemTime.wHour,
|
|
SystemTime.wMinute,
|
|
SystemTime.wSecond,
|
|
-1);
|
|
|
|
if ( bhfi.ftLastAccessTime.dwLowDateTime ||
|
|
bhfi.ftLastAccessTime.dwHighDateTime )
|
|
{
|
|
|
|
if ( !FileTimeToLocalFileTime( &(bhfi.ftLastAccessTime),
|
|
&LocalFTime ) ||
|
|
!FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
|
|
{
|
|
retval = -1;
|
|
goto done;
|
|
}
|
|
|
|
buf->st_atime = __loctotime64_t(SystemTime.wYear,
|
|
SystemTime.wMonth,
|
|
SystemTime.wDay,
|
|
SystemTime.wHour,
|
|
SystemTime.wMinute,
|
|
SystemTime.wSecond,
|
|
-1);
|
|
}
|
|
else
|
|
buf->st_atime = buf->st_mtime;
|
|
|
|
if ( bhfi.ftCreationTime.dwLowDateTime ||
|
|
bhfi.ftCreationTime.dwHighDateTime )
|
|
{
|
|
|
|
if ( !FileTimeToLocalFileTime( &(bhfi.ftCreationTime),
|
|
&LocalFTime ) ||
|
|
!FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
|
|
{
|
|
retval = -1;
|
|
goto done;
|
|
}
|
|
|
|
buf->st_ctime = __loctotime64_t(SystemTime.wYear,
|
|
SystemTime.wMonth,
|
|
SystemTime.wDay,
|
|
SystemTime.wHour,
|
|
SystemTime.wMinute,
|
|
SystemTime.wSecond,
|
|
-1);
|
|
}
|
|
else
|
|
buf->st_ctime = buf->st_mtime;
|
|
|
|
buf->st_size = ((__int64)(bhfi.nFileSizeHigh)) * (0x100000000i64) +
|
|
(__int64)(bhfi.nFileSizeLow);
|
|
|
|
buf->st_mode |= _S_IFREG;
|
|
|
|
/* On DOS, this field contains the drive number, but
|
|
* the drive number is not available on this platform.
|
|
* Also, for UNC network names, there is no drive number.
|
|
*/
|
|
buf->st_rdev = buf->st_dev = 0;
|
|
|
|
/* Common return code */
|
|
|
|
done:
|
|
#ifdef _MT
|
|
; }
|
|
__finally {
|
|
_unlock_fh(fildes);
|
|
}
|
|
#endif /* _MT */
|
|
|
|
return(retval);
|
|
}
|