(root)/
glib-2.79.0/
glib/
dirent/
dirent.c
       1  /*
       2   * dirent.c
       3   * This file has no copyright assigned and is placed in the Public Domain.
       4   * This file is a part of the mingw-runtime package.
       5   * No warranty is given; refer to the file DISCLAIMER within the package.
       6   *
       7   * Derived from DIRLIB.C by Matt J. Weinstein
       8   * This note appears in the DIRLIB.H
       9   * DIRLIB.H by M. J. Weinstein   Released to public domain 1-Jan-89
      10   *
      11   * Updated by Jeremy Bettis <jeremy@hksys.com>
      12   * Significantly revised and rewinddir, seekdir and telldir added by Colin
      13   * Peters <colin@fu.is.saga-u.ac.jp>
      14   *	
      15   */
      16  
      17  #include <stdlib.h>
      18  #include <errno.h>
      19  #include <string.h>
      20  #include <io.h>
      21  #include <direct.h>
      22  
      23  #include "dirent.h"
      24  
      25  #define WIN32_LEAN_AND_MEAN
      26  #include <windows.h> /* for GetFileAttributes */
      27  
      28  #include <tchar.h>
      29  
      30  #ifdef _UNICODE
      31  #define _tdirent	_wdirent
      32  #define _TDIR 		_WDIR
      33  #define _topendir	_wopendir
      34  #define _tclosedir	_wclosedir
      35  #define _treaddir	_wreaddir
      36  #define _trewinddir	_wrewinddir
      37  #define _ttelldir	_wtelldir
      38  #define _tseekdir	_wseekdir
      39  #else
      40  #define _tdirent	dirent
      41  #define _TDIR 		DIR
      42  #define _topendir	opendir
      43  #define _tclosedir	closedir
      44  #define _treaddir	readdir
      45  #define _trewinddir	rewinddir
      46  #define _ttelldir	telldir
      47  #define _tseekdir	seekdir
      48  #endif
      49  
      50  #define SUFFIX	_T("*")
      51  #define	SLASH	_T("\\")
      52  
      53  
      54  /*
      55   * opendir
      56   *
      57   * Returns a pointer to a DIR structure appropriately filled in to begin
      58   * searching a directory.
      59   */
      60  _TDIR *
      61  _topendir (const _TCHAR *szPath)
      62  {
      63    _TDIR *nd;
      64    unsigned int rc;
      65    _TCHAR szFullPath[MAX_PATH];
      66  	
      67    errno = 0;
      68  
      69    if (!szPath)
      70      {
      71        errno = EFAULT;
      72        return (_TDIR *) 0;
      73      }
      74  
      75    if (szPath[0] == _T('\0'))
      76      {
      77        errno = ENOTDIR;
      78        return (_TDIR *) 0;
      79      }
      80  
      81    /* Attempt to determine if the given path really is a directory. */
      82    rc = GetFileAttributes (szPath);
      83    if (rc == (unsigned int)-1)
      84      {
      85        /* call GetLastError for more error info */
      86        errno = ENOENT;
      87        return (_TDIR *) 0;
      88      }
      89    if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
      90      {
      91        /* Error, entry exists but not a directory. */
      92        errno = ENOTDIR;
      93        return (_TDIR *) 0;
      94      }
      95  
      96    /* Make an absolute pathname.  */
      97    _tfullpath (szFullPath, szPath, MAX_PATH);
      98  
      99    /* Allocate enough space to store DIR structure and the complete
     100     * directory path given. */
     101    nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen(szFullPath) + _tcslen (SLASH) +
     102  			 _tcslen(SUFFIX) + 1) * sizeof(_TCHAR));
     103  
     104    if (!nd)
     105      {
     106        /* Error, out of memory. */
     107        errno = ENOMEM;
     108        return (_TDIR *) 0;
     109      }
     110  
     111    /* Create the search expression. */
     112    _tcscpy (nd->dd_name, szFullPath);
     113  
     114    /* Add on a slash if the path does not end with one. */
     115    if (nd->dd_name[0] != _T('\0') &&
     116        nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('/') &&
     117        nd->dd_name[_tcslen (nd->dd_name) - 1] != _T('\\'))
     118      {
     119        _tcscat (nd->dd_name, SLASH);
     120      }
     121  
     122    /* Add on the search pattern */
     123    _tcscat (nd->dd_name, SUFFIX);
     124  
     125    /* Initialize handle to -1 so that a premature closedir doesn't try
     126     * to call _findclose on it. */
     127    nd->dd_handle = -1;
     128  
     129    /* Initialize the status. */
     130    nd->dd_stat = 0;
     131  
     132    /* Initialize the dirent structure. ino and reclen are invalid under
     133     * Win32, and name simply points at the appropriate part of the
     134     * findfirst_t structure. */
     135    nd->dd_dir.d_ino = 0;
     136    nd->dd_dir.d_reclen = 0;
     137    nd->dd_dir.d_namlen = 0;
     138    memset (nd->dd_dir.d_name, 0, sizeof (nd->dd_dir.d_name));
     139  
     140    return nd;
     141  }
     142  
     143  
     144  /*
     145   * readdir
     146   *
     147   * Return a pointer to a dirent structure filled with the information on the
     148   * next entry in the directory.
     149   */
     150  struct _tdirent *
     151  _treaddir (_TDIR * dirp)
     152  {
     153    errno = 0;
     154  
     155    /* Check for valid DIR struct. */
     156    if (!dirp)
     157      {
     158        errno = EFAULT;
     159        return (struct _tdirent *) 0;
     160      }
     161  
     162    if (dirp->dd_stat < 0)
     163      {
     164        /* We have already returned all files in the directory
     165         * (or the structure has an invalid dd_stat). */
     166        return (struct _tdirent *) 0;
     167      }
     168    else if (dirp->dd_stat == 0)
     169      {
     170        /* We haven't started the search yet. */
     171        /* Start the search */
     172        dirp->dd_handle = _tfindfirst (dirp->dd_name, &(dirp->dd_dta));
     173  
     174    	  if (dirp->dd_handle == -1)
     175  	{
     176  	  /* Whoops! Seems there are no files in that
     177  	   * directory. */
     178  	  dirp->dd_stat = -1;
     179  	}
     180        else
     181  	{
     182  	  dirp->dd_stat = 1;
     183  	}
     184      }
     185    else
     186      {
     187        /* Get the next search entry. */
     188        if (_tfindnext (dirp->dd_handle, &(dirp->dd_dta)))
     189  	{
     190  	  /* We are off the end or otherwise error.	
     191  	     _findnext sets errno to ENOENT if no more file
     192  	     Undo this. */
     193  	  DWORD winerr = GetLastError();
     194  	  if (winerr == ERROR_NO_MORE_FILES)
     195  	    errno = 0;	
     196  	  _findclose (dirp->dd_handle);
     197  	  dirp->dd_handle = -1;
     198  	  dirp->dd_stat = -1;
     199  	}
     200        else
     201  	{
     202  	  /* Update the status to indicate the correct
     203  	   * number. */
     204  	  dirp->dd_stat++;
     205  	}
     206      }
     207  
     208    if (dirp->dd_stat > 0)
     209      {
     210        /* Successfully got an entry. Everything about the file is
     211         * already appropriately filled in except the length of the
     212         * file name. */
     213        dirp->dd_dir.d_namlen = _tcslen (dirp->dd_dta.name);
     214        _tcscpy (dirp->dd_dir.d_name, dirp->dd_dta.name);
     215        return &dirp->dd_dir;
     216      }
     217  
     218    return (struct _tdirent *) 0;
     219  }
     220  
     221  
     222  /*
     223   * closedir
     224   *
     225   * Frees up resources allocated by opendir.
     226   */
     227  int
     228  _tclosedir (_TDIR * dirp)
     229  {
     230    int rc;
     231  
     232    errno = 0;
     233    rc = 0;
     234  
     235    if (!dirp)
     236      {
     237        errno = EFAULT;
     238        return -1;
     239      }
     240  
     241    if (dirp->dd_handle != -1)
     242      {
     243        rc = _findclose (dirp->dd_handle);
     244      }
     245  
     246    /* Delete the dir structure. */
     247    free (dirp);
     248  
     249    return rc;
     250  }
     251  
     252  /*
     253   * rewinddir
     254   *
     255   * Return to the beginning of the directory "stream". We simply call findclose
     256   * and then reset things like an opendir.
     257   */
     258  void
     259  _trewinddir (_TDIR * dirp)
     260  {
     261    errno = 0;
     262  
     263    if (!dirp)
     264      {
     265        errno = EFAULT;
     266        return;
     267      }
     268  
     269    if (dirp->dd_handle != -1)
     270      {
     271        _findclose (dirp->dd_handle);
     272      }
     273  
     274    dirp->dd_handle = -1;
     275    dirp->dd_stat = 0;
     276  }
     277  
     278  /*
     279   * telldir
     280   *
     281   * Returns the "position" in the "directory stream" which can be used with
     282   * seekdir to go back to an old entry. We simply return the value in stat.
     283   */
     284  long
     285  _ttelldir (_TDIR * dirp)
     286  {
     287    errno = 0;
     288  
     289    if (!dirp)
     290      {
     291        errno = EFAULT;
     292        return -1;
     293      }
     294    return dirp->dd_stat;
     295  }
     296  
     297  /*
     298   * seekdir
     299   *
     300   * Seek to an entry previously returned by telldir. We rewind the directory
     301   * and call readdir repeatedly until either dd_stat is the position number
     302   * or -1 (off the end). This is not perfect, in that the directory may
     303   * have changed while we weren't looking. But that is probably the case with
     304   * any such system.
     305   */
     306  void
     307  _tseekdir (_TDIR * dirp, long lPos)
     308  {
     309    errno = 0;
     310  
     311    if (!dirp)
     312      {
     313        errno = EFAULT;
     314        return;
     315      }
     316  
     317    if (lPos < -1)
     318      {
     319        /* Seeking to an invalid position. */
     320        errno = EINVAL;
     321        return;
     322      }
     323    else if (lPos == -1)
     324      {
     325        /* Seek past end. */
     326        if (dirp->dd_handle != -1)
     327  	{
     328  	  _findclose (dirp->dd_handle);
     329  	}
     330        dirp->dd_handle = -1;
     331        dirp->dd_stat = -1;
     332      }
     333    else
     334      {
     335        /* Rewind and read forward to the appropriate index. */
     336        _trewinddir (dirp);
     337  
     338        while ((dirp->dd_stat < lPos) && _treaddir (dirp))
     339  	;
     340      }
     341  }