Pharos 0.7.23
Modern Web Framework & Web App Hosting Service.
Loading...
Searching...
No Matches
native_fs.c
Go to the documentation of this file.
1/**
2 * @file
3 * @brief Provides filesystem helpers for directory creation, recursive copy or removal, and file writes.
4 */
5
6#include "native_fs.h"
7
8#include "native_support.h"
9
10#include <errno.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#ifdef _WIN32
16#include <direct.h>
17#include <io.h>
18#include <sys/stat.h>
19#define PHAROS_FS_PATH_SEP '\\'
20#define pharos_fs_mkdir(path, mode) _mkdir(path)
21#define pharos_fs_unlink _unlink
22#else
23#include <dirent.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#define PHAROS_FS_PATH_SEP '/'
27#define pharos_fs_mkdir mkdir
28#define pharos_fs_unlink unlink
29#endif
30
31int ensure_directory(const char *path) {
32 char *copy;
33 char *cursor;
34 if (path == NULL || path[0] == '\0') {
35 return 0;
36 }
37 if (path_is_directory(path)) {
38 return 0;
39 }
40#ifdef _WIN32
41 copy = _strdup(path);
42#else
43 copy = strdup(path);
44#endif
45 if (copy == NULL) {
46 return 69;
47 }
48 for (cursor = copy + 1; *cursor != '\0'; cursor++) {
49 if (*cursor == PHAROS_FS_PATH_SEP) {
50 *cursor = '\0';
51 if (copy[0] != '\0' && !path_is_directory(copy) && pharos_fs_mkdir(copy, 0755) != 0 && errno != EEXIST) {
52 free(copy);
53 return 69;
54 }
55 *cursor = PHAROS_FS_PATH_SEP;
56 }
57 }
58 if (!path_is_directory(copy) && pharos_fs_mkdir(copy, 0755) != 0 && errno != EEXIST) {
59 free(copy);
60 return 69;
61 }
62 free(copy);
63 return 0;
64}
65
66int write_text_file(const char *path, const char *content) {
67 FILE *file;
68 char *dir;
69 size_t content_len = content != NULL ? strlen(content) : 0;
70 dir = path_dirname(path);
71 if (dir == NULL) {
72 return 69;
73 }
74 if (ensure_directory(dir) != 0) {
75 free(dir);
76 return 69;
77 }
78 free(dir);
79 file = fopen(path, "wb");
80 if (file == NULL) {
81 return 69;
82 }
83 if (content_len > 0 && fwrite(content, 1, content_len, file) != content_len) {
84 fclose(file);
85 return 69;
86 }
87 if (fclose(file) != 0) {
88 return 69;
89 }
90 return 0;
91}
92
93int copy_file_binary(const char *source_path, const char *target_path) {
94 FILE *source = NULL;
95 FILE *target = NULL;
96 char *target_dir = NULL;
97 char chunk[4096];
98 size_t bytes_read;
99 int code = 0;
100 target_dir = path_dirname(target_path);
101 if (target_dir == NULL || ensure_directory(target_dir) != 0) {
102 code = 69;
103 goto cleanup;
104 }
105 source = fopen(source_path, "rb");
106 if (source == NULL) {
107 code = 66;
108 goto cleanup;
109 }
110 target = fopen(target_path, "wb");
111 if (target == NULL) {
112 code = 69;
113 goto cleanup;
114 }
115 while ((bytes_read = fread(chunk, 1, sizeof(chunk), source)) > 0) {
116 if (fwrite(chunk, 1, bytes_read, target) != bytes_read) {
117 code = 69;
118 goto cleanup;
119 }
120 }
121cleanup:
122 if (source != NULL && fclose(source) != 0 && code == 0) {
123 code = 69;
124 }
125 if (target != NULL && fclose(target) != 0 && code == 0) {
126 code = 69;
127 }
128 free(target_dir);
129 return code;
130}
131
132int copy_directory_recursive(const char *source_dir, const char *target_dir) {
133#ifndef _WIN32
134 DIR *dir;
135 struct dirent *entry;
136 if (ensure_directory(target_dir) != 0) {
137 return 69;
138 }
139 dir = opendir(source_dir);
140 if (dir == NULL) {
141 return 66;
142 }
143 while ((entry = readdir(dir)) != NULL) {
144 char *source_path;
145 char *target_path;
146 int code;
147 if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) {
148 continue;
149 }
150 source_path = path_join(source_dir, entry->d_name);
151 target_path = path_join(target_dir, entry->d_name);
152 if (source_path == NULL || target_path == NULL) {
153 free(source_path);
154 free(target_path);
155 closedir(dir);
156 return 69;
157 }
158 if (path_is_directory(source_path)) {
159 code = copy_directory_recursive(source_path, target_path);
160 } else {
161 code = copy_file_binary(source_path, target_path);
162 }
163 free(source_path);
164 free(target_path);
165 if (code != 0) {
166 closedir(dir);
167 return code;
168 }
169 }
170 closedir(dir);
171 return 0;
172#else
173 (void)source_dir;
174 (void)target_dir;
175 return 78;
176#endif
177}
178
179int remove_directory_recursive(const char *target_dir) {
180#ifndef _WIN32
181 DIR *dir;
182 struct dirent *entry;
183 if (target_dir == NULL || !path_exists(target_dir)) {
184 return 0;
185 }
186 if (!path_is_directory(target_dir)) {
187 return pharos_fs_unlink(target_dir) == 0 ? 0 : 69;
188 }
189 dir = opendir(target_dir);
190 if (dir == NULL) {
191 return 69;
192 }
193 while ((entry = readdir(dir)) != NULL) {
194 char *child_path;
195 int code;
196 if (streq(entry->d_name, ".") || streq(entry->d_name, "..")) {
197 continue;
198 }
199 child_path = path_join(target_dir, entry->d_name);
200 if (child_path == NULL) {
201 closedir(dir);
202 return 69;
203 }
204 if (path_is_directory(child_path)) {
205 code = remove_directory_recursive(child_path);
206 } else {
207 code = pharos_fs_unlink(child_path) == 0 ? 0 : 69;
208 }
209 free(child_path);
210 if (code != 0) {
211 closedir(dir);
212 return code;
213 }
214 }
215 closedir(dir);
216 return rmdir(target_dir) == 0 ? 0 : 69;
217#else
218 (void)target_dir;
219 return 78;
220#endif
221}
int ensure_directory(const char *path)
Creates a directory path and any missing parent directories.
Definition native_fs.c:31
int write_text_file(const char *path, const char *content)
Writes a text buffer to a file path.
Definition native_fs.c:66
#define PHAROS_FS_PATH_SEP
Definition native_fs.c:26
int remove_directory_recursive(const char *target_dir)
Recursively removes a directory tree.
Definition native_fs.c:179
int copy_directory_recursive(const char *source_dir, const char *target_dir)
Recursively copies one directory tree into another location.
Definition native_fs.c:132
#define pharos_fs_unlink
Definition native_fs.c:28
int copy_file_binary(const char *source_path, const char *target_path)
Copies one file as binary data.
Definition native_fs.c:93
#define pharos_fs_mkdir
Definition native_fs.c:27
Declares native filesystem helper routines.
char * path_join(const char *left, const char *right)
Joins two path segments using the native path separator.
int streq(const char *a, const char *b)
Tests whether two strings are exactly equal.
int path_is_directory(const char *path)
Tests whether a filesystem path refers to a directory.
char * path_dirname(const char *path)
Returns the parent directory component of a path.
int path_exists(const char *path)
Tests whether a filesystem path currently exists.
Declares shared low-level support helpers used across the Pharos native runtime.