Revision: 906 http://trac.macosforge.org/projects/darwinbuild/changeset/906 Author: wsiegrist@apple.com Date: 2010-11-03 15:55:58 -0700 (Wed, 03 Nov 2010) Log Message: ----------- Merged PR-8604911 Modified Paths: -------------- trunk/darwinup/Depot.cpp trunk/darwinup/File.cpp trunk/darwinup/File.h trunk/testing/darwinup/dest.tar.gz trunk/testing/darwinup/rep_file_dir.tar.gz trunk/testing/darwinup/rep_flink_dir.tar.gz trunk/testing/darwinup/rep_link_dir.tar.gz trunk/testing/darwinup/run-tests.sh Property Changed: ---------------- trunk/ Property changes on: trunk ___________________________________________________________________ Modified: svn:mergeinfo - /branches/PR-4841388:399-419 /branches/PR-6358021:442-443 /branches/PR-6392966:423-427 /branches/PR-6398060:433-434 /branches/PR-6493844:460-461 /branches/PR-6497694:466-468,471 /branches/PR-6634286:632-650 /branches/PR-6688645:479-490 /branches/PR-6722857:495-499 /branches/PR-6729491:655-664 /branches/PR-6973110:804-813 /branches/PR-7250612:635-650 /branches/PR-7341154:682-694 /branches/PR-7431723:660-664 /branches/PR-7461534:650-664 /branches/PR-7482850:670-671 /branches/PR-7489777:676-731 /branches/PR-7529688:692-694 /branches/PR-7593824:739-772 /branches/PR-7598640:703-731 /branches/PR-7748469:777-785 /branches/PR-7765119:790-791 /branches/PR-7798586:796-799 /branches/PR-7872907:830-840 /branches/PR-7935095:819-821 /branches/PR-8116613:849 /branches/PR-8279204:854-862 /branches/PR-8416637:870-880 /branches/PR-8486662:885-889 /branches/PR-8488185:894-898 + /branches/PR-4841388:399-419 /branches/PR-6358021:442-443 /branches/PR-6392966:423-427 /branches/PR-6398060:433-434 /branches/PR-6493844:460-461 /branches/PR-6497694:466-468,471 /branches/PR-6634286:632-650 /branches/PR-6688645:479-490 /branches/PR-6722857:495-499 /branches/PR-6729491:655-664 /branches/PR-6973110:804-813 /branches/PR-7250612:635-650 /branches/PR-7341154:682-694 /branches/PR-7431723:660-664 /branches/PR-7461534:650-664 /branches/PR-7482850:670-671 /branches/PR-7489777:676-731 /branches/PR-7529688:692-694 /branches/PR-7593824:739-772 /branches/PR-7598640:703-731 /branches/PR-7748469:777-785 /branches/PR-7765119:790-791 /branches/PR-7798586:796-799 /branches/PR-7872907:830-840 /branches/PR-7935095:819-821 /branches/PR-8116613:849 /branches/PR-8279204:854-862 /branches/PR-8416637:870-880 /branches/PR-8486662:885-889 /branches/PR-8488185:894-898 /branches/PR-8604911:903-905 Modified: trunk/darwinup/Depot.cpp =================================================================== --- trunk/darwinup/Depot.cpp 2010-11-01 20:40:42 UTC (rev 905) +++ trunk/darwinup/Depot.cpp 2010-11-03 22:55:58 UTC (rev 906) @@ -458,6 +458,32 @@ actual->info_set(FILE_INFO_ROLLBACK_DATA); file->info_set(FILE_INFO_INSTALL_DATA); } + // if actual is a dir and file is not, recurse to save its children + if (S_ISDIR(actual->mode()) && !S_ISDIR(file->mode())) { + IF_DEBUG("[analyze] directory being replaced by file, save children\n"); + const char* sub_argv[] = { actual->path(), NULL }; + FTS* subfts = fts_open((char**)sub_argv, + FTS_PHYSICAL | FTS_COMFOLLOW | FTS_XDEV, + fts_compare); + FTSENT* subent = fts_read(subfts); // throw away actual + while ((subent = fts_read(subfts)) != NULL) { + IF_DEBUG("saving child: %s\n", subent->fts_path); + // skip post-order visits + if (subent->fts_info == FTS_DP) { + continue; + } + File* subact = FileFactory(subent->fts_path); + subact->info_set(FILE_INFO_BASE_SYSTEM); + if (subent->fts_info != FTS_D) { + IF_DEBUG("saving file data\n"); + subact->info_set(FILE_INFO_ROLLBACK_DATA); + } + if (!dryrun) { + res = this->insert(rollback, subact); + } + *rollback_files += 1; + } + } preceding = actual; } @@ -527,41 +553,7 @@ IF_DEBUG("[analyze] external changes but file same as actual\n"); state = 'E'; } - - // XXX: should this be done in backup_file? - // If we're going to need to squirrel away data, create - // the directory hierarchy now. - if (INFO_TEST(actual->info(), FILE_INFO_ROLLBACK_DATA)) { - char path[PATH_MAX]; - char* backup_dirpath; - - // we need the path minus our destination prefix for moving to the archive - strlcpy(path, actual->path() + strlen(m_prefix) - 1, sizeof(path)); - - const char* dir = dirname(path); - assert(dir != NULL); - - char *uuidpath; - char uuidstr[37]; - uuid_unparse_upper(rollback->uuid(), uuidstr); - - asprintf(&uuidpath, "%s/%s", m_archives_path, uuidstr); - assert(uuidpath != NULL); - join_path(&backup_dirpath, uuidpath, dir); - assert(backup_dirpath != NULL); - - if (!dryrun) res = mkdir_p(backup_dirpath); - if (res != 0 && errno != EEXIST) { - fprintf(stderr, "%s:%d: %s: %s (%d)\n", - __FILE__, __LINE__, backup_dirpath, strerror(errno), errno); - } else { - res = 0; - } - free(backup_dirpath); - free(uuidpath); - } - - + if ((state != ' ' && preceding_flags != FILE_INFO_IDENTICAL) || INFO_TEST(actual->info(), FILE_INFO_BASE_SYSTEM | FILE_INFO_ROLLBACK_DATA)) { *rollback_files += 1; @@ -619,12 +611,42 @@ IF_DEBUG("[backup] backup_file: %s , %s \n", file->path(), context->archive->m_name); if (INFO_TEST(file->info(), FILE_INFO_ROLLBACK_DATA)) { - char *path; // the file's path + char *path; // the file's path char *dstpath; // the path inside the archives char *relpath; // the file's path minus the destination prefix char *uuidpath; // archives path plus the uuid char uuidstr[37]; + // If we're going to need to squirrel away data, create + // the directory hierarchy now. + char backup_path[PATH_MAX]; + char* backup_dirpath; + + // we need the path minus our destination prefix for moving to the archive + IF_DEBUG("[backup] file->path() = %s \n", file->path()); + strlcpy(backup_path, file->path(), sizeof(backup_path)); + IF_DEBUG("[backup] backup_path = %s \n", backup_path); + + const char* dir = dirname(backup_path); + assert(dir != NULL); + IF_DEBUG("[backup] dir = %s \n", dir); + + uuid_unparse_upper(context->archive->uuid(), uuidstr); + asprintf(&uuidpath, "%s/%s", context->depot->m_archives_path, uuidstr); + assert(uuidpath != NULL); + IF_DEBUG("[backup] uuidpath = %s \n", uuidpath); + join_path(&backup_dirpath, uuidpath, dir); + assert(backup_dirpath != NULL); + + IF_DEBUG("mkdir_p: %s\n", backup_dirpath); + res = mkdir_p(backup_dirpath); + if (res != 0 && errno != EEXIST) { + fprintf(stderr, "%s:%d: %s: %s (%d)\n", + __FILE__, __LINE__, backup_dirpath, strerror(errno), errno); + } else { + res = 0; + } + // we need the path minus our destination path for moving to the archive size_t prefixlen = strlen(context->depot->m_prefix); if (strncmp(context->archive->m_name, "<Rollback>", strlen("<Rollback>")) == 0) { @@ -637,17 +659,14 @@ relpath += prefixlen - 1; } - uuid_unparse_upper(context->archive->uuid(), uuidstr); - asprintf(&uuidpath, "%s/%s", context->depot->m_archives_path, uuidstr); - assert(uuidpath != NULL); join_path(&dstpath, uuidpath, relpath); assert(dstpath != NULL); IF_DEBUG("[backup] path = %s \n", path); IF_DEBUG("[backup] relpath = %s \n", relpath); IF_DEBUG("[backup] dstpath = %s \n", dstpath); - IF_DEBUG("[backup] uuidpath = %s \n", uuidpath); + ++context->files_modified; // XXX: res = file->backup() @@ -656,9 +675,14 @@ if (res != 0) fprintf(stderr, "%s:%d: backup failed: %s: %s (%d)\n", __FILE__, __LINE__, dstpath, strerror(errno), errno); + + // XXX: we cant propagate error from callback, but its safe to die here + assert(res == 0); + free(path); free(dstpath); free(uuidpath); + free(backup_dirpath); } return res; } @@ -919,8 +943,16 @@ state = 'U'; IF_DEBUG("[uninstall] restoring\n"); if (!dryrun && res == 0) { - res = preceding->install(context->depot->m_archives_path, - context->depot->m_prefix); + if (INFO_TEST(flags, FILE_INFO_TYPE_DIFFERS) && + S_ISDIR(preceding->mode())) { + // use rename instead of mkdir so children are restored + res = preceding->dirrename(context->depot->m_archives_path, + context->depot->m_prefix); + + } else { + res = preceding->install(context->depot->m_archives_path, + context->depot->m_prefix); + } } } else if (INFO_TEST(flags, FILE_INFO_MODE_DIFFERS) || INFO_TEST(flags, FILE_INFO_GID_DIFFERS) || Modified: trunk/darwinup/File.cpp =================================================================== --- trunk/darwinup/File.cpp 2010-11-01 20:40:42 UTC (rev 905) +++ trunk/darwinup/File.cpp 2010-11-03 22:55:58 UTC (rev 906) @@ -228,6 +228,11 @@ return res; } +int File::dirrename(const char* prefix, const char* dest) { + // only used for directories + assert(0); +} + int File::remove() { // not implemented fprintf(stderr, "%s:%d: call to abstract function File::remove\n", @@ -341,6 +346,14 @@ : File(serial, archive, info, path, mode, uid, gid, size, digest) {}; int Directory::install(const char* prefix, const char* dest) { + return this->_install(prefix, dest, false); +} + +int Directory::dirrename(const char* prefix, const char* dest) { + return this->_install(prefix, dest, true); +} + +int Directory::_install(const char* prefix, const char* dest, bool use_rename) { // We create a new directory instead of renaming the // existing one, since that would move the entire // sub-tree, and lead to a lot of ENOENT errors. @@ -352,12 +365,36 @@ mode_t mode = this->mode() & ALLPERMS; uid_t uid = this->uid(); gid_t gid = this->gid(); - - IF_DEBUG("[install] mkdir(%s, %04o)\n", dstpath, mode); - if (res == 0) res = mkdir(dstpath, mode); - // mkdir is limited by umask, so ensure mode is set - if (res == 0) res = chmod(dstpath, mode); + if (use_rename) { + // determine source path under archives directory for rename + char srcpath[PATH_MAX]; + const char* path = this->path(); + Archive* archive = this->archive(); + char* dirpath = archive->directory_name(prefix); + IF_DEBUG("[install] dirpath is %s\n", dirpath); + if (is_directory(dirpath) == 0) { + IF_DEBUG("[install] expanding archive for directory rename\n"); + res = archive->expand_directory(prefix); + } + if (res == 0 && dirpath) { + ssize_t len = snprintf(srcpath, sizeof(srcpath), "%s/%s", dirpath, path); + if ((size_t)len > sizeof(srcpath)) { + fprintf(stderr, "ERROR: [install] path too long: %s/%s\n", + dirpath, path); + return -1; + } + } + if (is_regular_file(dstpath)) unlink(dstpath); + if (res == 0) IF_DEBUG("[install] rename(%s, %s)\n", srcpath, dstpath); + if (res == 0) res = rename(srcpath, dstpath); + } else { + IF_DEBUG("[install] mkdir(%s, %04o)\n", dstpath, mode); + res = mkdir(dstpath, mode); + // mkdir is limited by umask, so ensure mode is set + if (res == 0) res = chmod(dstpath, mode); + } + if (res && errno == EEXIST) { if (is_directory(dstpath)) { // this is expected in normal cases, so no need to force Modified: trunk/darwinup/File.h =================================================================== --- trunk/darwinup/File.h 2010-11-01 20:40:42 UTC (rev 905) +++ trunk/darwinup/File.h 2010-11-03 22:55:58 UTC (rev 906) @@ -172,7 +172,9 @@ // Installs the file from the archive into the prefix // i.e., for regular files: // rename(prefix + this->archive()->uuid() + this->path(), dest + this->path()); - virtual int install(const char* prefix, const char* dest); + virtual int install(const char* prefix, const char* dest); + // only used for directories + virtual int dirrename(const char* prefix, const char* dest); // Sets the mode, uid, and gid of the file in the dest path // XXX: rename as repair()? @@ -242,6 +244,8 @@ Directory(Archive* archive, FTSENT* ent); Directory(uint64_t serial, Archive* archive, uint32_t info, const char* path, mode_t mode, uid_t uid, gid_t gid, off_t size, Digest* digest); virtual int install(const char* prefix, const char* dest); + virtual int dirrename(const char* prefix, const char* dest); + int _install(const char* prefix, const char* dest, bool use_rename); virtual int remove(); }; Modified: trunk/testing/darwinup/dest.tar.gz =================================================================== (Binary files differ) Modified: trunk/testing/darwinup/rep_file_dir.tar.gz =================================================================== (Binary files differ) Modified: trunk/testing/darwinup/rep_flink_dir.tar.gz =================================================================== (Binary files differ) Modified: trunk/testing/darwinup/rep_link_dir.tar.gz =================================================================== (Binary files differ) Modified: trunk/testing/darwinup/run-tests.sh =================================================================== --- trunk/testing/darwinup/run-tests.sh 2010-11-01 20:40:42 UTC (rev 905) +++ trunk/testing/darwinup/run-tests.sh 2010-11-03 22:55:58 UTC (rev 906) @@ -353,6 +353,9 @@ is_file $DEST/rep_file $DARWINUP -f install $PREFIX/rep_file_dir is_dir $DEST/rep_file +is_file $DEST/rep_file/subfile +is_dir $DEST/rep_file/subdir +is_file $DEST/rep_file/subdir/subsubfile $DARWINUP uninstall newest is_file $DEST/rep_file echo "DIFF: diffing original test files to dest (should be no diffs) ..." @@ -369,19 +372,31 @@ echo "========== TEST: Forcing object change: directory to file ==========" is_dir $DEST/rep_dir +is_file $DEST/rep_dir/subfile +is_dir $DEST/rep_dir/subdir +is_file $DEST/rep_dir/subdir/subsubfile $DARWINUP -f install $PREFIX/rep_dir_file is_file $DEST/rep_dir $DARWINUP uninstall newest is_dir $DEST/rep_dir +is_file $DEST/rep_dir/subfile +is_dir $DEST/rep_dir/subdir +is_file $DEST/rep_dir/subdir/subsubfile echo "DIFF: diffing original test files to dest (should be no diffs) ..." $DIFF $ORIG $DEST 2>&1 echo "========== TEST: Forcing object change: directory to symlink ==========" is_dir $DEST/rep_dir +is_file $DEST/rep_dir/subfile +is_dir $DEST/rep_dir/subdir +is_file $DEST/rep_dir/subdir/subsubfile $DARWINUP -f install $PREFIX/rep_dir_link is_link $DEST/rep_dir $DARWINUP uninstall newest is_dir $DEST/rep_dir +is_file $DEST/rep_dir/subfile +is_dir $DEST/rep_dir/subdir +is_file $DEST/rep_dir/subdir/subsubfile echo "DIFF: diffing original test files to dest (should be no diffs) ..." $DIFF $ORIG $DEST 2>&1 @@ -398,6 +413,9 @@ is_link $DEST/rep_link $DARWINUP -f install $PREFIX/rep_link_dir is_dir $DEST/rep_link +is_file $DEST/rep_link/anotherfile +is_dir $DEST/rep_link/anotherdir +is_file $DEST/rep_link/anotherdir/anothersubfile $DARWINUP uninstall newest is_link $DEST/rep_link echo "DIFF: diffing original test files to dest (should be no diffs) ..." @@ -416,6 +434,9 @@ is_link $DEST/rep_flink $DARWINUP -f install $PREFIX/rep_flink_dir is_dir $DEST/rep_flink +is_file $DEST/rep_flink/subfile +is_dir $DEST/rep_flink/subdir +is_file $DEST/rep_flink/subdir/subsubfile $DARWINUP uninstall newest is_link $DEST/rep_flink echo "DIFF: diffing original test files to dest (should be no diffs) ..."
participants (1)
-
source_changes@macosforge.org