summaryrefslogtreecommitdiff
path: root/libc/misc/dirent
diff options
context:
space:
mode:
Diffstat (limited to 'libc/misc/dirent')
-rw-r--r--libc/misc/dirent/Makefile44
-rw-r--r--libc/misc/dirent/closedir.c26
-rw-r--r--libc/misc/dirent/dirfd.c12
-rw-r--r--libc/misc/dirent/dirstream.h75
-rw-r--r--libc/misc/dirent/opendir.c55
-rw-r--r--libc/misc/dirent/readdir.c69
-rw-r--r--libc/misc/dirent/rewinddir.c15
-rw-r--r--libc/misc/dirent/seekdir.c14
-rw-r--r--libc/misc/dirent/telldir.c35
9 files changed, 345 insertions, 0 deletions
diff --git a/libc/misc/dirent/Makefile b/libc/misc/dirent/Makefile
new file mode 100644
index 000000000..e09773ead
--- /dev/null
+++ b/libc/misc/dirent/Makefile
@@ -0,0 +1,44 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2001 by Lineo, inc.
+#
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Library General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option) any
+# later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Library General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Derived in part from the Linux-8086 C library, the GNU C Library, and several
+# other sundry sources. Files within this library are copyright by their
+# respective copyright holders.
+
+TOPDIR=../../
+include $(TOPDIR)Rules.mak
+LIBC=$(TOPDIR)libc.a
+
+CSRC=closedir.c dirfd.c opendir.c readdir.c rewinddir.c seekdir.c telldir.c
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+OBJS=$(COBJS)
+
+all: $(OBJS) $(LIBC)
+
+$(LIBC): ar-target
+
+ar-target: $(OBJS)
+ $(AR) $(ARFLAGS) $(LIBC) $(OBJS)
+
+$(COBJS): %.o : %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+clean:
+ rm -f *.[oa] *~ core
+
diff --git a/libc/misc/dirent/closedir.c b/libc/misc/dirent/closedir.c
new file mode 100644
index 000000000..f2ead00f2
--- /dev/null
+++ b/libc/misc/dirent/closedir.c
@@ -0,0 +1,26 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+int closedir(DIR * dir)
+{
+ int fd;
+
+ if (!dir) {
+ errno = EBADF;
+ return -1;
+ }
+
+ /* We need to check dd_fd. */
+ if (dir->dd_fd == -1) {
+ errno = EBADF;
+ return -1;
+ }
+ fd = dir->dd_fd;
+ dir->dd_fd = -1;
+ free(dir->dd_buf);
+ free(dir);
+ return close(fd);
+}
diff --git a/libc/misc/dirent/dirfd.c b/libc/misc/dirent/dirfd.c
new file mode 100644
index 000000000..d401dccd2
--- /dev/null
+++ b/libc/misc/dirent/dirfd.c
@@ -0,0 +1,12 @@
+#include <errno.h>
+#include "dirstream.h"
+
+int dirfd(DIR * dir)
+{
+ if (!dir || dir->dd_fd == -1) {
+ errno = EBADF;
+ return -1;
+ }
+
+ return dir->dd_fd;
+}
diff --git a/libc/misc/dirent/dirstream.h b/libc/misc/dirent/dirstream.h
new file mode 100644
index 000000000..2b06b1501
--- /dev/null
+++ b/libc/misc/dirent/dirstream.h
@@ -0,0 +1,75 @@
+/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public License as
+published by the Free Software Foundation; either version 2 of the
+License, or (at your option) any later version.
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with the GNU C Library; see the file COPYING.LIB. If
+not, write to the, 1992 Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA. */
+
+/*
+ * POSIX Standard: 5.1.2 Directory Operations <dirent.h>
+ */
+
+#ifndef _DIRSTREAM_H
+
+#define _DIRSTREAM_H 1
+
+#include <sys/types.h>
+#include <dirent.h>
+#ifdef _POSIX_THREADS
+#include <pthread.h>
+#endif
+
+/* For now, syscall readdir () only supports one entry at a time. It
+ * will be changed in the future.
+#define NUMENT 3
+*/
+#ifndef NUMENT
+#define NUMENT 1
+#endif
+
+#define SINGLE_READDIR 11
+#define MULTI_READDIR 12
+#define NEW_READDIR 13
+
+/* Directory stream type. */
+struct __dirstream {
+ /* file descriptor */
+ int dd_fd;
+
+ /* offset of the next dir entry in buffer */
+ off_t dd_nextloc;
+
+ /* bytes of valid entries in buffer */
+ size_t dd_size;
+
+ /* -> directory buffer */
+ struct dirent *dd_buf;
+
+ /* offset of the next dir entry in directory. */
+ off_t dd_nextoff;
+
+ /* total size of buffer */
+ size_t dd_max;
+
+ enum {unknown, have_getdents, no_getdents} dd_getdents;
+
+ /* lock */
+#ifdef _POSIX_THREADS
+ pthread_mutex_t *dd_lock;
+#else
+ void *dd_lock;
+#endif
+}; /* stream data from opendir() */
+
+#endif /* dirent.h */
diff --git a/libc/misc/dirent/opendir.c b/libc/misc/dirent/opendir.c
new file mode 100644
index 000000000..329515447
--- /dev/null
+++ b/libc/misc/dirent/opendir.c
@@ -0,0 +1,55 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/dir.h>
+#include <sys/stat.h>
+#include "dirstream.h"
+
+
+/* opendir just makes an open() call - it return NULL if it fails
+ * (open sets errno), otherwise it returns a DIR * pointer.
+ */
+DIR *opendir(const char *name)
+{
+ int fd;
+ struct stat statbuf;
+ struct dirent *buf;
+ DIR *ptr;
+
+ if (stat(name, &statbuf))
+ return NULL;
+ if (!S_ISDIR(statbuf.st_mode)) {
+ errno = ENOTDIR;
+ return NULL;
+ }
+ if ((fd = open(name, O_RDONLY)) < 0)
+ return NULL;
+ /* According to POSIX, directory streams should be closed when
+ * exec. From "Anna Pluzhnikov" <besp@midway.uchicago.edu>.
+ */
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0)
+ return NULL;
+ if (!(ptr = malloc(sizeof(*ptr)))) {
+ close(fd);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ ptr->dd_max = statbuf.st_blksize;
+ if (ptr->dd_max < 512)
+ ptr->dd_max = 512;
+
+ if (!(buf = malloc(ptr->dd_max))) {
+ close(fd);
+ free(ptr);
+ errno = ENOMEM;
+ return NULL;
+ }
+ ptr->dd_fd = fd;
+ ptr->dd_nextoff = ptr->dd_nextloc = ptr->dd_size = 0;
+ ptr->dd_buf = buf;
+ ptr->dd_getdents = unknown;
+ return ptr;
+}
diff --git a/libc/misc/dirent/readdir.c b/libc/misc/dirent/readdir.c
new file mode 100644
index 000000000..a755ed24d
--- /dev/null
+++ b/libc/misc/dirent/readdir.c
@@ -0,0 +1,69 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include "dirstream.h"
+
+extern int getdents __P ((unsigned int fd, struct dirent *dirp, unsigned int count));
+
+
+struct dirent *readdir(DIR * dir)
+{
+ int result;
+ struct dirent *de;
+
+ if (!dir) {
+ errno = EBADF;
+ return NULL;
+ }
+
+ /* Are we running an old kernel? */
+ if (dir->dd_getdents == no_getdents) {
+ abort();
+ }
+
+ if (dir->dd_size <= dir->dd_nextloc) {
+ /* read dir->dd_max bytes of directory entries. */
+ result = getdents(dir->dd_fd, dir->dd_buf, dir->dd_max);
+
+ /* We assume we have getdents (). */
+ dir->dd_getdents = have_getdents;
+ if (result <= 0) {
+ result = -result;
+ if (result > 0) {
+ /* Are we right? */
+ if (result == ENOSYS) {
+ dir->dd_getdents = no_getdents;
+ abort();
+ }
+ errno = result;
+ }
+
+ return NULL;
+ }
+
+ dir->dd_size = result;
+ dir->dd_nextloc = 0;
+ }
+
+ de = (struct dirent *) (((char *) dir->dd_buf) + dir->dd_nextloc);
+
+ /* Am I right? H.J. */
+ dir->dd_nextloc += de->d_reclen;
+
+ /* We have to save the next offset here. */
+ dir->dd_nextoff = de->d_off;
+
+ /* convert */
+ dir->dd_buf->d_ino = de->d_ino;
+ dir->dd_buf->d_off = de->d_off;
+ dir->dd_buf->d_reclen = de->d_reclen;
+ dir->dd_buf->d_type = 0;
+ if (strlen((char *) &de->d_type) > 10)
+ de->d_name[10] = 0;
+ strcpy(dir->dd_buf->d_name, (char *) &de->d_name);
+ errno = 0;
+
+ return dir->dd_buf;
+}
diff --git a/libc/misc/dirent/rewinddir.c b/libc/misc/dirent/rewinddir.c
new file mode 100644
index 000000000..9d147fca2
--- /dev/null
+++ b/libc/misc/dirent/rewinddir.c
@@ -0,0 +1,15 @@
+#include <errno.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+/* rewinddir() just does an lseek(fd,0,0) - see close for comments */
+void rewinddir(DIR * dir)
+{
+ if (!dir) {
+ errno = EBADF;
+ return;
+ }
+ lseek(dir->dd_fd, 0, SEEK_SET);
+ dir->dd_nextoff = dir->dd_nextloc = dir->dd_size = 0;
+}
diff --git a/libc/misc/dirent/seekdir.c b/libc/misc/dirent/seekdir.c
new file mode 100644
index 000000000..7e4f24f72
--- /dev/null
+++ b/libc/misc/dirent/seekdir.c
@@ -0,0 +1,14 @@
+#include <errno.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+void seekdir(DIR * dir, off_t offset)
+{
+ if (!dir) {
+ errno = EBADF;
+ return;
+ }
+ dir->dd_nextoff = lseek(dir->dd_fd, offset, SEEK_SET);
+ dir->dd_size = dir->dd_nextloc = 0;
+}
diff --git a/libc/misc/dirent/telldir.c b/libc/misc/dirent/telldir.c
new file mode 100644
index 000000000..33e163aba
--- /dev/null
+++ b/libc/misc/dirent/telldir.c
@@ -0,0 +1,35 @@
+#include <errno.h>
+#include <unistd.h>
+#include "dirstream.h"
+
+
+off_t telldir(DIR * dir)
+{
+ off_t offset;
+
+ if (!dir) {
+ errno = EBADF;
+ return -1;
+ }
+
+ switch (dir->dd_getdents) {
+ case no_getdents:
+ /* We are running the old kernel. This is the starting offset
+ of the next readdir(). */
+ offset = lseek(dir->dd_fd, 0, SEEK_CUR);
+ break;
+
+ case unknown:
+ /* readdir () is not called yet. but seekdir () may be called. */
+ case have_getdents:
+ /* The next entry. */
+ offset = dir->dd_nextoff;
+ break;
+
+ default:
+ errno = EBADF;
+ offset = -1;
+ }
+
+ return offset;
+}