Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | if (this.Components) { |
michael@0 | 2 | throw new Error("This worker can only be loaded from a worker thread"); |
michael@0 | 3 | } |
michael@0 | 4 | |
michael@0 | 5 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 6 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 7 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 8 | |
michael@0 | 9 | |
michael@0 | 10 | // Worker thread for osfile asynchronous front-end |
michael@0 | 11 | |
michael@0 | 12 | // Exception names to be posted from the worker thread to main thread |
michael@0 | 13 | const EXCEPTION_NAMES = { |
michael@0 | 14 | EvalError: "EvalError", |
michael@0 | 15 | InternalError: "InternalError", |
michael@0 | 16 | RangeError: "RangeError", |
michael@0 | 17 | ReferenceError: "ReferenceError", |
michael@0 | 18 | SyntaxError: "SyntaxError", |
michael@0 | 19 | TypeError: "TypeError", |
michael@0 | 20 | URIError: "URIError" |
michael@0 | 21 | }; |
michael@0 | 22 | |
michael@0 | 23 | (function(exports) { |
michael@0 | 24 | "use strict"; |
michael@0 | 25 | |
michael@0 | 26 | // Timestamps, for use in Telemetry. |
michael@0 | 27 | // The object is set to |null| once it has been sent |
michael@0 | 28 | // to the main thread. |
michael@0 | 29 | let timeStamps = { |
michael@0 | 30 | entered: Date.now(), |
michael@0 | 31 | loaded: null |
michael@0 | 32 | }; |
michael@0 | 33 | |
michael@0 | 34 | importScripts("resource://gre/modules/osfile.jsm"); |
michael@0 | 35 | |
michael@0 | 36 | let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm"); |
michael@0 | 37 | let LOG = SharedAll.LOG.bind(SharedAll, "Agent"); |
michael@0 | 38 | |
michael@0 | 39 | // Post a message to the parent, decorate it with statistics if |
michael@0 | 40 | // necessary. Use this instead of self.postMessage. |
michael@0 | 41 | function post(message, ...transfers) { |
michael@0 | 42 | if (timeStamps) { |
michael@0 | 43 | message.timeStamps = timeStamps; |
michael@0 | 44 | timeStamps = null; |
michael@0 | 45 | } |
michael@0 | 46 | self.postMessage(message, ...transfers); |
michael@0 | 47 | } |
michael@0 | 48 | |
michael@0 | 49 | /** |
michael@0 | 50 | * Communications with the controller. |
michael@0 | 51 | * |
michael@0 | 52 | * Accepts messages: |
michael@0 | 53 | * {fun:function_name, args:array_of_arguments_or_null, id:id} |
michael@0 | 54 | * |
michael@0 | 55 | * Sends messages: |
michael@0 | 56 | * {ok: result, id:id} / {fail: serialized_form_of_OS.File.Error, id:id} |
michael@0 | 57 | */ |
michael@0 | 58 | self.onmessage = function onmessage(msg) { |
michael@0 | 59 | let data = msg.data; |
michael@0 | 60 | LOG("Received message", data); |
michael@0 | 61 | let id = data.id; |
michael@0 | 62 | |
michael@0 | 63 | let start; |
michael@0 | 64 | let options; |
michael@0 | 65 | if (data.args) { |
michael@0 | 66 | options = data.args[data.args.length - 1]; |
michael@0 | 67 | } |
michael@0 | 68 | // If |outExecutionDuration| option was supplied, start measuring the |
michael@0 | 69 | // duration of the operation. |
michael@0 | 70 | if (options && typeof options === "object" && "outExecutionDuration" in options) { |
michael@0 | 71 | start = Date.now(); |
michael@0 | 72 | } |
michael@0 | 73 | |
michael@0 | 74 | let result; |
michael@0 | 75 | let exn; |
michael@0 | 76 | let durationMs; |
michael@0 | 77 | try { |
michael@0 | 78 | let method = data.fun; |
michael@0 | 79 | LOG("Calling method", method); |
michael@0 | 80 | result = Agent[method].apply(Agent, data.args); |
michael@0 | 81 | LOG("Method", method, "succeeded"); |
michael@0 | 82 | } catch (ex) { |
michael@0 | 83 | exn = ex; |
michael@0 | 84 | LOG("Error while calling agent method", exn, exn.moduleStack || exn.stack || ""); |
michael@0 | 85 | } |
michael@0 | 86 | |
michael@0 | 87 | if (start) { |
michael@0 | 88 | // Record duration |
michael@0 | 89 | durationMs = Date.now() - start; |
michael@0 | 90 | LOG("Method took", durationMs, "ms"); |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | // Now, post a reply, possibly as an uncaught error. |
michael@0 | 94 | // We post this message from outside the |try ... catch| block |
michael@0 | 95 | // to avoid capturing errors that take place during |postMessage| and |
michael@0 | 96 | // built-in serialization. |
michael@0 | 97 | if (!exn) { |
michael@0 | 98 | LOG("Sending positive reply", result, "id is", id); |
michael@0 | 99 | if (result instanceof Meta) { |
michael@0 | 100 | if ("transfers" in result.meta) { |
michael@0 | 101 | // Take advantage of zero-copy transfers |
michael@0 | 102 | post({ok: result.data, id: id, durationMs: durationMs}, |
michael@0 | 103 | result.meta.transfers); |
michael@0 | 104 | } else { |
michael@0 | 105 | post({ok: result.data, id:id, durationMs: durationMs}); |
michael@0 | 106 | } |
michael@0 | 107 | if (result.meta.shutdown || false) { |
michael@0 | 108 | // Time to close the worker |
michael@0 | 109 | self.close(); |
michael@0 | 110 | } |
michael@0 | 111 | } else { |
michael@0 | 112 | post({ok: result, id:id, durationMs: durationMs}); |
michael@0 | 113 | } |
michael@0 | 114 | } else if (exn == StopIteration) { |
michael@0 | 115 | // StopIteration cannot be serialized automatically |
michael@0 | 116 | LOG("Sending back StopIteration"); |
michael@0 | 117 | post({StopIteration: true, id: id, durationMs: durationMs}); |
michael@0 | 118 | } else if (exn instanceof exports.OS.File.Error) { |
michael@0 | 119 | LOG("Sending back OS.File error", exn, "id is", id); |
michael@0 | 120 | // Instances of OS.File.Error know how to serialize themselves |
michael@0 | 121 | // (deserialization ensures that we end up with OS-specific |
michael@0 | 122 | // instances of |OS.File.Error|) |
michael@0 | 123 | post({fail: exports.OS.File.Error.toMsg(exn), id:id, durationMs: durationMs}); |
michael@0 | 124 | } else if (exn.constructor.name in EXCEPTION_NAMES) { |
michael@0 | 125 | LOG("Sending back exception", exn.constructor.name); |
michael@0 | 126 | post({fail: {exn: exn.constructor.name, message: exn.message, |
michael@0 | 127 | fileName: exn.moduleName || exn.fileName, lineNumber: exn.lineNumber}, |
michael@0 | 128 | id: id, durationMs: durationMs}); |
michael@0 | 129 | } else { |
michael@0 | 130 | // Other exceptions do not, and should be propagated through DOM's |
michael@0 | 131 | // built-in mechanism for uncaught errors, although this mechanism |
michael@0 | 132 | // may lose interesting information. |
michael@0 | 133 | LOG("Sending back regular error", exn, exn.moduleStack || exn.stack, "id is", id); |
michael@0 | 134 | |
michael@0 | 135 | throw exn; |
michael@0 | 136 | } |
michael@0 | 137 | }; |
michael@0 | 138 | |
michael@0 | 139 | /** |
michael@0 | 140 | * A data structure used to track opened resources |
michael@0 | 141 | */ |
michael@0 | 142 | let ResourceTracker = function ResourceTracker() { |
michael@0 | 143 | // A number used to generate ids |
michael@0 | 144 | this._idgen = 0; |
michael@0 | 145 | // A map from id to resource |
michael@0 | 146 | this._map = new Map(); |
michael@0 | 147 | }; |
michael@0 | 148 | ResourceTracker.prototype = { |
michael@0 | 149 | /** |
michael@0 | 150 | * Get a resource from its unique identifier. |
michael@0 | 151 | */ |
michael@0 | 152 | get: function(id) { |
michael@0 | 153 | let result = this._map.get(id); |
michael@0 | 154 | if (result == null) { |
michael@0 | 155 | return result; |
michael@0 | 156 | } |
michael@0 | 157 | return result.resource; |
michael@0 | 158 | }, |
michael@0 | 159 | /** |
michael@0 | 160 | * Remove a resource from its unique identifier. |
michael@0 | 161 | */ |
michael@0 | 162 | remove: function(id) { |
michael@0 | 163 | if (!this._map.has(id)) { |
michael@0 | 164 | throw new Error("Cannot find resource id " + id); |
michael@0 | 165 | } |
michael@0 | 166 | this._map.delete(id); |
michael@0 | 167 | }, |
michael@0 | 168 | /** |
michael@0 | 169 | * Add a resource, return a new unique identifier |
michael@0 | 170 | * |
michael@0 | 171 | * @param {*} resource A resource. |
michael@0 | 172 | * @param {*=} info Optional information. For debugging purposes. |
michael@0 | 173 | * |
michael@0 | 174 | * @return {*} A unique identifier. For the moment, this is a number, |
michael@0 | 175 | * but this might not remain the case forever. |
michael@0 | 176 | */ |
michael@0 | 177 | add: function(resource, info) { |
michael@0 | 178 | let id = this._idgen++; |
michael@0 | 179 | this._map.set(id, {resource:resource, info:info}); |
michael@0 | 180 | return id; |
michael@0 | 181 | }, |
michael@0 | 182 | /** |
michael@0 | 183 | * Return a list of all open resources i.e. the ones still present in |
michael@0 | 184 | * ResourceTracker's _map. |
michael@0 | 185 | */ |
michael@0 | 186 | listOpenedResources: function listOpenedResources() { |
michael@0 | 187 | return [resource.info.path for ([id, resource] of this._map)]; |
michael@0 | 188 | } |
michael@0 | 189 | }; |
michael@0 | 190 | |
michael@0 | 191 | /** |
michael@0 | 192 | * A map of unique identifiers to opened files. |
michael@0 | 193 | */ |
michael@0 | 194 | let OpenedFiles = new ResourceTracker(); |
michael@0 | 195 | |
michael@0 | 196 | /** |
michael@0 | 197 | * Execute a function in the context of a given file. |
michael@0 | 198 | * |
michael@0 | 199 | * @param {*} id A unique identifier, as used by |OpenFiles|. |
michael@0 | 200 | * @param {Function} f A function to call. |
michael@0 | 201 | * @param {boolean} ignoreAbsent If |true|, the error is ignored. Otherwise, the error causes an exception. |
michael@0 | 202 | * @return The return value of |f()| |
michael@0 | 203 | * |
michael@0 | 204 | * This function attempts to get the file matching |id|. If |
michael@0 | 205 | * the file exists, it executes |f| within the |this| set |
michael@0 | 206 | * to the corresponding file. Otherwise, it throws an error. |
michael@0 | 207 | */ |
michael@0 | 208 | let withFile = function withFile(id, f, ignoreAbsent) { |
michael@0 | 209 | let file = OpenedFiles.get(id); |
michael@0 | 210 | if (file == null) { |
michael@0 | 211 | if (!ignoreAbsent) { |
michael@0 | 212 | throw OS.File.Error.closed("accessing file"); |
michael@0 | 213 | } |
michael@0 | 214 | return undefined; |
michael@0 | 215 | } |
michael@0 | 216 | return f.call(file); |
michael@0 | 217 | }; |
michael@0 | 218 | |
michael@0 | 219 | let OpenedDirectoryIterators = new ResourceTracker(); |
michael@0 | 220 | let withDir = function withDir(fd, f, ignoreAbsent) { |
michael@0 | 221 | let file = OpenedDirectoryIterators.get(fd); |
michael@0 | 222 | if (file == null) { |
michael@0 | 223 | if (!ignoreAbsent) { |
michael@0 | 224 | throw OS.File.Error.closed("accessing directory"); |
michael@0 | 225 | } |
michael@0 | 226 | return undefined; |
michael@0 | 227 | } |
michael@0 | 228 | if (!(file instanceof File.DirectoryIterator)) { |
michael@0 | 229 | throw new Error("file is not a directory iterator " + file.__proto__.toSource()); |
michael@0 | 230 | } |
michael@0 | 231 | return f.call(file); |
michael@0 | 232 | }; |
michael@0 | 233 | |
michael@0 | 234 | let Type = exports.OS.Shared.Type; |
michael@0 | 235 | |
michael@0 | 236 | let File = exports.OS.File; |
michael@0 | 237 | |
michael@0 | 238 | /** |
michael@0 | 239 | * A constructor used to return data to the caller thread while |
michael@0 | 240 | * also executing some specific treatment (e.g. shutting down |
michael@0 | 241 | * the current thread, transmitting data instead of copying it). |
michael@0 | 242 | * |
michael@0 | 243 | * @param {object=} data The data to return to the caller thread. |
michael@0 | 244 | * @param {object=} meta Additional instructions, as an object |
michael@0 | 245 | * that may contain the following fields: |
michael@0 | 246 | * - {bool} shutdown If |true|, shut down the current thread after |
michael@0 | 247 | * having sent the result. |
michael@0 | 248 | * - {Array} transfers An array of objects that should be transferred |
michael@0 | 249 | * instead of being copied. |
michael@0 | 250 | * |
michael@0 | 251 | * @constructor |
michael@0 | 252 | */ |
michael@0 | 253 | let Meta = function Meta(data, meta) { |
michael@0 | 254 | this.data = data; |
michael@0 | 255 | this.meta = meta; |
michael@0 | 256 | }; |
michael@0 | 257 | |
michael@0 | 258 | /** |
michael@0 | 259 | * The agent. |
michael@0 | 260 | * |
michael@0 | 261 | * It is in charge of performing method-specific deserialization |
michael@0 | 262 | * of messages, calling the function/method of OS.File and serializing |
michael@0 | 263 | * back the results. |
michael@0 | 264 | */ |
michael@0 | 265 | let Agent = { |
michael@0 | 266 | // Update worker's OS.Shared.DEBUG flag message from controller. |
michael@0 | 267 | SET_DEBUG: function(aDEBUG) { |
michael@0 | 268 | SharedAll.Config.DEBUG = aDEBUG; |
michael@0 | 269 | }, |
michael@0 | 270 | // Return worker's current OS.Shared.DEBUG value to controller. |
michael@0 | 271 | // Note: This is used for testing purposes. |
michael@0 | 272 | GET_DEBUG: function() { |
michael@0 | 273 | return SharedAll.Config.DEBUG; |
michael@0 | 274 | }, |
michael@0 | 275 | /** |
michael@0 | 276 | * Execute shutdown sequence, returning data on leaked file descriptors. |
michael@0 | 277 | * |
michael@0 | 278 | * @param {bool} If |true|, kill the worker if this would not cause |
michael@0 | 279 | * leaks. |
michael@0 | 280 | */ |
michael@0 | 281 | Meta_shutdown: function(kill) { |
michael@0 | 282 | let result = { |
michael@0 | 283 | openedFiles: OpenedFiles.listOpenedResources(), |
michael@0 | 284 | openedDirectoryIterators: OpenedDirectoryIterators.listOpenedResources(), |
michael@0 | 285 | killed: false // Placeholder |
michael@0 | 286 | }; |
michael@0 | 287 | |
michael@0 | 288 | // Is it safe to kill the worker? |
michael@0 | 289 | let safe = result.openedFiles.length == 0 |
michael@0 | 290 | && result.openedDirectoryIterators.length == 0; |
michael@0 | 291 | result.killed = safe && kill; |
michael@0 | 292 | |
michael@0 | 293 | return new Meta(result, {shutdown: result.killed}); |
michael@0 | 294 | }, |
michael@0 | 295 | // Functions of OS.File |
michael@0 | 296 | stat: function stat(path, options) { |
michael@0 | 297 | return exports.OS.File.Info.toMsg( |
michael@0 | 298 | exports.OS.File.stat(Type.path.fromMsg(path), options)); |
michael@0 | 299 | }, |
michael@0 | 300 | setPermissions: function setPermissions(path, options = {}) { |
michael@0 | 301 | return exports.OS.File.setPermissions(Type.path.fromMsg(path), options); |
michael@0 | 302 | }, |
michael@0 | 303 | setDates: function setDates(path, accessDate, modificationDate) { |
michael@0 | 304 | return exports.OS.File.setDates(Type.path.fromMsg(path), accessDate, |
michael@0 | 305 | modificationDate); |
michael@0 | 306 | }, |
michael@0 | 307 | getCurrentDirectory: function getCurrentDirectory() { |
michael@0 | 308 | return exports.OS.Shared.Type.path.toMsg(File.getCurrentDirectory()); |
michael@0 | 309 | }, |
michael@0 | 310 | setCurrentDirectory: function setCurrentDirectory(path) { |
michael@0 | 311 | File.setCurrentDirectory(exports.OS.Shared.Type.path.fromMsg(path)); |
michael@0 | 312 | }, |
michael@0 | 313 | copy: function copy(sourcePath, destPath, options) { |
michael@0 | 314 | return File.copy(Type.path.fromMsg(sourcePath), |
michael@0 | 315 | Type.path.fromMsg(destPath), options); |
michael@0 | 316 | }, |
michael@0 | 317 | move: function move(sourcePath, destPath, options) { |
michael@0 | 318 | return File.move(Type.path.fromMsg(sourcePath), |
michael@0 | 319 | Type.path.fromMsg(destPath), options); |
michael@0 | 320 | }, |
michael@0 | 321 | getAvailableFreeSpace: function getAvailableFreeSpace(sourcePath) { |
michael@0 | 322 | return Type.uint64_t.toMsg( |
michael@0 | 323 | File.getAvailableFreeSpace(Type.path.fromMsg(sourcePath))); |
michael@0 | 324 | }, |
michael@0 | 325 | makeDir: function makeDir(path, options) { |
michael@0 | 326 | return File.makeDir(Type.path.fromMsg(path), options); |
michael@0 | 327 | }, |
michael@0 | 328 | removeEmptyDir: function removeEmptyDir(path, options) { |
michael@0 | 329 | return File.removeEmptyDir(Type.path.fromMsg(path), options); |
michael@0 | 330 | }, |
michael@0 | 331 | remove: function remove(path) { |
michael@0 | 332 | return File.remove(Type.path.fromMsg(path)); |
michael@0 | 333 | }, |
michael@0 | 334 | open: function open(path, mode, options) { |
michael@0 | 335 | let filePath = Type.path.fromMsg(path); |
michael@0 | 336 | let file = File.open(filePath, mode, options); |
michael@0 | 337 | return OpenedFiles.add(file, { |
michael@0 | 338 | // Adding path information to keep track of opened files |
michael@0 | 339 | // to report leaks when debugging. |
michael@0 | 340 | path: filePath |
michael@0 | 341 | }); |
michael@0 | 342 | }, |
michael@0 | 343 | openUnique: function openUnique(path, options) { |
michael@0 | 344 | let filePath = Type.path.fromMsg(path); |
michael@0 | 345 | let openedFile = OS.Shared.AbstractFile.openUnique(filePath, options); |
michael@0 | 346 | let resourceId = OpenedFiles.add(openedFile.file, { |
michael@0 | 347 | // Adding path information to keep track of opened files |
michael@0 | 348 | // to report leaks when debugging. |
michael@0 | 349 | path: openedFile.path |
michael@0 | 350 | }); |
michael@0 | 351 | |
michael@0 | 352 | return { |
michael@0 | 353 | path: openedFile.path, |
michael@0 | 354 | file: resourceId |
michael@0 | 355 | }; |
michael@0 | 356 | }, |
michael@0 | 357 | read: function read(path, bytes, options) { |
michael@0 | 358 | let data = File.read(Type.path.fromMsg(path), bytes, options); |
michael@0 | 359 | if (typeof data == "string") { |
michael@0 | 360 | return data; |
michael@0 | 361 | } |
michael@0 | 362 | return new Meta({ |
michael@0 | 363 | buffer: data.buffer, |
michael@0 | 364 | byteOffset: data.byteOffset, |
michael@0 | 365 | byteLength: data.byteLength |
michael@0 | 366 | }, { |
michael@0 | 367 | transfers: [data.buffer] |
michael@0 | 368 | }); |
michael@0 | 369 | }, |
michael@0 | 370 | exists: function exists(path) { |
michael@0 | 371 | return File.exists(Type.path.fromMsg(path)); |
michael@0 | 372 | }, |
michael@0 | 373 | writeAtomic: function writeAtomic(path, buffer, options) { |
michael@0 | 374 | if (options.tmpPath) { |
michael@0 | 375 | options.tmpPath = Type.path.fromMsg(options.tmpPath); |
michael@0 | 376 | } |
michael@0 | 377 | return File.writeAtomic(Type.path.fromMsg(path), |
michael@0 | 378 | Type.voidptr_t.fromMsg(buffer), |
michael@0 | 379 | options |
michael@0 | 380 | ); |
michael@0 | 381 | }, |
michael@0 | 382 | removeDir: function(path, options) { |
michael@0 | 383 | return File.removeDir(Type.path.fromMsg(path), options); |
michael@0 | 384 | }, |
michael@0 | 385 | new_DirectoryIterator: function new_DirectoryIterator(path, options) { |
michael@0 | 386 | let directoryPath = Type.path.fromMsg(path); |
michael@0 | 387 | let iterator = new File.DirectoryIterator(directoryPath, options); |
michael@0 | 388 | return OpenedDirectoryIterators.add(iterator, { |
michael@0 | 389 | // Adding path information to keep track of opened directory |
michael@0 | 390 | // iterators to report leaks when debugging. |
michael@0 | 391 | path: directoryPath |
michael@0 | 392 | }); |
michael@0 | 393 | }, |
michael@0 | 394 | // Methods of OS.File |
michael@0 | 395 | File_prototype_close: function close(fd) { |
michael@0 | 396 | return withFile(fd, |
michael@0 | 397 | function do_close() { |
michael@0 | 398 | try { |
michael@0 | 399 | return this.close(); |
michael@0 | 400 | } finally { |
michael@0 | 401 | OpenedFiles.remove(fd); |
michael@0 | 402 | } |
michael@0 | 403 | }); |
michael@0 | 404 | }, |
michael@0 | 405 | File_prototype_stat: function stat(fd) { |
michael@0 | 406 | return withFile(fd, |
michael@0 | 407 | function do_stat() { |
michael@0 | 408 | return exports.OS.File.Info.toMsg(this.stat()); |
michael@0 | 409 | }); |
michael@0 | 410 | }, |
michael@0 | 411 | File_prototype_setPermissions: function setPermissions(fd, options = {}) { |
michael@0 | 412 | return withFile(fd, |
michael@0 | 413 | function do_setPermissions() { |
michael@0 | 414 | return this.setPermissions(options); |
michael@0 | 415 | }); |
michael@0 | 416 | }, |
michael@0 | 417 | File_prototype_setDates: function setDates(fd, accessTime, modificationTime) { |
michael@0 | 418 | return withFile(fd, |
michael@0 | 419 | function do_setDates() { |
michael@0 | 420 | return this.setDates(accessTime, modificationTime); |
michael@0 | 421 | }); |
michael@0 | 422 | }, |
michael@0 | 423 | File_prototype_read: function read(fd, nbytes, options) { |
michael@0 | 424 | return withFile(fd, |
michael@0 | 425 | function do_read() { |
michael@0 | 426 | let data = this.read(nbytes, options); |
michael@0 | 427 | return new Meta({ |
michael@0 | 428 | buffer: data.buffer, |
michael@0 | 429 | byteOffset: data.byteOffset, |
michael@0 | 430 | byteLength: data.byteLength |
michael@0 | 431 | }, { |
michael@0 | 432 | transfers: [data.buffer] |
michael@0 | 433 | }); |
michael@0 | 434 | } |
michael@0 | 435 | ); |
michael@0 | 436 | }, |
michael@0 | 437 | File_prototype_readTo: function readTo(fd, buffer, options) { |
michael@0 | 438 | return withFile(fd, |
michael@0 | 439 | function do_readTo() { |
michael@0 | 440 | return this.readTo(exports.OS.Shared.Type.voidptr_t.fromMsg(buffer), |
michael@0 | 441 | options); |
michael@0 | 442 | }); |
michael@0 | 443 | }, |
michael@0 | 444 | File_prototype_write: function write(fd, buffer, options) { |
michael@0 | 445 | return withFile(fd, |
michael@0 | 446 | function do_write() { |
michael@0 | 447 | return this.write(exports.OS.Shared.Type.voidptr_t.fromMsg(buffer), |
michael@0 | 448 | options); |
michael@0 | 449 | }); |
michael@0 | 450 | }, |
michael@0 | 451 | File_prototype_setPosition: function setPosition(fd, pos, whence) { |
michael@0 | 452 | return withFile(fd, |
michael@0 | 453 | function do_setPosition() { |
michael@0 | 454 | return this.setPosition(pos, whence); |
michael@0 | 455 | }); |
michael@0 | 456 | }, |
michael@0 | 457 | File_prototype_getPosition: function getPosition(fd) { |
michael@0 | 458 | return withFile(fd, |
michael@0 | 459 | function do_getPosition() { |
michael@0 | 460 | return this.getPosition(); |
michael@0 | 461 | }); |
michael@0 | 462 | }, |
michael@0 | 463 | File_prototype_flush: function flush(fd) { |
michael@0 | 464 | return withFile(fd, |
michael@0 | 465 | function do_flush() { |
michael@0 | 466 | return this.flush(); |
michael@0 | 467 | }); |
michael@0 | 468 | }, |
michael@0 | 469 | // Methods of OS.File.DirectoryIterator |
michael@0 | 470 | DirectoryIterator_prototype_next: function next(dir) { |
michael@0 | 471 | return withDir(dir, |
michael@0 | 472 | function do_next() { |
michael@0 | 473 | try { |
michael@0 | 474 | return File.DirectoryIterator.Entry.toMsg(this.next()); |
michael@0 | 475 | } catch (x) { |
michael@0 | 476 | if (x == StopIteration) { |
michael@0 | 477 | OpenedDirectoryIterators.remove(dir); |
michael@0 | 478 | } |
michael@0 | 479 | throw x; |
michael@0 | 480 | } |
michael@0 | 481 | }, false); |
michael@0 | 482 | }, |
michael@0 | 483 | DirectoryIterator_prototype_nextBatch: function nextBatch(dir, size) { |
michael@0 | 484 | return withDir(dir, |
michael@0 | 485 | function do_nextBatch() { |
michael@0 | 486 | let result; |
michael@0 | 487 | try { |
michael@0 | 488 | result = this.nextBatch(size); |
michael@0 | 489 | } catch (x) { |
michael@0 | 490 | OpenedDirectoryIterators.remove(dir); |
michael@0 | 491 | throw x; |
michael@0 | 492 | } |
michael@0 | 493 | return result.map(File.DirectoryIterator.Entry.toMsg); |
michael@0 | 494 | }, false); |
michael@0 | 495 | }, |
michael@0 | 496 | DirectoryIterator_prototype_close: function close(dir) { |
michael@0 | 497 | return withDir(dir, |
michael@0 | 498 | function do_close() { |
michael@0 | 499 | this.close(); |
michael@0 | 500 | OpenedDirectoryIterators.remove(dir); |
michael@0 | 501 | }, true);// ignore error to support double-closing |DirectoryIterator| |
michael@0 | 502 | }, |
michael@0 | 503 | DirectoryIterator_prototype_exists: function exists(dir) { |
michael@0 | 504 | return withDir(dir, |
michael@0 | 505 | function do_exists() { |
michael@0 | 506 | return this.exists(); |
michael@0 | 507 | }); |
michael@0 | 508 | } |
michael@0 | 509 | }; |
michael@0 | 510 | if (!SharedAll.Constants.Win) { |
michael@0 | 511 | Agent.unixSymLink = function unixSymLink(sourcePath, destPath) { |
michael@0 | 512 | return File.unixSymLink(Type.path.fromMsg(sourcePath), |
michael@0 | 513 | Type.path.fromMsg(destPath)); |
michael@0 | 514 | }; |
michael@0 | 515 | } |
michael@0 | 516 | |
michael@0 | 517 | timeStamps.loaded = Date.now(); |
michael@0 | 518 | })(this); |