1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et 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 #include "RemoteOpenFileChild.h"
9 #include "mozilla/unused.h"
10 #include "mozilla/ipc/FileDescriptor.h"
11 #include "mozilla/ipc/FileDescriptorUtils.h"
12 #include "mozilla/ipc/URIUtils.h"
13 #include "mozilla/net/NeckoChild.h"
14 #include "nsThreadUtils.h"
15 #include "nsJARProtocolHandler.h"
16 #include "nsIRemoteOpenFileListener.h"
17 #include "nsProxyRelease.h"
18 #include "SerializedLoadContext.h"
20 // needed to alloc/free NSPR file descriptors
21 #include "private/pprio.h"
23 #if !defined(XP_WIN) && !defined(MOZ_WIDGET_COCOA)
27 using namespace mozilla::ipc
;
32 //-----------------------------------------------------------------------------
33 // Helper class to dispatch events async on windows/OSX
34 //-----------------------------------------------------------------------------
36 class CallsListenerInNewEvent
: public nsRunnable
39 CallsListenerInNewEvent(nsIRemoteOpenFileListener
*aListener
, nsresult aRv
)
40 : mListener(aListener
), mRV(aRv
)
42 MOZ_ASSERT(NS_IsMainThread());
43 MOZ_ASSERT(aListener
);
48 MOZ_ASSERT(NS_IsMainThread());
50 nsresult rv
= NS_DispatchToCurrentThread(this);
51 NS_ENSURE_SUCCESS_VOID(rv
);
57 MOZ_ASSERT(NS_IsMainThread());
58 MOZ_ASSERT(mListener
);
60 mListener
->OnRemoteFileOpenComplete(mRV
);
64 nsCOMPtr
<nsIRemoteOpenFileListener
> mListener
;
68 //-----------------------------------------------------------------------------
69 // RemoteOpenFileChild
70 //-----------------------------------------------------------------------------
72 NS_IMPL_ISUPPORTS(RemoteOpenFileChild
,
75 nsICachedFileDescriptorListener
)
77 RemoteOpenFileChild::RemoteOpenFileChild(const RemoteOpenFileChild
& other
)
78 : mTabChild(other
.mTabChild
)
79 , mNSPRFileDesc(nullptr)
80 , mAsyncOpenCalled(other
.mAsyncOpenCalled
)
82 #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
83 // Windows/OSX desktop builds skip remoting, so the file descriptor should
85 MOZ_ASSERT(!other
.mNSPRFileDesc
);
87 if (other
.mNSPRFileDesc
) {
88 PROsfd osfd
= dup(PR_FileDesc2NativeHandle(other
.mNSPRFileDesc
));
89 mNSPRFileDesc
= PR_ImportFile(osfd
);
93 // Note: don't clone mListener or we'll have a refcount leak.
94 other
.mURI
->Clone(getter_AddRefs(mURI
));
96 other
.mAppURI
->Clone(getter_AddRefs(mAppURI
));
98 other
.mFile
->Clone(getter_AddRefs(mFile
));
101 RemoteOpenFileChild::~RemoteOpenFileChild()
103 if (NS_IsMainThread()) {
105 NotifyListener(NS_ERROR_UNEXPECTED
);
108 nsCOMPtr
<nsIThread
> mainThread
= do_GetMainThread();
110 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ProxyRelease(mainThread
, mURI
, true)));
111 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ProxyRelease(mainThread
, mAppURI
, true)));
112 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_ProxyRelease(mainThread
, mListener
,
116 mTabChild
.forget(&tabChild
);
119 nsCOMPtr
<nsIRunnable
> runnable
=
120 NS_NewNonOwningRunnableMethod(tabChild
, &TabChild::Release
);
121 MOZ_ASSERT(runnable
);
123 MOZ_ALWAYS_TRUE(NS_SUCCEEDED(mainThread
->Dispatch(runnable
,
124 NS_DISPATCH_NORMAL
)));
127 using mozilla::unused
;
129 NS_WARNING("RemoteOpenFileChild released after thread shutdown, leaking "
132 unused
<< mURI
.forget();
133 unused
<< mAppURI
.forget();
134 unused
<< mListener
.forget();
135 unused
<< mTabChild
.forget();
140 // PR_Close both closes the file and deallocates the PRFileDesc
141 PR_Close(mNSPRFileDesc
);
146 RemoteOpenFileChild::Init(nsIURI
* aRemoteOpenUri
, nsIURI
* aAppUri
)
148 if (!aRemoteOpenUri
) {
149 return NS_ERROR_INVALID_ARG
;
153 aAppUri
->Clone(getter_AddRefs(mAppURI
));
156 nsAutoCString scheme
;
157 nsresult rv
= aRemoteOpenUri
->GetScheme(scheme
);
158 NS_ENSURE_SUCCESS(rv
, rv
);
160 if (!scheme
.EqualsLiteral("remoteopenfile")) {
161 return NS_ERROR_INVALID_ARG
;
164 // scheme of URI is not file:// so this is not a nsIFileURL. Convert to one.
165 nsCOMPtr
<nsIURI
> clonedURI
;
166 rv
= aRemoteOpenUri
->Clone(getter_AddRefs(clonedURI
));
167 NS_ENSURE_SUCCESS(rv
, rv
);
169 clonedURI
->SetScheme(NS_LITERAL_CSTRING("file"));
171 clonedURI
->GetSpec(spec
);
173 rv
= NS_NewURI(getter_AddRefs(mURI
), spec
);
174 NS_ENSURE_SUCCESS(rv
, rv
);
177 nsCOMPtr
<nsIFileURL
> fileURL
= do_QueryInterface(mURI
);
179 return NS_ERROR_UNEXPECTED
;
182 rv
= fileURL
->GetFile(getter_AddRefs(mFile
));
183 NS_ENSURE_SUCCESS(rv
, rv
);
189 RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags
,
190 nsIRemoteOpenFileListener
* aListener
,
191 nsITabChild
* aTabChild
,
192 nsILoadContext
*aLoadContext
)
195 return NS_ERROR_NOT_INITIALIZED
;
199 return NS_ERROR_INVALID_ARG
;
202 if (mAsyncOpenCalled
) {
203 return NS_ERROR_ALREADY_OPENED
;
206 if (aFlags
!= PR_RDONLY
) {
207 return NS_ERROR_NOT_AVAILABLE
;
210 mTabChild
= static_cast<TabChild
*>(aTabChild
);
212 if (MissingRequiredTabChild(mTabChild
, "remoteopenfile")) {
213 return NS_ERROR_ILLEGAL_VALUE
;
216 #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
217 // Windows/OSX desktop builds skip remoting, and just open file in child
218 // process when asked for NSPR handle
219 nsRefPtr
<CallsListenerInNewEvent
> runnable
=
220 new CallsListenerInNewEvent(aListener
, NS_OK
);
221 runnable
->Dispatch();
223 mAsyncOpenCalled
= true;
227 if (NS_FAILED(mFile
->GetPath(path
))) {
228 MOZ_CRASH("Couldn't get path from file!");
232 if (mTabChild
->GetCachedFileDescriptor(path
, this)) {
233 // The file descriptor was found in the cache and OnCachedFileDescriptor()
234 // will be called with it.
240 SerializeURI(mURI
, uri
);
241 OptionalURIParams appUri
;
242 SerializeURI(mAppURI
, appUri
);
244 IPC::SerializedLoadContext
loadContext(aLoadContext
);
245 gNeckoChild
->SendPRemoteOpenFileConstructor(this, loadContext
, uri
, appUri
);
247 // The chrome process now has a logical ref to us until it calls Send__delete.
250 mListener
= aListener
;
251 mAsyncOpenCalled
= true;
257 RemoteOpenFileChild::SetNSPRFileDesc(PRFileDesc
* aNSPRFileDesc
)
259 MOZ_ASSERT(!mNSPRFileDesc
);
261 return NS_ERROR_ALREADY_OPENED
;
264 mNSPRFileDesc
= aNSPRFileDesc
;
269 RemoteOpenFileChild::OnCachedFileDescriptor(const nsAString
& aPath
,
270 const FileDescriptor
& aFD
)
273 if (!aPath
.IsEmpty()) {
277 MOZ_ASSERT(NS_SUCCEEDED(mFile
->GetPath(path
)));
278 MOZ_ASSERT(path
== aPath
, "Paths don't match!");
282 HandleFileDescriptorAndNotifyListener(aFD
, /* aFromRecvDelete */ false);
286 RemoteOpenFileChild::HandleFileDescriptorAndNotifyListener(
287 const FileDescriptor
& aFD
,
288 bool aFromRecvDelete
)
290 #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
291 MOZ_CRASH("OS X and Windows shouldn't be doing IPDL here");
294 // We already notified our listener (either in response to a cached file
295 // descriptor callback or through the normal messaging mechanism). Close the
296 // file descriptor if it is valid.
298 nsRefPtr
<CloseFileRunnable
> runnable
= new CloseFileRunnable(aFD
);
299 runnable
->Dispatch();
304 MOZ_ASSERT(!mNSPRFileDesc
);
306 nsRefPtr
<TabChild
> tabChild
;
307 mTabChild
.swap(tabChild
);
309 // If RemoteOpenFile reply (Recv__delete__) for app's application.zip comes
310 // back sooner than the parent-pushed fd (TabChild::RecvCacheFileDescriptor())
311 // have TabChild cancel running callbacks, since we'll call them in
313 if (tabChild
&& aFromRecvDelete
) {
315 if (NS_FAILED(mFile
->GetPath(path
))) {
316 MOZ_CRASH("Couldn't get path from file!");
319 tabChild
->CancelCachedFileDescriptorCallback(path
, this);
323 mNSPRFileDesc
= PR_ImportFile(aFD
.PlatformHandle());
324 if (!mNSPRFileDesc
) {
325 NS_WARNING("Failed to import file handle!");
329 NotifyListener(mNSPRFileDesc
? NS_OK
: NS_ERROR_FILE_NOT_FOUND
);
334 RemoteOpenFileChild::NotifyListener(nsresult aResult
)
336 MOZ_ASSERT(mListener
);
337 mListener
->OnRemoteFileOpenComplete(aResult
);
338 mListener
= nullptr; // release ref to listener
340 nsRefPtr
<nsJARProtocolHandler
> handler(gJarHandler
);
341 NS_WARN_IF_FALSE(handler
, "nsJARProtocolHandler is already gone!");
344 handler
->RemoteOpenFileComplete(this, aResult
);
348 //-----------------------------------------------------------------------------
349 // RemoteOpenFileChild::PRemoteOpenFileChild
350 //-----------------------------------------------------------------------------
353 RemoteOpenFileChild::Recv__delete__(const FileDescriptor
& aFD
)
355 #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
356 NS_NOTREACHED("OS X and Windows shouldn't be doing IPDL here");
358 HandleFileDescriptorAndNotifyListener(aFD
, /* aFromRecvDelete */ true);
364 //-----------------------------------------------------------------------------
365 // RemoteOpenFileChild::nsIFile functions that we override logic for
366 //-----------------------------------------------------------------------------
369 RemoteOpenFileChild::Clone(nsIFile
**file
)
371 *file
= new RemoteOpenFileChild(*this);
377 /* The main event: get file descriptor from parent process
380 RemoteOpenFileChild::OpenNSPRFileDesc(int32_t aFlags
, int32_t aMode
,
381 PRFileDesc
**aRetval
)
383 #if defined(XP_WIN) || defined(MOZ_WIDGET_COCOA)
384 // Windows and OSX builds: just open nsIFile locally.
385 return mFile
->OpenNSPRFileDesc(aFlags
, aMode
, aRetval
);
388 if (aFlags
!= PR_RDONLY
) {
389 return NS_ERROR_NOT_AVAILABLE
;
392 if (!mNSPRFileDesc
) {
393 // Client skipped AsyncRemoteFileOpen() or didn't wait for result.
394 return NS_ERROR_NOT_AVAILABLE
;
397 PROsfd osfd
= dup(PR_FileDesc2NativeHandle(mNSPRFileDesc
));
398 *aRetval
= PR_ImportFile(osfd
);
405 //-----------------------------------------------------------------------------
406 // RemoteOpenFileChild::nsIFile functions that we delegate to underlying nsIFile
407 //-----------------------------------------------------------------------------
410 RemoteOpenFileChild::GetLeafName(nsAString
&aLeafName
)
412 return mFile
->GetLeafName(aLeafName
);
416 RemoteOpenFileChild::GetNativeLeafName(nsACString
&aLeafName
)
418 return mFile
->GetNativeLeafName(aLeafName
);
422 RemoteOpenFileChild::GetTarget(nsAString
&_retval
)
424 return mFile
->GetTarget(_retval
);
428 RemoteOpenFileChild::GetNativeTarget(nsACString
&_retval
)
430 return mFile
->GetNativeTarget(_retval
);
434 RemoteOpenFileChild::GetPath(nsAString
&_retval
)
436 return mFile
->GetPath(_retval
);
440 RemoteOpenFileChild::GetNativePath(nsACString
&_retval
)
442 return mFile
->GetNativePath(_retval
);
446 RemoteOpenFileChild::Equals(nsIFile
*inFile
, bool *_retval
)
448 return mFile
->Equals(inFile
, _retval
);
452 RemoteOpenFileChild::Contains(nsIFile
*inFile
, bool *_retval
)
454 return mFile
->Contains(inFile
, _retval
);
458 RemoteOpenFileChild::GetParent(nsIFile
**aParent
)
460 return mFile
->GetParent(aParent
);
464 RemoteOpenFileChild::GetFollowLinks(bool *aFollowLinks
)
466 return mFile
->GetFollowLinks(aFollowLinks
);
469 //-----------------------------------------------------------------------------
470 // RemoteOpenFileChild::nsIFile functions that are not currently supported
471 //-----------------------------------------------------------------------------
474 RemoteOpenFileChild::Append(const nsAString
&node
)
476 return NS_ERROR_NOT_IMPLEMENTED
;
480 RemoteOpenFileChild::AppendNative(const nsACString
&fragment
)
482 return NS_ERROR_NOT_IMPLEMENTED
;
486 RemoteOpenFileChild::Normalize()
488 return NS_ERROR_NOT_IMPLEMENTED
;
492 RemoteOpenFileChild::Create(uint32_t type
, uint32_t permissions
)
494 return NS_ERROR_NOT_IMPLEMENTED
;
498 RemoteOpenFileChild::SetLeafName(const nsAString
&aLeafName
)
500 return NS_ERROR_NOT_IMPLEMENTED
;
504 RemoteOpenFileChild::SetNativeLeafName(const nsACString
&aLeafName
)
506 return NS_ERROR_NOT_IMPLEMENTED
;
510 RemoteOpenFileChild::InitWithPath(const nsAString
&filePath
)
512 return NS_ERROR_NOT_IMPLEMENTED
;
516 RemoteOpenFileChild::InitWithNativePath(const nsACString
&filePath
)
518 return NS_ERROR_NOT_IMPLEMENTED
;
522 RemoteOpenFileChild::InitWithFile(nsIFile
*aFile
)
524 return NS_ERROR_NOT_IMPLEMENTED
;
528 RemoteOpenFileChild::SetFollowLinks(bool aFollowLinks
)
530 return NS_ERROR_NOT_IMPLEMENTED
;
534 RemoteOpenFileChild::AppendRelativePath(const nsAString
&node
)
536 return NS_ERROR_NOT_IMPLEMENTED
;
540 RemoteOpenFileChild::AppendRelativeNativePath(const nsACString
&fragment
)
542 return NS_ERROR_NOT_IMPLEMENTED
;
546 RemoteOpenFileChild::GetPersistentDescriptor(nsACString
&aPersistentDescriptor
)
548 return NS_ERROR_NOT_IMPLEMENTED
;
552 RemoteOpenFileChild::SetPersistentDescriptor(const nsACString
&aPersistentDescriptor
)
554 return NS_ERROR_NOT_IMPLEMENTED
;
558 RemoteOpenFileChild::GetRelativeDescriptor(nsIFile
*fromFile
, nsACString
& _retval
)
560 return NS_ERROR_NOT_IMPLEMENTED
;
564 RemoteOpenFileChild::SetRelativeDescriptor(nsIFile
*fromFile
,
565 const nsACString
& relativeDesc
)
567 return NS_ERROR_NOT_IMPLEMENTED
;
571 RemoteOpenFileChild::CopyTo(nsIFile
*newParentDir
, const nsAString
&newName
)
573 return NS_ERROR_NOT_IMPLEMENTED
;
577 RemoteOpenFileChild::CopyToNative(nsIFile
*newParent
, const nsACString
&newName
)
579 return NS_ERROR_NOT_IMPLEMENTED
;
583 RemoteOpenFileChild::CopyToFollowingLinks(nsIFile
*newParentDir
,
584 const nsAString
&newName
)
586 return NS_ERROR_NOT_IMPLEMENTED
;
590 RemoteOpenFileChild::CopyToFollowingLinksNative(nsIFile
*newParent
,
591 const nsACString
&newName
)
593 return NS_ERROR_NOT_IMPLEMENTED
;
597 RemoteOpenFileChild::MoveTo(nsIFile
*newParentDir
, const nsAString
&newName
)
599 return NS_ERROR_NOT_IMPLEMENTED
;
603 RemoteOpenFileChild::MoveToNative(nsIFile
*newParent
, const nsACString
&newName
)
605 return NS_ERROR_NOT_IMPLEMENTED
;
609 RemoteOpenFileChild::RenameTo(nsIFile
*newParentDir
, const nsAString
&newName
)
611 return NS_ERROR_NOT_IMPLEMENTED
;
615 RemoteOpenFileChild::Remove(bool recursive
)
617 return NS_ERROR_NOT_IMPLEMENTED
;
621 RemoteOpenFileChild::GetPermissions(uint32_t *aPermissions
)
623 return NS_ERROR_NOT_IMPLEMENTED
;
627 RemoteOpenFileChild::SetPermissions(uint32_t aPermissions
)
629 return NS_ERROR_NOT_IMPLEMENTED
;
633 RemoteOpenFileChild::GetPermissionsOfLink(uint32_t *aPermissionsOfLink
)
635 return NS_ERROR_NOT_IMPLEMENTED
;
639 RemoteOpenFileChild::SetPermissionsOfLink(uint32_t aPermissions
)
641 return NS_ERROR_NOT_IMPLEMENTED
;
645 RemoteOpenFileChild::GetLastModifiedTime(PRTime
*aLastModTime
)
647 return NS_ERROR_NOT_IMPLEMENTED
;
651 RemoteOpenFileChild::SetLastModifiedTime(PRTime aLastModTime
)
653 return NS_ERROR_NOT_IMPLEMENTED
;
657 RemoteOpenFileChild::GetLastModifiedTimeOfLink(PRTime
*aLastModTimeOfLink
)
659 return NS_ERROR_NOT_IMPLEMENTED
;
663 RemoteOpenFileChild::SetLastModifiedTimeOfLink(PRTime aLastModTimeOfLink
)
665 return NS_ERROR_NOT_IMPLEMENTED
;
669 RemoteOpenFileChild::GetFileSize(int64_t *aFileSize
)
671 return NS_ERROR_NOT_IMPLEMENTED
;
675 RemoteOpenFileChild::SetFileSize(int64_t aFileSize
)
677 return NS_ERROR_NOT_IMPLEMENTED
;
681 RemoteOpenFileChild::GetFileSizeOfLink(int64_t *aFileSize
)
683 return NS_ERROR_NOT_IMPLEMENTED
;
687 RemoteOpenFileChild::Exists(bool *_retval
)
689 return NS_ERROR_NOT_IMPLEMENTED
;
693 RemoteOpenFileChild::IsWritable(bool *_retval
)
695 return NS_ERROR_NOT_IMPLEMENTED
;
699 RemoteOpenFileChild::IsReadable(bool *_retval
)
701 return NS_ERROR_NOT_IMPLEMENTED
;
705 RemoteOpenFileChild::IsExecutable(bool *_retval
)
707 return NS_ERROR_NOT_IMPLEMENTED
;
711 RemoteOpenFileChild::IsHidden(bool *_retval
)
713 return NS_ERROR_NOT_IMPLEMENTED
;
717 RemoteOpenFileChild::IsDirectory(bool *_retval
)
719 return NS_ERROR_NOT_IMPLEMENTED
;
723 RemoteOpenFileChild::IsFile(bool *_retval
)
725 return NS_ERROR_NOT_IMPLEMENTED
;
729 RemoteOpenFileChild::IsSymlink(bool *_retval
)
731 return NS_ERROR_NOT_IMPLEMENTED
;
735 RemoteOpenFileChild::IsSpecial(bool *_retval
)
737 return NS_ERROR_NOT_IMPLEMENTED
;
741 RemoteOpenFileChild::CreateUnique(uint32_t type
, uint32_t attributes
)
743 return NS_ERROR_NOT_IMPLEMENTED
;
747 RemoteOpenFileChild::GetDirectoryEntries(nsISimpleEnumerator
**entries
)
749 return NS_ERROR_NOT_IMPLEMENTED
;
753 RemoteOpenFileChild::OpenANSIFileDesc(const char *mode
, FILE **_retval
)
755 // TODO: can implement using fdopen()?
756 return NS_ERROR_NOT_IMPLEMENTED
;
760 RemoteOpenFileChild::Load(PRLibrary
**_retval
)
762 return NS_ERROR_NOT_IMPLEMENTED
;
766 RemoteOpenFileChild::GetDiskSpaceAvailable(int64_t *aDiskSpaceAvailable
)
768 return NS_ERROR_NOT_IMPLEMENTED
;
772 RemoteOpenFileChild::Reveal()
774 return NS_ERROR_NOT_IMPLEMENTED
;
778 RemoteOpenFileChild::Launch()
780 return NS_ERROR_NOT_IMPLEMENTED
;
783 //-----------------------------------------------------------------------------
784 // RemoteOpenFileChild::nsIHashable functions that we delegate to underlying nsIFile
785 //-----------------------------------------------------------------------------
788 RemoteOpenFileChild::Equals(nsIHashable
* aOther
, bool *aResult
)
790 nsCOMPtr
<nsIHashable
> hashable
= do_QueryInterface(mFile
);
792 MOZ_ASSERT(hashable
);
795 return hashable
->Equals(aOther
, aResult
);
797 return NS_ERROR_UNEXPECTED
;
801 RemoteOpenFileChild::GetHashCode(uint32_t *aResult
)
803 nsCOMPtr
<nsIHashable
> hashable
= do_QueryInterface(mFile
);
805 MOZ_ASSERT(hashable
);
808 return hashable
->GetHashCode(aResult
);
810 return NS_ERROR_UNEXPECTED
;
814 } // namespace mozilla