4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-01-31 03:20:28 +08:00

Clean up DIRENT errno handling; make it more POSIX conformant.

This commit is contained in:
Keith Marshall 2011-11-26 22:12:51 +00:00
parent d8e7e40416
commit 1b60bb36b0
2 changed files with 106 additions and 93 deletions

View File

@ -1,6 +1,19 @@
2011-11-26 Keith Marshall <keithmarshall@users.sourceforge.net>
Clean up DIRENT errno handling; make it more POSIX conformant.
* mingwex/dirent.c (errno): Never zero it; POSIX forbids this.
(_tclosedir): Save errno at entry; restore it when no more files.
(DIRENT_RETURN_NOTHING): New macro; define it; use it in functions
with `void' return type, in place of the return arg when invoking...
(DIRENT_REJECT): New macro; define it; use it in all functions, to
set `errno' and bail out, on detection of an abnormal condition.
[errno = EFAULT]: Do not assign as this; POSIX specifies...
[errno = EBADF]: ...this instead.
2011-10-01 Keith Marshall <keithmarshall@users.sourceforge.net> 2011-10-01 Keith Marshall <keithmarshall@users.sourceforge.net>
Rationalise structure layout; add dirent.d_type field. Rationalise DIRENT structure layout; add dirent.d_type field.
* include/dirent.h (struct dirent): Rearrange; add d_type field. * include/dirent.h (struct dirent): Rearrange; add d_type field.
Add extra padding fields between d_type and d_name, to represent a Add extra padding fields between d_type and d_name, to represent a

View File

@ -1,5 +1,6 @@
/* /*
* dirent.c * dirent.c
*
* This file has no copyright assigned and is placed in the Public Domain. * This file has no copyright assigned and is placed in the Public Domain.
* This file is a part of the mingw-runtime package. * This file is a part of the mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER within the package. * No warranty is given; refer to the file DISCLAIMER within the package.
@ -9,8 +10,8 @@
* DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89 * DIRLIB.H by M. J. Weinstein Released to public domain 1-Jan-89
* *
* Updated by Jeremy Bettis <jeremy@hksys.com> * Updated by Jeremy Bettis <jeremy@hksys.com>
* Significantly revised and rewinddir, seekdir and telldir added by Colin * Significantly revised and rewinddir, seekdir and telldir added
* Peters <colin@fu.is.saga-u.ac.jp> * by Colin Peters <colin@fu.is.saga-u.ac.jp>
* *
*/ */
@ -26,7 +27,11 @@
#include <tchar.h> #include <tchar.h>
#define SUFFIX _T("*") #define SUFFIX _T("*")
#define SLASH _T("\\") #define SLASH _T("\\")
#define DIRENT_RETURN_NOTHING
#define DIRENT_REJECT( chk, err, rtn ) \
do { if( chk ){ errno = (err); return rtn; }} while(0)
union __dirstream_t union __dirstream_t
{ {
@ -153,51 +158,44 @@ _topendir (const _TCHAR *szPath)
unsigned int rc; unsigned int rc;
_TCHAR szFullPath[MAX_PATH]; _TCHAR szFullPath[MAX_PATH];
errno = 0; /* 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; however, the choice of
* EFAULT is not specified by POSIX, for any opendir failure.
*/
DIRENT_REJECT( (!szPath), EFAULT, (_TDIR *)(0) );
/*
* Conversely, POSIX *does* specify ENOENT for the empty path
* name case, where we previously had ENOTDIR; here, we correct
* this previous anomaly.
*/
DIRENT_REJECT( (*szPath == _T('\0')), ENOENT, (_TDIR *)(0) );
if (!szPath) /* Attempt to determine if the given path really is a directory.
{ * On error, user may call GetLastError() for more error info
errno = EFAULT; */
return (_TDIR *) 0; DIRENT_REJECT( ((rc = _tGetFileAttributes (szPath)) == (unsigned int)(-1)),
} ENOENT, (_TDIR *)(0)
);
if (szPath[0] == _T('\0')) /* Error, entry exists but not a directory.
{ */
errno = ENOTDIR; DIRENT_REJECT( (!(rc & FILE_ATTRIBUTE_DIRECTORY)), ENOTDIR, (_TDIR *)(0) );
return (_TDIR *) 0;
}
/* Attempt to determine if the given path really is a directory. */
rc = _tGetFileAttributes (szPath);
if (rc == (unsigned int)-1)
{
/* call GetLastError for more error info */
errno = ENOENT;
return (_TDIR *) 0;
}
if (!(rc & FILE_ATTRIBUTE_DIRECTORY))
{
/* Error, entry exists but not a directory. */
errno = ENOTDIR;
return (_TDIR *) 0;
}
/* Make an absolute pathname. */ /* Make an absolute pathname. */
_tfullpath (szFullPath, szPath, MAX_PATH); _tfullpath (szFullPath, szPath, MAX_PATH);
/* Allocate enough space to store DIR structure and the complete /* Allocate enough space to store DIR structure and the complete
* directory path given. */ * directory path given. */
nd = (_TDIR *) malloc (sizeof (_TDIR) + (_tcslen (szFullPath) nd = (_TDIR *)(malloc( sizeof( _TDIR )
+ _tcslen (SLASH) + (_tcslen( szFullPath ) + _tcslen( SLASH ) + _tcslen( SUFFIX ) + 1)
+ _tcslen (SUFFIX) + 1) * sizeof( _TCHAR )
* sizeof (_TCHAR)); ));
if (!nd) /* Error, out of memory.
{ */
/* Error, out of memory. */ DIRENT_REJECT( (!nd), ENOMEM, (_TDIR *)(0) );
errno = ENOMEM;
return (_TDIR *) 0;
}
/* Create the search expression. */ /* Create the search expression. */
_tcscpy (nd->dd_private.dd_name, szFullPath); _tcscpy (nd->dd_private.dd_name, szFullPath);
@ -241,16 +239,15 @@ _topendir (const _TCHAR *szPath)
* next entry in the directory. * next entry in the directory.
*/ */
struct _tdirent * struct _tdirent *
_treaddir (_TDIR * dirp) _treaddir (_TDIR *dirp)
{ {
errno = 0; /* Check for a valid DIR stream reference; (we can't really
* be certain until we try to read from it, except in the case
/* Check for valid DIR struct. */ * of a NULL pointer reference). Where we lack a valid reference,
if (!dirp) * POSIX mandates reporting EBADF; we previously had EFAULT, so
{ * this version corrects the former anomaly.
errno = EFAULT; */
return (struct _tdirent *) 0; DIRENT_REJECT( (!dirp), EBADF, (struct _tdirent *)(0) );
}
if (dirp->dd_private.dd_stat < 0) if (dirp->dd_private.dd_stat < 0)
{ {
@ -266,7 +263,7 @@ _treaddir (_TDIR * dirp)
if (dirp->dd_private.dd_handle == -1) if (dirp->dd_private.dd_handle == -1)
{ {
/* Whoops! Seems there are no files in that /* Oops! Seems there are no files in that
* directory. */ * directory. */
dirp->dd_private.dd_stat = -1; dirp->dd_private.dd_stat = -1;
} }
@ -277,15 +274,27 @@ _treaddir (_TDIR * dirp)
} }
else else
{ {
/* Get the next search entry. */ /* 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 (_tfindnext (dirp->dd_private.dd_handle, &(dirp->dd_private.dd_dta))) if (_tfindnext (dirp->dd_private.dd_handle, &(dirp->dd_private.dd_dta)))
{ {
/* We are off the end or otherwise error. /* May be an error, or just the case described above...
_findnext sets errno to ENOENT if no more file */
Undo this. */ if( GetLastError() == ERROR_NO_MORE_FILES )
DWORD winerr = GetLastError (); /*
if (winerr == ERROR_NO_MORE_FILES) * ...which requires us to reset errno.
errno = 0; */
errno = prev_errno;
/* FIXME: this is just wrong: we should NOT close the DIR
* handle here; it is the responsibility of closedir().
*/
_findclose (dirp->dd_private.dd_handle); _findclose (dirp->dd_private.dd_handle);
dirp->dd_private.dd_handle = -1; dirp->dd_private.dd_handle = -1;
dirp->dd_private.dd_stat = -1; dirp->dd_private.dd_stat = -1;
@ -341,16 +350,15 @@ _treaddir (_TDIR * dirp)
int int
_tclosedir (_TDIR * dirp) _tclosedir (_TDIR * dirp)
{ {
int rc; int rc = 0;
errno = 0; /* Attempting to reference a directory stream via a NULL pointer
rc = 0; * would cause a segmentation fault; evade this. Since NULL can
* never represent an open directory stream, set the EBADF errno
if (!dirp) * status, as mandated by POSIX, once again correcting previous
{ * anomalous use of EFAULT in this context.
errno = EFAULT; */
return -1; DIRENT_REJECT( (!dirp), EBADF, -1 );
}
if (dirp->dd_private.dd_handle != -1) if (dirp->dd_private.dd_handle != -1)
{ {
@ -372,13 +380,11 @@ _tclosedir (_TDIR * dirp)
void void
_trewinddir (_TDIR * dirp) _trewinddir (_TDIR * dirp)
{ {
errno = 0; /* Once again, evade a potential segmentation fault on passing
* a NULL reference pointer, and again correct previous anomalous
if (!dirp) * use of EFAULT, where POSIX mandates EBADF for errno reporting.
{ */
errno = EFAULT; DIRENT_REJECT( (!dirp), EBADF, DIRENT_RETURN_NOTHING );
return;
}
if (dirp->dd_private.dd_handle != -1) if (dirp->dd_private.dd_handle != -1)
{ {
@ -398,13 +404,11 @@ _trewinddir (_TDIR * dirp)
long long
_ttelldir (_TDIR * dirp) _ttelldir (_TDIR * dirp)
{ {
errno = 0; /* Once again, evade a potential segmentation fault on passing
* a NULL reference pointer, and again correct previous anomalous
if (!dirp) * use of EFAULT, where POSIX mandates EBADF for errno reporting.
{ */
errno = EFAULT; DIRENT_REJECT( (!dirp), EBADF, -1 );
return -1;
}
return dirp->dd_private.dd_stat; return dirp->dd_private.dd_stat;
} }
@ -420,21 +424,17 @@ _ttelldir (_TDIR * dirp)
void void
_tseekdir (_TDIR * dirp, long lPos) _tseekdir (_TDIR * dirp, long lPos)
{ {
errno = 0; /* Once again, evade a potential segmentation fault on passing
* a NULL reference pointer, and again correct previous anomalous
* use of EFAULT, where POSIX mandates EBADF for errno reporting.
*/
DIRENT_REJECT( (!dirp), EBADF, DIRENT_RETURN_NOTHING );
if (!dirp) /* Seeking to an invalid position.
{ */
errno = EFAULT; DIRENT_REJECT( (lPos < -1), EINVAL, DIRENT_RETURN_NOTHING );
return;
}
if (lPos < -1) if (lPos == -1)
{
/* Seeking to an invalid position. */
errno = EINVAL;
return;
}
else if (lPos == -1)
{ {
/* Seek past end. */ /* Seek past end. */
if (dirp->dd_private.dd_handle != -1) if (dirp->dd_private.dd_handle != -1)