зеркало из https://github.com/mozilla/gecko-dev.git
Bug 764269 - Handle symbolic links properly when copying the installation directory before staging an update; r=rstrong
This commit is contained in:
Родитель
4ef5db6e16
Коммит
d62f8e7c8a
|
@ -48,6 +48,7 @@
|
|||
# define NS_ttoi atoi
|
||||
# define NS_tstat stat
|
||||
# define NS_tgetcwd getcwd
|
||||
# define NS_tfputs fputs
|
||||
# define LOG_S "%s"
|
||||
#endif
|
||||
|
||||
|
@ -171,6 +172,9 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
"Usage: WORKINGDIR INFILE OUTFILE -s SECONDS [FILETOLOCK]\n" \
|
||||
" or: WORKINGDIR LOGFILE [ARG2 ARG3...]\n" \
|
||||
" or: signature-check filepath\n" \
|
||||
" or: setup-symlink dir1 dir2 file symlink\n" \
|
||||
" or: remove-symlink dir1 dir2 file symlink\n" \
|
||||
" or: check-symlink symlink\n" \
|
||||
"\n" \
|
||||
" WORKINGDIR \tThe relative path to the working directory to use.\n" \
|
||||
" INFILE \tThe relative path from the working directory for the file to\n" \
|
||||
|
@ -205,6 +209,68 @@ int NS_main(int argc, NS_tchar **argv)
|
|||
#endif
|
||||
}
|
||||
|
||||
if (!NS_tstrcmp(argv[1], NS_T("setup-symlink"))) {
|
||||
#ifdef XP_UNIX
|
||||
NS_tchar path[MAXPATHLEN];
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
|
||||
mkdir(path, 0755);
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]);
|
||||
mkdir(path, 0755);
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]);
|
||||
FILE * file = NS_tfopen(path, NS_T("w"));
|
||||
if (file) {
|
||||
NS_tfputs(NS_T("test"), file);
|
||||
fclose(file);
|
||||
}
|
||||
symlink(path, argv[5]);
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
|
||||
if (argc > 6 && !NS_tstrcmp(argv[6], NS_T("change-perm"))) {
|
||||
chmod(path, 0644);
|
||||
}
|
||||
return 0;
|
||||
#else
|
||||
// Not implemented on non-Unix platforms
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!NS_tstrcmp(argv[1], NS_T("remove-symlink"))) {
|
||||
#ifdef XP_UNIX
|
||||
NS_tchar path[MAXPATHLEN];
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
|
||||
chmod(path, 0755);
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]);
|
||||
unlink(path);
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]);
|
||||
rmdir(path);
|
||||
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
|
||||
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
|
||||
rmdir(path);
|
||||
return 0;
|
||||
#else
|
||||
// Not implemented on non-Unix platforms
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!NS_tstrcmp(argv[1], NS_T("check-symlink"))) {
|
||||
#ifdef XP_UNIX
|
||||
struct stat ss;
|
||||
lstat(argv[2], &ss);
|
||||
return S_ISLNK(ss.st_mode) ? 0 : 1;
|
||||
#else
|
||||
// Not implemented on non-Unix platforms
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!NS_tstrcmp(argv[1], NS_T("wait-for-service-stop"))) {
|
||||
#ifdef XP_WIN
|
||||
const int maxWaitSeconds = NS_ttoi(argv[3]);
|
||||
|
|
|
@ -14,7 +14,7 @@ const MAX_TIME_DIFFERENCE = 60000;
|
|||
// The files are listed in the same order as they are applied from the mar's
|
||||
// update.manifest. Complete updates have remove file and rmdir directory
|
||||
// operations located in the precomplete file performed first.
|
||||
const TEST_FILES = [
|
||||
var TEST_FILES = [
|
||||
{
|
||||
description : "Should never change",
|
||||
fileName : "channel-prefs.js",
|
||||
|
@ -234,6 +234,39 @@ ADDITIONAL_TEST_DIRS = [
|
|||
dirRemoved : true
|
||||
}];
|
||||
|
||||
function runHelperProcess(args) {
|
||||
let helperBin = do_get_file(HELPER_BIN_FILE);
|
||||
let process = AUS_Cc["@mozilla.org/process/util;1"].
|
||||
createInstance(AUS_Ci.nsIProcess);
|
||||
process.init(helperBin);
|
||||
logTestInfo("Running " + helperBin.path + " " + args.join(" "));
|
||||
process.run(true, args, args.length);
|
||||
do_check_eq(process.exitValue, 0);
|
||||
}
|
||||
|
||||
function createSymlink() {
|
||||
let args = ["setup-symlink", "moz-foo", "moz-bar", "target",
|
||||
getApplyDirFile().path + "/a/b/link"];
|
||||
runHelperProcess(args);
|
||||
args = ["setup-symlink", "moz-foo2", "moz-bar2", "target2",
|
||||
getApplyDirFile().path + "/a/b/link2", "change-perm"];
|
||||
runHelperProcess(args);
|
||||
}
|
||||
|
||||
function removeSymlink() {
|
||||
let args = ["remove-symlink", "moz-foo", "moz-bar", "target",
|
||||
getApplyDirFile().path + "/a/b/link"];
|
||||
runHelperProcess(args);
|
||||
args = ["remove-symlink", "moz-foo2", "moz-bar2", "target2",
|
||||
getApplyDirFile().path + "/a/b/link2"];
|
||||
runHelperProcess(args);
|
||||
}
|
||||
|
||||
function checkSymlink() {
|
||||
let args = ["check-symlink", getApplyDirFile().path + "/a/b/link"];
|
||||
runHelperProcess(args);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
do_register_cleanup(cleanupUpdaterTest);
|
||||
|
@ -253,10 +286,31 @@ function run_test() {
|
|||
applyToDir.lastModifiedTime = yesterday;
|
||||
}
|
||||
|
||||
if (IS_UNIX) {
|
||||
removeSymlink();
|
||||
createSymlink();
|
||||
do_register_cleanup(removeSymlink);
|
||||
TEST_FILES.push({
|
||||
description : "Readable symlink",
|
||||
fileName : "link",
|
||||
relPathDir : "a/b/",
|
||||
originalContents : "test",
|
||||
compareContents : "test",
|
||||
originalFile : null,
|
||||
compareFile : null,
|
||||
originalPerms : 0664,
|
||||
comparePerms : 0664
|
||||
});
|
||||
}
|
||||
|
||||
// apply the complete mar
|
||||
let exitValue = runUpdate();
|
||||
logTestInfo("testing updater binary process exitValue for success when " +
|
||||
"applying a complete mar");
|
||||
let updateLog = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX, true);
|
||||
updateLog.append(FILE_UPDATE_LOG);
|
||||
let updateLogContents = readFileBytes(updateLog);
|
||||
logTestInfo(updateLogContents);
|
||||
do_check_eq(exitValue, 0);
|
||||
|
||||
logTestInfo("testing update.status should be " + STATE_APPLIED);
|
||||
|
@ -308,8 +362,10 @@ function run_test() {
|
|||
}
|
||||
|
||||
checkFilesAfterUpdateSuccess();
|
||||
// Sorting on Linux is different so skip this check for now.
|
||||
if (!IS_UNIX) {
|
||||
if (IS_UNIX) {
|
||||
checkSymlink();
|
||||
} else {
|
||||
// Sorting on Linux is different so skip this check for now.
|
||||
checkUpdateLogContents(LOG_COMPLETE_SWITCH_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
|
@ -551,6 +551,27 @@ static int ensure_parent_dir(const NS_tchar *path)
|
|||
return rv;
|
||||
}
|
||||
|
||||
#ifdef XP_UNIX
|
||||
static int ensure_copy_symlink(const NS_tchar *path, const NS_tchar *dest)
|
||||
{
|
||||
// Copy symlinks by creating a new symlink to the same target
|
||||
NS_tchar target[MAXPATHLEN + 1] = {NS_T('\0')};
|
||||
int rv = readlink(path, target, MAXPATHLEN);
|
||||
if (rv == -1) {
|
||||
LOG(("ensure_copy_symlink: failed to read the link: " LOG_S ", err: %d\n",
|
||||
path, errno));
|
||||
return READ_ERROR;
|
||||
}
|
||||
rv = symlink(target, dest);
|
||||
if (rv == -1) {
|
||||
LOG(("ensure_copy_symlink: failed to create the new link: " LOG_S ", target: " LOG_S " err: %d\n",
|
||||
dest, target, errno));
|
||||
return READ_ERROR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Copy the file named path onto a new file named dest.
|
||||
static int ensure_copy(const NS_tchar *path, const NS_tchar *dest)
|
||||
{
|
||||
|
@ -565,13 +586,19 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest)
|
|||
return 0;
|
||||
#else
|
||||
struct stat ss;
|
||||
int rv = NS_tstat(path, &ss);
|
||||
int rv = NS_tlstat(path, &ss);
|
||||
if (rv) {
|
||||
LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d\n",
|
||||
path, errno));
|
||||
return READ_ERROR;
|
||||
}
|
||||
|
||||
#ifdef XP_UNIX
|
||||
if (S_ISLNK(ss.st_mode)) {
|
||||
return ensure_copy_symlink(path, dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
AutoFile infile = ensure_open(path, NS_T("rb"), ss.st_mode);
|
||||
if (!infile) {
|
||||
LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d\n",
|
||||
|
@ -646,12 +673,19 @@ static int ensure_copy_recursive(const NS_tchar *path, const NS_tchar *dest,
|
|||
copy_recursive_skiplist<N>& skiplist)
|
||||
{
|
||||
struct stat sInfo;
|
||||
int rv = NS_tstat(path, &sInfo);
|
||||
int rv = NS_tlstat(path, &sInfo);
|
||||
if (rv) {
|
||||
LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d\n",
|
||||
path, rv, errno));
|
||||
return READ_ERROR;
|
||||
}
|
||||
|
||||
#ifdef XP_UNIX
|
||||
if (S_ISLNK(sInfo.st_mode)) {
|
||||
return ensure_copy_symlink(path, dest);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!S_ISDIR(sInfo.st_mode)) {
|
||||
return ensure_copy(path, dest);
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче