apr/apr-0.9.6-readdir64.patch

141 lines
4.7 KiB
Diff
Raw Normal View History

--- apr-0.9.6/file_io/unix/dir.c.readdir64
+++ apr-0.9.6/file_io/unix/dir.c
@@ -77,24 +77,24 @@
* 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);
+ DIR *dir = opendir(dirname);
+
+ if (!dir) {
+ return errno;
+ }
(*new) = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t));
(*new)->pool = pool;
(*new)->dirname = apr_pstrdup(pool, dirname);
- (*new)->dirstruct = opendir(dirname);
+ (*new)->dirstruct = dir;
(*new)->entry = apr_pcalloc(pool, dirent_size);
- if ((*new)->dirstruct == NULL) {
- return errno;
- }
- else {
- apr_pool_cleanup_register((*new)->pool, (void *)(*new), dir_cleanup,
- apr_pool_cleanup_null);
- return APR_SUCCESS;
- }
+ apr_pool_cleanup_register((*new)->pool, *new, dir_cleanup,
+ apr_pool_cleanup_null);
+ return APR_SUCCESS;
}
apr_status_t apr_dir_close(apr_dir_t *thedir)
@@ -139,9 +139,28 @@
#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,22 @@
#endif
#ifdef DIRENT_INODE
if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
+#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;
+ }
+#else
wanted &= ~APR_FINFO_INODE;
+#endif /* HAVE_READDIR64_R */
}
-#endif
+#endif /* DIRENT_INODE */
wanted &= ~APR_FINFO_NAME;
--- apr-0.9.6/file_io/unix/filestat.c.readdir64
+++ apr-0.9.6/file_io/unix/filestat.c
@@ -77,9 +77,18 @@
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);
--- apr-0.9.6/include/arch/unix/apr_arch_file_io.h.readdir64
+++ apr-0.9.6/include/arch/unix/apr_arch_file_io.h
@@ -108,7 +108,11 @@
apr_pool_t *pool;
char *dirname;
DIR *dirstruct;
+#ifdef HAVE_READDIR64_R
+ struct dirent64 *entry;
+#else
struct dirent *entry;
+#endif
};
apr_status_t apr_unix_file_cleanup(void *);
--- apr-0.9.6/configure.in.readdir64
+++ apr-0.9.6/configure.in
@@ -1310,6 +1310,10 @@
AC_CHECK_FUNCS(memchr, have_memchr="1", have_memchr="0")
AC_CHECK_FUNCS($int64_strfn, have_int64_strfn="1", have_int64_strfn="0")
+if test "$ac_cv_sizeof_long" = "4"; then
+ AC_CHECK_FUNCS([readdir64_r])
+fi
+
dnl ----------------------------- We have a fallback position
if test "$have_int64_strfn" = "0" && test "$int64_strfn" = "strtoll"; then
int64_strfn="strtoq"