Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--newlib/libc/include/dirent.h3
-rw-r--r--winsup/cygwin/cygwin.din1
-rw-r--r--winsup/cygwin/dir.cc58
-rw-r--r--winsup/cygwin/fhandler/base.cc6
-rw-r--r--winsup/cygwin/include/cygwin/version.h3
-rw-r--r--winsup/cygwin/include/sys/dirent.h23
-rw-r--r--winsup/cygwin/local_includes/fhandler.h14
-rw-r--r--winsup/cygwin/release/3.6.02
-rw-r--r--winsup/cygwin/syscalls.cc29
9 files changed, 131 insertions, 8 deletions
diff --git a/newlib/libc/include/dirent.h b/newlib/libc/include/dirent.h
index cdfa21fa7..cc7e9e0f0 100644
--- a/newlib/libc/include/dirent.h
+++ b/newlib/libc/include/dirent.h
@@ -80,6 +80,9 @@ int scandirat(int, const char *, struct dirent ***,
const struct dirent **));
int versionsort(const struct dirent **, const struct dirent **);
#endif
+#if __POSIX_VISIBLE >= 200809
+ssize_t posix_getdents(int, void *, size_t, int);
+#endif /* __POSIX_VISIBLE >= 200809 */
__END_DECLS
#endif /*_DIRENT_H_*/
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 049be4cd0..6bac40cc0 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -1046,6 +1046,7 @@ poll SIGFE
popen SIGFE
posix_fadvise SIGFE
posix_fallocate SIGFE
+posix_getdents SIGFE
posix_madvise SIGFE
posix_memalign SIGFE
posix_openpt SIGFE
diff --git a/winsup/cygwin/dir.cc b/winsup/cygwin/dir.cc
index 82797a41f..c2cba839e 100644
--- a/winsup/cygwin/dir.cc
+++ b/winsup/cygwin/dir.cc
@@ -9,6 +9,7 @@ details. */
#include "winsup.h"
#include <stdlib.h>
#include <unistd.h>
+#include <sys/stat.h>
#define _LIBC
#include <dirent.h>
@@ -201,6 +202,63 @@ readdir_r (DIR *__restrict dir, dirent *__restrict de, dirent **__restrict ode)
return res;
}
+/* Not exposed through sys/stat.h when building Cygwin */
+extern "C" int fstatat (int, const char *__restrict ,
+ struct stat *__restrict, int);
+
+extern "C"
+ssize_t posix_getdents(int fd, void *buf, size_t nbytes, int flags)
+{
+ struct posix_dent *dent_buf, *src;
+ ssize_t cnt = 0;
+
+ cygheap_fdget cfd (fd);
+ /* Valid descriptor? */
+ if (cfd < 0)
+ return -1;
+ /* Valid flags? Right now only DT_FORCE_TYPE is defined */
+ if ((flags & ~DT_FORCE_TYPE) != 0)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ /* Create type-safe buffer pointer */
+ dent_buf = (struct posix_dent *) buf;
+ /* Check if nbytes is big enough to fit at least one struct posix_dent */
+ if (nbytes < sizeof (struct posix_dent))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+ /* Create internal DIR * on first invocation */
+ if (!cfd->getdents_dir ())
+ {
+ cfd->getdents_dir (cfd->opendir (fd));
+ if (!cfd->getdents_dir ())
+ return -1;
+ }
+ /* Now loop until EOF or buf is full */
+ while (nbytes >= sizeof (struct posix_dent))
+ {
+ /* Our struct posix_dent is identical to struct dirent */
+ src = (struct posix_dent *) readdir (cfd->getdents_dir ());
+ if (!src)
+ break;
+ /* Handle the suggested DT_FORCE_TYPE flag */
+ if (src->d_type == DT_UNKNOWN && (flags & DT_FORCE_TYPE))
+ {
+ struct stat st;
+
+ if (!fstatat (fd, src->d_name, &st, AT_SYMLINK_NOFOLLOW))
+ src->d_type = IFTODT (st.st_mode);
+ }
+ *dent_buf++ = *src;
+ ++cnt;
+ nbytes -= sizeof (struct posix_dent);
+ }
+ return cnt * sizeof (struct posix_dent);
+}
+
/* telldir */
extern "C" long
telldir (DIR *dir)
diff --git a/winsup/cygwin/fhandler/base.cc b/winsup/cygwin/fhandler/base.cc
index f1ad37522..643236751 100644
--- a/winsup/cygwin/fhandler/base.cc
+++ b/winsup/cygwin/fhandler/base.cc
@@ -1316,6 +1316,7 @@ fhandler_base::close ()
paranoid_printf ("CloseHandle failed, %E");
__seterrno ();
}
+ clear_getdents ();
return res;
}
@@ -1432,7 +1433,10 @@ fhandler_base::dup (fhandler_base *child, int flags)
VerifyHandle (nh);
child->set_handle (nh);
+ /* Just set to NULL, the struct is potentially still valid
+ in the parent fhandler. */
}
+ child->getdents_dir (NULL);
return 0;
}
@@ -1632,6 +1636,7 @@ fhandler_base::fixup_after_fork (HANDLE parent)
/* POSIX locks are not inherited across fork. */
if (unique_id)
del_my_locks (after_fork);
+ clear_getdents ();
}
void
@@ -1640,6 +1645,7 @@ fhandler_base::fixup_after_exec ()
debug_printf ("here for '%s'", get_name ());
if (unique_id && close_on_exec ())
del_my_locks (after_exec);
+ getdents_dir (NULL);
mandatory_locking (false);
}
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index e21e04add..6679eedd9 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -488,12 +488,13 @@ details. */
351: Add getlocalename_l.
352: Implement dirent.d_reclen.
353: Implement fdclosedir.
+ 354: Implement posix_getdents.
Note that we forgot to bump the api for ualarm, strtoll, strtoull,
sigaltstack, sethostname. */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 353
+#define CYGWIN_VERSION_API_MINOR 354
/* There is also a compatibity version number associated with the shared memory
regions. It is incremented when incompatible changes are made to the shared
diff --git a/winsup/cygwin/include/sys/dirent.h b/winsup/cygwin/include/sys/dirent.h
index dae324a7f..6272ea329 100644
--- a/winsup/cygwin/include/sys/dirent.h
+++ b/winsup/cygwin/include/sys/dirent.h
@@ -37,14 +37,30 @@ struct dirent
char d_name[NAME_MAX + 1];
};
+#if __POSIX_VISIBLE >= 200809
+#define DT_FORCE_TYPE 0x01 /* Suggested by SUS Base Specs Issue 8 */
+
+typedef __uint16_t reclen_t;
+
+/* This is a drop-in replacement for DIR, but used from posix_getdent()
+ per SUS Base Specs Issue 8 */
+struct posix_dent
+{
+ __uint32_t __d_version;
+ ino_t d_ino;
+ unsigned char d_type;
+ unsigned char __d_unused1[1];
+ reclen_t d_reclen;
+ __uint32_t __d_internal1;
+ char d_name[NAME_MAX + 1];
};
+#endif /* __POSIX_VISIBLE >= 200809 */
#define d_fileno d_ino /* BSD compatible definition */
typedef struct __DIR DIR;
-#if __BSD_VISIBLE
-#ifdef _DIRENT_HAVE_D_TYPE
+#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809
/* File types for `d_type'. */
enum
{
@@ -67,10 +83,11 @@ enum
DT_WHT = 14
# define DT_WHT DT_WHT
};
+#endif /* __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 */
+#if __BSD_VISIBLE
/* Convert between stat structure types and directory types. */
# define IFTODT(mode) (((mode) & 0170000) >> 12)
# define DTTOIF(dirtype) ((dirtype) << 12)
-#endif /* _DIRENT_HAVE_D_TYPE */
#endif /* __BSD_VISIBLE */
#endif /*_SYS_DIRENT_H*/
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h
index 1dc02608b..8e3088447 100644
--- a/winsup/cygwin/local_includes/fhandler.h
+++ b/winsup/cygwin/local_includes/fhandler.h
@@ -214,6 +214,9 @@ class fhandler_base
struct rabuf_t ra;
+ /* Used for posix_getdents () */
+ DIR *_getdents_dir;
+
/* Used for advisory file locking. See flock.cc. */
int64_t unique_id;
void del_my_locks (del_lock_called_from);
@@ -526,6 +529,17 @@ public:
}
HANDLE get_select_sem () { return select_sem; }
+
+ DIR *getdents_dir () const { return _getdents_dir; }
+ DIR *getdents_dir (DIR *_nd) { return _getdents_dir = _nd; }
+ void clear_getdents ()
+ {
+ if (getdents_dir ())
+ {
+ fdclosedir (getdents_dir ());
+ getdents_dir (NULL);
+ }
+ }
};
struct wsa_event
diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0
index fe933d8c7..f7754bd19 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -3,7 +3,7 @@ What's new:
- New API call: getlocalename_l.
-- New API call: fdclosedir.
+- New API calls: fdclosedir, posix_getdents.
What changed:
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 9d88b60b0..600c6c54e 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1609,10 +1609,33 @@ lseek (int fd, off_t pos, int dir)
else
{
cygheap_fdget cfd (fd);
- if (cfd >= 0)
- res = cfd->lseek (pos, dir);
- else
+ if (cfd < 0)
res = -1;
+ else if (cfd->getdents_dir ())
+ {
+ if (dir != SEEK_SET && dir != SEEK_CUR) /* No SEEK_END */
+ {
+ set_errno (EINVAL);
+ res = -1;
+ }
+ else
+ {
+ long cur;
+
+ cur = cfd->telldir (cfd->getdents_dir ());
+ if (dir == SEEK_CUR && cur == 0)
+ res = cur;
+ else
+ {
+ if (dir == SEEK_CUR)
+ pos = cur + pos;
+ cfd->seekdir (cfd->getdents_dir (), pos);
+ res = pos;
+ }
+ }
+ }
+ else
+ res = cfd->lseek (pos, dir);
}
/* Can't use %R/%lR here since res is always 8 bytes */
syscall_printf (res == -1 ? "%D = lseek(%d, %D, %d), errno %d"