Simplify uses of readdir() by creating a function ReadDir() that

includes error checking and an appropriate ereport(ERROR) message.
This gets rid of rather tedious and error-prone manipulation of errno,
as well as a Windows-specific bug workaround, at more than a dozen
call sites.  After an idea in a recent patch by Heikki Linnakangas.
This commit is contained in:
Tom Lane 2005-06-19 21:34:03 +00:00
parent e26b0abda3
commit 3f749924f8
10 changed files with 88 additions and 223 deletions

View File

@ -5,7 +5,7 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/contrib/dbsize/dbsize.c,v 1.17 2005/05/27 00:57:48 neilc Exp $
* $PostgreSQL: pgsql/contrib/dbsize/dbsize.c,v 1.18 2005/06/19 21:34:00 tgl Exp $
*
*/
@ -58,7 +58,7 @@ db_dir_size(const char *path)
if (!dirdesc)
return 0;
while ((direntry = readdir(dirdesc)) != NULL)
while ((direntry = ReadDir(dirdesc, path)) != NULL)
{
struct stat fst;
@ -97,13 +97,8 @@ calculate_database_size(Oid dbOid)
/* Scan the non-default tablespaces */
snprintf(pathname, MAXPGPATH, "%s/pg_tblspc", DataDir);
dirdesc = AllocateDir(pathname);
if (!dirdesc)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open tablespace directory \"%s\": %m",
pathname)));
while ((direntry = readdir(dirdesc)) != NULL)
while ((direntry = ReadDir(dirdesc, pathname)) != NULL)
{
if (strcmp(direntry->d_name, ".") == 0 ||
strcmp(direntry->d_name, "..") == 0)
@ -147,13 +142,7 @@ pg_tablespace_size(PG_FUNCTION_ARGS)
dirdesc = AllocateDir(tblspcPath);
if (!dirdesc)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open tablespace directory \"%s\": %m",
tblspcPath)));
while ((direntry = readdir(dirdesc)) != NULL)
while ((direntry = ReadDir(dirdesc, tblspcPath)) != NULL)
{
struct stat fst;

View File

@ -48,7 +48,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.24 2005/02/12 23:53:37 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/slru.c,v 1.25 2005/06/19 21:34:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -924,14 +924,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
cutoffPage -= cutoffPage % SLRU_PAGES_PER_SEGMENT;
cldir = AllocateDir(ctl->Dir);
if (cldir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
ctl->Dir)));
errno = 0;
while ((clde = readdir(cldir)) != NULL)
while ((clde = ReadDir(cldir, ctl->Dir)) != NULL)
{
if (strlen(clde->d_name) == 4 &&
strspn(clde->d_name, "0123456789ABCDEF") == 4)
@ -950,21 +943,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
}
}
}
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m", ctl->Dir)));
FreeDir(cldir);
return found;

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.4 2005/06/19 20:00:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/twophase.c,v 1.5 2005/06/19 21:34:01 tgl Exp $
*
* NOTES
* Each global transaction is associated with a global transaction
@ -1440,13 +1440,7 @@ PrescanPreparedTransactions(void)
snprintf(dir, MAXPGPATH, "%s/%s", DataDir, TWOPHASE_DIR);
cldir = AllocateDir(dir);
if (cldir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m", dir)));
errno = 0;
while ((clde = readdir(cldir)) != NULL)
while ((clde = ReadDir(cldir, dir)) != NULL)
{
if (strlen(clde->d_name) == 8 &&
strspn(clde->d_name, "0123456789ABCDEF") == 8)
@ -1466,7 +1460,6 @@ PrescanPreparedTransactions(void)
(errmsg("removing future twophase state file \"%s\"",
clde->d_name)));
RemoveTwoPhaseFile(xid, true);
errno = 0;
continue;
}
@ -1483,7 +1476,6 @@ PrescanPreparedTransactions(void)
(errmsg("removing corrupt twophase state file \"%s\"",
clde->d_name)));
RemoveTwoPhaseFile(xid, true);
errno = 0;
continue;
}
@ -1496,7 +1488,6 @@ PrescanPreparedTransactions(void)
clde->d_name)));
RemoveTwoPhaseFile(xid, true);
pfree(buf);
errno = 0;
continue;
}
@ -1528,22 +1519,7 @@ PrescanPreparedTransactions(void)
pfree(buf);
}
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m", dir)));
FreeDir(cldir);
return result;
@ -1566,13 +1542,7 @@ RecoverPreparedTransactions(void)
snprintf(dir, MAXPGPATH, "%s/%s", DataDir, TWOPHASE_DIR);
cldir = AllocateDir(dir);
if (cldir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m", dir)));
errno = 0;
while ((clde = readdir(cldir)) != NULL)
while ((clde = ReadDir(cldir, dir)) != NULL)
{
if (strlen(clde->d_name) == 8 &&
strspn(clde->d_name, "0123456789ABCDEF") == 8)
@ -1594,7 +1564,6 @@ RecoverPreparedTransactions(void)
(errmsg("removing stale twophase state file \"%s\"",
clde->d_name)));
RemoveTwoPhaseFile(xid, true);
errno = 0;
continue;
}
@ -1606,7 +1575,6 @@ RecoverPreparedTransactions(void)
(errmsg("removing corrupt twophase state file \"%s\"",
clde->d_name)));
RemoveTwoPhaseFile(xid, true);
errno = 0;
continue;
}
@ -1655,22 +1623,7 @@ RecoverPreparedTransactions(void)
pfree(buf);
}
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m", dir)));
FreeDir(cldir);
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.202 2005/06/19 20:00:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.203 2005/06/19 21:34:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -2265,8 +2265,7 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr,
XLogFileName(lastoff, ThisTimeLineID, log, seg);
errno = 0;
while ((xlde = readdir(xldir)) != NULL)
while ((xlde = ReadDir(xldir, XLogDir)) != NULL)
{
/*
* We ignore the timeline part of the XLOG segment identifiers in
@ -2326,22 +2325,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr,
XLogArchiveCleanup(xlde->d_name);
}
}
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read transaction log directory \"%s\": %m",
XLogDir)));
FreeDir(xldir);
}
@ -2362,8 +2347,7 @@ RemoveOldBackupHistory(void)
errmsg("could not open transaction log directory \"%s\": %m",
XLogDir)));
errno = 0;
while ((xlde = readdir(xldir)) != NULL)
while ((xlde = ReadDir(xldir, XLogDir)) != NULL)
{
if (strlen(xlde->d_name) > 24 &&
strspn(xlde->d_name, "0123456789ABCDEF") == 24 &&
@ -2381,22 +2365,8 @@ RemoveOldBackupHistory(void)
XLogArchiveCleanup(xlde->d_name);
}
}
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read transaction log directory \"%s\": %m",
XLogDir)));
FreeDir(xldir);
}

View File

@ -37,7 +37,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.21 2005/06/06 20:22:57 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.22 2005/06/19 21:34:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -519,23 +519,16 @@ remove_tablespace_directories(Oid tablespaceoid, bool redo)
pfree(location);
return true;
}
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
location)));
/* else let ReadDir report the error */
}
errno = 0;
while ((de = readdir(dirdesc)) != NULL)
while ((de = ReadDir(dirdesc, location)) != NULL)
{
/* Note we ignore PG_VERSION for the nonce */
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0 ||
strcmp(de->d_name, "PG_VERSION") == 0)
{
errno = 0;
continue;
}
subfile = palloc(strlen(location) + 1 + strlen(de->d_name) + 1);
sprintf(subfile, "%s/%s", location, de->d_name);
@ -555,22 +548,8 @@ remove_tablespace_directories(Oid tablespaceoid, bool redo)
subfile)));
pfree(subfile);
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m",
location)));
FreeDir(dirdesc);
/*
@ -685,38 +664,16 @@ directory_is_empty(const char *path)
struct dirent *de;
dirdesc = AllocateDir(path);
if (dirdesc == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
path)));
errno = 0;
while ((de = readdir(dirdesc)) != NULL)
while ((de = ReadDir(dirdesc, path)) != NULL)
{
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0)
{
errno = 0;
continue;
}
FreeDir(dirdesc);
return false;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m",
path)));
FreeDir(dirdesc);
return true;
}

View File

@ -19,7 +19,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.15 2005/03/10 07:14:03 neilc Exp $
* $PostgreSQL: pgsql/src/backend/postmaster/pgarch.c,v 1.16 2005/06/19 21:34:01 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -510,8 +510,7 @@ pgarch_readyXlog(char *xlog)
errmsg("could not open archive status directory \"%s\": %m",
XLogArchiveStatusDir)));
errno = 0;
while ((rlde = readdir(rldir)) != NULL)
while ((rlde = ReadDir(rldir, XLogArchiveStatusDir)) != NULL)
{
int basenamelen = (int) strlen(rlde->d_name) - 6;
@ -531,23 +530,7 @@ pgarch_readyXlog(char *xlog)
strcpy(newxlog, rlde->d_name);
}
}
errno = 0;
}
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read archive status directory \"%s\": %m",
XLogArchiveStatusDir)));
FreeDir(rldir);
if (found)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.116 2005/05/20 14:53:26 momjian Exp $
* $PostgreSQL: pgsql/src/backend/storage/file/fd.c,v 1.117 2005/06/19 21:34:02 tgl Exp $
*
* NOTES:
*
@ -1337,6 +1337,59 @@ TryAgain:
return NULL;
}
/*
* Read a directory opened with AllocateDir, ereport'ing any error.
*
* This is easier to use than raw readdir() since it takes care of some
* otherwise rather tedious and error-prone manipulation of errno. Also,
* if you are happy with a generic error message for AllocateDir failure,
* you can just do
*
* dir = AllocateDir(path);
* while ((dirent = ReadDir(dir, path)) != NULL)
* process dirent;
* FreeDir(path);
*
* since a NULL dir parameter is taken as indicating AllocateDir failed.
* (Make sure errno hasn't been changed since AllocateDir if you use this
* shortcut.)
*
* The pathname passed to AllocateDir must be passed to this routine too,
* but it is only used for error reporting.
*/
struct dirent *
ReadDir(DIR *dir, const char *dirname)
{
struct dirent *dent;
/* Give a generic message for AllocateDir failure, if caller didn't */
if (dir == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
dirname)));
errno = 0;
if ((dent = readdir(dir)) != NULL)
return dent;
#ifdef WIN32
/*
* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
* not in released version
*/
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m",
dirname)));
return NULL;
}
/*
* Close a directory opened with AllocateDir.
*
@ -1526,14 +1579,8 @@ RemovePgTempFiles(void)
*/
snprintf(db_path, sizeof(db_path), "%s/base", DataDir);
db_dir = AllocateDir(db_path);
if (db_dir == NULL)
{
/* this really should not happen */
elog(LOG, "could not open directory \"%s\": %m", db_path);
return;
}
while ((db_de = readdir(db_dir)) != NULL)
while ((db_de = ReadDir(db_dir, db_path)) != NULL)
{
if (strcmp(db_de->d_name, ".") == 0 ||
strcmp(db_de->d_name, "..") == 0)
@ -1576,7 +1623,7 @@ RemovePgTempFilesInDir(const char *tmpdirname)
return;
}
while ((temp_de = readdir(temp_dir)) != NULL)
while ((temp_de = ReadDir(temp_dir, tmpdirname)) != NULL)
{
if (strcmp(temp_de->d_name, ".") == 0 ||
strcmp(temp_de->d_name, "..") == 0)

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.43 2005/05/19 21:35:47 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/misc.c,v 1.44 2005/06/19 21:34:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -187,11 +187,10 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
if (!fctx->dirdesc) /* not a tablespace */
SRF_RETURN_DONE(funcctx);
while ((de = readdir(fctx->dirdesc)) != NULL)
while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
{
char *subdir;
DIR *dirdesc;
Oid datOid = atooid(de->d_name);
/* this test skips . and .., but is awfully weak */
@ -204,16 +203,13 @@ pg_tablespace_databases(PG_FUNCTION_ARGS)
subdir = palloc(strlen(fctx->location) + 1 + strlen(de->d_name) + 1);
sprintf(subdir, "%s/%s", fctx->location, de->d_name);
dirdesc = AllocateDir(subdir);
pfree(subdir);
if (!dirdesc)
continue; /* XXX more sloppiness */
while ((de = readdir(dirdesc)) != 0)
while ((de = ReadDir(dirdesc, subdir)) != NULL)
{
if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0)
break;
}
FreeDir(dirdesc);
pfree(subdir);
if (!de)
continue; /* indeed, nothing in it */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/storage/fd.h,v 1.51 2005/05/20 14:53:26 momjian Exp $
* $PostgreSQL: pgsql/src/include/storage/fd.h,v 1.52 2005/06/19 21:34:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -76,6 +76,7 @@ extern int FreeFile(FILE *file);
/* Operations to allow use of the <dirent.h> library routines */
extern DIR *AllocateDir(const char *dirname);
extern struct dirent *ReadDir(DIR *dir, const char *dirname);
extern int FreeDir(DIR *dir);
/* If you've really really gotta have a plain kernel FD, use this */

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.33 2005/06/15 00:09:26 momjian Exp $
* $PostgreSQL: pgsql/src/timezone/pgtz.c,v 1.34 2005/06/19 21:34:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -409,11 +409,12 @@ identify_system_timezone(void)
* score. bestzonename must be a buffer of length TZ_STRLEN_MAX + 1.
*/
static void
scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry * tt,
scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry *tt,
int *bestscore, char *bestzonename)
{
int tzdir_orig_len = strlen(tzdir);
DIR *dirdesc;
struct dirent *direntry;
dirdesc = AllocateDir(tzdir);
if (!dirdesc)
@ -424,22 +425,10 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry * tt,
return;
}
for (;;)
while ((direntry = ReadDir(dirdesc, tzdir)) != NULL)
{
struct dirent *direntry;
struct stat statbuf;
errno = 0;
direntry = readdir(dirdesc);
if (!direntry)
{
if (errno)
ereport(LOG,
(errcode_for_file_access(),
errmsg("error reading directory: %m")));
break;
}
/* Ignore . and .., plus any other "hidden" files */
if (direntry->d_name[0] == '.')
continue;
@ -452,6 +441,7 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry * tt,
ereport(LOG,
(errcode_for_file_access(),
errmsg("could not stat \"%s\": %m", tzdir)));
tzdir[tzdir_orig_len] = '\0';
continue;
}
@ -480,12 +470,12 @@ scan_available_timezones(char *tzdir, char *tzdirsub, struct tztry * tt,
StrNCpy(bestzonename, tzdirsub, TZ_STRLEN_MAX + 1);
}
}
/* Restore tzdir */
tzdir[tzdir_orig_len] = '\0';
}
FreeDir(dirdesc);
/* Restore tzdir */
tzdir[tzdir_orig_len] = '\0';
}
#else /* WIN32 */