diff options
Diffstat (limited to 'libc/misc/dirent')
-rw-r--r-- | libc/misc/dirent/Makefile | 44 | ||||
-rw-r--r-- | libc/misc/dirent/closedir.c | 26 | ||||
-rw-r--r-- | libc/misc/dirent/dirfd.c | 12 | ||||
-rw-r--r-- | libc/misc/dirent/dirstream.h | 75 | ||||
-rw-r--r-- | libc/misc/dirent/opendir.c | 55 | ||||
-rw-r--r-- | libc/misc/dirent/readdir.c | 69 | ||||
-rw-r--r-- | libc/misc/dirent/rewinddir.c | 15 | ||||
-rw-r--r-- | libc/misc/dirent/seekdir.c | 14 | ||||
-rw-r--r-- | libc/misc/dirent/telldir.c | 35 |
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; +} |