summaryrefslogtreecommitdiff
path: root/os-posix.c
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-01-01 23:11:55 -0500
committerpommicket <pommicket@gmail.com>2023-01-01 23:11:55 -0500
commit850ab378946e8d6f0818b4ccf8eee413f68dcb95 (patch)
tree579230cbcf4f6f4a4a00504178ea6ca1b7d5ab8f /os-posix.c
parent3ee947ced94ce24463838e0c587cb076ac81ec98 (diff)
start os.h merging
Diffstat (limited to 'os-posix.c')
-rw-r--r--os-posix.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/os-posix.c b/os-posix.c
new file mode 100644
index 0000000..68e1d4f
--- /dev/null
+++ b/os-posix.c
@@ -0,0 +1,134 @@
+#include "os.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+
+static FsType statbuf_path_type(const struct stat *statbuf) {
+ if (S_ISREG(statbuf->st_mode))
+ return FS_FILE;
+ if (S_ISDIR(statbuf->st_mode))
+ return FS_DIRECTORY;
+ return FS_OTHER;
+}
+
+FsType fs_path_type(char const *path) {
+ struct stat statbuf = {0};
+ if (stat(path, &statbuf) != 0)
+ return FS_NON_EXISTENT;
+ return statbuf_path_type(&statbuf);
+}
+
+FsPermission fs_path_permission(char const *path) {
+ FsPermission perm = 0;
+ if (access(path, R_OK) == 0) perm |= FS_PERMISSION_READ;
+ if (access(path, W_OK) == 0) perm |= FS_PERMISSION_WRITE;
+ return perm;
+}
+
+bool fs_file_exists(char const *path) {
+ return fs_path_type(path) == FS_FILE;
+}
+
+FsDirectoryEntry **fs_list_directory(char const *dirname) {
+ FsDirectoryEntry **entries = NULL;
+ DIR *dir = opendir(dirname);
+ if (dir) {
+ struct dirent *ent;
+ size_t nentries = 0;
+ int fd = dirfd(dir);
+ if (fd != -1) {
+ while (readdir(dir)) ++nentries;
+ rewinddir(dir);
+ entries = (FsDirectoryEntry **)calloc(nentries+1, sizeof *entries);
+ if (entries) {
+ size_t idx = 0;
+ while ((ent = readdir(dir))) {
+ char const *filename = ent->d_name;
+ size_t len = strlen(filename);
+ FsDirectoryEntry *entry = (FsDirectoryEntry *)calloc(1, sizeof *entry + len + 1);
+ if (!entry) break;
+ memcpy(entry->name, filename, len);
+ switch (ent->d_type) {
+ case DT_REG:
+ entry->type = FS_FILE;
+ break;
+ case DT_DIR:
+ entry->type = FS_DIRECTORY;
+ break;
+ case DT_LNK: // we need to dereference the link
+ case DT_UNKNOWN: { // information not available directly from dirent, we need to get it ourselves
+ struct stat statbuf = {0};
+ fstatat(fd, filename, &statbuf, 0);
+ entry->type = statbuf_path_type(&statbuf);
+ } break;
+ default:
+ entry->type = FS_OTHER;
+ }
+ if (idx < nentries) // this could actually fail if someone creates files between calculating nentries and here.
+ entries[idx++] = entry;
+ }
+ }
+ }
+ closedir(dir);
+ }
+ return entries;
+}
+
+int fs_mkdir(char const *path) {
+ if (mkdir(path, 0755) == 0) {
+ // directory created successfully
+ return 1;
+ } else if (errno == EEXIST) {
+ struct stat statbuf = {0};
+ if (stat(path, &statbuf) == 0) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ // already exists, and it's a directory
+ return 0;
+ } else {
+ // already exists, but not a directory
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+}
+
+int fs_get_cwd(char *buf, size_t buflen) {
+ assert(buf && buflen);
+ if (getcwd(buf, buflen)) {
+ return 1;
+ } else if (errno == ERANGE) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+struct timespec time_last_modified(char const *filename) {
+ struct stat statbuf = {0};
+ stat(filename, &statbuf);
+ return statbuf.st_mtim;
+}
+
+struct timespec time_get(void) {
+ struct timespec ts = {0};
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return ts;
+}
+
+void time_sleep_ns(u64 ns) {
+ struct timespec rem = {0}, req = {
+ (time_t)(ns / 1000000000),
+ (long)(ns % 1000000000)
+ };
+
+ while (nanosleep(&req, &rem) == EINTR) // sleep interrupted by signal
+ req = rem;
+}