summaryrefslogtreecommitdiffstats
path: root/lib/util.c
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <bigfoot@figboot.dev>2026-01-24 16:04:56 -0600
committerLibravatar bigfoot547 <bigfoot@figboot.dev>2026-01-24 16:04:56 -0600
commit154f94d1fd2de8f6510bfebba848a24c60b1ba8b (patch)
tree072bf7b9bb6f3599f54cf200e4d9eedde783c34d /lib/util.c
parentendian functions (diff)
Diffstat (limited to 'lib/util.c')
-rw-r--r--lib/util.c97
1 files changed, 96 insertions, 1 deletions
diff --git a/lib/util.c b/lib/util.c
index 6cfcf1f..29423d1 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -5,10 +5,54 @@
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int vl_mkdir_parents_open(int fd, char *path, mode_t nmode)
+{
+ int last = 0;
+ int at = fd;
+ int temp;
+ char *ch = path;
+ char *compstart = path;
+ int ret = -1;
+
+ do {
+ if (*ch == '/' || (*ch == '\0' && (last = 1))) {
+ if (ch == path) continue; /* false alarm: we're trying to create / */
+
+ *ch = '\0';
+
+ if (mkdirat(at, compstart, nmode) < 0 && errno != EEXIST) {
+ vl_debug("%s: failed to create directory %s: %s", __func__, path, strerror(errno));
+ goto cleanup;
+ }
+
+ temp = openat(at, compstart, O_RDONLY);
+ if (temp < 0) {
+ vl_debug("%s: failed to open new directory %s: %s", __func__, path, strerror(errno));
+ goto cleanup;
+ }
+
+ close(at);
+ temp = at;
+
+ compstart = ch + 1;
+ if (!last) *ch = '/'; /* make an effort to unclobber path */
+ }
+ } while (*(ch++));
+
+ ret = 0;
+
+cleanup:
+ if (at != fd) close(at);
+ return ret;
+}
/* will clobber path */
-int vl_mkdir_parents(int fd, char *path, mode_t mode)
+int vl_mkdir_parents(int fd, char *path, mode_t nmode)
{
+#if 0
int last = 0;
char *ch = path;
@@ -25,6 +69,57 @@ int vl_mkdir_parents(int fd, char *path, mode_t mode)
if (!last) *ch = '/';
}
} while (*(ch++));
+#endif /* old implementation */
+
+ fd = vl_mkdir_parents_open(fd, path, nmode);
+ if (fd >= 0) {
+ close(fd);
+ return 0;
+ }
+
+ return -1;
+}
+
+/* def: home-relative default */
+/* https://specifications.freedesktop.org/basedir/latest/ */
+static int open_xdg_dir(vl_arena *scratch, const char *xdg_env, const char *def)
+{
+ const char *xdg_dir = getenv(xdg_env);
+ int dfd;
+
+ if (xdg_dir && *xdg_dir == '/') {
+ char *xdg_dir_mod = vl_arena_strdup(scratch, xdg_dir);
+
+ /* must be an absolute path */
+ if ((dfd = vl_mkdir_parents_open(AT_FDCWD, xdg_dir_mod, 0700)) < 0) {
+ vl_warn("get_xdg_dir: Failed to create %s: %s", xdg_dir, strerror(errno));
+ return -1;
+ }
+
+ return dfd;
+ }
+
+ /* xdg dir is missing or not absolute (as required) */
+ const char *home = getenv("HOME");
+ /* TODO: could get passwd entry for home directory */
+
+ if (!home || *home != '/') {
+ vl_warn("Missing $HOME (or it is not an absolute path)! Cannot decide launcher data directory.");
+ return -1;
+ }
+
+ char *path = vl_arena_sprintf(scratch, "%s/%s", home, def);
+
+ if ((dfd = vl_mkdir_parents_open(AT_FDCWD, path, 0700)) < 0) {
+ vl_warn("%s: failed to create/open xdg dir %s: %s", __func__, path, strerror(errno));
+ return -1;
+ }
return 0;
}
+
+int vl_get_data_dir(vl_arena *alloc, const char *application, char **opath)
+{
+ /* TODO: not just linux */
+ int datadir = open_xdg_dir(alloc, "XDG_DATA_HOME", ".local/share");
+}