Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2014-03-05 16:06:46 -05:00
commit bf8677e172
256 changed files with 6142 additions and 14896 deletions

View File

@ -642,48 +642,48 @@ pref("dom.ipc.processPriorityManager.backgroundLRUPoolLevels", 5);
// /still/ have the same niceness; we'd effectively have erased NSPR's thread
// priorities.
// The kernel can only accept 6 (OomScoreAdjust, KillUnderMB) pairs. But it is
// The kernel can only accept 6 (OomScoreAdjust, KillUnderKB) pairs. But it is
// okay, kernel will still kill processes with larger OomScoreAdjust first even
// its OomScoreAdjust don't have a corresponding KillUnderMB.
// its OomScoreAdjust don't have a corresponding KillUnderKB.
pref("hal.processPriorityManager.gonk.MASTER.OomScoreAdjust", 0);
pref("hal.processPriorityManager.gonk.MASTER.KillUnderMB", 4);
pref("hal.processPriorityManager.gonk.MASTER.KillUnderKB", 4096);
pref("hal.processPriorityManager.gonk.MASTER.Nice", 0);
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.OomScoreAdjust", 67);
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderMB", 5);
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.KillUnderKB", 5120);
pref("hal.processPriorityManager.gonk.FOREGROUND_HIGH.Nice", 0);
pref("hal.processPriorityManager.gonk.FOREGROUND.OomScoreAdjust", 134);
pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderMB", 6);
pref("hal.processPriorityManager.gonk.FOREGROUND.KillUnderKB", 6144);
pref("hal.processPriorityManager.gonk.FOREGROUND.Nice", 1);
pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.OomScoreAdjust", 200);
pref("hal.processPriorityManager.gonk.FOREGROUND_KEYBOARD.Nice", 1);
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.OomScoreAdjust", 400);
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderMB", 7);
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.KillUnderKB", 7168);
pref("hal.processPriorityManager.gonk.BACKGROUND_PERCEIVABLE.Nice", 7);
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.OomScoreAdjust", 534);
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderMB", 8);
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.KillUnderKB", 8192);
pref("hal.processPriorityManager.gonk.BACKGROUND_HOMESCREEN.Nice", 18);
pref("hal.processPriorityManager.gonk.BACKGROUND.OomScoreAdjust", 667);
pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderMB", 20);
pref("hal.processPriorityManager.gonk.BACKGROUND.KillUnderKB", 20480);
pref("hal.processPriorityManager.gonk.BACKGROUND.Nice", 18);
// Processes get this niceness when they have low CPU priority.
pref("hal.processPriorityManager.gonk.LowCPUNice", 18);
// Fire a memory pressure event when the system has less than Xmb of memory
// remaining. You should probably set this just above Y.KillUnderMB for
// remaining. You should probably set this just above Y.KillUnderKB for
// the highest priority class Y that you want to make an effort to keep alive.
// (For example, we want BACKGROUND_PERCEIVABLE to stay alive.) If you set
// this too high, then we'll send out a memory pressure event every Z seconds
// (see below), even while we have processes that we would happily kill in
// order to free up memory.
pref("hal.processPriorityManager.gonk.notifyLowMemUnderMB", 14);
pref("hal.processPriorityManager.gonk.notifyLowMemUnderKB", 14336);
// We wait this long before polling the memory-pressure fd after seeing one
// memory pressure event. (When we're not under memory pressure, we sit

View File

@ -66,7 +66,12 @@ RecoveryService.prototype = {
#ifdef MOZ_WIDGET_GONK
// If this succeeds, then the device reboots and this never returns
if (librecovery.factoryReset() != 0) {
log("Error: Factory reset failed");
log("Error: Factory reset failed. Trying again after clearing cache.");
}
var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
cache.clear();
if (librecovery.factoryReset() != 0) {
log("Error: Factory reset failed again");
}
#endif
throw Cr.NS_ERROR_FAILURE;
@ -76,7 +81,12 @@ RecoveryService.prototype = {
#ifdef MOZ_WIDGET_GONK
// If this succeeds, then the device reboots and this never returns
if (librecovery.installFotaUpdate(updatePath, updatePath.length) != 0) {
log("Error: FOTA install failed");
log("Error: FOTA install failed. Trying again after clearing cache.");
}
var cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"].getService(Ci.nsICacheStorageService);
cache.clear();
if (librecovery.installFotaUpdate(updatePath, updatePath.length) != 0) {
log("Error: FOTA install failed again");
}
#endif
throw Cr.NS_ERROR_FAILURE;

View File

@ -15,11 +15,11 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
@ -104,5 +104,5 @@
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="c16df012d9649be75d6590f93aeacbdc24b29d53"/>
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="431afac2ebfdd9c1c8402b413ff5914ed448e961"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="5701d3cb45c2e848cc57003cda2e1141288ecae4"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="4f46930827957afbce500a4a920755a218bf3155"/>
</manifest>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>

View File

@ -15,11 +15,11 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="refs/tags/android-4.0.4_r2.1" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="d11f524d00cacf5ba0dfbf25e4aa2158b1c3a036"/>
@ -104,5 +104,5 @@
<project name="platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" path="prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6" revision="627f9b20fc518937b93747a7ff1ed4f5ed46e06f"/>
<project name="platform/prebuilts/tools" path="prebuilts/tools" revision="c16df012d9649be75d6590f93aeacbdc24b29d53"/>
<project name="platform_prebuilts_qemu-kernel" path="prebuilts/qemu-kernel" remote="b2g" revision="431afac2ebfdd9c1c8402b413ff5914ed448e961"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="5701d3cb45c2e848cc57003cda2e1141288ecae4"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="4f46930827957afbce500a4a920755a218bf3155"/>
</manifest>

View File

@ -4,6 +4,6 @@
"branch": "",
"revision": ""
},
"revision": "03dfc866c15f5322d13a542b722eeb1accb1c429",
"revision": "5d470e57a89125a55663058050b2cd147630a948",
"repo_path": "/integration/gaia-central"
}

View File

@ -13,14 +13,14 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
<!-- Stock Android things -->

View File

@ -11,14 +11,14 @@
<remote fetch="https://git.mozilla.org/releases" name="mozillaorg"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>
<!-- Stock Android things -->

View File

@ -15,14 +15,14 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
<!-- Stock Android things -->

View File

@ -13,14 +13,14 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="b2g/ics_strawberry" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>

View File

@ -13,14 +13,14 @@
<remote fetch="https://git.mozilla.org/external/apitrace" name="apitrace"/>
<default remote="caf" revision="ics_chocolate_rb4.2" sync-j="4"/>
<!-- Gonk specific things and forks -->
<project name="platform_build" path="build" remote="b2g" revision="59605a7c026ff06cc1613af3938579b1dddc6cfe">
<project name="platform_build" path="build" remote="b2g" revision="1ad48c4be51b279f7f63c1a13025b52fe087d231">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4bb8b32d8f1a3a64bfac8f2da7878dc63e613ca5"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="9cb35e701df44766d9b3560b0defe0a401a0ecdd"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="15e8982284c4560f9c74c2b9fe8bb361ebfe0cb6"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1f6a1fe07f81c5bc5e1d079c9b60f7f78ca2bf4f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="3d5c964015967ca8c86abe6dbbebee3cb82b1609"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="b2f773d8320d30648b89767dfe5b25ef94bc7e62"/>
<project name="gonk-patches" path="patches" remote="b2g" revision="223a2421006e8f5da33f516f6891c87cae86b0f6"/>

View File

@ -20,13 +20,16 @@ def get_build_entries(root_path):
parent_dir_rel_path = root[len(root_path)+1:]
rel_path_file = os.path.join(parent_dir_rel_path, file_name)
rel_path_file = rel_path_file.replace("\\", "/")
if not (rel_path_file.endswith("channel-prefs.js")):
if not (rel_path_file.endswith("channel-prefs.js") or
rel_path_file.endswith("update-settings.ini") or
rel_path_file.find("distribution/") != -1):
rel_file_path_set.add(rel_path_file)
for dir_name in dirs:
parent_dir_rel_path = root[len(root_path)+1:]
rel_path_dir = os.path.join(parent_dir_rel_path, dir_name)
rel_path_dir = rel_path_dir.replace("\\", "/")+"/"
if rel_path_dir.find("distribution/") == -1:
rel_dir_path_set.add(rel_path_dir)
rel_file_path_list = list(rel_file_path_set)

View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
function boom()
{
document.styleSheetSets.expando = null;
}
</script>
</head>
<body onload="boom();"></body>
</html>

View File

@ -147,3 +147,4 @@ skip-if(Android) load 851353-1.html
load 863950.html
load 864448.html
load 942979.html
load 978646.html

View File

@ -1904,6 +1904,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptGlobalObject)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMStyleSheets)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheetSetList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb);
@ -2042,6 +2043,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
tmp->mListenerManager = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMStyleSheets)
if (tmp->mStyleSheetSetList) {
tmp->mStyleSheetSetList->Disconnect();
tmp->mStyleSheetSetList = nullptr;
}
if (tmp->mSubDocuments) {
PL_DHashTableDestroy(tmp->mSubDocuments);
tmp->mSubDocuments = nullptr;

View File

@ -69,6 +69,14 @@ DOM4_MSG_DEF(QuotaExceededError, "The current transaction exceeded its quota lim
DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.")
/* FileSystem DOM errors. */
DOM4_MSG_DEF(InvalidAccessError, "Invalid file system path.", NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR)
DOM4_MSG_DEF(InvalidModificationError, "Failed to modify the file.", NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR)
DOM4_MSG_DEF(NoModificationAllowedError, "Modifications are not allowed for this file", NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR)
DOM4_MSG_DEF(AbortError, "File already exists.", NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR)
DOM4_MSG_DEF(TypeMismatchError, "The type of the file is incompatible with the expected type.", NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR)
DOM4_MSG_DEF(UnknownError, "The operation failed for reasons unrelated to the file system itself and not covered by any other error code.", NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR)
/* DOM error codes defined by us */
/* XXX string should be specified by norris */

View File

@ -105,6 +105,17 @@ nsJSUtils::ReportPendingException(JSContext *aContext)
if (JS_IsExceptionPending(aContext)) {
bool saved = JS_SaveFrameChain(aContext);
{
// JS_SaveFrameChain set the compartment of aContext to null, so we need
// to enter a compartment. The question is, which one? We don't want to
// enter the original compartment of aContext (or the compartment of the
// current exception on aContext, for that matter) because when we
// JS_ReportPendingException the JS engine can try to duck-type the
// exception and produce a JSErrorReport. It will then pass that
// JSErrorReport to the error reporter on aContext, which might expose
// information from it to script via onerror handlers. So it's very
// important that the duck typing happen in the same compartment as the
// onerror handler. In practice, that's the compartment of the window (or
// otherwise default global) of aContext, so use that here.
nsIScriptContext* scx = GetScriptContextFromJSContext(aContext);
JS::Rooted<JSObject*> scope(aContext);
scope = scx ? scx->GetWindowProxy()

View File

@ -207,8 +207,15 @@ CallbackObject::CallSetup::ShouldRethrowException(JS::Handle<JS::Value> aExcepti
CallbackObject::CallSetup::~CallSetup()
{
// First things first: if we have a JSContext, report any pending
// errors on it, unless we were told to re-throw them.
// To get our nesting right we have to destroy our JSAutoCompartment first.
// In particular, we want to do this before we try reporting any exceptions,
// so we end up reporting them while in the compartment of our entry point,
// not whatever cross-compartment wrappper mCallback might be.
// Be careful: the JSAutoCompartment might not have been constructed at all!
mAc.destroyIfConstructed();
// Now, if we have a JSContext, report any pending errors on it, unless we
// were told to re-throw them.
if (mCx) {
bool dealtWithPendingException = false;
if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
@ -231,13 +238,33 @@ CallbackObject::CallSetup::~CallSetup()
// Either we're supposed to report our exceptions, or we're supposed to
// re-throw them but we failed to JS_GetPendingException. Either way,
// just report the pending exception, if any.
nsJSUtils::ReportPendingException(mCx);
//
// We don't use nsJSUtils::ReportPendingException here because all it
// does at this point is JS_SaveFrameChain and enter a compartment around
// a JS_ReportPendingException call. But our mAutoEntryScript should
// already do a JS_SaveFrameChain and we are already in the compartment
// we want to be in, so all nsJSUtils::ReportPendingException would do is
// screw up our compartment, which is exactly what we do not want.
//
// XXXbz FIXME: bug 979525 means we don't always JS_SaveFrameChain here,
// so we need to go ahead and do that.
JS::Rooted<JSObject*> oldGlobal(mCx, JS::CurrentGlobalOrNull(mCx));
MOZ_ASSERT(oldGlobal, "How can we not have a global here??");
bool saved = JS_SaveFrameChain(mCx);
// Make sure the JSAutoCompartment goes out of scope before the
// JS_RestoreFrameChain call!
{
JSAutoCompartment ac(mCx, oldGlobal);
MOZ_ASSERT(!JS::DescribeScriptedCaller(mCx),
"Our comment above about JS_SaveFrameChain having been "
"called is a lie?");
JS_ReportPendingException(mCx);
}
if (saved) {
JS_RestoreFrameChain(mCx);
}
}
}
// To get our nesting right we have to destroy our JSAutoCompartment first.
// But be careful: it might not have been constructed at all!
mAc.destroyIfConstructed();
mAutoIncumbentScript.destroyIfConstructed();
mAutoEntryScript.destroyIfConstructed();

View File

@ -78,6 +78,10 @@ public:
// is being thrown. Code that would call ReportJSException* or
// StealJSException as needed must first call WouldReportJSException even if
// this ErrorResult has not failed.
//
// The exn argument to ThrowJSException can be in any compartment. It does
// not have to be in the compartment of cx. If someone later uses it, they
// will wrap it into whatever compartment they're working in, as needed.
void ThrowJSException(JSContext* cx, JS::Handle<JS::Value> exn);
void ReportJSException(JSContext* cx);
// Used to implement throwing exceptions from the JS implementation of

View File

@ -793,6 +793,7 @@ GetProperty(DBusMessageIter aIter, Properties* aPropertyTypes,
}
if (i == aPropertyTypeLen) {
BT_LOGR("unknown property: %s", property);
return false;
}
@ -1695,6 +1696,11 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
sDeviceProperties,
ArrayLength(sDeviceProperties));
if (v.type() == BluetoothValue::T__None) {
BT_WARNING("PropertyChanged event couldn't be parsed.");
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
BluetoothNamedValue& property = v.get_ArrayOfBluetoothNamedValue()[0];
if (property.name().EqualsLiteral("Paired")) {
// Original approach: Broadcast system message of

View File

@ -31,6 +31,8 @@ namespace dom {
class DeviceStorageEnumerationParameters;
class DOMCursor;
class DOMRequest;
class Promise;
class DeviceStorageFileSystem;
} // namespace dom
namespace ipc {
class FileDescriptor;
@ -157,6 +159,8 @@ class nsDOMDeviceStorage MOZ_FINAL
EnumerationParameters;
typedef mozilla::dom::DOMCursor DOMCursor;
typedef mozilla::dom::DOMRequest DOMRequest;
typedef mozilla::dom::Promise Promise;
typedef mozilla::dom::DeviceStorageFileSystem DeviceStorageFileSystem;
public:
typedef nsTArray<nsString> VolumeNameArray;
@ -255,6 +259,9 @@ public:
// Uses XPCOM GetStorageName
already_AddRefed<Promise>
GetRoot();
static void
CreateDeviceStorageFor(nsPIDOMWindow* aWin,
const nsAString& aType,
@ -332,6 +339,8 @@ private:
DEVICE_STORAGE_TYPE_SHARED,
DEVICE_STORAGE_TYPE_EXTERNAL
};
nsRefPtr<DeviceStorageFileSystem> mFileSystem;
};
#endif

View File

@ -11,11 +11,15 @@
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/DeviceStorageBinding.h"
#include "mozilla/dom/DeviceStorageFileSystem.h"
#include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/ipc/Blob.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/PContentPermissionRequestChild.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/LazyIdleThread.h"
#include "mozilla/Preferences.h"
#include "mozilla/Scoped.h"
@ -892,14 +896,7 @@ DeviceStorageFile::IsSafePath(const nsAString& aPath)
void
DeviceStorageFile::NormalizeFilePath() {
#if defined(XP_WIN)
char16_t* cur = mPath.BeginWriting();
char16_t* end = mPath.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('\\') == *cur)
*cur = char16_t('/');
}
#endif
FileSystemUtils::LocalPathToNormalizedPath(mPath, mPath);
}
void
@ -917,23 +914,9 @@ DeviceStorageFile::AppendRelativePath(const nsAString& aPath) {
NS_WARNING(NS_LossyConvertUTF16toASCII(aPath).get());
return;
}
#if defined(XP_WIN)
// replace forward slashes with backslashes,
// since nsLocalFileWin chokes on them
nsString temp;
temp.Assign(aPath);
char16_t* cur = temp.BeginWriting();
char16_t* end = temp.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('/') == *cur)
*cur = char16_t('\\');
}
mFile->AppendRelativePath(temp);
#else
mFile->AppendRelativePath(aPath);
#endif
nsString localPath;
FileSystemUtils::NormalizedPathToLocalPath(aPath, localPath);
mFile->AppendRelativePath(localPath);
}
nsresult
@ -3074,6 +3057,11 @@ nsDOMDeviceStorage::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
if (mFileSystem) {
mFileSystem->SetDeviceStorage(nullptr);
mFileSystem = nullptr;
}
if (!mStorageName.IsEmpty()) {
UnregisterForSDCardChanges(this);
}
@ -3812,6 +3800,16 @@ nsDOMDeviceStorage::Default()
return mStorageName.Equals(defaultStorageName);
}
already_AddRefed<Promise>
nsDOMDeviceStorage::GetRoot()
{
if (!mFileSystem) {
mFileSystem = new DeviceStorageFileSystem(mStorageType, mStorageName);
mFileSystem->SetDeviceStorage(this);
}
return mozilla::dom::Directory::GetRoot(mFileSystem);
}
NS_IMETHODIMP
nsDOMDeviceStorage::GetDefault(bool* aDefault)
{

View File

@ -1,3 +1,4 @@
[DEFAULT]
[test_app_permissions.html]
[test_fs_app_permissions.html]

View File

@ -21,3 +21,8 @@ support-files = devicestorage_common.js
[test_usedSpace.html]
[test_watch.html]
[test_watchOther.html]
# FileSystem API tests
[test_fs_basic.html]
[test_fs_createDirectory.html]
[test_fs_get.html]

View File

@ -0,0 +1,428 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<meta charset="utf-8">
<title>Permission test of FileSystem API for Device Storage</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css"?>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content">
</div>
<pre id="test">
<script type="application/javascript;version=1.7">
function randomFilename(l) {
let set = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
let result = "";
for (let i=0; i<l; i++) {
let r = Math.floor(set.length * Math.random());
result += set.substring(r, r + 1);
}
return result;
}
let MockPermissionPrompt = SpecialPowers.MockPermissionPrompt;
MockPermissionPrompt.init();
SimpleTest.waitForExplicitFinish();
function TestCreateDirectory(iframe, data) {
function cbError(e) {
is(e.name, "SecurityError", "[TestCreateDirectory] Should fire a SecurityError for type " + data.type);
is(data.shouldPass, false, "[TestCreateDirectory] Error callback was called for type " + data.type + '. Error: ' + e.name);
testComplete(iframe, data);
}
let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "[TestCreateDirectory] Should be able to get storage object for " + data.type);
if (!storage) {
testComplete(iframe, data);
return;
}
storage.getRoot().then(function(root) {
is(data.shouldPass, true, "[TestCreateDirectory] Success callback was called for type " + data.type);
let filename = randomFilename(100);
root.createDirectory(filename).then(function(d) {
let passed = d && (d.name === filename);
is(data.shouldPass, passed, "[TestCreateDirectory] Success callback was called for type " + data.type);
testComplete(iframe, data);
}, cbError);
}, cbError);
}
function TestGet(iframe, data) {
function cbError(e) {
is(e.name, "SecurityError", "[TestGet] Should fire a SecurityError for type " + data.type);
is(data.shouldPass, false, "[TestGet] Error callback was called for type " + data.type + '. Error: ' + e.name);
testComplete(iframe, data);
}
createTestFile(data.fileExtension);
let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type);
isnot(storage, null, "[TestGet] Should be able to get storage object for " + data.type);
if (!storage) {
testComplete(iframe, data);
return;
}
storage.getRoot().then(function(root) {
ok(true, "[TestGet] Success callback of getRoot was called for type " + data.type);
root.get("testfile" + data.fileExtension).then(function() {
is(data.shouldPass, true, "[TestGet] Success callback was called for type " + data.type);
testComplete(iframe, data);
}, cbError);
}, cbError);
}
let gTestUri = "https://example.com/tests/dom/devicestorage/test/test_fs_app_permissions.html"
let gData = [
// Directory#get
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
fileExtension: '.png',
test: TestGet
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogv',
test: TestGet
},
{
type: 'videos',
shouldPass: false,
fileExtension: '.ogg',
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.ogg',
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
test: TestGet
},
{
type: 'sdcard',
shouldPass: false,
fileExtension: '.txt',
test: TestGet
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
permissions: ["device-storage:pictures"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
permissions: ["device-storage:sdcard"],
test: TestGet
},
// Certified application with permision granted
{
type: 'pictures',
shouldPass: true,
fileExtension: '.png',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:pictures"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogv',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'videos',
shouldPass: true,
fileExtension: '.ogg',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:videos"],
test: TestGet
},
{
type: 'music',
shouldPass: true,
fileExtension: '.ogg',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'music',
shouldPass: false,
fileExtension: '.txt',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:music"],
test: TestGet
},
{
type: 'sdcard',
shouldPass: true,
fileExtension: '.txt',
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:sdcard"],
test: TestGet
},
// Directory#createDirectory
// Web applications with no permissions
{
type: 'pictures',
shouldPass: false,
test: TestCreateDirectory
},
{
type: 'videos',
shouldPass: false,
test: TestCreateDirectory
},
{
type: 'music',
shouldPass: false,
test: TestCreateDirectory
},
{
type: 'sdcard',
shouldPass: false,
test: TestCreateDirectory
},
// Web applications with permission granted
{
type: 'pictures',
shouldPass: true,
permissions: ["device-storage:pictures"],
test: TestCreateDirectory
},
{
type: 'videos',
shouldPass: true,
permissions: ["device-storage:videos"],
test: TestCreateDirectory
},
{
type: 'music',
shouldPass: true,
permissions: ["device-storage:music"],
test: TestCreateDirectory
},
{
type: 'sdcard',
shouldPass: true,
permissions: ["device-storage:sdcard"],
test: TestCreateDirectory
},
// Certified application with permision granted
{
type: 'pictures',
shouldPass: true,
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:pictures"],
test: TestCreateDirectory
},
{
type: 'videos',
shouldPass: true,
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:videos"],
test: TestCreateDirectory
},
{
type: 'music',
shouldPass: true,
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:music"],
test: TestCreateDirectory
},
{
type: 'sdcard',
shouldPass: true,
app: "https://example.com/manifest_cert.webapp",
permissions: ["device-storage:sdcard"],
test: TestCreateDirectory
}
];
function setupTest(iframe,data) {
if (data.permissions) {
for (let j in data.permissions) {
SpecialPowers.addPermission(data.permissions[j], true, iframe.contentDocument);
}
}
}
function testComplete(iframe, data) {
if (data.permissions) {
for (let j in data.permissions) {
SpecialPowers.removePermission(data.permissions[j], iframe.contentDocument);
}
}
document.getElementById('content').removeChild(iframe);
if (gData.length == 0) {
SimpleTest.finish();
} else {
gTestRunner.next();
}
}
function runTest() {
while (gData.length > 0) {
let iframe = document.createElement('iframe');
let data = gData.shift();
iframe.setAttribute('mozbrowser', '');
if (data.app) {
iframe.setAttribute('mozapp', data.app);
}
iframe.src = gTestUri;
iframe.addEventListener('load', function(e) {
setupTest(iframe, data)
data.test(iframe, data);
});
document.getElementById('content').appendChild(iframe);
yield undefined;
}
}
function createTestFile(extension) {
try {
const Cc = SpecialPowers.Cc;
const Ci = SpecialPowers.Ci;
let directoryService = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
let f = directoryService.get("TmpD", Ci.nsIFile);
f.appendRelativePath("device-storage-testing");
f.remove(true);
f.appendRelativePath("testfile" + extension);
f.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
} catch(e) {}
}
let gTestRunner = runTest();
SpecialPowers.addPermission("browser", true, gTestUri);
// We are more permissive with CSP in our testing environment....
const DEFAULT_CSP_PRIV = "default-src *; script-src 'self'; style-src 'self' 'unsafe-inline'; object-src 'none'";
const DEFAULT_CSP_CERT = "default-src *; script-src 'self'; style-src 'self'; object-src 'none'";
SpecialPowers.pushPrefEnv({'set': [["dom.mozBrowserFramesEnabled", true],
["device.storage.enabled", true],
["device.storage.testing", true],
["device.storage.prompt.testing", false],
["security.apps.privileged.CSP.default", DEFAULT_CSP_PRIV],
["security.apps.certified.CSP.default", DEFAULT_CSP_CERT]]},
function() { gTestRunner.next(); });
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,70 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test for the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
var gFileName = randomFilename(12);
// The root directory object.
var gRoot;
function getRootSuccess(r) {
ok(r && r.name === storage.storageName, "Failed to get the root directory.");
gRoot = r;
// Create a new directory under the root.
gRoot.createDirectory(gFileName).then(createDirectorySuccess, cbError);
}
function createDirectorySuccess(d) {
ok(d.name === gFileName, "Failed to create directory: name mismatch.");
// Get the new created directory from the root.
gRoot.get(gFileName).then(getSuccess, cbError);
}
function getSuccess(d) {
ok(d.name === gFileName, "Should get directory - " + gFileName + ".");
devicestorage_cleanup();
}
function cbError(e) {
ok(false, "Should not arrive here! Error: " + e.name);
devicestorage_cleanup();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage");
var promise = storage.getRoot();
ok(promise, "Should have a non-null promise");
promise.then(getRootSuccess, cbError);
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,105 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test createDirectory of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
// The root directory object.
var gRoot;
var gTestCount = 0;
var gPath = '';
var gName = '';
function testCreateDirectory(rootDir, path) {
rootDir.createDirectory(path).then(createDirectorySuccess, cbError);
}
function createDirectorySuccess(d) {
ok(d.name === gName, "Failed to create directory: name mismatch.");
// Get the new created directory from the root.
gRoot.get(gPath).then(getSuccess, cbError);
}
function getSuccess(d) {
ok(d.name === gName, "Should get directory - " + (gPath || "[root]") + ".");
switch (gTestCount) {
case 0:
gRoot = d;
// Create a new directory under the root.
gName = gPath = randomFilename(12);
testCreateDirectory(gRoot, gName);
break;
case 1:
// Create a sub-directory under current directory.
gName = randomFilename(12);
gPath = gPath + '/' + gName;
testCreateDirectory(d, gName);
break;
case 2:
// Create directory with an existing path.
gRoot.createDirectory(gPath).then(function(what) {
ok(false, "Should not overwrite an existing directory.");
devicestorage_cleanup();
}, function(e) {
ok(true, "Creating directory should fail if it already exists.");
// Create a directory whose intermediate directory doesn't exit.
gName = randomFilename(12);
gPath = 'sub1/sub2/' + gName;
testCreateDirectory(gRoot, gPath);
});
break;
default:
// Create the parent directory.
d.createDirectory('..').then(function(what) {
ok(false, "Should not overwrite an existing directory.");
devicestorage_cleanup();
}, function(e) {
ok(true, "Accessing parent directory with '..' is not allowed.");
devicestorage_cleanup();
});
break;
}
gTestCount++;
}
function cbError(e) {
ok(false, e.name + " error should not arrive here!");
devicestorage_cleanup();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage.");
var promise = storage.getRoot();
ok(promise, "Should have a non-null promise for getRoot.");
gName = storage.storageName;
promise.then(getSuccess, cbError);
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,183 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=910412
-->
<head>
<title>Test Directory#get of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=910412">Mozilla Bug 910412</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
devicestorage_setup();
// The root directory object.
var gRoot = null;
var gSub1 = null;
var gSub2 = null;
var gTestCount = 0;
var gPath = "/";
function testGetSuccess(dir, path) {
dir.get(path).then(getSuccess, cbError);
}
function testGetFailure(dir, path) {
dir.get(path).then(cbSuccess, getFailure);
}
function getSuccess(r) {
ok(r, "[" + gTestCount +"] Should get the file - " + gPath + ".");
switch (gTestCount) {
case 0:
gRoot = r;
// Get sub1/sub2/text.png from root.
gPath = "sub1/sub2/test.png";
testGetSuccess(gRoot, "sub1/sub2/test.png");
break;
case 1:
// Get sub1 from root.
gPath = "sub1";
testGetSuccess(gRoot, "sub1");
break;
case 2:
// Get sub1/sub2 from root.
gSub1 = r;
gPath = "sub1/sub2";
testGetSuccess(gRoot, "sub1/sub2");
break;
case 3:
// Get sub1/sub2 from sub2.
gSub2 = r;
gPath = "sub1/sub2";
testGetSuccess(gSub1, "sub2");
break;
case 4:
// Test path with leading and trailing white spaces.
gPath = "sub1/sub2";
testGetSuccess(gSub1, "\t sub2 ");
break;
case 5:
// Get sub1 from sub1/sub2 with "..".
gPath = "sub1/sub2/..";
testGetFailure(gSub2, "..");
break;
default:
ok(false, "Should not arrive at getSuccess!");
devicestorage_cleanup();
break;
}
gTestCount++;
}
function getFailure(e) {
ok(true, "[" + gTestCount +"] Should not get the file - " + gPath + ". Error: " + e.name);
switch (gTestCount) {
case 6:
// Test special path "..".
gPath = "sub1/sub2/../sub2";
testGetFailure(gSub2, "../sub2");
break;
case 7:
gPath = "sub1/sub2/../sub2";
testGetFailure(gRoot, "sub1/sub2/../sub2");
break;
case 8:
// Test special path ".".
gPath = "sub1/./sub2";
testGetFailure(gRoot, "sub1/./sub2");
break;
case 9:
gPath = "./sub1/sub2";
testGetFailure(gRoot, "./sub1/sub2");
break;
case 10:
gPath = "././sub1/sub2";
testGetFailure(gRoot, "././sub1/sub2");
break;
case 11:
gPath = "sub1/sub2/.";
testGetFailure(gRoot, "sub1/sub2/.");
break;
case 12:
gPath = "sub1/.";
testGetFailure(gSub1, "./");
break;
case 13:
// Test path starting with "/".
gPath = "sub1/";
testGetFailure(gSub1, "/");
break;
case 14:
// Test path ending with "/".
gPath = "sub1/";
testGetFailure(gSub1, "sub2/");
break;
case 15:
// Test empty path.
gPath = "sub2";
testGetFailure(gSub2, "");
break;
case 16:
// Test special path "//".
gPath = "sub1//sub2";
testGetFailure(gRoot, "sub1//sub2");
break;
case 17:
devicestorage_cleanup();
break;
default:
ok(false, "Should not arrive here!");
devicestorage_cleanup();
break;
}
gTestCount++;
}
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
devicestorage_cleanup();
}
function cbSuccess(e) {
ok(false, "Should not arrive at cbSuccess!");
devicestorage_cleanup();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
var storage = navigator.getDeviceStorage("pictures");
ok(storage, "Should have gotten a storage.");
// Create test files.
var req = storage.addNamed(createRandomBlob("image/png"), "sub1/sub2/test.png");
req.onsuccess = function() {
var promise = storage.getRoot();
ok(promise, "Should have a non-null promise for getRoot.");
promise.then(getSuccess, cbError);
};
req.onerror = function() {
ok(false, "Failed to created test files.");
devicestorage_cleanup();
};
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,146 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CreateDirectoryTask.h"
#include "DOMError.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/Promise.h"
#include "nsIFile.h"
#include "nsStringGlue.h"
namespace mozilla {
namespace dom {
CreateDirectoryTask::CreateDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aPath)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aPath)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (!aFileSystem) {
return;
}
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
}
mPromise = new Promise(globalObject);
}
CreateDirectoryTask::CreateDirectoryTask(
FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
mTargetRealPath = aParam.realPath();
}
CreateDirectoryTask::~CreateDirectoryTask()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
}
already_AddRefed<Promise>
CreateDirectoryTask::GetPromise()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return nsRefPtr<Promise>(mPromise).forget();
}
FileSystemParams
CreateDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemCreateDirectoryParams(aFileSystem, mTargetRealPath);
}
FileSystemResponseValue
CreateDirectoryTask::GetSuccessRequestResult() const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemDirectoryResponse(mTargetRealPath);
}
void
CreateDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
FileSystemDirectoryResponse r = aValue;
mTargetRealPath = r.realPath();
}
void
CreateDirectoryTask::Work()
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
if (!filesystem) {
return;
}
nsCOMPtr<nsIFile> file = filesystem->GetLocalFile(mTargetRealPath);
if (!file) {
SetError(NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR);
return;
}
bool ret;
nsresult rv = file->Exists(&ret);
if (NS_FAILED(rv)) {
SetError(rv);
return;
}
if (ret) {
SetError(NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR);
return;
}
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_FAILED(rv)) {
SetError(rv);
return;
}
}
void
CreateDirectoryTask::HandlerCallback()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
if (!filesystem) {
return;
}
if (HasError()) {
nsRefPtr<DOMError> domError = new DOMError(filesystem->GetWindow(),
mErrorValue);
mPromise->MaybeReject(domError);
return;
}
nsRefPtr<Directory> dir = new Directory(filesystem, mTargetRealPath);
mPromise->MaybeResolve(dir);
}
void
CreateDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral("create");
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,67 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_CreateDirectoryTask_h
#define mozilla_dom_CreateDirectoryTask_h
#include "mozilla/dom/FileSystemTaskBase.h"
#include "nsAutoPtr.h"
class nsCString;
class nsString;
namespace mozilla {
namespace dom {
class Directory;
class FileSystemBase;
class FileSystemCreateDirectoryParams;
class Promise;
class CreateDirectoryTask MOZ_FINAL
: public FileSystemTaskBase
{
public:
CreateDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aPath);
CreateDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemCreateDirectoryParams& aParam,
FileSystemRequestParent* aParent);
virtual
~CreateDirectoryTask();
already_AddRefed<Promise>
GetPromise();
virtual void
GetPermissionAccessType(nsCString& aAccess) const MOZ_OVERRIDE;
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const MOZ_OVERRIDE;
virtual FileSystemResponseValue
GetSuccessRequestResult() const MOZ_OVERRIDE;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) MOZ_OVERRIDE;
virtual void
Work() MOZ_OVERRIDE;
virtual void
HandlerCallback() MOZ_OVERRIDE;
private:
nsRefPtr<Promise> mPromise;
nsString mTargetRealPath;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_CreateDirectoryTask_h

View File

@ -0,0 +1,137 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/DeviceStorageFileSystem.h"
#include "DeviceStorage.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "nsDeviceStorage.h"
#include "nsIFile.h"
#include "nsPIDOMWindow.h"
namespace mozilla {
namespace dom {
DeviceStorageFileSystem::DeviceStorageFileSystem(
const nsAString& aStorageType,
const nsAString& aStorageName)
: mDeviceStorage(nullptr)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
mStorageType = aStorageType;
mStorageName = aStorageName;
// Generate the string representation of the file system.
mString.AppendLiteral("devicestorage-");
mString.Append(mStorageType);
mString.AppendLiteral("-");
mString.Append(mStorageName);
mIsTesting =
mozilla::Preferences::GetBool("device.storage.prompt.testing", false);
// Get the permission name required to access the file system.
nsresult rv =
DeviceStorageTypeChecker::GetPermissionForType(mStorageType, mPermission);
NS_WARN_IF(NS_FAILED(rv));
// Get the local path of the file system root.
// Since the child process is not allowed to access the file system, we only
// do this from the parent process.
if (!FileSystemUtils::IsParentProcess()) {
return;
}
nsCOMPtr<nsIFile> rootFile;
DeviceStorageFile::GetRootDirectoryForType(aStorageType,
aStorageName,
getter_AddRefs(rootFile));
NS_WARN_IF(!rootFile || NS_FAILED(rootFile->GetPath(mLocalRootPath)));
FileSystemUtils::LocalPathToNormalizedPath(mLocalRootPath,
mNormalizedLocalRootPath);
// DeviceStorageTypeChecker is a singleton object and must be initialized on
// the main thread. We initialize it here so that we can use it on the worker
// thread.
DebugOnly<DeviceStorageTypeChecker*> typeChecker
= DeviceStorageTypeChecker::CreateOrGet();
MOZ_ASSERT(typeChecker);
}
DeviceStorageFileSystem::~DeviceStorageFileSystem()
{
}
void
DeviceStorageFileSystem::SetDeviceStorage(nsDOMDeviceStorage* aDeviceStorage)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
mDeviceStorage = aDeviceStorage;
}
nsPIDOMWindow*
DeviceStorageFileSystem::GetWindow() const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (!mDeviceStorage) {
return nullptr;
}
return mDeviceStorage->GetOwner();
}
already_AddRefed<nsIFile>
DeviceStorageFileSystem::GetLocalFile(const nsAString& aRealPath) const
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Should be on parent process!");
nsAutoString localPath;
FileSystemUtils::NormalizedPathToLocalPath(aRealPath, localPath);
localPath = mLocalRootPath + localPath;
nsCOMPtr<nsIFile> file;
nsresult rv = NS_NewLocalFile(localPath, false, getter_AddRefs(file));
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return file.forget();
}
const nsAString&
DeviceStorageFileSystem::GetRootName() const
{
return mStorageName;
}
bool
DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Should be on parent process!");
MOZ_ASSERT(aFile);
// Check if this file belongs to this storage.
nsAutoString path;
if (NS_FAILED(aFile->GetPath(path))) {
return false;
}
FileSystemUtils::LocalPathToNormalizedPath(path, path);
if (!FileSystemUtils::IsDescendantPath(mNormalizedLocalRootPath, path)) {
return false;
}
// Check if the file type is compatible with the storage type.
DeviceStorageTypeChecker* typeChecker
= DeviceStorageTypeChecker::CreateOrGet();
MOZ_ASSERT(typeChecker);
return typeChecker->Check(mStorageType, aFile);
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,59 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_DeviceStorageFileSystem_h
#define mozilla_dom_DeviceStorageFileSystem_h
#include "mozilla/dom/FileSystemBase.h"
#include "nsString.h"
class nsDOMDeviceStorage;
namespace mozilla {
namespace dom {
class DeviceStorageFileSystem
: public FileSystemBase
{
public:
DeviceStorageFileSystem(const nsAString& aStorageType,
const nsAString& aStorageName);
void
SetDeviceStorage(nsDOMDeviceStorage* aDeviceStorage);
// Overrides FileSystemBase
virtual nsPIDOMWindow*
GetWindow() const MOZ_OVERRIDE;
virtual already_AddRefed<nsIFile>
GetLocalFile(const nsAString& aRealPath) const MOZ_OVERRIDE;
virtual const nsAString&
GetRootName() const MOZ_OVERRIDE;
virtual bool
IsSafeFile(nsIFile* aFile) const MOZ_OVERRIDE;
private:
virtual
~DeviceStorageFileSystem();
nsString mStorageType;
nsString mStorageName;
// The local path of the root. Only available in the parent process.
// In the child process, we don't use it and its value should be empty.
nsString mLocalRootPath;
nsString mNormalizedLocalRootPath;
nsDOMDeviceStorage* mDeviceStorage;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_DeviceStorageFileSystem_h

View File

@ -0,0 +1,184 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Directory.h"
#include "CreateDirectoryTask.h"
#include "FileSystemPermissionRequest.h"
#include "GetFileOrDirectoryTask.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsStringGlue.h"
#include "mozilla/dom/DirectoryBinding.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
// Resolve the name collision of Microsoft's API name with macros defined in
// Windows header files. Undefine the macro of CreateDirectory to avoid
// Directory#CreateDirectory being replaced by Directory#CreateDirectoryW.
#ifdef CreateDirectory
#undef CreateDirectory
#endif
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(Directory)
NS_IMPL_CYCLE_COLLECTING_ADDREF(Directory)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Directory)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Directory)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
// static
already_AddRefed<Promise>
Directory::GetRoot(FileSystemBase* aFileSystem)
{
nsRefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
aFileSystem, EmptyString(), true);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
Directory::Directory(FileSystemBase* aFileSystem,
const nsAString& aPath)
: mPath(aPath)
{
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
mFileSystem = do_GetWeakReference(aFileSystem);
// Remove the trailing "/".
mPath.Trim(FILESYSTEM_DOM_PATH_SEPARATOR, false, true);
SetIsDOMBinding();
}
Directory::~Directory()
{
}
nsPIDOMWindow*
Directory::GetParentObject() const
{
nsRefPtr<FileSystemBase> fs = do_QueryReferent(mFileSystem);
if (!fs) {
return nullptr;
}
return fs->GetWindow();
}
JSObject*
Directory::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
{
return DirectoryBinding::Wrap(aCx, aScope, this);
}
void
Directory::GetName(nsString& aRetval) const
{
aRetval.Truncate();
nsRefPtr<FileSystemBase> fs = do_QueryReferent(mFileSystem);
if (mPath.IsEmpty() && fs) {
aRetval = fs->GetRootName();
return;
}
aRetval = Substring(mPath,
mPath.RFindChar(FileSystemUtils::kSeparatorChar) + 1);
}
already_AddRefed<Promise>
Directory::CreateDirectory(const nsAString& aPath)
{
nsresult error = NS_OK;
nsString realPath;
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
nsRefPtr<FileSystemBase> fs = do_QueryReferent(mFileSystem);
nsRefPtr<CreateDirectoryTask> task = new CreateDirectoryTask(
fs, realPath);
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
already_AddRefed<Promise>
Directory::Get(const nsAString& aPath)
{
nsresult error = NS_OK;
nsString realPath;
if (!DOMPathToRealPath(aPath, realPath)) {
error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
}
nsRefPtr<FileSystemBase> fs = do_QueryReferent(mFileSystem);
nsRefPtr<GetFileOrDirectoryTask> task = new GetFileOrDirectoryTask(
fs, realPath, false);
task->SetError(error);
FileSystemPermissionRequest::RequestForTask(task);
return task->GetPromise();
}
bool
Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const
{
aRealPath.Truncate();
nsString relativePath;
relativePath = aPath;
// Trim white spaces.
static const char kWhitespace[] = "\b\t\r\n ";
relativePath.Trim(kWhitespace);
if (!IsValidRelativePath(relativePath)) {
return false;
}
aRealPath = mPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR) +
relativePath;
return true;
}
// static
bool
Directory::IsValidRelativePath(const nsString& aPath)
{
// We don't allow empty relative path to access the root.
if (aPath.IsEmpty()) {
return false;
}
// Leading and trailing "/" are not allowed.
if (aPath.First() == FileSystemUtils::kSeparatorChar ||
aPath.Last() == FileSystemUtils::kSeparatorChar) {
return false;
}
NS_NAMED_LITERAL_STRING(kCurrentDir, ".");
NS_NAMED_LITERAL_STRING(kParentDir, "..");
// Split path and check each path component.
nsCharSeparatedTokenizer tokenizer(aPath, FileSystemUtils::kSeparatorChar);
while (tokenizer.hasMoreTokens()) {
nsDependentSubstring pathComponent = tokenizer.nextToken();
// The path containing empty components, such as "foo//bar", is invalid.
// We don't allow paths, such as "../foo", "foo/./bar" and "foo/../bar",
// to walk up the directory.
if (pathComponent.IsEmpty() ||
pathComponent.Equals(kCurrentDir) ||
pathComponent.Equals(kParentDir)) {
return false;
}
}
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,82 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_Directory_h
#define mozilla_dom_Directory_h
#include "mozilla/Attributes.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsPIDOMWindow.h"
#include "nsWeakReference.h"
#include "nsWrapperCache.h"
// Resolve the name collision of Microsoft's API name with macros defined in
// Windows header files. Undefine the macro of CreateDirectory to avoid
// Directory#CreateDirectory being replaced by Directory#CreateDirectoryW.
#ifdef CreateDirectory
#undef CreateDirectory
#endif
namespace mozilla {
namespace dom {
class FileSystemBase;
class Promise;
class Directory MOZ_FINAL
: public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Directory)
public:
static already_AddRefed<Promise>
GetRoot(FileSystemBase* aFileSystem);
Directory(FileSystemBase* aFileSystem, const nsAString& aPath);
~Directory();
// ========= Begin WebIDL bindings. ===========
nsPIDOMWindow*
GetParentObject() const;
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
void
GetName(nsString& aRetval) const;
already_AddRefed<Promise>
CreateDirectory(const nsAString& aPath);
already_AddRefed<Promise>
Get(const nsAString& aPath);
// =========== End WebIDL bindings.============
private:
static bool
IsValidRelativePath(const nsString& aPath);
/*
* Convert relative DOM path to the absolute real path.
* @return true if succeed. false if the DOM path is invalid.
*/
bool
DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const;
nsWeakPtr mFileSystem;
nsString mPath;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_Directory_h

View File

@ -0,0 +1,67 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/FileSystemBase.h"
#include "DeviceStorageFileSystem.h"
#include "nsCharSeparatedTokenizer.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS1(FileSystemBase, nsISupportsWeakReference)
// static
already_AddRefed<FileSystemBase>
FileSystemBase::FromString(const nsAString& aString)
{
if (StringBeginsWith(aString, NS_LITERAL_STRING("devicestorage-"))) {
// The string representation of devicestorage file system is of the format:
// devicestorage-StorageType-StorageName
nsCharSeparatedTokenizer tokenizer(aString, char16_t('-'));
tokenizer.nextToken();
nsString storageType;
if (tokenizer.hasMoreTokens()) {
storageType = tokenizer.nextToken();
}
nsString storageName;
if (tokenizer.hasMoreTokens()) {
storageName = tokenizer.nextToken();
}
nsCOMPtr<DeviceStorageFileSystem> f =
new DeviceStorageFileSystem(storageType, storageName);
return f.forget();
}
return nullptr;
}
FileSystemBase::FileSystemBase()
: mIsTesting(false)
{
}
FileSystemBase::~FileSystemBase()
{
}
nsPIDOMWindow*
FileSystemBase::GetWindow() const
{
return nullptr;
}
bool
FileSystemBase::IsSafeFile(nsIFile* aFile) const
{
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,92 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_FileSystemBase_h
#define mozilla_dom_FileSystemBase_h
#include "nsWeakReference.h"
#include "nsAutoPtr.h"
#include "nsString.h"
class nsPIDOMWindow; // You need |#include "nsPIDOMWindow.h"| in CPP files.
namespace mozilla {
namespace dom {
/*
* To make FileSystemBase as a weak reference, so that before the child window
* is closed and the FileSystemBase is destroyed, we don't need to notify the
* FileSystemTaskBase instances, which hold the FileSystemBase reference, to
* cancel and wait until the instances finish.
*/
class FileSystemBase
: public nsSupportsWeakReference
{
NS_DECL_THREADSAFE_ISUPPORTS
public:
// Create file system object from its string representation.
static already_AddRefed<FileSystemBase>
FromString(const nsAString& aString);
FileSystemBase();
// Get the string representation of the file system.
const nsString&
ToString() const
{
return mString;
}
virtual nsPIDOMWindow*
GetWindow() const;
/*
* Create nsIFile object with the given real path (absolute DOM path).
*/
virtual already_AddRefed<nsIFile>
GetLocalFile(const nsAString& aRealPath) const = 0;
/*
* Get the virtual name of the root directory. This name will be exposed to
* the content page.
*/
virtual const nsAString&
GetRootName() const = 0;
virtual bool
IsSafeFile(nsIFile* aFile) const;
/*
* Get the permission name required to access this file system.
*/
const nsCString&
GetPermission() const
{
return mPermission;
}
bool
IsTesting() const
{
return mIsTesting;
}
protected:
virtual ~FileSystemBase();
// The string representation of the file system.
nsString mString;
// The permission name required to access the file system.
nsCString mPermission;
bool mIsTesting;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_FileSystemBase_h

View File

@ -0,0 +1,190 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "FileSystemPermissionRequest.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/TabChild.h"
#include "nsIDocument.h"
#include "nsPIDOMWindow.h"
#include "nsString.h"
namespace mozilla {
namespace dom {
NS_IMPL_ISUPPORTS2(FileSystemPermissionRequest, nsIRunnable, nsIContentPermissionRequest)
// static
void
FileSystemPermissionRequest::RequestForTask(FileSystemTaskBase* aTask)
{
MOZ_ASSERT(aTask, "aTask should not be null!");
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<FileSystemPermissionRequest> request =
new FileSystemPermissionRequest(aTask);
NS_DispatchToCurrentThread(request);
}
FileSystemPermissionRequest::FileSystemPermissionRequest(
FileSystemTaskBase* aTask)
: mTask(aTask)
{
MOZ_ASSERT(mTask, "aTask should not be null!");
MOZ_ASSERT(NS_IsMainThread());
mTask->GetPermissionAccessType(mPermissionAccess);
nsRefPtr<FileSystemBase> filesystem = mTask->GetFileSystem();
if (!filesystem) {
return;
}
mPermissionType = filesystem->GetPermission();
mWindow = filesystem->GetWindow();
if (!mWindow) {
return;
}
nsCOMPtr<nsIDocument> doc = mWindow->GetDoc();
if (!doc) {
return;
}
mPrincipal = doc->NodePrincipal();
}
FileSystemPermissionRequest::~FileSystemPermissionRequest()
{
}
bool
FileSystemPermissionRequest::Recv__delete__(const bool& aAllow,
const InfallibleTArray<PermissionChoice>& aChoices)
{
MOZ_ASSERT(aChoices.IsEmpty(),
"FileSystemPermissionRequest doesn't support permission choice");
if (aAllow) {
Allow(JS::UndefinedHandleValue);
} else {
Cancel();
}
return true;
}
void
FileSystemPermissionRequest::IPDLRelease()
{
Release();
}
NS_IMETHODIMP
FileSystemPermissionRequest::GetTypes(nsIArray** aTypes)
{
nsTArray<nsString> emptyOptions;
return CreatePermissionArray(mPermissionType,
mPermissionAccess,
emptyOptions,
aTypes);
}
NS_IMETHODIMP
FileSystemPermissionRequest::GetPrincipal(nsIPrincipal** aRequestingPrincipal)
{
NS_IF_ADDREF(*aRequestingPrincipal = mPrincipal);
return NS_OK;
}
NS_IMETHODIMP
FileSystemPermissionRequest::GetWindow(nsIDOMWindow** aRequestingWindow)
{
NS_IF_ADDREF(*aRequestingWindow = mWindow);
return NS_OK;
}
NS_IMETHODIMP
FileSystemPermissionRequest::GetElement(nsIDOMElement** aRequestingElement)
{
*aRequestingElement = nullptr;
return NS_OK;
}
NS_IMETHODIMP
FileSystemPermissionRequest::Cancel()
{
MOZ_ASSERT(NS_IsMainThread());
mTask->SetError(NS_ERROR_DOM_SECURITY_ERR);
mTask->Start();
return NS_OK;
}
NS_IMETHODIMP
FileSystemPermissionRequest::Allow(JS::HandleValue aChoices)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aChoices.isUndefined());
mTask->Start();
return NS_OK;
}
NS_IMETHODIMP
FileSystemPermissionRequest::Run()
{
MOZ_ASSERT(NS_IsMainThread());
nsRefPtr<FileSystemBase> filesystem = mTask->GetFileSystem();
if (!filesystem) {
Cancel();
return NS_OK;
}
if (filesystem->IsTesting()) {
Allow(JS::UndefinedHandleValue);
return NS_OK;
}
if (FileSystemUtils::IsParentProcess()) {
nsCOMPtr<nsIContentPermissionPrompt> prompt
= do_CreateInstance(NS_CONTENT_PERMISSION_PROMPT_CONTRACTID);
if (!prompt || NS_FAILED(prompt->Prompt(this))) {
Cancel();
}
return NS_OK;
}
if (!mWindow) {
Cancel();
return NS_OK;
}
// because owner implements nsITabChild, we can assume that it is
// the one and only TabChild.
TabChild* child = TabChild::GetFrom(mWindow->GetDocShell());
if (!child) {
Cancel();
return NS_OK;
}
// Retain a reference so the object isn't deleted without IPDL's
// knowledge. Corresponding release occurs in
// DeallocPContentPermissionRequest.
AddRef();
nsTArray<PermissionRequest> permArray;
nsTArray<nsString> emptyOptions;
permArray.AppendElement(PermissionRequest(mPermissionType,
mPermissionAccess,
emptyOptions));
child->SendPContentPermissionRequestConstructor(
this, permArray, IPC::Principal(mPrincipal));
Sendprompt();
return NS_OK;
}
} /* namespace dom */
} /* namespace mozilla */

View File

@ -0,0 +1,61 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_FileSystemPermissionRequest_h
#define mozilla_dom_FileSystemPermissionRequest_h
#include "PCOMContentPermissionRequestChild.h"
#include "nsAutoPtr.h"
#include "nsContentPermissionHelper.h"
#include "nsIRunnable.h"
class nsCString;
class nsPIDOMWindow;
namespace mozilla {
namespace dom {
class FileSystemTaskBase;
class FileSystemPermissionRequest MOZ_FINAL
: public nsIContentPermissionRequest
, public nsIRunnable
, public PCOMContentPermissionRequestChild
{
public:
// Request permission for the given task.
static void
RequestForTask(FileSystemTaskBase* aTask);
// Overrides PCOMContentPermissionRequestChild
virtual void
IPDLRelease() MOZ_OVERRIDE;
bool
Recv__delete__(const bool& aAllow,
const InfallibleTArray<PermissionChoice>& aChoices) MOZ_OVERRIDE;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
NS_DECL_NSIRUNNABLE
private:
FileSystemPermissionRequest(FileSystemTaskBase* aTask);
virtual
~FileSystemPermissionRequest();
nsCString mPermissionType;
nsCString mPermissionAccess;
nsRefPtr<FileSystemTaskBase> mTask;
nsCOMPtr<nsPIDOMWindow> mWindow;
nsCOMPtr<nsIPrincipal> mPrincipal;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_FileSystemPermissionRequest_h

View File

@ -0,0 +1,79 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/FileSystemRequestParent.h"
#include "CreateDirectoryTask.h"
#include "GetFileOrDirectoryTask.h"
#include "mozilla/AppProcessChecker.h"
#include "mozilla/dom/FileSystemBase.h"
namespace mozilla {
namespace dom {
FileSystemRequestParent::FileSystemRequestParent()
{
}
FileSystemRequestParent::~FileSystemRequestParent()
{
}
bool
FileSystemRequestParent::Dispatch(ContentParent* aParent,
const FileSystemParams& aParams)
{
MOZ_ASSERT(aParent, "aParent should not be null.");
nsRefPtr<FileSystemTaskBase> task;
switch (aParams.type()) {
case FileSystemParams::TFileSystemCreateDirectoryParams: {
const FileSystemCreateDirectoryParams& p = aParams;
mFileSystem = FileSystemBase::FromString(p.filesystem());
task = new CreateDirectoryTask(mFileSystem, p, this);
break;
}
case FileSystemParams::TFileSystemGetFileOrDirectoryParams: {
const FileSystemGetFileOrDirectoryParams& p = aParams;
mFileSystem = FileSystemBase::FromString(p.filesystem());
task = new GetFileOrDirectoryTask(mFileSystem, p, this);
break;
}
default: {
NS_RUNTIMEABORT("not reached");
break;
}
}
if (NS_WARN_IF(!task || !mFileSystem)) {
// Should never reach here.
return false;
}
if (!mFileSystem->IsTesting()) {
// Check the content process permission.
nsCString access;
task->GetPermissionAccessType(access);
nsAutoCString permissionName;
permissionName = mFileSystem->GetPermission();
permissionName.AppendLiteral("-");
permissionName.Append(access);
if (!AssertAppProcessPermission(aParent, permissionName.get())) {
return false;
}
}
task->Start();
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,44 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_FileSystemRequestParent_h
#define mozilla_dom_FileSystemRequestParent_h
#include "mozilla/dom/PFileSystemRequestParent.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
namespace mozilla {
namespace dom {
class FileSystemBase;
class FileSystemRequestParent
: public PFileSystemRequestParent
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemRequestParent)
public:
FileSystemRequestParent();
virtual
~FileSystemRequestParent();
bool
IsRunning()
{
return state() == PFileSystemRequest::__Start;
}
bool
Dispatch(ContentParent* aParent, const FileSystemParams& aParams);
private:
nsRefPtr<FileSystemBase> mFileSystem;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_FileSystemRequestParent_h

View File

@ -0,0 +1,208 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/FileSystemTaskBase.h"
#include "nsNetUtil.h" // Stream transport service.
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/PContent.h"
#include "mozilla/unused.h"
namespace mozilla {
namespace dom {
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem)
: mErrorValue(NS_OK)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
mFileSystem = do_GetWeakReference(aFileSystem);
}
FileSystemTaskBase::FileSystemTaskBase(FileSystemBase* aFileSystem,
const FileSystemParams& aParam,
FileSystemRequestParent* aParent)
: mErrorValue(NS_OK)
, mRequestParent(aParent)
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
MOZ_ASSERT(aFileSystem, "aFileSystem should not be null.");
mFileSystem = do_GetWeakReference(aFileSystem);
}
FileSystemTaskBase::~FileSystemTaskBase()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
}
already_AddRefed<FileSystemBase>
FileSystemTaskBase::GetFileSystem()
{
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
return filesystem.forget();
}
void
FileSystemTaskBase::Start()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (HasError()) {
HandlerCallback();
return;
}
if (FileSystemUtils::IsParentProcess()) {
// Run in parent process.
// Start worker thread.
nsCOMPtr<nsIEventTarget> target
= do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
NS_ASSERTION(target, "Must have stream transport service.");
target->Dispatch(this, NS_DISPATCH_NORMAL);
return;
}
// Run in child process.
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
if (!filesystem) {
return;
}
// Retain a reference so the task object isn't deleted without IPDL's
// knowledge. The reference will be released by
// mozilla::dom::ContentChild::DeallocPFileSystemRequestChild.
NS_ADDREF_THIS();
ContentChild::GetSingleton()->SendPFileSystemRequestConstructor(this,
GetRequestParams(filesystem->ToString()));
}
NS_IMETHODIMP
FileSystemTaskBase::Run()
{
if (!NS_IsMainThread()) {
// Run worker thread tasks
Work();
// Dispatch itself to main thread
NS_DispatchToMainThread(this);
return NS_OK;
}
// Run main thread tasks
HandleResult();
return NS_OK;
}
void
FileSystemTaskBase::HandleResult()
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
if (!filesystem) {
return;
}
if (mRequestParent && mRequestParent->IsRunning()) {
unused << mRequestParent->Send__delete__(mRequestParent,
GetRequestResult());
} else {
HandlerCallback();
}
}
FileSystemResponseValue
FileSystemTaskBase::GetRequestResult() const
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (HasError()) {
return FileSystemErrorResponse(mErrorValue);
} else {
return GetSuccessRequestResult();
}
}
void
FileSystemTaskBase::SetRequestResult(const FileSystemResponseValue& aValue)
{
MOZ_ASSERT(!FileSystemUtils::IsParentProcess(),
"Only call from child process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (aValue.type() == FileSystemResponseValue::TFileSystemErrorResponse) {
FileSystemErrorResponse r = aValue;
mErrorValue = r.error();
} else {
SetSuccessRequestResult(aValue);
}
}
bool
FileSystemTaskBase::Recv__delete__(const FileSystemResponseValue& aValue)
{
SetRequestResult(aValue);
HandlerCallback();
return true;
}
void
FileSystemTaskBase::SetError(const nsresult& aErrorValue)
{
uint16_t module = NS_ERROR_GET_MODULE(aErrorValue);
if (module == NS_ERROR_MODULE_DOM_FILESYSTEM ||
module == NS_ERROR_MODULE_DOM_FILE ||
module == NS_ERROR_MODULE_DOM) {
mErrorValue = aErrorValue;
return;
}
switch (aErrorValue) {
case NS_OK:
mErrorValue = NS_OK;
return;
case NS_ERROR_FILE_INVALID_PATH:
case NS_ERROR_FILE_UNRECOGNIZED_PATH:
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR;
return;
case NS_ERROR_FILE_DESTINATION_NOT_DIR:
mErrorValue = NS_ERROR_DOM_FILESYSTEM_INVALID_MODIFICATION_ERR;
return;
case NS_ERROR_FILE_ACCESS_DENIED:
case NS_ERROR_FILE_DIR_NOT_EMPTY:
mErrorValue = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR;
return;
case NS_ERROR_FILE_TARGET_DOES_NOT_EXIST:
case NS_ERROR_NOT_AVAILABLE:
mErrorValue = NS_ERROR_DOM_FILE_NOT_FOUND_ERR;
return;
case NS_ERROR_FILE_ALREADY_EXISTS:
mErrorValue = NS_ERROR_DOM_FILESYSTEM_PATH_EXISTS_ERR;
return;
case NS_ERROR_FILE_NOT_DIRECTORY:
mErrorValue = NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR;
return;
case NS_ERROR_UNEXPECTED:
default:
mErrorValue = NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR;
return;
}
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,239 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_FileSystemTaskBase_h
#define mozilla_dom_FileSystemTaskBase_h
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "mozilla/dom/PFileSystemRequestChild.h"
#include "nsWeakReference.h"
namespace mozilla {
namespace dom {
class FileSystemBase;
class FileSystemParams;
class Promise;
/*
* The base class to implement a Task class.
* The task is used to handle the OOP (out of process) operations.
* The file system operations can only be performed in the parent process. When
* performing such a parent-process-only operation, a task will delivered the
* operation to the parent process if needed.
*
* The following diagram illustrates the how a API call from the content page
* starts a task and gets call back results.
*
* The left block is the call sequence inside the child process, while the
* right block is the call sequence inside the parent process.
*
* There are two types of API call. One is from the content page of the child
* process and we mark the steps as (1) to (8). The other is from the content
* page of the parent process and we mark the steps as (1') to (4').
*
* Page Page
* | |
* | (1) | (1')
* ______|________________ | _____________________|_____________
* | | | | | | |
* | | Task in | | | Task in | |
* | | Child Process | | | Parent Process | |
* | V | IPC | V |
* [new FileSystemTaskBase()] | | [new FileSystemTaskBase()] |
* | | | | | | |
* | | (2) | | | (2') |
* | V | (3) | | |
* | [GetRequestParams]------------->[new FileSystemTaskBase(...)] |
* | | | | | |
* | | | | | (4) | |
* | | | | | V |
* | | | | -----------> [Work] |
* | | IPC | | |
* | | | | (5) | (3') |
* | | | | V |
* | | | | --------[HandleResult] |
* | | | | | | |
* | | | | (6) | |
* | | (7) | V | |
* | [SetRequestResult]<-------------[GetRequestResult] | |
* | | | | | (4') |
* | | (8) | | | | |
* | V | | | V |
* |[HandlerCallback] | IPC | [HandlerCallback] |
* |_______|_______________| | |_________________________|_________|
* | | |
* V V
* Page Page
*
* 1. From child process page
* Child:
* (1) Call FileSystem API from content page with JS. Create a task and run.
* The base constructor [FileSystemTaskBase()] of the task should be called.
* (2) Forward the task to the parent process through the IPC and call
* [GetRequestParams] to prepare the parameters of the IPC.
* Parent:
* (3) The parent process receives IPC and handle it in
* FileystemRequestParent.
* Get the IPC parameters and create a task to run the IPC task. The base
* constructor [FileSystemTaskBase(aParam, aParent)] of the task should be
* called to set the task as an IPC task.
* (4) The task operation will be performed in the member function of [Work].
* A worker thread will be created to run that function. If error occurs
* during the operation, call [SetError] to record the error and then abort.
* (5) After finishing the task operation, call [HandleResult] to send the
* result back to the child process though the IPC.
* (6) Call [GetRequestResult] request result to prepare the parameters of the
* IPC. Because the formats of the error result for different task are the
* same, FileSystemTaskBase can handle the error message without interfering.
* Each task only needs to implement its specific success result preparation
* function -[GetSuccessRequestResult].
* Child:
* (7) The child process receives IPC and calls [SetRequestResult] to get the
* task result. Each task needs to implement its specific success result
* parsing function [SetSuccessRequestResult] to get the success result.
* (8) Call [HandlerCallback] to send the task result to the content page.
* 2. From parent process page
* We don't need to send the task parameters and result to other process. So
* there are less steps, but their functions are the same. The correspondence
* between the two types of steps is:
* (1') = (1),
* (2') = (4),
* (3') = (5),
* (4') = (8).
*/
class FileSystemTaskBase
: public nsRunnable
, public PFileSystemRequestChild
{
public:
/*
* Start the task. If the task is running the child process, it will be
* forwarded to parent process by IPC, or else, creates a worker thread to
* do the task work.
*/
void
Start();
/*
* The error codes are defined in xpcom/base/ErrorList.h and their
* corresponding error name and message are defined in dom/base/domerr.msg.
*/
void
SetError(const nsresult& aErrorCode);
already_AddRefed<FileSystemBase>
GetFileSystem();
/*
* Get the type of permission access required to perform this task.
*/
virtual void
GetPermissionAccessType(nsCString& aAccess) const = 0;
NS_DECL_NSIRUNNABLE
protected:
/*
* To create a task to handle the page content request.
*/
FileSystemTaskBase(FileSystemBase* aFileSystem);
/*
* To create a parent process task delivered from the child process through
* IPC.
*/
FileSystemTaskBase(FileSystemBase* aFileSystem,
const FileSystemParams& aParam,
FileSystemRequestParent* aParent);
virtual
~FileSystemTaskBase();
/*
* The function to perform task operation. It will be run on the worker
* thread of the parent process.
* Overrides this function to define the task operation for individual task.
*/
virtual void
Work() = 0;
/*
* After the task is completed, this function will be called to pass the task
* result to the content page.
* Override this function to handle the call back to the content page.
*/
virtual void
HandlerCallback() = 0;
/*
* Wrap the task parameter to FileSystemParams for sending it through IPC.
* It will be called when we need to forward a task from the child process to
* the prarent process.
* @param filesystem The string representation of the file system.
*/
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const = 0;
/*
* Wrap the task success result to FileSystemResponseValue for sending it
* through IPC.
* It will be called when the task is completed successfully and we need to
* send the task success result back to the child process.
*/
virtual FileSystemResponseValue
GetSuccessRequestResult() const = 0;
/*
* Unwrap the IPC message to get the task success result.
* It will be called when the task is completed successfully and an IPC
* message is received in the child process and we want to get the task
* success result.
*/
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) = 0;
bool
HasError() const { return mErrorValue != NS_OK; }
// Overrides PFileSystemRequestChild
virtual bool
Recv__delete__(const FileSystemResponseValue& value) MOZ_OVERRIDE;
nsresult mErrorValue;
nsWeakPtr mFileSystem;
nsRefPtr<FileSystemRequestParent> mRequestParent;
private:
/*
* After finishing the task operation, handle the task result.
* If it is an IPC task, send back the IPC result. Or else, send the result
* to the content page.
*/
void
HandleResult();
/*
* Wrap the task result to FileSystemResponseValue for sending it through IPC.
* It will be called when the task is completed and we need to
* send the task result back to the child process.
*/
FileSystemResponseValue
GetRequestResult() const;
/*
* Unwrap the IPC message to get the task result.
* It will be called when the task is completed and an IPC message is received
* in the child process and we want to get the task result.
*/
void
SetRequestResult(const FileSystemResponseValue& aValue);
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_FileSystemTaskBase_h

View File

@ -0,0 +1,76 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/FileSystemUtils.h"
#include "nsXULAppAPI.h"
namespace mozilla {
namespace dom {
// static
void
FileSystemUtils::LocalPathToNormalizedPath(const nsAString& aLocal,
nsAString& aNorm)
{
nsString result;
result = aLocal;
#if defined(XP_WIN)
char16_t* cur = result.BeginWriting();
char16_t* end = result.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('\\') == *cur)
*cur = char16_t('/');
}
#endif
aNorm = result;
}
// static
void
FileSystemUtils::NormalizedPathToLocalPath(const nsAString& aNorm,
nsAString& aLocal)
{
nsString result;
result = aNorm;
#if defined(XP_WIN)
char16_t* cur = result.BeginWriting();
char16_t* end = result.EndWriting();
for (; cur < end; ++cur) {
if (char16_t('/') == *cur)
*cur = char16_t('\\');
}
#endif
aLocal = result;
}
// static
bool
FileSystemUtils::IsDescendantPath(const nsAString& aPath,
const nsAString& aDescendantPath)
{
// The descendant path should begin with its ancestor path.
nsAutoString prefix;
prefix = aPath + NS_LITERAL_STRING(FILESYSTEM_DOM_PATH_SEPARATOR);
// Check the sub-directory path to see if it has the parent path as prefix.
if (aDescendantPath.Length() < prefix.Length() ||
!StringBeginsWith(aDescendantPath, prefix)) {
return false;
}
return true;
}
// static
bool
FileSystemUtils::IsParentProcess()
{
return XRE_GetProcessType() == GeckoProcessType_Default;
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,53 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_FileSystemUtils_h
#define mozilla_dom_FileSystemUtils_h
#include "nsStringGlue.h"
namespace mozilla {
namespace dom {
#define FILESYSTEM_DOM_PATH_SEPARATOR "/"
/*
* This class is for error handling.
* All methods in this class are static.
*/
class FileSystemUtils
{
public:
/*
* Convert the path separator to "/".
*/
static void
LocalPathToNormalizedPath(const nsAString& aLocal, nsAString& aNorm);
/*
* Convert the normalized path separator "/" to the system dependent path
* separator, which is "/" on Mac and Linux, and "\" on Windows.
*/
static void
NormalizedPathToLocalPath(const nsAString& aNorm, nsAString& aLocal);
/*
* Return true if aDescendantPath is a descendant of aPath. Both aPath and
* aDescendantPath are absolute DOM path.
*/
static bool
IsDescendantPath(const nsAString& aPath, const nsAString& aDescendantPath);
static bool
IsParentProcess();
static const char16_t kSeparatorChar = char16_t('/');
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_FileSystemUtils_h

View File

@ -0,0 +1,226 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "GetFileOrDirectoryTask.h"
#include "js/Value.h"
#include "mozilla/dom/Directory.h"
#include "mozilla/dom/FileSystemBase.h"
#include "mozilla/dom/FileSystemUtils.h"
#include "mozilla/dom/Promise.h"
#include "nsDOMFile.h"
#include "nsIFile.h"
#include "nsStringGlue.h"
namespace mozilla {
namespace dom {
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
bool aDirectoryOnly)
: FileSystemTaskBase(aFileSystem)
, mTargetRealPath(aTargetPath)
, mIsDirectory(aDirectoryOnly)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (!aFileSystem) {
return;
}
nsCOMPtr<nsIGlobalObject> globalObject =
do_QueryInterface(aFileSystem->GetWindow());
if (!globalObject) {
return;
}
mPromise = new Promise(globalObject);
}
GetFileOrDirectoryTask::GetFileOrDirectoryTask(
FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent)
: FileSystemTaskBase(aFileSystem, aParam, aParent)
, mIsDirectory(false)
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
mTargetRealPath = aParam.realPath();
}
GetFileOrDirectoryTask::~GetFileOrDirectoryTask()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
}
already_AddRefed<Promise>
GetFileOrDirectoryTask::GetPromise()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return nsRefPtr<Promise>(mPromise).forget();
}
FileSystemParams
GetFileOrDirectoryTask::GetRequestParams(const nsString& aFileSystem) const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return FileSystemGetFileOrDirectoryParams(aFileSystem, mTargetRealPath);
}
FileSystemResponseValue
GetFileOrDirectoryTask::GetSuccessRequestResult() const
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
if (mIsDirectory) {
return FileSystemDirectoryResponse(mTargetRealPath);
}
ContentParent* cp = static_cast<ContentParent*>(mRequestParent->Manager());
BlobParent* actor = cp->GetOrCreateActorForBlob(mTargetFile);
if (!actor) {
return FileSystemErrorResponse(NS_ERROR_DOM_FILESYSTEM_UNKNOWN_ERR);
}
FileSystemFileResponse response;
response.blobParent() = actor;
return response;
}
void
GetFileOrDirectoryTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue)
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
switch (aValue.type()) {
case FileSystemResponseValue::TFileSystemFileResponse: {
FileSystemFileResponse r = aValue;
BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
mTargetFile = do_QueryInterface(blob);
mIsDirectory = false;
break;
}
case FileSystemResponseValue::TFileSystemDirectoryResponse: {
FileSystemDirectoryResponse r = aValue;
mTargetRealPath = r.realPath();
mIsDirectory = true;
break;
}
default: {
NS_RUNTIMEABORT("not reached");
break;
}
}
}
void
GetFileOrDirectoryTask::Work()
{
MOZ_ASSERT(FileSystemUtils::IsParentProcess(),
"Only call from parent process!");
MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!");
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
if (!filesystem) {
return;
}
// Whether we want to get the root directory.
bool getRoot = mTargetRealPath.IsEmpty();
nsCOMPtr<nsIFile> file = filesystem->GetLocalFile(mTargetRealPath);
if (!file) {
SetError(NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR);
return;
}
bool ret;
nsresult rv = file->Exists(&ret);
if (NS_FAILED(rv)) {
SetError(rv);
return;
}
if (!ret) {
if (!getRoot) {
SetError(NS_ERROR_DOM_FILE_NOT_FOUND_ERR);
return;
}
// If the root directory doesn't exit, create it.
rv = file->Create(nsIFile::DIRECTORY_TYPE, 0777);
if (NS_FAILED(rv)) {
SetError(rv);
return;
}
}
// Get isDirectory.
rv = file->IsDirectory(&mIsDirectory);
if (NS_FAILED(rv)) {
SetError(rv);
return;
}
if (!mIsDirectory) {
// Check if the root is a directory.
if (getRoot) {
SetError(NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR);
return;
}
// Get isFile
rv = file->IsFile(&ret);
if (NS_FAILED(rv)) {
SetError(rv);
return;
}
if (!ret) {
// Neither directory or file.
SetError(NS_ERROR_DOM_FILESYSTEM_TYPE_MISMATCH_ERR);
return;
}
if (!filesystem->IsSafeFile(file)) {
SetError(NS_ERROR_DOM_SECURITY_ERR);
return;
}
mTargetFile = new nsDOMFileFile(file);
}
}
void
GetFileOrDirectoryTask::HandlerCallback()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
nsRefPtr<FileSystemBase> filesystem = do_QueryReferent(mFileSystem);
if (!filesystem) {
return;
}
if (HasError()) {
nsRefPtr<DOMError> domError = new DOMError(filesystem->GetWindow(),
mErrorValue);
mPromise->MaybeReject(domError);
return;
}
if (mIsDirectory) {
nsRefPtr<Directory> dir = new Directory(filesystem, mTargetRealPath);
mPromise->MaybeResolve(dir);
return;
}
mPromise->MaybeResolve(mTargetFile);
}
void
GetFileOrDirectoryTask::GetPermissionAccessType(nsCString& aAccess) const
{
aAccess.AssignLiteral("read");
}
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,71 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_GetFileOrDirectory_h
#define mozilla_dom_GetFileOrDirectory_h
#include "mozilla/dom/FileSystemTaskBase.h"
#include "nsAutoPtr.h"
class nsIDOMFile;
class nsString;
namespace mozilla {
namespace dom {
class FileSystemBase;
class FileSystemFile;
class FileSystemGetFileOrDirectoryParams;
class Promise;
class GetFileOrDirectoryTask MOZ_FINAL
: public FileSystemTaskBase
{
public:
// If aDirectoryOnly is set, we should ensure that the target is a directory.
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const nsAString& aTargetPath,
bool aDirectoryOnly);
GetFileOrDirectoryTask(FileSystemBase* aFileSystem,
const FileSystemGetFileOrDirectoryParams& aParam,
FileSystemRequestParent* aParent);
virtual
~GetFileOrDirectoryTask();
already_AddRefed<Promise>
GetPromise();
virtual void
GetPermissionAccessType(nsCString& aAccess) const MOZ_OVERRIDE;
protected:
virtual FileSystemParams
GetRequestParams(const nsString& aFileSystem) const MOZ_OVERRIDE;
virtual FileSystemResponseValue
GetSuccessRequestResult() const MOZ_OVERRIDE;
virtual void
SetSuccessRequestResult(const FileSystemResponseValue& aValue) MOZ_OVERRIDE;
virtual void
Work() MOZ_OVERRIDE;
virtual void
HandlerCallback() MOZ_OVERRIDE;
private:
nsRefPtr<Promise> mPromise;
nsString mTargetRealPath;
// Whether we get a directory.
bool mIsDirectory;
nsCOMPtr<nsIDOMFile> mTargetFile;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_GetFileOrDirectory_h

View File

@ -0,0 +1,44 @@
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PBlob;
include protocol PContent;
namespace mozilla {
namespace dom {
struct FileSystemFileResponse
{
PBlob blob;
};
struct FileSystemDirectoryResponse
{
nsString realPath;
};
struct FileSystemErrorResponse
{
nsresult error;
};
union FileSystemResponseValue
{
FileSystemDirectoryResponse;
FileSystemFileResponse;
FileSystemErrorResponse;
};
sync protocol PFileSystemRequest
{
manager PContent;
child:
__delete__(FileSystemResponseValue response);
};
} // namespace dom
} // namespace mozilla

39
dom/filesystem/moz.build Normal file
View File

@ -0,0 +1,39 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS.mozilla.dom += [
'DeviceStorageFileSystem.h',
'Directory.h',
'FileSystemBase.h',
'FileSystemRequestParent.h',
'FileSystemTaskBase.h',
'FileSystemUtils.h',
]
SOURCES += [
'CreateDirectoryTask.cpp',
'DeviceStorageFileSystem.cpp',
'Directory.cpp',
'FileSystemBase.cpp',
'FileSystemPermissionRequest.cpp',
'FileSystemRequestParent.cpp',
'FileSystemTaskBase.cpp',
'FileSystemUtils.cpp',
'GetFileOrDirectoryTask.cpp',
]
FINAL_LIBRARY = 'gklayout'
IPDL_SOURCES += [
'PFileSystemRequest.ipdl',
]
include('/ipc/chromium/chromium-config.mozbuild')
LOCAL_INCLUDES += [
'/dom/base',
]

View File

@ -116,6 +116,8 @@
#include "mozilla/dom/indexedDB/PIndexedDBChild.h"
#include "mozilla/dom/mobilemessage/SmsChild.h"
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
#include "mozilla/dom/PFileSystemRequestChild.h"
#include "mozilla/dom/FileSystemTaskBase.h"
#include "mozilla/dom/bluetooth/PBluetoothChild.h"
#include "mozilla/dom/PFMRadioChild.h"
#include "mozilla/ipc/InputStreamUtils.h"
@ -1044,6 +1046,24 @@ ContentChild::DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild* aDev
return true;
}
PFileSystemRequestChild*
ContentChild::AllocPFileSystemRequestChild(const FileSystemParams& aParams)
{
NS_NOTREACHED("Should never get here!");
return nullptr;
}
bool
ContentChild::DeallocPFileSystemRequestChild(PFileSystemRequestChild* aFileSystem)
{
mozilla::dom::FileSystemTaskBase* child =
static_cast<mozilla::dom::FileSystemTaskBase*>(aFileSystem);
// The reference is increased in FileSystemTaskBase::Start of
// FileSystemTaskBase.cpp. We should decrease it after IPC.
NS_RELEASE(child);
return true;
}
PNeckoChild*
ContentChild::AllocPNeckoChild()
{

View File

@ -99,6 +99,9 @@ public:
virtual PDeviceStorageRequestChild* AllocPDeviceStorageRequestChild(const DeviceStorageParams&);
virtual bool DeallocPDeviceStorageRequestChild(PDeviceStorageRequestChild*);
virtual PFileSystemRequestChild* AllocPFileSystemRequestChild(const FileSystemParams&);
virtual bool DeallocPFileSystemRequestChild(PFileSystemRequestChild*);
virtual PBlobChild* AllocPBlobChild(const BlobConstructorParams& aParams);
virtual bool DeallocPBlobChild(PBlobChild*);

View File

@ -37,6 +37,7 @@
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
#include "mozilla/dom/GeolocationBinding.h"
#include "mozilla/dom/telephony/TelephonyParent.h"
#include "mozilla/dom/FileSystemRequestParent.h"
#include "SmsParent.h"
#include "mozilla/hal_sandbox/PHalParent.h"
#include "mozilla/ipc/BackgroundChild.h"
@ -2260,6 +2261,24 @@ ContentParent::DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent* d
return true;
}
PFileSystemRequestParent*
ContentParent::AllocPFileSystemRequestParent(const FileSystemParams& aParams)
{
nsRefPtr<FileSystemRequestParent> result = new FileSystemRequestParent();
if (!result->Dispatch(this, aParams)) {
return nullptr;
}
return result.forget().get();
}
bool
ContentParent::DeallocPFileSystemRequestParent(PFileSystemRequestParent* doomed)
{
FileSystemRequestParent* parent = static_cast<FileSystemRequestParent*>(doomed);
NS_RELEASE(parent);
return true;
}
PBlobParent*
ContentParent::AllocPBlobParent(const BlobConstructorParams& aParams)
{

View File

@ -346,6 +346,12 @@ private:
AllocPDeviceStorageRequestParent(const DeviceStorageParams&) MOZ_OVERRIDE;
virtual bool DeallocPDeviceStorageRequestParent(PDeviceStorageRequestParent*) MOZ_OVERRIDE;
virtual PFileSystemRequestParent*
AllocPFileSystemRequestParent(const FileSystemParams&) MOZ_OVERRIDE;
virtual bool
DeallocPFileSystemRequestParent(PFileSystemRequestParent*) MOZ_OVERRIDE;
virtual PBlobParent* AllocPBlobParent(const BlobConstructorParams& aParams) MOZ_OVERRIDE;
virtual bool DeallocPBlobParent(PBlobParent*) MOZ_OVERRIDE;

View File

@ -14,6 +14,7 @@ include protocol PCrashReporter;
include protocol PExternalHelperApp;
include protocol PDeviceStorageRequest;
include protocol PFMRadio;
include protocol PFileSystemRequest;
include protocol PHal;
include protocol PImageBridge;
include protocol PIndexedDB;
@ -193,6 +194,24 @@ union FMRadioRequestParams
FMRadioRequestCancelSeekParams;
};
struct FileSystemCreateDirectoryParams
{
nsString filesystem;
nsString realPath;
};
struct FileSystemGetFileOrDirectoryParams
{
nsString filesystem;
nsString realPath;
};
union FileSystemParams
{
FileSystemCreateDirectoryParams;
FileSystemGetFileOrDirectoryParams;
};
union PrefValue {
nsCString;
int32_t;
@ -222,6 +241,7 @@ intr protocol PContent
manages PBrowser;
manages PCrashReporter;
manages PDeviceStorageRequest;
manages PFileSystemRequest;
manages PExternalHelperApp;
manages PFMRadio;
manages PHal;
@ -371,6 +391,8 @@ parent:
PDeviceStorageRequest(DeviceStorageParams params);
PFileSystemRequest(FileSystemParams params);
sync PCrashReporter(NativeThreadId tid, uint32_t processType);
sync GetRandomValues(uint32_t length)

View File

@ -99,6 +99,7 @@ LOCAL_INCLUDES += [
'/dom/bluetooth/ipc',
'/dom/devicestorage',
'/dom/events',
'/dom/filesystem',
'/dom/fmradio/ipc',
'/dom/indexedDB',
'/dom/indexedDB/ipc',

View File

@ -14,7 +14,7 @@ dictionary SmsThreadListItem
unsigned long long unreadCount;
};
[scriptable, uuid(0ee2ada1-fa98-40f1-adb3-0d7fd6df3f48)]
[scriptable, uuid(46cf221e-9886-11e3-8039-171af7a2299e)]
interface nsIMobileMessageCallback : nsISupports
{
/**
@ -32,6 +32,7 @@ interface nsIMobileMessageCallback : nsISupports
const unsigned short INVALID_ADDRESS_ERROR = 7;
const unsigned short FDN_CHECK_ERROR = 8;
const unsigned short NON_ACTIVE_SIM_CARD_ERROR = 9;
const unsigned short STORAGE_FULL_ERROR = 10;
/**
* |message| can be nsIDOMMoz{Mms,Sms}Message.

View File

@ -25,7 +25,7 @@ interface nsIRilMobileMessageDatabaseRecordCallback : nsISupports
void notify(in nsresult aRv, in jsval aMessageRecord, in nsISupports aDomMessage);
};
[scriptable, uuid(a92eba51-e619-4f70-98c5-175a33590582)]
[scriptable, uuid(596ef782-9f7a-11e3-8508-ff3a7d599531)]
interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
{
/**
@ -119,4 +119,11 @@ interface nsIRilMobileMessageDatabaseService : nsIMobileMessageDatabaseService
*/
void getMessageRecordByTransactionId(in DOMString aTransactionId,
in nsIRilMobileMessageDatabaseRecordCallback aCallback);
/**
* |aCrError| nsresult: the NS_ERROR defined in Components.results.
*
* @returns the error code defined in nsIMobileMessageCallback
*/
jsval translateCrErrorToMessageCallbackError(in nsresult aCrError);
};

View File

@ -109,6 +109,9 @@ MobileMessageCallback::NotifyError(int32_t aError, bool aAsync)
case nsIMobileMessageCallback::NON_ACTIVE_SIM_CARD_ERROR:
errorStr = NS_LITERAL_STRING("NonActiveSimCardError");
break;
case nsIMobileMessageCallback::STORAGE_FULL_ERROR:
errorStr = NS_LITERAL_STRING("StorageFullError");
break;
default: // SUCCESS_NO_ERROR is handled above.
MOZ_CRASH("Should never get here!");
}

View File

@ -315,7 +315,7 @@ MmsConnection.prototype = {
getIccId: function() {
let iccInfo = this.radioInterface.rilContext.iccInfo;
if (!iccInfo || !(iccInfo instanceof Ci.nsIDOMMozGsmIccInfo)) {
if (!iccInfo) {
return null;
}
@ -1697,8 +1697,7 @@ MmsService.prototype = {
// At this point we could send a message to content to notify the user
// that storing an incoming MMS failed, most likely due to a full disk.
// The end user has to retrieve the MMS again.
if (DEBUG) debug("Could not store MMS " + domMessage.id +
", error code " + rv);
if (DEBUG) debug("Could not store MMS , error code " + rv);
return;
}
@ -1780,8 +1779,7 @@ MmsService.prototype = {
let transactionId = notification.headers["x-mms-transaction-id"];
gMobileMessageDatabaseService.getMessageRecordByTransactionId(transactionId,
(function(aRv, aMessageRecord) {
if (Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR === aRv
&& aMessageRecord) {
if (Components.isSuccessCode(aRv) && aMessageRecord) {
if (DEBUG) debug("We already got the NotificationIndication with transactionId = "
+ transactionId + " before.");
return;
@ -2171,9 +2169,16 @@ MmsService.prototype = {
gMobileMessageDatabaseService
.saveSendingMessage(savableMessage,
function notifySendingResult(aRv, aDomMessage) {
if (!Components.isSuccessCode(aRv)) {
if (DEBUG) debug("Error! Fail to save sending message! rv = " + aRv);
aRequest.notifySendMessageFailed(
gMobileMessageDatabaseService.translateCrErrorToMessageCallbackError(aRv));
Services.obs.notifyObservers(aDomMessage, kSmsFailedObserverTopic, null);
return;
}
if (DEBUG) debug("Saving sending message is done. Start to send.");
// TODO bug 832140 handle !Components.isSuccessCode(aRv)
Services.obs.notifyObservers(aDomMessage, kSmsSendingObserverTopic, null);
if (errorCode !== Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR) {
@ -2221,9 +2226,10 @@ MmsService.prototype = {
if (DEBUG) debug("Retrieving message with ID " + aMessageId);
gMobileMessageDatabaseService.getMessageRecordById(aMessageId,
(function notifyResult(aRv, aMessageRecord, aDomMessage) {
if (Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR != aRv) {
if (DEBUG) debug("Function getMessageRecordById() return error.");
aRequest.notifyGetMessageFailed(aRv);
if (!Components.isSuccessCode(aRv)) {
if (DEBUG) debug("Function getMessageRecordById() return error: " + aRv);
aRequest.notifyGetMessageFailed(
gMobileMessageDatabaseService.translateCrErrorToMessageCallbackError(aRv));
return;
}
if ("mms" != aMessageRecord.type) {
@ -2362,9 +2368,9 @@ MmsService.prototype = {
// At this point we could send a message to content to
// notify the user that storing an incoming MMS failed, most
// likely due to a full disk.
if (DEBUG) debug("Could not store MMS " + domMessage.id +
", error code " + rv);
aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
if (DEBUG) debug("Could not store MMS, error code " + rv);
aRequest.notifyGetMessageFailed(
gMobileMessageDatabaseService.translateCrErrorToMessageCallbackError(rv));
return;
}
@ -2396,9 +2402,9 @@ MmsService.prototype = {
(function(rv) {
let success = Components.isSuccessCode(rv);
if (!success) {
if (DEBUG) debug("Could not change the delivery status: MMS " +
domMessage.id + ", error code " + rv);
aRequest.notifyGetMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
if (DEBUG) debug("Could not change the delivery status, error code " + rv);
aRequest.notifyGetMessageFailed(
gMobileMessageDatabaseService.translateCrErrorToMessageCallbackError(rv));
return;
}

View File

@ -93,6 +93,13 @@ MobileMessageDB.prototype = {
*/
lastMessageId: 0,
/**
* An optional hook to check if device storage is full.
*
* @return true if full.
*/
isDiskFull: null,
/**
* Prepare the database. This may include opening the database and upgrading
* it to the latest schema version.
@ -238,7 +245,8 @@ MobileMessageDB.prototype = {
break;
default:
event.target.transaction.abort();
callback("Old database version: " + event.oldVersion, null);
if (DEBUG) debug("unexpected db version: " + event.oldVersion);
callback(Cr.NS_ERROR_FAILURE, null);
break;
}
}
@ -247,10 +255,12 @@ MobileMessageDB.prototype = {
};
request.onerror = function(event) {
//TODO look at event.target.Code and change error constant accordingly
callback("Error opening database!", null);
if (DEBUG) debug("Error opening database!");
callback(Cr.NS_ERROR_FAILURE, null);
};
request.onblocked = function(event) {
callback("Opening database request is blocked.", null);
if (DEBUG) debug("Opening database request is blocked.");
callback(Cr.NS_ERROR_FAILURE, null);
};
},
@ -270,7 +280,13 @@ MobileMessageDB.prototype = {
storeNames = [MESSAGE_STORE_NAME];
}
if (DEBUG) debug("Opening transaction for object stores: " + storeNames);
let self = this;
this.ensureDB(function(error, db) {
if (!error &&
txn_type === READ_WRITE &&
self.isDiskFull && self.isDiskFull()) {
error = Cr.NS_ERROR_FILE_NO_DEVICE_SPACE;
}
if (error) {
if (DEBUG) debug("Could not open database: " + error);
callback(error);
@ -1645,8 +1661,7 @@ MobileMessageDB.prototype = {
};
if (aError) {
// TODO bug 832140 check event.target.errorCode
notifyResult(Cr.NS_ERROR_FAILURE, null);
notifyResult(aError, null);
return;
}
@ -1678,8 +1693,7 @@ MobileMessageDB.prototype = {
};
if (error) {
// TODO bug 832140 check event.target.errorCode
notifyResult(Cr.NS_ERROR_FAILURE, null);
notifyResult(error, null);
return;
}
@ -2323,7 +2337,7 @@ MobileMessageDB.prototype = {
this.newTxn(READ_ONLY, function(error, txn, messageStore) {
if (error) {
if (DEBUG) debug(error);
aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null);
aCallback.notify(error, null, null);
return;
}
let request = messageStore.index("transactionId").get(aTransactionId);
@ -2333,13 +2347,12 @@ MobileMessageDB.prototype = {
let messageRecord = request.result;
if (!messageRecord) {
if (DEBUG) debug("Transaction ID " + aTransactionId + " not found");
aCallback.notify(Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR, null, null);
aCallback.notify(Cr.NS_ERROR_FILE_NOT_FOUND, null, null);
return;
}
// In this case, we don't need a dom message. Just pass null to the
// third argument.
aCallback.notify(Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR,
messageRecord, null);
aCallback.notify(Cr.NS_OK, messageRecord, null);
};
txn.onerror = function onerror(event) {
@ -2348,7 +2361,7 @@ MobileMessageDB.prototype = {
debug("Caught error on transaction", event.target.errorCode);
}
}
aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null);
aCallback.notify(Cr.NS_ERROR_FAILURE, null, null);
};
});
},
@ -2359,7 +2372,7 @@ MobileMessageDB.prototype = {
this.newTxn(READ_ONLY, function(error, txn, messageStore) {
if (error) {
if (DEBUG) debug(error);
aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null);
aCallback.notify(error, null, null);
return;
}
let request = messageStore.mozGetAll(aMessageId);
@ -2368,13 +2381,13 @@ MobileMessageDB.prototype = {
if (DEBUG) debug("Transaction " + txn + " completed.");
if (request.result.length > 1) {
if (DEBUG) debug("Got too many results for id " + aMessageId);
aCallback.notify(Ci.nsIMobileMessageCallback.UNKNOWN_ERROR, null, null);
aCallback.notify(Cr.NS_ERROR_UNEXPECTED, null, null);
return;
}
let messageRecord = request.result[0];
if (!messageRecord) {
if (DEBUG) debug("Message ID " + aMessageId + " not found");
aCallback.notify(Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR, null, null);
aCallback.notify(Cr.NS_ERROR_FILE_NOT_FOUND, null, null);
return;
}
if (messageRecord.id != aMessageId) {
@ -2382,12 +2395,11 @@ MobileMessageDB.prototype = {
debug("Requested message ID (" + aMessageId + ") is " +
"different from the one we got");
}
aCallback.notify(Ci.nsIMobileMessageCallback.UNKNOWN_ERROR, null, null);
aCallback.notify(Cr.NS_ERROR_UNEXPECTED, null, null);
return;
}
let domMessage = self.createDomMessageFromRecord(messageRecord);
aCallback.notify(Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR,
messageRecord, domMessage);
aCallback.notify(Cr.NS_OK, messageRecord, domMessage);
};
txn.onerror = function onerror(event) {
@ -2396,24 +2408,41 @@ MobileMessageDB.prototype = {
debug("Caught error on transaction", event.target.errorCode);
}
}
aCallback.notify(Ci.nsIMobileMessageCallback.INTERNAL_ERROR, null, null);
aCallback.notify(Cr.NS_ERROR_FAILURE, null, null);
};
});
},
translateCrErrorToMessageCallbackError: function(aCrError) {
switch(aCrError) {
case Cr.NS_OK:
return Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR;
case Cr.NS_ERROR_UNEXPECTED:
return Ci.nsIMobileMessageCallback.UNKNOWN_ERROR;
case Cr.NS_ERROR_FILE_NOT_FOUND:
return Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR;
case Cr.NS_ERROR_FILE_NO_DEVICE_SPACE:
return Ci.nsIMobileMessageCallback.STORAGE_FULL_ERROR;
default:
return Ci.nsIMobileMessageCallback.INTERNAL_ERROR;
}
},
/**
* nsIMobileMessageDatabaseService API
*/
getMessage: function(aMessageId, aRequest) {
if (DEBUG) debug("Retrieving message with ID " + aMessageId);
let self = this;
let notifyCallback = {
notify: function(aRv, aMessageRecord, aDomMessage) {
if (Ci.nsIMobileMessageCallback.SUCCESS_NO_ERROR == aRv) {
if (Cr.NS_OK == aRv) {
aRequest.notifyMessageGot(aDomMessage);
return;
}
aRequest.notifyGetMessageFailed(aRv, null);
aRequest.notifyGetMessageFailed(
self.translateCrErrorToMessageCallbackError(aRv), null);
}
};
this.getMessageRecordById(aMessageId, notifyCallback);
@ -2426,7 +2455,8 @@ MobileMessageDB.prototype = {
this.newTxn(READ_WRITE, function(error, txn, stores) {
if (error) {
if (DEBUG) debug("deleteMessage: failed to open transaction");
aRequest.notifyDeleteMessageFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
aRequest.notifyDeleteMessageFailed(
self.translateCrErrorToMessageCallbackError(error));
return;
}
txn.onerror = function onerror(event) {
@ -2502,10 +2532,12 @@ MobileMessageDB.prototype = {
markMessageRead: function(messageId, value, aSendReadReport, aRequest) {
if (DEBUG) debug("Setting message " + messageId + " read to " + value);
let self = this;
this.newTxn(READ_WRITE, function(error, txn, stores) {
if (error) {
if (DEBUG) debug(error);
aRequest.notifyMarkMessageReadFailed(Ci.nsIMobileMessageCallback.INTERNAL_ERROR);
aRequest.notifyMarkMessageReadFailed(
self.translateCrErrorToMessageCallbackError(error));
return;
}
@ -2597,7 +2629,6 @@ MobileMessageDB.prototype = {
this.newTxn(READ_ONLY, function(error, txn, threadStore) {
let collector = cursor.collector;
if (error) {
if (DEBUG) debug(error);
collector.collect(null, COLLECT_ID_ERROR, COLLECT_TIMESTAMP_UNUSED);
return;
}

View File

@ -17,6 +17,10 @@ const RIL_MOBILEMESSAGEDATABASESERVICE_CONTRACTID =
const RIL_MOBILEMESSAGEDATABASESERVICE_CID =
Components.ID("{29785f90-6b5b-11e2-9201-3b280170b2ec}");
XPCOMUtils.defineLazyServiceGetter(this, "gDiskSpaceWatcher",
"@mozilla.org/toolkit/disk-space-watcher;1",
"nsIDiskSpaceWatcher");
const DB_NAME = "sms";
/**
@ -29,6 +33,9 @@ function MobileMessageDatabaseService() {
let mmdb = new MMDB.MobileMessageDB();
mmdb.init(DB_NAME, 0, mmdb.updatePendingTransactionToError.bind(mmdb));
mmdb.isDiskFull = function() {
return gDiskSpaceWatcher.isDiskFull;
};
this.mmdb = mmdb;
}
MobileMessageDatabaseService.prototype = {
@ -88,6 +95,10 @@ MobileMessageDatabaseService.prototype = {
this.mmdb.getMessageRecordById(aMessageId, aCallback);
},
translateCrErrorToMessageCallbackError: function(aCrError) {
return this.mmdb.translateCrErrorToMessageCallbackError(aCrError);
},
/**
* nsIMobileMessageDatabaseService API
*/

View File

@ -42,4 +42,5 @@ qemu = true
[test_mmdb_new.js]
[test_mmdb_setmessagedeliverybyid_sms.js]
[test_mmdb_foreachmatchedmmsdeliveryinfo.js]
[test_mmdb_full_storage.js]
[test_replace_short_message_type.js]

View File

@ -0,0 +1,89 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 60000;
MARIONETTE_HEAD_JS = 'head.js';
let gMmdb;
let gIsDiskFull = true;
let gMessageToSave = {
type: "sms",
sender: "+0987654321",
receiver: "+1234567890",
body: "quick fox jump over the lazy dog",
deliveryStatusRequested: false,
timestamp: Date.now(),
iccId: "1029384756"
};
function testSaveSendingMessage() {
log("testSaveSendingMessage()");
let deferred = Promise.defer();
gMmdb.saveSendingMessage(gMessageToSave,
{ notify : function(aRv, aDomMessage) {
if (aRv === Cr.NS_ERROR_FILE_NO_DEVICE_SPACE) {
ok(true, "Forbidden due to storage full.");
deferred.resolve(Promise.resolve());
} else {
ok(false, "Unexpected result: " + aRv);
deferred.reject(aRv);
}
}});
return deferred.promise;
}
function testSaveReceivingMessage() {
log("testSaveReceivingMessage()");
let deferred = Promise.defer();
gMmdb.saveReceivedMessage(gMessageToSave,
{ notify : function(aRv, aDomMessage) {
if (aRv === Cr.NS_ERROR_FILE_NO_DEVICE_SPACE) {
ok(true, "Forbidden due to storage full.");
deferred.resolve(Promise.resolve());
} else {
ok(false, "Unexpected result: " + aRv);
deferred.reject(aRv);
}
}});
return deferred.promise;
}
function testGetMessage() {
log("testGetMessage()");
let deferred = Promise.defer();
gMmdb.getMessage(1,
{ notifyGetMessageFailed : function(aRv) {
if (aRv === Ci.nsIMobileMessageCallback.NOT_FOUND_ERROR) {
ok(true, "Getting message successfully!");
deferred.resolve(Promise.resolve());
} else {
ok(false, "Unexpected result: " + aRv);
deferred.reject(aRv);
}
}});
return deferred.promise;
}
startTestBase(function testCaseMain() {
gMmdb = newMobileMessageDB();
gMmdb.isDiskFull = function() {
return gIsDiskFull;
};
return initMobileMessageDB(gMmdb, "test_gMmdb_full_storage", 0)
.then(testSaveSendingMessage)
.then(testSaveReceivingMessage)
.then(testGetMessage)
.then(closeMobileMessageDB.bind(null, gMmdb));
});

View File

@ -50,6 +50,7 @@ PARALLEL_DIRS += [
'encoding',
'events',
'file',
'filesystem',
'fmradio',
'asmjscache',
'media',

View File

@ -201,6 +201,22 @@ private:
return WrapNewBindingObject(aCx, scope, aArgument, aValue);
}
// Accept objects that inherit from nsISupports but not nsWrapperCache (e.g.
// nsIDOMFile).
template <class T>
typename EnableIf<!IsBaseOf<nsWrapperCache, T>::value &&
IsBaseOf<nsISupports, T>::value, bool>::Type
ArgumentToJSValue(T& aArgument,
JSContext* aCx,
JSObject* aScope,
JS::MutableHandle<JS::Value> aValue)
{
JS::Rooted<JSObject*> scope(aCx, aScope);
nsresult rv = nsContentUtils::WrapNative(aCx, scope, &aArgument, aValue);
return NS_SUCCEEDED(rv);
}
template <template <typename> class SmartPtr, typename T>
bool
ArgumentToJSValue(const SmartPtr<T>& aArgument,

View File

@ -2293,7 +2293,7 @@ RadioInterface.prototype = {
getIccId: function() {
let iccInfo = this.rilContext.iccInfo;
if (!iccInfo || !(iccInfo instanceof GsmIccInfo)) {
if (!iccInfo) {
return null;
}
@ -3933,7 +3933,14 @@ RadioInterface.prototype = {
}
let notifyResult = (function notifyResult(rv, domMessage) {
// TODO bug 832140 handle !Components.isSuccessCode(rv)
if (!Components.isSuccessCode(rv)) {
if (DEBUG) this.debug("Error! Fail to save sending message! rv = " + rv);
request.notifySendMessageFailed(
gMobileMessageDatabaseService.translateCrErrorToMessageCallbackError(rv));
Services.obs.notifyObservers(domMessage, kSmsFailedObserverTopic, null);
return;
}
if (!silent) {
Services.obs.notifyObservers(domMessage, kSmsSendingObserverTopic, null);
}

View File

@ -55,4 +55,7 @@ interface DeviceStorage : EventTarget {
// Determines if this storage area is the one which will be used by default
// for storing new files.
readonly attribute boolean default;
[NewObject]
Promise getRoot();
};

View File

@ -0,0 +1,49 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
interface File;
/*
* All functions on Directory that accept DOMString arguments for file or
* directory names only allow relative path to current directory itself. The
* path should be a descendent path like "path/to/file.txt" and not contain a
* segment of ".." or ".". So the paths aren't allowd to walk up the directory
* tree. For example, paths like "../foo", "..", "/foo/bar" or "foo/../bar" are
* not allowed.
*/
[NoInterfaceObject]
interface Directory {
/*
* The leaf name of the directory.
*/
readonly attribute DOMString name;
/*
* Creates a descendent directory. This method will create any intermediate
* directories specified by the path segments.
*
* @param path The relative path of the new directory to current directory.
* If path exists, createDirectory must fail.
* @return If succeeds, the promise is resolved with the new created
* Directory object. Otherwise, rejected with a DOM error.
*/
[NewObject]
// Promise<Directory>
Promise createDirectory(DOMString path);
/*
* Gets a descendent file or directory with the given path.
*
* @param path The descendent entry's relative path to current directory.
* @return If the path exists and no error occurs, the promise is resolved
* with a File or Directory object, depending on the entry's type. Otherwise,
* rejected with a DOM error.
*/
[NewObject]
// Promise<(File or Directory)>
Promise get(DOMString path);
};

View File

@ -73,6 +73,7 @@ WEBIDL_FILES = [
'DesktopNotification.webidl',
'DeviceMotionEvent.webidl',
'DeviceStorage.webidl',
'Directory.webidl',
'Document.webidl',
'DocumentFragment.webidl',
'DocumentType.webidl',

View File

@ -311,6 +311,7 @@ public class GeckoSmsManager
public final static int kInvalidAddressError = 7;
public final static int kFdnCheckError = 8;
public final static int kNonActiveSimCardError = 9;
public final static int kStorageFullError = 10;
private final static int kMaxMessageSize = 160;

View File

@ -1228,7 +1228,7 @@ EnsureKernelLowMemKillerParamsSet()
nsAutoCString minfreeParams;
int32_t lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1;
int32_t lowerBoundOfNextKillUnderMB = 0;
int32_t lowerBoundOfNextKillUnderKB = 0;
int32_t countOfLowmemorykillerParametersSets = 0;
for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) {
@ -1245,18 +1245,18 @@ EnsureKernelLowMemKillerParamsSet()
MOZ_CRASH();
}
int32_t killUnderMB;
int32_t killUnderKB;
if (!NS_SUCCEEDED(Preferences::GetInt(
nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderMB",
nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
ProcessPriorityToString(priority)).get(),
&killUnderMB))) {
&killUnderKB))) {
continue;
}
// The LMK in kernel silently malfunctions if we assign the parameters
// in non-increasing order, so we add this assertion here. See bug 887192.
MOZ_ASSERT(oomScoreAdj > lowerBoundOfNextOomScoreAdj);
MOZ_ASSERT(killUnderMB > lowerBoundOfNextKillUnderMB);
MOZ_ASSERT(killUnderKB > lowerBoundOfNextKillUnderKB);
// The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728.
MOZ_ASSERT(countOfLowmemorykillerParametersSets < 6);
@ -1265,10 +1265,10 @@ EnsureKernelLowMemKillerParamsSet()
adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj));
// minfree is in pages.
minfreeParams.AppendPrintf("%d,", killUnderMB * 1024 * 1024 / PAGE_SIZE);
minfreeParams.AppendPrintf("%d,", killUnderKB * 1024 / PAGE_SIZE);
lowerBoundOfNextOomScoreAdj = oomScoreAdj;
lowerBoundOfNextKillUnderMB = killUnderMB;
lowerBoundOfNextKillUnderKB = killUnderKB;
countOfLowmemorykillerParametersSets++;
}
@ -1281,14 +1281,14 @@ EnsureKernelLowMemKillerParamsSet()
}
// Set the low-memory-notification threshold.
int32_t lowMemNotifyThresholdMB;
int32_t lowMemNotifyThresholdKB;
if (NS_SUCCEEDED(Preferences::GetInt(
"hal.processPriorityManager.gonk.notifyLowMemUnderMB",
&lowMemNotifyThresholdMB))) {
"hal.processPriorityManager.gonk.notifyLowMemUnderKB",
&lowMemNotifyThresholdKB))) {
// notify_trigger is in pages.
WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger",
nsPrintfCString("%d", lowMemNotifyThresholdMB * 1024 * 1024 / PAGE_SIZE).get());
nsPrintfCString("%d", lowMemNotifyThresholdKB * 1024 / PAGE_SIZE).get());
}
// Ensure OOM events appear in logcat

View File

@ -396,11 +396,9 @@ int32_t GeckoChildProcessHost::mChildCounter = 0;
bool
GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, base::ProcessArchitecture arch)
{
// If separate NSPR log files are not requested, we're done.
// If NSPR log files are not requested, we're done.
const char* origLogName = PR_GetEnv("NSPR_LOG_FILE");
const char* separateLogs = PR_GetEnv("GECKO_SEPARATE_NSPR_LOGS");
if (!origLogName || !separateLogs || !*separateLogs ||
*separateLogs == '0' || *separateLogs == 'N' || *separateLogs == 'n') {
if (!origLogName) {
return PerformAsyncLaunchInternal(aExtraOpts, arch);
}

View File

@ -1172,6 +1172,8 @@ JSContext::saveFrameChain()
void
JSContext::restoreFrameChain()
{
JS_ASSERT(enterCompartmentDepth_ == 0); // We're about to clobber it, and it
// will be wrong forevermore.
SavedFrameChain sfc = savedFrameChains_.popCopy();
setCompartment(sfc.compartment);
enterCompartmentDepth_ = sfc.enterCompartmentCount;

View File

@ -53,6 +53,7 @@ LOCAL_INCLUDES += [
'/dom/camera',
'/dom/events',
'/dom/file',
'/dom/filesystem',
'/dom/media',
'/dom/speakermanager',
'/dom/src/geolocation',

View File

@ -68,7 +68,7 @@ namespace detail {
* For more details, and examples of using these macros, see
* https://developer.mozilla.org/en/Using_RAII_classes_in_Mozilla
*/
class MOZ_EXPORT GuardObjectNotifier
class GuardObjectNotifier
{
private:
bool* statementDone;
@ -85,7 +85,7 @@ class MOZ_EXPORT GuardObjectNotifier
}
};
class MOZ_EXPORT GuardObjectNotificationReceiver
class GuardObjectNotificationReceiver
{
private:
bool statementDone;

View File

@ -305,6 +305,7 @@ public class GeckoSmsManager
public final static int kInvalidAddressError = 7;
public final static int kFdnCheckError = 8;
public final static int kNonActiveSimCardError = 9;
public final static int kStorageFullError = 10;
private final static int kMaxMessageSize = 160;

View File

@ -52,7 +52,6 @@ chrome-shared_PATH := $(CHROMETESTROOT)/chrome
_CHROME_DATA := \
simple.mar \
simple_no_pib.mar \
$(NULL)
INSTALL_TARGETS += chrome-data
chrome-data_TARGET := libs

View File

@ -1,5 +0,0 @@
rename_file: proceeding to rename the directory
rename_file: proceeding to rename the directory
Now, remove the tmpDir
succeeded
calling QuitProgressUI

View File

@ -1,19 +1,13 @@
UPDATE TYPE complete
PREPARE REMOVEFILE precomplete
PREPARE REMOVEFILE a/b/searchplugins/searchpluginstext0
PREPARE REMOVEFILE a/b/searchplugins/searchpluginspng0.png
PREPARE REMOVEFILE a/b/removed-files
PREPARE REMOVEFILE a/b/extensions/extensions1/extensions1png1.png
PREPARE REMOVEFILE a/b/extensions/extensions0/extensions0text0
PREPARE REMOVEFILE a/b/exe0.exe
PREPARE REMOVEFILE a/b/2/20/20text0
PREPARE REMOVEFILE a/b/2/20/20png0.png
PREPARE REMOVEFILE a/b/0/0exe0.exe
PREPARE REMOVEFILE a/b/0/00/00text0
PREPARE REMOVEDIR a/b/searchplugins/
PREPARE REMOVEDIR a/b/extensions/extensions1/
PREPARE REMOVEDIR a/b/extensions/extensions0/
PREPARE REMOVEDIR a/b/extensions/
PREPARE REMOVEDIR a/b/defaults/pref/
PREPARE REMOVEDIR a/b/defaults/
PREPARE REMOVEDIR a/b/2/20/
@ -27,13 +21,13 @@ PREPARE ADD a/b/searchplugins/searchpluginstext0
PREPARE ADD a/b/searchplugins/searchpluginspng1.png
PREPARE ADD a/b/searchplugins/searchpluginspng0.png
PREPARE ADD a/b/removed-files
PREPARE ADD a/b/extensions/extensions1/extensions1text0
PREPARE ADD a/b/extensions/extensions1/extensions1png1.png
PREPARE ADD a/b/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/extensions/extensions0/extensions0text0
PREPARE ADD a/b/extensions/extensions0/extensions0png1.png
PREPARE ADD a/b/extensions/extensions0/extensions0png0.png
PREPARE ADD a/b/exe0.exe
PREPARE ADD a/b/distribution/extensions/extensions1/extensions1text0
PREPARE ADD a/b/distribution/extensions/extensions1/extensions1png1.png
PREPARE ADD a/b/distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/distribution/extensions/extensions0/extensions0text0
PREPARE ADD a/b/distribution/extensions/extensions0/extensions0png1.png
PREPARE ADD a/b/distribution/extensions/extensions0/extensions0png0.png
PREPARE ADD a/b/1/10/10text0
PREPARE ADD a/b/0/0exe0.exe
PREPARE ADD a/b/0/00/00text1
@ -104,21 +98,15 @@ PREPARE REMOVEFILE a/b/4/4text0
PREPARE REMOVEDIR a/b/4/
PREPARE REMOVEFILE a/b/3/3text1
PREPARE REMOVEFILE a/b/3/3text0
EXECUTE REMOVEFILE precomplete
EXECUTE REMOVEFILE a/b/searchplugins/searchpluginstext0
EXECUTE REMOVEFILE a/b/searchplugins/searchpluginspng0.png
EXECUTE REMOVEFILE a/b/removed-files
EXECUTE REMOVEFILE a/b/extensions/extensions1/extensions1png1.png
EXECUTE REMOVEFILE a/b/extensions/extensions0/extensions0text0
EXECUTE REMOVEFILE a/b/exe0.exe
EXECUTE REMOVEFILE a/b/2/20/20text0
EXECUTE REMOVEFILE a/b/2/20/20png0.png
EXECUTE REMOVEFILE a/b/0/0exe0.exe
EXECUTE REMOVEFILE a/b/0/00/00text0
EXECUTE REMOVEDIR a/b/searchplugins/
EXECUTE REMOVEDIR a/b/extensions/extensions1/
EXECUTE REMOVEDIR a/b/extensions/extensions0/
EXECUTE REMOVEDIR a/b/extensions/
EXECUTE REMOVEDIR a/b/defaults/pref/
EXECUTE REMOVEDIR a/b/defaults/
EXECUTE REMOVEDIR a/b/2/20/
@ -132,13 +120,13 @@ EXECUTE ADD a/b/searchplugins/searchpluginstext0
EXECUTE ADD a/b/searchplugins/searchpluginspng1.png
EXECUTE ADD a/b/searchplugins/searchpluginspng0.png
EXECUTE ADD a/b/removed-files
EXECUTE ADD a/b/extensions/extensions1/extensions1text0
EXECUTE ADD a/b/extensions/extensions1/extensions1png1.png
EXECUTE ADD a/b/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/extensions/extensions0/extensions0text0
EXECUTE ADD a/b/extensions/extensions0/extensions0png1.png
EXECUTE ADD a/b/extensions/extensions0/extensions0png0.png
EXECUTE ADD a/b/exe0.exe
EXECUTE ADD a/b/distribution/extensions/extensions1/extensions1text0
EXECUTE ADD a/b/distribution/extensions/extensions1/extensions1png1.png
EXECUTE ADD a/b/distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/distribution/extensions/extensions0/extensions0text0
EXECUTE ADD a/b/distribution/extensions/extensions0/extensions0png1.png
EXECUTE ADD a/b/distribution/extensions/extensions0/extensions0png0.png
EXECUTE ADD a/b/1/10/10text0
EXECUTE ADD a/b/0/0exe0.exe
EXECUTE ADD a/b/0/00/00text1
@ -211,12 +199,9 @@ EXECUTE REMOVEFILE a/b/4/4text0
EXECUTE REMOVEDIR a/b/4/
EXECUTE REMOVEFILE a/b/3/3text1
EXECUTE REMOVEFILE a/b/3/3text0
FINISH REMOVEFILE precomplete
FINISH REMOVEFILE a/b/searchplugins/searchpluginstext0
FINISH REMOVEFILE a/b/searchplugins/searchpluginspng0.png
FINISH REMOVEFILE a/b/removed-files
FINISH REMOVEFILE a/b/extensions/extensions1/extensions1png1.png
FINISH REMOVEFILE a/b/extensions/extensions0/extensions0text0
FINISH REMOVEFILE a/b/exe0.exe
FINISH REMOVEFILE a/b/2/20/20text0
FINISH REMOVEFILE a/b/2/20/20png0.png
@ -224,12 +209,6 @@ FINISH REMOVEFILE a/b/0/0exe0.exe
FINISH REMOVEFILE a/b/0/00/00text0
FINISH REMOVEDIR a/b/searchplugins/
removing directory: a/b/searchplugins/, rv: 0
FINISH REMOVEDIR a/b/extensions/extensions1/
removing directory: a/b/extensions/extensions1/, rv: 0
FINISH REMOVEDIR a/b/extensions/extensions0/
removing directory: a/b/extensions/extensions0/, rv: 0
FINISH REMOVEDIR a/b/extensions/
removing directory: a/b/extensions/, rv: 0
FINISH REMOVEDIR a/b/defaults/pref/
removing directory: a/b/defaults/pref/, rv: 0
FINISH REMOVEDIR a/b/defaults/
@ -249,13 +228,13 @@ FINISH ADD a/b/searchplugins/searchpluginstext0
FINISH ADD a/b/searchplugins/searchpluginspng1.png
FINISH ADD a/b/searchplugins/searchpluginspng0.png
FINISH ADD a/b/removed-files
FINISH ADD a/b/extensions/extensions1/extensions1text0
FINISH ADD a/b/extensions/extensions1/extensions1png1.png
FINISH ADD a/b/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/extensions/extensions0/extensions0text0
FINISH ADD a/b/extensions/extensions0/extensions0png1.png
FINISH ADD a/b/extensions/extensions0/extensions0png0.png
FINISH ADD a/b/exe0.exe
FINISH ADD a/b/distribution/extensions/extensions1/extensions1text0
FINISH ADD a/b/distribution/extensions/extensions1/extensions1png1.png
FINISH ADD a/b/distribution/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/distribution/extensions/extensions0/extensions0text0
FINISH ADD a/b/distribution/extensions/extensions0/extensions0png1.png
FINISH ADD a/b/distribution/extensions/extensions0/extensions0png0.png
FINISH ADD a/b/1/10/10text0
FINISH ADD a/b/0/0exe0.exe
FINISH ADD a/b/0/00/00text1

View File

@ -1,345 +0,0 @@
UPDATE TYPE complete
PREPARE REMOVEFILE precomplete
PREPARE REMOVEFILE a/b/searchplugins/searchpluginstext0
PREPARE REMOVEFILE a/b/searchplugins/searchpluginspng0.png
PREPARE REMOVEFILE a/b/removed-files
PREPARE REMOVEFILE a/b/extensions/extensions1/extensions1png1.png
PREPARE REMOVEFILE a/b/extensions/extensions0/extensions0text0
PREPARE REMOVEFILE a/b/exe0.exe
PREPARE REMOVEFILE a/b/2/20/20text0
PREPARE REMOVEFILE a/b/2/20/20png0.png
PREPARE REMOVEFILE a/b/0/0exe0.exe
PREPARE REMOVEFILE a/b/0/00/00text0
PREPARE REMOVEDIR a/b/searchplugins/
PREPARE REMOVEDIR a/b/extensions/extensions1/
PREPARE REMOVEDIR a/b/extensions/extensions0/
PREPARE REMOVEDIR a/b/extensions/
PREPARE REMOVEDIR a/b/defaults/pref/
PREPARE REMOVEDIR a/b/defaults/
PREPARE REMOVEDIR a/b/2/20/
PREPARE REMOVEDIR a/b/2/
PREPARE REMOVEDIR a/b/0/00/
PREPARE REMOVEDIR a/b/0/
PREPARE REMOVEDIR a/b/
PREPARE REMOVEDIR a/
PREPARE ADD precomplete
PREPARE ADD a/b/searchplugins/searchpluginstext0
PREPARE ADD a/b/searchplugins/searchpluginspng1.png
PREPARE ADD a/b/searchplugins/searchpluginspng0.png
PREPARE ADD a/b/removed-files
PREPARE ADD a/b/extensions/extensions1/extensions1text0
PREPARE ADD a/b/extensions/extensions1/extensions1png1.png
PREPARE ADD a/b/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/extensions/extensions0/extensions0text0
PREPARE ADD a/b/extensions/extensions0/extensions0png1.png
PREPARE ADD a/b/extensions/extensions0/extensions0png0.png
PREPARE ADD a/b/exe0.exe
PREPARE ADD a/b/1/10/10text0
PREPARE ADD a/b/0/0exe0.exe
PREPARE ADD a/b/0/00/00text1
PREPARE ADD a/b/0/00/00text0
PREPARE ADD a/b/0/00/00png0.png
PREPARE REMOVEDIR a/b/9/99/
PREPARE REMOVEDIR a/b/9/99/
PREPARE REMOVEDIR a/b/9/98/
PREPARE REMOVEFILE a/b/9/97/970/97xtext0
PREPARE REMOVEFILE a/b/9/97/970/97xtext1
PREPARE REMOVEDIR a/b/9/97/970/
PREPARE REMOVEFILE a/b/9/97/971/97xtext0
PREPARE REMOVEFILE a/b/9/97/971/97xtext1
PREPARE REMOVEDIR a/b/9/97/971/
PREPARE REMOVEDIR a/b/9/97/
PREPARE REMOVEFILE a/b/9/96/96text0
PREPARE REMOVEFILE a/b/9/96/96text1
PREPARE REMOVEDIR a/b/9/96/
PREPARE REMOVEDIR a/b/9/95/
PREPARE REMOVEDIR a/b/9/95/
PREPARE REMOVEDIR a/b/9/94/
PREPARE REMOVEDIR a/b/9/94/
PREPARE REMOVEDIR a/b/9/93/
PREPARE REMOVEDIR a/b/9/92/
PREPARE REMOVEDIR a/b/9/91/
PREPARE REMOVEDIR a/b/9/90/
PREPARE REMOVEDIR a/b/9/90/
PREPARE REMOVEDIR a/b/8/89/
PREPARE REMOVEDIR a/b/8/89/
PREPARE REMOVEDIR a/b/8/88/
PREPARE REMOVEFILE a/b/8/87/870/87xtext0
PREPARE REMOVEFILE a/b/8/87/870/87xtext1
PREPARE REMOVEDIR a/b/8/87/870/
PREPARE REMOVEFILE a/b/8/87/871/87xtext0
PREPARE REMOVEFILE a/b/8/87/871/87xtext1
PREPARE REMOVEDIR a/b/8/87/871/
PREPARE REMOVEDIR a/b/8/87/
PREPARE REMOVEFILE a/b/8/86/86text0
PREPARE REMOVEFILE a/b/8/86/86text1
PREPARE REMOVEDIR a/b/8/86/
PREPARE REMOVEDIR a/b/8/85/
PREPARE REMOVEDIR a/b/8/85/
PREPARE REMOVEDIR a/b/8/84/
PREPARE REMOVEDIR a/b/8/84/
PREPARE REMOVEDIR a/b/8/83/
PREPARE REMOVEDIR a/b/8/82/
PREPARE REMOVEDIR a/b/8/81/
PREPARE REMOVEDIR a/b/8/80/
PREPARE REMOVEDIR a/b/8/80/
PREPARE REMOVEFILE a/b/7/70/7xtest.exe
PREPARE REMOVEFILE a/b/7/70/7xtext0
PREPARE REMOVEFILE a/b/7/70/7xtext1
PREPARE REMOVEDIR a/b/7/70/
PREPARE REMOVEFILE a/b/7/71/7xtest.exe
PREPARE REMOVEFILE a/b/7/71/7xtext0
PREPARE REMOVEFILE a/b/7/71/7xtext1
PREPARE REMOVEDIR a/b/7/71/
PREPARE REMOVEDIR a/b/7/
PREPARE REMOVEDIR a/b/6/
PREPARE REMOVEFILE a/b/5/5text1
PREPARE REMOVEFILE a/b/5/5text0
PREPARE REMOVEFILE a/b/5/5test.exe
PREPARE REMOVEFILE a/b/5/5text0
PREPARE REMOVEFILE a/b/5/5text1
PREPARE REMOVEDIR a/b/5/
PREPARE REMOVEFILE a/b/4/4text1
PREPARE REMOVEFILE a/b/4/4text0
PREPARE REMOVEDIR a/b/4/
PREPARE REMOVEFILE a/b/3/3text1
PREPARE REMOVEFILE a/b/3/3text0
EXECUTE REMOVEFILE precomplete
EXECUTE REMOVEFILE a/b/searchplugins/searchpluginstext0
EXECUTE REMOVEFILE a/b/searchplugins/searchpluginspng0.png
EXECUTE REMOVEFILE a/b/removed-files
EXECUTE REMOVEFILE a/b/extensions/extensions1/extensions1png1.png
EXECUTE REMOVEFILE a/b/extensions/extensions0/extensions0text0
EXECUTE REMOVEFILE a/b/exe0.exe
EXECUTE REMOVEFILE a/b/2/20/20text0
EXECUTE REMOVEFILE a/b/2/20/20png0.png
EXECUTE REMOVEFILE a/b/0/0exe0.exe
EXECUTE REMOVEFILE a/b/0/00/00text0
EXECUTE REMOVEDIR a/b/searchplugins/
EXECUTE REMOVEDIR a/b/extensions/extensions1/
EXECUTE REMOVEDIR a/b/extensions/extensions0/
EXECUTE REMOVEDIR a/b/extensions/
EXECUTE REMOVEDIR a/b/defaults/pref/
EXECUTE REMOVEDIR a/b/defaults/
EXECUTE REMOVEDIR a/b/2/20/
EXECUTE REMOVEDIR a/b/2/
EXECUTE REMOVEDIR a/b/0/00/
EXECUTE REMOVEDIR a/b/0/
EXECUTE REMOVEDIR a/b/
EXECUTE REMOVEDIR a/
EXECUTE ADD precomplete
EXECUTE ADD a/b/searchplugins/searchpluginstext0
EXECUTE ADD a/b/searchplugins/searchpluginspng1.png
EXECUTE ADD a/b/searchplugins/searchpluginspng0.png
EXECUTE ADD a/b/removed-files
EXECUTE ADD a/b/extensions/extensions1/extensions1text0
EXECUTE ADD a/b/extensions/extensions1/extensions1png1.png
EXECUTE ADD a/b/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/extensions/extensions0/extensions0text0
EXECUTE ADD a/b/extensions/extensions0/extensions0png1.png
EXECUTE ADD a/b/extensions/extensions0/extensions0png0.png
EXECUTE ADD a/b/exe0.exe
EXECUTE ADD a/b/1/10/10text0
EXECUTE ADD a/b/0/0exe0.exe
EXECUTE ADD a/b/0/00/00text1
EXECUTE ADD a/b/0/00/00text0
EXECUTE ADD a/b/0/00/00png0.png
EXECUTE REMOVEDIR a/b/9/99/
EXECUTE REMOVEDIR a/b/9/99/
EXECUTE REMOVEDIR a/b/9/98/
EXECUTE REMOVEFILE a/b/9/97/970/97xtext0
EXECUTE REMOVEFILE a/b/9/97/970/97xtext1
EXECUTE REMOVEDIR a/b/9/97/970/
EXECUTE REMOVEFILE a/b/9/97/971/97xtext0
EXECUTE REMOVEFILE a/b/9/97/971/97xtext1
EXECUTE REMOVEDIR a/b/9/97/971/
EXECUTE REMOVEDIR a/b/9/97/
EXECUTE REMOVEFILE a/b/9/96/96text0
EXECUTE REMOVEFILE a/b/9/96/96text1
EXECUTE REMOVEDIR a/b/9/96/
EXECUTE REMOVEDIR a/b/9/95/
EXECUTE REMOVEDIR a/b/9/95/
EXECUTE REMOVEDIR a/b/9/94/
EXECUTE REMOVEDIR a/b/9/94/
EXECUTE REMOVEDIR a/b/9/93/
EXECUTE REMOVEDIR a/b/9/92/
EXECUTE REMOVEDIR a/b/9/91/
EXECUTE REMOVEDIR a/b/9/90/
EXECUTE REMOVEDIR a/b/9/90/
EXECUTE REMOVEDIR a/b/8/89/
EXECUTE REMOVEDIR a/b/8/89/
EXECUTE REMOVEDIR a/b/8/88/
EXECUTE REMOVEFILE a/b/8/87/870/87xtext0
EXECUTE REMOVEFILE a/b/8/87/870/87xtext1
EXECUTE REMOVEDIR a/b/8/87/870/
EXECUTE REMOVEFILE a/b/8/87/871/87xtext0
EXECUTE REMOVEFILE a/b/8/87/871/87xtext1
EXECUTE REMOVEDIR a/b/8/87/871/
EXECUTE REMOVEDIR a/b/8/87/
EXECUTE REMOVEFILE a/b/8/86/86text0
EXECUTE REMOVEFILE a/b/8/86/86text1
EXECUTE REMOVEDIR a/b/8/86/
EXECUTE REMOVEDIR a/b/8/85/
EXECUTE REMOVEDIR a/b/8/85/
EXECUTE REMOVEDIR a/b/8/84/
EXECUTE REMOVEDIR a/b/8/84/
EXECUTE REMOVEDIR a/b/8/83/
EXECUTE REMOVEDIR a/b/8/82/
EXECUTE REMOVEDIR a/b/8/81/
EXECUTE REMOVEDIR a/b/8/80/
EXECUTE REMOVEDIR a/b/8/80/
EXECUTE REMOVEFILE a/b/7/70/7xtest.exe
EXECUTE REMOVEFILE a/b/7/70/7xtext0
EXECUTE REMOVEFILE a/b/7/70/7xtext1
EXECUTE REMOVEDIR a/b/7/70/
EXECUTE REMOVEFILE a/b/7/71/7xtest.exe
EXECUTE REMOVEFILE a/b/7/71/7xtext0
EXECUTE REMOVEFILE a/b/7/71/7xtext1
EXECUTE REMOVEDIR a/b/7/71/
EXECUTE REMOVEDIR a/b/7/
EXECUTE REMOVEDIR a/b/6/
EXECUTE REMOVEFILE a/b/5/5text1
EXECUTE REMOVEFILE a/b/5/5text0
EXECUTE REMOVEFILE a/b/5/5test.exe
EXECUTE REMOVEFILE a/b/5/5text0
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE a/b/5/5text1
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEDIR a/b/5/
EXECUTE REMOVEFILE a/b/4/4text1
EXECUTE REMOVEFILE a/b/4/4text0
EXECUTE REMOVEDIR a/b/4/
EXECUTE REMOVEFILE a/b/3/3text1
EXECUTE REMOVEFILE a/b/3/3text0
FINISH REMOVEFILE precomplete
FINISH REMOVEFILE a/b/searchplugins/searchpluginstext0
FINISH REMOVEFILE a/b/searchplugins/searchpluginspng0.png
FINISH REMOVEFILE a/b/removed-files
FINISH REMOVEFILE a/b/extensions/extensions1/extensions1png1.png
FINISH REMOVEFILE a/b/extensions/extensions0/extensions0text0
FINISH REMOVEFILE a/b/exe0.exe
FINISH REMOVEFILE a/b/2/20/20text0
FINISH REMOVEFILE a/b/2/20/20png0.png
FINISH REMOVEFILE a/b/0/0exe0.exe
FINISH REMOVEFILE a/b/0/00/00text0
FINISH REMOVEDIR a/b/searchplugins/
removing directory: a/b/searchplugins/, rv: 0
FINISH REMOVEDIR a/b/extensions/extensions1/
removing directory: a/b/extensions/extensions1/, rv: 0
FINISH REMOVEDIR a/b/extensions/extensions0/
removing directory: a/b/extensions/extensions0/, rv: 0
FINISH REMOVEDIR a/b/extensions/
removing directory: a/b/extensions/, rv: 0
FINISH REMOVEDIR a/b/defaults/pref/
removing directory: a/b/defaults/pref/, rv: 0
FINISH REMOVEDIR a/b/defaults/
removing directory: a/b/defaults/, rv: 0
FINISH REMOVEDIR a/b/2/20/
FINISH REMOVEDIR a/b/2/
FINISH REMOVEDIR a/b/0/00/
removing directory: a/b/0/00/, rv: 0
FINISH REMOVEDIR a/b/0/
removing directory: a/b/0/, rv: 0
FINISH REMOVEDIR a/b/
removing directory: a/b/, rv: 0
FINISH REMOVEDIR a/
removing directory: a/, rv: 0
FINISH ADD precomplete
FINISH ADD a/b/searchplugins/searchpluginstext0
FINISH ADD a/b/searchplugins/searchpluginspng1.png
FINISH ADD a/b/searchplugins/searchpluginspng0.png
FINISH ADD a/b/removed-files
FINISH ADD a/b/extensions/extensions1/extensions1text0
FINISH ADD a/b/extensions/extensions1/extensions1png1.png
FINISH ADD a/b/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/extensions/extensions0/extensions0text0
FINISH ADD a/b/extensions/extensions0/extensions0png1.png
FINISH ADD a/b/extensions/extensions0/extensions0png0.png
FINISH ADD a/b/exe0.exe
FINISH ADD a/b/1/10/10text0
FINISH ADD a/b/0/0exe0.exe
FINISH ADD a/b/0/00/00text1
FINISH ADD a/b/0/00/00text0
FINISH ADD a/b/0/00/00png0.png
FINISH REMOVEDIR a/b/9/99/
FINISH REMOVEDIR a/b/9/99/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/9/98/
FINISH REMOVEFILE a/b/9/97/970/97xtext0
FINISH REMOVEFILE a/b/9/97/970/97xtext1
FINISH REMOVEDIR a/b/9/97/970/
FINISH REMOVEFILE a/b/9/97/971/97xtext0
FINISH REMOVEFILE a/b/9/97/971/97xtext1
FINISH REMOVEDIR a/b/9/97/971/
FINISH REMOVEDIR a/b/9/97/
FINISH REMOVEFILE a/b/9/96/96text0
FINISH REMOVEFILE a/b/9/96/96text1
FINISH REMOVEDIR a/b/9/96/
FINISH REMOVEDIR a/b/9/95/
FINISH REMOVEDIR a/b/9/95/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/9/94/
FINISH REMOVEDIR a/b/9/94/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/9/93/
FINISH REMOVEDIR a/b/9/92/
removing directory: a/b/9/92/, rv: 0
FINISH REMOVEDIR a/b/9/91/
removing directory: a/b/9/91/, rv: 0
FINISH REMOVEDIR a/b/9/90/
FINISH REMOVEDIR a/b/9/90/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/89/
FINISH REMOVEDIR a/b/8/89/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/88/
FINISH REMOVEFILE a/b/8/87/870/87xtext0
FINISH REMOVEFILE a/b/8/87/870/87xtext1
FINISH REMOVEDIR a/b/8/87/870/
FINISH REMOVEFILE a/b/8/87/871/87xtext0
FINISH REMOVEFILE a/b/8/87/871/87xtext1
FINISH REMOVEDIR a/b/8/87/871/
FINISH REMOVEDIR a/b/8/87/
FINISH REMOVEFILE a/b/8/86/86text0
FINISH REMOVEFILE a/b/8/86/86text1
FINISH REMOVEDIR a/b/8/86/
FINISH REMOVEDIR a/b/8/85/
FINISH REMOVEDIR a/b/8/85/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/84/
FINISH REMOVEDIR a/b/8/84/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/83/
FINISH REMOVEDIR a/b/8/82/
removing directory: a/b/8/82/, rv: 0
FINISH REMOVEDIR a/b/8/81/
removing directory: a/b/8/81/, rv: 0
FINISH REMOVEDIR a/b/8/80/
FINISH REMOVEDIR a/b/8/80/
directory no longer exists; skipping
FINISH REMOVEFILE a/b/7/70/7xtest.exe
FINISH REMOVEFILE a/b/7/70/7xtext0
FINISH REMOVEFILE a/b/7/70/7xtext1
FINISH REMOVEDIR a/b/7/70/
FINISH REMOVEFILE a/b/7/71/7xtest.exe
FINISH REMOVEFILE a/b/7/71/7xtext0
FINISH REMOVEFILE a/b/7/71/7xtext1
FINISH REMOVEDIR a/b/7/71/
FINISH REMOVEDIR a/b/7/
FINISH REMOVEDIR a/b/6/
FINISH REMOVEFILE a/b/5/5text1
FINISH REMOVEFILE a/b/5/5text0
FINISH REMOVEFILE a/b/5/5test.exe
FINISH REMOVEDIR a/b/5/
FINISH REMOVEFILE a/b/4/4text1
FINISH REMOVEFILE a/b/4/4text0
FINISH REMOVEDIR a/b/4/
FINISH REMOVEFILE a/b/3/3text1
FINISH REMOVEFILE a/b/3/3text0
succeeded
calling QuitProgressUI
rename_file: proceeding to rename the directory
rename_file: proceeding to rename the directory
Now, remove the tmpDir
succeeded
calling QuitProgressUI

View File

@ -1,25 +1,14 @@
remove "precomplete"
remove "a/b/searchplugins/searchpluginstext0"
remove "a/b/searchplugins/searchpluginspng1.png"
remove "a/b/searchplugins/searchpluginspng0.png"
remove "a/b/removed-files"
remove "a/b/extensions/extensions1/extensions1text0"
remove "a/b/extensions/extensions1/extensions1png1.png"
remove "a/b/extensions/extensions1/extensions1png0.png"
remove "a/b/extensions/extensions0/extensions0text0"
remove "a/b/extensions/extensions0/extensions0png1.png"
remove "a/b/extensions/extensions0/extensions0png0.png"
remove "a/b/exe0.exe"
remove-cc "a/b/defaults/pref/channel-prefs.js"
remove "a/b/1/10/10text0"
remove "a/b/0/0exe0.exe"
remove "a/b/0/00/00text1"
remove "a/b/0/00/00text0"
remove "a/b/0/00/00png0.png"
rmdir "a/b/searchplugins/"
rmdir "a/b/extensions/extensions1/"
rmdir "a/b/extensions/extensions0/"
rmdir "a/b/extensions/"
rmdir "a/b/defaults/pref/"
rmdir "a/b/defaults/"
rmdir "a/b/1/10/"

View File

@ -3,13 +3,13 @@ PREPARE ADD precomplete
PREPARE ADD a/b/searchplugins/searchpluginstext0
PREPARE PATCH a/b/searchplugins/searchpluginspng1.png
PREPARE PATCH a/b/searchplugins/searchpluginspng0.png
PREPARE ADD a/b/extensions/extensions1/extensions1text0
PREPARE PATCH a/b/extensions/extensions1/extensions1png1.png
PREPARE PATCH a/b/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/extensions/extensions0/extensions0text0
PREPARE PATCH a/b/extensions/extensions0/extensions0png1.png
PREPARE PATCH a/b/extensions/extensions0/extensions0png0.png
PREPARE PATCH a/b/exe0.exe
PREPARE ADD a/b/distribution/extensions/extensions1/extensions1text0
PREPARE PATCH a/b/distribution/extensions/extensions1/extensions1png1.png
PREPARE PATCH a/b/distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/distribution/extensions/extensions0/extensions0text0
PREPARE PATCH a/b/distribution/extensions/extensions0/extensions0png1.png
PREPARE PATCH a/b/distribution/extensions/extensions0/extensions0png0.png
PREPARE PATCH a/b/0/0exe0.exe
PREPARE ADD a/b/0/00/00text0
PREPARE PATCH a/b/0/00/00png0.png
@ -89,29 +89,29 @@ EXECUTE ADD precomplete
EXECUTE ADD a/b/searchplugins/searchpluginstext0
EXECUTE PATCH a/b/searchplugins/searchpluginspng1.png
EXECUTE PATCH a/b/searchplugins/searchpluginspng0.png
EXECUTE ADD a/b/extensions/extensions1/extensions1text0
EXECUTE PATCH a/b/extensions/extensions1/extensions1png1.png
EXECUTE PATCH a/b/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/extensions/extensions0/extensions0text0
EXECUTE PATCH a/b/extensions/extensions0/extensions0png1.png
EXECUTE PATCH a/b/extensions/extensions0/extensions0png0.png
EXECUTE PATCH a/b/exe0.exe
EXECUTE ADD a/b/distribution/extensions/extensions1/extensions1text0
EXECUTE PATCH a/b/distribution/extensions/extensions1/extensions1png1.png
EXECUTE PATCH a/b/distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/distribution/extensions/extensions0/extensions0text0
EXECUTE PATCH a/b/distribution/extensions/extensions0/extensions0png1.png
EXECUTE PATCH a/b/distribution/extensions/extensions0/extensions0png0.png
EXECUTE PATCH a/b/0/0exe0.exe
LoadSourceFile: destination file size 776 does not match expected size 878
LoadSourceFile: destination file size 776 does not match expected size 79872
LoadSourceFile failed
### execution failed
FINISH ADD precomplete
FINISH ADD a/b/searchplugins/searchpluginstext0
FINISH PATCH a/b/searchplugins/searchpluginspng1.png
FINISH PATCH a/b/searchplugins/searchpluginspng0.png
FINISH ADD a/b/extensions/extensions1/extensions1text0
backup_restore: backup file doesn't exist: a/b/extensions/extensions1/extensions1text0.moz-backup
FINISH PATCH a/b/extensions/extensions1/extensions1png1.png
FINISH PATCH a/b/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/extensions/extensions0/extensions0text0
FINISH PATCH a/b/extensions/extensions0/extensions0png1.png
FINISH PATCH a/b/extensions/extensions0/extensions0png0.png
FINISH PATCH a/b/exe0.exe
FINISH ADD a/b/distribution/extensions/extensions1/extensions1text0
backup_restore: backup file doesn't exist: a/b/distribution/extensions/extensions1/extensions1text0.moz-backup
FINISH PATCH a/b/distribution/extensions/extensions1/extensions1png1.png
FINISH PATCH a/b/distribution/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/distribution/extensions/extensions0/extensions0text0
FINISH PATCH a/b/distribution/extensions/extensions0/extensions0png1.png
FINISH PATCH a/b/distribution/extensions/extensions0/extensions0png0.png
FINISH PATCH a/b/0/0exe0.exe
backup_restore: backup file doesn't exist: a/b/0/0exe0.exe.moz-backup
FINISH ADD a/b/0/00/00text0

View File

@ -3,13 +3,13 @@ PREPARE ADD precomplete
PREPARE ADD a/b/searchplugins/searchpluginstext0
PREPARE PATCH a/b/searchplugins/searchpluginspng1.png
PREPARE PATCH a/b/searchplugins/searchpluginspng0.png
PREPARE ADD a/b/extensions/extensions1/extensions1text0
PREPARE PATCH a/b/extensions/extensions1/extensions1png1.png
PREPARE PATCH a/b/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/extensions/extensions0/extensions0text0
PREPARE PATCH a/b/extensions/extensions0/extensions0png1.png
PREPARE PATCH a/b/extensions/extensions0/extensions0png0.png
PREPARE PATCH a/b/exe0.exe
PREPARE ADD a/b/distribution/extensions/extensions1/extensions1text0
PREPARE PATCH a/b/distribution/extensions/extensions1/extensions1png1.png
PREPARE PATCH a/b/distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/distribution/extensions/extensions0/extensions0text0
PREPARE PATCH a/b/distribution/extensions/extensions0/extensions0png1.png
PREPARE PATCH a/b/distribution/extensions/extensions0/extensions0png0.png
PREPARE PATCH a/b/0/0exe0.exe
PREPARE ADD a/b/0/00/00text0
PREPARE PATCH a/b/0/00/00png0.png
@ -89,13 +89,13 @@ EXECUTE ADD precomplete
EXECUTE ADD a/b/searchplugins/searchpluginstext0
EXECUTE PATCH a/b/searchplugins/searchpluginspng1.png
EXECUTE PATCH a/b/searchplugins/searchpluginspng0.png
EXECUTE ADD a/b/extensions/extensions1/extensions1text0
EXECUTE PATCH a/b/extensions/extensions1/extensions1png1.png
EXECUTE PATCH a/b/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/extensions/extensions0/extensions0text0
EXECUTE PATCH a/b/extensions/extensions0/extensions0png1.png
EXECUTE PATCH a/b/extensions/extensions0/extensions0png0.png
EXECUTE PATCH a/b/exe0.exe
EXECUTE ADD a/b/distribution/extensions/extensions1/extensions1text0
EXECUTE PATCH a/b/distribution/extensions/extensions1/extensions1png1.png
EXECUTE PATCH a/b/distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/distribution/extensions/extensions0/extensions0text0
EXECUTE PATCH a/b/distribution/extensions/extensions0/extensions0png1.png
EXECUTE PATCH a/b/distribution/extensions/extensions0/extensions0png0.png
EXECUTE PATCH a/b/0/0exe0.exe
EXECUTE ADD a/b/0/00/00text0
EXECUTE PATCH a/b/0/00/00png0.png
@ -177,13 +177,13 @@ FINISH ADD precomplete
FINISH ADD a/b/searchplugins/searchpluginstext0
FINISH PATCH a/b/searchplugins/searchpluginspng1.png
FINISH PATCH a/b/searchplugins/searchpluginspng0.png
FINISH ADD a/b/extensions/extensions1/extensions1text0
FINISH PATCH a/b/extensions/extensions1/extensions1png1.png
FINISH PATCH a/b/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/extensions/extensions0/extensions0text0
FINISH PATCH a/b/extensions/extensions0/extensions0png1.png
FINISH PATCH a/b/extensions/extensions0/extensions0png0.png
FINISH PATCH a/b/exe0.exe
FINISH ADD a/b/distribution/extensions/extensions1/extensions1text0
FINISH PATCH a/b/distribution/extensions/extensions1/extensions1png1.png
FINISH PATCH a/b/distribution/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/distribution/extensions/extensions0/extensions0text0
FINISH PATCH a/b/distribution/extensions/extensions0/extensions0png1.png
FINISH PATCH a/b/distribution/extensions/extensions0/extensions0png0.png
FINISH PATCH a/b/0/0exe0.exe
FINISH ADD a/b/0/00/00text0
FINISH PATCH a/b/0/00/00png0.png

View File

@ -1,278 +0,0 @@
UPDATE TYPE partial
PREPARE ADD precomplete
PREPARE ADD a/b/searchplugins/searchpluginstext0
PREPARE PATCH a/b/searchplugins/searchpluginspng1.png
PREPARE PATCH a/b/searchplugins/searchpluginspng0.png
PREPARE ADD a/b/extensions/extensions1/extensions1text0
PREPARE PATCH a/b/extensions/extensions1/extensions1png1.png
PREPARE PATCH a/b/extensions/extensions1/extensions1png0.png
PREPARE ADD a/b/extensions/extensions0/extensions0text0
PREPARE PATCH a/b/extensions/extensions0/extensions0png1.png
PREPARE PATCH a/b/extensions/extensions0/extensions0png0.png
PREPARE PATCH a/b/exe0.exe
PREPARE PATCH a/b/0/0exe0.exe
PREPARE ADD a/b/0/00/00text0
PREPARE PATCH a/b/0/00/00png0.png
PREPARE ADD a/b/2/20/20text0
PREPARE ADD a/b/2/20/20png0.png
PREPARE ADD a/b/0/00/00text2
PREPARE REMOVEFILE a/b/1/10/10text0
PREPARE REMOVEFILE a/b/0/00/00text1
PREPARE REMOVEDIR a/b/9/99/
PREPARE REMOVEDIR a/b/9/99/
PREPARE REMOVEDIR a/b/9/98/
PREPARE REMOVEFILE a/b/9/97/970/97xtext0
PREPARE REMOVEFILE a/b/9/97/970/97xtext1
PREPARE REMOVEDIR a/b/9/97/970/
PREPARE REMOVEFILE a/b/9/97/971/97xtext0
PREPARE REMOVEFILE a/b/9/97/971/97xtext1
PREPARE REMOVEDIR a/b/9/97/971/
PREPARE REMOVEDIR a/b/9/97/
PREPARE REMOVEFILE a/b/9/96/96text0
PREPARE REMOVEFILE a/b/9/96/96text1
PREPARE REMOVEDIR a/b/9/96/
PREPARE REMOVEDIR a/b/9/95/
PREPARE REMOVEDIR a/b/9/95/
PREPARE REMOVEDIR a/b/9/94/
PREPARE REMOVEDIR a/b/9/94/
PREPARE REMOVEDIR a/b/9/93/
PREPARE REMOVEDIR a/b/9/92/
PREPARE REMOVEDIR a/b/9/91/
PREPARE REMOVEDIR a/b/9/90/
PREPARE REMOVEDIR a/b/9/90/
PREPARE REMOVEDIR a/b/8/89/
PREPARE REMOVEDIR a/b/8/89/
PREPARE REMOVEDIR a/b/8/88/
PREPARE REMOVEFILE a/b/8/87/870/87xtext0
PREPARE REMOVEFILE a/b/8/87/870/87xtext1
PREPARE REMOVEDIR a/b/8/87/870/
PREPARE REMOVEFILE a/b/8/87/871/87xtext0
PREPARE REMOVEFILE a/b/8/87/871/87xtext1
PREPARE REMOVEDIR a/b/8/87/871/
PREPARE REMOVEDIR a/b/8/87/
PREPARE REMOVEFILE a/b/8/86/86text0
PREPARE REMOVEFILE a/b/8/86/86text1
PREPARE REMOVEDIR a/b/8/86/
PREPARE REMOVEDIR a/b/8/85/
PREPARE REMOVEDIR a/b/8/85/
PREPARE REMOVEDIR a/b/8/84/
PREPARE REMOVEDIR a/b/8/84/
PREPARE REMOVEDIR a/b/8/83/
PREPARE REMOVEDIR a/b/8/82/
PREPARE REMOVEDIR a/b/8/81/
PREPARE REMOVEDIR a/b/8/80/
PREPARE REMOVEDIR a/b/8/80/
PREPARE REMOVEFILE a/b/7/70/7xtest.exe
PREPARE REMOVEFILE a/b/7/70/7xtext0
PREPARE REMOVEFILE a/b/7/70/7xtext1
PREPARE REMOVEDIR a/b/7/70/
PREPARE REMOVEFILE a/b/7/71/7xtest.exe
PREPARE REMOVEFILE a/b/7/71/7xtext0
PREPARE REMOVEFILE a/b/7/71/7xtext1
PREPARE REMOVEDIR a/b/7/71/
PREPARE REMOVEDIR a/b/7/
PREPARE REMOVEDIR a/b/6/
PREPARE REMOVEFILE a/b/5/5text1
PREPARE REMOVEFILE a/b/5/5text0
PREPARE REMOVEFILE a/b/5/5test.exe
PREPARE REMOVEFILE a/b/5/5text0
PREPARE REMOVEFILE a/b/5/5text1
PREPARE REMOVEDIR a/b/5/
PREPARE REMOVEFILE a/b/4/4text1
PREPARE REMOVEFILE a/b/4/4text0
PREPARE REMOVEDIR a/b/4/
PREPARE REMOVEFILE a/b/3/3text1
PREPARE REMOVEFILE a/b/3/3text0
PREPARE REMOVEDIR a/b/1/10/
PREPARE REMOVEDIR a/b/1/
EXECUTE ADD precomplete
EXECUTE ADD a/b/searchplugins/searchpluginstext0
EXECUTE PATCH a/b/searchplugins/searchpluginspng1.png
EXECUTE PATCH a/b/searchplugins/searchpluginspng0.png
EXECUTE ADD a/b/extensions/extensions1/extensions1text0
EXECUTE PATCH a/b/extensions/extensions1/extensions1png1.png
EXECUTE PATCH a/b/extensions/extensions1/extensions1png0.png
EXECUTE ADD a/b/extensions/extensions0/extensions0text0
EXECUTE PATCH a/b/extensions/extensions0/extensions0png1.png
EXECUTE PATCH a/b/extensions/extensions0/extensions0png0.png
EXECUTE PATCH a/b/exe0.exe
EXECUTE PATCH a/b/0/0exe0.exe
EXECUTE ADD a/b/0/00/00text0
EXECUTE PATCH a/b/0/00/00png0.png
EXECUTE ADD a/b/2/20/20text0
EXECUTE ADD a/b/2/20/20png0.png
EXECUTE ADD a/b/0/00/00text2
EXECUTE REMOVEFILE a/b/1/10/10text0
EXECUTE REMOVEFILE a/b/0/00/00text1
EXECUTE REMOVEDIR a/b/9/99/
EXECUTE REMOVEDIR a/b/9/99/
EXECUTE REMOVEDIR a/b/9/98/
EXECUTE REMOVEFILE a/b/9/97/970/97xtext0
EXECUTE REMOVEFILE a/b/9/97/970/97xtext1
EXECUTE REMOVEDIR a/b/9/97/970/
EXECUTE REMOVEFILE a/b/9/97/971/97xtext0
EXECUTE REMOVEFILE a/b/9/97/971/97xtext1
EXECUTE REMOVEDIR a/b/9/97/971/
EXECUTE REMOVEDIR a/b/9/97/
EXECUTE REMOVEFILE a/b/9/96/96text0
EXECUTE REMOVEFILE a/b/9/96/96text1
EXECUTE REMOVEDIR a/b/9/96/
EXECUTE REMOVEDIR a/b/9/95/
EXECUTE REMOVEDIR a/b/9/95/
EXECUTE REMOVEDIR a/b/9/94/
EXECUTE REMOVEDIR a/b/9/94/
EXECUTE REMOVEDIR a/b/9/93/
EXECUTE REMOVEDIR a/b/9/92/
EXECUTE REMOVEDIR a/b/9/91/
EXECUTE REMOVEDIR a/b/9/90/
EXECUTE REMOVEDIR a/b/9/90/
EXECUTE REMOVEDIR a/b/8/89/
EXECUTE REMOVEDIR a/b/8/89/
EXECUTE REMOVEDIR a/b/8/88/
EXECUTE REMOVEFILE a/b/8/87/870/87xtext0
EXECUTE REMOVEFILE a/b/8/87/870/87xtext1
EXECUTE REMOVEDIR a/b/8/87/870/
EXECUTE REMOVEFILE a/b/8/87/871/87xtext0
EXECUTE REMOVEFILE a/b/8/87/871/87xtext1
EXECUTE REMOVEDIR a/b/8/87/871/
EXECUTE REMOVEDIR a/b/8/87/
EXECUTE REMOVEFILE a/b/8/86/86text0
EXECUTE REMOVEFILE a/b/8/86/86text1
EXECUTE REMOVEDIR a/b/8/86/
EXECUTE REMOVEDIR a/b/8/85/
EXECUTE REMOVEDIR a/b/8/85/
EXECUTE REMOVEDIR a/b/8/84/
EXECUTE REMOVEDIR a/b/8/84/
EXECUTE REMOVEDIR a/b/8/83/
EXECUTE REMOVEDIR a/b/8/82/
EXECUTE REMOVEDIR a/b/8/81/
EXECUTE REMOVEDIR a/b/8/80/
EXECUTE REMOVEDIR a/b/8/80/
EXECUTE REMOVEFILE a/b/7/70/7xtest.exe
EXECUTE REMOVEFILE a/b/7/70/7xtext0
EXECUTE REMOVEFILE a/b/7/70/7xtext1
EXECUTE REMOVEDIR a/b/7/70/
EXECUTE REMOVEFILE a/b/7/71/7xtest.exe
EXECUTE REMOVEFILE a/b/7/71/7xtext0
EXECUTE REMOVEFILE a/b/7/71/7xtext1
EXECUTE REMOVEDIR a/b/7/71/
EXECUTE REMOVEDIR a/b/7/
EXECUTE REMOVEDIR a/b/6/
EXECUTE REMOVEFILE a/b/5/5text1
EXECUTE REMOVEFILE a/b/5/5text0
EXECUTE REMOVEFILE a/b/5/5test.exe
EXECUTE REMOVEFILE a/b/5/5text0
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE a/b/5/5text1
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEDIR a/b/5/
EXECUTE REMOVEFILE a/b/4/4text1
EXECUTE REMOVEFILE a/b/4/4text0
EXECUTE REMOVEDIR a/b/4/
EXECUTE REMOVEFILE a/b/3/3text1
EXECUTE REMOVEFILE a/b/3/3text0
EXECUTE REMOVEDIR a/b/1/10/
EXECUTE REMOVEDIR a/b/1/
FINISH ADD precomplete
FINISH ADD a/b/searchplugins/searchpluginstext0
FINISH PATCH a/b/searchplugins/searchpluginspng1.png
FINISH PATCH a/b/searchplugins/searchpluginspng0.png
FINISH ADD a/b/extensions/extensions1/extensions1text0
FINISH PATCH a/b/extensions/extensions1/extensions1png1.png
FINISH PATCH a/b/extensions/extensions1/extensions1png0.png
FINISH ADD a/b/extensions/extensions0/extensions0text0
FINISH PATCH a/b/extensions/extensions0/extensions0png1.png
FINISH PATCH a/b/extensions/extensions0/extensions0png0.png
FINISH PATCH a/b/exe0.exe
FINISH PATCH a/b/0/0exe0.exe
FINISH ADD a/b/0/00/00text0
FINISH PATCH a/b/0/00/00png0.png
FINISH ADD a/b/2/20/20text0
FINISH ADD a/b/2/20/20png0.png
FINISH ADD a/b/0/00/00text2
FINISH REMOVEFILE a/b/1/10/10text0
FINISH REMOVEFILE a/b/0/00/00text1
FINISH REMOVEDIR a/b/9/99/
FINISH REMOVEDIR a/b/9/99/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/9/98/
FINISH REMOVEFILE a/b/9/97/970/97xtext0
FINISH REMOVEFILE a/b/9/97/970/97xtext1
FINISH REMOVEDIR a/b/9/97/970/
FINISH REMOVEFILE a/b/9/97/971/97xtext0
FINISH REMOVEFILE a/b/9/97/971/97xtext1
FINISH REMOVEDIR a/b/9/97/971/
FINISH REMOVEDIR a/b/9/97/
FINISH REMOVEFILE a/b/9/96/96text0
FINISH REMOVEFILE a/b/9/96/96text1
FINISH REMOVEDIR a/b/9/96/
FINISH REMOVEDIR a/b/9/95/
FINISH REMOVEDIR a/b/9/95/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/9/94/
FINISH REMOVEDIR a/b/9/94/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/9/93/
FINISH REMOVEDIR a/b/9/92/
removing directory: a/b/9/92/, rv: 0
FINISH REMOVEDIR a/b/9/91/
removing directory: a/b/9/91/, rv: 0
FINISH REMOVEDIR a/b/9/90/
FINISH REMOVEDIR a/b/9/90/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/89/
FINISH REMOVEDIR a/b/8/89/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/88/
FINISH REMOVEFILE a/b/8/87/870/87xtext0
FINISH REMOVEFILE a/b/8/87/870/87xtext1
FINISH REMOVEDIR a/b/8/87/870/
FINISH REMOVEFILE a/b/8/87/871/87xtext0
FINISH REMOVEFILE a/b/8/87/871/87xtext1
FINISH REMOVEDIR a/b/8/87/871/
FINISH REMOVEDIR a/b/8/87/
FINISH REMOVEFILE a/b/8/86/86text0
FINISH REMOVEFILE a/b/8/86/86text1
FINISH REMOVEDIR a/b/8/86/
FINISH REMOVEDIR a/b/8/85/
FINISH REMOVEDIR a/b/8/85/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/84/
FINISH REMOVEDIR a/b/8/84/
directory no longer exists; skipping
FINISH REMOVEDIR a/b/8/83/
FINISH REMOVEDIR a/b/8/82/
removing directory: a/b/8/82/, rv: 0
FINISH REMOVEDIR a/b/8/81/
removing directory: a/b/8/81/, rv: 0
FINISH REMOVEDIR a/b/8/80/
FINISH REMOVEDIR a/b/8/80/
directory no longer exists; skipping
FINISH REMOVEFILE a/b/7/70/7xtest.exe
FINISH REMOVEFILE a/b/7/70/7xtext0
FINISH REMOVEFILE a/b/7/70/7xtext1
FINISH REMOVEDIR a/b/7/70/
FINISH REMOVEFILE a/b/7/71/7xtest.exe
FINISH REMOVEFILE a/b/7/71/7xtext0
FINISH REMOVEFILE a/b/7/71/7xtext1
FINISH REMOVEDIR a/b/7/71/
FINISH REMOVEDIR a/b/7/
FINISH REMOVEDIR a/b/6/
FINISH REMOVEFILE a/b/5/5text1
FINISH REMOVEFILE a/b/5/5text0
FINISH REMOVEFILE a/b/5/5test.exe
FINISH REMOVEDIR a/b/5/
FINISH REMOVEFILE a/b/4/4text1
FINISH REMOVEFILE a/b/4/4text0
FINISH REMOVEDIR a/b/4/
FINISH REMOVEFILE a/b/3/3text1
FINISH REMOVEFILE a/b/3/3text0
FINISH REMOVEDIR a/b/1/10/
FINISH REMOVEDIR a/b/1/
succeeded
calling QuitProgressUI
rename_file: proceeding to rename the directory
rename_file: proceeding to rename the directory
Now, remove the tmpDir
succeeded
calling QuitProgressUI

View File

@ -1,16 +1,8 @@
remove "precomplete"
remove "a/b/searchplugins/searchpluginstext0"
remove "a/b/searchplugins/searchpluginspng1.png"
remove "a/b/searchplugins/searchpluginspng0.png"
remove "a/b/removed-files"
remove "a/b/extensions/extensions1/extensions1text0"
remove "a/b/extensions/extensions1/extensions1png1.png"
remove "a/b/extensions/extensions1/extensions1png0.png"
remove "a/b/extensions/extensions0/extensions0text0"
remove "a/b/extensions/extensions0/extensions0png1.png"
remove "a/b/extensions/extensions0/extensions0png0.png"
remove "a/b/exe0.exe"
remove-cc "a/b/defaults/pref/channel-prefs.js"
remove "a/b/2/20/20text0"
remove "a/b/2/20/20png0.png"
remove "a/b/0/0exe0.exe"
@ -18,9 +10,6 @@ remove "a/b/0/00/00text2"
remove "a/b/0/00/00text0"
remove "a/b/0/00/00png0.png"
rmdir "a/b/searchplugins/"
rmdir "a/b/extensions/extensions1/"
rmdir "a/b/extensions/extensions0/"
rmdir "a/b/extensions/"
rmdir "a/b/defaults/pref/"
rmdir "a/b/defaults/"
rmdir "a/b/2/20/"

View File

@ -59,6 +59,7 @@ const CRC_ERROR = 4;
const WRITE_ERROR = 7;
const DIR_PATCH = "0";
const DIR_TOBEDELETED = "tobedeleted";
const DIR_UPDATES = "updates";
#ifdef XP_MACOSX
const DIR_BIN_REL_PATH = "Contents/MacOS/";

View File

@ -11,33 +11,18 @@
* features greater than JavaScript 1.7.
*/
const FILE_SIMPLE_NO_PIB_MAR = "simple_no_pib.mar";
const SIZE_SIMPLE_NO_PIB_MAR = "351";
const MD5_HASH_SIMPLE_NO_PIB_MAR = "d0a7f84dacc55a252ab916668a7cb216";
const SHA1_HASH_SIMPLE_NO_PIB_MAR = "f5053f9552d087c6c6ed83f9b19405eccf1436" +
"fc";
const SHA256_HASH_SIMPLE_NO_PIB_MAR = "663c7cbd11fe45b0a71438387db924d205997a" +
"b85ccf5b40aebbdaef179796ab";
const SHA384_HASH_SIMPLE_NO_PIB_MAR = "a57250554755a9f42b91932993599bb6b05e06" +
"3dcbd71846e350232945dbad2b0c83208a0781" +
"0cf798b3d1139399c453";
const SHA512_HASH_SIMPLE_NO_PIB_MAR = "55d3e2a86acaeb0abb7a444c13bba748846fcb" +
"ac7ff058f8ee9c9260ba01e6aef86fa4a6c46a" +
"3016b675ef94e77e63fbe912f64d155bed9b1c" +
"341dd56e575a26";
const FILE_SIMPLE_MAR = "simple.mar";
const SIZE_SIMPLE_MAR = "735";
const MD5_HASH_SIMPLE_MAR = "025228705a76117b5499a22d9eed9271";
const SHA1_HASH_SIMPLE_MAR = "87a9b1f57b3ff9bb20b677c5c0924b46b6f6781e";
const SHA256_HASH_SIMPLE_MAR = "443ef6a8ddcd2af88f9b72b1732d335454a483127766a" +
"30ca3a5647d2ae159da";
const SHA384_HASH_SIMPLE_MAR = "c8a493e50569c190a1c67793be80f0f9d13b08d839d79" +
"dd8d7be2859cfd2f75b242f272a8fbbcbe4419d399259" +
"35d732";
const SHA512_HASH_SIMPLE_MAR = "9f9afbb5a6fa70e71fa28c73c5b1968cf8831ae02ebd4" +
"28839ed2acf0b257c08c76c1f286c94c029dd3a4ad708" +
"f9703f61e6bf5f30982e9deee7d6838c1dbe14";
const SIZE_SIMPLE_MAR = "1031";
const MD5_HASH_SIMPLE_MAR = "1f8c038577bb6845d94ccec4999113ee";
const SHA1_HASH_SIMPLE_MAR = "5d49a672c87f10f31d7e326349564a11272a028b";
const SHA256_HASH_SIMPLE_MAR = "1aabbed5b1dd6e16e139afc5b43d479e254e0c26" +
"3c8fb9249c0a1bb93071c5fb";
const SHA384_HASH_SIMPLE_MAR = "26615014ea034af32ef5651492d5f493f5a7a1a48522e" +
"d24c366442a5ec21d5ef02e23fb58d79729b8ca2f9541" +
"99dd53";
const SHA512_HASH_SIMPLE_MAR = "922e5ae22081795f6e8d65a3c508715c9a314054179a8" +
"bbfe5f50dc23919ad89888291bc0a07586ab17dd0304a" +
"b5347473601127571c66f61f5080348e05c36b";
const STATE_NONE = "null";
const STATE_DOWNLOADING = "downloading";

View File

@ -75,27 +75,28 @@ const IS_MAR_CHECKS_ENABLED = false;
const URL_HOST = "http://localhost";
const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX;
const FILE_COMPLETE_EXE = "complete.exe";
const FILE_COMPLETE_MAR = "complete.mar";
const FILE_COMPLETE_WIN_MAR = "complete_win.mar";
const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX;
const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe";
const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe";
const FILE_OLD_VERSION_MAR = "old_version.mar";
const FILE_PARTIAL_EXE = "partial.exe";
const FILE_PARTIAL_MAR = "partial.mar";
const FILE_PARTIAL_WIN_MAR = "partial_win.mar";
const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX;
const FILE_UPDATER_INI_BAK = "updater.ini.bak";
const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar";
const LOG_COMPLETE_SUCCESS = "complete_log_success";
const LOG_COMPLETE_SWITCH_SUCCESS = "complete_log_switch_success"
const LOG_COMPLETE_CC_SUCCESS = "complete_cc_log_success";
const LOG_COMPLETE_CC_SWITCH_SUCCESS = "complete_cc_log_switch_success";
const LOG_PARTIAL_SUCCESS = "partial_log_success";
const LOG_PARTIAL_SWITCH_SUCCESS = "partial_log_switch_success";
const LOG_PARTIAL_FAILURE = "partial_log_failure";
const LOG_SWITCH_SUCCESS = "rename_file: proceeding to rename the directory\n" +
"rename_file: proceeding to rename the directory\n" +
"Now, remove the tmpDir\n" +
"succeeded\n" +
"calling QuitProgressUI";
const ERR_RENAME_FILE = "rename_file: failed to rename file";
const ERR_UNABLE_OPEN_DEST = "unable to open destination file";
const ERR_BACKUP_DISCARD = "backup_discard: unable to remove";
@ -183,6 +184,460 @@ var gEnvXPCOMMemLeakLog;
var gEnvDyldLibraryPath;
var gEnvLdLibraryPath;
// Set to true to log additional information for debugging. To log additional
// information for an individual test set DEBUG_AUS_TEST to true in the test's
// run_test function.
var DEBUG_AUS_TEST = true;
// Never set DEBUG_TEST_LOG to true except when running tests locally or on the
// try server since this will force a test that failed a parallel run to fail
// when the same test runs non-parallel so the log from parallel test run can
// be displayed in the log.
var DEBUG_TEST_LOG = false;
// Set to false to keep the log file from the failed parallel test run.
var gDeleteLogFile = true;
var gRealDump;
var gTestLogText = "";
var gPassed;
#include ../shared.js
var gTestFiles = [];
var gTestDirs = [];
// Common files for both successful and failed updates.
var gTestFilesCommon = [
{
description : "Should never change",
fileName : FILE_UPDATE_SETTINGS_INI,
relPathDir : "a/b/",
originalContents : "ShouldNotBeReplaced\n",
compareContents : "ShouldNotBeReplaced\n",
originalFile : null,
compareFile : null,
originalPerms : 0o767,
comparePerms : 0o767
}, {
description : "Should never change",
fileName : "channel-prefs.js",
relPathDir : "a/b/defaults/pref/",
originalContents : "ShouldNotBeReplaced\n",
compareContents : "ShouldNotBeReplaced\n",
originalFile : null,
compareFile : null,
originalPerms : 0o767,
comparePerms : 0o767
}];
// Files for a complete successful update. This can be used for a complete
// failed update by calling setTestFilesAndDirsForFailure.
var gTestFilesCompleteSuccess = [
{
description : "Added by update.manifest (add)",
fileName : "precomplete",
relPathDir : "",
originalContents : null,
compareContents : null,
originalFile : "partial_precomplete",
compareFile : "complete_precomplete",
originalPerms : 0o666,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "FromComplete\n",
originalFile : null,
compareFile : null,
originalPerms : 0o775,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginspng1.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : "complete.png",
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginspng0.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "partial.png",
compareFile : "complete.png",
originalPerms : 0o666,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "removed-files",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "partial_removed-files",
compareFile : "complete_removed-files",
originalPerms : 0o666,
comparePerms : 0o644
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/distribution/extensions/extensions1/",
originalContents : null,
compareContents : "FromComplete\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1png1.png",
relPathDir : "a/b/distribution/extensions/extensions1/",
originalContents : null,
compareContents : null,
originalFile : "partial.png",
compareFile : "complete.png",
originalPerms : 0o666,
comparePerms : 0o644
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1png0.png",
relPathDir : "a/b/distribution/extensions/extensions1/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : "complete.png",
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/distribution/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "FromComplete\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0png1.png",
relPathDir : "a/b/distribution/extensions/extensions0/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : "complete.png",
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0png0.png",
relPathDir : "a/b/distribution/extensions/extensions0/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : "complete.png",
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : FILE_HELPER_BIN,
compareFile : FILE_COMPLETE_EXE,
originalPerms : 0o777,
comparePerms : 0o755
}, {
description : "Added by update.manifest (add)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "FromComplete\n",
originalFile : null,
compareFile : null,
originalPerms : 0o767,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "0exe0.exe",
relPathDir : "a/b/0/",
originalContents : null,
compareContents : null,
originalFile : FILE_HELPER_BIN,
compareFile : FILE_COMPLETE_EXE,
originalPerms : 0o777,
comparePerms : 0o755
}, {
description : "Added by update.manifest (add)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "FromComplete\n",
originalFile : null,
compareFile : null,
originalPerms : 0o677,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "FromComplete\n",
originalFile : null,
compareFile : null,
originalPerms : 0o775,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "00png0.png",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : "complete.png",
originalPerms : 0o776,
comparePerms : 0o644
}, {
description : "Removed by precomplete (remove)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}];
// Concatenate the common files to the end of the array.
gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon);
// Files for a partial successful update. This can be used for a partial failed
// update by calling setTestFilesAndDirsForFailure.
var gTestFilesPartialSuccess = [
{
description : "Added by update.manifest (add)",
fileName : "precomplete",
relPathDir : "",
originalContents : null,
compareContents : null,
originalFile : "complete_precomplete",
compareFile : "partial_precomplete",
originalPerms : 0o666,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "FromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : 0o775,
comparePerms : 0o644
}, {
description : "Patched by update.manifest if the file exists " +
"(patch-if)",
fileName : "searchpluginspng1.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o666,
comparePerms : 0o666
}, {
description : "Patched by update.manifest if the file exists " +
"(patch-if)",
fileName : "searchpluginspng0.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o666,
comparePerms : 0o666
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/distribution/extensions/extensions1/",
originalContents : null,
compareContents : "FromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 0o644
}, {
description : "Patched by update.manifest if the parent directory " +
"exists (patch-if)",
fileName : "extensions1png1.png",
relPathDir : "a/b/distribution/extensions/extensions1/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o666,
comparePerms : 0o666
}, {
description : "Patched by update.manifest if the parent directory " +
"exists (patch-if)",
fileName : "extensions1png0.png",
relPathDir : "a/b/distribution/extensions/extensions1/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o666,
comparePerms : 0o666
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/distribution/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "FromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : 0o644,
comparePerms : 0o644
}, {
description : "Patched by update.manifest if the parent directory " +
"exists (patch-if)",
fileName : "extensions0png1.png",
relPathDir : "a/b/distribution/extensions/extensions0/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o644,
comparePerms : 0o644
}, {
description : "Patched by update.manifest if the parent directory " +
"exists (patch-if)",
fileName : "extensions0png0.png",
relPathDir : "a/b/distribution/extensions/extensions0/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o644,
comparePerms : 0o644
}, {
description : "Patched by update.manifest (patch)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : FILE_COMPLETE_EXE,
compareFile : FILE_PARTIAL_EXE,
originalPerms : 0o755,
comparePerms : 0o755
}, {
description : "Patched by update.manifest (patch)",
fileName : "0exe0.exe",
relPathDir : "a/b/0/",
originalContents : null,
compareContents : null,
originalFile : FILE_COMPLETE_EXE,
compareFile : FILE_PARTIAL_EXE,
originalPerms : 0o755,
comparePerms : 0o755
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "FromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : 0o644,
comparePerms : 0o644
}, {
description : "Patched by update.manifest (patch)",
fileName : "00png0.png",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : null,
originalFile : "complete.png",
compareFile : "partial.png",
originalPerms : 0o666,
comparePerms : 0o666
}, {
description : "Added by update.manifest (add)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : "FromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : "partial.png",
originalPerms : null,
comparePerms : 0o644
}, {
description : "Added by update.manifest (add)",
fileName : "00text2",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : "FromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 0o644
}, {
description : "Removed by update.manifest (remove)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeDeleted\n",
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeDeleted\n",
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}];
// Concatenate the common files to the end of the array.
gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon);
/**
* The mar files used for the updater tests contain the following remove
* operations.
@ -238,7 +693,7 @@ var gEnvLdLibraryPath;
* rmdir "1/10/"
* rmdir "1/"
*/
var TEST_DIRS = [
var gTestDirsCommon = [
{
relPathDir : "a/b/3/",
dirRemoved : false,
@ -338,25 +793,48 @@ var TEST_DIRS = [
dirRemoved : true
}];
// Populated by tests if needed.
var ADDITIONAL_TEST_DIRS = [];
// Directories for a complete successful update. This array can be used for a
// complete failed update by calling setTestFilesAndDirsForFailure.
var gTestDirsCompleteSuccess = [
{
description : "Removed by precomplete (rmdir)",
relPathDir : "a/b/2/20/",
dirRemoved : true
}, {
description : "Removed by precomplete (rmdir)",
relPathDir : "a/b/2/",
dirRemoved : true
}];
// Set to true to log additional information for debugging. To log additional
// information for an individual test set DEBUG_AUS_TEST to true in the test's
// run_test function.
var DEBUG_AUS_TEST = true;
// Never set DEBUG_TEST_LOG to true except when running tests locally or on the
// try server since this will force a test that failed a parallel run to fail
// when the same test runs non-parallel so the log from parallel test run can
// be displayed in the log.
var DEBUG_TEST_LOG = false;
// Set to false to keep the log file from the failed parallel test run.
var gDeleteLogFile = true;
var gRealDump;
var gTestLogText = "";
var gPassed;
// Concatenate the common files to the beginning of the array.
gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess);
#include ../shared.js
// Directories for a partial successful update. This array can be used for a
// partial failed update by calling setTestFilesAndDirsForFailure.
var gTestDirsPartialSuccess = [
{
description : "Removed by update.manifest (rmdir)",
relPathDir : "a/b/1/10/",
dirRemoved : true
}, {
description : "Removed by update.manifest (rmdir)",
relPathDir : "a/b/1/",
dirRemoved : true
}];
// Concatenate the common files to the beginning of the array.
gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess);
// Extra directories to check for existence for both complete and partial
// updates. Whether they exist or not is set when calling setupUpdaterTest.
var gTestExtraDirs = [
{
relPathDir : DIR_UPDATED,
dirExists : false
}, {
relPathDir : DIR_TOBEDELETED,
dirExists : false
}];
// This makes it possible to run most tests on xulrunner where the update
// channel default preference is not set.
@ -610,6 +1088,25 @@ function setDefaultPrefs() {
Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true);
}
/**
* Helper function for updater binary tests that sets the appropriate values
* to check for update failures.
*/
function setTestFilesAndDirsForFailure() {
gTestFiles.forEach(function STFADFF_Files(aTestFile) {
aTestFile.compareContents = aTestFile.originalContents;
aTestFile.compareFile = aTestFile.originalFile;
aTestFile.comparePerms = aTestFile.originalPerms;
});
gTestDirs.forEach(function STFADFF_Dirs(aTestDir) {
aTestDir.dirRemoved = false;
if (aTestDir.filesRemoved) {
aTestDir.filesRemoved = false;
}
});
}
/**
* Initializes the most commonly used settings and creates an instance of the
* update service stub.
@ -736,27 +1233,6 @@ function getUpdatedDirPath() {
return getApplyDirPath() + (gStageUpdate ? DIR_UPDATED + "/" : "");
}
/**
* Helper function for getting the directory where files are added, removed,
* and modified by the simple.mar update file.
*
* @return nsIFile for the directory where files are added, removed, and
* modified by the simple.mar update file.
*/
function getUpdateTestDir() {
return getApplyDirFile("update_test", true);
}
/**
* Helper function for getting the updating directory which is used by the
* updater to extract the update manifest and patch files.
*
* @return nsIFile for the directory for the updating directory.
*/
function getUpdatingDir() {
return getApplyDirFile("updating", true);
}
#ifdef XP_WIN
XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash",
function test_gInstallDirPathHash() {
@ -1015,10 +1491,6 @@ function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) {
let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
callbackApp.permissions = PERMS_DIRECTORY;
updateSettingsIni = getApplyDirFile(null, true);
updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
let args = [updatesDir.path, applyToDirPath, 0];
if (gStageUpdate) {
args[2] = -1;
@ -1067,9 +1539,6 @@ function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) {
logTestInfo("testing update status against expected status");
do_check_eq(status, aExpectedStatus);
logTestInfo("testing updating directory doesn't exist");
do_check_false(getUpdatingDir().exists());
if (aCallback !== null) {
if (typeof(aCallback) == typeof(Function)) {
aCallback();
@ -1244,7 +1713,7 @@ function setupAppFiles() {
// Required files for the application or the test that aren't listed in the
// dependentlibs.list file.
let fileRelPaths = [FILE_APP_BIN, FILE_UPDATER_BIN, FILE_UPDATE_SETTINGS_INI,
let fileRelPaths = [FILE_APP_BIN, FILE_UPDATER_BIN,
"application.ini", "dependentlibs.list"];
// On Linux the updater.png must also be copied
@ -1533,10 +2002,6 @@ function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) {
copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN);
copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
let updateSettingsIni = getApplyDirFile(null, true);
updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
let launchBin = getLaunchBin();
let args = getProcessArgs(["-dump-args", appArgsLogPath]);
@ -1588,9 +2053,6 @@ function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) {
checkServiceLogs(svcOriginalLog);
}
logTestInfo("testing updating directory doesn't exist");
do_check_false(getUpdatingDir().exists());
checkUpdateFinished();
}
@ -1714,7 +2176,7 @@ function setupHelperFinish() {
* @param aMarFile
* The mar file for the update test.
*/
function setupUpdaterTest(aMarFile) {
function setupUpdaterTest(aMarFile, aUpdatedDirExists, aToBeDeletedDirExists) {
let updatesPatchDir = getUpdatesPatchDir();
if (!updatesPatchDir.exists()) {
updatesPatchDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
@ -1723,8 +2185,10 @@ function setupUpdaterTest(aMarFile) {
let mar = getTestDirFile(aMarFile);
mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_ARCHIVE);
createUpdateSettingsINI();
let applyToDir = getApplyDirFile(null, true);
TEST_FILES.forEach(function SUT_TF_FE(aTestFile) {
gTestFiles.forEach(function SUT_TF_FE(aTestFile) {
if (aTestFile.originalFile || aTestFile.originalContents) {
let testDir = getApplyDirFile(aTestFile.relPathDir, true);
if (!testDir.exists())
@ -1760,8 +2224,7 @@ function setupUpdaterTest(aMarFile) {
// Add the test directory that will be updated for a successful update or left
// in the initial state for a failed update.
var testDirs = TEST_DIRS.concat(ADDITIONAL_TEST_DIRS);
testDirs.forEach(function SUT_TD_FE(aTestDir) {
gTestDirs.forEach(function SUT_TD_FE(aTestDir) {
let testDir = getApplyDirFile(aTestDir.relPathDir, true);
if (!testDir.exists()) {
testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
@ -1794,6 +2257,23 @@ function setupUpdaterTest(aMarFile) {
});
}
});
gTestExtraDirs[0].dirExists = aUpdatedDirExists;
gTestExtraDirs[1].dirExists = IS_WIN ? aToBeDeletedDirExists : false;
}
/**
* Helper function for updater binary tests that creates the update-settings.ini
* file.
*/
function createUpdateSettingsINI() {
updateSettingsIni = getApplyDirFile(null, true);
if (IS_MACOSX) {
updateSettingsIni.append("Contents");
updateSettingsIni.append("MacOS");
}
updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
}
/**
@ -1808,6 +2288,18 @@ function checkUpdateLogContents(aCompareLogFile) {
updateLog.append(FILE_UPDATE_LOG);
let updateLogContents = readFileBytes(updateLog);
// The channel-prefs.js is defined in gTestFilesCommon which will always be
// located to the end of gTestFiles.
if (gTestFiles.length > 1 &&
gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
!gTestFiles[gTestFiles.length - 1].originalContents) {
updateLogContents = updateLogContents.replace(/.* a\/b\/defaults\/.*/g, "");
}
if (gTestFiles.length > 2 &&
gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
!gTestFiles[gTestFiles.length - 2].originalContents) {
updateLogContents = updateLogContents.replace(/.* a\/b\/update-settings.ini.*/g, "");
}
if (gStageUpdate) {
// Skip the staged update messages
updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
@ -1824,13 +2316,13 @@ function checkUpdateLogContents(aCompareLogFile) {
if (gSwitchApp) {
// Remove the lines which contain absolute paths
updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, "");
#ifdef XP_MACOSX
if (IS_MACOSX) {
// Remove the entire section about moving the precomplete file as it contains
// absolute paths.
updateLogContents = updateLogContents.replace(/\n/g, "%%%EOL%%%");
updateLogContents = updateLogContents.replace(/Moving the precomplete file.*Finished moving the precomplete file/, "");
updateLogContents = updateLogContents.replace(/%%%EOL%%%/g, "\n");
#endif
}
}
updateLogContents = updateLogContents.replace(/\r/g, "");
// Replace error codes since they are different on each platform.
@ -1848,8 +2340,27 @@ function checkUpdateLogContents(aCompareLogFile) {
// from the previous launch of the updater.
updateLogContents = updateLogContents.replace(/^calling QuitProgressUI\n[^\n]*\nUPDATE TYPE/g, "UPDATE TYPE");
let compareLog = getTestDirFile(aCompareLogFile);
let compareLogContents = readFileBytes(compareLog);
let compareLogContents = "";
if (aCompareLogFile) {
compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile));
}
if (gSwitchApp) {
compareLogContents += LOG_SWITCH_SUCCESS;
}
// The channel-prefs.js is defined in gTestFilesCommon which will always be
// located to the end of gTestFiles.
if (gTestFiles.length > 1 &&
gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
!gTestFiles[gTestFiles.length - 1].originalContents) {
compareLogContents = compareLogContents.replace(/.* a\/b\/defaults\/.*/g, "");
}
if (gTestFiles.length > 2 &&
gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
!gTestFiles[gTestFiles.length - 2].originalContents) {
compareLogContents = compareLogContents.replace(/.* a\/b\/update-settings.ini.*/g, "");
}
// Remove leading and trailing newlines
compareLogContents = compareLogContents.replace(/\n+/g, "\n");
// Remove leading and trailing newlines
compareLogContents = compareLogContents.replace(/^\n|\n$/g, "");
@ -1890,7 +2401,7 @@ function checkUpdateLogContains(aCheckString) {
*/
function checkFilesAfterUpdateSuccess() {
logTestInfo("testing contents of files after a successful update");
TEST_FILES.forEach(function CFAUS_TF_FE(aTestFile) {
gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) {
let testFile = getTargetDirFile(aTestFile.relPathDir + aTestFile.fileName,
true);
logTestInfo("testing file: " + testFile.path);
@ -1933,8 +2444,7 @@ function checkFilesAfterUpdateSuccess() {
logTestInfo("testing operations specified in removed-files were performed " +
"after a successful update");
var testDirs = TEST_DIRS.concat(ADDITIONAL_TEST_DIRS);
testDirs.forEach(function CFAUS_TD_FE(aTestDir) {
gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) {
let testDir = getTargetDirFile(aTestDir.relPathDir, true);
logTestInfo("testing directory: " + testDir.path);
if (aTestDir.dirRemoved) {
@ -1984,7 +2494,7 @@ function checkFilesAfterUpdateSuccess() {
function checkFilesAfterUpdateFailure(aGetDirectory) {
let getdir = aGetDirectory || getTargetDirFile;
logTestInfo("testing contents of files after a failed update");
TEST_FILES.forEach(function CFAUF_TF_FE(aTestFile) {
gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) {
let testFile = getdir(aTestFile.relPathDir + aTestFile.fileName, true);
logTestInfo("testing file: " + testFile.path);
if (aTestFile.compareFile || aTestFile.compareContents) {
@ -2026,9 +2536,9 @@ function checkFilesAfterUpdateFailure(aGetDirectory) {
logTestInfo("testing operations specified in removed-files were not " +
"performed after a failed update");
TEST_DIRS.forEach(function CFAUF_TD_FE(aTestDir) {
gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) {
let testDir = getdir(aTestDir.relPathDir, true);
logTestInfo("testing directory file: " + testDir.path);
logTestInfo("testing directory: " + testDir.path);
do_check_true(testDir.exists());
if (aTestDir.files) {
@ -2060,10 +2570,40 @@ function checkFilesAfterUpdateFailure(aGetDirectory) {
}
/**
* Helper function for updater binary tests for verifying patch files and
* moz-backup files aren't left behind after a successful or failed update.
* Helper function for updater binary tests for verifying the state of common
* files and directories after a successful or failed update.
*/
function checkFilesAfterUpdateCommon() {
logTestInfo("testing extra directories");
gTestExtraDirs.forEach(function CFAUC_TED_FE(aTestExtraDir) {
let testDir = getTargetDirFile(aTestExtraDir.relPathDir, true);
logTestInfo("testing directory: " + testDir.path);
if (aTestExtraDir.dirExists) {
do_check_true(testDir.exists());
} else {
do_check_false(testDir.exists());
}
});
logTestInfo("testing updating directory doesn't exist in the application " +
"directory");
let updatingDir = getTargetDirFile("updating", true);
do_check_false(updatingDir.exists());
if (gStageUpdate) {
logTestInfo("testing updating directory doesn't exist in the updated " +
"directory");
updatingDir = getApplyDirFile("updating", true);
do_check_false(updatingDir.exists());
// This should never exist since the update was applied to the updated
// directory and the files should never be in use.
logTestInfo("testing tobedeleted directory doesn't exist in the updated " +
"directory");
let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true);
do_check_false(toBeDeletedDir.exists());
}
logTestInfo("testing patch files should not be left behind");
let updatesDir = getUpdatesPatchDir();
let entries = updatesDir.QueryInterface(AUS_Ci.nsIFile).directoryEntries;

View File

@ -7,11 +7,6 @@
* apply it.
*/
/**
* The MAR file used for this test should not contain a version 2 update
* manifest file (e.g. updatev2.manifest).
*/
function run_test() {
if (MOZ_APP_NAME == "xulrunner") {
logTestInfo("Unable to run this test on xulrunner");
@ -19,6 +14,10 @@ function run_test() {
}
setupTestCommon();
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
setTestFilesAndDirsForFailure();
setupUpdaterTest(FILE_COMPLETE_MAR, false, false);
let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
let patches = getLocalPatchString(null, null, null, null, null, "true",
@ -30,18 +29,11 @@ function run_test() {
writeVersionFile(getAppVersion());
writeStatusFile(STATE_PENDING);
let updatesPatchDir = getUpdatesPatchDir();
let mar = getTestDirFile(FILE_SIMPLE_MAR);
mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
reloadUpdateManagerData();
do_check_true(!!gUpdateManager.activeUpdate);
lockDirectory(getAppBaseDir());
let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
setupAppFilesAsync();
}
@ -60,9 +52,9 @@ function checkUpdateApplied() {
// Don't proceed until the update has failed, and reset to pending.
if (gUpdateManager.activeUpdate.state != STATE_PENDING) {
if (++gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to be " +
STATE_PENDING + ", current state is: " +
gUpdateManager.activeUpdate.state);
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to equal: " +
STATE_PENDING +
", current state: " + gUpdateManager.activeUpdate.state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
}

View File

@ -7,11 +7,6 @@
* apply it.
*/
/**
* The MAR file used for this test should not contain a version 2 update
* manifest file (e.g. updatev2.manifest).
*/
Components.utils.import("resource://gre/modules/ctypes.jsm");
function run_test() {
@ -21,6 +16,9 @@ function run_test() {
}
setupTestCommon();
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
setupUpdaterTest(FILE_COMPLETE_MAR, false, false);
if (IS_WIN) {
Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false);
@ -36,13 +34,6 @@ function run_test() {
writeVersionFile(getAppVersion());
writeStatusFile(STATE_PENDING);
let updatesPatchDir = getUpdatesPatchDir();
let mar = getTestDirFile(FILE_SIMPLE_MAR);
mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
reloadUpdateManagerData();
do_check_true(!!gUpdateManager.activeUpdate);
@ -50,6 +41,16 @@ function run_test() {
}
function setupAppFilesFinished() {
// For Mac OS X set the last modified time for the root directory to a date in
// the past to test that the last modified time is updated on a successful
// update (bug 600098).
if (IS_MACOSX) {
let now = Date.now();
let yesterday = now - (1000 * 60 * 60 * 24);
let applyToDir = getApplyDirFile();
applyToDir.lastModifiedTime = yesterday;
}
stageUpdate();
}
@ -81,25 +82,26 @@ function customLaunchAppToApplyUpdate() {
*/
function checkUpdateApplied() {
gTimeoutRuns++;
// Don't proceed until the active update's state is applied.
// Don't proceed until the active update's state is the expected value.
if (gUpdateManager.activeUpdate.state != STATE_APPLIED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to be " +
"applied, current state is: " +
gUpdateManager.activeUpdate.state);
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to equal: " +
STATE_APPLIED +
", current state: " + gUpdateManager.activeUpdate.state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
}
return;
}
// Don't proceed until the update's status state is applied.
// Don't proceed until the update's status state is the expected value.
let state = readStatusState();
if (state != STATE_APPLIED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
"status state to equal " + STATE_APPLIED + ", " +
"current status state: " + state);
"status state to equal: " +
STATE_APPLIED +
", current status state: " + state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
}
@ -107,7 +109,17 @@ function checkUpdateApplied() {
}
// Don't proceed until the last update log has been created.
let log = getUpdatesDir();
let log;
if (IS_WIN) {
log = getUpdatesDir();
} else {
log = getUpdatedDir();
if (IS_MACOSX) {
log.append("Contents");
log.append("MacOS");
}
log.append(DIR_UPDATES);
}
log.append(FILE_LAST_LOG);
if (!log.exists()) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
@ -119,12 +131,6 @@ function checkUpdateApplied() {
return;
}
// Log the contents of the update.log so it is simpler to diagnose a test
// failure.
let contents = readFile(log);
logTestInfo("contents of " + log.path + ":\n" +
contents.replace(/\r\n/g, "\n"));
let updatedDir = getUpdatedDir();
logTestInfo("testing " + updatedDir.path + " should exist");
do_check_true(updatedDir.exists());
@ -136,47 +142,32 @@ function checkUpdateApplied() {
do_check_eq(readStatusState(), STATE_APPLIED);
}
let updateTestDir = getUpdateTestDir();
logTestInfo("testing " + updateTestDir.path + " shouldn't exist");
do_check_false(updateTestDir.exists());
updateTestDir = updatedDir.clone();
updateTestDir.append("update_test");
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
let updatesDir = getUpdatesDir();
log = updatesDir.clone();
log = getUpdatesDir();
log.append("0");
log.append(FILE_UPDATE_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
log = updatesDir.clone();
log = getUpdatesDir();
log.append(FILE_LAST_LOG);
if (IS_WIN) {
logTestInfo("testing " + log.path + " should exist");
do_check_true(log.exists());
} else {
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
}
log = updatesDir.clone();
log = getUpdatesDir();
log.append(FILE_BACKUP_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
updatesDir = updatedDir.clone();
let updatesDir = getUpdatedDir();
if (IS_MACOSX) {
updatesDir.append("Contents");
updatesDir.append("MacOS");
}
updatesDir.append("updates");
log = updatesDir.clone();
log.append("0");
@ -200,7 +191,15 @@ function checkUpdateApplied() {
logTestInfo("testing " + updatesDir.path + " shouldn't exist");
do_check_false(updatesDir.exists());
// Now, switch the updated version of the app.
// On Windows, make sure not to use the maintenance service for switching
// the app.
if (IS_WIN) {
writeStatusFile(STATE_APPLIED);
do_check_eq(readStatusState(), STATE_APPLIED);
}
// Switch the application to the staged application that was updated by
// launching the application.
do_timeout(TEST_CHECK_TIMEOUT, launchAppToApplyUpdate);
}
@ -210,13 +209,14 @@ function checkUpdateApplied() {
*/
function checkUpdateFinished() {
gTimeoutRuns++;
// Don't proceed until the update's status state is succeeded.
// Don't proceed until the update's status state is the expected value.
let state = readStatusState();
if (state != STATE_SUCCEEDED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
"status state to equal " + STATE_SUCCEEDED + ", " +
"current status state: " + state);
"status state to equal: " +
STATE_SUCCEEDED +
", current status state: " + state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
}
@ -236,27 +236,43 @@ function checkUpdateFinished() {
return;
}
let updateTestDir = getUpdateTestDir();
if (IS_WIN) {
// Don't proceed until the updater binary is no longer in use.
let updater = getUpdatesPatchDir();
updater.append(FILE_UPDATER_BIN);
if (updater.exists()) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded while waiting for updater binary to no longer be " +
"in use");
} else {
try {
updater.remove(false);
} catch (e) {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
return;
}
}
}
}
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
if (IS_MACOSX) {
logTestInfo("testing last modified time on the apply to directory has " +
"changed after a successful update (bug 600098)");
let now = Date.now();
let applyToDir = getApplyDirFile();
let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
}
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
checkFilesAfterUpdateSuccess();
// Sorting on Linux is different so skip this check for now.
if (!IS_UNIX) {
checkUpdateLogContents(LOG_COMPLETE_SUCCESS);
}
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
checkCallbackAppLog();
let updatesDir = getUpdatesDir();
log = updatesDir.clone();
let log = getUpdatesDir();
log.append("0");
log.append(FILE_UPDATE_LOG);
if (IS_WIN) {
@ -269,16 +285,17 @@ function checkUpdateFinished() {
do_check_false(log.exists());
}
log = updatesDir.clone();
log = getUpdatesDir();
log.append(FILE_LAST_LOG);
logTestInfo("testing " + log.path + " should exist");
do_check_true(log.exists());
log = updatesDir.clone();
log = getUpdatesDir();
log.append(FILE_BACKUP_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
let updatesDir = getUpdatesDir();
updatesDir.append("0");
logTestInfo("testing " + updatesDir.path + " should exist");
do_check_true(updatesDir.exists());

View File

@ -7,11 +7,6 @@
* apply it.
*/
/**
* The MAR file used for this test should not contain a version 2 update
* manifest file (e.g. updatev2.manifest).
*/
function run_test() {
if (MOZ_APP_NAME == "xulrunner") {
logTestInfo("Unable to run this test on xulrunner");
@ -19,6 +14,9 @@ function run_test() {
}
setupTestCommon();
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
setupUpdaterTest(FILE_COMPLETE_MAR, false, false);
if (IS_WIN) {
Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false);
@ -34,13 +32,6 @@ function run_test() {
writeVersionFile(getAppVersion());
writeStatusFile(STATE_PENDING);
let updatesPatchDir = getUpdatesPatchDir();
let mar = getTestDirFile(FILE_SIMPLE_MAR);
mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
reloadUpdateManagerData();
do_check_true(!!gUpdateManager.activeUpdate);
@ -48,6 +39,16 @@ function run_test() {
}
function setupAppFilesFinished() {
// For Mac OS X set the last modified time for the root directory to a date in
// the past to test that the last modified time is updated on a successful
// update (bug 600098).
if (IS_MACOSX) {
let now = Date.now();
let yesterday = now - (1000 * 60 * 60 * 24);
let applyToDir = getApplyDirFile();
applyToDir.lastModifiedTime = yesterday;
}
stageUpdate();
}
@ -56,25 +57,26 @@ function setupAppFilesFinished() {
*/
function checkUpdateApplied() {
gTimeoutRuns++;
// Don't proceed until the update state is applied.
// Don't proceed until the active update's state is the expected value.
if (gUpdateManager.activeUpdate.state != STATE_APPLIED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to be " +
"applied, current state is: " +
gUpdateManager.activeUpdate.state);
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for update to equal: " +
STATE_APPLIED +
", current state: " + gUpdateManager.activeUpdate.state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
}
return;
}
// Don't proceed until the update status state is applied.
// Don't proceed until the update's status state is the expected value.
let state = readStatusState();
if (state != STATE_APPLIED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
"status state to equal " + STATE_APPLIED + ", " +
"current status state: " + state);
"status state to equal: " +
STATE_APPLIED +
", current status state: " + state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateApplied);
}
@ -104,38 +106,16 @@ function checkUpdateApplied() {
return;
}
// Log the contents of the update.log so it is simpler to diagnose a test
// failure.
let contents = readFile(log);
logTestInfo("contents of " + log.path + ":\n" +
contents.replace(/\r\n/g, "\n"));
let updatedDir = getUpdatedDir();
logTestInfo("testing " + updatedDir.path + " should exist");
do_check_true(updatedDir.exists());
let updateTestDir = getUpdateTestDir();
logTestInfo("testing " + updateTestDir.path + " shouldn't exist");
do_check_false(updateTestDir.exists());
updateTestDir = getUpdatedDir();
updateTestDir.append("update_test");
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
// On Windows, make sure not to use the maintenance service for switching
// the app.
if (IS_WIN) {
writeStatusFile(STATE_APPLIED);
do_check_eq(readStatusState(), STATE_APPLIED);
}
log = getUpdatesDir();
log.append("0");
@ -193,7 +173,8 @@ function checkUpdateApplied() {
do_check_eq(readStatusState(), STATE_APPLIED);
}
// Now, switch the updated version of the app
// Switch the application to the staged application that was updated by
// launching the application.
do_timeout(TEST_CHECK_TIMEOUT, launchAppToApplyUpdate);
}
@ -203,13 +184,13 @@ function checkUpdateApplied() {
*/
function checkUpdateFinished() {
gTimeoutRuns++;
// Don't proceed until the update status state is succeeded.
// Don't proceed until the update's status state is the expected value.
let state = readStatusState();
if (state != STATE_SUCCEEDED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
"status state to equal " + STATE_SUCCEEDED + ", " +
"current status state: " + state);
"status state to equal: " + STATE_SUCCEEDED +
", current status state: " + state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
}
@ -221,19 +202,22 @@ function checkUpdateFinished() {
let updatedDir = getUpdatedDir();
if (updatedDir.exists()) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded while waiting for update dir to not exist");
do_throw("Exceeded while waiting for updated dir to not exist. Path: " +
updatedDir.path);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
}
return;
}
if (IS_WIN) {
// Don't proceed until the updater binary is no longer in use.
let updater = getUpdatesPatchDir();
updater.append(FILE_UPDATER_BIN);
if (updater.exists()) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded while waiting for updater binary to no longer be in " +
"use");
do_throw("Exceeded while waiting for updater binary to no longer be " +
"in use");
} else {
try {
updater.remove(false);
@ -243,25 +227,25 @@ function checkUpdateFinished() {
}
}
}
}
let updateTestDir = getUpdateTestDir();
if (IS_MACOSX) {
logTestInfo("testing last modified time on the apply to directory has " +
"changed after a successful update (bug 600098)");
let now = Date.now();
let applyToDir = getApplyDirFile();
let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
}
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
checkFilesAfterUpdateSuccess();
// Sorting on Linux is different so skip this check for now.
if (!IS_UNIX) {
gSwitchApp = true;
checkUpdateLogContents();
}
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
checkCallbackAppLog();
let log = getUpdatesDir();
log.append("0");

View File

@ -7,11 +7,6 @@
* apply it.
*/
/**
* The MAR file used for this test should not contain a version 2 update
* manifest file (e.g. updatev2.manifest).
*/
function run_test() {
if (MOZ_APP_NAME == "xulrunner") {
logTestInfo("Unable to run this test on xulrunner");
@ -19,6 +14,19 @@ function run_test() {
}
setupTestCommon();
gTestFiles = gTestFilesCompleteSuccess;
gTestDirs = gTestDirsCompleteSuccess;
setupUpdaterTest(FILE_COMPLETE_MAR, false, false);
// For Mac OS X set the last modified time for the root directory to a date in
// the past to test that the last modified time is updated on a successful
// update (bug 600098).
if (IS_MACOSX) {
let now = Date.now();
let yesterday = now - (1000 * 60 * 60 * 24);
let applyToDir = getApplyDirFile();
applyToDir.lastModifiedTime = yesterday;
}
let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL);
let patches = getLocalPatchString(null, null, null, null, null, "true",
@ -30,34 +38,6 @@ function run_test() {
writeVersionFile(getAppVersion());
writeStatusFile(STATE_PENDING);
// This is the directory where the files that will be updated are located.
let updateTestDir = getUpdateTestDir();
// Add the directory where the files will be added and add files that will be
// removed.
if (!updateTestDir.exists()) {
updateTestDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
}
logTestInfo("update test directory path: " + updateTestDir.path);
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
writeFile(file, "ToBeRemoved");
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
writeFile(file, "ToBeReplaced");
file = updateTestDir.clone();
file.append("removed-files");
writeFile(file, "ToBeReplaced");
let updatesPatchDir = getUpdatesPatchDir();
let mar = getTestDirFile(FILE_SIMPLE_MAR);
mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
let updateSettingsIni = getApplyDirFile(FILE_UPDATE_SETTINGS_INI, true);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
setupAppFilesAsync();
}
@ -71,13 +51,13 @@ function setupAppFilesFinished() {
*/
function checkUpdateFinished() {
gTimeoutRuns++;
// Don't proceed until the update status state is succeeded.
// Don't proceed until the update's status state is the expected value.
let state = readStatusState();
if (state != STATE_SUCCEEDED) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " +
"status state to equal " + STATE_SUCCEEDED + ", " +
"current status state: " + state);
"status state to equal: " + STATE_SUCCEEDED +
", current status state: " + state);
} else {
do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
}
@ -97,12 +77,14 @@ function checkUpdateFinished() {
return;
}
if (IS_WIN) {
// Don't proceed until the updater binary is no longer in use.
let updater = getUpdatesPatchDir();
updater.append(FILE_UPDATER_BIN);
if (updater.exists()) {
if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
do_throw("Exceeded while waiting for updater binary to no longer be in " +
"use");
do_throw("Exceeded while waiting for updater binary to no longer be " +
"in use");
} else {
try {
updater.remove(false);
@ -112,35 +94,30 @@ function checkUpdateFinished() {
}
}
}
}
// Log the contents of the update.log so it is simpler to diagnose a test
// failure. For example, on Windows if the application binary is in use the
// updater will not apply the update.
let contents = readFile(log);
logTestInfo("contents of " + log.path + ":\n" +
contents.replace(/\r\n/g, "\n"));
if (IS_MACOSX) {
logTestInfo("testing last modified time on the apply to directory has " +
"changed after a successful update (bug 600098)");
let now = Date.now();
let applyToDir = getApplyDirFile();
let timeDiff = Math.abs(applyToDir.lastModifiedTime - now);
do_check_true(timeDiff < MAC_MAX_TIME_DIFFERENCE);
}
checkFilesAfterUpdateSuccess();
// Sorting on Linux is different so skip this check for now.
if (!IS_UNIX) {
checkUpdateLogContents(LOG_COMPLETE_SUCCESS);
}
checkCallbackAppLog();
standardInit();
let update = gUpdateManager.getUpdateAt(0);
do_check_eq(update.state, STATE_SUCCEEDED);
let updateTestDir = getUpdateTestDir();
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
log = getUpdatesPatchDir();
log.append(FILE_UPDATE_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");

Some files were not shown because too many files have changed in this diff Show More