+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;
+}