diff options
author | jorton <jorton@13f79535-47bb-0310-9956-ffa450edef68> | 2005-08-31 12:32:14 +0000 |
---|---|---|
committer | jorton <jorton@13f79535-47bb-0310-9956-ffa450edef68> | 2005-08-31 12:32:14 +0000 |
commit | ca2eb4bc44c16a2e300b5bcba3e2b0149e600de3 (patch) | |
tree | d13ab455e127b436e572fb328287e3fc7e7d45ef /file_io | |
parent | 2cd583370fb3d67588229e6e145c1d4d154bd210 (diff) | |
download | libapr-ca2eb4bc44c16a2e300b5bcba3e2b0149e600de3.tar.gz |
Add some workarounds for cases where readdir_r fails due to large
integers in struct dirent's d_ino or d_off fields in LFS builds (seen
in some peculiar NFS environments):
* configure.in: Check for readdir64_r for LFS builds.
* include/arch/unix/apr_arch_file_io.h (struct apr_dir_t): Use struct
dirent64 for entry field if readdir64_r is present.
* file_io/unix/dir.c (apr_dir_open): Use size of the entry field.
(apr_dir_read): Use readdir64_r if available; check for d_ino
overflow.
* file_io/unix/filestat.c (fill_out_finfo): Check for inode number
overflow.
git-svn-id: http://svn.apache.org/repos/asf/apr/apr/trunk@265032 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'file_io')
-rw-r--r-- | file_io/unix/dir.c | 38 | ||||
-rw-r--r-- | file_io/unix/filestat.c | 11 |
2 files changed, 44 insertions, 5 deletions
diff --git a/file_io/unix/dir.c b/file_io/unix/dir.c index 590380f2e..da7e5a1eb 100644 --- a/file_io/unix/dir.c +++ b/file_io/unix/dir.c @@ -77,8 +77,8 @@ apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, * one-byte array. Note: gcc evaluates this at compile time. */ apr_size_t dirent_size = - (sizeof((*new)->entry->d_name) > 1 ? - sizeof(struct dirent) : sizeof (struct dirent) + 255); + sizeof(*(*new)->entry) + + (sizeof((*new)->entry->d_name) > 1 ? 0 : 255); (*new) = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t)); @@ -139,9 +139,28 @@ apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, #endif #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \ && !defined(READDIR_IS_THREAD_SAFE) +#ifdef HAVE_READDIR64_R + struct dirent64 *retent; + + /* If LFS is enabled and readdir64_r is available, readdir64_r is + * used in preference to readdir_r. This allows directories to be + * read which contain a (64-bit) inode number which doesn't fit + * into the 32-bit apr_ino_t, iff the caller doesn't actually care + * about the inode number (i.e. wanted & APR_FINFO_INODE == 0). + * (such inodes may be seen in some wonky NFS environments) + * + * Similarly, if the d_off field cannot be reprented in a 32-bit + * offset, the libc readdir_r() would barf; using readdir64_r + * bypasses that case entirely since APR does not care about + * d_off. */ + + ret = readdir64_r(thedir->dirstruct, thedir->entry, &retent); +#else + struct dirent *retent; ret = readdir_r(thedir->dirstruct, thedir->entry, &retent); +#endif /* Avoid the Linux problem where at end-of-directory thedir->entry * is set to NULL, but ret = APR_SUCCESS. @@ -191,9 +210,20 @@ apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted, #endif #ifdef DIRENT_INODE if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) { - wanted &= ~APR_FINFO_INODE; +#ifdef HAVE_READDIR64_R + /* If readdir64_r is used, check for the overflow case of trying + * to fit a 64-bit integer into a 32-bit integer. */ + if (sizeof(apr_ino_t) >= sizeof(retent->DIRENT_INODE) + || (apr_ino_t)retent->DIRENT_INODE == retent->DIRENT_INODE) { + wanted &= ~APR_FINFO_INODE; + } else { + /* Prevent the fallback code below from filling in the + * inode if the stat call fails. */ + retent->DIRENT_INODE = 0; + } } -#endif +#endif /* HAVE_READDIR64_R */ +#endif /* DIRENT_INODE */ wanted &= ~APR_FINFO_NAME; diff --git a/file_io/unix/filestat.c b/file_io/unix/filestat.c index d7a48663a..b1a43101a 100644 --- a/file_io/unix/filestat.c +++ b/file_io/unix/filestat.c @@ -77,9 +77,18 @@ static void fill_out_finfo(apr_finfo_t *finfo, struct_stat *info, finfo->user = info->st_uid; finfo->group = info->st_gid; finfo->size = info->st_size; - finfo->inode = info->st_ino; finfo->device = info->st_dev; finfo->nlink = info->st_nlink; + + /* Check for overflow if storing a 64-bit st_ino in a 32-bit + * apr_ino_t for LFS builds: */ + if (sizeof(apr_ino_t) >= sizeof(info->st_ino) + || (apr_ino_t)info->st_ino == info->st_ino) { + finfo->inode = info->st_ino; + } else { + finfo->valid &= ~APR_FINFO_INODE; + } + apr_time_ansi_put(&finfo->atime, info->st_atime); apr_time_ansi_put(&finfo->mtime, info->st_mtime); apr_time_ansi_put(&finfo->ctime, info->st_ctime); |