зеркало из 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_ttoi atoi
|
||||||
# define NS_tstat stat
|
# define NS_tstat stat
|
||||||
# define NS_tgetcwd getcwd
|
# define NS_tgetcwd getcwd
|
||||||
|
# define NS_tfputs fputs
|
||||||
# define LOG_S "%s"
|
# define LOG_S "%s"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -171,6 +172,9 @@ int NS_main(int argc, NS_tchar **argv)
|
||||||
"Usage: WORKINGDIR INFILE OUTFILE -s SECONDS [FILETOLOCK]\n" \
|
"Usage: WORKINGDIR INFILE OUTFILE -s SECONDS [FILETOLOCK]\n" \
|
||||||
" or: WORKINGDIR LOGFILE [ARG2 ARG3...]\n" \
|
" or: WORKINGDIR LOGFILE [ARG2 ARG3...]\n" \
|
||||||
" or: signature-check filepath\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" \
|
"\n" \
|
||||||
" WORKINGDIR \tThe relative path to the working directory to use.\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" \
|
" 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
|
#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"))) {
|
if (!NS_tstrcmp(argv[1], NS_T("wait-for-service-stop"))) {
|
||||||
#ifdef XP_WIN
|
#ifdef XP_WIN
|
||||||
const int maxWaitSeconds = NS_ttoi(argv[3]);
|
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
|
// 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
|
// update.manifest. Complete updates have remove file and rmdir directory
|
||||||
// operations located in the precomplete file performed first.
|
// operations located in the precomplete file performed first.
|
||||||
const TEST_FILES = [
|
var TEST_FILES = [
|
||||||
{
|
{
|
||||||
description : "Should never change",
|
description : "Should never change",
|
||||||
fileName : "channel-prefs.js",
|
fileName : "channel-prefs.js",
|
||||||
|
@ -234,6 +234,39 @@ ADDITIONAL_TEST_DIRS = [
|
||||||
dirRemoved : true
|
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() {
|
function run_test() {
|
||||||
do_test_pending();
|
do_test_pending();
|
||||||
do_register_cleanup(cleanupUpdaterTest);
|
do_register_cleanup(cleanupUpdaterTest);
|
||||||
|
@ -253,10 +286,31 @@ function run_test() {
|
||||||
applyToDir.lastModifiedTime = yesterday;
|
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
|
// apply the complete mar
|
||||||
let exitValue = runUpdate();
|
let exitValue = runUpdate();
|
||||||
logTestInfo("testing updater binary process exitValue for success when " +
|
logTestInfo("testing updater binary process exitValue for success when " +
|
||||||
"applying a complete mar");
|
"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);
|
do_check_eq(exitValue, 0);
|
||||||
|
|
||||||
logTestInfo("testing update.status should be " + STATE_APPLIED);
|
logTestInfo("testing update.status should be " + STATE_APPLIED);
|
||||||
|
@ -308,8 +362,10 @@ function run_test() {
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFilesAfterUpdateSuccess();
|
checkFilesAfterUpdateSuccess();
|
||||||
|
if (IS_UNIX) {
|
||||||
|
checkSymlink();
|
||||||
|
} else {
|
||||||
// Sorting on Linux is different so skip this check for now.
|
// Sorting on Linux is different so skip this check for now.
|
||||||
if (!IS_UNIX) {
|
|
||||||
checkUpdateLogContents(LOG_COMPLETE_SWITCH_SUCCESS);
|
checkUpdateLogContents(LOG_COMPLETE_SWITCH_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -551,6 +551,27 @@ static int ensure_parent_dir(const NS_tchar *path)
|
||||||
return rv;
|
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.
|
// Copy the file named path onto a new file named dest.
|
||||||
static int ensure_copy(const NS_tchar *path, const NS_tchar *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;
|
return 0;
|
||||||
#else
|
#else
|
||||||
struct stat ss;
|
struct stat ss;
|
||||||
int rv = NS_tstat(path, &ss);
|
int rv = NS_tlstat(path, &ss);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d\n",
|
LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d\n",
|
||||||
path, errno));
|
path, errno));
|
||||||
return READ_ERROR;
|
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);
|
AutoFile infile = ensure_open(path, NS_T("rb"), ss.st_mode);
|
||||||
if (!infile) {
|
if (!infile) {
|
||||||
LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d\n",
|
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)
|
copy_recursive_skiplist<N>& skiplist)
|
||||||
{
|
{
|
||||||
struct stat sInfo;
|
struct stat sInfo;
|
||||||
int rv = NS_tstat(path, &sInfo);
|
int rv = NS_tlstat(path, &sInfo);
|
||||||
if (rv) {
|
if (rv) {
|
||||||
LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d\n",
|
LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d\n",
|
||||||
path, rv, errno));
|
path, rv, errno));
|
||||||
return READ_ERROR;
|
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)) {
|
if (!S_ISDIR(sInfo.st_mode)) {
|
||||||
return ensure_copy(path, dest);
|
return ensure_copy(path, dest);
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче