diff options
Diffstat (limited to 'libc')
| -rw-r--r-- | libc/misc/Makefile | 2 | ||||
| -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 | ||||
| -rw-r--r-- | libc/sysdeps/linux/common/Makefile | 7 | 
11 files changed, 348 insertions, 6 deletions
| diff --git a/libc/misc/Makefile b/libc/misc/Makefile index 47c0edd1e..0abb71201 100644 --- a/libc/misc/Makefile +++ b/libc/misc/Makefile @@ -25,7 +25,7 @@ include $(TOPDIR)Rules.mak  LIBC=$(TOPDIR)libc.a -DIRS = assert crypt ctype fnmatch glob internals lsearch mntent syslog \ +DIRS = assert crypt ctype dirent fnmatch glob internals lsearch mntent syslog \  	time utmp tsearch locale sysvipc  all: libc.a 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; +} diff --git a/libc/sysdeps/linux/common/Makefile b/libc/sysdeps/linux/common/Makefile index c54f7cd1d..8dae9d1d3 100644 --- a/libc/sysdeps/linux/common/Makefile +++ b/libc/sysdeps/linux/common/Makefile @@ -25,12 +25,9 @@ TOPDIR=../../../  include $(TOPDIR)Rules.mak  LIBC=$(TOPDIR)libc.a -CSRC=	waitpid.c getdents.c kernel_version.c rewinddir.c \ -	statfix.c getdnnm.c seekdir.c telldir.c tell.c gethstnm.c \ -	mkfifo.c setegid.c wait.c errno.c closedir.c getpagesize.c \ -	opendir.c seteuid.c wait3.c dirfd.c readdir.c setpgrp.c \ +CSRC=	waitpid.c getdents.c kernel_version.c statfix.c getdnnm.c tell.c gethstnm.c \ +	mkfifo.c setegid.c wait.c errno.c getpagesize.c  seteuid.c wait3.c setpgrp.c \  	getdtablesize.c -  COBJS=$(patsubst %.c,%.o, $(CSRC))  MSRC=syscalls.c | 
