/* Helper function to copy data between archives. */ static int copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) { ssize_t bytes_read; ssize_t bytes_written; off_t progress = 0; bytes_read = archive_read_data(ina, bsdtar->buff, FILEDATABUFLEN); while (bytes_read > 0) { disk_pause(bsdtar); if (network_select(0)) return (-1); siginfo_printinfo(bsdtar, progress); bytes_written = archive_write_data(a, bsdtar->buff, bytes_read); if (bytes_written < bytes_read) { bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); return (-1); } if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 1)) return (-1); progress += bytes_written; bytes_read = archive_read_data(ina, bsdtar->buff, FILEDATABUFLEN); } return (0); }
/* Helper function to copy file to archive. */ static int write_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive_entry *entry, int fd) { ssize_t bytes_read; ssize_t bytes_written; off_t progress = 0; bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN); while (bytes_read > 0) { disk_pause(bsdtar); if (network_select(0)) return (-1); siginfo_printinfo(bsdtar, progress); bytes_written = archive_write_data(a, bsdtar->buff, bytes_read); if (bytes_written < 0) { /* Write failed; this is bad */ bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); return (-1); } if (bytes_written < bytes_read) { /* Write was truncated; warn but continue. */ if (!bsdtar->option_quiet) bsdtar_warnc(bsdtar, 0, "%s: Truncated write; file may have " "grown while being archived.", archive_entry_pathname(entry)); return (0); } if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 1)) exit(1); progress += bytes_written; bytes_read = read(fd, bsdtar->buff, FILEDATABUFLEN); } return 0; }
void NetworkWorker::run() { while (true) { { Glib::Threads::Mutex::Lock lock(m_mutex); if (m_network.disconnected) break; network_set_fds(&m_network); m_network.tv.tv_sec = 1; m_network.tv.tv_usec = 0; } network_select(&m_network); { Glib::Threads::Mutex::Lock lock(m_mutex); network_recv(&m_network); network_send(&m_network); m_stop = m_network.disconnected; if (m_network.has_data_in) { std::string data(m_network.buf_in); m_network.buf_in[0] = 0; m_network.has_data_in = FALSE; int pos; while ((pos = data.find("\r\n")) != std::string::npos) { m_in_data.push(data.substr(0, pos)); data = data.substr(pos + 2); } strcpy(m_network.buf_in, data.c_str()); strcat(m_network.buf_in, "\0"); if (strlen(m_network.buf_in) > 0) m_network.has_data_in = TRUE; } } { Glib::Threads::Mutex::Lock lock(m_mutex); m_dispatcher.emit(); } } }
/* * Add the file or dir hierarchy named by 'path' to the archive */ static void write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) { struct archive_entry *entry = NULL, *spare_entry = NULL; struct tree *tree; char symlink_mode = bsdtar->symlink_mode; dev_t first_dev = 0; int dev_recorded = 0; int tree_ret; dev_t last_dev = 0; char * fstype; tree = tree_open(path); if (!tree) { bsdtar_warnc(bsdtar, errno, "%s: Cannot open", path); bsdtar->return_value = 1; return; } while ((tree_ret = tree_next(tree))) { int r; const char *name = tree_current_path(tree); const struct stat *st = NULL; /* info to use for this entry */ const struct stat *lst = NULL; /* lstat() information */ int descend; if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 0)) exit(1); disk_pause(bsdtar); if (network_select(0)) exit(1); if (tree_ret == TREE_ERROR_FATAL) bsdtar_errc(bsdtar, 1, tree_errno(tree), "%s: Unable to continue traversing directory tree", name); if (tree_ret == TREE_ERROR_DIR) { bsdtar_warnc(bsdtar, errno, "%s: Couldn't visit directory", name); bsdtar->return_value = 1; } if (tree_ret != TREE_REGULAR) continue; /* * If this file/dir is excluded by a filename * pattern, skip it. */ if (excluded(bsdtar, name)) continue; /* * Get lstat() info from the tree library. */ lst = tree_current_lstat(tree); if (lst == NULL) { /* Couldn't lstat(); must not exist. */ bsdtar_warnc(bsdtar, errno, "%s: Cannot stat", name); /* Return error if files disappear during traverse. */ bsdtar->return_value = 1; continue; } /* * Distinguish 'L'/'P'/'H' symlink following. */ switch(symlink_mode) { case 'H': /* 'H': After the first item, rest like 'P'. */ symlink_mode = 'P'; /* 'H': First item (from command line) like 'L'. */ /* FALLTHROUGH */ case 'L': /* 'L': Do descend through a symlink to dir. */ descend = tree_current_is_dir(tree); /* 'L': Follow symlinks to files. */ archive_read_disk_set_symlink_logical(bsdtar->diskreader); /* 'L': Archive symlinks as targets, if we can. */ st = tree_current_stat(tree); if (st != NULL) break; /* If stat fails, we have a broken symlink; * in that case, don't follow the link. */ /* FALLTHROUGH */ default: /* 'P': Don't descend through a symlink to dir. */ descend = tree_current_is_physical_dir(tree); /* 'P': Don't follow symlinks to files. */ archive_read_disk_set_symlink_physical(bsdtar->diskreader); /* 'P': Archive symlinks as symlinks. */ st = lst; break; } if (bsdtar->option_no_subdirs) descend = 0; /* * If user has asked us not to cross mount points, * then don't descend into a dir on a different * device. */ if (!dev_recorded) { last_dev = first_dev = lst->st_dev; dev_recorded = 1; } if (bsdtar->option_dont_traverse_mounts) { if (lst->st_dev != first_dev) descend = 0; } /* * If the user did not specify --insane-filesystems, do not * cross into a new filesystem which is known to be synthetic. * Note that we will archive synthetic filesystems if we are * explicitly told to do so. */ if ((bsdtar->option_insane_filesystems == 0) && (descend != 0) && (lst->st_dev != last_dev)) { fstype = getfstype(tree_current_access_path(tree)); if (fstype == NULL) bsdtar_errc(bsdtar, 1, errno, "%s: Error getting filesystem type", name); if (getfstype_issynthetic(fstype)) { if (!bsdtar->option_quiet) bsdtar_warnc(bsdtar, 0, "Not descending into filesystem of type %s: %s", fstype, name); descend = 0; } else { /* This device is ok to archive. */ last_dev = lst->st_dev; } free(fstype); } /* * In -u mode, check that the file is newer than what's * already in the archive; in all modes, obey --newerXXX flags. */ if (!new_enough(bsdtar, name, st)) { if (!descend) continue; if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; tree_descend(tree); continue; } archive_entry_free(entry); entry = archive_entry_new(); archive_entry_set_pathname(entry, name); archive_entry_copy_sourcepath(entry, tree_current_access_path(tree)); /* Populate the archive_entry with metadata from the disk. */ /* XXX TODO: Arrange to open a regular file before * calling this so we can pass in an fd and shorten * the race to query metadata. The linkify dance * makes this more complex than it might sound. */ r = archive_read_disk_entry_from_file(bsdtar->diskreader, entry, -1, st); if (r != ARCHIVE_OK) bsdtar_warnc(bsdtar, archive_errno(bsdtar->diskreader), "%s", archive_error_string(bsdtar->diskreader)); if (r < ARCHIVE_WARN) continue; /* XXX TODO: Just use flag data from entry; avoid the * duplicate check here. */ /* * If this file/dir is flagged "nodump" and we're * honoring such flags, skip this file/dir. */ #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) /* BSD systems store flags in struct stat */ if (bsdtar->option_honor_nodump && (lst->st_flags & UF_NODUMP)) continue; #endif #if defined(EXT2_NODUMP_FL) /* Linux uses ioctl to read flags. */ if (bsdtar->option_honor_nodump) { unsigned long fflags, dummy; archive_entry_fflags(entry, &fflags, &dummy); if (fflags & EXT2_NODUMP_FL) continue; } #endif /* * Don't back up the cache directory or any files inside it. */ if ((lst->st_ino == bsdtar->cachedir_ino) && (lst->st_dev == bsdtar->cachedir_dev)) { if (!bsdtar->option_quiet) bsdtar_warnc(bsdtar, 0, "Not adding cache directory to archive: %s", name); continue; } /* * If the user vetoes this file/directory, skip it. * We want this to be fairly late; if some other * check would veto this file, we shouldn't bother * the user with it. */ if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; /* Note: if user vetoes, we won't descend. */ if (descend) tree_descend(tree); /* * Rewrite the pathname to be archived. If rewrite * fails, skip the entry. */ if (edit_pathname(bsdtar, entry)) continue; /* * If this is a socket, skip the entry: POSIX requires that * pax(1) emit a "diagnostic message" (i.e., warning) that * sockets cannot be archived, but this can make backups of * running systems very noisy. */ if (S_ISSOCK(st->st_mode)) continue; /* Display entry as we process it. * This format is required by SUSv2. */ if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(entry)); /* * If the user hasn't specifically asked to have the access * time stored, zero it. At the moment this usually only * matters for files which have flags set, since the "posix * restricted" format doesn't store access times for most * other files. */ if (bsdtar->option_store_atime == 0) archive_entry_set_atime(entry, 0, 0); /* Non-regular files get archived with zero size. */ if (!S_ISREG(st->st_mode)) archive_entry_set_size(entry, 0); /* Record what we're doing, for SIGINFO / SIGUSR1. */ siginfo_setinfo(bsdtar, "adding", archive_entry_pathname(entry), archive_entry_size(entry)); archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); /* Handle SIGINFO / SIGUSR1 request if one was made. */ siginfo_printinfo(bsdtar, 0); while (entry != NULL) { write_entry_backend(bsdtar, a, entry, st, tree_current_realpath(tree)); archive_entry_free(entry); entry = spare_entry; spare_entry = NULL; } if (bsdtar->verbose) fprintf(stderr, "\n"); } archive_entry_free(entry); if (tree_close(tree)) bsdtar_errc(bsdtar, 1, 0, "Error traversing directory tree"); }
static int append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina, void * cookie) { struct archive_entry *in_entry; int e; while (0 == archive_read_next_header(ina, &in_entry)) { if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 0)) exit(1); if (cookie == NULL) disk_pause(bsdtar); if (network_select(0)) exit(1); if (!new_enough(bsdtar, archive_entry_pathname(in_entry), archive_entry_stat(in_entry))) continue; if (excluded(bsdtar, archive_entry_pathname(in_entry))) continue; if (bsdtar->option_interactive && !yes("copy '%s'", archive_entry_pathname(in_entry))) continue; if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(in_entry)); siginfo_setinfo(bsdtar, "copying", archive_entry_pathname(in_entry), archive_entry_size(in_entry)); siginfo_printinfo(bsdtar, 0); if (MODE_HEADER(bsdtar, a)) goto err_fatal; e = archive_write_header(a, in_entry); if (e != ARCHIVE_OK) { if (!bsdtar->verbose) bsdtar_warnc(bsdtar, 0, "%s: %s", archive_entry_pathname(in_entry), archive_error_string(a)); else fprintf(stderr, ": %s", archive_error_string(a)); } if (e == ARCHIVE_FATAL) exit(1); if (e < ARCHIVE_WARN) goto done; if (MODE_DATA(bsdtar, a)) goto err_fatal; if (archive_entry_size(in_entry) == 0) archive_read_data_skip(ina); else if (cookie == NULL) { if (copy_file_data(bsdtar, a, ina)) exit(1); } else { switch (archive_multitape_copy(ina, cookie, a, bsdtar->write_cookie)) { case -1: goto err_fatal; case -2: goto err_read; } } done: if (MODE_DONE(bsdtar, a)) goto err_fatal; if (bsdtar->verbose) fprintf(stderr, "\n"); continue; err_read: bsdtar->return_value = 1; if (MODE_DONE(bsdtar, a)) goto err_fatal; if (bsdtar->verbose) fprintf(stderr, "\n"); break; err_fatal: bsdtar_warnc(bsdtar, archive_errno(a), "%s", archive_error_string(a)); exit(1); } /* Note: If we got here, we saw no write errors, so return success. */ return (0); }