1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/osfile/modules/osfile_win_allthreads.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,403 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/** 1.9 + * This module defines the thread-agnostic components of the Win version 1.10 + * of OS.File. It depends on the thread-agnostic cross-platform components 1.11 + * of OS.File. 1.12 + * 1.13 + * It serves the following purposes: 1.14 + * - open kernel32; 1.15 + * - define OS.Shared.Win.Error; 1.16 + * - define a few constants and types that need to be defined on all platforms. 1.17 + * 1.18 + * This module can be: 1.19 + * - opened from the main thread as a jsm module; 1.20 + * - opened from a chrome worker through require(). 1.21 + */ 1.22 + 1.23 +"use strict"; 1.24 + 1.25 +let SharedAll; 1.26 +if (typeof Components != "undefined") { 1.27 + let Cu = Components.utils; 1.28 + // Module is opened as a jsm module 1.29 + Cu.import("resource://gre/modules/ctypes.jsm", this); 1.30 + 1.31 + SharedAll = {}; 1.32 + Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll); 1.33 + this.exports = {}; 1.34 +} else if (typeof "module" != "undefined" && typeof "require" != "undefined") { 1.35 + // Module is loaded with require() 1.36 + SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm"); 1.37 +} else { 1.38 + throw new Error("Please open this module with Component.utils.import or with require()"); 1.39 +} 1.40 + 1.41 +let LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads"); 1.42 +let Const = SharedAll.Constants.Win; 1.43 + 1.44 +// Open libc 1.45 +let libc = new SharedAll.Library("libc", "kernel32.dll"); 1.46 +exports.libc = libc; 1.47 + 1.48 +// Define declareFFI 1.49 +let declareFFI = SharedAll.declareFFI.bind(null, libc); 1.50 +exports.declareFFI = declareFFI; 1.51 + 1.52 +let Scope = {}; 1.53 + 1.54 +// Define Error 1.55 +libc.declareLazy(Scope, "FormatMessage", 1.56 + "FormatMessageW", ctypes.winapi_abi, 1.57 + /*return*/ ctypes.uint32_t, 1.58 + /*flags*/ ctypes.uint32_t, 1.59 + /*source*/ ctypes.voidptr_t, 1.60 + /*msgid*/ ctypes.uint32_t, 1.61 + /*langid*/ ctypes.uint32_t, 1.62 + /*buf*/ ctypes.jschar.ptr, 1.63 + /*size*/ ctypes.uint32_t, 1.64 + /*Arguments*/ctypes.voidptr_t); 1.65 + 1.66 +/** 1.67 + * A File-related error. 1.68 + * 1.69 + * To obtain a human-readable error message, use method |toString|. 1.70 + * To determine the cause of the error, use the various |becauseX| 1.71 + * getters. To determine the operation that failed, use field 1.72 + * |operation|. 1.73 + * 1.74 + * Additionally, this implementation offers a field 1.75 + * |winLastError|, which holds the OS-specific error 1.76 + * constant. If you need this level of detail, you may match the value 1.77 + * of this field against the error constants of |OS.Constants.Win|. 1.78 + * 1.79 + * @param {string=} operation The operation that failed. If unspecified, 1.80 + * the name of the calling function is taken to be the operation that 1.81 + * failed. 1.82 + * @param {number=} lastError The OS-specific constant detailing the 1.83 + * reason of the error. If unspecified, this is fetched from the system 1.84 + * status. 1.85 + * @param {string=} path The file path that manipulated. If unspecified, 1.86 + * assign the empty string. 1.87 + * 1.88 + * @constructor 1.89 + * @extends {OS.Shared.Error} 1.90 + */ 1.91 +let OSError = function OSError(operation = "unknown operation", 1.92 + lastError = ctypes.winLastError, path = "") { 1.93 + operation = operation; 1.94 + SharedAll.OSError.call(this, operation, path); 1.95 + this.winLastError = lastError; 1.96 +}; 1.97 +OSError.prototype = Object.create(SharedAll.OSError.prototype); 1.98 +OSError.prototype.toString = function toString() { 1.99 + let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))(); 1.100 + let result = Scope.FormatMessage( 1.101 + Const.FORMAT_MESSAGE_FROM_SYSTEM | 1.102 + Const.FORMAT_MESSAGE_IGNORE_INSERTS, 1.103 + null, 1.104 + /* The error number */ this.winLastError, 1.105 + /* Default language */ 0, 1.106 + /* Output buffer*/ buf, 1.107 + /* Minimum size of buffer */ 1024, 1.108 + /* Format args*/ null 1.109 + ); 1.110 + if (!result) { 1.111 + buf = "additional error " + 1.112 + ctypes.winLastError + 1.113 + " while fetching system error message"; 1.114 + } 1.115 + return "Win error " + this.winLastError + " during operation " 1.116 + + this.operation + (this.path? " on file " + this.path : "") + 1.117 + " (" + buf.readString() + ")"; 1.118 +}; 1.119 + 1.120 +/** 1.121 + * |true| if the error was raised because a file or directory 1.122 + * already exists, |false| otherwise. 1.123 + */ 1.124 +Object.defineProperty(OSError.prototype, "becauseExists", { 1.125 + get: function becauseExists() { 1.126 + return this.winLastError == Const.ERROR_FILE_EXISTS || 1.127 + this.winLastError == Const.ERROR_ALREADY_EXISTS; 1.128 + } 1.129 +}); 1.130 +/** 1.131 + * |true| if the error was raised because a file or directory 1.132 + * does not exist, |false| otherwise. 1.133 + */ 1.134 +Object.defineProperty(OSError.prototype, "becauseNoSuchFile", { 1.135 + get: function becauseNoSuchFile() { 1.136 + return this.winLastError == Const.ERROR_FILE_NOT_FOUND || 1.137 + this.winLastError == Const.ERROR_PATH_NOT_FOUND; 1.138 + } 1.139 +}); 1.140 +/** 1.141 + * |true| if the error was raised because a directory is not empty 1.142 + * does not exist, |false| otherwise. 1.143 + */ 1.144 +Object.defineProperty(OSError.prototype, "becauseNotEmpty", { 1.145 + get: function becauseNotEmpty() { 1.146 + return this.winLastError == Const.ERROR_DIR_NOT_EMPTY; 1.147 + } 1.148 +}); 1.149 +/** 1.150 + * |true| if the error was raised because a file or directory 1.151 + * is closed, |false| otherwise. 1.152 + */ 1.153 +Object.defineProperty(OSError.prototype, "becauseClosed", { 1.154 + get: function becauseClosed() { 1.155 + return this.winLastError == Const.ERROR_INVALID_HANDLE; 1.156 + } 1.157 +}); 1.158 +/** 1.159 + * |true| if the error was raised because permission is denied to 1.160 + * access a file or directory, |false| otherwise. 1.161 + */ 1.162 +Object.defineProperty(OSError.prototype, "becauseAccessDenied", { 1.163 + get: function becauseAccessDenied() { 1.164 + return this.winLastError == Const.ERROR_ACCESS_DENIED; 1.165 + } 1.166 +}); 1.167 +/** 1.168 + * |true| if the error was raised because some invalid argument was passed, 1.169 + * |false| otherwise. 1.170 + */ 1.171 +Object.defineProperty(OSError.prototype, "becauseInvalidArgument", { 1.172 + get: function becauseInvalidArgument() { 1.173 + return this.winLastError == Const.ERROR_NOT_SUPPORTED || 1.174 + this.winLastError == Const.ERROR_BAD_ARGUMENTS; 1.175 + } 1.176 +}); 1.177 + 1.178 +/** 1.179 + * Serialize an instance of OSError to something that can be 1.180 + * transmitted across threads (not necessarily a string). 1.181 + */ 1.182 +OSError.toMsg = function toMsg(error) { 1.183 + return { 1.184 + operation: error.operation, 1.185 + winLastError: error.winLastError, 1.186 + path: error.path 1.187 + }; 1.188 +}; 1.189 + 1.190 +/** 1.191 + * Deserialize a message back to an instance of OSError 1.192 + */ 1.193 +OSError.fromMsg = function fromMsg(msg) { 1.194 + return new OSError(msg.operation, msg.winLastError, msg.path); 1.195 +}; 1.196 +exports.Error = OSError; 1.197 + 1.198 +/** 1.199 + * Code shared by implementation of File.Info on Windows 1.200 + * 1.201 + * @constructor 1.202 + */ 1.203 +let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, 1.204 + winBirthDate, 1.205 + lastAccessDate, lastWriteDate) { 1.206 + this._path = path; 1.207 + this._isDir = isDir; 1.208 + this._isSymLink = isSymLink; 1.209 + this._size = size; 1.210 + this._winBirthDate = winBirthDate; 1.211 + this._lastAccessDate = lastAccessDate; 1.212 + this._lastModificationDate = lastWriteDate; 1.213 +}; 1.214 + 1.215 +AbstractInfo.prototype = { 1.216 + /** 1.217 + * The path of the file, used for error-reporting. 1.218 + * 1.219 + * @type {string} 1.220 + */ 1.221 + get path() { 1.222 + return this._path; 1.223 + }, 1.224 + /** 1.225 + * |true| if this file is a directory, |false| otherwise 1.226 + */ 1.227 + get isDir() { 1.228 + return this._isDir; 1.229 + }, 1.230 + /** 1.231 + * |true| if this file is a symbolic link, |false| otherwise 1.232 + */ 1.233 + get isSymLink() { 1.234 + return this._isSymLink; 1.235 + }, 1.236 + /** 1.237 + * The size of the file, in bytes. 1.238 + * 1.239 + * Note that the result may be |NaN| if the size of the file cannot be 1.240 + * represented in JavaScript. 1.241 + * 1.242 + * @type {number} 1.243 + */ 1.244 + get size() { 1.245 + return this._size; 1.246 + }, 1.247 + // Deprecated 1.248 + get creationDate() { 1.249 + return this._winBirthDate; 1.250 + }, 1.251 + /** 1.252 + * The date of creation of this file. 1.253 + * 1.254 + * @type {Date} 1.255 + */ 1.256 + get winBirthDate() { 1.257 + return this._winBirthDate; 1.258 + }, 1.259 + /** 1.260 + * The date of last access to this file. 1.261 + * 1.262 + * Note that the definition of last access may depend on the underlying 1.263 + * operating system and file system. 1.264 + * 1.265 + * @type {Date} 1.266 + */ 1.267 + get lastAccessDate() { 1.268 + return this._lastAccessDate; 1.269 + }, 1.270 + /** 1.271 + * The date of last modification of this file. 1.272 + * 1.273 + * Note that the definition of last access may depend on the underlying 1.274 + * operating system and file system. 1.275 + * 1.276 + * @type {Date} 1.277 + */ 1.278 + get lastModificationDate() { 1.279 + return this._lastModificationDate; 1.280 + } 1.281 +}; 1.282 +exports.AbstractInfo = AbstractInfo; 1.283 + 1.284 +/** 1.285 + * Code shared by implementation of File.DirectoryIterator.Entry on Windows 1.286 + * 1.287 + * @constructor 1.288 + */ 1.289 +let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, 1.290 + winCreationDate, winLastWriteDate, 1.291 + winLastAccessDate, path) { 1.292 + this._isDir = isDir; 1.293 + this._isSymLink = isSymLink; 1.294 + this._name = name; 1.295 + this._winCreationDate = winCreationDate; 1.296 + this._winLastWriteDate = winLastWriteDate; 1.297 + this._winLastAccessDate = winLastAccessDate; 1.298 + this._path = path; 1.299 +}; 1.300 + 1.301 +AbstractEntry.prototype = { 1.302 + /** 1.303 + * |true| if the entry is a directory, |false| otherwise 1.304 + */ 1.305 + get isDir() { 1.306 + return this._isDir; 1.307 + }, 1.308 + /** 1.309 + * |true| if the entry is a symbolic link, |false| otherwise 1.310 + */ 1.311 + get isSymLink() { 1.312 + return this._isSymLink; 1.313 + }, 1.314 + /** 1.315 + * The name of the entry. 1.316 + * @type {string} 1.317 + */ 1.318 + get name() { 1.319 + return this._name; 1.320 + }, 1.321 + /** 1.322 + * The creation time of this file. 1.323 + * @type {Date} 1.324 + */ 1.325 + get winCreationDate() { 1.326 + return this._winCreationDate; 1.327 + }, 1.328 + /** 1.329 + * The last modification time of this file. 1.330 + * @type {Date} 1.331 + */ 1.332 + get winLastWriteDate() { 1.333 + return this._winLastWriteDate; 1.334 + }, 1.335 + /** 1.336 + * The last access time of this file. 1.337 + * @type {Date} 1.338 + */ 1.339 + get winLastAccessDate() { 1.340 + return this._winLastAccessDate; 1.341 + }, 1.342 + /** 1.343 + * The full path of the entry 1.344 + * @type {string} 1.345 + */ 1.346 + get path() { 1.347 + return this._path; 1.348 + } 1.349 +}; 1.350 +exports.AbstractEntry = AbstractEntry; 1.351 + 1.352 +// Special constants that need to be defined on all platforms 1.353 + 1.354 +exports.POS_START = Const.FILE_BEGIN; 1.355 +exports.POS_CURRENT = Const.FILE_CURRENT; 1.356 +exports.POS_END = Const.FILE_END; 1.357 + 1.358 +// Special types that need to be defined for communication 1.359 +// between threads 1.360 +let Type = Object.create(SharedAll.Type); 1.361 +exports.Type = Type; 1.362 + 1.363 +/** 1.364 + * Native paths 1.365 + * 1.366 + * Under Windows, expressed as wide strings 1.367 + */ 1.368 +Type.path = Type.wstring.withName("[in] path"); 1.369 +Type.out_path = Type.out_wstring.withName("[out] path"); 1.370 + 1.371 +// Special constructors that need to be defined on all threads 1.372 +OSError.closed = function closed(operation, path) { 1.373 + return new OSError(operation, Const.ERROR_INVALID_HANDLE, path); 1.374 +}; 1.375 + 1.376 +OSError.exists = function exists(operation, path) { 1.377 + return new OSError(operation, Const.ERROR_FILE_EXISTS, path); 1.378 +}; 1.379 + 1.380 +OSError.noSuchFile = function noSuchFile(operation, path) { 1.381 + return new OSError(operation, Const.ERROR_FILE_NOT_FOUND, path); 1.382 +}; 1.383 + 1.384 +OSError.invalidArgument = function invalidArgument(operation) { 1.385 + return new OSError(operation, Const.ERROR_NOT_SUPPORTED); 1.386 +}; 1.387 + 1.388 +let EXPORTED_SYMBOLS = [ 1.389 + "declareFFI", 1.390 + "libc", 1.391 + "Error", 1.392 + "AbstractInfo", 1.393 + "AbstractEntry", 1.394 + "Type", 1.395 + "POS_START", 1.396 + "POS_CURRENT", 1.397 + "POS_END" 1.398 +]; 1.399 + 1.400 +//////////// Boilerplate 1.401 +if (typeof Components != "undefined") { 1.402 + this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS; 1.403 + for (let symbol of EXPORTED_SYMBOLS) { 1.404 + this[symbol] = exports[symbol]; 1.405 + } 1.406 +}