From e2a71b0366aa80a7cf131fdbde6012671493d364 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaroslav=20de=20la=20Pe=C3=B1a=20Smirnov?= Date: Tue, 9 Nov 2021 20:47:16 +0300 Subject: Copy/sync static files --- src/fs.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) (limited to 'src/fs.c') diff --git a/src/fs.c b/src/fs.c index e4a6d7b..a1b5626 100644 --- a/src/fs.c +++ b/src/fs.c @@ -6,12 +6,19 @@ #include #include #include +#include #include #include #include +#include #include #include #include +#ifdef __linux__ +#include +#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; +} -- cgit v1.2.3