💾 Archived View for gemini.rmf-dev.com › repo › Vaati › Vgmi › files › 00b27da2981ae09dab55da606d4ba… captured on 2023-12-28 at 15:45:21. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

Go Back

0 /*

1 * ISC License

2 * Copyright (c) 2023 RMF <rawmonk@firemail.cc>

3 */

4 #include <stdio.h>

5 #include <stdlib.h>

6 #include <string.h>

7 #include <unistd.h>

8 #include <stdint.h>

9 #include <sys/types.h>

10 #include <sys/stat.h>

11 #include <pwd.h>

12 #include <fcntl.h>

13 #ifdef __linux__

14 #include <linux/limits.h>

15 #endif

16 #include <errno.h>

17 #include "macro.h"

18 #include "strlcpy.h"

19 #include "storage.h"

20 #include "error.h"

21 #include "utf8.h"

22

23 #ifndef PATH_MAX

24 #define PATH_MAX 1024

25 #endif

26

27 #define CONFIG_FOLDER "vgmi"

28 #define DOWNLOAD_PATH "Downloads"

29 #define CONFIG_PATH ".config/"CONFIG_FOLDER

30

31 int storage_fd = -1, download_fd = -1;

32

33 static int storage_mkdir(const char *path) {

34

35 struct stat st;

36 const char *ptr;

37 char path_copy[PATH_MAX];

38 int i;

39

40 if (stat(path, &st) == 0) return 0;

41

42 i = STRLCPY(path_copy, path);

43 path_copy[i] = '/';

44 path_copy[i + 1] = 0;

45 for (ptr = path_copy; ptr && *ptr; ptr = strchr(ptr, '/')) {

46 char buf[PATH_MAX];

47 if (ptr++ == path_copy) continue;

48 if ((size_t)(ptr - path_copy) >= sizeof(buf)) return -1;

49 strlcpy(buf, path_copy, ptr - path_copy + 1);

50 if (stat(buf, &st) == 0) continue;

51 if (mkdir(buf, 0700)) return -1;

52 }

53

54 return 0;

55 }

56

57 static int storage_from_home(char *out, size_t length, const char *dir) {

58

59 struct passwd *pw;

60 const char *path = getenv("HOME");

61

62 if (path) {

63 snprintf(out, length, "%s/%s", path, dir);

64 return 0;

65 }

66

67 pw = getpwuid(getuid());

68 if (pw) {

69 snprintf(out, length, "%s/%s", pw->pw_dir, dir);

70 return 0;

71 }

72

73 return -1;

74 }

75

76 int storage_path(char *out, size_t length) {

77

78 const char *path;

79

80 if (length > PATH_MAX) length = PATH_MAX;

81

82 path = getenv("XDG_CONFIG_HOME");

83 if (path) {

84 int i = strlcpy(out, path, length);

85 strlcpy(&out[i], CONFIG_FOLDER, length - i);

86 return 0;

87 }

88

89 return storage_from_home(out, length, CONFIG_PATH);

90 }

91

92 int storage_download_path(char *out, size_t length) {

93

94 FILE *f;

95

96 if (length > PATH_MAX) length = PATH_MAX;

97

98 f = popen("xdg-user-dir DOWNLOAD 2>&1", "r");

99 if (f) {

100 fread(out, 1, length, f);

101 pclose(f);

102 if (out[0] == '/') { /* success if the output is a path */

103 size_t i = 0;

104 while (i < length) {

105 uint32_t ch;

106 int len = utf8_char_to_unicode(&ch, &out[i]);

107 if (ch < ' ') {

108 out[i] = 0;

109 break;

110 }

111 i += len;

112 }

113 return 0;

114 }

115 }

116

117 return storage_from_home(out, length, DOWNLOAD_PATH);

118 }

119

120 static FILE* _fopen(const char *name, const char *mode, int dir) {

121

122 int fd;

123 int flags;

124

125 if (strchr(mode, 'w')) flags = O_WRONLY | O_TRUNC | O_CREAT;

126 else if (strchr(mode, 'r')) flags = O_RDONLY;

127 else if (strchr(mode, 'a')) flags = O_WRONLY | O_APPEND | O_CREAT;

128 else return NULL;

129

130 fd = openat(dir, name, flags, 0600);

131 if (fd < 0) return NULL;

132

133 return fdopen(fd, mode);

134 }

135

136 FILE* storage_fopen(const char *name, const char *mode) {

137 return _fopen(name, mode, storage_fd);

138 }

139

140 FILE* storage_download_fopen(const char *name, const char *mode) {

141 return _fopen(name, mode, download_fd);

142 }

143

144 int storage_open(const char *name, int flags, int mode) {

145 return openat(storage_fd, name, flags, mode);

146 }

147

148 int storage_download_open(const char *name, int flags, int mode) {

149 return openat(download_fd, name, flags, mode);

150 }

151

152 int storage_download_exist(const char *name) {

153 struct stat stat;

154 return !fstatat(download_fd, name, &stat, 0);

155 }

156

157 int storage_read(const char *name, char *out, size_t length,

158 size_t *length_out) {

159 int fd;

160 size_t file_length;

161

162 fd = openat(storage_fd, name, O_RDONLY, 0);

163 if (fd < 0) return ERROR_STORAGE_ACCESS;

164

165 file_length = lseek(fd, 0, SEEK_END);

166 lseek(fd, 0, SEEK_SET);

167

168 if (length < file_length) return ERROR_BUFFER_OVERFLOW;

169

170 if (read(fd, out, file_length) != (ssize_t)file_length)

171 return ERROR_STORAGE_ACCESS;

172 *length_out = file_length;

173

174 close(fd);

175 return 0;

176 }

177

178 int storage_init() {

179

180 char path[PATH_MAX], download[PATH_MAX];

181 int ret;

182

183 if (storage_path(V(path))) return ERROR_STORAGE_ACCESS;

184 if (storage_download_path(V(download))) return ERROR_STORAGE_ACCESS;

185 if (storage_mkdir(path)) return ERROR_STORAGE_ACCESS;

186 if (storage_mkdir(download)) return ERROR_STORAGE_ACCESS;

187 if ((ret = open(path, O_DIRECTORY)) < 0) return ERROR_STORAGE_ACCESS;

188 storage_fd = ret;

189 if ((ret = open(download, O_DIRECTORY)) < 0)

190 return ERROR_STORAGE_ACCESS;

191 download_fd = ret;

192 return 0;

193 }

194

195 int storage_close() {

196 close(storage_fd);

197 close(download_fd);

198 return 0;

199 }

200