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