michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. michael@0: */ michael@0: michael@0: function run_test() { michael@0: setupTestCommon(); michael@0: michael@0: // Verify write access to the custom app dir michael@0: logTestInfo("testing write access to the application directory"); michael@0: let testFile = getCurrentProcessDir(); michael@0: testFile.append("update_write_access_test"); michael@0: testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); michael@0: do_check_true(testFile.exists()); michael@0: testFile.remove(false); michael@0: do_check_false(testFile.exists()); michael@0: michael@0: standardInit(); michael@0: michael@0: if (IS_WIN) { michael@0: // Create a mutex to prevent being able to check for or apply updates. michael@0: logTestInfo("attempting to create mutex"); michael@0: let handle = createMutex(getPerInstallationMutexName()); michael@0: michael@0: logTestInfo("testing that the mutex was successfully created"); michael@0: do_check_neq(handle, null); michael@0: michael@0: // Check if available updates cannot be checked for when there is a mutex michael@0: // for this installation. michael@0: logTestInfo("testing nsIApplicationUpdateService:canCheckForUpdates is " + michael@0: "false when there is a mutex"); michael@0: do_check_false(gAUS.canCheckForUpdates); michael@0: michael@0: // Check if updates cannot be applied when there is a mutex for this michael@0: // installation. michael@0: logTestInfo("testing nsIApplicationUpdateService:canApplyUpdates is " + michael@0: "false when there is a mutex"); michael@0: do_check_false(gAUS.canApplyUpdates); michael@0: michael@0: logTestInfo("destroying mutex"); michael@0: closeHandle(handle) michael@0: } michael@0: michael@0: // Check if available updates can be checked for michael@0: logTestInfo("testing nsIApplicationUpdateService:canCheckForUpdates is true"); michael@0: do_check_true(gAUS.canCheckForUpdates); michael@0: // Check if updates can be applied michael@0: logTestInfo("testing nsIApplicationUpdateService:canApplyUpdates is true"); michael@0: do_check_true(gAUS.canApplyUpdates); michael@0: michael@0: if (IS_WIN) { michael@0: // Attempt to create a mutex when application update has already created one michael@0: // with the same name. michael@0: logTestInfo("attempting to create mutex"); michael@0: let handle = createMutex(getPerInstallationMutexName()); michael@0: michael@0: logTestInfo("testing that the mutex was not successfully created"); michael@0: do_check_eq(handle, null); michael@0: } michael@0: michael@0: doTestFinish(); michael@0: } michael@0: michael@0: if (IS_WIN) { michael@0: /** michael@0: * Determines a unique mutex name for the installation. michael@0: * michael@0: * @return Global mutex path. michael@0: */ michael@0: function getPerInstallationMutexName() { michael@0: let hasher = AUS_Cc["@mozilla.org/security/hash;1"]. michael@0: createInstance(AUS_Ci.nsICryptoHash); michael@0: hasher.init(hasher.SHA1); michael@0: michael@0: let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsILocalFile); michael@0: michael@0: let converter = AUS_Cc["@mozilla.org/intl/scriptableunicodeconverter"]. michael@0: createInstance(AUS_Ci.nsIScriptableUnicodeConverter); michael@0: converter.charset = "UTF-8"; michael@0: let data = converter.convertToByteArray(exeFile.path.toLowerCase()); michael@0: michael@0: hasher.update(data, data.length); michael@0: return "Global\\MozillaUpdateMutex-" + hasher.finish(true); michael@0: } michael@0: michael@0: /** michael@0: * Closes a Win32 handle. michael@0: * michael@0: * @param aHandle michael@0: * The handle to close. michael@0: */ michael@0: function closeHandle(aHandle) { michael@0: let lib = ctypes.open("kernel32.dll"); michael@0: let CloseHandle = lib.declare("CloseHandle", michael@0: ctypes.winapi_abi, michael@0: ctypes.int32_t, /* success */ michael@0: ctypes.void_t.ptr); /* handle */ michael@0: CloseHandle(aHandle); michael@0: lib.close(); michael@0: } michael@0: michael@0: /** michael@0: * Creates a mutex. michael@0: * michael@0: * @param aName michael@0: * The name for the mutex. michael@0: * @return The Win32 handle to the mutex. michael@0: */ michael@0: function createMutex(aName) { michael@0: const INITIAL_OWN = 1; michael@0: const ERROR_ALREADY_EXISTS = 0xB7; michael@0: let lib = ctypes.open("kernel32.dll"); michael@0: let CreateMutexW = lib.declare("CreateMutexW", michael@0: ctypes.winapi_abi, michael@0: ctypes.void_t.ptr, /* return handle */ michael@0: ctypes.void_t.ptr, /* security attributes */ michael@0: ctypes.int32_t, /* initial owner */ michael@0: ctypes.jschar.ptr); /* name */ michael@0: michael@0: let handle = CreateMutexW(null, INITIAL_OWN, aName); michael@0: lib.close(); michael@0: let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS; michael@0: if (handle && !handle.isNull() && alreadyExists) { michael@0: closeHandle(handle); michael@0: handle = null; michael@0: } michael@0: michael@0: if (handle && handle.isNull()) { michael@0: handle = null; michael@0: } michael@0: michael@0: return handle; michael@0: } michael@0: }