diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/fs.c | 88 | ||||
-rw-r--r-- | src/site.c | 10 |
2 files changed, 97 insertions, 1 deletions
@@ -6,12 +6,19 @@ #include <fcntl.h> #include <stdio.h> #include <ctype.h> +#include <unistd.h> #include <stdint.h> #include <stdlib.h> #include <limits.h> +#include <dirent.h> #include <string.h> #include <strings.h> #include <sys/stat.h> +#ifdef __linux__ +#include <sys/sendfile.h> +#endif + +#define BUFSIZE 8192 #define CONTENTDIR "content" #define DEFAULTALBUM "unorganized" @@ -142,3 +149,84 @@ setdatetime(const char *path, const struct timespec *mtim) log_printl_errno(LOG_ERROR, "Warning: couldn't set times of %s", path); } } + +bool +filesync(const char *restrict srcpath, const char *restrict dstpath) +{ + int fdsrc; + struct stat stsrc; + + fdsrc = open(srcpath, O_RDONLY); + if (fdsrc < 0) return false; + if (fstat(fdsrc, &stsrc)) goto dir_error; + + if (S_ISDIR(stsrc.st_mode)) { + if (mkdir(dstpath, 0755)) { + if (errno != EEXIST) goto dir_error; + if (stat(dstpath, &stsrc)) goto dir_error; + if (!S_ISDIR(stsrc.st_mode)){ + errno = ENOTDIR; + goto dir_error; + } + } + DIR *dir = fdopendir(fdsrc); + if (dir == NULL) goto dir_error; + struct dirent *ent; + while ((ent = readdir(dir))) { + if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) { + continue; + } + char entsrc[PATH_MAX], entdst[PATH_MAX]; + sprintf(entsrc, "%s/%s", srcpath, ent->d_name); + sprintf(entdst, "%s/%s", dstpath, ent->d_name); + if (filesync(entsrc, entdst)) { + closedir(dir); + goto dir_error; + } + } + closedir(dir); + + goto dir_success; + } + + int fddst, uptodate; + if ((uptodate = file_is_uptodate(dstpath, &stsrc.st_mtim)) > 0) { + goto dir_success; + } else if (uptodate < 0) { + goto dir_error; + } + fddst = open(dstpath, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fddst < 0) goto dir_error; + +#ifdef __linux__ + ssize_t nwrote = sendfile(fddst, fdsrc, NULL, stsrc.st_size); + if (nwrote != stsrc.st_size) goto copy_error; +#else + char buf[BUFSIZE]; + ssize_t nread; + + while ((nread = read(fdsrc, buf, BUFSIZE)) > 0) { + ssize_t nwrote = write(fddst, buf, nread); + if (nread != nwrote) goto copy_error; + } + if (nread < 0) goto copy_error; +#endif + + struct timespec tms[] = { + { .tv_sec = stsrc.st_mtim.tv_sec, .tv_nsec = stsrc.st_mtim.tv_nsec }, + { .tv_sec = stsrc.st_mtim.tv_sec, .tv_nsec = stsrc.st_mtim.tv_nsec }, + }; + futimens(fddst, tms); + + log_printl(LOG_DETAIL, "Copied %s", srcpath); + + close(fddst); +dir_success: + close(fdsrc); + return true; +copy_error: + close(fddst); +dir_error: + close(fdsrc); + return false; +} @@ -197,8 +197,16 @@ bool site_build(struct site *site) { struct stat dstat; + char staticp[PATH_MAX]; + if (!nmkdir(site->output_dir, &dstat, false)) return false; + joinpathb(staticp, site->root_dir, STATICDIR); + if (!filesync(staticp, site->output_dir) && errno != ENOENT) { + log_printl_errno(LOG_FATAL, "Can't copy static files"); + return false; + } + if (chdir(site->output_dir)) { log_printl_errno(LOG_FATAL, "Can't change to directory %s", site->output_dir); @@ -210,7 +218,7 @@ site_build(struct site *site) if (!bstree_inorder_walk(site->albums->root, albums_walk, (void *)site)) { return false; } - /* TODO: static files and css */ + chdir(site->root_dir); return true; } |