Will Rowe and I were talking earlier today, and our directory API is
horribly broken and inefficient. Basically, on Unix if you want to get
any information about a file in a directory, we have to do a stat for each
piece of information.
For example, if you want the size, that's one stat. If you then want the
file type, that's another stat. Yuck!
Here is a design that Will suggested earlier today, implemented for
Unix. Basically, it just uses the finfo structure to store information
about the file when you read it from the directory.
? build.log
? build.err
Index: file_io/unix/dir.c
===================================================================
RCS file: /home/cvs/apr/file_io/unix/dir.c,v
retrieving revision 1.42
diff -u -d -b -w -u -r1.42 dir.c
--- file_io/unix/dir.c 2001/01/05 19:40:05 1.42
+++ file_io/unix/dir.c 2001/01/22 02:46:57
@@ -53,6 +53,7 @@
*/
#include "fileio.h"
+#include "apr_file_info.h"
#include "apr_strings.h"
#include "apr_portable.h"
@@ -106,20 +107,18 @@
return rv;
}
-apr_status_t apr_readdir(apr_dir_t *thedir)
+apr_status_t apr_readdir(apr_finfo_t *finfo, apr_dir_t *thedir)
{
#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
&& !defined(READDIR_IS_THREAD_SAFE)
apr_status_t ret;
-#endif
-
-#if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
- && !defined(READDIR_IS_THREAD_SAFE)
ret = readdir_r(thedir->dirstruct, thedir->entry, &thedir->entry);
/* Avoid the Linux problem where at end-of-directory thedir->entry
* is set to NULL, but ret = APR_SUCCESS.
*/
+ finfo->cntxt = thedir->cntxt;
+ finfo->fname = apr_pstrcat(thedir->cntxt, thedir->dirname, "/",
thedir->entry->d_name, NULL);
return (ret == APR_SUCCESS && thedir->entry == NULL) ? APR_ENOENT : ret;
#else
@@ -131,6 +130,8 @@
}
return errno;
}
+ finfo->cntxt = thedir->cntxt;
+ finfo->fname = apr_pstrcat(thedir->cntxt, thedir->dirname, "/",
thedir->entry->d_name, NULL);
return APR_SUCCESS;
#endif
}
@@ -161,94 +162,6 @@
else {
return errno;
}
-}
-
-apr_status_t apr_dir_entry_size(apr_size_t *size, apr_dir_t *thedir)
-{
- struct stat filestat;
- char *fname = NULL;
-
- if (thedir->entry == NULL) {
- *size = -1;
- return APR_ENOFILE;
- }
- fname = apr_pstrcat(thedir->cntxt, thedir->dirname, "/",
- thedir->entry->d_name, NULL);
- if (stat(fname, &filestat) == -1) {
- *size = 0;
- return errno;
- }
-
- *size = filestat.st_size;
- return APR_SUCCESS;
-}
-
-apr_status_t apr_dir_entry_mtime(apr_time_t *mtime, apr_dir_t *thedir)
-{
- struct stat filestat;
- char *fname = NULL;
-
- if (thedir->entry == NULL) {
- *mtime = -1;
- return APR_ENOFILE;
- }
-
- fname = apr_pstrcat(thedir->cntxt, thedir->dirname, "/",
- thedir->entry->d_name, NULL);
- if (stat(fname, &filestat) == -1) {
- *mtime = -1;
- return errno;
- }
-
- apr_ansi_time_to_apr_time(mtime, filestat.st_mtime);
- return APR_SUCCESS;
-}
-
-apr_status_t apr_dir_entry_ftype(apr_filetype_e *type, apr_dir_t *thedir)
-{
- struct stat filestat;
- char *fname = NULL;
-
- if (thedir->entry == NULL) {
- *type = APR_REG;
- return APR_ENOFILE;
- }
-
- fname = apr_pstrcat(thedir->cntxt, thedir->dirname, "/",
- thedir->entry->d_name, NULL);
- if (stat(fname, &filestat) == -1) {
- *type = APR_REG;
- return errno;
- }
-
- if (S_ISREG(filestat.st_mode))
- *type = APR_REG;
- if (S_ISDIR(filestat.st_mode))
- *type = APR_DIR;
- if (S_ISCHR(filestat.st_mode))
- *type = APR_CHR;
- if (S_ISBLK(filestat.st_mode))
- *type = APR_BLK;
- if (S_ISFIFO(filestat.st_mode))
- *type = APR_PIPE;
- if (S_ISLNK(filestat.st_mode))
- *type = APR_LNK;
-#ifndef BEOS
- if (S_ISSOCK(filestat.st_mode))
- *type = APR_SOCK;
-#endif
- return APR_SUCCESS;
-}
-
-apr_status_t apr_get_dir_filename(const char **new, apr_dir_t *thedir)
-{
- /* Detect End-Of-File */
- if (thedir == NULL || thedir->entry == NULL) {
- *new = NULL;
- return APR_ENOENT;
- }
- (*new) = thedir->entry->d_name;
- return APR_SUCCESS;
}
apr_status_t apr_get_os_dir(apr_os_dir_t **thedir, apr_dir_t *dir)
Index: include/apr_file_info.h
===================================================================
RCS file: /home/cvs/apr/include/apr_file_info.h,v
retrieving revision 1.4
diff -u -d -b -w -u -r1.4 apr_file_info.h
--- include/apr_file_info.h 2001/01/20 22:18:55 1.4
+++ include/apr_file_info.h 2001/01/22 02:46:57
@@ -255,9 +255,9 @@
* Read the next entry from the specified directory.
* @param thedir the directory descriptor to read from, and fill out.
* @tip All systems return . and .. as the first two files.
- * @deffunc apr_status_t apr_readdir(apr_dir_t *thedir)
+ * @deffunc apr_status_t apr_readdir(apr_finfo_t *finfo, apr_dir_t *thedir)
*/
-APR_DECLARE(apr_status_t) apr_readdir(apr_dir_t *thedir);
+APR_DECLARE(apr_status_t) apr_readdir(apr_finfo_t *finfo, apr_dir_t *thedir);
/**
* Rewind the directory to the first entry.
@@ -265,42 +265,6 @@
* @deffunc apr_status_t apr_rewinddir(apr_dir_t *thedir)
*/
APR_DECLARE(apr_status_t) apr_rewinddir(apr_dir_t *thedir);
-
-/**
- * Get the file name of the current directory entry.
- * @param new_path the file name of the directory entry.
- * @param thedir the currently open directory.
- * @deffunc apr_status_t apr_get_dir_filename(const char **new_path, apr_dir_t
*thedir)
- */
-APR_DECLARE(apr_status_t) apr_get_dir_filename(const char **new_path,
- apr_dir_t *thedir);
-
-/**
- * Get the size of the current directory entry.
- * @param size the size of the directory entry.
- * @param thedir the currently open directory.
- * @deffunc apr_status_t apr_dir_entry_size(apr_size_t *size, apr_dir_t
*thedir)
- */
-APR_DECLARE(apr_status_t) apr_dir_entry_size(apr_size_t *size,
- apr_dir_t *thedir);
-
-/**
- * Get the last modified time of the current directory entry.
- * @param mtime the last modified time of the directory entry.
- * @param thedir the currently open directory.
- * @deffunc apr_status_t apr_dir_entry_mtime(apr_time_t *mtime, apr_dir_t
*thedir)
- */
-APR_DECLARE(apr_status_t) apr_dir_entry_mtime(apr_time_t *mtime,
- apr_dir_t *thedir);
-
-/**
- * Get the file type of the current directory entry.
- * @param type the file type of the directory entry.
- * @param thedir the currently open directory.
- * @deffunc apr_status_t apr_dir_entry_ftype(apr_filetype_e *type, apr_dir_t
*thedir)
- */
-APR_DECLARE(apr_status_t) apr_dir_entry_ftype(apr_filetype_e *type,
- apr_dir_t *thedir);
#ifdef __cplusplus
}
Index: test/testfile.c
===================================================================
RCS file: /home/cvs/apr/test/testfile.c,v
retrieving revision 1.24
diff -u -d -b -w -u -r1.24 testfile.c
--- test/testfile.c 2001/01/15 19:19:24 1.24
+++ test/testfile.c 2001/01/22 02:46:59
@@ -290,8 +290,7 @@
apr_dir_t *temp;
apr_file_t *file = NULL;
apr_size_t bytes;
- apr_filetype_e type;
- const char *fname;
+ apr_finfo_t finfo;
fprintf(stdout, "Testing Directory functions.\n");
@@ -322,7 +321,7 @@
}
fprintf(stdout, "\tReading Directory.......");
- if ((apr_readdir(temp)) != APR_SUCCESS) {
+ if ((apr_readdir(&finfo, temp)) != APR_SUCCESS) {
fprintf(stderr, "Could not read directory\n");
return -1;
}
@@ -336,29 +335,28 @@
/* Because I want the file I created, I am skipping the "." and ".."
* files that are here.
*/
- if (apr_readdir(temp) != APR_SUCCESS) {
+ if (apr_readdir(&finfo, temp) != APR_SUCCESS) {
fprintf(stderr, "Error reading directory testdir");
return -1;
}
- apr_get_dir_filename(&fname, temp);
- } while (fname[0] == '.');
- if (strcmp(fname, "testfile")) {
- fprintf(stderr, "Got wrong file name %s\n", fname);
+ } while (!strncmp(finfo.fname, "testdir/.", strlen("testdir/.")));
+ if (strcmp(finfo.fname, "testdir/testfile")) {
+ fprintf(stderr, "Got wrong file name %s\n", finfo.fname);
return -1;
}
fprintf(stdout, "OK\n");
+ apr_stat(&finfo, finfo.fname, APR_FINFO_NORM, finfo.cntxt);
+
fprintf(stdout, "\t\tFile type.......");
- apr_dir_entry_ftype(&type, temp);
- if (type != APR_REG) {
+ if (finfo.filetype != APR_REG) {
fprintf(stderr, "Got wrong file type\n");
return -1;
}
fprintf(stdout, "OK\n");
fprintf(stdout, "\t\tFile size.......");
- apr_dir_entry_size(&bytes, temp);
- if (bytes != strlen("Another test!!!")) {
+ if (finfo.size != strlen("Another test!!!")) {
fprintf(stderr, "Got wrong file size %" APR_SIZE_T_FMT "\n", bytes);
return -1;
}
_______________________________________________________________________________
Ryan Bloom [EMAIL PROTECTED]
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------