Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef nsFileStreams_h__
7 #define nsFileStreams_h__
9 #include "nsAutoPtr.h"
10 #include "nsIFileStreams.h"
11 #include "nsIFile.h"
12 #include "nsIInputStream.h"
13 #include "nsIOutputStream.h"
14 #include "nsISafeOutputStream.h"
15 #include "nsISeekableStream.h"
16 #include "nsILineInputStream.h"
17 #include "nsCOMPtr.h"
18 #include "nsIIPCSerializableInputStream.h"
19 #include "nsReadLine.h"
20 #include <algorithm>
23 ////////////////////////////////////////////////////////////////////////////////
25 class nsFileStreamBase : public nsISeekableStream,
26 public nsIFileMetadata
27 {
28 public:
29 NS_DECL_THREADSAFE_ISUPPORTS
30 NS_DECL_NSISEEKABLESTREAM
31 NS_DECL_NSIFILEMETADATA
33 nsFileStreamBase();
34 virtual ~nsFileStreamBase();
36 protected:
37 nsresult Close();
38 nsresult Available(uint64_t* _retval);
39 nsresult Read(char* aBuf, uint32_t aCount, uint32_t* _retval);
40 nsresult ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
41 uint32_t aCount, uint32_t* _retval);
42 nsresult IsNonBlocking(bool* _retval);
43 nsresult Flush();
44 nsresult Write(const char* aBuf, uint32_t aCount, uint32_t* _retval);
45 nsresult WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
46 uint32_t* _retval);
47 nsresult WriteSegments(nsReadSegmentFun aReader, void* aClosure,
48 uint32_t aCount, uint32_t* _retval);
50 PRFileDesc* mFD;
52 /**
53 * Flags describing our behavior. See the IDL file for possible values.
54 */
55 int32_t mBehaviorFlags;
57 /**
58 * Whether we have a pending open (see DEFER_OPEN in the IDL file).
59 */
60 bool mDeferredOpen;
62 struct OpenParams {
63 nsCOMPtr<nsIFile> localFile;
64 int32_t ioFlags;
65 int32_t perm;
66 };
68 /**
69 * Data we need to do an open.
70 */
71 OpenParams mOpenParams;
73 /**
74 * Prepares the data we need to open the file, and either does the open now
75 * by calling DoOpen(), or leaves it to be opened later by a call to
76 * DoPendingOpen().
77 */
78 nsresult MaybeOpen(nsIFile* aFile, int32_t aIoFlags, int32_t aPerm,
79 bool aDeferred);
81 /**
82 * Cleans up data prepared in MaybeOpen.
83 */
84 void CleanUpOpen();
86 /**
87 * Open the file. This is called either from MaybeOpen (during Init)
88 * or from DoPendingOpen (if DEFER_OPEN is used when initializing this
89 * stream). The default behavior of DoOpen is to open the file and save the
90 * file descriptor.
91 */
92 virtual nsresult DoOpen();
94 /**
95 * If there is a pending open, do it now. It's important for this to be
96 * inline since we do it in almost every stream API call.
97 */
98 inline nsresult DoPendingOpen();
99 };
101 ////////////////////////////////////////////////////////////////////////////////
103 class nsFileInputStream : public nsFileStreamBase,
104 public nsIFileInputStream,
105 public nsILineInputStream,
106 public nsIIPCSerializableInputStream
107 {
108 public:
109 NS_DECL_ISUPPORTS_INHERITED
110 NS_DECL_NSIFILEINPUTSTREAM
111 NS_DECL_NSILINEINPUTSTREAM
112 NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
114 NS_IMETHOD Close();
115 NS_IMETHOD Tell(int64_t *aResult);
116 NS_IMETHOD Available(uint64_t* _retval);
117 NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* _retval);
118 NS_IMETHOD ReadSegments(nsWriteSegmentFun aWriter, void *aClosure,
119 uint32_t aCount, uint32_t* _retval)
120 {
121 return nsFileStreamBase::ReadSegments(aWriter, aClosure, aCount,
122 _retval);
123 }
124 NS_IMETHOD IsNonBlocking(bool* _retval)
125 {
126 return nsFileStreamBase::IsNonBlocking(_retval);
127 }
129 // Overrided from nsFileStreamBase
130 NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset);
132 nsFileInputStream()
133 : mLineBuffer(nullptr), mIOFlags(0), mPerm(0), mCachedPosition(0)
134 {}
136 virtual ~nsFileInputStream()
137 {
138 Close();
139 }
141 static nsresult
142 Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
144 protected:
145 nsAutoPtr<nsLineBuffer<char> > mLineBuffer;
147 /**
148 * The file being opened.
149 */
150 nsCOMPtr<nsIFile> mFile;
151 /**
152 * The IO flags passed to Init() for the file open.
153 */
154 int32_t mIOFlags;
155 /**
156 * The permissions passed to Init() for the file open.
157 */
158 int32_t mPerm;
160 /**
161 * Cached position for Tell for automatically reopening streams.
162 */
163 int64_t mCachedPosition;
165 protected:
166 /**
167 * Internal, called to open a file. Parameters are the same as their
168 * Init() analogues.
169 */
170 nsresult Open(nsIFile* file, int32_t ioFlags, int32_t perm);
171 };
173 ////////////////////////////////////////////////////////////////////////////////
175 class nsPartialFileInputStream : public nsFileInputStream,
176 public nsIPartialFileInputStream
177 {
178 public:
179 using nsFileInputStream::Init;
180 using nsFileInputStream::Read;
181 NS_DECL_ISUPPORTS_INHERITED
182 NS_DECL_NSIPARTIALFILEINPUTSTREAM
183 NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
185 nsPartialFileInputStream()
186 : mStart(0), mLength(0), mPosition(0)
187 { }
189 NS_IMETHOD Tell(int64_t *aResult);
190 NS_IMETHOD Available(uint64_t *aResult);
191 NS_IMETHOD Read(char* aBuf, uint32_t aCount, uint32_t* aResult);
192 NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset);
194 static nsresult
195 Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
197 private:
198 uint64_t TruncateSize(uint64_t aSize) {
199 return std::min<uint64_t>(mLength - mPosition, aSize);
200 }
202 uint64_t mStart;
203 uint64_t mLength;
204 uint64_t mPosition;
205 };
207 ////////////////////////////////////////////////////////////////////////////////
209 class nsFileOutputStream : public nsFileStreamBase,
210 public nsIFileOutputStream
211 {
212 public:
213 NS_DECL_ISUPPORTS_INHERITED
214 NS_DECL_NSIFILEOUTPUTSTREAM
215 NS_FORWARD_NSIOUTPUTSTREAM(nsFileStreamBase::)
217 virtual ~nsFileOutputStream()
218 {
219 Close();
220 }
222 static nsresult
223 Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
224 };
226 ////////////////////////////////////////////////////////////////////////////////
228 /**
229 * A safe file output stream that overwrites the destination file only
230 * once writing is complete. This protects against incomplete writes
231 * due to the process or the thread being interrupted or crashed.
232 */
233 class nsAtomicFileOutputStream : public nsFileOutputStream,
234 public nsISafeOutputStream
235 {
236 public:
237 NS_DECL_ISUPPORTS_INHERITED
238 NS_DECL_NSISAFEOUTPUTSTREAM
240 nsAtomicFileOutputStream() :
241 mTargetFileExists(true),
242 mWriteResult(NS_OK) {}
244 virtual ~nsAtomicFileOutputStream()
245 {
246 Close();
247 }
249 virtual nsresult DoOpen() MOZ_OVERRIDE;
251 NS_IMETHODIMP Close();
252 NS_IMETHODIMP Write(const char *buf, uint32_t count, uint32_t *result);
253 NS_IMETHODIMP Init(nsIFile* file, int32_t ioFlags, int32_t perm, int32_t behaviorFlags);
255 protected:
256 nsCOMPtr<nsIFile> mTargetFile;
257 nsCOMPtr<nsIFile> mTempFile;
259 bool mTargetFileExists;
260 nsresult mWriteResult; // Internally set in Write()
262 };
264 ////////////////////////////////////////////////////////////////////////////////
266 /**
267 * A safe file output stream that overwrites the destination file only
268 * once writing + flushing is complete. This protects against more
269 * classes of software/hardware errors than nsAtomicFileOutputStream,
270 * at the expense of being more costly to the disk, OS and battery.
271 */
272 class nsSafeFileOutputStream : public nsAtomicFileOutputStream
273 {
274 public:
276 NS_IMETHOD Finish();
277 };
279 ////////////////////////////////////////////////////////////////////////////////
281 class nsFileStream : public nsFileStreamBase,
282 public nsIInputStream,
283 public nsIOutputStream,
284 public nsIFileStream
285 {
286 public:
287 NS_DECL_ISUPPORTS_INHERITED
288 NS_DECL_NSIFILESTREAM
289 NS_FORWARD_NSIINPUTSTREAM(nsFileStreamBase::)
291 // Can't use NS_FORWARD_NSIOUTPUTSTREAM due to overlapping methods
292 // Close() and IsNonBlocking()
293 NS_IMETHOD Flush()
294 {
295 return nsFileStreamBase::Flush();
296 }
297 NS_IMETHOD Write(const char* aBuf, uint32_t aCount, uint32_t* _retval)
298 {
299 return nsFileStreamBase::Write(aBuf, aCount, _retval);
300 }
301 NS_IMETHOD WriteFrom(nsIInputStream* aFromStream, uint32_t aCount,
302 uint32_t* _retval)
303 {
304 return nsFileStreamBase::WriteFrom(aFromStream, aCount, _retval);
305 }
306 NS_IMETHOD WriteSegments(nsReadSegmentFun aReader, void* aClosure,
307 uint32_t aCount, uint32_t* _retval)
308 {
309 return nsFileStreamBase::WriteSegments(aReader, aClosure, aCount,
310 _retval);
311 }
313 virtual ~nsFileStream()
314 {
315 Close();
316 }
317 };
319 ////////////////////////////////////////////////////////////////////////////////
321 #endif // nsFileStreams_h__