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/. */
6 
7 #include "FileCreatorParent.h"
8 #include "mozilla/dom/FileBlobImpl.h"
9 #include "mozilla/dom/IPCBlobUtils.h"
10 #include "mozilla/dom/MultipartBlobImpl.h"
11 #include "nsIFile.h"
12 
13 namespace mozilla::dom {
14 
FileCreatorParent()15 FileCreatorParent::FileCreatorParent()
16     : mBackgroundEventTarget(GetCurrentEventTarget()), mIPCActive(true) {}
17 
18 FileCreatorParent::~FileCreatorParent() = default;
19 
CreateAndShareFile(const nsString & aFullPath,const nsString & aType,const nsString & aName,const Maybe<int64_t> & aLastModified,const bool & aExistenceCheck,const bool & aIsFromNsIFile)20 mozilla::ipc::IPCResult FileCreatorParent::CreateAndShareFile(
21     const nsString& aFullPath, const nsString& aType, const nsString& aName,
22     const Maybe<int64_t>& aLastModified, const bool& aExistenceCheck,
23     const bool& aIsFromNsIFile) {
24   RefPtr<dom::BlobImpl> blobImpl;
25   nsresult rv =
26       CreateBlobImpl(aFullPath, aType, aName, aLastModified.isSome(),
27                      aLastModified.isSome() ? aLastModified.value() : 0,
28                      aExistenceCheck, aIsFromNsIFile, getter_AddRefs(blobImpl));
29   if (NS_WARN_IF(NS_FAILED(rv))) {
30     Unused << Send__delete__(this, FileCreationErrorResult(rv));
31     return IPC_OK();
32   }
33 
34   MOZ_ASSERT(blobImpl);
35 
36   // FileBlobImpl is unable to return the correct type on this thread because
37   // nsIMIMEService is not thread-safe. We must exec the 'type' getter on
38   // main-thread before send the blob to the child actor.
39 
40   RefPtr<FileCreatorParent> self = this;
41   NS_DispatchToMainThread(NS_NewRunnableFunction(
42       "FileCreatorParent::CreateAndShareFile", [self, blobImpl]() {
43         nsAutoString type;
44         blobImpl->GetType(type);
45 
46         self->mBackgroundEventTarget->Dispatch(NS_NewRunnableFunction(
47             "FileCreatorParent::CreateAndShareFile return", [self, blobImpl]() {
48               if (self->mIPCActive) {
49                 IPCBlob ipcBlob;
50                 nsresult rv = dom::IPCBlobUtils::Serialize(
51                     blobImpl, self->Manager(), ipcBlob);
52                 if (NS_WARN_IF(NS_FAILED(rv))) {
53                   Unused << Send__delete__(self, FileCreationErrorResult(rv));
54                   return;
55                 }
56 
57                 Unused << Send__delete__(self,
58                                          FileCreationSuccessResult(ipcBlob));
59               }
60             }));
61       }));
62 
63   return IPC_OK();
64 }
65 
ActorDestroy(ActorDestroyReason aWhy)66 void FileCreatorParent::ActorDestroy(ActorDestroyReason aWhy) {
67   mIPCActive = false;
68 }
69 
70 /* static */
CreateBlobImpl(const nsAString & aPath,const nsAString & aType,const nsAString & aName,bool aLastModifiedPassed,int64_t aLastModified,bool aExistenceCheck,bool aIsFromNsIFile,BlobImpl ** aBlobImpl)71 nsresult FileCreatorParent::CreateBlobImpl(
72     const nsAString& aPath, const nsAString& aType, const nsAString& aName,
73     bool aLastModifiedPassed, int64_t aLastModified, bool aExistenceCheck,
74     bool aIsFromNsIFile, BlobImpl** aBlobImpl) {
75   MOZ_ASSERT(!NS_IsMainThread());
76 
77   nsCOMPtr<nsIFile> file;
78   nsresult rv = NS_NewLocalFile(aPath, true, getter_AddRefs(file));
79   if (NS_WARN_IF(NS_FAILED(rv))) {
80     return rv;
81   }
82 
83   bool exists;
84   rv = file->Exists(&exists);
85   if (NS_WARN_IF(NS_FAILED(rv))) {
86     return rv;
87   }
88 
89   if (aExistenceCheck) {
90     if (!exists) {
91       return NS_ERROR_FILE_NOT_FOUND;
92     }
93 
94     bool isDir;
95     rv = file->IsDirectory(&isDir);
96     if (NS_WARN_IF(NS_FAILED(rv))) {
97       return rv;
98     }
99 
100     if (isDir) {
101       return NS_ERROR_FILE_IS_DIRECTORY;
102     }
103   }
104 
105   RefPtr<FileBlobImpl> impl = new FileBlobImpl(file);
106 
107   // If the file doesn't exist, we cannot have its path, its size and so on.
108   // Let's set them now.
109   if (!exists) {
110     MOZ_ASSERT(!aExistenceCheck);
111 
112     impl->SetMozFullPath(aPath);
113     impl->SetLastModified(0);
114     impl->SetEmptySize();
115   }
116 
117   if (!aName.IsEmpty()) {
118     impl->SetName(aName);
119   }
120 
121   if (!aType.IsEmpty()) {
122     impl->SetType(aType);
123   }
124 
125   if (aLastModifiedPassed) {
126     impl->SetLastModified(aLastModified);
127   }
128 
129   if (!aIsFromNsIFile) {
130     impl->SetMozFullPath(u""_ns);
131   }
132 
133   impl.forget(aBlobImpl);
134   return NS_OK;
135 }
136 
137 }  // namespace mozilla::dom
138