281 lines
8.7 KiB
C
281 lines
8.7 KiB
C
|
/***
|
||
|
*stat64.c - get file status
|
||
|
*
|
||
|
* Copyright (c) 1998-2001, Microsoft Corporation. All rights reserved.
|
||
|
*
|
||
|
*Purpose:
|
||
|
* defines _stat64() - get file status
|
||
|
*
|
||
|
*Revision History:
|
||
|
* 06-02-98 GJF Created.
|
||
|
* 11-10-99 GB Made changes so as to take care of DST.
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
#include <cruntime.h>
|
||
|
#include <sys/types.h>
|
||
|
#include <sys/stat.h>
|
||
|
#include <errno.h>
|
||
|
#include <ctype.h>
|
||
|
#include <msdos.h>
|
||
|
#include <oscalls.h>
|
||
|
#include <string.h>
|
||
|
#include <internal.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <direct.h>
|
||
|
#include <mbstring.h>
|
||
|
#include <tchar.h>
|
||
|
|
||
|
|
||
|
#define ISSLASH(a) ((a) == _T('\\') || (a) == _T('/'))
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Number of 100 nanosecond units from 1/1/1601 to 1/1/1970
|
||
|
*/
|
||
|
#define EPOCH_BIAS 116444736000000000i64
|
||
|
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
#define __tdtoxmode __wdtoxmode
|
||
|
#else /* ndef _UNICODE */
|
||
|
#define __tdtoxmode __dtoxmode
|
||
|
#endif /* _UNICODE */
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Local routine which returns true if the argument is a UNC name
|
||
|
* specifying the root name of a share, such as '\\server\share\'.
|
||
|
*/
|
||
|
|
||
|
static int IsRootUNCName(const _TSCHAR *path);
|
||
|
|
||
|
extern unsigned short __cdecl __tdtoxmode(int, const _TSCHAR *);
|
||
|
|
||
|
|
||
|
/***
|
||
|
*int _stat64(name, buf) - get file status info
|
||
|
*
|
||
|
*Purpose:
|
||
|
* _stat64 obtains information about the file and stores it in the
|
||
|
* structure pointed to by buf.
|
||
|
*
|
||
|
* Note: Unlike _stat, _stat64 uses the UTC time values returned in
|
||
|
* WIN32_FIND_DATA 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:
|
||
|
* _TSCHAR *name - pathname of given file
|
||
|
* struct _stat *buffer - pointer to buffer to store info in
|
||
|
*
|
||
|
*Exit:
|
||
|
* fills in structure pointed to by buffer
|
||
|
* returns 0 if successful
|
||
|
* returns -1 and sets errno if unsuccessful
|
||
|
*
|
||
|
*Exceptions:
|
||
|
*
|
||
|
*******************************************************************************/
|
||
|
|
||
|
int __cdecl _tstat64 (
|
||
|
REG1 const _TSCHAR *name,
|
||
|
REG2 struct __stat64 *buf
|
||
|
)
|
||
|
{
|
||
|
_TSCHAR * path;
|
||
|
_TSCHAR pathbuf[ _MAX_PATH ];
|
||
|
int drive; /* A: = 1, B: = 2, etc. */
|
||
|
HANDLE findhandle;
|
||
|
WIN32_FIND_DATA findbuf;
|
||
|
|
||
|
/* Don't allow wildcards to be interpreted by system */
|
||
|
|
||
|
#ifdef _UNICODE
|
||
|
if (wcspbrk(name, L"?*")) {
|
||
|
#else
|
||
|
if (_mbspbrk(name, "?*")) {
|
||
|
#endif
|
||
|
errno = ENOENT;
|
||
|
_doserrno = E_nofile;
|
||
|
return(-1);
|
||
|
}
|
||
|
|
||
|
/* Try to get disk from name. If none, get current disk. */
|
||
|
|
||
|
if (name[1] == _T(':')){
|
||
|
if ( *name && !name[2] ){
|
||
|
errno = ENOENT; /* return an error if name is */
|
||
|
_doserrno = E_nofile; /* just drive letter then colon */
|
||
|
return( -1 );
|
||
|
}
|
||
|
drive = _totlower(*name) - _T('a') + 1;
|
||
|
}
|
||
|
else
|
||
|
drive = _getdrive();
|
||
|
|
||
|
/* Call Find Match File */
|
||
|
findhandle = FindFirstFile((_TSCHAR *)name, &findbuf);
|
||
|
if ( findhandle == INVALID_HANDLE_VALUE ) {
|
||
|
#ifdef _UNICODE
|
||
|
if ( !( wcspbrk(name, L"./\\") &&
|
||
|
#else
|
||
|
if ( !( _mbspbrk(name, "./\\") &&
|
||
|
#endif
|
||
|
(path = _tfullpath( pathbuf, name, _MAX_PATH )) &&
|
||
|
/* root dir. ('C:\') or UNC root dir. ('\\server\share\') */
|
||
|
((_tcslen( path ) == 3) || IsRootUNCName(path)) &&
|
||
|
(GetDriveType( path ) > 1) ) )
|
||
|
{
|
||
|
errno = ENOENT;
|
||
|
_doserrno = E_nofile;
|
||
|
return( -1 );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Root directories (such as C:\ or \\server\share\ are fabricated.
|
||
|
*/
|
||
|
|
||
|
findbuf.dwFileAttributes = A_D;
|
||
|
findbuf.nFileSizeHigh = 0;
|
||
|
findbuf.nFileSizeLow = 0;
|
||
|
findbuf.cFileName[0] = _T('\0');
|
||
|
|
||
|
buf->st_mtime = __loctotime64_t(1980,1,1,0,0,0, -1);
|
||
|
buf->st_atime = buf->st_mtime;
|
||
|
buf->st_ctime = buf->st_mtime;
|
||
|
}
|
||
|
else {
|
||
|
SYSTEMTIME SystemTime;
|
||
|
FILETIME LocalFTime;
|
||
|
|
||
|
if ( !FileTimeToLocalFileTime( &findbuf.ftLastWriteTime,
|
||
|
&LocalFTime ) ||
|
||
|
!FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
|
||
|
{
|
||
|
_dosmaperr( GetLastError() );
|
||
|
FindClose( findhandle );
|
||
|
return( -1 );
|
||
|
}
|
||
|
|
||
|
buf->st_mtime = __loctotime64_t( SystemTime.wYear,
|
||
|
SystemTime.wMonth,
|
||
|
SystemTime.wDay,
|
||
|
SystemTime.wHour,
|
||
|
SystemTime.wMinute,
|
||
|
SystemTime.wSecond,
|
||
|
-1 );
|
||
|
|
||
|
if ( findbuf.ftLastAccessTime.dwLowDateTime ||
|
||
|
findbuf.ftLastAccessTime.dwHighDateTime )
|
||
|
{
|
||
|
if ( !FileTimeToLocalFileTime( &findbuf.ftLastAccessTime,
|
||
|
&LocalFTime ) ||
|
||
|
!FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
|
||
|
{
|
||
|
_dosmaperr( GetLastError() );
|
||
|
FindClose( findhandle );
|
||
|
return( -1 );
|
||
|
}
|
||
|
|
||
|
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 ( findbuf.ftCreationTime.dwLowDateTime ||
|
||
|
findbuf.ftCreationTime.dwHighDateTime )
|
||
|
{
|
||
|
if ( !FileTimeToLocalFileTime( &findbuf.ftCreationTime,
|
||
|
&LocalFTime ) ||
|
||
|
!FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
|
||
|
{
|
||
|
_dosmaperr( GetLastError() );
|
||
|
FindClose( findhandle );
|
||
|
return( -1 );
|
||
|
}
|
||
|
|
||
|
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 ;
|
||
|
|
||
|
FindClose(findhandle);
|
||
|
}
|
||
|
|
||
|
/* Fill in buf */
|
||
|
|
||
|
buf->st_mode = __tdtoxmode(findbuf.dwFileAttributes, name);
|
||
|
buf->st_nlink = 1;
|
||
|
buf->st_size = ((__int64)(findbuf.nFileSizeHigh)) * (0x100000000i64) +
|
||
|
(__int64)(findbuf.nFileSizeLow);
|
||
|
|
||
|
/* now set the common fields */
|
||
|
|
||
|
buf->st_uid = buf->st_gid = buf->st_ino = 0;
|
||
|
|
||
|
buf->st_rdev = buf->st_dev = (_dev_t)(drive - 1); /* A=0, B=1, etc. */
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* IsRootUNCName - returns TRUE if the argument is a UNC name specifying
|
||
|
* a root share. That is, if it is of the form \\server\share\.
|
||
|
* This routine will also return true if the argument is of the
|
||
|
* form \\server\share (no trailing slash) but Win32 currently
|
||
|
* does not like that form.
|
||
|
*
|
||
|
* Forward slashes ('/') may be used instead of backslashes ('\').
|
||
|
*/
|
||
|
|
||
|
static int IsRootUNCName(const _TSCHAR *path)
|
||
|
{
|
||
|
/*
|
||
|
* If a root UNC name, path will start with 2 (but not 3) slashes
|
||
|
*/
|
||
|
|
||
|
if ( ( _tcslen ( path ) >= 5 ) /* minimum string is "//x/y" */
|
||
|
&& ISSLASH(path[0]) && ISSLASH(path[1]))
|
||
|
{
|
||
|
const _TSCHAR * p = path + 2 ;
|
||
|
|
||
|
/*
|
||
|
* find the slash between the server name and share name
|
||
|
*/
|
||
|
while ( * ++ p )
|
||
|
if ( ISSLASH(*p) )
|
||
|
break ;
|
||
|
|
||
|
if ( *p && p[1] )
|
||
|
{
|
||
|
/*
|
||
|
* is there a further slash?
|
||
|
*/
|
||
|
while ( * ++ p )
|
||
|
if ( ISSLASH(*p) )
|
||
|
break ;
|
||
|
|
||
|
/*
|
||
|
* just final slash (or no final slash)
|
||
|
*/
|
||
|
if ( !*p || !p[1])
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0 ;
|
||
|
}
|