/*** *stat.c - get file status * * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved. * *Purpose: * defines _stat() - get file status * *******************************************************************************/ #ifndef _MAC #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define ISSLASH(a) ((a) == _T('\\') || (a) == _T('/')) #ifdef _UNICODE #define __tdtoxmode __wdtoxmode #else /* _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); /*** *unsigned __tdtoxmode(attr, name) - * *Purpose: * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ #ifdef _USE_INT64 extern unsigned short __cdecl __tdtoxmode(int, const _TSCHAR *); #else /* _USE_INT64 */ unsigned short __cdecl __tdtoxmode ( int attr, const _TSCHAR *name ) { REG1 unsigned short uxmode; unsigned dosmode; REG2 const _TSCHAR *p; dosmode = attr & 0xff; if ((p = name)[1] == _T(':')) p += 2; /* check to see if this is a directory - note we must make a special * check for the root, which DOS thinks is not a directory */ uxmode = (unsigned short) (((ISSLASH(*p) && !p[1]) || (dosmode & A_D) || !*p) ? _S_IFDIR|_S_IEXEC : _S_IFREG); /* If attribute byte does not have read-only bit, it is read-write */ uxmode |= (dosmode & A_RO) ? _S_IREAD : (_S_IREAD|_S_IWRITE); /* see if file appears to be executable - check extension of name */ if (p = _tcsrchr(name, _T('.'))) { if ( !_tcsicmp(p, _T(".exe")) || !_tcsicmp(p, _T(".cmd")) || !_tcsicmp(p, _T(".bat")) || !_tcsicmp(p, _T(".com")) ) uxmode |= _S_IEXEC; } /* propagate user read/write/execute bits to group/other fields */ uxmode |= (uxmode & 0700) >> 3; uxmode |= (uxmode & 0700) >> 6; return(uxmode); } #endif /* _USE_INT64 */ /*** *int _stat(name, buf) - get file status info * *Purpose: * _stat obtains information about the file and stores it in the * structure pointed to by buf. * * Note: We cannot directly use the file time stamps returned in the * WIN32_FIND_DATA structure. The values are supposedly in system time * and system time is ambiguously defined (it is UTC for Windows NT, local * time for Win32S and probably local time for Win32C). Therefore, these * values must be converted to local time before than can be used. * *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: * *******************************************************************************/ #ifdef _USE_INT64 int __cdecl _tstati64 ( REG1 const _TSCHAR *name, REG2 struct _stati64 *buf ) #else /* _USE_INT64 */ int __cdecl _tstat ( REG1 const _TSCHAR *name, REG2 struct _stat *buf ) #endif /* _USE_INT64 */ { _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 /* _UNICODE */ if (_mbspbrk(name, "?*")) { #endif /* _UNICODE */ 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 /* _UNICODE */ if ( !( _mbspbrk(name, "./\\") && #endif /* _UNICODE */ (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 = __loctotime_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 = __loctotime_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 = __loctotime_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 = __loctotime_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; #ifdef _USE_INT64 buf->st_size = ((__int64)(findbuf.nFileSizeHigh)) * (0x100000000i64) + (__int64)(findbuf.nFileSizeLow); #else /* _USE_INT64 */ buf->st_size = findbuf.nFileSizeLow; #endif /* _USE_INT64 */ /* 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 ; } #else /* _MAC */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef _MBCS #include #define STRPBRK _mbspbrk #else /* _MBCS */ #define STRPBRK strpbrk #endif /* _MBCS */ unsigned short __cdecl _dtoxmode ( CInfoPBPtr pcinfoPB ); /*** *unsigned _dtoxmode(CInfoPBPtr) - * *Purpose: * *Entry: * *Exit: * *Exceptions: * *******************************************************************************/ unsigned short __cdecl _dtoxmode ( CInfoPBPtr pcinfoPB ) { REG1 unsigned short uxmode; unsigned char dosmode; int fReadOnly; dosmode = pcinfoPB->hFileInfo.ioFlAttrib; /* file or dir */ if (dosmode & 0x10) { uxmode = _S_IFDIR; fReadOnly = pcinfoPB->dirInfo.ioDrUsrWds.frFlags == fsRdPerm; } else { uxmode = _S_IFREG; fReadOnly = pcinfoPB->hFileInfo.ioFlFndrInfo.fdFlags == fsRdPerm; /* see if file appears to be executable - check 'APPL'? */ if (pcinfoPB->hFileInfo.ioFlFndrInfo.fdType == 'APPL') uxmode |= _S_IEXEC; } /* If attribute byte has 0 bit set, file is locked, then read-only */ uxmode |= (((dosmode & 0x01) || fReadOnly) ? _S_IREAD : (_S_IREAD|_S_IWRITE)); /* propagate user read/write/execute bits to group/other fields */ uxmode |= (uxmode & 0700) >> 3; uxmode |= (uxmode & 0700) >> 6; return(uxmode); } /*** *int _stat(name, buf) - get file status info * *Purpose: * _stat obtains information about the file and stores it in the structure * pointed to by buf. * *Entry: * char *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 _stat ( REG1 const char *name, REG2 struct _stat *buf ) { CInfoPBRec cinfoPB; OSErr osErr; char szBuf[256]; DateTimeRec dt; DateTimeRec dtc; HParamBlockRec hparamBlock; if (!*name) { errno = ENOENT; return -1; } strcpy(szBuf, name); cinfoPB.hFileInfo.ioNamePtr = _c2pstr(szBuf); cinfoPB.hFileInfo.ioFDirIndex = 0; cinfoPB.hFileInfo.ioVRefNum = 0; cinfoPB.hFileInfo.ioDirID = 0; osErr = PBGetCatInfoSync(&cinfoPB); switch (osErr) { case noErr: break; case bdNamErr: case dirNFErr: case extFSErr: case fnfErr: case ioErr: case nsvErr: case paramErr: errno = ENOENT; return -1; default: return -1; } /* file or dir ? */ if (cinfoPB.hFileInfo.ioFlAttrib & 0x10) { /*dir*/ Secs2Date(cinfoPB.dirInfo.ioDrMdDat, &dt); Secs2Date(cinfoPB.dirInfo.ioDrCrDat, &dtc); buf->st_size = 0; } else { /*file*/ Secs2Date(cinfoPB.hFileInfo.ioFlMdDat, &dt); Secs2Date(cinfoPB.hFileInfo.ioFlCrDat, &dtc); buf->st_size = cinfoPB.hFileInfo.ioFlLgLen + cinfoPB.hFileInfo.ioFlRLgLen; } buf->st_mtime = _gmtotime_t( dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second ); buf->st_atime = buf->st_mtime; buf->st_ctime = _gmtotime_t( dtc.year, dtc.month, dtc.day, dtc.hour, dtc.minute, dtc.second ); buf->st_nlink = 1; buf->st_uid = buf->st_gid = buf->st_ino = 0; buf->st_mode = _dtoxmode(&cinfoPB); /* get volume number and map it to st_dev/rdev */ hparamBlock.volumeParam.ioNamePtr = szBuf; hparamBlock.volumeParam.ioVRefNum = 0; hparamBlock.volumeParam.ioVolIndex = 0; osErr = PBHGetVInfoSync(&hparamBlock); if (osErr != noErr) return -1; buf->st_rdev = buf->st_dev = hparamBlock.volumeParam.ioVRefNum; return(0); } #endif /* _MAC */