diff --git a/src/kernel/core/fs/devfs.cpp b/src/kernel/core/fs/devfs.cpp index eea781e36e..ceaec984b4 100644 --- a/src/kernel/core/fs/devfs.cpp +++ b/src/kernel/core/fs/devfs.cpp @@ -97,6 +97,7 @@ struct devfs_cookie { struct devfs_cookie *next; struct devfs_cookie *prev; struct devfs_vnode *ptr; + int state; // iteration state } dir; struct cookie_dev { void *dcookie; @@ -104,6 +105,14 @@ struct devfs_cookie { } u; }; +// directory iteration states +enum { + ITERATION_STATE_DOT = 0, + ITERATION_STATE_DOT_DOT = 1, + ITERATION_STATE_OTHERS = 2, + ITERATION_STATE_BEGIN = ITERATION_STATE_DOT, +}; + /* the one and only allowed devfs instance */ static struct devfs *sDeviceFileSystem = NULL; @@ -961,6 +970,7 @@ devfs_open_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie *_cookie) mutex_lock(&fs->lock); cookie->u.dir.ptr = vnode->stream.u.dir.dir_head; + cookie->u.dir.state = ITERATION_STATE_BEGIN; *_cookie = cookie; mutex_unlock(&fs->lock); @@ -975,6 +985,10 @@ devfs_read_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, struct dirent struct devfs_cookie *cookie = (struct devfs_cookie *)_cookie; struct devfs *fs = (struct devfs *)_fs; status_t status = B_OK; + struct devfs_vnode *childNode = NULL; + const char *name = NULL; + struct devfs_vnode *nextChildNode = NULL; + int nextState = cookie->u.dir.state; TRACE(("devfs_read_dir: vnode %p, cookie %p, buffer %p, size %ld\n", _vnode, cookie, dirent, bufferSize)); @@ -983,25 +997,49 @@ devfs_read_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, struct dirent mutex_lock(&fs->lock); - if (cookie->u.dir.ptr == NULL) { + switch (cookie->u.dir.state) { + case ITERATION_STATE_DOT: + childNode = vnode; + name = "."; + nextChildNode = vnode->stream.u.dir.dir_head; + nextState = cookie->u.dir.state + 1; + break; + case ITERATION_STATE_DOT_DOT: + childNode = vnode->parent; + name = ".."; + nextChildNode = vnode->stream.u.dir.dir_head; + nextState = cookie->u.dir.state + 1; + break; + default: + childNode = cookie->u.dir.ptr; + if (childNode) { + name = childNode->name; + nextChildNode = childNode->dir_next; + } + break; + } + + if (!childNode) { *_num = 0; goto err; } dirent->d_dev = fs->id; - dirent->d_ino = cookie->u.dir.ptr->id; - dirent->d_reclen = strlen(cookie->u.dir.ptr->name) + sizeof(struct dirent); + dirent->d_ino = childNode->id; + dirent->d_reclen = strlen(name) + sizeof(struct dirent); if (dirent->d_reclen > bufferSize) { status = ENOBUFS; goto err; } - status = user_strlcpy(dirent->d_name, cookie->u.dir.ptr->name, bufferSize - sizeof(struct dirent)); + status = user_strlcpy(dirent->d_name, name, + bufferSize - sizeof(struct dirent)); if (status < B_OK) goto err; - cookie->u.dir.ptr = cookie->u.dir.ptr->dir_next; + cookie->u.dir.ptr = nextChildNode; + cookie->u.dir.state = nextState; status = B_OK; err: @@ -1026,6 +1064,7 @@ devfs_rewind_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) mutex_lock(&fs->lock); cookie->u.dir.ptr = vnode->stream.u.dir.dir_head; + cookie->u.dir.state = ITERATION_STATE_BEGIN; mutex_unlock(&fs->lock); return B_OK; diff --git a/src/kernel/core/fs/rootfs.c b/src/kernel/core/fs/rootfs.c index 779468555d..220475affe 100755 --- a/src/kernel/core/fs/rootfs.c +++ b/src/kernel/core/fs/rootfs.c @@ -68,6 +68,15 @@ struct rootfs_cookie { struct rootfs_cookie *prev; struct rootfs_vnode *ptr; int oflags; + int state; // iteration state +}; + +// directory iteration states +enum { + ITERATION_STATE_DOT = 0, + ITERATION_STATE_DOT_DOT = 1, + ITERATION_STATE_OTHERS = 2, + ITERATION_STATE_BEGIN = ITERATION_STATE_DOT, }; #define ROOTFS_HASH_SIZE 16 @@ -623,6 +632,7 @@ rootfs_open_dir(fs_volume _fs, fs_vnode _v, fs_cookie *_cookie) cookie->ptr = vnode->stream.dir.dir_head; //cookie->oflags = oflags; + cookie->state = ITERATION_STATE_BEGIN; insert_cookie_in_jar(vnode, cookie); *_cookie = cookie; @@ -636,34 +646,63 @@ rootfs_open_dir(fs_volume _fs, fs_vnode _v, fs_cookie *_cookie) static status_t rootfs_read_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie, struct dirent *dirent, size_t bufferSize, uint32 *_num) { + struct rootfs_vnode *vnode = (struct rootfs_vnode *)_vnode; struct rootfs_cookie *cookie = _cookie; struct rootfs *fs = _fs; status_t status = B_OK; + struct rootfs_vnode *childNode = NULL; + const char *name = NULL; + struct rootfs_vnode *nextChildNode = NULL; + int nextState = cookie->state; TRACE(("rootfs_read_dir: vnode %p, cookie %p, buffer = %p, bufferSize = %ld, num = %p\n", _vnode, cookie, dirent, bufferSize,_num)); mutex_lock(&fs->lock); - if (cookie->ptr == NULL) { + switch (cookie->state) { + case ITERATION_STATE_DOT: + childNode = vnode; + name = "."; + nextChildNode = vnode->stream.dir.dir_head; + nextState = cookie->state + 1; + break; + case ITERATION_STATE_DOT_DOT: + childNode = vnode->parent; + name = ".."; + nextChildNode = vnode->stream.dir.dir_head; + nextState = cookie->state + 1; + break; + default: + childNode = cookie->ptr; + if (childNode) { + name = childNode->name; + nextChildNode = childNode->dir_next; + } + break; + } + + if (!childNode) { // we're at the end of the directory *_num = 0; goto err; } dirent->d_dev = fs->id; - dirent->d_ino = cookie->ptr->id; - dirent->d_reclen = strlen(cookie->ptr->name) + sizeof(struct dirent); + dirent->d_ino = childNode->id; + dirent->d_reclen = strlen(name) + sizeof(struct dirent); if (dirent->d_reclen > bufferSize) { status = ENOBUFS; goto err; } - status = user_strlcpy(dirent->d_name, cookie->ptr->name, bufferSize - sizeof(struct dirent)); + status = user_strlcpy(dirent->d_name, name, + bufferSize - sizeof(struct dirent)); if (status < B_OK) goto err; - cookie->ptr = cookie->ptr->dir_next; + cookie->ptr = nextChildNode; + cookie->state = nextState; status = B_OK; err: @@ -683,6 +722,7 @@ rootfs_rewind_dir(fs_volume _fs, fs_vnode _vnode, fs_cookie _cookie) mutex_lock(&fs->lock); cookie->ptr = vnode->stream.dir.dir_head; + cookie->state = ITERATION_STATE_BEGIN; mutex_unlock(&fs->lock); return B_OK;