diff options
author | Christopher Faylor <me@cgf.cx> | 2000-02-17 22:38:31 +0300 |
---|---|---|
committer | Christopher Faylor <me@cgf.cx> | 2000-02-17 22:38:31 +0300 |
commit | 369d8a8fd5e887eca547bf34bccfdf755c9e5397 (patch) | |
tree | 5c5dc851bf01a5938662571357ffd5d7bb152a79 /winsup/mingw/dirent.c | |
parent | 4415a7ef3e26c669f5f7c5c7efbf7b6ea9b7e2f4 (diff) |
import winsup-2000-02-17 snapshot
Diffstat (limited to 'winsup/mingw/dirent.c')
-rw-r--r-- | winsup/mingw/dirent.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/winsup/mingw/dirent.c b/winsup/mingw/dirent.c new file mode 100644 index 000000000..00041d76e --- /dev/null +++ b/winsup/mingw/dirent.c @@ -0,0 +1,313 @@ +/* + * dirent.c + * + * Derived from DIRLIB.C by Matt J. Weinstein + * This note appears in the DIRLIB.H + * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 + * + * Updated by Jeremy Bettis <jeremy@hksys.com> + * Significantly revised and rewinddir, seekdir and telldir added by Colin + * Peters <colin@fu.is.saga-u.ac.jp> + * + * $Revision$ + * $Author$ + * $Date$ + * + */ + +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <io.h> +#include <direct.h> +#include <sys/stat.h> + +#include <dirent.h> + +#define SUFFIX "*" +#define SLASH "\\" + +/* + * opendir + * + * Returns a pointer to a DIR structure appropriately filled in to begin + * searching a directory. + */ +DIR * +opendir (const char *szPath) +{ + DIR *nd; + struct _stat statDir; + + errno = 0; + + if (!szPath) + { + errno = EFAULT; + return (DIR *) 0; + } + + if (szPath[0] == '\0') + { + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Attempt to determine if the given path really is a directory. */ + if (_stat (szPath, &statDir)) + { + /* Error, stat should have set an error value. */ + return (DIR *) 0; + } + + if (!S_ISDIR (statDir.st_mode)) + { + /* Error, stat reports not a directory. */ + errno = ENOTDIR; + return (DIR *) 0; + } + + /* Allocate enough space to store DIR structure and the complete + * directory path given. */ + nd = (DIR *) malloc (sizeof (DIR) + strlen (szPath) + strlen (SLASH) + + strlen (SUFFIX)); + + if (!nd) + { + /* Error, out of memory. */ + errno = ENOMEM; + return (DIR *) 0; + } + + /* Create the search expression. */ + strcpy (nd->dd_name, szPath); + + /* Add on a slash if the path does not end with one. */ + if (nd->dd_name[0] != '\0' && + nd->dd_name[strlen (nd->dd_name) - 1] != '/' && + nd->dd_name[strlen (nd->dd_name) - 1] != '\\') + { + strcat (nd->dd_name, SLASH); + } + + /* Add on the search pattern */ + strcat (nd->dd_name, SUFFIX); + + /* Initialize handle to -1 so that a premature closedir doesn't try + * to call _findclose on it. */ + nd->dd_handle = -1; + + /* Initialize the status. */ + nd->dd_stat = 0; + + /* Initialize the dirent structure. ino and reclen are invalid under + * Win32, and name simply points at the appropriate part of the + * findfirst_t structure. */ + nd->dd_dir.d_ino = 0; + nd->dd_dir.d_reclen = 0; + nd->dd_dir.d_namlen = 0; + nd->dd_dir.d_name = nd->dd_dta.name; + + return nd; +} + + +/* + * readdir + * + * Return a pointer to a dirent structure filled with the information on the + * next entry in the directory. + */ +struct dirent * +readdir (DIR * dirp) +{ + errno = 0; + + /* Check for valid DIR struct. */ + if (!dirp) + { + errno = EFAULT; + return (struct dirent *) 0; + } + + if (dirp->dd_dir.d_name != dirp->dd_dta.name) + { + /* The structure does not seem to be set up correctly. */ + errno = EINVAL; + return (struct dirent *) 0; + } + + if (dirp->dd_stat < 0) + { + /* We have already returned all files in the directory + * (or the structure has an invalid dd_stat). */ + return (struct dirent *) 0; + } + else if (dirp->dd_stat == 0) + { + /* We haven't started the search yet. */ + /* Start the search */ + dirp->dd_handle = _findfirst (dirp->dd_name, &(dirp->dd_dta)); + + if (dirp->dd_handle == -1) + { + /* Whoops! Seems there are no files in that + * directory. */ + dirp->dd_stat = -1; + } + else + { + dirp->dd_stat = 1; + } + } + else + { + /* Get the next search entry. */ + if (_findnext (dirp->dd_handle, &(dirp->dd_dta))) + { + /* We are off the end or otherwise error. */ + _findclose (dirp->dd_handle); + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Update the status to indicate the correct + * number. */ + dirp->dd_stat++; + } + } + + if (dirp->dd_stat > 0) + { + /* Successfully got an entry. Everything about the file is + * already appropriately filled in except the length of the + * file name. */ + dirp->dd_dir.d_namlen = strlen (dirp->dd_dir.d_name); + return &dirp->dd_dir; + } + + return (struct dirent *) 0; +} + + +/* + * closedir + * + * Frees up resources allocated by opendir. + */ +int +closedir (DIR * dirp) +{ + int rc; + + errno = 0; + rc = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + + if (dirp->dd_handle != -1) + { + rc = _findclose (dirp->dd_handle); + } + + /* Delete the dir structure. */ + free (dirp); + + return rc; +} + +/* + * rewinddir + * + * Return to the beginning of the directory "stream". We simply call findclose + * and then reset things like an opendir. + */ +void +rewinddir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + + dirp->dd_handle = -1; + dirp->dd_stat = 0; +} + +/* + * telldir + * + * Returns the "position" in the "directory stream" which can be used with + * seekdir to go back to an old entry. We simply return the value in stat. + */ +long +telldir (DIR * dirp) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return -1; + } + return dirp->dd_stat; +} + +/* + * seekdir + * + * Seek to an entry previously returned by telldir. We rewind the directory + * and call readdir repeatedly until either dd_stat is the position number + * or -1 (off the end). This is not perfect, in that the directory may + * have changed while we weren't looking. But that is probably the case with + * any such system. + */ +void +seekdir (DIR * dirp, long lPos) +{ + errno = 0; + + if (!dirp) + { + errno = EFAULT; + return; + } + + if (lPos < -1) + { + /* Seeking to an invalid position. */ + errno = EINVAL; + return; + } + else if (lPos == -1) + { + /* Seek past end. */ + if (dirp->dd_handle != -1) + { + _findclose (dirp->dd_handle); + } + dirp->dd_handle = -1; + dirp->dd_stat = -1; + } + else + { + /* Rewind and read forward to the appropriate index. */ + rewinddir (dirp); + + while ((dirp->dd_stat < lPos) && readdir (dirp)) + ; + } +} |