update uwproj
[mizunara.git] / mizucp / main.c
index 18aaf5a..f590dc7 100644 (file)
 #include "main.h"
 
 #include "srvctrl.h"
+#include "atomic.h"
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 #include <signal.h>
@@ -61,6 +63,13 @@ static MZQueue         *queue_end;
 
 static int scan_complete;
 
+
+static uint64_t stat_num_files;
+static uint64_t stat_copied_files;
+static uint64_t stat_error_files;
+static uint64_t stat_total_size;
+static uint64_t stat_copied_size;
+
 int main(int argc, char** argv) { 
     int ret = 1;
     
@@ -215,13 +224,12 @@ int mzcp_copy(CPSettings *settings) {
 
 
 int mzcp_start_scan(CPSettings *settings) {
-    struct stat s;
-    if(stat(settings->from, &s)) {
+    if(stat(settings->from, &settings->root_stat)) {
         // TODO: error
         return 1;
     }
     
-    if(!S_ISDIR(s.st_mode)) {
+    if(!S_ISDIR(settings->root_stat.st_mode)) {
         // queue single file
         queue_begin = queue_root_elm_new();
         if(!queue_begin) {
@@ -259,6 +267,7 @@ void* scan_run(void *data) {
     }
     file->path = root;
     file->isdir = 1;
+    file->mode = settings->root_stat.st_mode;
     if(enqueue_file(file)) {
         scan_complete = 1;
         // TODO: error
@@ -298,12 +307,18 @@ void* scan_run(void *data) {
             SrcFile *f = calloc(1, sizeof(SrcFile));
             f->path = util_concat_path(elm->path, name);
             f->isdir = S_ISDIR(s.st_mode);
+            f->size = s.st_size;
+            f->mode = s.st_mode;
             f->depends_on = elm;
             
             if(enqueue_file(f)) {
                 // TODO: error?
                 fprintf(stderr, "enqueue failed\n");
                 break;
+            } else {
+                mz_atomic_inc64(&stat_num_files);
+                int64_t sz = s.st_size;
+                mz_atomic_add64(&stat_total_size, sz);
             }
             
             // put dir on stack
@@ -399,17 +414,60 @@ static SrcFile* queue_get_file(void) {
 
 void* copy_run(void *data) {
     CPSettings *settings = data;
+    
+    char *buffer = malloc(MZ_COPY_BUFSIZE);
+    size_t bufsize = MZ_COPY_BUFSIZE;
+    
     for(;;) {
         SrcFile *file = queue_get_file();
         if(!file) {
             break;
         }
         
-        char *from = file->path ? util_concat_path(settings->from, file->path) : settings->from;
-        printf("src: %s\n", from);
-        
+        char *from = file->path ? util_concat_path(settings->from, file->path) : settings->from;  
         char *to = util_concat_path(settings->to, file->path ? file->path : util_resource_name(settings->from));
-        printf("dst: %s\n", to);
+        
+        size_t from_len = strlen(from);
+        size_t to_len = strlen(to);
+        
+        if(from[from_len-1] == '/') {
+            from[from_len-1] = 0;
+        }
+        if(to[to_len-1] == '/') {
+            to[to_len-1] = 0;
+        }
+        
+        if(file->depends_on) {
+            SrcFile *dep = file->depends_on;
+            // check first without lock
+            if(dep->status == 0) {
+                if(dep->lock) {
+                    pthread_mutex_lock(&dep->lock->mutex);
+                    if(file->depends_on->status == 0) {
+                        pthread_cond_wait(&dep->lock->cond, &dep->lock->mutex);
+                    }
+                    pthread_mutex_unlock(&dep->lock->mutex);
+                } else {
+                    // locking disabled (because we have only one thread)
+                    // but in that case the file status can't be 0
+                    // therefore this case here should not happen
+                    file->status = -1;
+                }
+            }
+            // check again
+            if(dep->status == -1) {
+                file->status = -1;
+            }
+        }
+        
+        int ret;
+        if(file->status == 0) {
+            if(file->isdir) {
+            ret = mz_copy_dir(settings, file, from, to);
+            } else {
+                ret = mz_copy_file(settings, file, from, to, buffer, bufsize);
+            }
+        }
         
         free(to);
         if(from != settings->from) {
@@ -420,3 +478,86 @@ void* copy_run(void *data) {
     return NULL;
 }
 
+static void file_set_status(SrcFile *file, int status) {
+    if(file->lock) {
+        pthread_mutex_lock(&file->lock->mutex);
+        file->status = status;
+        pthread_cond_broadcast(&file->lock->cond);
+        pthread_mutex_unlock(&file->lock->mutex);
+    } else {
+        file->status = status;
+    }
+}
+
+int mz_copy_dir(CPSettings *settings, SrcFile *file, const char *from, const char *to) {
+    printf("mkdir %s\n", to);
+    int ret = mkdir(to, file->mode);
+    if(ret) {
+        if(errno == EEXIST) {
+            struct stat s;
+            if(!stat(to, &s)) {
+                if(S_ISDIR(s.st_mode)) {
+                    ret = 0;
+                }
+            }
+        }
+    }
+    file_set_status(file, !ret ? 1 : -1);
+    return ret;
+}
+
+int mz_copy_file(CPSettings *settings, SrcFile *file, const char *from, const char *to, char *buffer, size_t bufsize) {
+    printf("cp %s %s\n", from, to);
+    int fin = open(from, O_RDONLY);
+    if(fin < 0) {
+        file_set_status(file, -1);
+        return 1;
+    }
+    
+    int ret = 0;
+    
+    int fout = open(to, O_WRONLY|O_CREAT, file->mode);
+    if(fout < 0) {
+        perror("open");
+        close(fin);
+        file_set_status(file, -1);
+        return 1;
+    }
+    
+    int64_t copied = 0;
+    ssize_t r;
+    while((r = read(fin, buffer, bufsize)) > 0) {
+        ssize_t w = write(fout, buffer, r);
+        if(w > 0) {
+            mz_atomic_add64(&stat_copied_size, w);
+            copied += w;
+        }
+        if(w != r) {
+            ret = 1;
+            break;
+        }
+    }
+    
+    close(fin);
+    close(fout);
+    
+    if(!ret) {
+        file_set_status(file, 1);
+        mz_atomic_inc64(&stat_copied_files);
+        if(copied != file->size) {
+            // size changed after scan -> readjust total size
+            int64_t filesz_diff = copied - file->size;
+            mz_atomic_add64(&stat_total_size, filesz_diff);
+        }
+    } else {
+        file_set_status(file, -1);
+        mz_atomic_inc64(&stat_error_files);
+        if(copied != file->size) {
+            // count the full file size as copied, although we had an error
+            int64_t filesz_diff = file->size - copied;
+            mz_atomic_add64(&stat_copied_size, filesz_diff);
+        }
+    }
+    
+    return ret;
+}