michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "TestCommon.h" michael@0: #include "nsIComponentRegistrar.h" michael@0: #include "nsIStreamTransportService.h" michael@0: #include "nsIAsyncInputStream.h" michael@0: #include "nsIProgressEventSink.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "nsIRequest.h" michael@0: #include "nsIServiceManager.h" michael@0: #include "nsIComponentManager.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "nsMemory.h" michael@0: #include "nsStringAPI.h" michael@0: #include "nsIFileStreams.h" michael@0: #include "nsIStreamListener.h" michael@0: #include "nsIFile.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsAutoLock.h" michael@0: #include "prlog.h" michael@0: #include "prenv.h" michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #if defined(PR_LOGGING) michael@0: // michael@0: // set NSPR_LOG_MODULES=Test:5 michael@0: // michael@0: static PRLogModuleInfo *gTestLog = nullptr; michael@0: #endif michael@0: #define LOG(args) PR_LOG(gTestLog, PR_LOG_DEBUG, args) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID); michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: #define CHUNK_SIZE 500 michael@0: michael@0: class MyCopier : public nsIInputStreamCallback michael@0: , public nsIOutputStreamCallback michael@0: { michael@0: public: michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: MyCopier() michael@0: : mLock(nullptr) michael@0: , mInputCondition(NS_OK) michael@0: { michael@0: } michael@0: michael@0: virtual ~MyCopier() michael@0: { michael@0: if (mLock) michael@0: nsAutoLock::DestroyLock(mLock); michael@0: if (mInput) michael@0: mInput->Close(); michael@0: if (mOutput) michael@0: mOutput->Close(); michael@0: } michael@0: michael@0: // called on any thread michael@0: NS_IMETHOD OnInputStreamReady(nsIAsyncInputStream *inStr) michael@0: { michael@0: LOG(("OnInputStreamReady\n")); michael@0: nsAutoLock lock(mLock); michael@0: NS_ASSERTION(inStr == mInput, "unexpected stream"); michael@0: Process_Locked(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // called on any thread michael@0: NS_IMETHOD OnOutputStreamReady(nsIAsyncOutputStream *outStr) michael@0: { michael@0: LOG(("OnOutputStreamReady\n")); michael@0: nsAutoLock lock(mLock); michael@0: NS_ASSERTION(outStr == mOutput, "unexpected stream"); michael@0: Process_Locked(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: void Close_Locked() michael@0: { michael@0: LOG(("Close_Locked\n")); michael@0: michael@0: mOutput->Close(); michael@0: mOutput = 0; michael@0: mInput->Close(); michael@0: mInput = 0; michael@0: michael@0: // post done copying event michael@0: QuitPumpingEvents(); michael@0: } michael@0: michael@0: void Process_Locked() michael@0: { michael@0: while (1) { michael@0: mInputCondition = NS_OK; // reset michael@0: michael@0: uint32_t n; michael@0: nsresult rv = mOutput->WriteSegments(FillOutputBuffer, this, CHUNK_SIZE, &n); michael@0: if (NS_FAILED(rv) || (n == 0)) { michael@0: if (rv == NS_BASE_STREAM_WOULD_BLOCK) michael@0: mOutput->AsyncWait(this, 0, 0, nullptr); michael@0: else if (mInputCondition == NS_BASE_STREAM_WOULD_BLOCK) michael@0: mInput->AsyncWait(this, 0, 0, nullptr); michael@0: else michael@0: Close_Locked(); michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: nsresult AsyncCopy(nsITransport *srcTrans, nsITransport *destTrans) michael@0: { michael@0: mLock = nsAutoLock::NewLock("MyCopier::mLock"); michael@0: if (!mLock) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: nsresult rv; michael@0: michael@0: nsCOMPtr inStr; michael@0: rv = srcTrans->OpenInputStream(0, 0, 0, getter_AddRefs(inStr)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr outStr; michael@0: rv = destTrans->OpenOutputStream(0, 0, 0, getter_AddRefs(outStr)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: mInput = do_QueryInterface(inStr); michael@0: mOutput = do_QueryInterface(outStr); michael@0: michael@0: return mInput->AsyncWait(this, 0, 0, nullptr); michael@0: } michael@0: michael@0: static NS_METHOD FillOutputBuffer(nsIOutputStream *outStr, michael@0: void *closure, michael@0: char *buffer, michael@0: uint32_t offset, michael@0: uint32_t count, michael@0: uint32_t *countRead) michael@0: { michael@0: MyCopier *self = (MyCopier *) closure; michael@0: michael@0: nsresult rv = self->mInput->Read(buffer, count, countRead); michael@0: if (NS_FAILED(rv)) michael@0: self->mInputCondition = rv; michael@0: else if (*countRead == 0) michael@0: self->mInputCondition = NS_BASE_STREAM_CLOSED; michael@0: michael@0: return self->mInputCondition; michael@0: } michael@0: michael@0: protected: michael@0: PRLock *mLock; michael@0: nsCOMPtr mInput; michael@0: nsCOMPtr mOutput; michael@0: nsresult mInputCondition; michael@0: }; michael@0: michael@0: NS_IMPL_ISUPPORTS(MyCopier, michael@0: nsIInputStreamCallback, michael@0: nsIOutputStreamCallback) michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: /** michael@0: * asynchronously copy file. michael@0: */ michael@0: static nsresult michael@0: RunTest(nsIFile *srcFile, nsIFile *destFile) michael@0: { michael@0: nsresult rv; michael@0: michael@0: LOG(("RunTest\n")); michael@0: michael@0: nsCOMPtr sts = michael@0: do_GetService(kStreamTransportServiceCID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr srcStr; michael@0: rv = NS_NewLocalFileInputStream(getter_AddRefs(srcStr), srcFile); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr destStr; michael@0: rv = NS_NewLocalFileOutputStream(getter_AddRefs(destStr), destFile); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr srcTransport; michael@0: rv = sts->CreateInputTransport(srcStr, int64_t(-1), int64_t(-1), true, michael@0: getter_AddRefs(srcTransport)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr destTransport; michael@0: rv = sts->CreateOutputTransport(destStr, int64_t(-1), int64_t(-1), true, michael@0: getter_AddRefs(destTransport)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: MyCopier *copier = new MyCopier(); michael@0: if (copier == nullptr) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(copier); michael@0: michael@0: rv = copier->AsyncCopy(srcTransport, destTransport); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: PumpEvents(); michael@0: michael@0: NS_RELEASE(copier); michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static nsresult michael@0: RunBlockingTest(nsIFile *srcFile, nsIFile *destFile) michael@0: { michael@0: nsresult rv; michael@0: michael@0: LOG(("RunBlockingTest\n")); michael@0: michael@0: nsCOMPtr sts = michael@0: do_GetService(kStreamTransportServiceCID, &rv); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr srcIn; michael@0: rv = NS_NewLocalFileInputStream(getter_AddRefs(srcIn), srcFile); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr fileOut; michael@0: rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOut), destFile); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr destTransport; michael@0: rv = sts->CreateOutputTransport(fileOut, int64_t(-1), int64_t(-1), michael@0: true, getter_AddRefs(destTransport)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr destOut; michael@0: rv = destTransport->OpenOutputStream(nsITransport::OPEN_BLOCKING, 100, 10, getter_AddRefs(destOut)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: char buf[120]; michael@0: uint32_t n; michael@0: for (;;) { michael@0: rv = srcIn->Read(buf, sizeof(buf), &n); michael@0: if (NS_FAILED(rv) || (n == 0)) return rv; michael@0: michael@0: rv = destOut->Write(buf, n, &n); michael@0: if (NS_FAILED(rv)) return rv; michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: //////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: int michael@0: main(int argc, char* argv[]) michael@0: { michael@0: if (test_common_init(&argc, &argv) != 0) michael@0: return -1; michael@0: michael@0: nsresult rv; michael@0: michael@0: if (argc < 2) { michael@0: printf("usage: %s \n", argv[0]); michael@0: return -1; michael@0: } michael@0: char* fileName = argv[1]; michael@0: { michael@0: nsCOMPtr servMan; michael@0: NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); michael@0: nsCOMPtr registrar = do_QueryInterface(servMan); michael@0: NS_ASSERTION(registrar, "Null nsIComponentRegistrar"); michael@0: if (registrar) michael@0: registrar->AutoRegister(nullptr); michael@0: michael@0: #if defined(PR_LOGGING) michael@0: gTestLog = PR_NewLogModule("Test"); michael@0: #endif michael@0: michael@0: nsCOMPtr srcFile; michael@0: rv = NS_NewNativeLocalFile(nsDependentCString(fileName), false, getter_AddRefs(srcFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsCOMPtr destFile; michael@0: rv = srcFile->Clone(getter_AddRefs(destFile)); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsAutoCString leafName; michael@0: rv = destFile->GetNativeLeafName(leafName); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: nsAutoCString newName(leafName); michael@0: newName.Append(NS_LITERAL_CSTRING(".1")); michael@0: rv = destFile->SetNativeLeafName(newName); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = RunTest(srcFile, destFile); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunTest failed"); michael@0: michael@0: newName = leafName; michael@0: newName.Append(NS_LITERAL_CSTRING(".2")); michael@0: rv = destFile->SetNativeLeafName(newName); michael@0: if (NS_FAILED(rv)) return rv; michael@0: michael@0: rv = RunBlockingTest(srcFile, destFile); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "RunBlockingTest failed"); michael@0: michael@0: // give background threads a chance to finish whatever work they may michael@0: // be doing. michael@0: PR_Sleep(PR_SecondsToInterval(1)); michael@0: } // this scopes the nsCOMPtrs michael@0: // no nsCOMPtrs are allowed to be alive when you call NS_ShutdownXPCOM michael@0: rv = NS_ShutdownXPCOM(nullptr); michael@0: NS_ASSERTION(NS_SUCCEEDED(rv), "NS_ShutdownXPCOM failed"); michael@0: return NS_OK; michael@0: }