Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / dom / system / IOUtils.h
blob6acfcbfb2435e498cee5efb1e681130ea3334284
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_dom_IOUtils__
8 #define mozilla_dom_IOUtils__
10 #include "js/Utility.h"
11 #include "mozilla/AlreadyAddRefed.h"
12 #include "mozilla/Attributes.h"
13 #include "mozilla/Buffer.h"
14 #include "mozilla/DataMutex.h"
15 #include "mozilla/MozPromise.h"
16 #include "mozilla/Result.h"
17 #include "mozilla/StaticPtr.h"
18 #include "mozilla/dom/BindingDeclarations.h"
19 #include "mozilla/dom/IOUtilsBinding.h"
20 #include "mozilla/dom/TypedArray.h"
21 #include "nsIAsyncShutdown.h"
22 #include "nsIFile.h"
23 #include "nsISerialEventTarget.h"
24 #include "nsPrintfCString.h"
25 #include "nsProxyRelease.h"
26 #include "nsString.h"
27 #include "nsStringFwd.h"
28 #include "nsTArray.h"
29 #include "prio.h"
31 class nsFileRandomAccessStream;
33 namespace mozilla {
35 /**
36 * Utility class to be used with |UniquePtr| to automatically close NSPR file
37 * descriptors when they go out of scope.
39 * Example:
41 * UniquePtr<PRFileDesc, PR_CloseDelete> fd = PR_Open(path, flags, mode);
43 class PR_CloseDelete {
44 public:
45 constexpr PR_CloseDelete() = default;
46 PR_CloseDelete(const PR_CloseDelete& aOther) = default;
47 PR_CloseDelete(PR_CloseDelete&& aOther) = default;
48 PR_CloseDelete& operator=(const PR_CloseDelete& aOther) = default;
49 PR_CloseDelete& operator=(PR_CloseDelete&& aOther) = default;
51 void operator()(PRFileDesc* aPtr) const { PR_Close(aPtr); }
54 namespace dom {
56 /**
57 * Implementation for the Web IDL interface at dom/chrome-webidl/IOUtils.webidl.
58 * Methods of this class must only be called from the parent process.
60 class IOUtils final {
61 public:
62 class IOError;
64 enum class ShutdownPhase : uint8_t {
65 ProfileBeforeChange,
66 SendTelemetry,
67 XpcomWillShutdown,
68 Count,
71 template <typename T>
72 using PhaseArray = EnumeratedArray<IOUtils::ShutdownPhase, T,
73 size_t(IOUtils::ShutdownPhase::Count)>;
75 static already_AddRefed<Promise> Read(GlobalObject& aGlobal,
76 const nsAString& aPath,
77 const ReadOptions& aOptions,
78 ErrorResult& aError);
80 static already_AddRefed<Promise> ReadUTF8(GlobalObject& aGlobal,
81 const nsAString& aPath,
82 const ReadUTF8Options& aOptions,
83 ErrorResult& aError);
85 static already_AddRefed<Promise> ReadJSON(GlobalObject& aGlobal,
86 const nsAString& aPath,
87 const ReadUTF8Options& aOptions,
88 ErrorResult& aError);
90 static already_AddRefed<Promise> Write(GlobalObject& aGlobal,
91 const nsAString& aPath,
92 const Uint8Array& aData,
93 const WriteOptions& aOptions,
94 ErrorResult& aError);
96 static already_AddRefed<Promise> WriteUTF8(GlobalObject& aGlobal,
97 const nsAString& aPath,
98 const nsACString& aString,
99 const WriteOptions& aOptions,
100 ErrorResult& aError);
102 static already_AddRefed<Promise> WriteJSON(GlobalObject& aGlobal,
103 const nsAString& aPath,
104 JS::Handle<JS::Value> aValue,
105 const WriteOptions& aOptions,
106 ErrorResult& aError);
108 static already_AddRefed<Promise> Move(GlobalObject& aGlobal,
109 const nsAString& aSourcePath,
110 const nsAString& aDestPath,
111 const MoveOptions& aOptions,
112 ErrorResult& aError);
114 static already_AddRefed<Promise> Remove(GlobalObject& aGlobal,
115 const nsAString& aPath,
116 const RemoveOptions& aOptions,
117 ErrorResult& aError);
119 static already_AddRefed<Promise> MakeDirectory(
120 GlobalObject& aGlobal, const nsAString& aPath,
121 const MakeDirectoryOptions& aOptions, ErrorResult& aError);
123 static already_AddRefed<Promise> Stat(GlobalObject& aGlobal,
124 const nsAString& aPath,
125 ErrorResult& aError);
127 static already_AddRefed<Promise> Copy(GlobalObject& aGlobal,
128 const nsAString& aSourcePath,
129 const nsAString& aDestPath,
130 const CopyOptions& aOptions,
131 ErrorResult& aError);
133 static already_AddRefed<Promise> SetAccessTime(
134 GlobalObject& aGlobal, const nsAString& aPath,
135 const Optional<int64_t>& aAccess, ErrorResult& aError);
137 static already_AddRefed<Promise> SetModificationTime(
138 GlobalObject& aGlobal, const nsAString& aPath,
139 const Optional<int64_t>& aModification, ErrorResult& aError);
141 private:
142 using SetTimeFn = decltype(&nsIFile::SetLastAccessedTime);
144 static_assert(
145 std::is_same_v<SetTimeFn, decltype(&nsIFile::SetLastModifiedTime)>);
147 static already_AddRefed<Promise> SetTime(GlobalObject& aGlobal,
148 const nsAString& aPath,
149 const Optional<int64_t>& aNewTime,
150 SetTimeFn aSetTimeFn,
151 const char* const aTimeKind,
152 ErrorResult& aError);
154 public:
155 static already_AddRefed<Promise> GetChildren(
156 GlobalObject& aGlobal, const nsAString& aPath,
157 const GetChildrenOptions& aOptions, ErrorResult& aError);
159 static already_AddRefed<Promise> SetPermissions(GlobalObject& aGlobal,
160 const nsAString& aPath,
161 uint32_t aPermissions,
162 const bool aHonorUmask,
163 ErrorResult& aError);
165 static already_AddRefed<Promise> Exists(GlobalObject& aGlobal,
166 const nsAString& aPath,
167 ErrorResult& aError);
169 static already_AddRefed<Promise> CreateUniqueFile(GlobalObject& aGlobal,
170 const nsAString& aParent,
171 const nsAString& aPrefix,
172 const uint32_t aPermissions,
173 ErrorResult& aError);
174 static already_AddRefed<Promise> CreateUniqueDirectory(
175 GlobalObject& aGlobal, const nsAString& aParent, const nsAString& aPrefix,
176 const uint32_t aPermissions, ErrorResult& aError);
178 private:
180 * A helper method for CreateUniqueFile and CreateUniqueDirectory.
182 static already_AddRefed<Promise> CreateUnique(GlobalObject& aGlobal,
183 const nsAString& aParent,
184 const nsAString& aPrefix,
185 const uint32_t aFileType,
186 const uint32_t aPermissions,
187 ErrorResult& aError);
189 public:
190 static already_AddRefed<Promise> ComputeHexDigest(
191 GlobalObject& aGlobal, const nsAString& aPath,
192 const HashAlgorithm aAlgorithm, ErrorResult& aError);
194 #if defined(XP_WIN)
195 static already_AddRefed<Promise> GetWindowsAttributes(GlobalObject& aGlobal,
196 const nsAString& aPath,
197 ErrorResult& aError);
199 static already_AddRefed<Promise> SetWindowsAttributes(
200 GlobalObject& aGlobal, const nsAString& aPath,
201 const mozilla::dom::WindowsFileAttributes& aAttrs, ErrorResult& aError);
202 #elif defined(XP_MACOSX)
203 static already_AddRefed<Promise> HasMacXAttr(GlobalObject& aGlobal,
204 const nsAString& aPath,
205 const nsACString& aAttr,
206 ErrorResult& aError);
207 static already_AddRefed<Promise> GetMacXAttr(GlobalObject& aGlobal,
208 const nsAString& aPath,
209 const nsACString& aAttr,
210 ErrorResult& aError);
211 static already_AddRefed<Promise> SetMacXAttr(GlobalObject& aGlobal,
212 const nsAString& aPath,
213 const nsACString& aAttr,
214 const Uint8Array& aValue,
215 ErrorResult& aError);
216 static already_AddRefed<Promise> DelMacXAttr(GlobalObject& aGlobal,
217 const nsAString& aPath,
218 const nsACString& aAttr,
219 ErrorResult& aError);
220 #endif
222 #ifdef XP_UNIX
223 using UnixString = OwningUTF8StringOrUint8Array;
224 static uint32_t LaunchProcess(GlobalObject& aGlobal,
225 const Sequence<UnixString>& aArgv,
226 const LaunchOptions& aOptions,
227 ErrorResult& aRv);
228 #endif
230 static already_AddRefed<Promise> GetFile(
231 GlobalObject& aGlobal, const Sequence<nsString>& aComponents,
232 ErrorResult& aError);
234 static already_AddRefed<Promise> GetDirectory(
235 GlobalObject& aGlobal, const Sequence<nsString>& aComponents,
236 ErrorResult& aError);
238 static void GetProfileBeforeChange(GlobalObject& aGlobal,
239 JS::MutableHandle<JS::Value>,
240 ErrorResult& aRv);
242 static void GetSendTelemetry(GlobalObject& aGlobal,
243 JS::MutableHandle<JS::Value>, ErrorResult& aRv);
245 static RefPtr<SyncReadFile> OpenFileForSyncReading(GlobalObject& aGlobal,
246 const nsAString& aPath,
247 ErrorResult& aRv);
249 class JsBuffer;
252 * The kind of buffer to allocate.
254 * This controls what kind of JS object (a JSString or a Uint8Array) is
255 * returned by |ToJSValue()|.
257 enum class BufferKind {
258 String,
259 Uint8Array,
262 private:
263 ~IOUtils() = default;
265 template <typename T>
266 using IOPromise = MozPromise<T, IOError, true>;
268 friend class IOUtilsShutdownBlocker;
269 struct InternalFileInfo;
270 struct InternalWriteOpts;
271 class MozLZ4;
272 class EventQueue;
273 class State;
275 template <typename Fn>
276 static already_AddRefed<Promise> WithPromiseAndState(GlobalObject& aGlobal,
277 ErrorResult& aError,
278 Fn aFn);
281 * Dispatch a task on the event queue and resolve or reject the associated
282 * promise based on the result.
284 * NB: If the calling thread is a worker, this function takes care of keepting
285 * it alive until the |IOPromise| can complete.
287 * @param aPromise The promise corresponding to the task running on the event
288 * queue.
289 * @param aFunc The task to run.
291 template <typename OkT, typename Fn>
292 static void DispatchAndResolve(EventQueue* aQueue, Promise* aPromise,
293 Fn aFunc);
296 * Creates a new JS Promise.
298 * @return The new promise, or |nullptr| on failure.
300 static already_AddRefed<Promise> CreateJSPromise(GlobalObject& aGlobal,
301 ErrorResult& aError);
303 // Allow conversion of |InternalFileInfo| with |ToJSValue|.
304 friend bool ToJSValue(JSContext* aCx,
305 const InternalFileInfo& aInternalFileInfo,
306 JS::MutableHandle<JS::Value> aValue);
309 * Attempts to read the entire file at |aPath| into a buffer.
311 * @param aFile The location of the file.
312 * @param aOffset The offset to start reading from.
313 * @param aMaxBytes If |Some|, then only read up this this number of bytes,
314 * otherwise attempt to read the whole file.
315 * @param aDecompress If true, decompress the bytes read from disk before
316 * returning the result to the caller.
317 * @param aBufferKind The kind of buffer to allocate.
319 * @return A buffer containing the entire (decompressed) file contents, or an
320 * error.
322 static Result<JsBuffer, IOError> ReadSync(nsIFile* aFile,
323 const uint64_t aOffset,
324 const Maybe<uint32_t> aMaxBytes,
325 const bool aDecompress,
326 BufferKind aBufferKind);
329 * Attempts to read the entire file at |aPath| as a UTF-8 string.
331 * @param aFile The location of the file.
332 * @param aDecompress If true, decompress the bytes read from disk before
333 * returning the result to the caller.
335 * @return The (decompressed) contents of the file re-encoded as a UTF-16
336 * string.
338 static Result<JsBuffer, IOError> ReadUTF8Sync(nsIFile* aFile,
339 const bool aDecompress);
342 * Attempt to write the entirety of |aByteArray| to the file at |aPath|.
343 * This may occur by writing to an intermediate destination and performing a
344 * move, depending on |aOptions|.
346 * @param aFile The location of the file.
347 * @param aByteArray The data to write to the file.
348 * @param aOptions Options to modify the way the write is completed.
350 * @return The number of bytes written to the file, or an error if the write
351 * failed or was incomplete.
353 static Result<uint32_t, IOError> WriteSync(
354 nsIFile* aFile, const Span<const uint8_t>& aByteArray,
355 const InternalWriteOpts& aOptions);
358 * Attempts to move the file located at |aSourceFile| to |aDestFile|.
360 * @param aSourceFile The location of the file to move.
361 * @param aDestFile The destination for the file.
362 * @param aNoOverWrite If true, abort with an error if a file already exists
363 * at |aDestFile|. Otherwise, the file will be overwritten by the move.
365 * @return Ok if the file was moved successfully, or an error.
367 static Result<Ok, IOError> MoveSync(nsIFile* aSourceFile, nsIFile* aDestFile,
368 bool aNoOverwrite);
371 * Attempts to copy the file at |aSourceFile| to |aDestFile|.
373 * @param aSourceFile The location of the file to copy.
374 * @param aDestFile The destination that the file will be copied to.
376 * @return Ok if the operation was successful, or an error.
378 static Result<Ok, IOError> CopySync(nsIFile* aSourceFile, nsIFile* aDestFile,
379 bool aNoOverWrite, bool aRecursive);
382 * Provides the implementation for |CopySync| and |MoveSync|.
384 * @param aMethod A pointer to one of |nsIFile::MoveTo| or |CopyTo|
385 * instance methods.
386 * @param aMethodName The name of the method to the performed. Either "move"
387 * or "copy".
388 * @param aSource The source file to be copied or moved.
389 * @param aDest The destination file.
390 * @param aNoOverwrite If true, allow overwriting |aDest| during the copy or
391 * move. Otherwise, abort with an error if the file would
392 * be overwritten.
394 * @return Ok if the operation was successful, or an error.
396 template <typename CopyOrMoveFn>
397 static Result<Ok, IOError> CopyOrMoveSync(CopyOrMoveFn aMethod,
398 const char* aMethodName,
399 nsIFile* aSource, nsIFile* aDest,
400 bool aNoOverwrite);
403 * Attempts to remove the file located at |aFile|.
405 * @param aFile The location of the file.
406 * @param aIgnoreAbsent If true, suppress errors due to an absent target
407 * file.
408 * @param aRecursive If true, attempt to recursively remove descendant
409 * files. This option is safe to use even if the target
410 * is not a directory.
411 * @param aRetryReadonly Retry a delete that failed with a NotAllowedError by
412 * first removing the readonly attribute. Only has an
413 * effect on Windows.
415 * @return Ok if the file was removed successfully, or an error.
417 static Result<Ok, IOError> RemoveSync(nsIFile* aFile, bool aIgnoreAbsent,
418 bool aRecursive, bool aRetryReadonly);
421 * Attempts to create a new directory at |aFile|.
423 * @param aFile The location of the directory to create.
424 * @param aCreateAncestors If true, create missing ancestor directories as
425 * needed. Otherwise, report an error if the target
426 * has non-existing ancestor directories.
427 * @param aIgnoreExisting If true, suppress errors that occur if the target
428 * directory already exists. Otherwise, propagate the
429 * error if it occurs.
430 * @param aMode Optional file mode. Defaults to 0777 to allow the
431 * system umask to compute the best mode for the new
432 * directory.
434 * @return Ok if the directory was created successfully, or an error.
436 static Result<Ok, IOError> MakeDirectorySync(nsIFile* aFile,
437 bool aCreateAncestors,
438 bool aIgnoreExisting,
439 int32_t aMode = 0777);
442 * Attempts to stat a file at |aFile|.
444 * @param aFile The location of the file.
446 * @return An |InternalFileInfo| struct if successful, or an error.
448 static Result<IOUtils::InternalFileInfo, IOError> StatSync(nsIFile* aFile);
451 * Attempts to update the last access or modification time of the file at
452 * |aFile|.
454 * @param aFile The location of the file.
455 * @param SetTimeFn A member function pointer to either
456 * nsIFile::SetLastAccessedTime or
457 * nsIFile::SetLastModifiedTime.
458 * @param aNewTime Some value in milliseconds since Epoch.
460 * @return Timestamp of the file if the operation was successful, or an error.
462 static Result<int64_t, IOError> SetTimeSync(nsIFile* aFile,
463 SetTimeFn aSetTimeFn,
464 int64_t aNewTime);
467 * Returns the immediate children of the directory at |aFile|, if any.
469 * @param aFile The location of the directory.
471 * @return An array of absolute paths identifying the children of |aFile|.
472 * If there are no children, an empty array. Otherwise, an error.
474 static Result<nsTArray<nsString>, IOError> GetChildrenSync(
475 nsIFile* aFile, bool aIgnoreAbsent);
478 * Set the permissions of the given file.
480 * Windows does not make a distinction between user, group, and other
481 * permissions like UNICES do. If a permission flag is set for any of user,
482 * group, or other has a permission, then all users will have that
483 * permission.
485 * @param aFile The location of the file.
486 * @param aPermissions The permissions to set, as a UNIX file mode.
488 * @return |Ok| if the permissions were successfully set, or an error.
490 static Result<Ok, IOError> SetPermissionsSync(nsIFile* aFile,
491 const uint32_t aPermissions);
494 * Return whether or not the file exists.
496 * @param aFile The location of the file.
498 * @return Whether or not the file exists.
500 static Result<bool, IOError> ExistsSync(nsIFile* aFile);
503 * Create a file or directory with a unique path.
505 * @param aFile The location of the file or directory (including prefix)
506 * @param aFileType One of |nsIFile::NORMAL_FILE_TYPE| or
507 * |nsIFile::DIRECTORY_TYPE|.
508 * @param aperms The permissions to create the file or directory with.
510 * @return A unique path.
512 static Result<nsString, IOError> CreateUniqueSync(
513 nsIFile* aFile, const uint32_t aFileType, const uint32_t aPermissions);
516 * Compute the hash of a file.
518 * @param aFile The file to hash.
519 * @param aAlgorithm The hashing algorithm to use.
521 * @return The hash of the file, as a hex digest.
523 static Result<nsCString, IOError> ComputeHexDigestSync(
524 nsIFile* aFile, const HashAlgorithm aAlgorithm);
526 #if defined(XP_WIN)
528 * Return the Windows-specific attributes of the file.
530 * @param aFile The location of the file.
532 * @return The Windows-specific attributes of the file.
534 static Result<uint32_t, IOError> GetWindowsAttributesSync(nsIFile* aFile);
537 * Set the Windows-specific attributes of the file.
539 * @param aFile The location of the file.
540 * @param aAttrs The attributes to set on the file.
542 * @return |Ok| if the attributes were successfully set, or an error.
544 static Result<Ok, IOError> SetWindowsAttributesSync(
545 nsIFile* aFile, const uint32_t aSetAttrs, const uint32_t aClearAttrs);
546 #elif defined(XP_MACOSX)
547 static Result<bool, IOError> HasMacXAttrSync(nsIFile* aFile,
548 const nsCString& aAttr);
549 static Result<nsTArray<uint8_t>, IOError> GetMacXAttrSync(
550 nsIFile* aFile, const nsCString& aAttr);
551 static Result<Ok, IOError> SetMacXAttrSync(nsIFile* aFile,
552 const nsCString& aAttr,
553 const nsTArray<uint8_t>& aValue);
554 static Result<Ok, IOError> DelMacXAttrSync(nsIFile* aFile,
555 const nsCString& aAttr);
556 #endif
558 static void GetShutdownClient(GlobalObject& aGlobal,
559 JS::MutableHandle<JS::Value> aClient,
560 ErrorResult& aRv, const ShutdownPhase aPhase);
562 enum class EventQueueStatus {
563 Uninitialized,
564 Initialized,
565 Shutdown,
568 enum class ShutdownBlockerStatus {
569 Uninitialized,
570 Initialized,
571 Failed,
575 * Internal IOUtils state.
577 class State {
578 public:
579 StaticAutoPtr<EventQueue> mEventQueue;
580 EventQueueStatus mQueueStatus = EventQueueStatus::Uninitialized;
581 ShutdownBlockerStatus mBlockerStatus = ShutdownBlockerStatus::Uninitialized;
584 * Set up shutdown hooks to free our internals at shutdown.
586 * NB: Must be called on main thread.
588 void SetShutdownHooks();
591 using StateMutex = StaticDataMutex<State>;
594 * Lock the state mutex and return a handle. If shutdown has not yet
595 * finished, the internals will be constructed if necessary.
597 * @returns A handle to the internal state, which can be used to retrieve the
598 * event queue.
599 * If |Some| is returned, |mEventQueue| is guaranteed to be
600 * initialized. If shutdown has finished, |Nothing| is returned.
602 static Maybe<StateMutex::AutoLock> GetState();
604 static StateMutex sState;
608 * The IOUtils event queue.
610 class IOUtils::EventQueue final {
611 friend void IOUtils::State::SetShutdownHooks();
613 public:
614 EventQueue();
616 EventQueue(const EventQueue&) = delete;
617 EventQueue(EventQueue&&) = delete;
618 EventQueue& operator=(const EventQueue&) = delete;
619 EventQueue& operator=(EventQueue&&) = delete;
622 * Dispatch a task on the event queue.
624 * NB: If using this directly from |IOUtils| instead of
625 * |IOUtils::DispatchAndResolve| *and* the calling thread is a worker, you
626 * *must* take care to keep the worker thread alive until the |IOPromise|
627 * resolves or rejects. See the implementation of
628 * |IOUtils::DispatchAndResolve| or |IOUtils::GetWindowsAttributes| for an
629 * example.
631 * @param aFunc The task to dispatch on the event queue.
633 * @return A promise that resolves to the task's return value or rejects with
634 * an error.
636 template <typename OkT, typename Fn>
637 RefPtr<IOPromise<OkT>> Dispatch(Fn aFunc);
639 Result<already_AddRefed<nsIAsyncShutdownBarrier>, nsresult>
640 GetShutdownBarrier(const ShutdownPhase aPhase);
641 Result<already_AddRefed<nsIAsyncShutdownClient>, nsresult> GetShutdownClient(
642 const ShutdownPhase aPhase);
644 private:
645 nsresult SetShutdownHooks();
647 nsCOMPtr<nsISerialEventTarget> mBackgroundEventTarget;
648 IOUtils::PhaseArray<nsCOMPtr<nsIAsyncShutdownBarrier>> mBarriers;
652 * An error class used with the |Result| type returned by most private |IOUtils|
653 * methods.
655 class IOUtils::IOError {
656 public:
657 IOError(nsresult aCode, const nsCString& aMsg)
658 : mCode(aCode), mMessage(aMsg) {}
660 IOError(nsresult aCode, const char* const aFmt, ...) MOZ_FORMAT_PRINTF(3, 4)
661 : mCode(aCode) {
662 va_list ap;
663 va_start(ap, aFmt);
664 mMessage.AppendVprintf(aFmt, ap);
665 va_end(ap);
668 static IOError WithCause(const IOError& aCause, const nsCString& aMsg) {
669 IOError e(aCause.mCode, aMsg);
670 e.mMessage.AppendPrintf(": %s", aCause.mMessage.get());
671 return e;
674 static IOError WithCause(const IOError& aCause, const char* const aFmt, ...)
675 MOZ_FORMAT_PRINTF(2, 3) {
676 va_list ap;
677 va_start(ap, aFmt);
679 IOError e(aCause.mCode, EmptyCString());
680 e.mMessage.AppendVprintf(aFmt, ap);
681 e.mMessage.AppendPrintf(": %s", aCause.mMessage.get());
683 va_end(ap);
684 return e;
688 * Returns the |nsresult| associated with this error.
690 nsresult Code() const { return mCode; }
693 * Returns the message associated with this error.
695 const nsCString& Message() const { return mMessage; }
697 private:
698 nsresult mCode;
699 nsCString mMessage;
703 * This is an easier to work with representation of a |mozilla::dom::FileInfo|
704 * for private use in the IOUtils implementation.
706 * Because web IDL dictionaries are not easily copy/moveable, this class is
707 * used instead, until converted to the proper |mozilla::dom::FileInfo| before
708 * returning any results to JavaScript.
710 struct IOUtils::InternalFileInfo {
711 nsString mPath;
712 FileType mType = FileType::Other;
713 uint64_t mSize = 0;
714 Maybe<PRTime> mCreationTime; // In ms since epoch.
715 PRTime mLastAccessed = 0; // In ms since epoch.
716 PRTime mLastModified = 0; // In ms since epoch.
717 uint32_t mPermissions = 0;
721 * This is an easier to work with representation of a
722 * |mozilla::dom::WriteOptions| for private use in the |IOUtils|
723 * implementation.
725 * Because web IDL dictionaries are not easily copy/moveable, this class is
726 * used instead.
728 struct IOUtils::InternalWriteOpts {
729 RefPtr<nsIFile> mBackupFile;
730 RefPtr<nsIFile> mTmpFile;
731 WriteMode mMode;
732 bool mFlush = false;
733 bool mCompress = false;
735 static Result<InternalWriteOpts, IOUtils::IOError> FromBinding(
736 const WriteOptions& aOptions);
740 * Re-implements the file compression and decompression utilities found
741 * in toolkit/components/lz4/lz4.js
743 * This implementation uses the non-standard data layout:
745 * - MAGIC_NUMBER (8 bytes)
746 * - content size (uint32_t, little endian)
747 * - content, as obtained from mozilla::Compression::LZ4::compress
749 * See bug 1209390 for more info.
751 class IOUtils::MozLZ4 {
752 public:
753 static constexpr std::array<uint8_t, 8> MAGIC_NUMBER{
754 {'m', 'o', 'z', 'L', 'z', '4', '0', '\0'}};
756 static const uint32_t HEADER_SIZE = 8 + sizeof(uint32_t);
759 * Compresses |aUncompressed| byte array, and returns a byte array with the
760 * correct format whose contents may be written to disk.
762 static Result<nsTArray<uint8_t>, IOError> Compress(
763 Span<const uint8_t> aUncompressed);
766 * Checks |aFileContents| for the correct file header, and returns the
767 * decompressed content.
769 static Result<IOUtils::JsBuffer, IOError> Decompress(
770 Span<const uint8_t> aFileContents, IOUtils::BufferKind);
773 class IOUtilsShutdownBlocker : public nsIAsyncShutdownBlocker,
774 public nsIAsyncShutdownCompletionCallback {
775 public:
776 NS_DECL_THREADSAFE_ISUPPORTS
777 NS_DECL_NSIASYNCSHUTDOWNBLOCKER
778 NS_DECL_NSIASYNCSHUTDOWNCOMPLETIONCALLBACK
780 explicit IOUtilsShutdownBlocker(const IOUtils::ShutdownPhase aPhase)
781 : mPhase(aPhase) {}
783 private:
784 virtual ~IOUtilsShutdownBlocker() = default;
787 * Called on the main thread after the event queue has been flushed.
789 void OnFlush();
791 static constexpr IOUtils::PhaseArray<const char16_t*> PHASE_NAMES{
792 u"profile-before-change",
793 u"profile-before-change-telemetry",
794 u"xpcom-will-shutdown",
797 // The last shutdown phase before we should shut down the event loop.
798 static constexpr auto LAST_IO_PHASE = IOUtils::ShutdownPhase::SendTelemetry;
800 IOUtils::ShutdownPhase mPhase;
801 nsCOMPtr<nsIAsyncShutdownClient> mParentClient;
805 * A buffer that is allocated inside one of JS heaps so that it can be converted
806 * to a JSString or Uint8Array object with at most one copy in the worst case.
808 class IOUtils::JsBuffer final {
809 public:
811 * Create a new buffer of the given kind with the requested capacity.
813 * @param aBufferKind The kind of buffer to create (either a string or an
814 * array).
815 * @param aCapacity The capacity of the buffer.
817 * @return Either a successfully created buffer or an error if it could not be
818 * allocated.
820 static Result<JsBuffer, IOUtils::IOError> Create(
821 IOUtils::BufferKind aBufferKind, size_t aCapacity);
824 * Create a new, empty buffer.
826 * This operation cannot fail.
828 * @param aBufferKind The kind of buffer to create (either a string or an
829 * array).
831 * @return An empty JsBuffer.
833 static JsBuffer CreateEmpty(IOUtils::BufferKind aBufferKind);
835 JsBuffer(const JsBuffer&) = delete;
836 JsBuffer(JsBuffer&& aOther) noexcept;
837 JsBuffer& operator=(const JsBuffer&) = delete;
838 JsBuffer& operator=(JsBuffer&& aOther) noexcept;
840 size_t Length() { return mLength; }
841 char* Elements() { return mBuffer.get(); }
842 void SetLength(size_t aNewLength) {
843 MOZ_RELEASE_ASSERT(aNewLength <= mCapacity);
844 mLength = aNewLength;
848 * Return a span for writing to the buffer.
850 * |SetLength| should be called after the buffer has been written to.
852 * @returns A span for writing to. The size of the span is the entire
853 * allocated capacity.
855 Span<char> BeginWriting() {
856 MOZ_RELEASE_ASSERT(mBuffer.get());
857 return Span(mBuffer.get(), mCapacity);
861 * Return a span for reading from.
863 * @returns A span for reading form. The size of the span is the set length
864 * of the buffer.
866 Span<const char> BeginReading() const {
867 MOZ_RELEASE_ASSERT(mBuffer.get() || mLength == 0);
868 return Span(mBuffer.get(), mLength);
872 * Consume the JsBuffer and convert it into a JSString.
874 * NOTE: This method asserts the buffer was allocated as a string buffer.
876 * @param aBuffer The buffer to convert to a string. After this call, the
877 * buffer will be invaldated and |IntoString| cannot be called
878 * again.
880 * @returns A JSString with the contents of |aBuffer|.
882 static JSString* IntoString(JSContext* aCx, JsBuffer aBuffer);
885 * Consume the JsBuffer and convert it into a Uint8Array.
887 * NOTE: This method asserts the buffer was allocated as an array buffer.
889 * @param aBuffer The buffer to convert to an array. After this call, the
890 * buffer will be invalidated and |IntoUint8Array| cannot be
891 * called again.
893 * @returns A JSBuffer
895 static JSObject* IntoUint8Array(JSContext* aCx, JsBuffer aBuffer);
897 friend bool ToJSValue(JSContext* aCx, JsBuffer&& aBuffer,
898 JS::MutableHandle<JS::Value> aValue);
900 private:
901 IOUtils::BufferKind mBufferKind;
902 size_t mCapacity;
903 size_t mLength;
904 JS::UniqueChars mBuffer;
906 JsBuffer(BufferKind aBufferKind, size_t aCapacity);
909 class SyncReadFile : public nsISupports, public nsWrapperCache {
910 public:
911 SyncReadFile(nsISupports* aParent, RefPtr<nsFileRandomAccessStream>&& aStream,
912 int64_t aSize);
914 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
915 NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(SyncReadFile)
917 nsISupports* GetParentObject() const { return mParent; }
919 virtual JSObject* WrapObject(JSContext* aCx,
920 JS::Handle<JSObject*> aGivenProto) override;
922 int64_t Size() const { return mSize; }
923 void ReadBytesInto(const Uint8Array&, const int64_t, ErrorResult& aRv);
924 void Close();
926 private:
927 virtual ~SyncReadFile();
929 nsCOMPtr<nsISupports> mParent;
930 RefPtr<nsFileRandomAccessStream> mStream;
931 int64_t mSize = 0;
934 } // namespace dom
935 } // namespace mozilla
937 #endif