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 GetOSTempDirSync(const GlobalObject
&, nsString
& aResult
,
98 static void GetXulLibraryPathSync(const GlobalObject
&, nsString
& aResult
,
101 static already_AddRefed
<Promise
> GetProfileDirAsync(
102 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
103 static already_AddRefed
<Promise
> GetLocalProfileDirAsync(
104 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
105 static already_AddRefed
<Promise
> GetTempDirAsync(const GlobalObject
& aGlobal
,
107 static already_AddRefed
<Promise
> GetOSTempDirAsync(
108 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
109 static already_AddRefed
<Promise
> GetXulLibraryPathAsync(
110 const GlobalObject
& aGlobal
, ErrorResult
& aErr
);
113 class DirectoryCache
;
114 friend class DirectoryCache
;
116 static StaticDataMutex
<Maybe
<DirectoryCache
>> sDirCache
;
120 * A cache of commonly used directories
122 class PathUtils::DirectoryCache final
{
125 * A directory that can be requested via |GetDirectorySync| or
126 * |GetDirectoryAsync|.
128 enum class Directory
{
130 * The user's profile directory.
134 * The user's local profile directory.
138 * The temporary directory for the process.
142 * The OS temporary directory.
150 * The number of Directory entries.
156 DirectoryCache(const DirectoryCache
&) = delete;
157 DirectoryCache(DirectoryCache
&&) = delete;
158 DirectoryCache
& operator=(const DirectoryCache
&) = delete;
159 DirectoryCache
& operator=(DirectoryCache
&&) = delete;
162 * Ensure the cache is instantiated and schedule its destructor to run at
165 * If the cache is already instantiated, this is a no-op.
167 * @param aCache The cache to ensure is instantiated.
169 static DirectoryCache
& Ensure(Maybe
<DirectoryCache
>& aCache
);
171 void GetDirectorySync(nsString
& aResult
, ErrorResult
& aErr
,
172 const Directory aRequestedDir
);
175 * Request the path of a specific directory.
177 * If the directory has not been requested before, this may require a trip to
178 * the main thread to retrieve its path.
180 * @param aGlobalObject The JavaScript global.
181 * @param aErr The error result.
182 * @param aRequestedDir The directory for which the path is to be retrieved.
184 * @return A promise that resolves to the path of the requested directory.
186 already_AddRefed
<Promise
> GetDirectoryAsync(const GlobalObject
& aGlobalObject
,
188 const Directory aRequestedDir
);
191 using PopulateDirectoriesPromise
= MozPromise
<Ok
, nsresult
, false>;
194 * Populate the directory cache entry for the requested directory.
196 * @param aRequestedDir The directory cache entry that was requested via
199 * @return If the requested directory has not been populated, this returns a
200 * promise that resolves when the population is complete.
202 * If the requested directory has already been populated, it returns
205 already_AddRefed
<PopulateDirectoriesPromise
> PopulateDirectories(
206 const Directory aRequestedDir
);
209 * Initialize the requested directory cache entry.
211 * If |Directory::Temp| is requested, all cache entries will be populated.
212 * Otherwise, only the profile and local profile cache entries will be
213 * populated. The profile and local profile cache entries have no additional
214 * overhead for populating them, but the temp directory requires creating a
215 * directory on the main thread if it has not already happened.
217 * Must be called on the main thread.
219 * @param aRequestedDir The requested directory.
221 * @return The result of initializing directories.
223 nsresult
PopulateDirectoriesImpl(const Directory aRequestedDir
);
226 * Resolve the internal PopulateDirectoriesPromise corresponding to
227 * |aRequestedDir| with the given result.
229 * This will allow all pending queries for the requested directory to resolve
232 * @param aRv The return value from PopulateDirectoriesImpl.
233 * @param aRequestedDir The requested directory cache entry. This is used to
234 * determine which internal MozPromiseHolder we are
237 void ResolvePopulateDirectoriesPromise(nsresult aRv
,
238 const Directory aRequestedDir
);
241 * Resolve the given JS promise with the path of the requested directory
243 * Can only be called once the cache entry for the requested directory is
246 * @param aPromise The JS promise to resolve.
247 * @param aRequestedDir The requested directory cache entry.
249 void ResolveWithDirectory(Promise
* aPromise
, const Directory aRequestedDir
);
251 template <typename T
>
252 using DirectoryArray
= EnumeratedArray
<Directory
, Directory::Count
, T
>;
254 DirectoryArray
<nsString
> mDirectories
;
255 DirectoryArray
<MozPromiseHolder
<PopulateDirectoriesPromise
>> mPromises
;
257 static constexpr DirectoryArray
<const char*> kDirectoryNames
{
258 NS_APP_USER_PROFILE_50_DIR
, NS_APP_USER_PROFILE_LOCAL_50_DIR
,
259 NS_APP_CONTENT_PROCESS_TEMP_DIR
, NS_OS_TEMP_DIR
,
260 NS_XPCOM_LIBRARY_FILE
,
265 } // namespace mozilla