--- a/mailnews/Makefile.in
+++ b/mailnews/Makefile.in
@@ -53,20 +53,16 @@ PARALLEL_DIRS += \
extensions\
imap \
import \
local \
mime \
news \
$(NULL)
-ifdef ENABLE_TESTS
-PARALLEL_DIRS += test
-endif
-
ifeq ($(OS_ARCH),WINNT)
ifndef GNU_CC
PARALLEL_DIRS += mapi/mapiDLL mapi/mapihook
endif
endif
ifdef MOZ_STATIC_MAIL_BUILD
DIRS += build
--- a/mailnews/imap/test/unit/test_largeOfflineStore.js
+++ b/mailnews/imap/test/unit/test_largeOfflineStore.js
@@ -4,16 +4,17 @@
* stores, i.e., > 4GB.
*/
var gIMAPDaemon, gServer, gIMAPIncomingServer;
const gIMAPService = Cc["@mozilla.org/messenger/messageservice;1?type=imap"]
.getService(Ci.nsIMsgMessageService);
+load("../../mailnews/resources/mailTestUtils.js");
load("../../mailnews/resources/messageGenerator.js");
var gDownloadedOnce = false;
var gIMAPInbox;
var gOfflineStoreSize;
function run_test()
{
@@ -30,59 +31,39 @@ function run_test()
// pref tuning: one connection only, turn off notifications
let prefBranch = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefBranch);
prefBranch.setBoolPref("mail.biff.play_sound", false);
prefBranch.setBoolPref("mail.biff.show_alert", false);
prefBranch.setBoolPref("mail.biff.show_tray_icon", false);
prefBranch.setBoolPref("mail.biff.animate_dock_icon", false);
+ // Figure out the name of the IMAP inbox
+ let inboxFile = gIMAPIncomingServer.rootMsgFolder.filePath.clone();
+ inboxFile.append("INBOX");
+ if (!inboxFile.exists())
+ inboxFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0644", 8));
+
// On Windows, check whether the drive is NTFS. If it is, mark the file as
// sparse. If it isn't, then bail out now, because in all probability it is
// FAT32, which doesn't support file sizes greater than 4 GB.
- if ("@mozilla.org/windows-registry-key;1" in Cc)
+ if ("@mozilla.org/windows-registry-key;1" in Cc &&
+ get_file_system(inboxFile) != "NTFS")
{
- // Figure out the name of the IMAP inbox
- let file = gIMAPIncomingServer.rootMsgFolder.filePath.clone();
- file.append("INBOX");
- if (!file.exists())
- file.create(Ci.nsIFile.NORMAL_FILE_TYPE, parseInt("0644", 8));
-
- // Now call upon our helper
- let helper = do_get_cwd().clone();
- // '../../mailnews/LargeOfflineStoreHelper.exe'.
- helper = helper.parent.parent;
- helper.normalize();
- helper.append("mailnews");
- helper.append("LargeOfflineStoreHelper.exe");
- if (!helper.exists()) {
- do_throw(helper.leafName + " not found");
- }
-
- let helperProc = Cc["@mozilla.org/process/util;1"]
- .createInstance(Ci.nsIProcess);
- helperProc.init(helper);
- let args = [file.path];
- // XXX This needs to be fixed to use runw once it lands (bug 411511)
- helperProc.run(true, args, args.length);
- let exitValue = helperProc.exitValue;
-
- // 0 is success, 1 is "unable to run," and any other value is failure
- if (exitValue == 1)
- {
- dump("On Windows, this test only works on NTFS volumes.\n");
- endTest();
- return;
- }
-
- if (exitValue != 0)
- {
- do_throw(helper.leafName + " failed with exit value " + exitValue +
- ", see above for details");
- }
+ dump("On Windows, this test only works on NTFS volumes.\n");
+ endTest();
+ return;
+ }
+ let isFileSparse = mark_file_region_sparse(inboxFile, 0, 0x10000000f);
+ if (!isFileSparse && inboxFile.diskSpaceAvailable < 0x200000000)
+ {
+ dump("On systems where files can't be marked sparse, this test needs 8 " +
+ "GB of free disk space.\n");
+ endTest();
+ return;
}
let inbox = gIMAPDaemon.getMailbox("INBOX");
let ioService = Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
// "Master" do_test_pending(), paired with a do_test_finished() at the end of
@@ -104,27 +85,16 @@ function run_test()
dataUri = ioService.newURI("data:text/plain;base64," +
btoa(messages[1].toMessageString()),
null, null);
imapMsg = new imapMessage(dataUri.spec, inbox.uidnext++, []);
inbox.addMessage(imapMsg);
// Get the IMAP inbox...
let rootFolder = gIMAPIncomingServer.rootFolder;
- let freeDiskSpace = rootFolder.filePath.diskSpaceAvailable;
-
- // On Windows, the file is marked as sparse above. Linux file systems
- // generally support sparse files automatically. OS X's HFS+, however, doesn't
- // support sparse files, so check for at least 8 GB of free disk space before
- // consuming 4 GB.
- if ("nsILocalFileMac" in Ci && freeDiskSpace < 0x200000000) {
- dump("On MacOSX, this test needs 8 GB of free disk space.\n");
- endTest();
- return;
- }
gIMAPInbox = rootFolder.getFolderWithFlags(Ci.nsMsgFolderFlags.Inbox);
let outputStream = gIMAPInbox.offlineStoreOutputStream
.QueryInterface(Ci.nsISeekableStream);
// seek to 15 bytes past 4GB.
outputStream.seek(0, 0x10000000f);
outputStream.write("from\r\n", 6);
outputStream.close();
deleted file mode 100644
--- a/mailnews/test/LargeOfflineStoreHelper.cpp
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is mozilla.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Messaging, Inc.
- *
- * Portions created by the Initial Developer are Copyright (C) 2010
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- * Siddharth Agarwal <sid.bugzilla@gmail.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either of the GNU General Public License Version 2 or later (the "GPL"),
- * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-/**
- * A helper to large offline store tests on Windows. This:
- *
- * - Detects whether the volume of the given file (provided using argv[1]) is
- * NTFS. If it isn't, then it returns the error code 1.
- * - If the volume is NTFS, then it proceeds to mark the given file as
- * sparse. It also marks the first 4 GB + 15 bytes of the file as zero.
- */
-
-#include <windows.h>
-#include <stdio.h>
-#include <string.h>
-#include <winioctl.h>
-
-#define SUCCESS (0)
-#define UNABLE_TO_RUN (1)
-#define FAIL (2)
-
-int markFileAsSparse(HANDLE hFile)
-{
- // Mark the file as sparse, and mark the first 4 GB + 15 bytes as a sparse
- // region
- DWORD bytesReturned;
- FILE_SET_SPARSE_BUFFER sparseBuffer = {0};
- sparseBuffer.SetSparse = 1;
- if (!::DeviceIoControl(hFile, FSCTL_SET_SPARSE, &sparseBuffer,
- sizeof(sparseBuffer), NULL, 0, &bytesReturned, NULL))
- {
- fprintf(stderr, "Unable to mark file as sparse, error %d\n",
- ::GetLastError());
- return FAIL;
- }
-
- LARGE_INTEGER zdStart;
- zdStart.QuadPart = 0;
- LARGE_INTEGER zdEnd;
- zdEnd.QuadPart = 0x10000000fLL;
- FILE_ZERO_DATA_INFORMATION zdInfo = {0};
- zdInfo.FileOffset = zdStart;
- zdInfo.BeyondFinalZero = zdEnd;
- if (!::DeviceIoControl(hFile, FSCTL_SET_ZERO_DATA, &zdInfo, sizeof(zdInfo),
- NULL, 0, &bytesReturned, NULL))
- {
- fprintf(stderr, "Unable to mark region as zero, error %d\n",
- ::GetLastError());
- return FAIL;
- }
-
- // Move to past the sparse region and mark it as the end of the file. The
- // above DeviceIoControl call is useless unless followed by this.
- if (!::SetFilePointerEx(hFile, zdEnd, NULL, FILE_BEGIN))
- {
- fprintf(stderr, "Unable to set file pointer to end, error %d\n",
- ::GetLastError());
- return FAIL;
- }
- if (!::SetEndOfFile(hFile))
- {
- fprintf(stderr, "Unable to set end of file, error %d\n", ::GetLastError());
- return FAIL;
- }
-
- return SUCCESS;
-}
-
-int wmain(int argc, wchar_t* argv[])
-{
- if (argc != 2)
- return FAIL;
-
- // The volume path should be at most 1 greater than than the length of the
- // path -- add 1 for a trailing backslash if necessary, and 1 for the
- // terminating null character
- size_t volumePathLength = wcslen(argv[1]) + 2;
- wchar_t* volumePath = new wchar_t[volumePathLength];
- if (!::GetVolumePathNameW(argv[1], volumePath, volumePathLength))
- {
- fprintf(stderr, "Unable to get volume path for %s, error %d\n", argv[1],
- ::GetLastError());
- return FAIL;
- }
-
- wchar_t fsName[MAX_PATH + 1];
- if (!::GetVolumeInformationW(volumePath, NULL, NULL, NULL, NULL,
- NULL, fsName, MAX_PATH + 1))
- {
- fprintf(stderr, "Unable to get volume information for %s, error %d\n",
- argv[1], ::GetLastError());
- return FAIL;
- }
-
- // We're only going to run the test on NTFS
- if (wcscmp(fsName, L"NTFS"))
- return UNABLE_TO_RUN;
-
- HANDLE hFile = ::CreateFileW(argv[1], GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
- FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (hFile == INVALID_HANDLE_VALUE)
- {
- fprintf(stderr, "CreateFile failed for %s, error %d\n", argv[1],
- ::GetLastError());
- return FAIL;
- }
-
- int rv = markFileAsSparse(hFile);
- ::CloseHandle(hFile);
- return rv;
-}
deleted file mode 100644
--- a/mailnews/test/Makefile.in
+++ /dev/null
@@ -1,61 +0,0 @@
-# ***** BEGIN LICENSE BLOCK *****
-# Version: MPL 1.1/GPL 2.0/LGPL 2.1
-#
-# The contents of this file are subject to the Mozilla Public License Version
-# 1.1 (the "License"); you may not use this file except in compliance with
-# the License. You may obtain a copy of the License at
-# http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an "AS IS" basis,
-# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
-# for the specific language governing rights and limitations under the
-# License.
-#
-# The Original Code is mozilla.org code.
-#
-# The Initial Developer of the Original Code is
-# Mozilla Messaging, Inc.
-#
-# Portions created by the Initial Developer are Copyright (C) 2010
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-# Siddharth Agarwal <sid.bugzilla@gmail.com>
-# Serge Gautherie <sgautherie.bz@free.fr>
-#
-# Alternatively, the contents of this file may be used under the terms of
-# either of the GNU General Public License Version 2 or later (the "GPL"),
-# or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
-# in which case the provisions of the GPL or the LGPL are applicable instead
-# of those above. If you wish to allow use of your version of this file only
-# under the terms of either the GPL or the LGPL, and not to allow others to
-# use your version of this file under the terms of the MPL, indicate your
-# decision by deleting the provisions above and replace them with the notice
-# and other provisions required by the GPL or the LGPL. If you do not delete
-# the provisions above, a recipient may use your version of this file under
-# the terms of any one of the MPL, the GPL or the LGPL.
-#
-# ***** END LICENSE BLOCK *****
-
-DEPTH = ../..
-topsrcdir = @top_srcdir@
-srcdir = @srcdir@
-VPATH = @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-ifeq ($(OS_ARCH),WINNT)
-CPPSRCS = \
- LargeOfflineStoreHelper.cpp \
- $(NULL)
-
-SIMPLE_PROGRAMS = $(CPPSRCS:.cpp=$(BIN_SUFFIX))
-endif # ifeq ($(OS_ARCH),WINNT)
-
-include $(topsrcdir)/config/rules.mk
-
-ifeq ($(OS_ARCH),WINNT)
-# need the executable for running the xpcshell unit tests
-libs::
- $(INSTALL) $(SIMPLE_PROGRAMS) $(DEPTH)/mozilla/_tests/xpcshell/mailnews
-endif # ifeq ($(OS_ARCH),WINNT)
--- a/mailnews/test/resources/mailTestUtils.js
+++ b/mailnews/test/resources/mailTestUtils.js
@@ -15,16 +15,17 @@
*
* The Initial Developer of the Original Code is
* Kent James <kent@caspia.com>.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Banner <bugzilla@standard8.plus.com>
+ * Siddharth Agarwal <sid.bugzilla@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
@@ -39,16 +40,18 @@
var gMailTestUtils_js__;
if (!gMailTestUtils_js__) {
gMailTestUtils_js__ = true;
// we would like for everyone to have fixIterator and toXPComArray
Components.utils.import("resource:///modules/iteratorUtils.jsm");
// exposes component loader's btoa impl
Components.utils.import("resource:///modules/IOUtils.js");
+// JS ctypes, needed for a few native functions
+Components.utils.import("resource://gre/modules/ctypes.jsm");
// Local Mail Folders. Requires prior setup of profile directory
var gLocalIncomingServer;
var gLocalInboxFolder;
function loadLocalMailAccount()
{
@@ -168,16 +171,273 @@ function loadFileToString(aFile, aCharse
}
fstream.close();
return data;
}
/**
+ * Return the file system a particular file is on. Currently only supported on
+ * Windows.
+ *
+ * @param aFile The file to get the file system for.
+ */
+function get_file_system(aFile) {
+ if (!("@mozilla.org/windows-registry-key;1" in Cc))
+ throw new Exception("get_file_system is only supported on Windows");
+
+ // Win32 type and other constants.
+ const BOOL = ctypes.int32_t;
+ const MAX_PATH = 260;
+
+ let kernel32 = ctypes.open("kernel32.dll");
+
+ try {
+ // Returns the path of the volume a file is on.
+ let GetVolumePathName = kernel32.declare(
+ "GetVolumePathNameW",
+ ctypes.stdcall_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ ctypes.jschar.ptr, // in: lpszFileName
+ ctypes.jschar.ptr, // out: lpszVolumePathName
+ ctypes.uint32_t // in: cchBufferLength
+ );
+
+ // Returns the last error.
+ let GetLastError = kernel32.declare(
+ "GetLastError",
+ ctypes.stdcall_abi,
+ ctypes.uint32_t // return type: the last error
+ );
+
+ let filePath = aFile.path;
+ // The volume path should be at most 1 greater than than the length of the
+ // path -- add 1 for a trailing backslash if necessary, and 1 for the
+ // terminating null character. Note that the parentheses around the type are
+ // necessary for new to apply correctly.
+ let volumePath = new (ctypes.jschar.array(filePath.length + 2));
+
+ if (!GetVolumePathName(filePath, volumePath, volumePath.length)) {
+ throw new Exception("Unable to get volume path for " + filePath + ", error " +
+ GetLastError());
+ }
+
+ // Returns information about the file system for the given volume path. We just need
+ // the file system name.
+ let GetVolumeInformation = kernel32.declare(
+ "GetVolumeInformationW",
+ ctypes.stdcall_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ ctypes.jschar.ptr, // in, optional: lpRootPathName
+ ctypes.jschar.ptr, // out: lpVolumeNameBuffer
+ ctypes.uint32_t, // in: nVolumeNameSize
+ ctypes.uint32_t.ptr, // out, optional: lpVolumeSerialNumber
+ ctypes.uint32_t.ptr, // out, optional: lpMaximumComponentLength
+ ctypes.uint32_t.ptr, // out, optional: lpFileSystemFlags
+ ctypes.jschar.ptr, // out: lpFileSystemNameBuffer
+ ctypes.uint32_t // in: nFileSystemNameSize
+ );
+
+ // We're only interested in the name of the file system.
+ let fsName = new (ctypes.jschar.array(MAX_PATH + 1));
+
+ if (!GetVolumeInformation(volumePath, null, 0, null, null, null, fsName,
+ fsName.length)) {
+ throw new Exception("Unable to get volume information for " +
+ volumePath.readString() + ", error " + GetLastError());
+ }
+
+ return fsName.readString();
+ }
+ finally {
+ kernel32.close();
+ }
+}
+
+/**
+ * Try marking a region of a file as sparse, so that zeros don't consume
+ * significant amounts of disk space. This is a platform-dependent routine and
+ * is not supported on all platforms. The current status of this function is:
+ * - Windows: Supported, but only on NTFS volumes.
+ * - Mac: Not supported.
+ * - Linux: As long as you seek to a position before writing, happens automatically
+ * on most file systems, so this function is a no-op.
+ *
+ * @param aFile The file to mark as sparse.
+ * @param aRegionStart The start position of the sparse region, in bytes.
+ * @param aRegionBytes The number of bytes to mark as sparse.
+ * @returns Whether the OS and file system supports marking files as sparse. If
+ * this is true, then the file has been marked as sparse. If this is
+ * false, then the underlying system doesn't support marking files as
+ * sparse. If an exception is thrown, then the system does support
+ * marking files as sparse, but an error occured while doing so.
+ *
+ */
+function mark_file_region_sparse(aFile, aRegionStart, aRegionBytes) {
+ if ("@mozilla.org/windows-registry-key;1" in Cc) {
+ // If the file system is not NTFS, sorry, we don't support sparse files.
+ if (get_file_system(aFile) != "NTFS")
+ return false;
+
+ // Win32 type and other constants.
+ const BOOL = ctypes.int32_t;
+ const HANDLE = ctypes.voidptr_t;
+ // A BOOLEAN (= BYTE = unsigned char) is distinct from a BOOL.
+ // http://blogs.msdn.com/b/oldnewthing/archive/2004/12/22/329884.aspx
+ const BOOLEAN = ctypes.unsigned_char;
+ const FILE_SET_SPARSE_BUFFER = new ctypes.StructType(
+ "FILE_SET_SPARSE_BUFFER",
+ [{"SetSparse": BOOLEAN}]
+ );
+ // LARGE_INTEGER is actually a type union. We'll use the int64 representation
+ const LARGE_INTEGER = ctypes.int64_t;
+ const FILE_ZERO_DATA_INFORMATION = new ctypes.StructType(
+ "FILE_ZERO_DATA_INFORMATION",
+ [{"FileOffset": LARGE_INTEGER},
+ {"BeyondFinalZero": LARGE_INTEGER}]
+ );
+
+ const GENERIC_WRITE = 0x40000000;
+ const OPEN_ALWAYS = 4;
+ const FILE_ATTRIBUTE_NORMAL = 0x80;
+ const INVALID_HANDLE_VALUE = new ctypes.Int64(-1);
+ const FSCTL_SET_SPARSE = 0x900c4;
+ const FSCTL_SET_ZERO_DATA = 0x980c8;
+ const FILE_BEGIN = 0;
+
+ let kernel32 = ctypes.open("kernel32.dll");
+
+ try {
+ let CreateFile = kernel32.declare(
+ "CreateFileW",
+ ctypes.stdcall_abi,
+ HANDLE, // return type: handle to the file
+ ctypes.jschar.ptr, // in: lpFileName
+ ctypes.uint32_t, // in: dwDesiredAccess
+ ctypes.uint32_t, // in: dwShareMode
+ ctypes.voidptr_t, // in, optional: lpSecurityAttributes (note that
+ // we're cheating here by not declaring a
+ // SECURITY_ATTRIBUTES structure -- that's because
+ // we're going to pass in null anyway)
+ ctypes.uint32_t, // in: dwCreationDisposition
+ ctypes.uint32_t, // in: dwFlagsAndAttributes
+ HANDLE // in, optional: hTemplateFile
+ );
+
+ // Returns the last error.
+ let GetLastError = kernel32.declare(
+ "GetLastError",
+ ctypes.stdcall_abi,
+ ctypes.uint32_t // return type: the last error
+ );
+
+ let filePath = aFile.path;
+ let hFile = CreateFile(filePath, GENERIC_WRITE, 0, null, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, null);
+ let hFileInt = ctypes.cast(hFile, ctypes.intptr_t);
+ if (ctypes.Int64.compare(hFileInt.value, INVALID_HANDLE_VALUE) == 0) {
+ throw new Exception("CreateFile failed for " + filePath + ", error " +
+ GetLastError());
+ }
+
+ try {
+ let DeviceIoControl = kernel32.declare(
+ "DeviceIoControl",
+ ctypes.stdcall_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ HANDLE, // in: hDevice
+ ctypes.uint32_t, // in: dwIoControlCode
+ ctypes.voidptr_t, // in, optional: lpInBuffer
+ ctypes.uint32_t, // in: nInBufferSize
+ ctypes.voidptr_t, // out, optional: lpOutBuffer
+ ctypes.uint32_t, // in: nOutBufferSize
+ ctypes.uint32_t.ptr, // out, optional: lpBytesReturned
+ ctypes.voidptr_t // inout, optional: lpOverlapped (again, we're
+ // cheating here by not having this as an
+ // OVERLAPPED structure
+ );
+ // bytesReturned needs to be passed in, even though it's meaningless
+ let bytesReturned = new ctypes.uint32_t();
+ let sparseBuffer = new FILE_SET_SPARSE_BUFFER();
+ sparseBuffer.SetSparse = 1;
+
+ // Mark the file as sparse
+ if (!DeviceIoControl(hFile, FSCTL_SET_SPARSE, sparseBuffer.address(),
+ FILE_SET_SPARSE_BUFFER.size, null, 0,
+ bytesReturned.address(), null)) {
+ throw new Exception("Unable to mark file as sparse, error " +
+ GetLastError());
+ }
+
+ let zdInfo = new FILE_ZERO_DATA_INFORMATION();
+ zdInfo.FileOffset = aRegionStart;
+ let regionEnd = aRegionStart + aRegionBytes;
+ zdInfo.BeyondFinalZero = regionEnd;
+ // Mark the region as a sparse region
+ if (!DeviceIoControl(hFile, FSCTL_SET_ZERO_DATA, zdInfo.address(),
+ FILE_ZERO_DATA_INFORMATION.size, null, 0,
+ bytesReturned.address(), null)) {
+ throw new Exception("Unable to mark region as zero, error " +
+ GetLastError());
+ }
+
+ // Move to past the sparse region and mark it as the end of the file. The
+ // above DeviceIoControl call is useless unless followed by this.
+ let SetFilePointerEx = kernel32.declare(
+ "SetFilePointerEx",
+ ctypes.stdcall_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ HANDLE, // in: hFile
+ LARGE_INTEGER, // in: liDistanceToMove
+ LARGE_INTEGER.ptr, // out, optional: lpNewFilePointer
+ ctypes.uint32_t // in: dwMoveMethod
+ );
+ if (!SetFilePointerEx(hFile, regionEnd, null, FILE_BEGIN)) {
+ throw new Exception("Unable to set file pointer to end, error " +
+ GetLastError());
+ }
+
+ let SetEndOfFile = kernel32.declare(
+ "SetEndOfFile",
+ ctypes.stdcall_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ HANDLE // in: hFile
+ );
+ if (!SetEndOfFile(hFile))
+ throw new Exception("Unable to set end of file, error " + GetLastError());
+
+ return true;
+ }
+ finally {
+ let CloseHandle = kernel32.declare(
+ "CloseHandle",
+ ctypes.stdcall_abi,
+ BOOL, // return type: 1 indicates success, 0 failure
+ HANDLE // in: hObject
+ );
+ CloseHandle(hFile);
+ }
+ }
+ finally {
+ kernel32.close();
+ }
+ }
+ else if ("nsILocalFileMac" in Ci) {
+ // Macs don't support marking files as sparse.
+ return false;
+ }
+ else {
+ // Assuming Unix here. Unix file systems generally automatically sparsify
+ // files.
+ return true;
+ }
+}
+
+/**
* A variant of do_timeout that accepts an actual function instead of
* requiring you to pass a string to evaluate. If the function throws an
* exception when invoked, we will use do_throw to ensure that the test fails.
*
* @param aDelayInMS The number of milliseconds to wait before firing the timer.
* @param aFunc The function to invoke when the timer fires.
* @param aFuncThis Optional 'this' pointer to use.
* @param aFuncArgs Optional list of arguments to pass to the function.