Backed out changeset 4e2a9894fb4c (bug 1772932) for causing bc failures on browser_addon_list_reordering.js. CLOSED TREE

This commit is contained in:
Iulian Moraru 2023-02-25 08:57:55 +02:00
parent 9258abc05d
commit 09f8e5b108
21 changed files with 172 additions and 143 deletions

View file

@ -1842,11 +1842,9 @@ class SchemaAPIManager extends EventEmitter {
ExtensionAPI,
ExtensionAPIPersistent,
ExtensionCommon,
IOUtils,
MatchGlob,
MatchPattern,
MatchPatternSet,
PathUtils,
Services,
StructuredCloneHolder,
WebExtensionPolicy,

View file

@ -21,6 +21,7 @@ ChromeUtils.defineModuleGetter(
ChromeUtils.defineESModuleGetters(lazy, {
JSONFile: "resource://gre/modules/JSONFile.sys.mjs",
});
ChromeUtils.defineModuleGetter(lazy, "OS", "resource://gre/modules/osfile.jsm");
function isStructuredCloneHolder(value) {
return (
@ -104,7 +105,10 @@ var ExtensionStorage = {
* @returns {Promise<JSONFile>}
*/
async _readFile(extensionId) {
await IOUtils.makeDirectory(this.getExtensionDir(extensionId));
lazy.OS.File.makeDir(this.getExtensionDir(extensionId), {
ignoreExisting: true,
from: lazy.OS.Constants.Path.profileDir,
});
let jsonFile = new lazy.JSONFile({
path: this.getStorageFile(extensionId),
@ -182,7 +186,7 @@ var ExtensionStorage = {
* @returns {string}
*/
getExtensionDir(extensionId) {
return PathUtils.join(this.extensionDir, extensionId);
return lazy.OS.Path.join(this.extensionDir, extensionId);
},
/**
@ -194,7 +198,7 @@ var ExtensionStorage = {
* @returns {string}
*/
getStorageFile(extensionId) {
return PathUtils.join(this.extensionDir, extensionId, "storage.js");
return lazy.OS.Path.join(this.extensionDir, extensionId, "storage.js");
},
/**
@ -446,7 +450,7 @@ var ExtensionStorage = {
};
XPCOMUtils.defineLazyGetter(ExtensionStorage, "extensionDir", () =>
PathUtils.join(PathUtils.profileDir, "browser-extension-data")
lazy.OS.Path.join(lazy.OS.Constants.Path.profileDir, "browser-extension-data")
);
ExtensionStorage.init();

View file

@ -20,6 +20,7 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
ExtensionStorage: "resource://gre/modules/ExtensionStorage.jsm",
ExtensionUtils: "resource://gre/modules/ExtensionUtils.jsm",
getTrimmedString: "resource://gre/modules/ExtensionTelemetry.jsm",
OS: "resource://gre/modules/osfile.jsm",
});
// The userContextID reserved for the extension storage (its purpose is ensuring that the IndexedDB
@ -460,15 +461,17 @@ async function migrateJSONFileData(extension, storagePrincipal) {
abortIfShuttingDown();
oldStoragePath = lazy.ExtensionStorage.getStorageFile(extension.id);
oldStorageExists = await IOUtils.exists(oldStoragePath).catch(fileErr => {
// If we can't access the oldStoragePath here, then extension is also going to be unable to
// access it, and so we log the error but we don't stop the extension from switching to
// the IndexedDB backend.
extension.logWarning(
`Unable to access extension storage.local data file: ${fileErr.message}::${fileErr.stack}`
);
return false;
});
oldStorageExists = await lazy.OS.File.exists(oldStoragePath).catch(
fileErr => {
// If we can't access the oldStoragePath here, then extension is also going to be unable to
// access it, and so we log the error but we don't stop the extension from switching to
// the IndexedDB backend.
extension.logWarning(
`Unable to access extension storage.local data file: ${fileErr.message}::${fileErr.stack}`
);
return false;
}
);
// Migrate any data stored in the JSONFile backend (if any), and remove the old data file
// if the migration has been completed successfully.
@ -542,12 +545,15 @@ async function migrateJSONFileData(extension, storagePrincipal) {
try {
// Only migrate the file when it actually exists (e.g. the file name is not going to exist
// when it is corrupted, because JSONFile internally rename it to `.corrupt`.
if (await IOUtils.exists(oldStoragePath)) {
const uniquePath = await IOUtils.createUniqueFile(
PathUtils.parent(oldStoragePath),
`${PathUtils.filename(oldStoragePath)}.migrated`
if (await lazy.OS.File.exists(oldStoragePath)) {
let openInfo = await lazy.OS.File.openUnique(
`${oldStoragePath}.migrated`,
{
humanReadable: true,
}
);
await IOUtils.move(oldStoragePath, uniquePath);
await openInfo.file.close();
await lazy.OS.File.move(oldStoragePath, openInfo.path);
}
} catch (err) {
nonFatalError = err;

View file

@ -52,6 +52,8 @@ ChromeUtils.defineModuleGetter(
"ExtensionPermissions",
"resource://gre/modules/ExtensionPermissions.jsm"
);
ChromeUtils.defineModuleGetter(lazy, "OS", "resource://gre/modules/osfile.jsm");
XPCOMUtils.defineLazyGetter(
lazy,
"apiManager",
@ -214,7 +216,7 @@ class MockExtension {
});
})
.then(() => {
return IOUtils.remove(this.file.path);
return lazy.OS.File.remove(this.file.path);
});
}

View file

@ -21,6 +21,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
});
XPCOMUtils.defineLazyModuleGetters(lazy, {
OS: "resource://gre/modules/osfile.jsm",
Schemas: "resource://gre/modules/Schemas.jsm",
});
@ -99,7 +100,7 @@ var NativeManifests = {
_tryPath(type, path, name, context, logIfNotFound) {
return Promise.resolve()
.then(() => IOUtils.readUTF8(path))
.then(() => lazy.OS.File.read(path, { encoding: "utf-8" }))
.then(data => {
let manifest;
try {
@ -147,7 +148,7 @@ var NativeManifests = {
return manifest;
})
.catch(ex => {
if (DOMException.isInstance(ex) && ex.name == "NotFoundError") {
if (ex instanceof lazy.OS.File.Error && ex.becauseNoSuchFile) {
if (logIfNotFound) {
Cu.reportError(
`Error reading native manifest file ${path}: file is referenced in the registry but does not exist`
@ -161,7 +162,7 @@ var NativeManifests = {
async _tryPaths(type, name, dirs, context) {
for (let dir of dirs) {
let path = PathUtils.join(dir, TYPES[type], `${name}.json`);
let path = lazy.OS.Path.join(dir, TYPES[type], `${name}.json`);
let manifest = await this._tryPath(type, path, name, context, false);
if (manifest) {
return { path, manifest };

View file

@ -31,6 +31,7 @@ ChromeUtils.defineESModuleGetters(lazy, {
XPCOMUtils.defineLazyModuleGetters(lazy, {
NativeManifests: "resource://gre/modules/NativeManifests.jsm",
OS: "resource://gre/modules/osfile.jsm",
});
// For a graceful shutdown (i.e., when the extension is unloaded or when it
@ -88,26 +89,21 @@ var NativeApp = class extends EventEmitter {
let command = hostInfo.manifest.path;
if (AppConstants.platform == "win") {
// OS.Path.join() ignores anything before the last absolute path
// it sees, so if command is already absolute, it remains unchanged
// here. If it is relative, we get the proper absolute path here.
command = lazy.OS.Path.join(
lazy.OS.Path.dirname(hostInfo.path),
command
);
// Normalize in case the extension used / instead of \.
command = command.replaceAll("/", "\\");
if (!PathUtils.isAbsolute(command)) {
const parentPath = PathUtils.parent(
hostInfo.path.replaceAll("/", "\\")
);
command = PathUtils.joinRelative(parentPath, command);
}
} else if (!PathUtils.isAbsolute(command)) {
// Only windows supports relative paths.
throw new Error(
"NativeApp requires absolute path to command on this platform"
);
}
let subprocessOpts = {
command: command,
arguments: [hostInfo.path, context.extension.id],
workdir: PathUtils.parent(command),
workdir: lazy.OS.Path.dirname(command),
stderr: "pipe",
disclaim: true,
};

View file

@ -9,6 +9,7 @@ ChromeUtils.defineESModuleGetters(this, {
Downloads: "resource://gre/modules/Downloads.sys.mjs",
FileUtils: "resource://gre/modules/FileUtils.sys.mjs",
});
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
ChromeUtils.defineModuleGetter(
this,
"DownloadLastDir",
@ -668,26 +669,21 @@ this.downloads = class extends ExtensionAPIPersistent {
return Promise.reject({ message: "filename must not be empty" });
}
if (PathUtils.isAbsolute(filename)) {
let path = OS.Path.split(filename);
if (path.absolute) {
return Promise.reject({
message: "filename must not be an absolute path",
});
}
const pathComponents = PathUtils.splitRelative(filename, {
allowEmpty: true,
allowCurrentDir: true,
allowParentDir: true,
});
if (pathComponents.some(component => component == "..")) {
if (path.components.some(component => component == "..")) {
return Promise.reject({
message: "filename must not contain back-references (..)",
});
}
if (
pathComponents.some(component => {
path.components.some(component => {
let sanitized = DownloadPaths.sanitize(component, {
compressWhitespaces: false,
});
@ -830,10 +826,7 @@ this.downloads = class extends ExtensionAPIPersistent {
}
}
let target = PathUtils.joinRelative(
downloadsDir,
filename || "download"
);
let target = OS.Path.join(downloadsDir, filename || "download");
let saveAs;
if (options.saveAs !== null) {
@ -850,10 +843,10 @@ this.downloads = class extends ExtensionAPIPersistent {
}
// Create any needed subdirectories if required by filename.
const dir = PathUtils.parent(target);
await IOUtils.makeDirectory(dir);
const dir = OS.Path.dirname(target);
await OS.File.makeDir(dir, { from: downloadsDir });
if (await IOUtils.exists(target)) {
if (await OS.File.exists(target)) {
// This has a race, something else could come along and create
// the file between this test and them time the download code
// creates the target file. But we can't easily fix it without
@ -867,7 +860,7 @@ this.downloads = class extends ExtensionAPIPersistent {
if (saveAs) {
// createNiceUniqueFile actually creates the file, which
// is premature if we need to show a SaveAs dialog.
await IOUtils.remove(target);
await OS.File.remove(target);
}
break;
@ -922,7 +915,7 @@ this.downloads = class extends ExtensionAPIPersistent {
// so that this doesn't break where navigator:browser isn't the
// main window (e.g. Thunderbird).
const window = global.windowTracker.getTopWindow().window;
const basename = PathUtils.filename(target);
const basename = OS.Path.basename(target);
const ext = basename.match(/\.([^.]+)$/)?.[1];
// If the filename passed in by the extension is a simple name
@ -1061,12 +1054,9 @@ this.downloads = class extends ExtensionAPIPersistent {
message: `Cannot remove incomplete download id ${id}`,
});
}
return IOUtils.remove(item.filename, { ignoreAbsent: false }).catch(
return OS.File.remove(item.filename, { ignoreAbsent: false }).catch(
err => {
if (
DOMException.isInstance(err) &&
err.name === "NotFoundError"
) {
if (err.becauseNoSuchFile) {
return Promise.reject({
message: `Could not remove download id ${item.id} because the file doesn't exist`,
});
@ -1223,7 +1213,7 @@ this.downloads = class extends ExtensionAPIPersistent {
let file = FileUtils.File(download.target.path);
path = Services.io.newFileURI(file).spec;
} else {
path = PathUtils.filename(download.target.path);
path = OS.Path.basename(download.target.path);
pathPrefix = "//";
}

View file

@ -6,6 +6,11 @@
"use strict";
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
// eslint-disable-next-line mozilla/reject-importGlobalProperties
Cu.importGlobalProperties(["IOUtils", "PathUtils"]);
const PREF_ASYNC_STACK = "javascript.options.asyncstack";
const ASYNC_STACKS_ENABLED = Services.prefs.getBoolPref(
@ -131,7 +136,10 @@ this.geckoProfiler = class extends ExtensionAPI {
throw new ExtensionError("Path cannot contain a subdirectory.");
}
let dirPath = PathUtils.join(PathUtils.profileDir, "profiler");
let dirPath = PathUtils.join(
OS.Constants.Path.profileDir,
"profiler"
);
let filePath = PathUtils.join(dirPath, fileName);
try {

View file

@ -12,29 +12,26 @@
<script type="text/javascript">
"use strict";
const {OS} = ChromeUtils.import("resource://gre/modules/osfile.jsm");
// Test that the default paths searched for native host manifests
// are the ones we expect.
add_task(async function test_default_paths() {
let expectUser, expectGlobal;
switch (AppConstants.platform) {
case "macosx": {
expectUser = PathUtils.joinRelative(
Services.dirsvc.get("Home", Ci.nsIFile).path,
"Library/Application Support/Mozilla"
);
expectUser = OS.Path.join(OS.Constants.Path.homeDir,
"Library/Application Support/Mozilla");
expectGlobal = "/Library/Application Support/Mozilla";
break;
}
case "linux": {
expectUser = PathUtils.join(
Services.dirsvc.get("Home", Ci.nsIFile).path,
".mozilla"
);
expectUser = OS.Path.join(OS.Constants.Path.homeDir, ".mozilla");
const libdir = AppConstants.HAVE_USR_LIB64_DIR ? "lib64" : "lib";
expectGlobal = PathUtils.join("/usr", libdir, "mozilla");
expectGlobal = OS.Path.join("/usr", libdir, "mozilla");
break;
}

View file

@ -46,12 +46,8 @@ async function background() {
"Should fail with a forbidden header"
);
const absoluteFilename = SpecialPowers.Services.appinfo.OS === "WINNT"
? "C:\\tmp\\file.gif"
: "/tmp/file.gif";
await browser.test.assertRejects(
browser.downloads.download({url, filename: absoluteFilename}),
browser.downloads.download({url, filename: "/tmp/file.gif"}),
/filename must not be an absolute path/,
"Should fail with an absolute file path"
);

View file

@ -8,6 +8,7 @@
ChromeUtils.defineESModuleGetters(this, {
MockRegistry: "resource://testing-common/MockRegistry.sys.mjs",
});
ChromeUtils.defineModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
if (AppConstants.platform == "win") {
ChromeUtils.defineESModuleGetters(this, {
SubprocessImpl: "resource://gre/modules/subprocess/subprocess_win.sys.mjs",
@ -31,29 +32,28 @@ const TYPE_SLUG =
AppConstants.platform === "linux"
? "native-messaging-hosts"
: "NativeMessagingHosts";
OS.File.makeDir(OS.Path.join(tmpDir.path, TYPE_SLUG));
add_setup(async function setup() {
await IOUtils.makeDirectory(PathUtils.join(tmpDir.path, TYPE_SLUG));
});
registerCleanupFunction(async () => {
await IOUtils.remove(tmpDir.path, { recursive: true });
registerCleanupFunction(() => {
tmpDir.remove(true);
});
function getPath(filename) {
return PathUtils.join(tmpDir.path, TYPE_SLUG, filename);
return OS.Path.join(tmpDir.path, TYPE_SLUG, filename);
}
const ID = "native@tests.mozilla.org";
async function setupHosts(scripts) {
const PERMS = { unixMode: 0o755 };
const pythonPath = await Subprocess.pathSearch(Services.env.get("PYTHON"));
async function writeManifest(script, scriptPath, path) {
let body = `#!${pythonPath} -u\n${script.script}`;
await IOUtils.writeUTF8(scriptPath, body);
await IOUtils.setPermissions(scriptPath, 0o755);
await OS.File.writeAtomic(scriptPath, body);
await OS.File.setPermissions(scriptPath, PERMS);
let manifest = {
name: script.name,
@ -67,7 +67,7 @@ async function setupHosts(scripts) {
script._hookModifyManifest?.(manifest);
let manifestPath = getPath(`${script.name}.json`);
await IOUtils.writeJSON(manifestPath, manifest);
await OS.File.writeAtomic(manifestPath, JSON.stringify(manifest));
return manifestPath;
}
@ -115,7 +115,7 @@ async function setupHosts(scripts) {
let scriptPath = getPath(`${script.name}.py`);
let batBody = `@ECHO OFF\n${pythonPath} -u "${scriptPath}" %*\n`;
await IOUtils.writeUTF8(batPath, batBody);
await OS.File.writeAtomic(batPath, batBody);
let manifestPath = await writeManifest(script, scriptPath, batPath);

View file

@ -268,7 +268,7 @@ add_task(async function test_downloads() {
// Try to download to an absolute path.
const absolutePath = OS.Path.join(
WINDOWS ? "C:\\tmp" : "/tmp",
WINDOWS ? "\\tmp" : "/tmp",
"file_download.txt"
);
await download({

View file

@ -6,6 +6,8 @@ const { Downloads } = ChromeUtils.importESModule(
"resource://gre/modules/Downloads.sys.mjs"
);
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
const { TestUtils } = ChromeUtils.importESModule(
"resource://testing-common/TestUtils.sys.mjs"
);
@ -230,16 +232,19 @@ let downloadDir;
let extension;
async function waitForCreatedPartFile(baseFilename = "interruptible.html") {
const partFilePath = PathUtils.join(downloadDir.path, `${baseFilename}.part`);
const partFilePath = `${downloadDir.path}/${baseFilename}.part`;
info(`Wait for ${partFilePath} to be created`);
let lastError;
await TestUtils.waitForCondition(
() =>
IOUtils.exists(partFilePath).catch(err => {
lastError = err;
return false;
}),
async () =>
OS.File.stat(partFilePath).then(
() => true,
err => {
lastError = err;
return false;
}
),
`Wait for the ${partFilePath} to exists before pausing the download`
).catch(err => {
if (lastError) {
@ -854,8 +859,17 @@ add_task(async function test_file_removeFile_permission_failure() {
// completely artificial such as mocking + breaking an internal API.
equal(msg.errmsg, "An unexpected error occurred", "Error message redacted");
// Note: these errors are specific to OS.File.remove. If IOUtils.remove is
// used instead in ext-downloads.js (bug 1772932), then the error name is
// going to be "NotAllowedError" on Windows and non-Windows.
const expectedErrorMessagePattern =
AppConstants.platform === "win"
? // error 32 = ERROR_SHARING_VIOLATION
/Win error 32 during operation remove on file .*subdir.*downloaded_filename/
: // error 13 = EACCES
/Unix error 13 during operation remove on file .*subdir.*downloaded_filename/;
AddonTestUtils.checkMessages(consoleOutput.messages, {
expected: [{ message: /NotAllowedError/ }],
expected: [{ message: expectedErrorMessagePattern }],
});
ok(await IOUtils.exists(expectedPath), "File exists before removeFile()");

View file

@ -2,6 +2,8 @@
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
let getExtension = () => {
return ExtensionTestUtils.loadExtension({
background: async function() {
@ -119,7 +121,9 @@ let getExtension = () => {
});
};
let verifyProfileData = profile => {
let verifyProfileData = bytes => {
let textDecoder = new TextDecoder();
let profile = JSON.parse(textDecoder.decode(bytes));
ok("libs" in profile, "The profile contains libs.");
ok("meta" in profile, "The profile contains meta.");
ok("threads" in profile, "The profile contains threads.");
@ -148,40 +152,40 @@ add_task(async function testProfilerControl() {
extension.sendMessage("test profile");
await extension.awaitMessage("tested profile");
const profilerPath = PathUtils.join(PathUtils.profileDir, "profiler");
const profilerPath = OS.Path.join(OS.Constants.Path.profileDir, "profiler");
let data, fileName, targetPath;
// test with file name only
fileName = "bar.profile";
targetPath = PathUtils.join(profilerPath, fileName);
targetPath = OS.Path.join(profilerPath, fileName);
extension.sendMessage("test dump to file", { fileName });
data = await extension.awaitMessage("tested dump to file");
equal(data.error, undefined, "No error thrown");
ok(await IOUtils.exists(targetPath), "Saved gecko profile exists.");
verifyProfileData(await IOUtils.readJSON(targetPath));
ok(await OS.File.exists(targetPath), "Saved gecko profile exists.");
verifyProfileData(await OS.File.read(targetPath));
// test overwriting the formerly created file
extension.sendMessage("test dump to file", { fileName });
data = await extension.awaitMessage("tested dump to file");
equal(data.error, undefined, "No error thrown");
ok(await IOUtils.exists(targetPath), "Saved gecko profile exists.");
verifyProfileData(await IOUtils.readJSON(targetPath));
ok(await OS.File.exists(targetPath), "Saved gecko profile exists.");
verifyProfileData(await OS.File.read(targetPath));
// test with a POSIX path, which is not allowed
fileName = "foo/bar.profile";
targetPath = PathUtils.join(profilerPath, ...fileName.split("/"));
targetPath = OS.Path.join(profilerPath, ...fileName.split("/"));
extension.sendMessage("test dump to file", { fileName });
data = await extension.awaitMessage("tested dump to file");
equal(data.error, "Path cannot contain a subdirectory.");
ok(!(await IOUtils.exists(targetPath)), "Gecko profile hasn't been saved.");
ok(!(await OS.File.exists(targetPath)), "Gecko profile hasn't been saved.");
// test with a non POSIX path which is not allowed
fileName = "foo\\bar.profile";
targetPath = PathUtils.join(profilerPath, ...fileName.split("\\"));
targetPath = OS.Path.join(profilerPath, ...fileName.split("\\"));
extension.sendMessage("test dump to file", { fileName });
data = await extension.awaitMessage("tested dump to file");
equal(data.error, "Path cannot contain a subdirectory.");
ok(!(await IOUtils.exists(targetPath)), "Gecko profile hasn't been saved.");
ok(!(await OS.File.exists(targetPath)), "Gecko profile hasn't been saved.");
extension.sendMessage("test profile as array buffer");
await extension.awaitMessage("tested profile as array buffer");

View file

@ -3,8 +3,9 @@
const { FileUtils } = ChromeUtils.importESModule(
"resource://gre/modules/FileUtils.sys.mjs"
);
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
add_setup(async function setup() {
add_task(async function setup() {
// Add a test .ftl file
// (Note: other tests do this by patching L10nRegistry.load() but in
// this test L10nRegistry is also loaded in the extension process --
@ -13,8 +14,8 @@ add_setup(async function setup() {
let dir = FileUtils.getDir("TmpD", ["l10ntest"]);
dir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
await IOUtils.writeUTF8(
PathUtils.join(dir.path, "test.ftl"),
await OS.File.writeAtomic(
OS.Path.join(dir.path, "test.ftl"),
"key = value\n"
);

View file

@ -383,7 +383,7 @@ if (AppConstants.platform == "win") {
appname: "relative.echo",
expectedError: "An unexpected error occurred",
expectedConsoleMessages: [
/NativeApp requires absolute path to command on this platform/,
/File at path "relative\.echo\.py" does not exist, or is not executable/,
],
});
});

View file

@ -34,6 +34,10 @@ const { TelemetryTestUtils } = ChromeUtils.importESModule(
"resource://testing-common/TelemetryTestUtils.sys.mjs"
);
XPCOMUtils.defineLazyModuleGetters(this, {
OS: "resource://gre/modules/osfile.jsm",
});
const { promiseShutdownManager, promiseStartupManager } = AddonTestUtils;
const {
@ -58,7 +62,7 @@ async function createExtensionJSONFileWithData(extensionId, data) {
await jsonFile._save();
const oldStorageFilename = ExtensionStorage.getStorageFile(extensionId);
equal(
await IOUtils.exists(oldStorageFilename),
await OS.File.exists(oldStorageFilename),
true,
"The old json file has been created"
);
@ -315,13 +319,13 @@ add_task(async function test_storage_local_data_migration() {
);
equal(
await IOUtils.exists(oldStorageFilename),
await OS.File.exists(oldStorageFilename),
false,
"The old json storage file name should not exist anymore"
);
equal(
await IOUtils.exists(`${oldStorageFilename}.migrated`),
await OS.File.exists(`${oldStorageFilename}.migrated`),
true,
"The old json storage file name should have been renamed as .migrated"
);
@ -475,14 +479,16 @@ add_task(async function test_storage_local_corrupted_data_migration() {
const invalidData = `{"test_key_string": "test_value1"`;
const oldStorageFilename = ExtensionStorage.getStorageFile(EXTENSION_ID);
await IOUtils.makeDirectory(
PathUtils.join(PathUtils.profileDir, "browser-extension-data", EXTENSION_ID)
const profileDir = OS.Constants.Path.profileDir;
await OS.File.makeDir(
OS.Path.join(profileDir, "browser-extension-data", EXTENSION_ID),
{ from: profileDir, ignoreExisting: true }
);
// Write the json file with some invalid data.
await IOUtils.writeUTF8(oldStorageFilename, invalidData, { flush: true });
await OS.File.writeAtomic(oldStorageFilename, invalidData, { flush: true });
equal(
await IOUtils.readUTF8(oldStorageFilename),
await OS.File.read(oldStorageFilename, { encoding: "utf-8" }),
invalidData,
"The old json file has been overwritten with invalid data"
);
@ -534,7 +540,7 @@ add_task(async function test_storage_local_corrupted_data_migration() {
);
equal(
await IOUtils.exists(`${oldStorageFilename}.corrupt`),
await OS.File.exists(`${oldStorageFilename}.corrupt`),
true,
"The old json storage should still be available if failed to be read"
);
@ -623,7 +629,7 @@ add_task(async function test_storage_local_data_migration_failure() {
"No data stored in the ExtensionStorageIDB backend as expected"
);
equal(
await IOUtils.exists(oldStorageFilename),
await OS.File.exists(oldStorageFilename),
true,
"The old json storage should still be available if failed to be read"
);

View file

@ -4,6 +4,10 @@ ChromeUtils.defineESModuleGetters(this, {
MockRegistry: "resource://testing-common/MockRegistry.sys.mjs",
});
XPCOMUtils.defineLazyModuleGetters(this, {
OS: "resource://gre/modules/osfile.jsm",
});
const MANIFEST = {
name: "test-storage-managed@mozilla.com",
description: "",
@ -40,10 +44,10 @@ add_task(async function setup() {
let typeSlug =
AppConstants.platform === "linux" ? "managed-storage" : "ManagedStorage";
await IOUtils.makeDirectory(PathUtils.join(tmpDir.path, typeSlug));
OS.File.makeDir(OS.Path.join(tmpDir.path, typeSlug));
let path = PathUtils.join(tmpDir.path, typeSlug, `${MANIFEST.name}.json`);
await IOUtils.writeJSON(path, MANIFEST);
let path = OS.Path.join(tmpDir.path, typeSlug, `${MANIFEST.name}.json`);
await OS.File.writeAtomic(path, JSON.stringify(MANIFEST));
let registry;
if (AppConstants.platform === "win") {

View file

@ -1,5 +1,7 @@
"use strict";
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
const HOSTS = new Set(["example.com", "example.org", "example.net"]);
const server = createHttpServer({ hosts: HOSTS });
@ -68,8 +70,8 @@ server.registerPathHandler("/lorem.html.gz", async (request, response) => {
);
response.setHeader("Content-Encoding", "gzip", false);
let data = await IOUtils.read(do_get_file("data/lorem.html.gz").path);
response.write(String.fromCharCode(...data));
let data = await OS.File.read(do_get_file("data/lorem.html.gz").path);
response.write(String.fromCharCode(...new Uint8Array(data)));
response.finish();
});

View file

@ -3,6 +3,7 @@
/* eslint-disable mozilla/no-arbitrary-setTimeout */
/* eslint-disable no-shadow */
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
const { ExtensionTestCommon } = ChromeUtils.import(
"resource://testing-common/ExtensionTestCommon.jsm"
);
@ -74,8 +75,8 @@ server.registerPathHandler("/lorem.html.gz", async (request, response) => {
);
response.setHeader("Content-Encoding", "gzip", false);
let data = await IOUtils.read(do_get_file("data/lorem.html.gz").path);
response.write(String.fromCharCode(...data));
let data = await OS.File.read(do_get_file("data/lorem.html.gz").path);
response.write(String.fromCharCode(...new Uint8Array(data)));
response.finish();
});

View file

@ -16,6 +16,7 @@ const { Subprocess } = ChromeUtils.importESModule(
const { NativeApp } = ChromeUtils.import(
"resource://gre/modules/NativeMessaging.jsm"
);
const { OS } = ChromeUtils.import("resource://gre/modules/osfile.jsm");
let registry = null;
if (AppConstants.platform == "win") {
@ -55,10 +56,8 @@ let globalDir = dir.clone();
globalDir.append("global");
globalDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
add_setup(async function setup() {
await IOUtils.makeDirectory(PathUtils.join(userDir.path, TYPE_SLUG));
await IOUtils.makeDirectory(PathUtils.join(globalDir.path, TYPE_SLUG));
});
OS.File.makeDir(OS.Path.join(userDir.path, TYPE_SLUG));
OS.File.makeDir(OS.Path.join(globalDir.path, TYPE_SLUG));
let dirProvider = {
getFile(property) {
@ -82,7 +81,7 @@ function writeManifest(path, manifest) {
if (typeof manifest != "string") {
manifest = JSON.stringify(manifest);
}
return IOUtils.writeUTF8(path, manifest);
return OS.File.writeAtomic(path, manifest);
}
let PYTHON;
@ -157,7 +156,7 @@ add_task(async function test_nonexistent_manifest() {
);
});
const USER_TEST_JSON = PathUtils.join(userDir.path, TYPE_SLUG, "test.json");
const USER_TEST_JSON = OS.Path.join(userDir.path, TYPE_SLUG, "test.json");
add_task(async function test_nonexistent_manifest_with_registry_entry() {
if (registry) {
@ -169,7 +168,7 @@ add_task(async function test_nonexistent_manifest_with_registry_entry() {
);
}
await IOUtils.remove(USER_TEST_JSON);
await OS.File.remove(USER_TEST_JSON);
let { messages, result } = await promiseConsoleOutput(() =>
lookupApplication("test", context)
);
@ -284,12 +283,12 @@ add_task(async function test_no_allowed_extensions() {
);
});
const GLOBAL_TEST_JSON = PathUtils.join(globalDir.path, TYPE_SLUG, "test.json");
const GLOBAL_TEST_JSON = OS.Path.join(globalDir.path, TYPE_SLUG, "test.json");
let globalManifest = Object.assign({}, templateManifest);
globalManifest.description = "This manifest is from the systemwide directory";
add_task(async function good_manifest_system_dir() {
await IOUtils.remove(USER_TEST_JSON);
await OS.File.remove(USER_TEST_JSON);
await writeManifest(GLOBAL_TEST_JSON, globalManifest);
if (registry) {
registry.setValue(
@ -380,8 +379,8 @@ while True:
stdout.write(msg)
`;
let scriptPath = PathUtils.join(userDir.path, TYPE_SLUG, "wontdie.py");
let manifestPath = PathUtils.join(userDir.path, TYPE_SLUG, "wontdie.json");
let scriptPath = OS.Path.join(userDir.path, TYPE_SLUG, "wontdie.py");
let manifestPath = OS.Path.join(userDir.path, TYPE_SLUG, "wontdie.json");
const ID = "native@tests.mozilla.org";
let manifest = {
@ -392,12 +391,12 @@ while True:
};
if (AppConstants.platform == "win") {
await IOUtils.writeUTF8(scriptPath, SCRIPT);
await OS.File.writeAtomic(scriptPath, SCRIPT);
let batPath = PathUtils.join(userDir.path, TYPE_SLUG, "wontdie.bat");
let batPath = OS.Path.join(userDir.path, TYPE_SLUG, "wontdie.bat");
let batBody = `@ECHO OFF\n${PYTHON} -u "${scriptPath}" %*\n`;
await IOUtils.writeUTF8(batPath, batBody);
await IOUtils.setPermissions(batPath, 0o755);
await OS.File.writeAtomic(batPath, batBody);
await OS.File.setPermissions(batPath, { unixMode: 0o755 });
manifest.path = batPath;
await writeManifest(manifestPath, manifest);
@ -409,8 +408,8 @@ while True:
manifestPath
);
} else {
await IOUtils.writeUTF8(scriptPath, `#!${PYTHON} -u\n${SCRIPT}`);
await IOUtils.setPermissions(scriptPath, 0o755);
await OS.File.writeAtomic(scriptPath, `#!${PYTHON} -u\n${SCRIPT}`);
await OS.File.setPermissions(scriptPath, { unixMode: 0o755 });
manifest.path = scriptPath;
await writeManifest(manifestPath, manifest);
}