From dc73df1834c98dc13ba9c22bc3d009f604c07af7 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Wed, 8 Jul 2020 08:32:30 -0700 Subject: Expose low-level opendir/readdir dir traversal. * stream.c (UTF_DECL_OPENDIR): Macro defined, to enable w_opendir declaration in utf8.h. (w_opendir): Static function removed. * sysif.c (UTF_DECL_OPENDIR): Macro defined. (dir_s): Symbol defined unconditionally now, regardless of HAVE_PWUID. (dirent_s): New symbol. (dirent_st): New static variable. (struct dir): New struct type. (opendir_free, opendir_mark opendir_wrap, readdir_wrap): New static functions. (opendir_ops): New static structure. (sysif_init): Intern dirent symbol. Create dirent structure type. Register opendir and readdir intrinsic functions. Register variables dt-blk, dt-chr, dt-dir, dt-fifo, dt-lnk, dt-reg, dt-sock and dt-unknown. * utf8.c (UTF8_DECL_OPENDIR): Macro defined. (w_opendir): Function moved here from stream.c, and turned external. * utf8.h (w_opendir): Declared, conditionally on UTF8_DECL_OPENDIR being defined, so that most modules that include utf8.h don't have to include . * txr.1: Documented. diff --git a/sysif.c b/sysif.c --- sysif.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 104 insertions(+), 3 deletions(-) (limited to 'sysif.c') diff --git a/sysif.c b/sysif.c index 21bf00b4..12509c85 100644 --- a/sysif.c +++ b/sysif.c @@ -25,10 +25,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define UTF8_DECL_OPENDIR #include #include #include #include +#include #include #include #include @@ -108,10 +110,10 @@ val dev_s, ino_s, mode_s, nlink_s, uid_s; val gid_s, rdev_s, size_s, blksize_s, blocks_s; val atime_s, mtime_s, ctime_s; val atime_nsec_s, mtime_nsec_s, ctime_nsec_s; -val path_s; +val path_s, dir_s, dirent_s; #if HAVE_PWUID -val passwd_s, gecos_s, dir_s, shell_s; +val passwd_s, gecos_s, shell_s; #endif #if HAVE_GRGID @@ -133,6 +135,8 @@ val dlhandle_s, dlsym_s; static val at_exit_list; +static val dirent_st; + static val errno_wrap(val newval) { val self = lit("errno"); @@ -2219,9 +2223,74 @@ static val isatty_wrap(val spec) } #endif +struct dir { + DIR *dir; + val path; +}; + +static void opendir_free(val obj) +{ + struct dir *d = coerce(struct dir *, obj->co.handle); + closedir(d->dir); + free(d); +} + +static void opendir_mark(val obj) +{ + struct dir *d = coerce(struct dir *, obj->co.handle); + gc_mark(d->path); +} + +static struct cobj_ops opendir_ops = cobj_ops_init(eq, + cobj_print_op, + opendir_free, + opendir_mark, + cobj_eq_hash_op); +static val opendir_wrap(val path, val prefix_p) +{ + DIR *dir = w_opendir(c_str(path)); + + if (dir == 0) { + uw_throwf(system_error_s, lit("opendir failed for ~a: ~d/~s"), + path, num(errno), errno_to_str(errno), nao); + } else { + struct dir *d = coerce(struct dir *, chk_malloc(sizeof *d)); + d->dir = dir; + d->path = if2(default_null_arg(prefix_p), path); + return cobj(coerce(mem_t *, d), dir_s, &opendir_ops); + } +} + +static val readdir_wrap(val dirobj, val dirent_in) +{ + val self = lit("readdir"); + struct dir *d = coerce(struct dir *, cobj_handle(self, dirobj, dir_s)); + struct dirent *dent = readdir(d->dir); + + if (dent == 0) { + return nil; + } else { + args_decl(args, ARGS_MIN); + val dirent = default_arg(dirent_in, make_struct(dirent_st, nil, args)); + slotset(dirent, name_s, + if3(d->path, + path_cat(d->path, string_utf8(dent->d_name)), + string_utf8(dent->d_name))); + slotset(dirent, ino_s, num(dent->d_ino)); +#ifdef _DIRENT_HAVE_D_TYPE + slotset(dirent, type_s, num(dent->d_type)); +#else + if (dirent_in == dirent) + slotset(dirent, type_s, nil); +#endif + return dirent; + } +} + void sysif_init(void) { prot1(&at_exit_list); + prot1(&dirent_st); atexit(at_exit_handler); @@ -2256,10 +2325,11 @@ void sysif_init(void) mtime_nsec_s = intern(lit("mtime-nsec"), user_package); ctime_nsec_s = intern(lit("ctime-nsec"), user_package); path_s = intern(lit("path"), user_package); + dir_s = intern(lit("dir"), user_package); + dirent_s = intern(lit("dirent"), user_package); #if HAVE_PWUID passwd_s = intern(lit("passwd"), user_package); gecos_s = intern(lit("gecos"), user_package); - dir_s = intern(lit("dir"), user_package); shell_s = intern(lit("shell"), user_package); #endif #if HAVE_GRGID @@ -2783,4 +2853,35 @@ void sysif_init(void) #if HAVE_ISATTY reg_fun(intern(lit("isatty"), user_package), func_n1(isatty_wrap)); #endif + + dirent_st = make_struct_type(dirent_s, nil, nil, + list(name_s, ino_s, type_s, nao), + nil, nil, nil, nil); + reg_fun(intern(lit("opendir"), user_package), func_n2o(opendir_wrap, 1)); + reg_fun(intern(lit("readdir"), user_package), func_n2o(readdir_wrap, 1)); + +#ifdef DT_BLK + reg_varl(intern(lit("dt-blk"), user_package), num_fast(DT_BLK)); +#endif +#ifdef DT_CHR + reg_varl(intern(lit("dt-chr"), user_package), num_fast(DT_CHR)); +#endif +#ifdef DT_DIR + reg_varl(intern(lit("dt-dir"), user_package), num_fast(DT_DIR)); +#endif +#ifdef DT_FIFO + reg_varl(intern(lit("dt-fifo"), user_package), num_fast(DT_FIFO)); +#endif +#ifdef DT_LNK + reg_varl(intern(lit("dt-lnk"), user_package), num_fast(DT_LNK)); +#endif +#ifdef DT_REG + reg_varl(intern(lit("dt-reg"), user_package), num_fast(DT_REG)); +#endif +#ifdef DT_SOCK + reg_varl(intern(lit("dt-sock"), user_package), num_fast(DT_SOCK)); +#endif +#ifdef DT_UNKNOWN + reg_varl(intern(lit("dt-unknown"), user_package), num_fast(DT_UNKNOWN)); +#endif } -- cgit v1.2.3