From c5090606a42ba79ed3ba4d99e639e3975eb741e0 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sat, 30 Mar 2019 12:06:14 -0400 Subject: [PATCH] Add os/stat function. Allows getting more information about files. This is really useful for writing software that needs to inspect the file system (like a static site generator). We still need a way to iterate directories though. --- src/core/os.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/core/os.c b/src/core/os.c index 0e23f334..84cfd815 100644 --- a/src/core/os.c +++ b/src/core/os.c @@ -384,6 +384,86 @@ static Janet os_touch(int32_t argc, Janet *argv) { return janet_wrap_boolean(res != -1); } +#ifdef JANET_WINDOWS +static const uint8_t *janet_decode_permissions(unsigned short m) { + uint8_t flags[9] = {0}; + flags[0] = flags[3] = flags[6] = (m & S_IREAD) ? 'r' : '-'; + flags[1] = flags[4] = flags[7] = (m & S_IWRITE) ? 'w' : '-'; + flags[2] = flags[5] = flags[8] = (m & S_IEXEC) ? 'x' : '-'; + return janet_string(flags, sizeof(flags)); +} + +static const uint8_t *janet_decode_mode(unsigned short m) { + const char *str = "other"; + if (_S_ISREG(m)) str = "file"; + else if (_S_ISDIR(m)) str = "directory"; + return janet_ckeyword(str); +} +#else +static const uint8_t *janet_decode_permissions(mode_t m) { + uint8_t flags[9] = {0}; + flags[0] = (m & S_IRUSR) ? 'r' : '-'; + flags[1] = (m & S_IWUSR) ? 'w' : '-'; + flags[2] = (m & S_IXUSR) ? 'x' : '-'; + flags[3] = (m & S_IRGRP) ? 'r' : '-'; + flags[4] = (m & S_IWGRP) ? 'w' : '-'; + flags[5] = (m & S_IXGRP) ? 'x' : '-'; + flags[6] = (m & S_IROTH) ? 'r' : '-'; + flags[7] = (m & S_IWOTH) ? 'w' : '-'; + flags[8] = (m & S_IXOTH) ? 'x' : '-'; + return janet_string(flags, sizeof(flags)); +} + +static const uint8_t *janet_decode_mode(mode_t m) { + const char *str = "other"; + if (S_ISREG(m)) str = "file"; + else if (S_ISDIR(m)) str = "directory"; + else if (S_ISFIFO(m)) str = "fifo"; + else if (S_ISBLK(m)) str = "block"; + else if (S_ISSOCK(m)) str = "socket"; + else if (S_ISLNK(m)) str = "link"; + else if (S_ISCHR(m)) str = "character"; + return janet_ckeyword(str); +} +#endif + +static Janet os_stat(int32_t argc, Janet *argv) { + janet_arity(argc, 1, 2); + const char *path = janet_getcstring(argv, 0); + JanetTable *tab; + if (argc == 2) { + tab = janet_gettable(argv, 1); + } else { + tab = janet_table(0); + } + /* Build result */ +#ifdef JANET_WINDOWS + struct _stat st; + int res = _stat(path, &st); +#else + struct stat st; + int res = stat(path, &st); +#endif + if (-1 == res) { + janet_panicv(janet_cstringv(strerror(errno))); + } + janet_table_put(tab, janet_ckeywordv("dev"), janet_wrap_number(st.st_dev)); + janet_table_put(tab, janet_ckeywordv("inode"), janet_wrap_number(st.st_ino)); + janet_table_put(tab, janet_ckeywordv("mode"), janet_wrap_keyword(janet_decode_mode(st.st_mode))); + janet_table_put(tab, janet_ckeywordv("permissions"), janet_wrap_string(janet_decode_permissions(st.st_mode))); + janet_table_put(tab, janet_ckeywordv("uid"), janet_wrap_number(st.st_uid)); + janet_table_put(tab, janet_ckeywordv("gid"), janet_wrap_number(st.st_gid)); + janet_table_put(tab, janet_ckeywordv("size"), janet_wrap_number(st.st_size)); + janet_table_put(tab, janet_ckeywordv("nlink"), janet_wrap_number(st.st_nlink)); + janet_table_put(tab, janet_ckeywordv("rdev"), janet_wrap_number(st.st_rdev)); + janet_table_put(tab, janet_ckeywordv("blocksize"), janet_wrap_number(st.st_blksize)); + janet_table_put(tab, janet_ckeywordv("blocks"), janet_wrap_number(st.st_blocks)); + janet_table_put(tab, janet_ckeywordv("accessed"), janet_wrap_number(st.st_atime)); + janet_table_put(tab, janet_ckeywordv("modified"), janet_wrap_number(st.st_mtime)); + janet_table_put(tab, janet_ckeywordv("changed"), janet_wrap_number(st.st_ctime)); + return janet_wrap_table(tab); +} + #endif /* JANET_REDUCED_OS */ static const JanetReg os_cfuns[] = { @@ -407,6 +487,11 @@ static const JanetReg os_cfuns[] = { "Get the string value of an environment variable.") }, #ifndef JANET_REDUCED_OS + { + "os/stat", os_stat, + JDOC("(os/stat path)\n\n" + "Gets information about a file or directory. Returns a table.") + }, { "os/touch", os_touch, JDOC("(os/touch path [, actime [, modtime]])\n\n"