diff --git a/lib/chibi/filesystem.stub b/lib/chibi/filesystem.stub index a82af25e..29b35810 100644 --- a/lib/chibi/filesystem.stub +++ b/lib/chibi/filesystem.stub @@ -14,6 +14,7 @@ (cond-expand (windows + (c-include-verbatim "filesystem_win32_shim.c") (define-c-struct stat predicate: stat? (dev_t st_dev stat-dev) @@ -30,10 +31,6 @@ (time_t st_mtime stat-mtime) (time_t st_ctime stat-ctime))) (else - (define-c-type DIR - finalizer: closedir) - (define-c-struct dirent - (string d_name dirent-name)) (define-c-struct stat predicate: stat? (dev_t st_dev stat-dev) @@ -51,18 +48,19 @@ (time_t st_ctime stat-ctime)) )) +(define-c-type DIR + finalizer: closedir) +(define-c-struct dirent + (string d_name dirent-name)) - -(cond-expand - ((not windows) - (define-c boolean S_ISREG (mode_t)) - (define-c boolean S_ISDIR (mode_t)) - (define-c boolean S_ISCHR (mode_t)) - (define-c boolean S_ISBLK (mode_t)) - (define-c boolean S_ISFIFO (mode_t)) - (define-c boolean S_ISLNK (mode_t)) - (define-c boolean S_ISSOCK (mode_t)))) +(define-c boolean S_ISREG (mode_t)) +(define-c boolean S_ISDIR (mode_t)) +(define-c boolean S_ISCHR (mode_t)) +(define-c boolean S_ISBLK (mode_t)) +(define-c boolean S_ISFIFO (mode_t)) +(define-c boolean S_ISLNK (mode_t)) +(define-c boolean S_ISSOCK (mode_t)) (cond-expand ((not windows) @@ -152,7 +150,7 @@ ((not windows) (define-c errno (create-directory "mkdir") (string (default #o775 int)))) (else - (define-c errno (create-directory "mkdir") (string)))) + (define-c errno (create-directory "mkdir_shim") (string (default #o775 int))))) ;;> Deletes the directory named \var{string} from the filesystem. ;;> Does not attempt to delete recursively. @@ -160,10 +158,8 @@ (define-c errno (delete-directory "rmdir") (string)) -(cond-expand - ((not windows) - (define-c (free DIR) opendir (string)) - (define-c dirent readdir ((link (pointer DIR)))))) +(define-c (free DIR) opendir (string)) +(define-c dirent readdir ((link (pointer DIR)))) ;;> Duplicates the given file descriptor, returning he new value, ;; or -1 on failure. @@ -248,11 +244,9 @@ (port-or-fileno off_t)))) ;; Used for file-is-readable?, file-is-writable?, file-is-executable?. -(cond-expand - ((not windows) - (define-c-const int (access/read "R_OK")) - (define-c-const int (access/write "W_OK")) - (define-c-const int (access/execute "X_OK")))) +(define-c-const int (access/read "R_OK")) +(define-c-const int (access/write "W_OK")) +(define-c-const int (access/execute "X_OK")) (define-c int (file-access "access") (string int)) ;;> Applies the specified locking operation using flock(2) to the port diff --git a/lib/chibi/filesystem_win32_shim.c b/lib/chibi/filesystem_win32_shim.c new file mode 100644 index 00000000..49429c15 --- /dev/null +++ b/lib/chibi/filesystem_win32_shim.c @@ -0,0 +1,104 @@ +/* Win32 shim for (chibi filesystem) */ + +#include +#include +#include +#include +#include + +static int mkdir_shim(const char* path, int ignored) { + return mkdir(path); +} + +#if !defined(__MINGW32__) && !defined(__MINGW64__) +/* Flags for _access() API */ +#define R_OK 4 +#define W_OK 2 +#define X_OK 1 /* Follow MinGW */ + +#define SHIM_WIN32_STAT_IS(m, flg) ((m & _S_IFMT) == flg) +#define S_ISREG(m) SHIM_WIN32_STAT_IS(m, _S_IFREG) +#define S_ISDIR(m) SHIM_WIN32_STAT_IS(m, _S_IFDIR) +#define S_ISCHR(m) SHIM_WIN32_STAT_IS(m, _S_IFCHR) +#define S_ISFIFO(m) SHIM_WIN32_STAT_IS(m, _S_IFIFO) +#define S_ISBLK(m) 0 +#endif + +#define S_ISLNK(m) 0 +#define S_ISSOCK(m) S_ISFIFO(m) + +struct dirent { + char d_name[MAX_PATH]; +}; + +struct DIR_s { + int want_next; + HANDLE hFind; + struct dirent result; +}; + +typedef struct DIR_s DIR; + +static DIR* opendir(const char* path) { + HANDLE hFind; + WIN32_FIND_DATAA ffd; + DIR* dp; + char* query; + query = malloc(MAX_PATH + 1); + if(!query){ + errno = ENOMEM; + return NULL; + } + query[0] = 0; + strncat(query, path, MAX_PATH); + strncat(query, "\\*", MAX_PATH); + query[MAX_PATH] = 0; + hFind = FindFirstFileA(query, &ffd); + if(hFind == INVALID_HANDLE_VALUE){ + switch(GetLastError()){ + case ERROR_FILE_NOT_FOUND: + errno = ENOENT; + break; + default: + errno = EACCES; + break; + } + return NULL; + } + free(query); + dp = malloc(sizeof(DIR)); + if(!dp){ + errno = ENOMEM; + return NULL; + } + dp->hFind = hFind; + strncpy(dp->result.d_name, ffd.cFileName, MAX_PATH); + dp->want_next = 0; + return dp; +} + +static struct dirent *readdir(DIR *dp) { + BOOL b; + WIN32_FIND_DATAA ffd; + if(dp->want_next){ + /* Query the next file */ + b = FindNextFile(dp->hFind, &ffd); + if(! b){ + return NULL; + } + strncpy(dp->result.d_name, ffd.cFileName, MAX_PATH); + } + dp->want_next = 1; + return &dp->result; +} + +static int closedir(DIR *dp) { + BOOL b; + b = FindClose(dp->hFind); + if(! b){ + errno = EBADF; + return -1; + } + free(dp); + return 0; +}