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_PathUtils__
8 #define mozilla_dom_PathUtils__
10 #include "mozilla/DataMutex.h"
11 #include "mozilla/EnumeratedArray.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/MozPromise.h"
14 #include "mozilla/Mutex.h"
15 #include "mozilla/Result.h"
16 #include "mozilla/dom/PathUtilsBinding.h"
17 #include "mozilla/dom/Promise.h"
18 #include "nsAppDirectoryServiceDefs.h"
19 #include "nsDirectoryServiceDefs.h"
28 class PathUtils final
{
31 * Initialize the given nsIFile with the given path.
33 * This is equivalent to calling nsIFile::InitWithPath() with the caveat that
34 * on Windows debug or during Windows CI tests, we will crash if the path
35 * contains a forward slash.
37 * @param aFile The file to initialize.
38 * @param aPath The path to initialize the file with.
40 * @return The result of calling nsIFile::InitWithPath.
42 static nsresult
InitFileWithPath(nsIFile
* aFile
, const nsAString
& aPath
);
44 static void Filename(const GlobalObject
&, const nsAString
& aPath
,
45 nsString
& aResult
, ErrorResult
& aErr
);
47 static void Parent(const GlobalObject
&, const nsAString
& aPath
,
48 const int32_t aDepth
, nsString
& aResult
,
51 static void Join(const GlobalObject
&, const Sequence
<nsString
>& aComponents
,
52 nsString
& aResult
, ErrorResult
& aErr
);
55 * Join a sequence of path components and return an nsIFile with the resulting
58 * @param aComponents A sequence of path components. The first component must
59 * be an absolute path.
60 * @param aErr The error result, if any.
62 * @return An nsIFile with the resulting path, if there were no errors.
63 * Otherwise, nullptr is returned.
65 static already_AddRefed
<nsIFile
> Join(const Span
<const nsString
>& aComponents
,
68 static void JoinRelative(const GlobalObject
&, const nsAString
& aBasePath
,
69 const nsAString
& aRelativePath
, nsString
& aResult
,
72 static void ToExtendedWindowsPath(const GlobalObject
&, const nsAString
& aPath
,
73 nsString
& aResult
, ErrorResult
& aErr
);
75 static void Normalize(const GlobalObject
&, const nsAString
& aPath
,
76 nsString
& aResult
, ErrorResult
& aErr
);
78 static void Split(const GlobalObject
&, const nsAString
& aPath
,
79 nsTArray
<nsString
>& aResult
, ErrorResult
& aErr
);
81 static void SplitRelative(const GlobalObject
& aGlobal
, const nsAString
& aPath
,
82 const SplitRelativeOptions
& aOptions
,
83 nsTArray
<nsString
>& aResult
, ErrorResult
& aErr
);
85 static void ToFileURI(const GlobalObject
&, const nsAString
& aPath
,
86 nsCString
& aResult
, ErrorResult
& aErr
);
88 static bool IsAbsolute(const GlobalObject
&, const nsAString
& aPath
);
90 static void GetProfileDirSync(const GlobalObject
&, nsString
& aResult
,
92 static void GetLocalProfileDirSync(const GlobalObject
&, nsString
& aResult
,
94 static void GetTempDirSync(const GlobalObject
&, nsString
& aResult
,
96 static void GetXulLibraryPathSync(const GlobalObject
&, nsString
& aResult
,
99 static already_AddRefed
<Promise
> GetProfileDirAsync(
100 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
101 static already_AddRefed
<Promise
> GetLocalProfileDirAsync(
102 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
103 static already_AddRefed
<Promise
> GetTempDirAsync(const GlobalObject
& aGlobal
,
105 static already_AddRefed
<Promise
> GetXulLibraryPathAsync(
106 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
109 class DirectoryCache
;
110 friend class DirectoryCache
;
112 static StaticDataMutex
<Maybe
<DirectoryCache
>> sDirCache
;
116 * A cache of commonly used directories
118 class PathUtils::DirectoryCache final
{
121 * A directory that can be requested via |GetDirectorySync| or
122 * |GetDirectoryAsync|.
124 enum class Directory
{
126 * The user's profile directory.
130 * The user's local profile directory.
134 * The OS temporary directory.
142 * The number of Directory entries.
148 DirectoryCache(const DirectoryCache
&) = delete;
149 DirectoryCache(DirectoryCache
&&) = delete;
150 DirectoryCache
& operator=(const DirectoryCache
&) = delete;
151 DirectoryCache
& operator=(DirectoryCache
&&) = delete;
154 * Ensure the cache is instantiated and schedule its destructor to run at
157 * If the cache is already instantiated, this is a no-op.
159 * @param aCache The cache to ensure is instantiated.
161 static DirectoryCache
& Ensure(Maybe
<DirectoryCache
>& aCache
);
163 void GetDirectorySync(nsString
& aResult
, ErrorResult
& aErr
,
164 const Directory aRequestedDir
);
167 * Request the path of a specific directory.
169 * If the directory has not been requested before, this may require a trip to
170 * the main thread to retrieve its path.
172 * @param aGlobalObject The JavaScript global.
173 * @param aErr The error result.
174 * @param aRequestedDir The directory for which the path is to be retrieved.
176 * @return A promise that resolves to the path of the requested directory.
178 already_AddRefed
<Promise
> GetDirectoryAsync(const GlobalObject
& aGlobalObject
,
180 const Directory aRequestedDir
);
183 using PopulateDirectoriesPromise
= MozPromise
<Ok
, nsresult
, false>;
186 * Populate the directory cache entry for the requested directory.
188 * @param aRequestedDir The directory cache entry that was requested via
191 * @return If the requested directory has not been populated, this returns a
192 * promise that resolves when the population is complete.
194 * If the requested directory has already been populated, it returns
197 already_AddRefed
<PopulateDirectoriesPromise
> PopulateDirectories(
198 const Directory aRequestedDir
);
201 * Initialize the requested directory cache entry.
203 * If |Directory::Temp| is requested, all cache entries will be populated.
204 * Otherwise, only the profile and local profile cache entries will be
205 * populated. The profile and local profile cache entries have no additional
206 * overhead for populating them, but the temp directory requires creating a
207 * directory on the main thread if it has not already happened.
209 * Must be called on the main thread.
211 * @param aRequestedDir The requested directory.
213 * @return The result of initializing directories.
215 nsresult
PopulateDirectoriesImpl(const Directory aRequestedDir
);
218 * Resolve the internal PopulateDirectoriesPromise corresponding to
219 * |aRequestedDir| with the given result.
221 * This will allow all pending queries for the requested directory to resolve
224 * @param aRv The return value from PopulateDirectoriesImpl.
225 * @param aRequestedDir The requested directory cache entry. This is used to
226 * determine which internal MozPromiseHolder we are
229 void ResolvePopulateDirectoriesPromise(nsresult aRv
,
230 const Directory aRequestedDir
);
233 * Resolve the given JS promise with the path of the requested directory
235 * Can only be called once the cache entry for the requested directory is
238 * @param aPromise The JS promise to resolve.
239 * @param aRequestedDir The requested directory cache entry.
241 void ResolveWithDirectory(Promise
* aPromise
, const Directory aRequestedDir
);
243 template <typename T
>
244 using DirectoryArray
= EnumeratedArray
<Directory
, Directory::Count
, T
>;
246 DirectoryArray
<nsString
> mDirectories
;
247 DirectoryArray
<MozPromiseHolder
<PopulateDirectoriesPromise
>> mPromises
;
249 static constexpr DirectoryArray
<const char*> kDirectoryNames
{
250 NS_APP_USER_PROFILE_50_DIR
,
251 NS_APP_USER_PROFILE_LOCAL_50_DIR
,
253 NS_XPCOM_LIBRARY_FILE
,
258 } // namespace mozilla