Simplify directory reading.

This commit is contained in:
Jonas 'Sortie' Termansen 2015-11-20 02:57:09 +01:00
parent 56085108b6
commit 2e4b15daed
34 changed files with 139 additions and 590 deletions

View File

@ -148,7 +148,7 @@ bool RespondMakeDir(int chl, ino_t ino)
return RespondMessage(chl, FSM_RESP_MKDIR, &body, sizeof(body));
}
bool RespondReadDir(int chl, struct kernel_dirent* dirent)
bool RespondReadDir(int chl, struct dirent* dirent)
{
struct fsm_resp_readdirents body;
body.ino = dirent->d_ino;
@ -371,8 +371,8 @@ void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
}
union
{
struct kernel_dirent kernel_entry;
uint8_t padding[sizeof(struct kernel_dirent) + 256];
struct dirent kernel_entry;
uint8_t padding[sizeof(struct dirent) + 256];
};
memset(&kernel_entry, 0, sizeof(kernel_entry));
@ -398,13 +398,12 @@ void HandleReadDir(int chl, struct fsm_req_readdirents* msg, Filesystem* fs)
if ( entry->inode && entry->name_len && !(msg->rec_num--) )
{
kernel_entry.d_reclen = sizeof(kernel_entry) + entry->name_len;
kernel_entry.d_nextoff = 0;
kernel_entry.d_ino = entry->inode;
kernel_entry.d_dev = 0;
kernel_entry.d_type = 0; // TODO: Support this!
kernel_entry.d_namlen = entry->name_len;
memcpy(kernel_entry.d_name, entry->name, entry->name_len);
size_t dname_offset = offsetof(struct kernel_dirent, d_name);
size_t dname_offset = offsetof(struct dirent, d_name);
padding[dname_offset + kernel_entry.d_namlen] = '\0';
block->Unref();
inode->Unref();

View File

@ -351,9 +351,8 @@ int Descriptor::isatty(ioctx_t* ctx)
}
ssize_t Descriptor::readdirents(ioctx_t* ctx,
struct kernel_dirent* dirent,
size_t size,
size_t maxcount)
struct dirent* dirent,
size_t size)
{
// TODO: COMPATIBILITY HACK: Traditionally, you can open a directory with
// O_RDONLY and pass it to fdopendir and then use it, which doesn't
@ -370,35 +369,12 @@ ssize_t Descriptor::readdirents(ioctx_t* ctx,
// because the execute bit on directories control search permission.
if ( !(dflags & (O_SEARCH | O_READ | O_WRITE)) )
return errno = EPERM, -1;
if ( !maxcount )
return 0;
if ( 1 < maxcount )
maxcount = 1;
if ( SSIZE_MAX < size )
size = SSIZE_MAX;
if ( size < sizeof(*dirent) )
return errno = EINVAL, -1;
ScopedLock lock(&current_offset_lock);
ssize_t ret = vnode->readdirents(ctx, dirent, size, current_offset, maxcount);
if ( ret == 0 )
{
const char* name = "";
size_t name_length = strlen(name);
size_t needed = sizeof(*dirent) + name_length + 1;
struct kernel_dirent retdirent;
memset(&retdirent, 0, sizeof(retdirent));
retdirent.d_reclen = needed;
retdirent.d_nextoff = 0;
retdirent.d_namlen = name_length;
if ( !ctx->copy_to_dest(dirent, &retdirent, sizeof(retdirent)) )
return -1;
if ( size < needed )
return errno = ERANGE, -1;
if ( !ctx->copy_to_dest(dirent->d_name, name, name_length+1) )
return -1;
return needed;
}
ssize_t ret = vnode->readdirents(ctx, dirent, size, current_offset);
if ( 0 < ret )
current_offset++;
return ret;

View File

@ -217,39 +217,29 @@ Dir::~Dir()
delete[] children;
}
ssize_t Dir::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t /*maxcount*/)
ssize_t Dir::readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
off_t start)
{
ScopedLock lock(&dir_lock);
if ( children_used <= (uintmax_t) start )
return 0;
struct kernel_dirent retdirent;
struct dirent retdirent;
memset(&retdirent, 0, sizeof(retdirent));
const char* name = children[start].name;
size_t namelen = strlen(name);
size_t needed = sizeof(*dirent) + namelen + 1;
ssize_t ret = -1;
if ( size < needed )
{
errno = ERANGE;
retdirent.d_namlen = namelen;
}
else
{
Ref<Inode> inode = children[start].inode;
ret = needed;
retdirent.d_reclen = needed;
retdirent.d_nextoff = 0;
retdirent.d_namlen = namelen;
retdirent.d_ino = inode->ino;
retdirent.d_dev = inode->dev;
retdirent.d_type = ModeToDT(inode->type);
}
Ref<Inode> inode = children[start].inode;
retdirent.d_reclen = sizeof(*dirent) + namelen + 1;
retdirent.d_namlen = namelen;
retdirent.d_ino = inode->ino;
retdirent.d_dev = inode->dev;
retdirent.d_type = ModeToDT(inode->type);
if ( !ctx->copy_to_dest(dirent, &retdirent, sizeof(retdirent)) )
return -1;
if ( 0 <= ret && !ctx->copy_to_dest(dirent->d_name, name, namelen+1) )
if ( size < retdirent.d_reclen )
return errno = ERANGE, -1;
if ( !ctx->copy_to_dest(dirent->d_name, name, namelen+1) )
return -1;
return ret;
return (ssize_t) retdirent.d_reclen;
}
size_t Dir::FindChild(const char* filename)

View File

@ -65,8 +65,8 @@ class Dir : public AbstractInode
public:
Dir(dev_t dev, ino_t ino, uid_t owner, gid_t group, mode_t mode);
virtual ~Dir();
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t maxcount);
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
size_t size, off_t start);
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);

View File

@ -217,8 +217,8 @@ public:
const struct timespec* ctime,
const struct timespec* mtime);
virtual int isatty(ioctx_t* ctx);
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t maxcount);
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
size_t size, off_t start);
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
@ -1009,8 +1009,8 @@ int Unode::isatty(ioctx_t* ctx)
return ret;
}
ssize_t Unode::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t /*maxcount*/)
ssize_t Unode::readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
off_t start)
{
Channel* channel = server->Connect(ctx);
if ( !channel )
@ -1030,9 +1030,9 @@ ssize_t Unode::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
goto break_if;
}
struct kernel_dirent entry;
struct dirent entry;
memset(&entry, 0, sizeof(entry));
entry.d_reclen = sizeof(entry) + resp.namelen + 1;
entry.d_nextoff = 0;
entry.d_namlen = resp.namelen;
entry.d_dev = (dev_t) server;
entry.d_ino = resp.ino;
@ -1041,14 +1041,13 @@ ssize_t Unode::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
if ( !ctx->copy_to_dest(dirent, &entry, sizeof(entry)) )
goto break_if;
size_t needed = sizeof(*dirent) + resp.namelen + 1;
if ( size < needed && (errno = ERANGE) )
if ( size < entry.d_reclen && (errno = ERANGE) )
goto break_if;
uint8_t nul = 0;
char nul = '\0';
if ( channel->KernelRecv(ctx, dirent->d_name, resp.namelen) &&
ctx->copy_to_dest(&dirent->d_name[resp.namelen], &nul, 1) )
ret = (ssize_t) needed;
ret = (ssize_t) entry.d_reclen;
} break_if:
channel->KernelClose();
return ret;

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2012, 2014, 2015.
This file is part of Sortix.
@ -54,11 +54,7 @@ typedef __ino_t ino_t;
#include <stddef.h>
#endif
#ifndef NULL
#define __need_NULL
#include <stddef.h>
#endif
#if __USE_SORTIX
#define DT_UNKNOWN __DT_UNKNOWN
#define DT_BLK __DT_BLK
#define DT_CHR __DT_CHR
@ -67,14 +63,16 @@ typedef __ino_t ino_t;
#define DT_LNK __DT_LNK
#define DT_REG __DT_REG
#define DT_SOCK __DT_SOCK
#endif
#if __USE_SORTIX
#define IFTODT(x) __IFTODT(x)
#define DTTOIF(x) __DTTOIF(x)
#endif
struct kernel_dirent
struct dirent
{
size_t d_reclen;
size_t d_nextoff;
size_t d_namlen;
ino_t d_ino;
dev_t d_dev;
@ -82,13 +80,6 @@ struct kernel_dirent
__extension__ char d_name[];
};
static __inline struct kernel_dirent* kernel_dirent_next(struct kernel_dirent* ent)
{
if ( !ent->d_nextoff )
return NULL;
return (struct kernel_dirent*) ((uint8_t*) ent + ent->d_nextoff);
}
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -34,12 +34,12 @@
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/refcount.h>
struct dirent;
struct stat;
struct statvfs;
struct termios;
struct wincurpos;
struct winsize;
struct kernel_dirent;
namespace Sortix {
@ -75,8 +75,7 @@ public:
int utimens(ioctx_t* ctx, const struct timespec* atime,
const struct timespec* ctime, const struct timespec* mtime);
int isatty(ioctx_t* ctx);
ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent, size_t size,
size_t maxcount);
ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size);
Ref<Descriptor> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode = 0);
int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);

View File

@ -34,12 +34,12 @@
#include <sortix/kernel/refcount.h>
struct dirent;
struct stat;
struct statvfs;
struct termios;
struct wincurpos;
struct winsize;
struct kernel_dirent;
namespace Sortix {
@ -76,8 +76,8 @@ public:
const struct timespec* ctime,
const struct timespec* mtime) = 0;
virtual int isatty(ioctx_t* ctx) = 0;
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t maxcount) = 0;
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
size_t size, off_t start) = 0;
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode) = 0;
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode) = 0;
@ -171,8 +171,8 @@ public:
const struct timespec* ctime,
const struct timespec* mtime);
virtual int isatty(ioctx_t* ctx);
virtual ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t maxcount);
virtual ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent,
size_t size, off_t start);
virtual Ref<Inode> open(ioctx_t* ctx, const char* filename, int flags,
mode_t mode);
virtual int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);

View File

@ -129,7 +129,7 @@ ssize_t sys_pwritev(int, const struct iovec*, int, off_t);
int sys_raise(int);
uint64_t sys_rdmsr(uint32_t);
ssize_t sys_read(int, void*, size_t);
ssize_t sys_readdirents(int, struct kernel_dirent*, size_t);
ssize_t sys_readdirents(int, struct dirent*, size_t);
ssize_t sys_readlinkat(int, const char*, char*, size_t);
ssize_t sys_readv(int, const struct iovec*, int);
ssize_t sys_recv(int, void*, size_t, int);

View File

@ -33,12 +33,12 @@
#include <sortix/kernel/refcount.h>
struct dirent;
struct stat;
struct statvfs;
struct termios;
struct wincurpos;
struct winsize;
struct kernel_dirent;
namespace Sortix {
@ -72,8 +72,8 @@ public:
int utimens(ioctx_t* ctx, const struct timespec* atime,
const struct timespec* ctime, const struct timespec* mtime);
int isatty(ioctx_t* ctx);
ssize_t readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t maxcount);
ssize_t readdirents(ioctx_t* ctx, struct dirent* dirent, size_t size,
off_t start);
Ref<Vnode> open(ioctx_t* ctx, const char* filename, int flags, mode_t mode);
int mkdir(ioctx_t* ctx, const char* filename, mode_t mode);
int unlink(ioctx_t* ctx, const char* filename);

View File

@ -383,11 +383,11 @@ bool ExtractFromPhysicalInto(addr_t physaddr, size_t size, Ref<Descriptor> desc)
union
{
struct kernel_dirent dirent;
uint8_t dirent_data[sizeof(struct kernel_dirent) + sizeof(uintmax_t) * 3];
struct dirent dirent;
uint8_t dirent_data[sizeof(struct dirent) + sizeof(uintmax_t) * 3];
};
while ( 0 < ctx.links->readdirents(&ctx.ioctx, &dirent, sizeof(dirent_data), 1) &&
while ( 0 < ctx.links->readdirents(&ctx.ioctx, &dirent, sizeof(dirent_data)) &&
((const char*) dirent.d_name)[0] )
{
if ( ((const char*) dirent.d_name)[0] == '.' )

View File

@ -202,9 +202,9 @@ int AbstractInode::isatty(ioctx_t* /*ctx*/)
}
ssize_t AbstractInode::readdirents(ioctx_t* /*ctx*/,
struct kernel_dirent* /*dirent*/,
size_t /*size*/, off_t /*start*/,
size_t /*maxcount*/)
struct dirent* /*dirent*/,
size_t /*size*/,
off_t /*start*/)
{
if ( inode_type == INODE_TYPE_DIR )
return errno = EBADF, -1;

View File

@ -382,16 +382,15 @@ int sys_ioctl(int fd, int cmd, uintptr_t arg)
}
}
ssize_t sys_readdirents(int fd, struct kernel_dirent* dirent, size_t size)
ssize_t sys_readdirents(int fd, struct dirent* dirent, size_t size)
{
if ( size < sizeof(kernel_dirent) ) { errno = EINVAL; return -1; }
if ( SSIZE_MAX < size )
size = SSIZE_MAX;
Ref<Descriptor> desc = CurrentProcess()->GetDescriptor(fd);
if ( !desc )
return -1;
ioctx_t ctx; SetupUserIOCtx(&ctx);
return desc->readdirents(&ctx, dirent, size, 1 /*maxcount*/);
return desc->readdirents(&ctx, dirent, size);
}
int sys_fchdir(int fd)

View File

@ -281,10 +281,10 @@ int Vnode::isatty(ioctx_t* ctx)
return inode->isatty(ctx);
}
ssize_t Vnode::readdirents(ioctx_t* ctx, struct kernel_dirent* dirent,
size_t size, off_t start, size_t count)
ssize_t Vnode::readdirents(ioctx_t* ctx, struct dirent* dirent,
size_t size, off_t start)
{
return inode->readdirents(ctx, dirent, size, start, count);
return inode->readdirents(ctx, dirent, size, start);
}
int Vnode::mkdir(ioctx_t* ctx, const char* filename, mode_t mode)

View File

@ -36,16 +36,7 @@ ctype/tolower.o \
ctype/toupper.o \
dirent/alphasort.o \
dirent/alphasort_r.o \
dirent/closedir.o \
dirent/dclearerr.o \
dirent/deof.o \
dirent/derror.o \
dirent/dirfd.o \
dirent/dnewdir.o \
dirent/dregister.o \
dirent/dunregister.o \
dirent/readdir.o \
dirent/rewinddir.o \
dirent/versionsort.o \
dirent/versionsort_r.o \
errno/errno.o \
@ -330,9 +321,12 @@ $(CPUDIR)/fork.o \
$(CPUDIR)/setjmp.o \
$(CPUDIR)/signal.o \
$(CPUDIR)/syscall.o \
dirent/closedir.o \
dirent/dscandir_r.o \
dirent/fdopendir.o \
dirent/opendir.o \
dirent/readdir.o \
dirent/rewinddir.o \
dirent/scandir.o \
dlfcn/dlfcn.o \
err/err.o \

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of the Sortix C Library.
@ -23,15 +23,13 @@
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
#include <stdlib.h>
#include <unistd.h>
extern "C" int closedir(DIR* dir)
{
int result = dir->close_func ? dir->close_func(dir->user) : 0;
dunregister(dir);
close(dir->fd);
free(dir->entry);
if ( dir->free_func )
dir->free_func(dir);
return result;
free(dir);
return 0;
}

View File

@ -1,31 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
dirent/dclearerr.cpp
Clears the error flag from a directory stream.
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
extern "C" void dclearerr(DIR* dir)
{
dir->flags &= ~_DIR_ERROR;
}

View File

@ -1,31 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
dirent/deof.cpp
Returns the end-of-file flag of a directory stream.
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
extern "C" int deof(DIR* dir)
{
return dir->flags & _DIR_EOF;
}

View File

@ -1,31 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
dirent/derror.cpp
Returns the error flag of a directory stream.
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
extern "C" int derror(DIR* dir)
{
return dir->flags & _DIR_ERROR;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of the Sortix C Library.
@ -23,12 +23,9 @@
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
#include <errno.h>
extern "C" int dirfd(DIR* dir)
{
if ( !dir->fd_func )
return errno = EBADF, 0;
return dir->fd_func(dir->user);
return dir->fd;
}

View File

@ -1,45 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
dirent/dnewdir.cpp
Allocates and registers a new directory stream structure.
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
#include <stddef.h>
#include <stdlib.h>
static void dfreedir(DIR* dir)
{
free(dir);
}
extern "C" DIR* dnewdir(void)
{
DIR* dir = (DIR*) calloc(sizeof(DIR), 1);
if ( !dir )
return NULL;
dir->flags = 0;
dir->free_func = dfreedir;
dir->closedir_indirect = closedir;
dregister(dir);
return dir;
}

View File

@ -1,36 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
dirent/dregister.cpp
Registers an directory stream for later automatic closing.
*******************************************************************************/
#include <dirent.h>
#include <pthread.h>
extern "C" void dregister(DIR* dir)
{
pthread_mutex_lock(&__first_dir_lock);
dir->flags |= _DIR_REGISTERED;
if ( (dir->next = __first_dir) )
dir->next->prev = dir;
__first_dir = dir;
pthread_mutex_unlock(&__first_dir_lock);
}

View File

@ -1,41 +0,0 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
This file is part of the Sortix C Library.
The Sortix C Library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your
option) any later version.
The Sortix 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 Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
dirent/dunregister.cpp
Unregisters an directory stream for later automatic closing.
*******************************************************************************/
#include <dirent.h>
#include <pthread.h>
extern "C" void dunregister(DIR* dir)
{
if ( !(dir->flags & _DIR_REGISTERED) )
return;
pthread_mutex_lock(&__first_dir_lock);
if ( !dir->prev )
__first_dir = dir->next;
if ( dir->prev )
dir->prev->next = dir->next;
if ( dir->next )
dir->next->prev = dir->prev;
dir->flags &= ~_DIR_REGISTERED;
pthread_mutex_unlock(&__first_dir_lock);
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of the Sortix C Library.
@ -22,129 +22,20 @@
*******************************************************************************/
#include <sys/readdirents.h>
#include <assert.h>
#include <dirent.h>
#include <DIR.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct fddir_sortix_struct
{
struct kernel_dirent* dirent;
struct kernel_dirent* current;
size_t direntsize;
int fd;
} fddir_sortix_t;
static int fddir_sortix_readents(fddir_sortix_t* info)
{
if ( !info->dirent )
{
// Allocate a buffer of at least sizeof(kernel_dirent).
info->direntsize = sizeof(struct kernel_dirent) + 4UL;
info->dirent = (struct kernel_dirent*) malloc(info->direntsize);
if ( !info->dirent )
return -1;
}
int saved_errno = errno;
if ( readdirents(info->fd, info->dirent, info->direntsize) < 0 )
{
if ( errno != ERANGE )
return -1;
errno = saved_errno;
size_t newdirentsize = sizeof(struct kernel_dirent) + info->dirent->d_namlen + 1;
if ( newdirentsize < info->direntsize )
newdirentsize *= 2;
struct kernel_dirent* newdirent = (struct kernel_dirent*) malloc(newdirentsize);
if ( !newdirent )
return -1;
free(info->dirent);
info->dirent = newdirent;
info->direntsize = newdirentsize;
return fddir_sortix_readents(info);
}
return 0;
}
static int fddir_sortix_read(void* user, struct dirent* dirent, size_t* size)
{
fddir_sortix_t* info = (fddir_sortix_t*) user;
if ( !info->current )
{
if ( fddir_sortix_readents(info) )
return -1;
info->current = info->dirent;
}
size_t provided = (user) ? *size : 0;
size_t needed = sizeof(struct dirent) + info->current->d_namlen + 1;
*size = needed;
if ( provided < needed )
return 1;
dirent->d_reclen = needed;
dirent->d_namlen = info->current->d_namlen;
dirent->d_ino = info->current->d_ino;
dirent->d_dev = info->current->d_dev;
dirent->d_type = info->current->d_type;
strcpy(dirent->d_name, info->current->d_name);
info->current = kernel_dirent_next(info->current);
return 0;
}
static int fddir_sortix_rewind(void* user)
{
fddir_sortix_t* info = (fddir_sortix_t*) user;
return lseek(info->fd, 0, SEEK_SET);
}
static int fddir_sortix_fd(void* user)
{
fddir_sortix_t* info = (fddir_sortix_t*) user;
return info->fd;
}
static int fddir_sortix_close(void* user)
{
fddir_sortix_t* info = (fddir_sortix_t*) user;
int result = close(info->fd);
free(info->dirent);
free(info);
return result;
}
extern "C" DIR* fdopendir(int fd)
{
fddir_sortix_t* info = (fddir_sortix_t*) calloc(sizeof(fddir_sortix_t), 1);
if ( !info )
return NULL;
DIR* dir = dnewdir();
if ( !dir )
return free(info), (DIR*) NULL;
int old_dflags = fcntl(fd, F_GETFD);
if ( 0 <= old_dflags )
if ( 0 <= old_dflags && !(old_dflags & FD_CLOEXEC) )
fcntl(fd, F_SETFD, old_dflags | FD_CLOEXEC);
info->fd = fd;
dir->read_func = fddir_sortix_read;
dir->rewind_func = fddir_sortix_rewind;
dir->fd_func = fddir_sortix_fd;
dir->close_func = fddir_sortix_close;
dir->user = (void*) info;
// TODO: Potentially reopen as O_EXEC when the kernel requires that.
DIR* dir = (DIR*) calloc(sizeof(DIR), 1);
if ( !dir )
return NULL;
dir->fd = fd;
return dir;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of the Sortix C Library.
@ -24,16 +24,17 @@
#include <dirent.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
extern "C" DIR* opendir(const char* path)
{
int fd = open(path, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
int fd = open(path, O_SEARCH | O_DIRECTORY | O_CLOEXEC);
if ( fd < 0 )
return NULL;
DIR* dir = fdopendir(fd);
DIR* dir = (DIR*) calloc(sizeof(DIR), 1);
if ( !dir )
return close(fd), (DIR*) NULL;
dir->fd = fd;
return dir;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of the Sortix C Library.
@ -22,38 +22,34 @@
*******************************************************************************/
#include <sys/readdirents.h>
#include <dirent.h>
#include <DIR.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
extern "C" struct dirent* readdir(DIR* dir)
{
int old_errno = errno;
if ( !dir->read_func )
return dir->flags |= _DIR_ERROR, errno = EBADF, (struct dirent*) NULL;
size_t size = dir->entrysize;
int status;
while ( 0 < (status = dir->read_func(dir->user, dir->entry, &size)) )
struct dirent fallback;
struct dirent* entry = dir->entry ? dir->entry : &fallback;
size_t size = dir->entry ? dir->size : sizeof(fallback);
ssize_t amount;
while ( (amount = readdirents(dir->fd, entry, size)) < 0 )
{
struct dirent* biggerdir = (struct dirent*) malloc(size);
if ( !biggerdir )
return dir->flags |= _DIR_ERROR, (struct dirent*) NULL;
if ( errno != ERANGE )
return NULL;
errno = old_errno;
size_t needed = entry->d_reclen;
free(dir->entry);
dir->entry = biggerdir;
dir->entrysize = size;
dir->entry = NULL;
struct dirent* new_dirent = (struct dirent*) malloc(needed);
if ( !new_dirent )
return NULL;
entry = dir->entry = new_dirent;
size = dir->size = needed;
}
if ( status < 0 )
return dir->flags |= _DIR_ERROR, (struct dirent*) NULL;
dir->flags &= ~_DIR_ERROR;
if ( !dir->entry->d_name[0] )
return dir->flags |= _DIR_EOF, errno = old_errno, (struct dirent*) NULL;
if ( amount == 0 )
return NULL;
return dir->entry;
}

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2014, 2015.
This file is part of the Sortix C Library.
@ -23,11 +23,9 @@
*******************************************************************************/
#include <dirent.h>
#include <DIR.h>
#include <unistd.h>
extern "C" void rewinddir(DIR* dir)
{
if ( dir->rewind_func )
dir->rewind_func(dir->user);
dir->flags &= ~_DIR_EOF;
lseek(dir->fd, 0, SEEK_SET);
}

View File

@ -54,26 +54,11 @@ typedef struct __DIR DIR;
struct __DIR
{
void* user;
int (*read_func)(void* user, struct dirent* dirent, size_t* size);
int (*rewind_func)(void* user);
int (*fd_func)(void* user);
int (*close_func)(void* user);
void (*free_func)(DIR* dir);
/* Application writers shouldn't use anything beyond this point. */
int (*closedir_indirect)(DIR*);
DIR* prev;
DIR* next;
struct dirent* entry;
size_t entrysize;
int flags;
size_t size;
int fd;
};
#if defined(__is_sortix_libc)
extern DIR* __first_dir;
extern __pthread_mutex_t __first_dir_lock;
#endif
#ifdef __cplusplus
} /* extern "C" */
#endif

View File

@ -29,67 +29,25 @@
#include <sys/__/types.h>
#include <sortix/__/dirent.h>
#include <sortix/dirent.h>
#if defined(__is_sortix_libc)
#include <DIR.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __dev_t_defined
#define __dev_t_defined
typedef __dev_t dev_t;
#endif
#ifndef __ino_t_defined
#define __ino_t_defined
typedef __ino_t ino_t;
#endif
#ifndef __size_t_defined
#define __size_t_defined
#define __need_size_t
#include <stddef.h>
#endif
#ifndef __DIR_defined
#define __DIR_defined
typedef struct __DIR DIR;
#endif
#if __USE_SORTIX
#define DT_UNKNOWN __DT_UNKNOWN
#define DT_BLK __DT_BLK
#define DT_CHR __DT_CHR
#define DT_DIR __DT_DIR
#define DT_FIFO __DT_FIFO
#define DT_LNK __DT_LNK
#define DT_REG __DT_REG
#define DT_SOCK __DT_SOCK
#ifdef __cplusplus
extern "C" {
#endif
#if __USE_SORTIX
#define IFTODT(x) __IFTODT(x)
#define DTTOIF(x) __DTTOIF(x)
#endif
struct dirent
{
size_t d_reclen;
size_t d_namlen;
ino_t d_ino;
dev_t d_dev;
unsigned char d_type;
__extension__ char d_name[];
};
int closedir(DIR* dir);
DIR* opendir(const char* path);
struct dirent* readdir(DIR* dir);
void rewinddir(DIR* dir);
int closedir(DIR*);
DIR* opendir(const char*);
struct dirent* readdir(DIR*);
void rewinddir(DIR*);
#if __USE_SORTIX || __USE_XOPEN
/* TODO: seekdir */
@ -104,8 +62,8 @@ void rewinddir(DIR* dir);
/* Functions from POSIX 2008. */
#if __USE_SORTIX || 200809L <= __USE_POSIX
int alphasort(const struct dirent**, const struct dirent**);
int dirfd(DIR* dir);
DIR* fdopendir(int fd);
int dirfd(DIR*);
DIR* fdopendir(int);
int scandir(const char*, struct dirent***, int (*)(const struct dirent*),
int (*)(const struct dirent**, const struct dirent**));
#endif
@ -118,17 +76,11 @@ int versionsort(const struct dirent**, const struct dirent**);
/* Functions that are Sortix extensions. */
#if __USE_SORTIX
int alphasort_r(const struct dirent**, const struct dirent**, void*);
void dclearerr(DIR* dir);
int deof(DIR* dif);
int derror(DIR* dir);
DIR* dnewdir(void);
void dregister(DIR* dir);
int dscandir_r(DIR*, struct dirent***,
int (*)(const struct dirent*, void*),
void*,
int (*)(const struct dirent**, const struct dirent**, void*),
void*);
void dunregister(DIR* dir);
int versionsort_r(const struct dirent**, const struct dirent**, void*);
#endif

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2015.
This file is part of the Sortix C Library.
@ -29,22 +29,24 @@
#include <sys/__/types.h>
#include <sys/types.h>
#include <stddef.h>
#include <stdint.h>
#include <sortix/dirent.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __size_t_defined
#define __size_t_defined
#define __need_size_t
#include <stddef.h>
#endif
ssize_t readdirents(int fd, struct kernel_dirent* dirent, size_t size);
#ifndef __ssize_t_defined
#define __ssize_t_defined
typedef __ssize_t ssize_t;
#endif
struct dirent;
#ifdef __cplusplus
extern "C" {
#endif
ssize_t readdirents(int, struct dirent*, size_t);
#ifdef __cplusplus
} /* extern "C" */

View File

@ -60,11 +60,8 @@ extern "C" void exit(int status)
__exit_handler_stack = __exit_handler_stack->next;
}
pthread_mutex_lock(&__first_dir_lock);
pthread_mutex_lock(&__first_file_lock);
while ( __first_dir )
__first_dir->closedir_indirect(__first_dir);
for ( FILE* fp = __first_file; fp; fp = fp->next )
{
flockfile(fp);

View File

@ -1,6 +1,6 @@
/*******************************************************************************
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012.
Copyright(C) Jonas 'Sortie' Termansen 2011, 2012, 2015.
This file is part of the Sortix C Library.
@ -18,16 +18,16 @@
along with the Sortix C Library. If not, see <http://www.gnu.org/licenses/>.
sys/readdirents/readdirents.cpp
Reads entries from a directory file descriptor.
Reads directory entries from a directory file descriptor.
*******************************************************************************/
#include <sys/readdirents.h>
#include <sys/syscall.h>
DEFN_SYSCALL4(ssize_t, sys_readdirents, SYSCALL_READDIRENTS, int, struct kernel_dirent*, size_t, size_t);
DEFN_SYSCALL3(ssize_t, sys_readdirents, SYSCALL_READDIRENTS, int, struct dirent*, size_t);
extern "C" ssize_t readdirents(int fd, struct kernel_dirent* dirent, size_t size)
extern "C" ssize_t readdirents(int fd, struct dirent* dirent, size_t size)
{
return sys_readdirents(fd, dirent, size, 1);
return sys_readdirents(fd, dirent, size);
}

View File

@ -272,7 +272,8 @@ static bool do_chmod_directory(int fd,
joiner = "";
bool success = true;
while ( struct dirent* entry = readdir(dir) )
struct dirent* entry;
while ( (errno = 0, entry = readdir(dir)) )
{
if ( !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") )
continue;
@ -291,7 +292,7 @@ static bool do_chmod_directory(int fd,
free(entry_path);
}
if ( derror(dir) )
if ( errno != 0 )
{
error(0, errno, "reading directory: `%s'", path);
closedir(dir);

View File

@ -223,7 +223,8 @@ bool disk_usage_file_at(int relfd,
}
bool success = true;
while ( struct dirent* entry = readdir(dir) )
struct dirent* entry;
while ( (errno = 0, entry = readdir(dir)) )
{
if ( !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") )
continue;
@ -249,14 +250,12 @@ bool disk_usage_file_at(int relfd,
if ( num_bytes_ptr )
*num_bytes_ptr = num_bytes;
#if defined(__sortix__)
if ( derror(dir) && errno != ENOTDIR )
if ( errno && errno != ENOTDIR )
{
error(0, errno, "reading directory `%s'", path);
closedir(dir);
return false;
}
#endif
if ( print_if_dir )
print_disk_usage(num_bytes, block_size, flags, path);