diff options
Diffstat (limited to 'winsup/mingw/mingwex/dirent.c')
-rw-r--r-- | winsup/mingw/mingwex/dirent.c | 468 |
1 files changed, 0 insertions, 468 deletions
diff --git a/winsup/mingw/mingwex/dirent.c b/winsup/mingw/mingwex/dirent.c deleted file mode 100644 index a6b37408b..000000000 --- a/winsup/mingw/mingwex/dirent.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * dirent.c - * - * This file has no copyright assigned and is placed in the Public Domain. - * - * This file is a part of the mingw-runtime package. - * No warranty is given; refer to the file DISCLAIMER within the package. - * - * 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> - * Further significantly revised for improved memory utilisation, - * efficiency in operation, and better POSIX standards compliance - * by Keith Marshall <keithmarshall@users.sourceforge.net> - * - */ -#include <stdlib.h> -#include <errno.h> -#include <string.h> -#include <io.h> -#include <dirent.h> - -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <tchar.h> - -#define DIRENT_RETURN_NOTHING -#define DIRENT_REJECT( chk, err, rtn ) \ - do { if( chk ){ errno = (err); return rtn; }} while(0) - -union __dirstream_t -{ - /* Actual (private) declaration for opaque data type "DIR". */ - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct dirent dd_dir; - - struct __dirstream_private_t - { - /* Three padding fields, matching the head of dd_dir... - */ - long dd_ino; /* Always zero. */ - unsigned short dd_reclen; /* Always zero. */ - unsigned short dd_namlen; /* Length of name in d_name. */ - - /* ...to keep the start of this disk transfer area for this dir - * aligned at the offset of the dd_dir.d_type field - */ - struct _finddata_t dd_dta; - - /* _findnext handle */ - intptr_t dd_handle; - - /* Status of search: - * (type is now int -- was short in older versions). - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - char dd_name[1]; - - } dd_private; -}; - -union __wdirstream_t -{ - /* Actual (private) declaration for opaque data type "_WDIR". */ - - /* dirent struct to return from dir (NOTE: this makes this thread - * safe as long as only one thread uses a particular DIR struct at - * a time) */ - struct _wdirent dd_dir; - - struct __wdirstream_private_t - { - /* Three padding fields, matching the head of dd_dir... - */ - long dd_ino; /* Always zero. */ - unsigned short dd_reclen; /* Always zero. */ - unsigned short dd_namlen; /* Length of name in d_name. */ - - /* ...to keep the start of this disk transfer area for this dir - * aligned at the offset of the dd_dir.d_type field - */ - struct _wfinddata_t dd_dta; - - /* _findnext handle */ - intptr_t dd_handle; - - /* Status of search: - * 0 = not started yet (next entry to read is first entry) - * -1 = off the end - * positive = 0 based index of next entry - */ - int dd_stat; - - /* given path for dir with search pattern (struct is extended) */ - wchar_t dd_name[1]; - - } dd_private; -}; - -/* We map the BSD d_type field in the returned dirent structure - * from the Microsoft _finddata_t dd_dta.attrib bits, which are: - * - * _A_NORMAL (0x0000) normal file: best fit for DT_REG - * _A_RDONLY (0x0001) read-only: no BSD d_type equivalent - * _A_HIDDEN (0x0002) hidden entity: no BSD equivalent - * _A_SYSTEM (0x0004) system entity: no BSD equivalent - * _A_VOLID (0x0008) volume label: no BSD equivalent - * _A_SUBDIR (0x0010) directory: best fit for DT_DIR - * _A_ARCH (0x0020) "dirty": no BSD equivalent - * - * Of these, _A_RDONLY, _A_HIDDEN, _A_SYSTEM, and _A_ARCH are - * modifier bits, rather than true entity type specifiers; we - * will ignore them in the mapping, by applying this mask: - */ -#define DT_IGNORED (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH) - -#define DIRENT_OPEN(D) \ - ((D).dd_handle = _tfindfirst((D).dd_name, &((D).dd_dta))) - -#define DIRENT_UPDATE(D) \ - _tfindnext( (D).dd_handle, &(D).dd_dta ) - - -/***** - * - * opendir() - * - * Returns a pointer to a DIR structure appropriately filled in - * to begin searching a directory. - * - */ -_TDIR * -_topendir( const _TCHAR *path_name ) -{ - _TDIR *nd; - _TCHAR abs_path[MAX_PATH]; - - /* Reject any request which passes a NULL or an empty path name; - * note that POSIX doesn't specify the handling for the NULL case, - * and some implementations may simply fail with a segmentation - * fault. We will fail more gracefully. Previous versions used - * EFAULT here, but EINVAL seems more appropriate; however, POSIX - * specifies neither of these for any opendir() failure. - */ - DIRENT_REJECT( (path_name == NULL), EINVAL, (_TDIR *)(NULL) ); - /* - * Conversely, POSIX *does* specify ENOENT for the empty path - * name case, where we previously had ENOTDIR; here, we correct - * this previous anomaly. - */ - DIRENT_REJECT( (*path_name == _T('\0')), ENOENT, (_TDIR *)(NULL) ); - - /* Identify the absolute path name corresponding to the (maybe - * relative) path name we are to process; (this ensures that we - * may always refer back to this same path name, e.g. to rewind - * the "directory stream", even after an intervening change of - * current working directory). - */ - _tfullpath( abs_path, path_name, MAX_PATH ); - - /* Ensure that the generated absolute path name ends with a - * directory separator (backslash) character, so that we may - * correctly append a wild-card matching pattern which will - * cause _findfirst() and _findnext() to return every entry - * in the specified directory; (note that, for now we may - * simply assume that abs_path refers to a directory; - * we will verify that when we call _findfirst() on it). - */ - if( *abs_path != _T('\0') ) - { - size_t offset = _tcslen( abs_path ) - 1; - if( (abs_path[offset] != _T('/')) && (abs_path[offset] != _T('\\')) ) - _tcscat( abs_path, _T("\\") ); - } - - /* Now append the "match everything" wild-card pattern. - */ - _tcscat( abs_path, _T("*") ); - - /* Allocate space to store DIR structure. The size MUST be - * adjusted to accommodate the complete absolute path name for - * the specified directory, extended to include the wild-card - * matching pattern, as above; (note that we DO NOT need any - * special provision for the terminating NUL on the path name, - * since the base size of the DIR structure includes it). - */ - nd = (_TDIR *)(malloc( - sizeof( _TDIR ) + (_tcslen( abs_path ) * sizeof( _TCHAR )) - )); - - /* Bail out, if insufficient memory. - */ - DIRENT_REJECT( (nd == NULL), ENOMEM, (_TDIR *)(NULL) ); - - /* Copy the extended absolute path name string into place - * within the allocated space for the DIR structure. - */ - _tcscpy( nd->dd_private.dd_name, abs_path ); - - /* Initialize the "directory stream", by calling _findfirst() on it; - * this leaves the data for the first directory entry in the internal - * dirent buffer, ready to be retrieved by readdir(). - */ - if( DIRENT_OPEN( nd->dd_private ) == (intptr_t)(-1) ) - { - /* The _findfirst() call, (implied by DIRENT_OPEN), failed; - * _findfirst() sets EINVAL where POSIX mandates ENOTDIR... - */ - if( errno == EINVAL ) - errno = ENOTDIR; - - /* ...otherwise, while it may not be strictly POSIX conformant, - * just accept whatever value _findfirst() assigned to errno. In - * any event, prepare to return the NULL "directory stream"; since - * this implies that we will lose our reference pointer to the - * block of memory we allocated for the stream, free that - * before we bail out. - */ - free( nd ); - return (_TDIR *)(NULL); - } - - /* Initialize the status, (i.e. the location index), so that - * readdir() will simply return the first directory entry, which - * has already been fetched by _findfirst(), without performing - * an intervening _findnext() call. - */ - nd->dd_private.dd_stat = 0; - - /* The d_ino and d_reclen fields have no relevance in MS-Windows; - * initialize them to zero, as a one-time assignment for this DIR - * instance, and henceforth forget them; (users should simply - * ignore them). - */ - nd->dd_dir.d_ino = 0; - nd->dd_dir.d_reclen = 0; - - /* We've now completely initialized an instance of a DIR structure, - * representing the requested "directory stream"; return a pointer - * via which the caller may access it. - */ - return nd; -} - - -/***** - * - * readdir() - * - * Return a pointer to a dirent structure filled in with information - * on the next available entry, (if any), in the "directory stream". - */ -struct _tdirent * -_treaddir( _TDIR *dirp ) -{ - /* Check for a valid DIR stream reference; (we can't really - * be certain until we try to read from it, except in the case - * of a NULL pointer reference). Where we lack a valid reference, - * POSIX mandates reporting EBADF; we previously had EFAULT, so - * this version corrects the former anomaly. - */ - DIRENT_REJECT( (dirp == NULL), EBADF, (struct _tdirent *)(NULL) ); - - /* Okay to proceed. If this is the first readdir() request - * following an opendir(), or a rewinddir(), then we already - * have the requisite return information... - */ - if( dirp->dd_private.dd_stat++ > 0 ) - { - /* Otherwise... - * - * Get the next search entry. POSIX mandates that this must - * return NULL after the last entry has been read, but that it - * MUST NOT change errno in this case. MS-Windows _findnext() - * DOES change errno (to ENOENT) after the last entry has been - * read, so we must be prepared to restore it to its previous - * value, when no actual error has occurred. - */ - int prev_errno = errno; - if( DIRENT_UPDATE( dirp->dd_private ) != 0 ) - { - /* May be an error, or just the case described above... - */ - if( GetLastError() == ERROR_NO_MORE_FILES ) - /* - * ...which requires us to reset errno. - */ - errno = prev_errno; - - /* In either case, there is no valid data to return. - */ - return (struct _tdirent *)(NULL); - } - } - - /* Successfully got an entry. Everything about the file is - * already appropriately filled in, except for the length of - * the file name in the d_namlen field... - */ - dirp->dd_dir.d_namlen = _tcslen( dirp->dd_dir.d_name ); - /* - * ...and the attributes returned in the dd_dta.attrib field; - * these require adjustment to their BSD equivalents, which are - * returned via the union with the dd_dir.d_type field: - */ - switch( dirp->dd_dir.d_type &= ~DT_IGNORED ) - { - case DT_REG: - case DT_DIR: - /* After stripping out the modifier bits in DT_IGNORED, - * (which we ALWAYS ignore), this pair require no further - * adjustment... - */ - break; - - default: - /* ...while nothing else has an appropriate equivalent - * in the BSD d_type identification model. - */ - dirp->dd_dir.d_type = DT_UNKNOWN; - } - return &dirp->dd_dir; -} - - -/***** - * - * closedir() - * - * Frees up resources allocated by opendir(). - * - */ -int -_tclosedir( _TDIR * dirp ) -{ - /* Attempting to reference a directory stream via a NULL pointer - * would cause a segmentation fault; evade this. Since NULL can - * never represent an open directory stream, set the EBADF errno - * status, as mandated by POSIX, once again correcting previous - * anomalous use of EFAULT in this context. - */ - DIRENT_REJECT( - ((dirp == NULL) || (_findclose( dirp->dd_private.dd_handle ) != 0)), - EBADF, -1 - ); - - /* If we didn't bail out above, we have a valid DIR structure - * with which we have finished; release the memory allocated - * to it, before returning "success". - */ - free( dirp ); - return 0; -} - - -/***** - * - * rewinddir() - * - * Return to the beginning of the directory "stream". We simply call - * _findclose(), to clear prior context, then _findfirst() to restart - * the directory search, resetting the location index appropriately, - * as it would be left by opendir(). - * - */ -void -_trewinddir( _TDIR * dirp ) -{ - /* This is an XSI extension to POSIX, which specifies no formal - * error conditions; we will continue to check for and evade the - * potential segmentation fault which would result from passing a - * NULL reference pointer. For consistency with the core functions - * implemented above, we will again report this as EBADF, rather - * than the EFAULT of previous versions. - */ - DIRENT_REJECT( - ((dirp == NULL) || (_findclose( dirp->dd_private.dd_handle ) != 0)), - EBADF, DIRENT_RETURN_NOTHING - ); - - /* We successfully closed the prior search context; reopen... - */ - if( DIRENT_OPEN( dirp->dd_private ) != (intptr_t)(-1) ) - /* - * ...and, on success, reset the location index. - */ - dirp->dd_private.dd_stat = 0; -} - - -/***** - * - * telldir() - * - * Returns the "position" in the "directory stream" which can then - * be passed to seekdir(), to return back to a previous entry. We - * simply return the current location index from the dd_stat field. - * - */ -long -_ttelldir( _TDIR * dirp ) -{ - /* This too is a POSIX-XSI extension, with no mandatory error - * conditions. Once again, evade a potential segmentation fault - * on passing a NULL reference pointer, again reporting it as - * EBADF in preference to the EFAULT of previous versions. - */ - DIRENT_REJECT( (dirp == NULL), EBADF, -1 ); - - /* We didn't bail out; just assume dirp is valid, and return - * the location index from the dd_stat field. - */ - return dirp->dd_private.dd_stat; -} - - -/***** - * - * seekdir() - * - * Seek to an entry previously returned by telldir(). We rewind - * the "directory stream", then repeatedly call _findnext() while - * incrementing its internal location index until it matches the - * position requested, or we reach the end of the stream. This is - * not perfect, in that the directory may have changed while we - * weren't looking, but it is the best we can achieve, and may - * likely reproduce the behaviour of other implementations. - * - */ -void -_tseekdir( _TDIR * dirp, long loc ) -{ - /* Another POSIX-XSI extension, with no specified mandatory - * error conditions; we require a seek location of zero or - * greater, and will reject less than zero as EINVAL... - */ - DIRENT_REJECT( (loc < 0L), EINVAL, DIRENT_RETURN_NOTHING ); - - /* Other than this, we simply accept any error condition - * which arises as we "rewind" the "directory stream"... - */ - _trewinddir( dirp ); - - /* ...and, if this is successful... - */ - if( (loc > 0) && (dirp->dd_private.dd_handle != (intptr_t)(-1)) ) - /* - * ...seek forward until the location index within - * the DIR structure matches the requested location. - */ - while( (++dirp->dd_private.dd_stat < loc) - && (DIRENT_UPDATE( dirp->dd_private ) == 0) ) - ; -} - -/* $RCSfile$: end of file */ |