/* 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/. */ // Heap snapshots are always saved in the temp directory, and have a regular // naming convention. This module provides helpers for working with heap // snapshot files in a safe manner. Because we attempt to avoid unnecessary // copies of the heap snapshot files by checking the local filesystem for a heap // snapshot file with the given snapshot id, we want to ensure that we are only // attempting to open heap snapshot files and not `~/.ssh/id_rsa`, for // example. Therefore, the RDP only talks about snapshot ids, or transfering the // bulk file data. A file path can be recovered from a snapshot id, which allows // one to check for the presence of the heap snapshot file on the local file // system, but we don't have to worry about opening arbitrary files. // // The heap snapshot file path conventions permits the following forms: // // $TEMP_DIRECTORY/XXXXXXXXXX.fxsnapshot // $TEMP_DIRECTORY/XXXXXXXXXX-XXXXX.fxsnapshot // // Where the strings of "X" are zero or more digits. "use strict"; const { Ci } = require("chrome"); loader.lazyRequireGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm", true); loader.lazyRequireGetter(this, "OS", "resource://gre/modules/osfile.jsm", true); function getHeapSnapshotFileTemplate() { return OS.Path.join(OS.Constants.Path.tmpDir, `${Date.now()}.fxsnapshot`); } /** * Get a unique temp file path for a new heap snapshot. The file is guaranteed * not to exist before this call. * * @returns String */ exports.getNewUniqueHeapSnapshotTempFilePath = function () { let file = new FileUtils.File(getHeapSnapshotFileTemplate()); // The call to createUnique will append "-N" after the leaf name (but before // the extension) until a new file is found and create it. This guarantees we // won't accidentally choose the same file twice. file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o666); return file.path; }; function isValidSnapshotFileId(snapshotId) { return /^\d+(\-\d+)?$/.test(snapshotId); } /** * Get the file path for the given snapshot id. * * @param {String} snapshotId * * @returns String | null */ exports.getHeapSnapshotTempFilePath = function (snapshotId) { // Don't want anyone sneaking "../../../.." strings into the snapshot id and // trying to make us open arbitrary files. if (!isValidSnapshotFileId(snapshotId)) { return null; } return OS.Path.join(OS.Constants.Path.tmpDir, snapshotId + ".fxsnapshot"); }; /** * Return true if we have the heap snapshot file for the given snapshot id on * the local file system. False is returned otherwise. * * @returns Promise */ exports.haveHeapSnapshotTempFile = function (snapshotId) { const path = exports.getHeapSnapshotTempFilePath(snapshotId); if (!path) { return Promise.resolve(false); } return OS.File.stat(path).then(() => true, () => false); }; /** * Given a heap snapshot's file path, extricate the snapshot id. * * @param {String} path * * @returns String */ exports.getSnapshotIdFromPath = function (path) { return path.slice(OS.Constants.Path.tmpDir.length + 1, path.length - ".fxsnapshot".length); };