#include "fileutils.h" #include "alloc.h" #include #include #include #include #include #include #include #include #include #include const char* get_home_dir(void) { const char *home_dir = getenv("HOME"); if(!home_dir) { struct passwd *pw = getpwuid(getuid()); home_dir = pw->pw_dir; } return home_dir; } int file_get_content(const char *filepath, char **data, long *size) { int result = 0; FILE *file = fopen(filepath, "rb"); if(!file) { /*perror(filepath);*/ return -1; } int fd = fileno(file); struct stat s; if(fstat(fd, &s) == -1 || !S_ISREG(s.st_mode)) { fclose(file); return -1; } fseek(file, 0, SEEK_END); *size = ftell(file); if(*size == -1) { fprintf(stderr, "Failed to tell the size of file %s, is it not a file?\n", filepath); result = -1; goto cleanup; } fseek(file, 0, SEEK_SET); *data = alloc_or_crash(*size + 1); if((long)fread(*data, 1, *size, file) != *size) { fprintf(stderr, "Failed to read all bytes in file %s\n", filepath); result = -1; goto cleanup; } (*data)[*size] = '\0'; cleanup: fclose(file); return result; } int file_get_last_modified_time(const char *path, time_t *last_modified) { struct stat s = {0}; if(stat(path, &s) == 0) { *last_modified = s.st_mtim.tv_sec; return 0; } return -1; } int create_directory_recursive(char *path) { int path_len = strlen(path); char *p = path; char *end = path + path_len; for(;;) { char *slash_p = strchr(p, '/'); // Skips first '/', we don't want to try and create the root directory if(slash_p == path) { ++p; continue; } if(!slash_p) slash_p = end; char prev_char = *slash_p; *slash_p = '\0'; int err = mkdir(path, S_IRWXU); *slash_p = prev_char; if(err == -1 && errno != EEXIST) return err; if(slash_p == end) break; else p = slash_p + 1; } return 0; } static int is_directory(const char *path) { struct stat s = {0}; if(stat(path, &s) == 0) return S_ISDIR(s.st_mode); return 0; } static int remove_recursive_mutable(char *path) { int path_len = strlen(path); int res = 0; struct dirent *dir; DIR *d = opendir(path); if(!d) { fprintf(stderr, "Failed to open directory: %s\n", path); return -1; } while((dir = readdir(d)) != NULL) { int filename_len = strlen(dir->d_name); if((filename_len == 1 && dir->d_name[0] == '.') || (filename_len == 2 && dir->d_name[0] == '.' && dir->d_name[1] == '.')) continue; path[path_len] = '/'; memcpy(path + path_len + 1, dir->d_name, filename_len); path[path_len + 1 + filename_len] = '\0'; int is_dir = dir->d_type == DT_DIR; if(dir->d_type == DT_UNKNOWN) is_dir = is_directory(path); if(is_dir) { res = remove_recursive_mutable(path); if(res != 0) goto cleanup; } res = remove(path); if(res != 0) goto cleanup; } cleanup: path[path_len] = '\0'; res |= remove(path); closedir(d); return res; } int remove_recursive(char *path) { int path_len = strlen(path); char fullpath[PATH_MAX]; memcpy(fullpath, path, path_len); fullpath[path_len] = '\0'; return remove_recursive_mutable(fullpath); } int file_exists(const char *path) { return access(path, F_OK); } int create_lock_file(const char *path) { int fd = open(path, O_CREAT | O_EXCL | O_SYNC, 0666); if(fd == -1) return -1; return close(fd); } int file_overwrite(const char *filepath, const char *data, size_t size) { FILE *file = fopen(filepath, "wb"); if(!file) { perror(filepath); return -1; } unsigned long bytes_written = fwrite(data, 1, size, file); if(bytes_written != size) { fprintf(stderr, "Failed to write all bytes to file %s. Expected to write %zu bytes, only wrote %zu bytes\n", filepath, size, (size_t)bytes_written); fclose(file); return -1; } fclose(file); return 0; } int file_overwrite_in_dir(const char *dir, const char *filename, const char *data, size_t size) { char filepath[PATH_MAX]; const char *filepath_components[] = { dir, filename }; int filepath_len = path_join(filepath, filepath_components, 2); char tmp_filepath[PATH_MAX]; strcpy(tmp_filepath, filepath); strcpy(tmp_filepath + filepath_len, ".tmp"); int fd = open(tmp_filepath, O_CREAT | O_WRONLY, 0666); if(fd == -1) { perror(filepath); return -1; } ssize_t bytes_written = write(fd, data, size); if(bytes_written != (ssize_t)size) { fprintf(stderr, "Failed to write all bytes to file %s. Expected to write %zu bytes, only wrote %zd bytes\n", filepath, size, bytes_written); close(fd); return -1; } if(fsync(fd) == -1) { perror(filepath); close(fd); return -1; } close(fd); /* fsync + rename is atomic! */ return rename(tmp_filepath, filepath); } int path_join(char *output, const char **components, int num_components) { int offset = 0; for(int i = 0; i < num_components; ++i) { if(i > 0) { output[offset] = '/'; ++offset; } int component_len = strlen(components[i]); memcpy(output + offset, components[i], component_len); offset += component_len; } output[offset] = '\0'; return offset; }