1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/netwerk/base/src/nsFileStreams.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1014 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "ipc/IPCMessageUtils.h" 1.10 + 1.11 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.12 +#include <unistd.h> 1.13 +#elif defined(XP_WIN) 1.14 +#include <windows.h> 1.15 +#else 1.16 +// XXX add necessary include file for ftruncate (or equivalent) 1.17 +#endif 1.18 + 1.19 +#include "private/pprio.h" 1.20 + 1.21 +#include "nsFileStreams.h" 1.22 +#include "nsIFile.h" 1.23 +#include "nsReadLine.h" 1.24 +#include "nsIClassInfoImpl.h" 1.25 +#include "mozilla/ipc/InputStreamUtils.h" 1.26 +#include "nsNetCID.h" 1.27 + 1.28 +#define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067 1.29 + 1.30 +typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType; 1.31 + 1.32 +using namespace mozilla::ipc; 1.33 +using mozilla::DebugOnly; 1.34 + 1.35 +//////////////////////////////////////////////////////////////////////////////// 1.36 +// nsFileStreamBase 1.37 + 1.38 +nsFileStreamBase::nsFileStreamBase() 1.39 + : mFD(nullptr) 1.40 + , mBehaviorFlags(0) 1.41 + , mDeferredOpen(false) 1.42 +{ 1.43 +} 1.44 + 1.45 +nsFileStreamBase::~nsFileStreamBase() 1.46 +{ 1.47 + Close(); 1.48 +} 1.49 + 1.50 +NS_IMPL_ISUPPORTS(nsFileStreamBase, 1.51 + nsISeekableStream, 1.52 + nsIFileMetadata) 1.53 + 1.54 +NS_IMETHODIMP 1.55 +nsFileStreamBase::Seek(int32_t whence, int64_t offset) 1.56 +{ 1.57 + nsresult rv = DoPendingOpen(); 1.58 + NS_ENSURE_SUCCESS(rv, rv); 1.59 + 1.60 + if (mFD == nullptr) 1.61 + return NS_BASE_STREAM_CLOSED; 1.62 + 1.63 + int64_t cnt = PR_Seek64(mFD, offset, (PRSeekWhence)whence); 1.64 + if (cnt == int64_t(-1)) { 1.65 + return NS_ErrorAccordingToNSPR(); 1.66 + } 1.67 + return NS_OK; 1.68 +} 1.69 + 1.70 +NS_IMETHODIMP 1.71 +nsFileStreamBase::Tell(int64_t *result) 1.72 +{ 1.73 + nsresult rv = DoPendingOpen(); 1.74 + NS_ENSURE_SUCCESS(rv, rv); 1.75 + 1.76 + if (mFD == nullptr) 1.77 + return NS_BASE_STREAM_CLOSED; 1.78 + 1.79 + int64_t cnt = PR_Seek64(mFD, 0, PR_SEEK_CUR); 1.80 + if (cnt == int64_t(-1)) { 1.81 + return NS_ErrorAccordingToNSPR(); 1.82 + } 1.83 + *result = cnt; 1.84 + return NS_OK; 1.85 +} 1.86 + 1.87 +NS_IMETHODIMP 1.88 +nsFileStreamBase::SetEOF() 1.89 +{ 1.90 + nsresult rv = DoPendingOpen(); 1.91 + NS_ENSURE_SUCCESS(rv, rv); 1.92 + 1.93 + if (mFD == nullptr) 1.94 + return NS_BASE_STREAM_CLOSED; 1.95 + 1.96 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.97 + // Some system calls require an EOF offset. 1.98 + int64_t offset; 1.99 + rv = Tell(&offset); 1.100 + if (NS_FAILED(rv)) return rv; 1.101 +#endif 1.102 + 1.103 +#if defined(XP_UNIX) || defined(XP_BEOS) 1.104 + if (ftruncate(PR_FileDesc2NativeHandle(mFD), offset) != 0) { 1.105 + NS_ERROR("ftruncate failed"); 1.106 + return NS_ERROR_FAILURE; 1.107 + } 1.108 +#elif defined(XP_WIN) 1.109 + if (!SetEndOfFile((HANDLE) PR_FileDesc2NativeHandle(mFD))) { 1.110 + NS_ERROR("SetEndOfFile failed"); 1.111 + return NS_ERROR_FAILURE; 1.112 + } 1.113 +#else 1.114 + // XXX not implemented 1.115 +#endif 1.116 + 1.117 + return NS_OK; 1.118 +} 1.119 + 1.120 +NS_IMETHODIMP 1.121 +nsFileStreamBase::GetSize(int64_t* _retval) 1.122 +{ 1.123 + nsresult rv = DoPendingOpen(); 1.124 + NS_ENSURE_SUCCESS(rv, rv); 1.125 + 1.126 + if (!mFD) { 1.127 + return NS_BASE_STREAM_CLOSED; 1.128 + } 1.129 + 1.130 + PRFileInfo64 info; 1.131 + if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { 1.132 + return NS_BASE_STREAM_OSERROR; 1.133 + } 1.134 + 1.135 + *_retval = int64_t(info.size); 1.136 + 1.137 + return NS_OK; 1.138 +} 1.139 + 1.140 +NS_IMETHODIMP 1.141 +nsFileStreamBase::GetLastModified(int64_t* _retval) 1.142 +{ 1.143 + nsresult rv = DoPendingOpen(); 1.144 + NS_ENSURE_SUCCESS(rv, rv); 1.145 + 1.146 + if (!mFD) { 1.147 + return NS_BASE_STREAM_CLOSED; 1.148 + } 1.149 + 1.150 + PRFileInfo64 info; 1.151 + if (PR_GetOpenFileInfo64(mFD, &info) == PR_FAILURE) { 1.152 + return NS_BASE_STREAM_OSERROR; 1.153 + } 1.154 + 1.155 + int64_t modTime = int64_t(info.modifyTime); 1.156 + if (modTime == 0) { 1.157 + *_retval = 0; 1.158 + } 1.159 + else { 1.160 + *_retval = modTime / int64_t(PR_USEC_PER_MSEC); 1.161 + } 1.162 + 1.163 + return NS_OK; 1.164 +} 1.165 + 1.166 +nsresult 1.167 +nsFileStreamBase::Close() 1.168 +{ 1.169 + CleanUpOpen(); 1.170 + 1.171 + nsresult rv = NS_OK; 1.172 + if (mFD) { 1.173 + if (PR_Close(mFD) == PR_FAILURE) 1.174 + rv = NS_BASE_STREAM_OSERROR; 1.175 + mFD = nullptr; 1.176 + } 1.177 + return rv; 1.178 +} 1.179 + 1.180 +nsresult 1.181 +nsFileStreamBase::Available(uint64_t* aResult) 1.182 +{ 1.183 + nsresult rv = DoPendingOpen(); 1.184 + NS_ENSURE_SUCCESS(rv, rv); 1.185 + 1.186 + if (!mFD) { 1.187 + return NS_BASE_STREAM_CLOSED; 1.188 + } 1.189 + 1.190 + // PR_Available with files over 4GB returns an error, so we have to 1.191 + // use the 64-bit version of PR_Available. 1.192 + int64_t avail = PR_Available64(mFD); 1.193 + if (avail == -1) { 1.194 + return NS_ErrorAccordingToNSPR(); 1.195 + } 1.196 + 1.197 + // If available is greater than 4GB, return 4GB 1.198 + *aResult = (uint64_t)avail; 1.199 + return NS_OK; 1.200 +} 1.201 + 1.202 +nsresult 1.203 +nsFileStreamBase::Read(char* aBuf, uint32_t aCount, uint32_t* aResult) 1.204 +{ 1.205 + nsresult rv = DoPendingOpen(); 1.206 + NS_ENSURE_SUCCESS(rv, rv); 1.207 + 1.208 + if (!mFD) { 1.209 + *aResult = 0; 1.210 + return NS_OK; 1.211 + } 1.212 + 1.213 + int32_t bytesRead = PR_Read(mFD, aBuf, aCount); 1.214 + if (bytesRead == -1) { 1.215 + return NS_ErrorAccordingToNSPR(); 1.216 + } 1.217 + 1.218 + *aResult = bytesRead; 1.219 + return NS_OK; 1.220 +} 1.221 + 1.222 +nsresult 1.223 +nsFileStreamBase::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, 1.224 + uint32_t aCount, uint32_t* aResult) 1.225 +{ 1.226 + // ReadSegments is not implemented because it would be inefficient when 1.227 + // the writer does not consume all data. If you want to call ReadSegments, 1.228 + // wrap a BufferedInputStream around the file stream. That will call 1.229 + // Read(). 1.230 + 1.231 + // If this is ever implemented you might need to modify 1.232 + // nsPartialFileInputStream::ReadSegments 1.233 + 1.234 + return NS_ERROR_NOT_IMPLEMENTED; 1.235 +} 1.236 + 1.237 +nsresult 1.238 +nsFileStreamBase::IsNonBlocking(bool *aNonBlocking) 1.239 +{ 1.240 + *aNonBlocking = false; 1.241 + return NS_OK; 1.242 +} 1.243 + 1.244 +nsresult 1.245 +nsFileStreamBase::Flush(void) 1.246 +{ 1.247 + nsresult rv = DoPendingOpen(); 1.248 + NS_ENSURE_SUCCESS(rv, rv); 1.249 + 1.250 + if (mFD == nullptr) 1.251 + return NS_BASE_STREAM_CLOSED; 1.252 + 1.253 + int32_t cnt = PR_Sync(mFD); 1.254 + if (cnt == -1) { 1.255 + return NS_ErrorAccordingToNSPR(); 1.256 + } 1.257 + return NS_OK; 1.258 +} 1.259 + 1.260 +nsresult 1.261 +nsFileStreamBase::Write(const char *buf, uint32_t count, uint32_t *result) 1.262 +{ 1.263 + nsresult rv = DoPendingOpen(); 1.264 + NS_ENSURE_SUCCESS(rv, rv); 1.265 + 1.266 + if (mFD == nullptr) 1.267 + return NS_BASE_STREAM_CLOSED; 1.268 + 1.269 + int32_t cnt = PR_Write(mFD, buf, count); 1.270 + if (cnt == -1) { 1.271 + return NS_ErrorAccordingToNSPR(); 1.272 + } 1.273 + *result = cnt; 1.274 + return NS_OK; 1.275 +} 1.276 + 1.277 +nsresult 1.278 +nsFileStreamBase::WriteFrom(nsIInputStream *inStr, uint32_t count, uint32_t *_retval) 1.279 +{ 1.280 + NS_NOTREACHED("WriteFrom (see source comment)"); 1.281 + return NS_ERROR_NOT_IMPLEMENTED; 1.282 + // File streams intentionally do not support this method. 1.283 + // If you need something like this, then you should wrap 1.284 + // the file stream using nsIBufferedOutputStream 1.285 +} 1.286 + 1.287 +nsresult 1.288 +nsFileStreamBase::WriteSegments(nsReadSegmentFun reader, void * closure, uint32_t count, uint32_t *_retval) 1.289 +{ 1.290 + return NS_ERROR_NOT_IMPLEMENTED; 1.291 + // File streams intentionally do not support this method. 1.292 + // If you need something like this, then you should wrap 1.293 + // the file stream using nsIBufferedOutputStream 1.294 +} 1.295 + 1.296 +nsresult 1.297 +nsFileStreamBase::MaybeOpen(nsIFile* aFile, int32_t aIoFlags, 1.298 + int32_t aPerm, bool aDeferred) 1.299 +{ 1.300 + NS_ENSURE_STATE(aFile); 1.301 + 1.302 + mOpenParams.ioFlags = aIoFlags; 1.303 + mOpenParams.perm = aPerm; 1.304 + 1.305 + if (aDeferred) { 1.306 + // Clone the file, as it may change between now and the deferred open 1.307 + nsCOMPtr<nsIFile> file; 1.308 + nsresult rv = aFile->Clone(getter_AddRefs(file)); 1.309 + NS_ENSURE_SUCCESS(rv, rv); 1.310 + 1.311 + mOpenParams.localFile = do_QueryInterface(file); 1.312 + NS_ENSURE_TRUE(mOpenParams.localFile, NS_ERROR_UNEXPECTED); 1.313 + 1.314 + mDeferredOpen = true; 1.315 + return NS_OK; 1.316 + } 1.317 + 1.318 + mOpenParams.localFile = aFile; 1.319 + 1.320 + return DoOpen(); 1.321 +} 1.322 + 1.323 +void 1.324 +nsFileStreamBase::CleanUpOpen() 1.325 +{ 1.326 + mOpenParams.localFile = nullptr; 1.327 + mDeferredOpen = false; 1.328 +} 1.329 + 1.330 +nsresult 1.331 +nsFileStreamBase::DoOpen() 1.332 +{ 1.333 + NS_ASSERTION(!mFD, "Already have a file descriptor!"); 1.334 + NS_ASSERTION(mOpenParams.localFile, "Must have a file to open"); 1.335 + 1.336 + PRFileDesc* fd; 1.337 + nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags, 1.338 + mOpenParams.perm, 1.339 + &fd); 1.340 + CleanUpOpen(); 1.341 + if (NS_FAILED(rv)) 1.342 + return rv; 1.343 + mFD = fd; 1.344 + 1.345 + return NS_OK; 1.346 +} 1.347 + 1.348 +nsresult 1.349 +nsFileStreamBase::DoPendingOpen() 1.350 +{ 1.351 + if (!mDeferredOpen) { 1.352 + return NS_OK; 1.353 + } 1.354 + 1.355 + return DoOpen(); 1.356 +} 1.357 + 1.358 +//////////////////////////////////////////////////////////////////////////////// 1.359 +// nsFileInputStream 1.360 + 1.361 +NS_IMPL_ADDREF_INHERITED(nsFileInputStream, nsFileStreamBase) 1.362 +NS_IMPL_RELEASE_INHERITED(nsFileInputStream, nsFileStreamBase) 1.363 + 1.364 +NS_IMPL_CLASSINFO(nsFileInputStream, nullptr, nsIClassInfo::THREADSAFE, 1.365 + NS_LOCALFILEINPUTSTREAM_CID) 1.366 + 1.367 +NS_INTERFACE_MAP_BEGIN(nsFileInputStream) 1.368 + NS_INTERFACE_MAP_ENTRY(nsIInputStream) 1.369 + NS_INTERFACE_MAP_ENTRY(nsIFileInputStream) 1.370 + NS_INTERFACE_MAP_ENTRY(nsILineInputStream) 1.371 + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream) 1.372 + NS_IMPL_QUERY_CLASSINFO(nsFileInputStream) 1.373 +NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase) 1.374 + 1.375 +NS_IMPL_CI_INTERFACE_GETTER(nsFileInputStream, 1.376 + nsIInputStream, 1.377 + nsIFileInputStream, 1.378 + nsISeekableStream, 1.379 + nsILineInputStream) 1.380 + 1.381 +nsresult 1.382 +nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.383 +{ 1.384 + NS_ENSURE_NO_AGGREGATION(aOuter); 1.385 + 1.386 + nsFileInputStream* stream = new nsFileInputStream(); 1.387 + if (stream == nullptr) 1.388 + return NS_ERROR_OUT_OF_MEMORY; 1.389 + NS_ADDREF(stream); 1.390 + nsresult rv = stream->QueryInterface(aIID, aResult); 1.391 + NS_RELEASE(stream); 1.392 + return rv; 1.393 +} 1.394 + 1.395 +nsresult 1.396 +nsFileInputStream::Open(nsIFile* aFile, int32_t aIOFlags, int32_t aPerm) 1.397 +{ 1.398 + nsresult rv = NS_OK; 1.399 + 1.400 + // If the previous file is open, close it 1.401 + if (mFD) { 1.402 + rv = Close(); 1.403 + if (NS_FAILED(rv)) return rv; 1.404 + } 1.405 + 1.406 + // Open the file 1.407 + if (aIOFlags == -1) 1.408 + aIOFlags = PR_RDONLY; 1.409 + if (aPerm == -1) 1.410 + aPerm = 0; 1.411 + 1.412 + rv = MaybeOpen(aFile, aIOFlags, aPerm, 1.413 + mBehaviorFlags & nsIFileInputStream::DEFER_OPEN); 1.414 + if (NS_FAILED(rv)) return rv; 1.415 + 1.416 + if (mBehaviorFlags & DELETE_ON_CLOSE) { 1.417 + // POSIX compatible filesystems allow a file to be unlinked while a 1.418 + // file descriptor is still referencing the file. since we've already 1.419 + // opened the file descriptor, we'll try to remove the file. if that 1.420 + // fails, then we'll just remember the nsIFile and remove it after we 1.421 + // close the file descriptor. 1.422 + rv = aFile->Remove(false); 1.423 + if (NS_SUCCEEDED(rv)) { 1.424 + // No need to remove it later. Clear the flag. 1.425 + mBehaviorFlags &= ~DELETE_ON_CLOSE; 1.426 + } 1.427 + } 1.428 + 1.429 + return NS_OK; 1.430 +} 1.431 + 1.432 +NS_IMETHODIMP 1.433 +nsFileInputStream::Init(nsIFile* aFile, int32_t aIOFlags, int32_t aPerm, 1.434 + int32_t aBehaviorFlags) 1.435 +{ 1.436 + NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED); 1.437 + NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED); 1.438 + 1.439 + mBehaviorFlags = aBehaviorFlags; 1.440 + 1.441 + mFile = aFile; 1.442 + mIOFlags = aIOFlags; 1.443 + mPerm = aPerm; 1.444 + 1.445 + return Open(aFile, aIOFlags, aPerm); 1.446 +} 1.447 + 1.448 +NS_IMETHODIMP 1.449 +nsFileInputStream::Close() 1.450 +{ 1.451 + // Get the cache position at the time the file was close. This allows 1.452 + // NS_SEEK_CUR on a closed file that has been opened with 1.453 + // REOPEN_ON_REWIND. 1.454 + if (mBehaviorFlags & REOPEN_ON_REWIND) { 1.455 + // Get actual position. Not one modified by subclasses 1.456 + nsFileStreamBase::Tell(&mCachedPosition); 1.457 + } 1.458 + 1.459 + // null out mLineBuffer in case Close() is called again after failing 1.460 + mLineBuffer = nullptr; 1.461 + nsresult rv = nsFileStreamBase::Close(); 1.462 + if (NS_FAILED(rv)) return rv; 1.463 + if (mFile && (mBehaviorFlags & DELETE_ON_CLOSE)) { 1.464 + rv = mFile->Remove(false); 1.465 + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to delete file"); 1.466 + // If we don't need to save the file for reopening, free it up 1.467 + if (!(mBehaviorFlags & REOPEN_ON_REWIND)) { 1.468 + mFile = nullptr; 1.469 + } 1.470 + } 1.471 + return rv; 1.472 +} 1.473 + 1.474 +NS_IMETHODIMP 1.475 +nsFileInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* _retval) 1.476 +{ 1.477 + nsresult rv = nsFileStreamBase::Read(aBuf, aCount, _retval); 1.478 + NS_ENSURE_SUCCESS(rv, rv); 1.479 + 1.480 + // Check if we're at the end of file and need to close 1.481 + if (mBehaviorFlags & CLOSE_ON_EOF && *_retval == 0) { 1.482 + Close(); 1.483 + } 1.484 + 1.485 + return NS_OK; 1.486 +} 1.487 + 1.488 +NS_IMETHODIMP 1.489 +nsFileInputStream::ReadLine(nsACString& aLine, bool* aResult) 1.490 +{ 1.491 + nsresult rv = DoPendingOpen(); 1.492 + NS_ENSURE_SUCCESS(rv, rv); 1.493 + 1.494 + if (!mLineBuffer) { 1.495 + mLineBuffer = new nsLineBuffer<char>; 1.496 + } 1.497 + return NS_ReadLine(this, mLineBuffer.get(), aLine, aResult); 1.498 +} 1.499 + 1.500 +NS_IMETHODIMP 1.501 +nsFileInputStream::Seek(int32_t aWhence, int64_t aOffset) 1.502 +{ 1.503 + nsresult rv = DoPendingOpen(); 1.504 + NS_ENSURE_SUCCESS(rv, rv); 1.505 + 1.506 + mLineBuffer = nullptr; 1.507 + if (!mFD) { 1.508 + if (mBehaviorFlags & REOPEN_ON_REWIND) { 1.509 + rv = Open(mFile, mIOFlags, mPerm); 1.510 + NS_ENSURE_SUCCESS(rv, rv); 1.511 + 1.512 + // If the file was closed, and we do a relative seek, use the 1.513 + // position we cached when we closed the file to seek to the right 1.514 + // location. 1.515 + if (aWhence == NS_SEEK_CUR) { 1.516 + aWhence = NS_SEEK_SET; 1.517 + aOffset += mCachedPosition; 1.518 + } 1.519 + } else { 1.520 + return NS_BASE_STREAM_CLOSED; 1.521 + } 1.522 + } 1.523 + 1.524 + return nsFileStreamBase::Seek(aWhence, aOffset); 1.525 +} 1.526 + 1.527 +NS_IMETHODIMP 1.528 +nsFileInputStream::Tell(int64_t *aResult) 1.529 +{ 1.530 + return nsFileStreamBase::Tell(aResult); 1.531 +} 1.532 + 1.533 +NS_IMETHODIMP 1.534 +nsFileInputStream::Available(uint64_t *aResult) 1.535 +{ 1.536 + return nsFileStreamBase::Available(aResult); 1.537 +} 1.538 + 1.539 +void 1.540 +nsFileInputStream::Serialize(InputStreamParams& aParams, 1.541 + FileDescriptorArray& aFileDescriptors) 1.542 +{ 1.543 + FileInputStreamParams params; 1.544 + 1.545 + if (mFD) { 1.546 + FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFD)); 1.547 + NS_ASSERTION(fd, "This should never be null!"); 1.548 + 1.549 + DebugOnly<FileDescriptor*> dbgFD = aFileDescriptors.AppendElement(fd); 1.550 + NS_ASSERTION(dbgFD->IsValid(), "Sending an invalid file descriptor!"); 1.551 + 1.552 + params.fileDescriptorIndex() = aFileDescriptors.Length() - 1; 1.553 + } else { 1.554 + NS_WARNING("This file has not been opened (or could not be opened). " 1.555 + "Sending an invalid file descriptor to the other process!"); 1.556 + } 1.557 + 1.558 + int32_t behaviorFlags = mBehaviorFlags; 1.559 + 1.560 + // The other process shouldn't close when it reads the end because it will 1.561 + // not be able to reopen the file later. 1.562 + behaviorFlags &= ~nsIFileInputStream::CLOSE_ON_EOF; 1.563 + 1.564 + // The other process will not be able to reopen the file so transferring 1.565 + // this flag is meaningless. 1.566 + behaviorFlags &= ~nsIFileInputStream::REOPEN_ON_REWIND; 1.567 + 1.568 + // The other process is going to have an open file descriptor automatically 1.569 + // so transferring this flag is meaningless. 1.570 + behaviorFlags &= ~nsIFileInputStream::DEFER_OPEN; 1.571 + 1.572 + params.behaviorFlags() = behaviorFlags; 1.573 + params.ioFlags() = mIOFlags; 1.574 + 1.575 + aParams = params; 1.576 +} 1.577 + 1.578 +bool 1.579 +nsFileInputStream::Deserialize(const InputStreamParams& aParams, 1.580 + const FileDescriptorArray& aFileDescriptors) 1.581 +{ 1.582 + NS_ASSERTION(!mFD, "Already have a file descriptor?!"); 1.583 + NS_ASSERTION(!mDeferredOpen, "Deferring open?!"); 1.584 + NS_ASSERTION(!mFile, "Should never have a file here!"); 1.585 + NS_ASSERTION(!mPerm, "This should always be 0!"); 1.586 + 1.587 + if (aParams.type() != InputStreamParams::TFileInputStreamParams) { 1.588 + NS_WARNING("Received unknown parameters from the other process!"); 1.589 + return false; 1.590 + } 1.591 + 1.592 + const FileInputStreamParams& params = aParams.get_FileInputStreamParams(); 1.593 + 1.594 + uint32_t fileDescriptorIndex = params.fileDescriptorIndex(); 1.595 + 1.596 + FileDescriptor fd; 1.597 + if (fileDescriptorIndex < aFileDescriptors.Length()) { 1.598 + fd = aFileDescriptors[fileDescriptorIndex]; 1.599 + NS_WARN_IF_FALSE(fd.IsValid(), "Received an invalid file descriptor!"); 1.600 + } else { 1.601 + NS_WARNING("Received a bad file descriptor index!"); 1.602 + } 1.603 + 1.604 + if (fd.IsValid()) { 1.605 + PRFileDesc* fileDesc = PR_ImportFile(PROsfd(fd.PlatformHandle())); 1.606 + if (!fileDesc) { 1.607 + NS_WARNING("Failed to import file handle!"); 1.608 + return false; 1.609 + } 1.610 + mFD = fileDesc; 1.611 + } 1.612 + 1.613 + mBehaviorFlags = params.behaviorFlags(); 1.614 + mIOFlags = params.ioFlags(); 1.615 + 1.616 + return true; 1.617 +} 1.618 + 1.619 +//////////////////////////////////////////////////////////////////////////////// 1.620 +// nsPartialFileInputStream 1.621 + 1.622 +NS_IMPL_ADDREF_INHERITED(nsPartialFileInputStream, nsFileStreamBase) 1.623 +NS_IMPL_RELEASE_INHERITED(nsPartialFileInputStream, nsFileStreamBase) 1.624 + 1.625 +NS_IMPL_CLASSINFO(nsPartialFileInputStream, nullptr, nsIClassInfo::THREADSAFE, 1.626 + NS_PARTIALLOCALFILEINPUTSTREAM_CID) 1.627 + 1.628 +// Don't forward to nsFileInputStream as we don't want to QI to 1.629 +// nsIFileInputStream 1.630 +NS_INTERFACE_MAP_BEGIN(nsPartialFileInputStream) 1.631 + NS_INTERFACE_MAP_ENTRY(nsIInputStream) 1.632 + NS_INTERFACE_MAP_ENTRY(nsIPartialFileInputStream) 1.633 + NS_INTERFACE_MAP_ENTRY(nsILineInputStream) 1.634 + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream) 1.635 + NS_IMPL_QUERY_CLASSINFO(nsPartialFileInputStream) 1.636 +NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase) 1.637 + 1.638 +NS_IMPL_CI_INTERFACE_GETTER(nsPartialFileInputStream, 1.639 + nsIInputStream, 1.640 + nsIPartialFileInputStream, 1.641 + nsISeekableStream, 1.642 + nsILineInputStream) 1.643 + 1.644 +nsresult 1.645 +nsPartialFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, 1.646 + void **aResult) 1.647 +{ 1.648 + NS_ENSURE_NO_AGGREGATION(aOuter); 1.649 + 1.650 + nsPartialFileInputStream* stream = new nsPartialFileInputStream(); 1.651 + 1.652 + NS_ADDREF(stream); 1.653 + nsresult rv = stream->QueryInterface(aIID, aResult); 1.654 + NS_RELEASE(stream); 1.655 + return rv; 1.656 +} 1.657 + 1.658 +NS_IMETHODIMP 1.659 +nsPartialFileInputStream::Init(nsIFile* aFile, uint64_t aStart, 1.660 + uint64_t aLength, int32_t aIOFlags, 1.661 + int32_t aPerm, int32_t aBehaviorFlags) 1.662 +{ 1.663 + mStart = aStart; 1.664 + mLength = aLength; 1.665 + mPosition = 0; 1.666 + 1.667 + nsresult rv = nsFileInputStream::Init(aFile, aIOFlags, aPerm, 1.668 + aBehaviorFlags); 1.669 + NS_ENSURE_SUCCESS(rv, rv); 1.670 + 1.671 + return nsFileInputStream::Seek(NS_SEEK_SET, mStart); 1.672 +} 1.673 + 1.674 +NS_IMETHODIMP 1.675 +nsPartialFileInputStream::Tell(int64_t *aResult) 1.676 +{ 1.677 + int64_t tell = 0; 1.678 + nsresult rv = nsFileInputStream::Tell(&tell); 1.679 + if (NS_SUCCEEDED(rv)) { 1.680 + *aResult = tell - mStart; 1.681 + } 1.682 + return rv; 1.683 +} 1.684 + 1.685 +NS_IMETHODIMP 1.686 +nsPartialFileInputStream::Available(uint64_t* aResult) 1.687 +{ 1.688 + uint64_t available = 0; 1.689 + nsresult rv = nsFileInputStream::Available(&available); 1.690 + if (NS_SUCCEEDED(rv)) { 1.691 + *aResult = TruncateSize(available); 1.692 + } 1.693 + return rv; 1.694 +} 1.695 + 1.696 +NS_IMETHODIMP 1.697 +nsPartialFileInputStream::Read(char* aBuf, uint32_t aCount, uint32_t* aResult) 1.698 +{ 1.699 + uint32_t readsize = (uint32_t) TruncateSize(aCount); 1.700 + if (readsize == 0 && mBehaviorFlags & CLOSE_ON_EOF) { 1.701 + Close(); 1.702 + *aResult = 0; 1.703 + return NS_OK; 1.704 + } 1.705 + 1.706 + nsresult rv = nsFileInputStream::Read(aBuf, readsize, aResult); 1.707 + if (NS_SUCCEEDED(rv)) { 1.708 + mPosition += readsize; 1.709 + } 1.710 + return rv; 1.711 +} 1.712 + 1.713 +NS_IMETHODIMP 1.714 +nsPartialFileInputStream::Seek(int32_t aWhence, int64_t aOffset) 1.715 +{ 1.716 + int64_t offset; 1.717 + switch (aWhence) { 1.718 + case NS_SEEK_SET: 1.719 + offset = mStart + aOffset; 1.720 + break; 1.721 + case NS_SEEK_CUR: 1.722 + offset = mStart + mPosition + aOffset; 1.723 + break; 1.724 + case NS_SEEK_END: 1.725 + offset = mStart + mLength + aOffset; 1.726 + break; 1.727 + default: 1.728 + return NS_ERROR_ILLEGAL_VALUE; 1.729 + } 1.730 + 1.731 + if (offset < (int64_t)mStart || offset > (int64_t)(mStart + mLength)) { 1.732 + return NS_ERROR_INVALID_ARG; 1.733 + } 1.734 + 1.735 + nsresult rv = nsFileInputStream::Seek(NS_SEEK_SET, offset); 1.736 + if (NS_SUCCEEDED(rv)) { 1.737 + mPosition = offset - mStart; 1.738 + } 1.739 + return rv; 1.740 +} 1.741 + 1.742 +void 1.743 +nsPartialFileInputStream::Serialize(InputStreamParams& aParams, 1.744 + FileDescriptorArray& aFileDescriptors) 1.745 +{ 1.746 + // Serialize the base class first. 1.747 + InputStreamParams fileParams; 1.748 + nsFileInputStream::Serialize(fileParams, aFileDescriptors); 1.749 + 1.750 + PartialFileInputStreamParams params; 1.751 + 1.752 + params.fileStreamParams() = fileParams.get_FileInputStreamParams(); 1.753 + params.begin() = mStart; 1.754 + params.length() = mLength; 1.755 + 1.756 + aParams = params; 1.757 +} 1.758 + 1.759 +bool 1.760 +nsPartialFileInputStream::Deserialize( 1.761 + const InputStreamParams& aParams, 1.762 + const FileDescriptorArray& aFileDescriptors) 1.763 +{ 1.764 + NS_ASSERTION(!mFD, "Already have a file descriptor?!"); 1.765 + NS_ASSERTION(!mStart, "Already have a start?!"); 1.766 + NS_ASSERTION(!mLength, "Already have a length?!"); 1.767 + NS_ASSERTION(!mPosition, "Already have a position?!"); 1.768 + 1.769 + if (aParams.type() != InputStreamParams::TPartialFileInputStreamParams) { 1.770 + NS_WARNING("Received unknown parameters from the other process!"); 1.771 + return false; 1.772 + } 1.773 + 1.774 + const PartialFileInputStreamParams& params = 1.775 + aParams.get_PartialFileInputStreamParams(); 1.776 + 1.777 + // Deserialize the base class first. 1.778 + InputStreamParams fileParams(params.fileStreamParams()); 1.779 + if (!nsFileInputStream::Deserialize(fileParams, aFileDescriptors)) { 1.780 + NS_WARNING("Base class deserialize failed!"); 1.781 + return false; 1.782 + } 1.783 + 1.784 + NS_ASSERTION(mFD, "Must have a file descriptor now!"); 1.785 + 1.786 + mStart = params.begin(); 1.787 + mLength = params.length(); 1.788 + mPosition = 0; 1.789 + 1.790 + if (!mStart) { 1.791 + return true; 1.792 + } 1.793 + 1.794 + // XXX This is so broken. Main thread IO alert. 1.795 + return NS_SUCCEEDED(nsFileInputStream::Seek(NS_SEEK_SET, mStart)); 1.796 +} 1.797 + 1.798 +//////////////////////////////////////////////////////////////////////////////// 1.799 +// nsFileOutputStream 1.800 + 1.801 +NS_IMPL_ISUPPORTS_INHERITED(nsFileOutputStream, 1.802 + nsFileStreamBase, 1.803 + nsIOutputStream, 1.804 + nsIFileOutputStream) 1.805 + 1.806 +nsresult 1.807 +nsFileOutputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) 1.808 +{ 1.809 + NS_ENSURE_NO_AGGREGATION(aOuter); 1.810 + 1.811 + nsFileOutputStream* stream = new nsFileOutputStream(); 1.812 + if (stream == nullptr) 1.813 + return NS_ERROR_OUT_OF_MEMORY; 1.814 + NS_ADDREF(stream); 1.815 + nsresult rv = stream->QueryInterface(aIID, aResult); 1.816 + NS_RELEASE(stream); 1.817 + return rv; 1.818 +} 1.819 + 1.820 +NS_IMETHODIMP 1.821 +nsFileOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, 1.822 + int32_t behaviorFlags) 1.823 +{ 1.824 + NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED); 1.825 + NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED); 1.826 + 1.827 + mBehaviorFlags = behaviorFlags; 1.828 + 1.829 + if (ioFlags == -1) 1.830 + ioFlags = PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE; 1.831 + if (perm <= 0) 1.832 + perm = 0664; 1.833 + 1.834 + return MaybeOpen(file, ioFlags, perm, 1.835 + mBehaviorFlags & nsIFileOutputStream::DEFER_OPEN); 1.836 +} 1.837 + 1.838 +//////////////////////////////////////////////////////////////////////////////// 1.839 +// nsAtomicFileOutputStream 1.840 + 1.841 +NS_IMPL_ISUPPORTS_INHERITED(nsAtomicFileOutputStream, 1.842 + nsFileOutputStream, 1.843 + nsISafeOutputStream, 1.844 + nsIOutputStream, 1.845 + nsIFileOutputStream) 1.846 + 1.847 +NS_IMETHODIMP 1.848 +nsAtomicFileOutputStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, 1.849 + int32_t behaviorFlags) 1.850 +{ 1.851 + return nsFileOutputStream::Init(file, ioFlags, perm, behaviorFlags); 1.852 +} 1.853 + 1.854 +nsresult 1.855 +nsAtomicFileOutputStream::DoOpen() 1.856 +{ 1.857 + // Make sure mOpenParams.localFile will be empty if we bail somewhere in 1.858 + // this function 1.859 + nsCOMPtr<nsIFile> file; 1.860 + file.swap(mOpenParams.localFile); 1.861 + 1.862 + nsresult rv = file->Exists(&mTargetFileExists); 1.863 + if (NS_FAILED(rv)) { 1.864 + NS_ERROR("Can't tell if target file exists"); 1.865 + mTargetFileExists = true; // Safer to assume it exists - we just do more work. 1.866 + } 1.867 + 1.868 + // follow symlinks, for two reasons: 1.869 + // 1) if a user has deliberately set up a profile file as a symlink, we honor it 1.870 + // 2) to make the MoveToNative() in Finish() an atomic operation (which may not 1.871 + // be the case if moving across directories on different filesystems). 1.872 + nsCOMPtr<nsIFile> tempResult; 1.873 + rv = file->Clone(getter_AddRefs(tempResult)); 1.874 + if (NS_SUCCEEDED(rv)) { 1.875 + tempResult->SetFollowLinks(true); 1.876 + 1.877 + // XP_UNIX ignores SetFollowLinks(), so we have to normalize. 1.878 + tempResult->Normalize(); 1.879 + } 1.880 + 1.881 + if (NS_SUCCEEDED(rv) && mTargetFileExists) { 1.882 + uint32_t origPerm; 1.883 + if (NS_FAILED(file->GetPermissions(&origPerm))) { 1.884 + NS_ERROR("Can't get permissions of target file"); 1.885 + origPerm = mOpenParams.perm; 1.886 + } 1.887 + // XXX What if |perm| is more restrictive then |origPerm|? 1.888 + // This leaves the user supplied permissions as they were. 1.889 + rv = tempResult->CreateUnique(nsIFile::NORMAL_FILE_TYPE, origPerm); 1.890 + } 1.891 + if (NS_SUCCEEDED(rv)) { 1.892 + // nsFileOutputStream::DoOpen will work on the temporary file, so we 1.893 + // prepare it and place it in mOpenParams.localFile. 1.894 + mOpenParams.localFile = tempResult; 1.895 + mTempFile = tempResult; 1.896 + mTargetFile = file; 1.897 + rv = nsFileOutputStream::DoOpen(); 1.898 + } 1.899 + return rv; 1.900 +} 1.901 + 1.902 +NS_IMETHODIMP 1.903 +nsAtomicFileOutputStream::Close() 1.904 +{ 1.905 + nsresult rv = nsFileOutputStream::Close(); 1.906 + 1.907 + // the consumer doesn't want the original file overwritten - 1.908 + // so clean up by removing the temp file. 1.909 + if (mTempFile) { 1.910 + mTempFile->Remove(false); 1.911 + mTempFile = nullptr; 1.912 + } 1.913 + 1.914 + return rv; 1.915 +} 1.916 + 1.917 +NS_IMETHODIMP 1.918 +nsAtomicFileOutputStream::Finish() 1.919 +{ 1.920 + nsresult rv = nsFileOutputStream::Close(); 1.921 + 1.922 + // if there is no temp file, don't try to move it over the original target. 1.923 + // It would destroy the targetfile if close() is called twice. 1.924 + if (!mTempFile) 1.925 + return rv; 1.926 + 1.927 + // Only overwrite if everything was ok, and the temp file could be closed. 1.928 + if (NS_SUCCEEDED(mWriteResult) && NS_SUCCEEDED(rv)) { 1.929 + NS_ENSURE_STATE(mTargetFile); 1.930 + 1.931 + if (!mTargetFileExists) { 1.932 + // If the target file did not exist when we were initialized, then the 1.933 + // temp file we gave out was actually a reference to the target file. 1.934 + // since we succeeded in writing to the temp file (and hence succeeded 1.935 + // in writing to the target file), there is nothing more to do. 1.936 +#ifdef DEBUG 1.937 + bool equal; 1.938 + if (NS_FAILED(mTargetFile->Equals(mTempFile, &equal)) || !equal) 1.939 + NS_ERROR("mTempFile not equal to mTargetFile"); 1.940 +#endif 1.941 + } 1.942 + else { 1.943 + nsAutoString targetFilename; 1.944 + rv = mTargetFile->GetLeafName(targetFilename); 1.945 + if (NS_SUCCEEDED(rv)) { 1.946 + // This will replace target. 1.947 + rv = mTempFile->MoveTo(nullptr, targetFilename); 1.948 + if (NS_FAILED(rv)) 1.949 + mTempFile->Remove(false); 1.950 + } 1.951 + } 1.952 + } 1.953 + else { 1.954 + mTempFile->Remove(false); 1.955 + 1.956 + // if writing failed, propagate the failure code to the caller. 1.957 + if (NS_FAILED(mWriteResult)) 1.958 + rv = mWriteResult; 1.959 + } 1.960 + mTempFile = nullptr; 1.961 + return rv; 1.962 +} 1.963 + 1.964 +NS_IMETHODIMP 1.965 +nsAtomicFileOutputStream::Write(const char *buf, uint32_t count, uint32_t *result) 1.966 +{ 1.967 + nsresult rv = nsFileOutputStream::Write(buf, count, result); 1.968 + if (NS_SUCCEEDED(mWriteResult)) { 1.969 + if (NS_FAILED(rv)) 1.970 + mWriteResult = rv; 1.971 + else if (count != *result) 1.972 + mWriteResult = NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; 1.973 + 1.974 + if (NS_FAILED(mWriteResult) && count > 0) 1.975 + NS_WARNING("writing to output stream failed! data may be lost"); 1.976 + } 1.977 + return rv; 1.978 +} 1.979 + 1.980 +//////////////////////////////////////////////////////////////////////////////// 1.981 +// nsSafeFileOutputStream 1.982 + 1.983 +NS_IMETHODIMP 1.984 +nsSafeFileOutputStream::Finish() 1.985 +{ 1.986 + (void) Flush(); 1.987 + return nsAtomicFileOutputStream::Finish(); 1.988 +} 1.989 + 1.990 +//////////////////////////////////////////////////////////////////////////////// 1.991 +// nsFileStream 1.992 + 1.993 +NS_IMPL_ISUPPORTS_INHERITED(nsFileStream, 1.994 + nsFileStreamBase, 1.995 + nsIInputStream, 1.996 + nsIOutputStream, 1.997 + nsIFileStream) 1.998 + 1.999 +NS_IMETHODIMP 1.1000 +nsFileStream::Init(nsIFile* file, int32_t ioFlags, int32_t perm, 1.1001 + int32_t behaviorFlags) 1.1002 +{ 1.1003 + NS_ENSURE_TRUE(mFD == nullptr, NS_ERROR_ALREADY_INITIALIZED); 1.1004 + NS_ENSURE_TRUE(!mDeferredOpen, NS_ERROR_ALREADY_INITIALIZED); 1.1005 + 1.1006 + mBehaviorFlags = behaviorFlags; 1.1007 + 1.1008 + if (ioFlags == -1) 1.1009 + ioFlags = PR_RDWR; 1.1010 + if (perm <= 0) 1.1011 + perm = 0; 1.1012 + 1.1013 + return MaybeOpen(file, ioFlags, perm, 1.1014 + mBehaviorFlags & nsIFileStream::DEFER_OPEN); 1.1015 +} 1.1016 + 1.1017 +////////////////////////////////////////////////////////////////////////////////