a lot of stuff tbh
This commit is contained in:
parent
d80773bb00
commit
8ddd9186b8
42 changed files with 6463 additions and 1593 deletions
11
deprecated/coroutine.c
Normal file
11
deprecated/coroutine.c
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#include "coroutine.h"
|
||||
|
||||
coroutine_t coInit() {
|
||||
return (coroutine_t) {
|
||||
.state = 0
|
||||
};
|
||||
}
|
||||
|
||||
bool coIsDead(coroutine_t co) {
|
||||
return co.state == -1;
|
||||
}
|
||||
133
deprecated/coroutine.h
Normal file
133
deprecated/coroutine.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h> // bool
|
||||
#include <string.h> // memset
|
||||
#include "tracelog.h" // fatal
|
||||
|
||||
// heavily inspired by https://gist.github.com/Enichan/5f01140530ff0133fde19c9549a2a973
|
||||
|
||||
#if 0
|
||||
// Usage example:
|
||||
typedef struct {
|
||||
int result;
|
||||
coroutine_t co;
|
||||
} co_int_t;
|
||||
|
||||
bool coVoid(co_void_t *co) {
|
||||
costate(co_nostate);
|
||||
coroutine({
|
||||
printf("hello"); yield();
|
||||
printf("world"); yield();
|
||||
printf("how"); yield();
|
||||
printf("is"); yield();
|
||||
printf("it"); yield();
|
||||
printf("going?\n");
|
||||
});
|
||||
}
|
||||
|
||||
bool countToTen(co_int_t *co) {
|
||||
costate(int i; int ii;);
|
||||
coroutine({
|
||||
for(self.i = 0; self.i < 10; ++self.i) {
|
||||
self.ii += self.i;
|
||||
yieldVal(self.ii);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int main() {
|
||||
co_void_t covoid = {0};
|
||||
while(coVoid(&covoid)) {
|
||||
printf(" ");
|
||||
}
|
||||
|
||||
co_int_t coint;
|
||||
coint.co = coInit();
|
||||
while(countToTen(&coint)) {
|
||||
printf("%d ", coint.result);
|
||||
}
|
||||
printf("\n");
|
||||
// reset coroutine for next call
|
||||
coint.co = coInit();
|
||||
while(countToTen(&coint)) {
|
||||
printf("%d ", coint.result);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int state;
|
||||
} coroutine_t;
|
||||
|
||||
typedef struct {
|
||||
coroutine_t co;
|
||||
} co_void_t;
|
||||
|
||||
coroutine_t coInit();
|
||||
bool coIsDead(coroutine_t co);
|
||||
|
||||
#define COVAR co
|
||||
#define COSELF self
|
||||
|
||||
#define costate(...) \
|
||||
typedef struct { bool init; __VA_ARGS__ } COSTATE; \
|
||||
static COSTATE self = {0}
|
||||
|
||||
#define co_nostate { char __dummy__; }
|
||||
|
||||
#define yieldBreak() \
|
||||
COVAR->co.state = -1; \
|
||||
self.init = false; \
|
||||
return false;
|
||||
|
||||
#define coroutine(...) \
|
||||
if(!self.init) { \
|
||||
if(COVAR->co.state != 0) { \
|
||||
fatal("coroutine not initialized in %s:%d,\n" \
|
||||
"did you forget to do '= {0};'?", \
|
||||
__FILE__, __LINE__); \
|
||||
} \
|
||||
memset(&self, 0, sizeof(self)); \
|
||||
self.init = true; \
|
||||
} \
|
||||
switch(COVAR->co.state) { \
|
||||
case 0:; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
yieldBreak();
|
||||
|
||||
#define yield() _yield(__COUNTER__)
|
||||
#define _yield(count) \
|
||||
do { \
|
||||
COVAR->co.state = count; \
|
||||
return true; \
|
||||
case count:; \
|
||||
} while(0);
|
||||
|
||||
#define yieldVal(v) _yieldVal(v, __COUNTER__)
|
||||
#define _yieldVal(v, count) \
|
||||
do { \
|
||||
COVAR->co.state = count; \
|
||||
COVAR->result = v; \
|
||||
return true; \
|
||||
case count:; \
|
||||
} while(0);
|
||||
|
||||
// increment __COUNTER__ past 0 so we don't get double case errors
|
||||
#define CONCAT_IMPL(x, y) x##y
|
||||
#define MACRO_CONCAT(x, y) CONCAT_IMPL(x, y)
|
||||
#define __INC_COUNTER int MACRO_CONCAT(__counter_tmp_, __COUNTER__)
|
||||
__INC_COUNTER;
|
||||
|
||||
#undef CONCAT_IMPL
|
||||
#undef MACRO_CONCAT
|
||||
#undef __INC_COUNTER
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
295
deprecated/dirwatch.c
Normal file
295
deprecated/dirwatch.c
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
#include "dirwatch.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include "tracelog.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win32_slim.h"
|
||||
#include "str.h"
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
dirwatch_cb_t on_event;
|
||||
BOOL should_continue;
|
||||
HANDLE stop_event;
|
||||
} __dirwatch_internal_t;
|
||||
|
||||
static int watchDirThread(void *cdata) {
|
||||
__dirwatch_internal_t *desc = (__dirwatch_internal_t*)cdata;
|
||||
|
||||
// stop_event is called from another thread when watchDirThread should exit
|
||||
desc->stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
HANDLE file = CreateFile(
|
||||
desc->path,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
assert(file != INVALID_HANDLE_VALUE);
|
||||
OVERLAPPED overlapped = {0};
|
||||
overlapped.hEvent = CreateEvent(NULL, FALSE, 0, NULL);
|
||||
|
||||
uint8_t change_buf[1024];
|
||||
BOOL success = ReadDirectoryChangesW(
|
||||
file, change_buf, sizeof(change_buf), TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL, &overlapped, NULL
|
||||
);
|
||||
assert(success);
|
||||
|
||||
HANDLE events[2] = {
|
||||
overlapped.hEvent,
|
||||
desc->stop_event
|
||||
};
|
||||
|
||||
WCHAR old_name[MAX_PATH];
|
||||
dirwatch_file_t data = {0};
|
||||
|
||||
// if the variable is 32bit aligned, a read/write is already atomice
|
||||
// https://docs.microsoft.com/en-us/windows/win32/sync/interlocked-variable-access
|
||||
while(desc->should_continue) {
|
||||
DWORD result = WaitForMultipleObjects(2, events, FALSE, INFINITE);
|
||||
|
||||
if(result == WAIT_OBJECT_0) {
|
||||
DWORD bytes_transferred;
|
||||
GetOverlappedResult(file, &overlapped, &bytes_transferred, FALSE);
|
||||
|
||||
FILE_NOTIFY_INFORMATION *event = (FILE_NOTIFY_INFORMATION*)change_buf;
|
||||
|
||||
for(;;) {
|
||||
DWORD name_len = event->FileNameLength / sizeof(wchar_t);
|
||||
|
||||
switch(event->Action) {
|
||||
case FILE_ACTION_ADDED:
|
||||
data.name = strFromWCHAR(event->FileName, name_len).buf;
|
||||
data.oldname = NULL;
|
||||
desc->on_event(desc->path, DIRWATCH_FILE_ADDED, data);
|
||||
break;
|
||||
case FILE_ACTION_REMOVED:
|
||||
data.name = strFromWCHAR(event->FileName, name_len).buf;
|
||||
data.oldname = NULL;
|
||||
desc->on_event(desc->path, DIRWATCH_FILE_REMOVED, data);
|
||||
break;
|
||||
case FILE_ACTION_RENAMED_OLD_NAME:
|
||||
memcpy(old_name, event->FileName, event->FileNameLength);
|
||||
old_name[event->FileNameLength] = '\0';
|
||||
break;
|
||||
case FILE_ACTION_RENAMED_NEW_NAME:
|
||||
data.name = strFromWCHAR(event->FileName, name_len).buf;
|
||||
data.oldname = strFromWCHAR(old_name, 0).buf;
|
||||
desc->on_event(desc->path, DIRWATCH_FILE_RENAMED, data);
|
||||
break;
|
||||
}
|
||||
|
||||
if(data.name) free(data.name);
|
||||
if(data.oldname) free(data.oldname);
|
||||
|
||||
data = (dirwatch_file_t){0};
|
||||
|
||||
if(event->NextEntryOffset) {
|
||||
*((uint8_t**)&event) += event->NextEntryOffset;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
success = ReadDirectoryChangesW(
|
||||
file, change_buf, sizeof(change_buf), TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME |
|
||||
FILE_NOTIFY_CHANGE_DIR_NAME |
|
||||
FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL, &overlapped, NULL
|
||||
);
|
||||
assert(success);
|
||||
}
|
||||
// stop_event
|
||||
else if(result == WAIT_OBJECT_0 + 1) {
|
||||
warn("stopping");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
dirwatch_t watchDir(dirwatch_desc_t desc) {
|
||||
dirwatch_t dir = {0};
|
||||
|
||||
__dirwatch_internal_t *opts = HeapAlloc(
|
||||
GetProcessHeap(),
|
||||
0,
|
||||
sizeof(__dirwatch_internal_t)
|
||||
);
|
||||
|
||||
opts->path = desc.path;
|
||||
opts->on_event = desc.on_event;
|
||||
opts->should_continue = true;
|
||||
|
||||
dir.desc = (dirwatch_desc_t *)opts;
|
||||
|
||||
dir.handle = thrCreate(watchDirThread, (void *)dir.desc);
|
||||
|
||||
if(thrValid(dir.handle)) {
|
||||
info("watching %s", desc.path);
|
||||
}
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
void waitForWatchDir(dirwatch_t *ctx) {
|
||||
if(!thrValid(ctx->handle)) {
|
||||
err("not valid");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!thrJoin(ctx->handle, NULL)) {
|
||||
err("dirwatch: couldn't wait for thread");
|
||||
}
|
||||
info("waited");
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, ctx->desc);
|
||||
}
|
||||
|
||||
void stopWatchDir(dirwatch_t *ctx, bool immediately) {
|
||||
(void)immediately;
|
||||
__dirwatch_internal_t *opts = (__dirwatch_internal_t *)ctx->desc;
|
||||
opts->should_continue = false;
|
||||
if(immediately) {
|
||||
if(!SetEvent(opts->stop_event)) {
|
||||
err("couldn't signal event stop_event: %d", GetLastError());
|
||||
}
|
||||
}
|
||||
if(!thrJoin(ctx->handle, NULL)) {
|
||||
err("dirwatch: couldn't wait for thread");
|
||||
}
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, ctx->desc);
|
||||
}
|
||||
|
||||
#else
|
||||
#include <sys/inotify.h>
|
||||
#include <unistd.h> // read
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <linux/limits.h> // MAX_PATH
|
||||
#include <stdatomic.h>
|
||||
|
||||
#define EVENT_SIZE (sizeof(struct inotify_event))
|
||||
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
|
||||
|
||||
#define ERROR(str) { err(str ": %s", strerror(errno)); goto error; }
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
dirwatch_cb_t on_event;
|
||||
atomic_bool should_continue;
|
||||
int fd;
|
||||
int wd;
|
||||
} __dirwatch_internal_t;
|
||||
|
||||
static int watchDirThread(void *cdata) {
|
||||
__dirwatch_internal_t *desc = (__dirwatch_internal_t *)cdata;
|
||||
info("watching %s", desc->path);
|
||||
|
||||
int length/*, fd, wd*/;
|
||||
char buffer[BUF_LEN];
|
||||
|
||||
desc->fd = inotify_init();
|
||||
|
||||
if(desc->fd < 0) {
|
||||
ERROR("inotify_init failed");
|
||||
}
|
||||
|
||||
desc->wd = inotify_add_watch(desc->fd, desc->path, IN_MOVE | IN_CREATE | IN_DELETE);
|
||||
|
||||
char old_path[PATH_MAX] = {0};
|
||||
dirwatch_file_t data = {0};
|
||||
|
||||
while(desc->should_continue) {
|
||||
length = (int)read(desc->fd, buffer, BUF_LEN);
|
||||
|
||||
if(length < 0) {
|
||||
ERROR("couldn't read");
|
||||
}
|
||||
|
||||
for(int i = 0; i < length;) {
|
||||
struct inotify_event *event = (struct inotify_event *) &buffer[i];
|
||||
if(event->len) {
|
||||
uint32_t e = event->mask;
|
||||
// bool is_dir = e & IN_ISDIR;
|
||||
|
||||
if(e & IN_CREATE) {
|
||||
data.name = event->name;
|
||||
desc->on_event(desc->path, DIRWATCH_FILE_ADDED, data);
|
||||
}
|
||||
else if(e & IN_DELETE) {
|
||||
data.name = event->name;
|
||||
desc->on_event(desc->path, DIRWATCH_FILE_REMOVED, data);
|
||||
}
|
||||
else if(e & IN_MOVED_FROM) {
|
||||
memcpy(old_path, event->name, event->len);
|
||||
old_path[event->len] = '\0';
|
||||
}
|
||||
else if(e & IN_MOVED_TO) {
|
||||
data.oldname = old_path;
|
||||
data.name = event->name;
|
||||
desc->on_event(desc->path, DIRWATCH_FILE_RENAMED, data);
|
||||
}
|
||||
}
|
||||
|
||||
i += EVENT_SIZE + event->len;
|
||||
}
|
||||
}
|
||||
|
||||
inotify_rm_watch(desc->fd, desc->wd);
|
||||
close(desc->fd);
|
||||
|
||||
return 0;
|
||||
error:
|
||||
return 1;
|
||||
}
|
||||
|
||||
dirwatch_t watchDir(dirwatch_desc_t desc) {
|
||||
dirwatch_t dir = {0};
|
||||
|
||||
__dirwatch_internal_t *opts = malloc(sizeof(__dirwatch_internal_t));
|
||||
opts->path = desc.path;
|
||||
opts->on_event = desc.on_event;
|
||||
opts->fd = 0;
|
||||
opts->wd = 0;
|
||||
opts->should_continue = true;
|
||||
|
||||
dir.desc = (dirwatch_desc_t *)opts;
|
||||
|
||||
dir.handle = thrCreate(watchDirThread, opts);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
void waitForWatchDir(dirwatch_t *ctx) {
|
||||
thrJoin(ctx->handle, NULL);
|
||||
free(ctx->desc);
|
||||
}
|
||||
|
||||
void stopWatchDir(dirwatch_t *ctx, bool immediately) {
|
||||
__dirwatch_internal_t *opts = (__dirwatch_internal_t *)ctx->desc;
|
||||
opts->should_continue = false;
|
||||
// this one might get called in the thread first, but it doesn't matter
|
||||
if(immediately) {
|
||||
inotify_rm_watch(opts->fd, opts->wd);
|
||||
close(opts->fd);
|
||||
}
|
||||
thrJoin(ctx->handle, NULL);
|
||||
free(opts);
|
||||
}
|
||||
|
||||
#endif
|
||||
67
deprecated/dirwatch.h
Normal file
67
deprecated/dirwatch.h
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Basic usage:
|
||||
*
|
||||
* // this function will be called from another thread every time
|
||||
* // something happens to 'path'
|
||||
* void onEvent(const char *path, int action, dirwatch_file_t file) {
|
||||
* switch(action) {
|
||||
* case DIRWATCH_FILE_ADDED: [do something] break;
|
||||
* case DIRWATCH_FILE_REMOVED: [do something] break;
|
||||
* case DIRWATCH_FILE_RENAMED: [do something] break;
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* int main() {
|
||||
* dirwatch_t dir = watchDir((dirwatch_desc_t){
|
||||
* .dirname = "watch/",
|
||||
* .on_event = onEvent
|
||||
* });
|
||||
*
|
||||
* waitForWatchDir(&dir);
|
||||
* }
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "cthreads.h"
|
||||
|
||||
enum {
|
||||
DIRWATCH_FILE_ADDED,
|
||||
DIRWATCH_FILE_REMOVED,
|
||||
DIRWATCH_FILE_RENAMED,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *oldname;
|
||||
} dirwatch_file_t;
|
||||
|
||||
typedef void (*dirwatch_cb_t)(const char *path, int action, dirwatch_file_t data);
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
dirwatch_cb_t on_event;
|
||||
} dirwatch_desc_t;
|
||||
|
||||
typedef struct {
|
||||
cthread_t handle;
|
||||
dirwatch_desc_t *desc;
|
||||
} dirwatch_t;
|
||||
|
||||
// Creates a thread and starts watching the folder specified by desc
|
||||
// if any action happend on_event will be called from this thread
|
||||
dirwatch_t watchDir(dirwatch_desc_t desc);
|
||||
// waits forever
|
||||
void waitForWatchDir(dirwatch_t *ctx);
|
||||
// stops dirwatch thread, if immediately is true, it will try to close it right away
|
||||
// otherwise it might wait for one last event
|
||||
void stopWatchDir(dirwatch_t *ctx, bool immediately);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
134
deprecated/fs.c
Normal file
134
deprecated/fs.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include "fs.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tracelog.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "win32_slim.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
static fsmode_t _modeToType(unsigned int mode) {
|
||||
switch(mode & _S_IFMT) {
|
||||
case _S_IFDIR: return FS_MODE_DIR;
|
||||
case _S_IFCHR: return FS_MODE_CHARACTER_DEVICE;
|
||||
case _S_IFREG: return FS_MODE_FILE;
|
||||
case _S_IFIFO: return FS_MODE_FIFO;
|
||||
default: return FS_MODE_UKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
fs_stat_t fsStat(file_t fp) {
|
||||
TCHAR path[MAX_PATH];
|
||||
GetFinalPathNameByHandle(
|
||||
(HANDLE)fp.handle,
|
||||
path,
|
||||
MAX_PATH,
|
||||
0
|
||||
);
|
||||
|
||||
struct stat statbuf;
|
||||
int res = stat(path, &statbuf);
|
||||
if(res == 0) {
|
||||
return (fs_stat_t) {
|
||||
.type = _modeToType(statbuf.st_mode),
|
||||
.size = statbuf.st_size,
|
||||
.last_access = statbuf.st_atime,
|
||||
.last_modif = statbuf.st_mtime
|
||||
};
|
||||
}
|
||||
else {
|
||||
return (fs_stat_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
fs_time_t fsAsTime(int64_t timer) {
|
||||
struct tm t;
|
||||
errno_t error = localtime_s(&t, &timer);
|
||||
|
||||
if(error == 0) {
|
||||
return (fs_time_t) {
|
||||
.year = t.tm_year + 1900,
|
||||
.month = t.tm_mon + 1,
|
||||
.day = t.tm_mday,
|
||||
.hour = t.tm_hour,
|
||||
.minutes = t.tm_min,
|
||||
.seconds = t.tm_sec,
|
||||
.daylight_saving = t.tm_isdst > 0
|
||||
};
|
||||
}
|
||||
else {
|
||||
char buf[128];
|
||||
strerror_s(buf, sizeof(buf), error);
|
||||
err("%s", buf);
|
||||
return (fs_time_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
bool fsIsDir(const char *path) {
|
||||
DWORD attr = GetFileAttributes(path);
|
||||
|
||||
return attr != INVALID_FILE_ATTRIBUTES &&
|
||||
attr & FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
#else
|
||||
#include <sys/stat.h>
|
||||
|
||||
static fsmode_t _modeToType(unsigned int mode) {
|
||||
switch(mode & __S_IFMT) {
|
||||
case __S_IFDIR: return FS_MODE_DIR;
|
||||
case __S_IFCHR: return FS_MODE_CHARACTER_DEVICE;
|
||||
case __S_IFREG: return FS_MODE_FILE;
|
||||
case __S_IFIFO: return FS_MODE_FIFO;
|
||||
default: return FS_MODE_UKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
fs_stat_t fsStat(file_t fp) {
|
||||
int fd = fileno((FILE*)fp);
|
||||
struct stat statbuf;
|
||||
int res = fstat(fd, &statbuf);
|
||||
if(res == 0) {
|
||||
return (fs_stat_t) {
|
||||
.type = _modeToType(statbuf.st_mode),
|
||||
.size = (uint64_t)statbuf.st_size,
|
||||
.last_access = statbuf.st_atime,
|
||||
.last_modif = statbuf.st_mtime
|
||||
};
|
||||
}
|
||||
else {
|
||||
return (fs_stat_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
fs_time_t fsAsTime(int64_t timer) {
|
||||
struct tm *t = localtime(&timer);
|
||||
|
||||
if(t) {
|
||||
return (fs_time_t) {
|
||||
.year = t->tm_year + 1900,
|
||||
.month = t->tm_mon + 1,
|
||||
.day = t->tm_mday,
|
||||
.hour = t->tm_hour,
|
||||
.minutes = t->tm_min,
|
||||
.seconds = t->tm_sec,
|
||||
.daylight_saving = t->tm_isdst > 0
|
||||
};
|
||||
}
|
||||
else {
|
||||
err("%s", strerror(errno));
|
||||
return (fs_time_t) { 0 };
|
||||
}
|
||||
}
|
||||
|
||||
bool fsIsDir(const char *path) {
|
||||
struct stat statbuf;
|
||||
return stat(path, &statbuf) == 0 && S_ISDIR(statbuf.st_mode);
|
||||
}
|
||||
|
||||
#endif
|
||||
44
deprecated/fs.h
Normal file
44
deprecated/fs.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "file.h"
|
||||
|
||||
typedef enum {
|
||||
FS_MODE_FILE,
|
||||
FS_MODE_DIR,
|
||||
FS_MODE_CHARACTER_DEVICE,
|
||||
FS_MODE_FIFO,
|
||||
FS_MODE_UKNOWN,
|
||||
} fsmode_t;
|
||||
|
||||
typedef struct {
|
||||
fsmode_t type;
|
||||
uint64_t size;
|
||||
int64_t last_access;
|
||||
int64_t last_modif;
|
||||
} fs_stat_t;
|
||||
|
||||
typedef struct {
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
int hour;
|
||||
int minutes;
|
||||
int seconds;
|
||||
bool daylight_saving;
|
||||
} fs_time_t;
|
||||
|
||||
fs_stat_t fsStat(file_t fp);
|
||||
fs_time_t fsAsTime(int64_t time);
|
||||
|
||||
bool fsIsDir(const char *path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
Loading…
Add table
Add a link
Reference in a new issue