instow

:)
git clone https://git.sr.ht/~ashymad/instow
Log | Files | Refs | LICENSE

nftw.c (4095B)


      1 #define _GNU_SOURCE
      2 #define _FILE_OFFSET_BITS 64
      3 
      4 #include <errno.h>
      5 #include <fcntl.h>
      6 #include <ftw.h>
      7 #include <janet.h>
      8 #include <stdbool.h>
      9 #include <unistd.h>
     10 
     11 #include "os.h"
     12 
     13 static JanetFunction *janet_callback = NULL;
     14 
     15 static const char *FTW_(int flag) {
     16   switch (flag) {
     17   case FTW_F:
     18     return "f";
     19   case FTW_D:
     20     return "d";
     21   case FTW_DNR:
     22     return "dnr";
     23   case FTW_DP:
     24     return "dp";
     25   case FTW_NS:
     26     return "ns";
     27   case FTW_SL:
     28     return "sl";
     29   case FTW_SLN:
     30     return "sln";
     31   default:
     32     return "err";
     33   }
     34 }
     35 
     36 int callback(const char *path, const struct stat *st, int flag,
     37              struct FTW *info) {
     38 
     39   JanetTable *ftwtab = janet_table(0);
     40   janet_table_put(ftwtab, janet_ckeywordv("base"),
     41                   janet_wrap_integer(info->base));
     42   janet_table_put(ftwtab, janet_ckeywordv("level"),
     43                   janet_wrap_integer(info->level));
     44 
     45   return janet_unwrap_integer(janet_call(
     46       janet_callback, 4,
     47       (const Janet[]){janet_cstringv(path), stat2table(st, NULL),
     48                       janet_ckeywordv(FTW_(flag)), janet_wrap_table(ftwtab)}));
     49 }
     50 
     51 struct {
     52   const char *name;
     53   int value;
     54 } flagnames[] = {
     55     {"chdir", FTW_CHDIR},
     56     {"depth", FTW_DEPTH},
     57     {"mount", FTW_MOUNT},
     58     {"phys", FTW_PHYS},
     59 };
     60 
     61 static Janet c_nftw(int32_t argc, Janet *argv) {
     62   janet_arity(argc, 3, 7);
     63 
     64   int flags = 0;
     65 
     66   for (int i = 3; i < argc; i++) {
     67     for (int j = 0; j < sizeof(flagnames) / sizeof(flagnames[0]); j++) {
     68       if (strcmp((const char *)janet_unwrap_keyword(argv[i]),
     69                  flagnames[j].name) == 0) {
     70         flags |= flagnames[j].value;
     71         break;
     72       }
     73     }
     74   }
     75 
     76   janet_callback = janet_unwrap_function(argv[1]);
     77 
     78   return janet_wrap_integer(nftw((const char *)janet_unwrap_string(argv[0]),
     79                                  callback, janet_unwrap_integer(argv[2]),
     80                                  flags));
     81 }
     82 
     83 static Janet c_fileno(int32_t argc, Janet *argv) {
     84   janet_fixarity(argc, 1);
     85   return janet_wrap_integer(
     86       fileno(((JanetFile *)janet_unwrap_abstract(argv[0]))->file));
     87 }
     88 
     89 static Janet c_fstat(int32_t argc, Janet *argv) {
     90   janet_arity(argc, 1, 2);
     91 
     92   struct stat st;
     93   if (fstat(janet_unwrap_integer(argv[0]), &st) == -1)
     94     return janet_wrap_nil();
     95 
     96   const uint8_t *key =
     97       argc == 2 ? (const uint8_t *)janet_unwrap_string(argv[1]) : NULL;
     98 
     99   return stat2table(&st, key);
    100 }
    101 
    102 static int O_(char name) {
    103   switch (name) {
    104   case '+':
    105     return O_APPEND;
    106   case 'c':
    107     return O_CREAT;
    108   case 'x':
    109     return O_EXCL;
    110   case '-':
    111     return O_TRUNC;
    112   default:
    113     return 0;
    114   }
    115 }
    116 
    117 static int parseO(const unsigned char *opts) {
    118   int flags = 0;
    119   bool read = false;
    120   bool write = false;
    121   for (int i = 0; opts[i]; i++) {
    122     if (opts[i] == 'w')
    123       write = true;
    124     else if (opts[i] == 'r')
    125       read = true;
    126     else
    127       flags |= O_(opts[i]);
    128   }
    129 
    130   if (read && write)
    131     flags |= O_RDWR;
    132   else if (write)
    133     flags |= O_WRONLY;
    134   else if (read)
    135     flags |= O_RDONLY;
    136 
    137   return flags;
    138 }
    139 
    140 static Janet c_open(int argc, Janet *argv) {
    141   janet_arity(argc, 1, 3);
    142 
    143   int flags = argc > 1 ? parseO(janet_unwrap_string(argv[1])) : 0;
    144   jmode_t mode = argc > 2 ? os_getmode(argv, 2) : 644;
    145 
    146   return janet_wrap_integer(
    147       open((const char *)janet_unwrap_string(argv[0]), flags, mode));
    148 }
    149 
    150 static Janet c_close(int argc, Janet *argv) {
    151   janet_fixarity(argc, 1);
    152 
    153   return janet_wrap_integer(close(janet_unwrap_integer(argv[0])));
    154 }
    155 
    156 static Janet c_strerror(int argc, Janet *argv) {
    157   janet_fixarity(argc, 0);
    158 
    159   return janet_cstringv(strerror(errno));
    160 }
    161 
    162 static JanetReg cfuns[] = {
    163     {"nftw", c_nftw, "(nftw path callback fd_limit & flags)\n\nruns nftw"},
    164     {"fileno", c_fileno, "(fileno file)\n\nreturns fd"},
    165     {"fstat", c_fstat, "(fstat fd &opt key)\n\nreturns stats from fd"},
    166     {"open", c_open, "(open path &opt flags mode)\n\nreturns fd"},
    167     {"close", c_close, "(close fd)\n\ncloses fd"},
    168     {"strerror", c_strerror, "(strerror)\n\nprint errno error string"},
    169     {NULL, NULL, NULL}};
    170 
    171 JANET_MODULE_ENTRY(JanetTable *env) { janet_cfuns(env, "nftw", cfuns); }