1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/osfile/modules/osfile_unix_allthreads.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,365 @@ 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 Unix 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 libc; 1.15 + * - define OS.Unix.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, "Unix", "allthreads"); 1.42 +let Const = SharedAll.Constants.libc; 1.43 + 1.44 +// Open libc 1.45 +let libc = new SharedAll.Library("libc", 1.46 + "libc.so", "libSystem.B.dylib", "a.out"); 1.47 +exports.libc = libc; 1.48 + 1.49 +// Define declareFFI 1.50 +let declareFFI = SharedAll.declareFFI.bind(null, libc); 1.51 +exports.declareFFI = declareFFI; 1.52 + 1.53 +// Define lazy binding 1.54 +let LazyBindings = {}; 1.55 +libc.declareLazy(LazyBindings, "strerror", 1.56 + "strerror", ctypes.default_abi, 1.57 + /*return*/ ctypes.char.ptr, 1.58 + /*errnum*/ ctypes.int); 1.59 + 1.60 +/** 1.61 + * A File-related error. 1.62 + * 1.63 + * To obtain a human-readable error message, use method |toString|. 1.64 + * To determine the cause of the error, use the various |becauseX| 1.65 + * getters. To determine the operation that failed, use field 1.66 + * |operation|. 1.67 + * 1.68 + * Additionally, this implementation offers a field 1.69 + * |unixErrno|, which holds the OS-specific error 1.70 + * constant. If you need this level of detail, you may match the value 1.71 + * of this field against the error constants of |OS.Constants.libc|. 1.72 + * 1.73 + * @param {string=} operation The operation that failed. If unspecified, 1.74 + * the name of the calling function is taken to be the operation that 1.75 + * failed. 1.76 + * @param {number=} lastError The OS-specific constant detailing the 1.77 + * reason of the error. If unspecified, this is fetched from the system 1.78 + * status. 1.79 + * @param {string=} path The file path that manipulated. If unspecified, 1.80 + * assign the empty string. 1.81 + * 1.82 + * @constructor 1.83 + * @extends {OS.Shared.Error} 1.84 + */ 1.85 +let OSError = function OSError(operation = "unknown operation", 1.86 + errno = ctypes.errno, path = "") { 1.87 + operation = operation; 1.88 + SharedAll.OSError.call(this, operation, path); 1.89 + this.unixErrno = errno; 1.90 +}; 1.91 +OSError.prototype = Object.create(SharedAll.OSError.prototype); 1.92 +OSError.prototype.toString = function toString() { 1.93 + return "Unix error " + this.unixErrno + 1.94 + " during operation " + this.operation + 1.95 + (this.path? " on file " + this.path : "") + 1.96 + " (" + LazyBindings.strerror(this.unixErrno).readString() + ")"; 1.97 +}; 1.98 + 1.99 +/** 1.100 + * |true| if the error was raised because a file or directory 1.101 + * already exists, |false| otherwise. 1.102 + */ 1.103 +Object.defineProperty(OSError.prototype, "becauseExists", { 1.104 + get: function becauseExists() { 1.105 + return this.unixErrno == Const.EEXIST; 1.106 + } 1.107 +}); 1.108 +/** 1.109 + * |true| if the error was raised because a file or directory 1.110 + * does not exist, |false| otherwise. 1.111 + */ 1.112 +Object.defineProperty(OSError.prototype, "becauseNoSuchFile", { 1.113 + get: function becauseNoSuchFile() { 1.114 + return this.unixErrno == Const.ENOENT; 1.115 + } 1.116 +}); 1.117 + 1.118 +/** 1.119 + * |true| if the error was raised because a directory is not empty 1.120 + * does not exist, |false| otherwise. 1.121 + */ 1.122 + Object.defineProperty(OSError.prototype, "becauseNotEmpty", { 1.123 + get: function becauseNotEmpty() { 1.124 + return this.unixErrno == Const.ENOTEMPTY; 1.125 + } 1.126 + }); 1.127 +/** 1.128 + * |true| if the error was raised because a file or directory 1.129 + * is closed, |false| otherwise. 1.130 + */ 1.131 +Object.defineProperty(OSError.prototype, "becauseClosed", { 1.132 + get: function becauseClosed() { 1.133 + return this.unixErrno == Const.EBADF; 1.134 + } 1.135 +}); 1.136 +/** 1.137 + * |true| if the error was raised because permission is denied to 1.138 + * access a file or directory, |false| otherwise. 1.139 + */ 1.140 +Object.defineProperty(OSError.prototype, "becauseAccessDenied", { 1.141 + get: function becauseAccessDenied() { 1.142 + return this.unixErrno == Const.EACCES; 1.143 + } 1.144 +}); 1.145 +/** 1.146 + * |true| if the error was raised because some invalid argument was passed, 1.147 + * |false| otherwise. 1.148 + */ 1.149 +Object.defineProperty(OSError.prototype, "becauseInvalidArgument", { 1.150 + get: function becauseInvalidArgument() { 1.151 + return this.unixErrno == Const.EINVAL; 1.152 + } 1.153 +}); 1.154 + 1.155 +/** 1.156 + * Serialize an instance of OSError to something that can be 1.157 + * transmitted across threads (not necessarily a string). 1.158 + */ 1.159 +OSError.toMsg = function toMsg(error) { 1.160 + return { 1.161 + operation: error.operation, 1.162 + unixErrno: error.unixErrno, 1.163 + path: error.path 1.164 + }; 1.165 +}; 1.166 + 1.167 +/** 1.168 + * Deserialize a message back to an instance of OSError 1.169 + */ 1.170 +OSError.fromMsg = function fromMsg(msg) { 1.171 + return new OSError(msg.operation, msg.unixErrno, msg.path); 1.172 +}; 1.173 +exports.Error = OSError; 1.174 + 1.175 +/** 1.176 + * Code shared by implementations of File.Info on Unix 1.177 + * 1.178 + * @constructor 1.179 +*/ 1.180 +let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, lastAccessDate, 1.181 + lastModificationDate, unixLastStatusChangeDate, 1.182 + unixOwner, unixGroup, unixMode) { 1.183 + this._path = path; 1.184 + this._isDir = isDir; 1.185 + this._isSymlLink = isSymLink; 1.186 + this._size = size; 1.187 + this._lastAccessDate = lastAccessDate; 1.188 + this._lastModificationDate = lastModificationDate; 1.189 + this._unixLastStatusChangeDate = unixLastStatusChangeDate; 1.190 + this._unixOwner = unixOwner; 1.191 + this._unixGroup = unixGroup; 1.192 + this._unixMode = unixMode; 1.193 +}; 1.194 + 1.195 +AbstractInfo.prototype = { 1.196 + /** 1.197 + * The path of the file, used for error-reporting. 1.198 + * 1.199 + * @type {string} 1.200 + */ 1.201 + get path() { 1.202 + return this._path; 1.203 + }, 1.204 + /** 1.205 + * |true| if this file is a directory, |false| otherwise 1.206 + */ 1.207 + get isDir() { 1.208 + return this._isDir; 1.209 + }, 1.210 + /** 1.211 + * |true| if this file is a symbolink link, |false| otherwise 1.212 + */ 1.213 + get isSymLink() { 1.214 + return this._isSymlLink; 1.215 + }, 1.216 + /** 1.217 + * The size of the file, in bytes. 1.218 + * 1.219 + * Note that the result may be |NaN| if the size of the file cannot be 1.220 + * represented in JavaScript. 1.221 + * 1.222 + * @type {number} 1.223 + */ 1.224 + get size() { 1.225 + return this._size; 1.226 + }, 1.227 + /** 1.228 + * The date of last access to this file. 1.229 + * 1.230 + * Note that the definition of last access may depend on the 1.231 + * underlying operating system and file system. 1.232 + * 1.233 + * @type {Date} 1.234 + */ 1.235 + get lastAccessDate() { 1.236 + return this._lastAccessDate; 1.237 + }, 1.238 + /** 1.239 + * Return the date of last modification of this file. 1.240 + */ 1.241 + get lastModificationDate() { 1.242 + return this._lastModificationDate; 1.243 + }, 1.244 + /** 1.245 + * Return the date at which the status of this file was last modified 1.246 + * (this is the date of the latest write/renaming/mode change/... 1.247 + * of the file) 1.248 + */ 1.249 + get unixLastStatusChangeDate() { 1.250 + return this._unixLastStatusChangeDate; 1.251 + }, 1.252 + /* 1.253 + * Return the Unix owner of this file 1.254 + */ 1.255 + get unixOwner() { 1.256 + return this._unixOwner; 1.257 + }, 1.258 + /* 1.259 + * Return the Unix group of this file 1.260 + */ 1.261 + get unixGroup() { 1.262 + return this._unixGroup; 1.263 + }, 1.264 + /* 1.265 + * Return the Unix group of this file 1.266 + */ 1.267 + get unixMode() { 1.268 + return this._unixMode; 1.269 + } 1.270 +}; 1.271 +exports.AbstractInfo = AbstractInfo; 1.272 + 1.273 +/** 1.274 + * Code shared by implementations of File.DirectoryIterator.Entry on Unix 1.275 + * 1.276 + * @constructor 1.277 +*/ 1.278 +let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) { 1.279 + this._isDir = isDir; 1.280 + this._isSymlLink = isSymLink; 1.281 + this._name = name; 1.282 + this._path = path; 1.283 +}; 1.284 + 1.285 +AbstractEntry.prototype = { 1.286 + /** 1.287 + * |true| if the entry is a directory, |false| otherwise 1.288 + */ 1.289 + get isDir() { 1.290 + return this._isDir; 1.291 + }, 1.292 + /** 1.293 + * |true| if the entry is a directory, |false| otherwise 1.294 + */ 1.295 + get isSymLink() { 1.296 + return this._isSymlLink; 1.297 + }, 1.298 + /** 1.299 + * The name of the entry 1.300 + * @type {string} 1.301 + */ 1.302 + get name() { 1.303 + return this._name; 1.304 + }, 1.305 + /** 1.306 + * The full path to the entry 1.307 + */ 1.308 + get path() { 1.309 + return this._path; 1.310 + } 1.311 +}; 1.312 +exports.AbstractEntry = AbstractEntry; 1.313 + 1.314 +// Special constants that need to be defined on all platforms 1.315 + 1.316 +exports.POS_START = Const.SEEK_SET; 1.317 +exports.POS_CURRENT = Const.SEEK_CUR; 1.318 +exports.POS_END = Const.SEEK_END; 1.319 + 1.320 +// Special types that need to be defined for communication 1.321 +// between threads 1.322 +let Type = Object.create(SharedAll.Type); 1.323 +exports.Type = Type; 1.324 + 1.325 +/** 1.326 + * Native paths 1.327 + * 1.328 + * Under Unix, expressed as C strings 1.329 + */ 1.330 +Type.path = Type.cstring.withName("[in] path"); 1.331 +Type.out_path = Type.out_cstring.withName("[out] path"); 1.332 + 1.333 +// Special constructors that need to be defined on all threads 1.334 +OSError.closed = function closed(operation, path) { 1.335 + return new OSError(operation, Const.EBADF, path); 1.336 +}; 1.337 + 1.338 +OSError.exists = function exists(operation, path) { 1.339 + return new OSError(operation, Const.EEXIST, path); 1.340 +}; 1.341 + 1.342 +OSError.noSuchFile = function noSuchFile(operation, path) { 1.343 + return new OSError(operation, Const.ENOENT, path); 1.344 +}; 1.345 + 1.346 +OSError.invalidArgument = function invalidArgument(operation) { 1.347 + return new OSError(operation, Const.EINVAL); 1.348 +}; 1.349 + 1.350 +let EXPORTED_SYMBOLS = [ 1.351 + "declareFFI", 1.352 + "libc", 1.353 + "Error", 1.354 + "AbstractInfo", 1.355 + "AbstractEntry", 1.356 + "Type", 1.357 + "POS_START", 1.358 + "POS_CURRENT", 1.359 + "POS_END" 1.360 +]; 1.361 + 1.362 +//////////// Boilerplate 1.363 +if (typeof Components != "undefined") { 1.364 + this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS; 1.365 + for (let symbol of EXPORTED_SYMBOLS) { 1.366 + this[symbol] = exports[symbol]; 1.367 + } 1.368 +}