43 char const **char_a = (
char const **)a;
44 char const **char_b = (
char const **)b;
46 return strcmp(*char_a, *char_b);
49 namespace shrinkwrap {
66 , dest(strdup(dest)) {}
69 return ((src == NULL) && (dest == NULL));
84 , recursive(recursive) {}
99 pthread_mutex_t
lock_pipe = PTHREAD_MUTEX_INITIALIZER;
110 if (!strcmp(type,
"posix")) {
112 }
else if (!strcmp(type,
"cvmfs")) {
116 "Unknown File System Interface : %s", type);
122 if (!src) {
return false; }
123 if (!dest) {
return false; }
125 if (src->
size != dest->
size) {
return false; }
162 const char *src_name,
164 const char *dest_name,
169 size_t bytes_transferred = 0;
178 "Failed open src : %s : %d : %s\n",
179 src_name, errno, strerror(errno));
187 "Failed open dest : %s : %d : %s\n",
188 dest_name, errno, strerror(errno));
196 size_t actual_read = 0;
197 retval = src_fs->
do_fread(src, buffer,
sizeof(buffer), &actual_read);
200 "Read failed : %d %s\n", errno, strerror(errno));
204 bytes_transferred+=actual_read;
206 retval = dest_fs->
do_fwrite(dest, buffer, actual_read);
209 "Write failed : %d %s\n", errno, strerror(errno));
224 "Failed close src : %s : %d : %s\n",
225 src_name, errno, strerror(errno));
233 "Failed close dest : %s : %d : %s\n",
234 dest_name, errno, strerror(errno));
249 size_t len = 2 + strlen(dir)+ strlen(entry);
250 char * path =
reinterpret_cast<char *
>(smalloc(len));
251 snprintf(path, len,
"%s/%s", dir, entry);
284 location = (*iter)+1;
291 if (dir_list && dir_list[location]) {
294 return getNext(fs, dir, dir_list, entry, iter,
295 st, get_hash, is_src, pstats);
297 if (entry && !
updateStat(fs, *entry, st, get_hash)) {
298 return getNext(fs, dir, dir_list, entry, iter,
299 st, get_hash, is_src, pstats);
306 switch ((*st)->st_mode & S_IFMT) {
354 FileCopy next_copy(src_ident, dest_data);
359 if (!
copyFile(src, src_ident, dest, dest_data, pstats)) {
361 "Failed to copy %s->%s : %d : %s",
362 entry, dest_data, errno, strerror(errno));
378 "Failed to link %s->%s : %d : %s",
379 entry, dest_data, errno, strerror(errno));
395 if (errno == EEXIST) {
399 "Traversal failed to set_meta %s", entry);
404 "Traversal failed to mkdir %s : %d : %s",
405 entry, errno, strerror(errno));
413 dirs_.push_back(
new RecDir(dir, recursive));
426 return strcmp(src, dest);
439 char **src_dir = NULL;
441 ssize_t src_iter = -1;
442 char * src_entry = NULL;
446 char **dest_dir = NULL;
448 ssize_t dest_iter = -1;
449 char * dest_entry = NULL;
452 qsort(dest_dir, dest_len,
sizeof(
char *),
strcmp_list);
457 getNext(src, dir, src_dir, &src_entry, &src_iter,
458 &src_st,
true,
true, pstats);
461 getNext(dest, dir, dest_dir, &dest_entry, &dest_iter,
462 &dest_st,
false,
false, pstats);
469 if (!src_entry && !dest_entry)
487 switch (src_st->
st_mode & S_IFMT) {
489 if (!
handle_file(src, src_st, dest, dest_st, src_entry, pstats))
493 if (!
handle_dir(src, src_st, dest, dest_st, src_entry))
495 if (result && recursive)
503 "Traversal failed to symlink %s->%s : %d : %s",
504 src_entry, src_st->
cvm_symlink, errno, strerror(errno));
516 "Encountered unknown file type '%d' for source file %s",
523 switch (dest_st->
st_mode & S_IFMT) {
528 "Failed to unlink file %s", dest_entry);
537 if (!
Sync(dest_entry, src, dest,
true, pstats)) {
543 "Failed to remove directory %s", dest_entry);
549 "Encountered unknown file type '%d' for destination file %s",
574 uint64_t last_print_time) {
576 dirs_.push_back(
new RecDir(
"",
true));
578 while (!
dirs_.empty()) {
579 RecDir *next_dir =
dirs_.back();
582 if (!
Sync(next_dir->dir, src, dest, next_dir->recursive, pstats)) {
584 "File %s failed to copy\n", next_dir->dir);
625 if (next_copy.IsTerminateJob())
628 if (!next_copy.src || !next_copy.dest) {
632 next_copy.dest, mwc->
pstats)) {
634 "File %s failed to copy\n", next_copy.src);
636 files_transferred->
Inc();
641 free(next_copy.dest);
651 "Number of files from source repository");
653 "Number of directories from source repository");
655 "Number of symlinks from source repository");
657 "Byte count of projected repository");
659 "Number of file system entries processed in the source");
661 "Number of file system entries processed in the destination");
663 "Number of data files transferred from source to destination");
665 "Bytes transferred from source to destination");
667 "Number of files not copied due to deduplication");
669 "Number of bytes not copied due to deduplication");
679 uint64_t stat_period) {
688 pthread_t *workers = NULL;
696 reinterpret_cast<pthread_t *
>(smalloc(
sizeof(pthread_t) *
num_parallel_));
698 specificWorkerContexts =
712 specificWorkerContexts[i].
mwc = mwc;
714 int retval = pthread_create(&workers[i], NULL,
MainWorker,
715 static_cast<void*>(&(specificWorkerContexts[i])));
725 uint64_t last_print_time = 0;
727 int result = !
SyncFull(src, dest, pstats, last_print_time);
744 FileCopy terminate_workers;
748 int retval = pthread_join(workers[i], NULL);
753 delete specificWorkerContexts;
768 "Performing garbage collection...");
773 (end_time-start_time));
Counter * Register(const std::string &name, const std::string &desc)
bool SyncFull(struct fs_traversal *src, struct fs_traversal *dest, perf::Statistics *pstats, uint64_t last_print_time)
struct fs_traversal * FindInterface(const char *type)
int(* do_fopen)(void *file_ctx, fs_open_type op_mode)
#define SHRINKWRAP_STAT_DATA_BYTES_DEDUPED
bool cvmfs_attr_cmp(struct cvmfs_attr *src, struct cvmfs_attr *dest, struct fs_traversal *dest_fs)
void list_src_dir(struct fs_traversal *src, const char *dir, char ***buf, size_t *len)
#define SHRINKWRAP_STAT_COUNT_FILE
void cvmfs_attr_free(struct cvmfs_attr *attr)
bool getNext(struct fs_traversal *fs, const char *dir, char **dir_list, char **entry, ssize_t *iter, struct cvmfs_attr **st, bool get_hash, bool is_src, perf::Statistics *pstats)
#define SHRINKWRAP_STAT_DATA_FILES
static void * MainWorker(void *data)
int(* set_meta)(struct fs_traversal_context *ctx, const char *path, const struct cvmfs_attr *stat)
bool(* is_hash_consistent)(struct fs_traversal_context *ctx, const struct cvmfs_attr *stat)
static SpecTree * Create(const std::string &path)
#define SHRINKWRAP_STAT_COUNT_SYMLINK
FileCopy(char *src, char *dest)
pthread_mutex_t lock_pipe
struct fs_traversal * posix_get_interface()
struct fs_traversal * libcvmfs_get_interface()
#define SHRINKWRAP_STAT_COUNT_DIR
assert((mem||(size==0))&&"Out Of Memory")
int(* do_unlink)(struct fs_traversal_context *ctx, const char *path)
bool handle_file(struct fs_traversal *src, struct cvmfs_attr *src_st, struct fs_traversal *dest, struct cvmfs_attr *dest_st, const char *entry, perf::Statistics *pstats)
int(* garbage_collector)(struct fs_traversal_context *ctx)
int strcmp_list(const void *a, const void *b)
bool IsTerminateJob() const
struct fs_traversal * dest_fs
int(* do_rmdir)(struct fs_traversal_context *ctx, const char *path)
void MakePipe(int pipe_fd[2])
void *(* get_handle)(struct fs_traversal_context *ctx, const char *identifier)
#define SHRINKWRAP_STAT_DATA_BYTES
perf::Statistics * GetSyncStatTemplate()
void(* do_ffree)(void *file_ctx)
int SyncInit(struct fs_traversal *src, struct fs_traversal *dest, const char *base, const char *spec, uint64_t parallel, uint64_t stat_period)
uint64_t stat_update_period_
void cvmfs_list_free(char **buf)
Counter * Lookup(const std::string &name) const
int(* touch)(struct fs_traversal_context *ctx, const struct cvmfs_attr *stat)
int(* do_symlink)(struct fs_traversal_context *ctx, const char *src, const char *dest, const struct cvmfs_attr *stat_info)
struct fs_traversal * src_fs
perf::Statistics * pstats
int(* do_link)(struct fs_traversal_context *ctx, const char *path, const char *identifier)
void(* list_dir)(struct fs_traversal_context *ctx, const char *dir, char ***buf, size_t *len)
#define SHRINKWRAP_STAT_ENTRIES_SRC
bool updateStat(struct fs_traversal *fs, const char *entry, struct cvmfs_attr **st, bool get_hash)
void add_dir_for_sync(const char *dir, bool recursive)
int robust_strcmp(const char *src, const char *dest)
int(* do_fclose)(void *file_ctx)
int(* get_stat)(struct fs_traversal_context *ctx, const char *path, struct cvmfs_attr *stat, bool get_hash)
int64_t Xadd(const int64_t delta)
#define SHRINKWRAP_STAT_ENTRIES_DEST
int(* do_fwrite)(void *file_ctx, const char *buff, size_t len)
bool copyFile(struct fs_traversal *src_fs, const char *src_name, struct fs_traversal *dest_fs, const char *dest_name, perf::Statistics *pstats)
std::string PrintList(const PrintOptions print_options)
int(* do_fread)(void *file_ctx, char *buff, size_t len, size_t *read_len)
void SafeSleepMs(const unsigned ms)
int(* do_mkdir)(struct fs_traversal_context *ctx, const char *path, const struct cvmfs_attr *stat)
RecDir(const char *dir, bool recursive)
bool IsMatching(std::string path)
#define SHRINKWRAP_STAT_DATA_FILES_DEDUPED
int ListDir(const char *dir, char ***buf, size_t *len)
char *(* get_identifier)(struct fs_traversal_context *ctx, const struct cvmfs_attr *stat)
char * get_full_path(const char *dir, const char *entry)
struct MainWorkerContext * mwc
void WritePipe(int fd, const void *buf, size_t nbyte)
void ReadPipe(int fd, void *buf, size_t nbyte)
void ClosePipe(int pipe_fd[2])
struct cvmfs_attr * cvmfs_attr_init()
bool handle_dir(struct fs_traversal *src, struct cvmfs_attr *src_st, struct fs_traversal *dest, struct cvmfs_attr *dest_st, const char *entry)
#define SHRINKWRAP_STAT_COUNT_BYTE
struct fs_traversal_context * context_
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)