diff options
Diffstat (limited to 'sys/fs/tmpfs/tmpfs_subr.c')
-rw-r--r-- | sys/fs/tmpfs/tmpfs_subr.c | 47 |
1 files changed, 26 insertions, 21 deletions
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/sys/fs/tmpfs/tmpfs_subr.c index ec96936..f4508c6 100644 --- a/sys/fs/tmpfs/tmpfs_subr.c +++ b/sys/fs/tmpfs/tmpfs_subr.c @@ -348,6 +348,9 @@ tmpfs_dirent_hash(const char *name, u_int len) static __inline off_t tmpfs_dirent_cookie(struct tmpfs_dirent *de) { + if (de == NULL) + return (TMPFS_DIRCOOKIE_EOF); + MPASS(de->td_cookie >= TMPFS_DIRCOOKIE_MIN); return (de->td_cookie); @@ -1144,7 +1147,7 @@ tmpfs_dir_getdotdotdent(struct tmpfs_node *node, struct uio *uio) * error code if another error happens. */ int -tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int cnt, +tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int maxcookies, u_long *cookies, int *ncookies) { struct tmpfs_dir_cursor dc; @@ -1155,25 +1158,33 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int cnt, TMPFS_VALIDATE_DIR(node); off = 0; + + /* + * Lookup the node from the current offset. The starting offset of + * 0 will lookup both '.' and '..', and then the first real entry, + * or EOF if there are none. Then find all entries for the dir that + * fit into the buffer. Once no more entries are found (de == NULL), + * the offset is set to TMPFS_DIRCOOKIE_EOF, which will cause the next + * call to return 0. + */ switch (uio->uio_offset) { case TMPFS_DIRCOOKIE_DOT: error = tmpfs_dir_getdotdent(node, uio); if (error != 0) return (error); uio->uio_offset = TMPFS_DIRCOOKIE_DOTDOT; - if (cnt != 0) + if (cookies != NULL) cookies[(*ncookies)++] = off = uio->uio_offset; + /* FALLTHROUGH */ case TMPFS_DIRCOOKIE_DOTDOT: error = tmpfs_dir_getdotdotdent(node, uio); if (error != 0) return (error); de = tmpfs_dir_first(node, &dc); - if (de == NULL) - uio->uio_offset = TMPFS_DIRCOOKIE_EOF; - else - uio->uio_offset = tmpfs_dirent_cookie(de); - if (cnt != 0) + uio->uio_offset = tmpfs_dirent_cookie(de); + if (cookies != NULL) cookies[(*ncookies)++] = off = uio->uio_offset; + /* EOF. */ if (de == NULL) return (0); break; @@ -1183,7 +1194,7 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int cnt, de = tmpfs_dir_lookup_cookie(node, uio->uio_offset, &dc); if (de == NULL) return (EINVAL); - if (cnt != 0) + if (cookies != NULL) off = tmpfs_dirent_cookie(de); } @@ -1251,25 +1262,19 @@ tmpfs_dir_getdents(struct tmpfs_node *node, struct uio *uio, int cnt, error = uiomove(&d, d.d_reclen, uio); if (error == 0) { de = tmpfs_dir_next(node, &dc); - if (cnt != 0) { - if (de == NULL) - off = TMPFS_DIRCOOKIE_EOF; - else - off = tmpfs_dirent_cookie(de); - MPASS(*ncookies < cnt); + if (cookies != NULL) { + off = tmpfs_dirent_cookie(de); + MPASS(*ncookies < maxcookies); cookies[(*ncookies)++] = off; } } } while (error == 0 && uio->uio_resid > 0 && de != NULL); - /* Update the offset and cache. */ - if (cnt == 0) { - if (de == NULL) - off = TMPFS_DIRCOOKIE_EOF; - else - off = tmpfs_dirent_cookie(de); - } + /* Skip setting off when using cookies as it is already done above. */ + if (cookies == NULL) + off = tmpfs_dirent_cookie(de); + /* Update the offset and cache. */ uio->uio_offset = off; node->tn_dir.tn_readdir_lastn = off; node->tn_dir.tn_readdir_lastp = de; |