home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / stat.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  16KB  |  548 lines

  1. /***
  2. *stat.c - get file status
  3. *
  4. *       Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       defines _stat() - get file status
  8. *
  9. *******************************************************************************/
  10.  
  11. #ifndef _MAC
  12.  
  13. #include <cruntime.h>
  14. #include <sys/types.h>
  15. #include <sys/stat.h>
  16. #include <errno.h>
  17. #include <ctype.h>
  18. #include <msdos.h>
  19. #include <dostypes.h>
  20. #include <oscalls.h>
  21. #include <string.h>
  22. #include <internal.h>
  23. #include <stdlib.h>
  24. #include <direct.h>
  25. #include <mbstring.h>
  26. #include <tchar.h>
  27.  
  28.  
  29. #define ISSLASH(a)  ((a) == _T('\\') || (a) == _T('/'))
  30.  
  31.  
  32. #ifdef _UNICODE
  33. #define __tdtoxmode __wdtoxmode
  34. #else  /* _UNICODE */
  35. #define __tdtoxmode __dtoxmode
  36. #endif  /* _UNICODE */
  37.  
  38.  
  39. /*
  40.  * Local routine which returns true if the argument is a UNC name
  41.  * specifying the root name of a share, such as '\\server\share\'.
  42.  */
  43.  
  44. static int IsRootUNCName(const _TSCHAR *path);
  45.  
  46.  
  47. /***
  48. *unsigned __tdtoxmode(attr, name) -
  49. *
  50. *Purpose:
  51. *
  52. *Entry:
  53. *
  54. *Exit:
  55. *
  56. *Exceptions:
  57. *
  58. *******************************************************************************/
  59.  
  60. #ifdef _USE_INT64
  61.  
  62. extern unsigned short __cdecl __tdtoxmode(int, const _TSCHAR *);
  63.  
  64. #else  /* _USE_INT64 */
  65.  
  66. unsigned short __cdecl __tdtoxmode (
  67.         int attr,
  68.         const _TSCHAR *name
  69.         )
  70. {
  71.         REG1 unsigned short uxmode;
  72.         unsigned dosmode;
  73.         REG2 const _TSCHAR *p;
  74.  
  75.         dosmode = attr & 0xff;
  76.         if ((p = name)[1] == _T(':'))
  77.             p += 2;
  78.  
  79.         /* check to see if this is a directory - note we must make a special
  80.         * check for the root, which DOS thinks is not a directory
  81.         */
  82.  
  83.         uxmode = (unsigned short)
  84.                  (((ISSLASH(*p) && !p[1]) || (dosmode & A_D) || !*p)
  85.                  ? _S_IFDIR|_S_IEXEC : _S_IFREG);
  86.  
  87.         /* If attribute byte does not have read-only bit, it is read-write */
  88.  
  89.         uxmode |= (dosmode & A_RO) ? _S_IREAD : (_S_IREAD|_S_IWRITE);
  90.  
  91.         /* see if file appears to be executable - check extension of name */
  92.  
  93.         if (p = _tcsrchr(name, _T('.'))) {
  94.             if ( !_tcsicmp(p, _T(".exe")) ||
  95.                  !_tcsicmp(p, _T(".cmd")) ||
  96.                  !_tcsicmp(p, _T(".bat")) ||
  97.                  !_tcsicmp(p, _T(".com")) )
  98.                 uxmode |= _S_IEXEC;
  99.         }
  100.  
  101.         /* propagate user read/write/execute bits to group/other fields */
  102.  
  103.         uxmode |= (uxmode & 0700) >> 3;
  104.         uxmode |= (uxmode & 0700) >> 6;
  105.  
  106.         return(uxmode);
  107. }
  108.  
  109. #endif  /* _USE_INT64 */
  110.  
  111. /***
  112. *int _stat(name, buf) - get file status info
  113. *
  114. *Purpose:
  115. *       _stat obtains information about the file and stores it in the
  116. *       structure pointed to by buf.
  117. *
  118. *       Note: We cannot directly use the file time stamps returned in the
  119. *       WIN32_FIND_DATA structure. The values are supposedly in system time
  120. *       and system time is ambiguously defined (it is UTC for Windows NT, local
  121. *       time for Win32S and probably local time for Win32C). Therefore, these
  122. *       values must be converted to local time before than can be used.
  123. *
  124. *Entry:
  125. *       _TSCHAR *name -    pathname of given file
  126. *       struct _stat *buffer - pointer to buffer to store info in
  127. *
  128. *Exit:
  129. *       fills in structure pointed to by buffer
  130. *       returns 0 if successful
  131. *       returns -1 and sets errno if unsuccessful
  132. *
  133. *Exceptions:
  134. *
  135. *******************************************************************************/
  136.  
  137. #ifdef _USE_INT64
  138.  
  139. int __cdecl _tstati64 (
  140.         REG1 const _TSCHAR *name,
  141.         REG2 struct _stati64 *buf
  142.         )
  143.  
  144. #else  /* _USE_INT64 */
  145.  
  146. int __cdecl _tstat (
  147.         REG1 const _TSCHAR *name,
  148.         REG2 struct _stat *buf
  149.         )
  150.  
  151. #endif  /* _USE_INT64 */
  152.  
  153. {
  154.         _TSCHAR *  path;
  155.         _TSCHAR    pathbuf[ _MAX_PATH ];
  156.         int drive;          /* A: = 1, B: = 2, etc. */
  157.         HANDLE findhandle;
  158.         WIN32_FIND_DATA findbuf;
  159.  
  160.         /* Don't allow wildcards to be interpreted by system */
  161.  
  162. #ifdef _UNICODE
  163.         if (wcspbrk(name, L"?*")) {
  164. #else  /* _UNICODE */
  165.         if (_mbspbrk(name, "?*")) {
  166. #endif  /* _UNICODE */
  167.             errno = ENOENT;
  168.             _doserrno = E_nofile;
  169.             return(-1);
  170.         }
  171.  
  172.         /* Try to get disk from name.  If none, get current disk.  */
  173.  
  174.         if (name[1] == _T(':')){
  175.             if ( *name && !name[2] ){
  176.                 errno = ENOENT;             /* return an error if name is   */
  177.                 _doserrno = E_nofile;       /* just drive letter then colon */
  178.                 return( -1 );
  179.             }
  180.             drive = _totlower(*name) - _T('a') + 1;
  181.         }
  182.         else
  183.             drive = _getdrive();
  184.  
  185.         /* Call Find Match File */
  186.         findhandle = FindFirstFile((_TSCHAR *)name, &findbuf);
  187.         if ( findhandle == INVALID_HANDLE_VALUE ) {
  188. #ifdef _UNICODE
  189.             if ( !( wcspbrk(name, L"./\\") &&
  190. #else  /* _UNICODE */
  191.             if ( !( _mbspbrk(name, "./\\") &&
  192. #endif  /* _UNICODE */
  193.                  (path = _tfullpath( pathbuf, name, _MAX_PATH )) &&
  194.                  /* root dir. ('C:\') or UNC root dir. ('\\server\share\') */
  195.                  ((_tcslen( path ) == 3) || IsRootUNCName(path)) &&
  196.                  (GetDriveType( path ) > 1) ) )
  197.             {
  198.                 errno = ENOENT;
  199.                 _doserrno = E_nofile;
  200.                 return( -1 );
  201.             }
  202.  
  203.             /*
  204.              * Root directories (such as C:\ or \\server\share\ are fabricated.
  205.              */
  206.  
  207.             findbuf.dwFileAttributes = A_D;
  208.             findbuf.nFileSizeHigh = 0;
  209.             findbuf.nFileSizeLow = 0;
  210.             findbuf.cFileName[0] = _T('\0');
  211.  
  212.             buf->st_mtime = __loctotime_t(1980,1,1,0,0,0, -1);
  213.             buf->st_atime = buf->st_mtime;
  214.             buf->st_ctime = buf->st_mtime;
  215.         }
  216.         else {
  217.             SYSTEMTIME SystemTime;
  218.             FILETIME LocalFTime;
  219.  
  220.             if ( !FileTimeToLocalFileTime( &findbuf.ftLastWriteTime,
  221.                                            &LocalFTime )            ||
  222.                  !FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
  223.             {
  224.                 _dosmaperr( GetLastError() );
  225.                 FindClose( findhandle );
  226.                 return( -1 );
  227.             }
  228.  
  229.             buf->st_mtime = __loctotime_t( SystemTime.wYear,
  230.                                            SystemTime.wMonth,
  231.                                            SystemTime.wDay,
  232.                                            SystemTime.wHour,
  233.                                            SystemTime.wMinute,
  234.                                            SystemTime.wSecond,
  235.                                            -1 );
  236.  
  237.             if ( findbuf.ftLastAccessTime.dwLowDateTime ||
  238.                  findbuf.ftLastAccessTime.dwHighDateTime )
  239.             {
  240.                 if ( !FileTimeToLocalFileTime( &findbuf.ftLastAccessTime,
  241.                                                &LocalFTime )                ||
  242.                      !FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
  243.                 {
  244.                     _dosmaperr( GetLastError() );
  245.                     FindClose( findhandle );
  246.                     return( -1 );
  247.                 }
  248.  
  249.                 buf->st_atime = __loctotime_t( SystemTime.wYear,
  250.                                                SystemTime.wMonth,
  251.                                                SystemTime.wDay,
  252.                                                SystemTime.wHour,
  253.                                                SystemTime.wMinute,
  254.                                                SystemTime.wSecond,
  255.                                                -1 );
  256.             } else
  257.                 buf->st_atime = buf->st_mtime ;
  258.  
  259.             if ( findbuf.ftCreationTime.dwLowDateTime ||
  260.                  findbuf.ftCreationTime.dwHighDateTime )
  261.             {
  262.                 if ( !FileTimeToLocalFileTime( &findbuf.ftCreationTime,
  263.                                                &LocalFTime )                ||
  264.                      !FileTimeToSystemTime( &LocalFTime, &SystemTime ) )
  265.                 {
  266.                     _dosmaperr( GetLastError() );
  267.                     FindClose( findhandle );
  268.                     return( -1 );
  269.                 }
  270.  
  271.                 buf->st_ctime = __loctotime_t( SystemTime.wYear,
  272.                                                SystemTime.wMonth,
  273.                                                SystemTime.wDay,
  274.                                                SystemTime.wHour,
  275.                                                SystemTime.wMinute,
  276.                                                SystemTime.wSecond,
  277.                                                -1 );
  278.             } else
  279.                 buf->st_ctime = buf->st_mtime ;
  280.  
  281.             FindClose(findhandle);
  282.         }
  283.  
  284.         /* Fill in buf */
  285.  
  286.         buf->st_mode = __tdtoxmode(findbuf.dwFileAttributes, name);
  287.         buf->st_nlink = 1;
  288.  
  289. #ifdef _USE_INT64
  290.         buf->st_size = ((__int64)(findbuf.nFileSizeHigh)) * (0x100000000i64) +
  291.                         (__int64)(findbuf.nFileSizeLow);
  292. #else  /* _USE_INT64 */
  293.         buf->st_size = findbuf.nFileSizeLow;
  294. #endif  /* _USE_INT64 */
  295.  
  296.         /* now set the common fields */
  297.  
  298.         buf->st_uid = buf->st_gid = buf->st_ino = 0;
  299.  
  300.         buf->st_rdev = buf->st_dev = (_dev_t)(drive - 1); /* A=0, B=1, etc. */
  301.  
  302.         return(0);
  303. }
  304.  
  305.  
  306. /*
  307.  * IsRootUNCName - returns TRUE if the argument is a UNC name specifying
  308.  *      a root share.  That is, if it is of the form \\server\share\.
  309.  *      This routine will also return true if the argument is of the
  310.  *      form \\server\share (no trailing slash) but Win32 currently
  311.  *      does not like that form.
  312.  *
  313.  *      Forward slashes ('/') may be used instead of backslashes ('\').
  314.  */
  315.  
  316. static int IsRootUNCName(const _TSCHAR *path)
  317. {
  318.         /*
  319.          * If a root UNC name, path will start with 2 (but not 3) slashes
  320.          */
  321.  
  322.         if ( ( _tcslen ( path ) >= 5 ) /* minimum string is "//x/y" */
  323.              && ISSLASH(path[0]) && ISSLASH(path[1]))
  324.         {
  325.             const _TSCHAR * p = path + 2 ;
  326.  
  327.             /*
  328.              * find the slash between the server name and share name
  329.              */
  330.             while ( * ++ p )
  331.                 if ( ISSLASH(*p) )
  332.                     break ;
  333.  
  334.             if ( *p && p[1] )
  335.             {
  336.                 /*
  337.                  * is there a further slash?
  338.                  */
  339.                 while ( * ++ p )
  340.                     if ( ISSLASH(*p) )
  341.                         break ;
  342.  
  343.                 /*
  344.                  * just final slash (or no final slash)
  345.                  */
  346.                 if ( !*p || !p[1])
  347.                     return 1;
  348.             }
  349.         }
  350.  
  351.         return 0 ;
  352. }
  353.  
  354.  
  355. #else  /* _MAC */
  356.  
  357.  
  358. #include <cruntime.h>
  359. #include <sys/types.h>
  360. #include <sys/stat.h>
  361. #include <errno.h>
  362. #include <ctype.h>
  363. #include <string.h>
  364. #include <internal.h>
  365. #include <stdlib.h>
  366. #include <direct.h>
  367. #include <macos\osutils.h>
  368. #include <macos\files.h>
  369. #include <macos\errors.h>
  370.  
  371. #ifdef _MBCS
  372. #include <mbstring.h>
  373. #define STRPBRK _mbspbrk
  374. #else  /* _MBCS */
  375. #define STRPBRK strpbrk
  376. #endif  /* _MBCS */
  377.  
  378.  
  379. unsigned short __cdecl _dtoxmode ( CInfoPBPtr pcinfoPB );
  380.  
  381. /***
  382. *unsigned _dtoxmode(CInfoPBPtr) -
  383. *
  384. *Purpose:
  385. *
  386. *Entry:
  387. *
  388. *Exit:
  389. *
  390. *Exceptions:
  391. *
  392. *******************************************************************************/
  393.  
  394. unsigned short __cdecl _dtoxmode (
  395.         CInfoPBPtr pcinfoPB
  396.         )
  397. {
  398.         REG1 unsigned short uxmode;
  399.         unsigned char dosmode;
  400.         int fReadOnly;
  401.  
  402.         dosmode = pcinfoPB->hFileInfo.ioFlAttrib;
  403.  
  404.         /* file or dir */
  405.         if (dosmode & 0x10)
  406.         {
  407.             uxmode = _S_IFDIR;
  408.             fReadOnly = pcinfoPB->dirInfo.ioDrUsrWds.frFlags == fsRdPerm;
  409.         }
  410.         else
  411.         {
  412.             uxmode = _S_IFREG;
  413.             fReadOnly = pcinfoPB->hFileInfo.ioFlFndrInfo.fdFlags == fsRdPerm;
  414.             /* see if file appears to be executable - check 'APPL'? */
  415.             if (pcinfoPB->hFileInfo.ioFlFndrInfo.fdType == 'APPL')
  416.                 uxmode |= _S_IEXEC;
  417.         }
  418.  
  419.  
  420.         /* If attribute byte has 0 bit set, file is locked, then read-only */
  421.  
  422.         uxmode |= (((dosmode & 0x01) || fReadOnly) ? _S_IREAD :
  423.                   (_S_IREAD|_S_IWRITE));
  424.  
  425.  
  426.         /* propagate user read/write/execute bits to group/other fields */
  427.  
  428.         uxmode |= (uxmode & 0700) >> 3;
  429.         uxmode |= (uxmode & 0700) >> 6;
  430.  
  431.         return(uxmode);
  432. }
  433.  
  434.  
  435. /***
  436. *int _stat(name, buf) - get file status info
  437. *
  438. *Purpose:
  439. *       _stat obtains information about the file and stores it in the structure
  440. *       pointed to by buf.
  441. *
  442. *Entry:
  443. *       char *name -    pathname of given file
  444. *       struct _stat *buffer - pointer to buffer to store info in
  445. *
  446. *Exit:
  447. *       fills in structure pointed to by buffer
  448. *       returns 0 if successful
  449. *       returns -1 and sets errno if unsuccessful
  450. *
  451. *Exceptions:
  452. *
  453. *******************************************************************************/
  454.  
  455. int __cdecl _stat (
  456.         REG1 const char *name,
  457.         REG2 struct _stat *buf
  458.         )
  459. {
  460.         CInfoPBRec cinfoPB;
  461.         OSErr osErr;
  462.         char szBuf[256];
  463.         DateTimeRec dt;
  464.         DateTimeRec dtc;
  465.         HParamBlockRec hparamBlock;
  466.  
  467.  
  468.         if (!*name)
  469.         {
  470.             errno = ENOENT;
  471.             return -1;
  472.         }
  473.  
  474.         strcpy(szBuf, name);
  475.         cinfoPB.hFileInfo.ioNamePtr = _c2pstr(szBuf);
  476.         cinfoPB.hFileInfo.ioFDirIndex = 0;
  477.         cinfoPB.hFileInfo.ioVRefNum = 0;
  478.         cinfoPB.hFileInfo.ioDirID = 0;
  479.  
  480.         osErr = PBGetCatInfoSync(&cinfoPB);
  481.         switch (osErr)
  482.         {
  483.             case noErr:
  484.                 break;
  485.             case bdNamErr:
  486.             case dirNFErr:
  487.             case extFSErr:
  488.             case fnfErr:
  489.             case ioErr:
  490.             case nsvErr:
  491.             case paramErr:
  492.                 errno = ENOENT;
  493.                 return -1;
  494.             default:
  495.                 return -1;
  496.         }
  497.  
  498.  
  499.         /* file or dir ? */
  500.         if (cinfoPB.hFileInfo.ioFlAttrib & 0x10)
  501.         {   /*dir*/
  502.             Secs2Date(cinfoPB.dirInfo.ioDrMdDat, &dt);
  503.             Secs2Date(cinfoPB.dirInfo.ioDrCrDat, &dtc);
  504.             buf->st_size = 0;
  505.         }
  506.         else
  507.         {   /*file*/
  508.             Secs2Date(cinfoPB.hFileInfo.ioFlMdDat, &dt);
  509.             Secs2Date(cinfoPB.hFileInfo.ioFlCrDat, &dtc);
  510.             buf->st_size = cinfoPB.hFileInfo.ioFlLgLen +
  511.                            cinfoPB.hFileInfo.ioFlRLgLen;
  512.         }
  513.  
  514.         buf->st_mtime = _gmtotime_t( dt.year,
  515.                                      dt.month,
  516.                                      dt.day,
  517.                                      dt.hour,
  518.                                      dt.minute,
  519.                                      dt.second );
  520.  
  521.         buf->st_atime = buf->st_mtime;
  522.         buf->st_ctime = _gmtotime_t( dtc.year,
  523.                                      dtc.month,
  524.                                      dtc.day,
  525.                                      dtc.hour,
  526.                                      dtc.minute,
  527.                                      dtc.second );
  528.  
  529.         buf->st_nlink = 1;
  530.         buf->st_uid = buf->st_gid = buf->st_ino = 0;
  531.  
  532.         buf->st_mode = _dtoxmode(&cinfoPB);
  533.  
  534.         /* get volume number and map it to st_dev/rdev */
  535.         hparamBlock.volumeParam.ioNamePtr = szBuf;
  536.         hparamBlock.volumeParam.ioVRefNum = 0;
  537.         hparamBlock.volumeParam.ioVolIndex = 0;
  538.         osErr = PBHGetVInfoSync(&hparamBlock);
  539.         if (osErr != noErr)
  540.             return -1;
  541.  
  542.         buf->st_rdev = buf->st_dev = hparamBlock.volumeParam.ioVRefNum;
  543.  
  544.         return(0);
  545. }
  546.  
  547. #endif  /* _MAC */
  548.