int bbcp_File::Read_All(bbcp_BuffPool &inPool, int Vn) { bbcp_FileChkSum *csP = 0; bbcp_BuffPool *outPool; bbcp_Buffer *bP; pthread_t tid; int ec, rc = 0; // Get the size of the file // if ((bytesLeft = FSp->getSize(IOB->FD())) < 0) {bbcp_Emsg("Read", static_cast<int>(-bytesLeft), "stat", iofn); inPool.Abort(); return 200; } // Adjust bytes left based on where we will be reading from // bytesLeft -= nextoffset; if (bytesLeft < 0) {bbcp_Emsg("Read", ESPIPE, "stat", iofn); inPool.Abort(); return 200; } // If this is a real-time copy operation, start the rtcopy object // if (rtCopy && !bbcp_RTCopy.Start(FSp, iofn, IOB->FD())) {inPool.Abort(); return 200; } // Set up checksumming. We would prefer to do this in the calling thread but // this is easier. One day we will generalize buffer piping. // if (bbcp_Config.csOpts & bbcp_csVerIn) {csP = new bbcp_FileChkSum(&inPool, this, bbcp_Config.csType, bbcp_Config.csOpts & bbcp_csVerIO); if ((rc = bbcp_Thread_Start(bbcp_FileCSX, (void *)csP, &tid)) < 0) {bbcp_Emsg("File", rc, "starting file checksum thread."); delete csP; if (rtCopy) bbcp_RTCopy.Stop(); inPool.Abort(); return 201; } outPool = &csP->csPool; } else outPool = &inPool; // Establish logging options // if (bbcp_Config.Options & bbcp_LOGRD) IOB->Log("DISK", 0); // Determine what kind of reading we will do here and do it // // cerr <<"BLOCKSIZE " <<blockSize <<endl; if (bbcp_Config.Options & bbcp_XPIPE) rc = Read_Pipe (&inPool, outPool); else if (blockSize ) rc = Read_Direct(&inPool, outPool); else rc = (Vn > 1 ? Read_Vector(&inPool, outPool, Vn) : Read_Normal(&inPool, outPool)); // Delete the real-time copy object if we have one to kill possible thread // if (rtCopy) bbcp_RTCopy.Stop(); // Check if we ended because with an error // if (rc && rc != -ENOBUFS) {const char *Act=(bbcp_Config.Options & bbcp_XPIPE ? "piping":"writing"); bbcp_Emsg("Read", -rc, Act, iofn); } // Now close the input file, make sure no errors occur here // if ((ec = IOB->Close())) if (!rc) {bbcp_Emsg("Read", -ec, "closing", iofn); rc = ec;} // Prepare an empty buffer to shutdown the buffer pipeline. The offet indicates // how much data should have been sent and received. A negative offset implies // that we encountered an error. // if (!(bP = inPool.getEmptyBuff())) return 255; bP->blen = 0; bP->boff = (rc ? -1 : nextoffset); // Verify check sum if so wanted. Note that is link-level check summing is in // if (csP) {csP->csPool.putFullBuff(bP); bbcp_Thread_Wait(tid); if (!rc && *bbcp_Config.csString) {char *csTxt, *csVal = csP->csObj->Final(&csTxt); if (memcmp(csVal, bbcp_Config.csValue, csP->csObj->csSize())) {bbcp_Fmsg("Read", iofn, "source checksum", bbcp_Config.csString, "does not match", csTxt); rc = EILSEQ; } else {DEBUG(csP->csObj->Type() <<": " <<csTxt <<' ' <<iofn);} } delete csP; } else inPool.putFullBuff(bP); // All done // DEBUG("EOF offset=" <<nextoffset <<" rc=" <<rc <<" fn=" <<iofn); return rc; }
int bbcp_File::Write_All(bbcp_BuffPool& inPool, int nstrms) { bbcp_FileChkSum* csP = 0; bbcp_BuffPool* iBP; pthread_t tid; int ec, rc, csType; // If we have no IOB, then do a simple in-line passthru // if (!IOB) return Passthru(&inPool, &bbcp_CPool, 0, nstrms); // Establish checksum options as well as ordering options. Note that we do // not support checksums in unordered streams and should have been prohibited. // csType = bbcp_Config.csOpts & bbcp_csVerOut ? bbcp_Config.csType : bbcp_csNOP; if (bbcp_Config.csOpts & bbcp_csVerOut || bbcp_Config.Options & bbcp_ORDER) { csP = new bbcp_FileChkSum(&inPool, this, csType, bbcp_Config.csOpts & bbcp_csVerIO, nstrms); nstrms = 1; if ((rc = bbcp_Thread_Start(bbcp_FileCSY, (void*)csP, &tid)) < 0) { bbcp_Emsg("File", rc, "starting file checksum thread."); if (csP) delete csP; if (IOB) IOB->Close(); return 201; } else iBP = &(csP->csPool); } else iBP = &inPool; // Establish logging options // if (bbcp_Config.Options & bbcp_LOGRD) IOB->Log(0, "DISK"); // Determine what kind of writing we will do here and do it // rc = (blockSize ? Write_Direct(iBP, &inPool, nstrms) : Write_Normal(iBP, &inPool, nstrms)); // Check if we ended because of an error or end of file // if (rc < 0 && rc != -ENOBUFS) { const char* Act = (bbcp_Config.Options & bbcp_XPIPE ? "piping" : "writing"); bbcp_Emsg("Write", -rc, Act, iofn); inPool.Abort(); } // Check if we should verify a checksum // if (csP) { bbcp_Thread_Wait(tid); if (!rc && csP->csObj) rc = verChkSum(csP); delete csP; } // If checksums are being printed, send off ours if we have it // if (bbcp_Config.csOpts & bbcp_csPrint && *bbcp_Config.csString) cout << "200 cks: " << bbcp_Config.csString << ' ' << iofn << endl; // Check if we should fsync this file // if (!rc && IOB && (bbcp_Config.Options & bbcp_FSYNC) && (rc = FSp->Fsync((bbcp_Config.Options & bbcp_DSYNC ? iofn : 0), IOB->FD()))) bbcp_Emsg("Write", -rc, "synchronizing", iofn); // Close the output file and make sure it's ok // if (IOB && (ec = IOB->Close())) if (!rc) { bbcp_Emsg("Write", -ec, "closing", iofn); rc = ec; } // All done // return rc; }
int bbcp_Node::RecvFile(bbcp_FileSpec *fp, bbcp_Node *Remote) { static const int wOnly = S_IWUSR; const char *Args = 0, *Act = "opening", *Path = fp->targpath; long tretc = 0; int i, oflag, retc, Mode = wOnly, progtid = 0; long long startoff = 0; pid_t Child[2] = {0,0}; bbcp_File *outFile, *seqFile = 0; bbcp_ZCX *cxp = 0; pthread_t tid, link_tid[BBCP_MAXSTREAMS+4]; bbcp_Timer Elapsed_Timer; bbcp_ProgMon *pmp = 0; float CRatio; // Perform Force or Append processing // if (bbcp_Config.Options & bbcp_XPIPE) {oflag = O_WRONLY; Path = bbcp_Config.snkSpec->pathname; Args = bbcp_Config.snkSpec->fileargs; if (bbcp_Config.snkSpec->Info.Otype != 'p') Act = "running"; else {Mode |= S_IFIFO; if (Args) {bbcp_Fmsg("RecvFile", "Spaces disallowed in named output pipe",Path); return -EINVAL; } } } else if (bbcp_Config.Options & bbcp_FORCE) {if (!(bbcp_Config.Options & bbcp_NOUNLINK)) fp->FSys()->RM(Path); oflag = O_WRONLY | O_CREAT | O_TRUNC; } else if (bbcp_Config.Options & bbcp_APPEND) {if (retc = fp->WriteSigFile()) return retc; if (startoff = fp->targetsz) oflag = O_WRONLY; else oflag = O_CREAT | O_WRONLY; } else oflag = O_WRONLY | O_CREAT | O_EXCL; // Establish mode, we normally make the file write-only // if ( bbcp_Config.Options & bbcp_RTCSNK && !(bbcp_Config.Options & (bbcp_RTCHIDE|bbcp_XPIPE))) Mode = bbcp_Config.Mode|S_IWUSR|S_ISUID; // Tell the user what we are bout to do // if (bbcp_Config.Options & bbcp_BLAB | bbcp_Config.Progint) if (bbcp_Config.Options & bbcp_APPEND) {char buff[32]; sprintf(buff, "%lld", startoff); bbcp_Fmsg("RecvFile","Appending to",Path,"at offset",buff); } else bbcp_Fmsg("RecvFile", "Creating", Path); else DEBUG("Receiving " <<fp->pathname <<" as " <<Path <<" offset=" <<startoff); // Receive the file in a sub-process so that we don't muck with this one // if ((Child[0] = bbcp_OS.Fork()) < 0) return bbcp_Emsg("RecvFile", errno, "forking to create", Path); if (Child[0]) {char buff[128]; Parent_Monitor.Start(0,Remote); DEBUG("Waiting for child " <<Child[0] <<" to finish"); retc = bbcp_OS.Waitpid(Child); Parent_Monitor.Stop(); if (bbcp_Config.Options & bbcp_BLAB) write(STDERR_FILENO, buff, Usage("Target", buff, sizeof(buff))); return retc; } /******************************************************************************* (net)->data_link[i]->BPool->CStage[1]->CStage[0]->CPool->outFile->(file) *******************************************************************************/ // Set Concurrency // bbcp_Thread_MT(bbcp_Config.MTLevel); // Request direct I/O if so wanted // if (bbcp_Config.Options & bbcp_ODIO) {fp->FSys()->DirectIO(1); DEBUG("Direct output requested.");} // Open the file and set the starting offset // Elapsed_Timer.Start(); if (!(outFile = fp->FSys()->Open(Path, oflag, Mode, Args))) return bbcp_Emsg("RecvFile", errno, Act, Path); if (startoff && ((retc = outFile->Seek(startoff)) < 0)) return bbcp_Emsg("RecvFile",retc,"setting write offset for",Path); outFile->setSize(fp->Info.size); // If compression is wanted, set up the compression objects // if (bbcp_Config.Options & bbcp_COMPRESS && !(cxp = setup_CX(0, outFile->ioFD()))) return -ECANCELED; // Start a thread for each data link we have // for (i = 0; i < dlcount; i++) {if ((retc = bbcp_Thread_Start(bbcp_Net2Buff, (void *)data_link[i], &tid))<0) {bbcp_Emsg("RecvFile",retc,"starting net thread for",Path); _exit(100); } link_tid[i] = tid; DEBUG("Thread " <<tid <<" assigned to stream " <<i); } // If we are compressing start the sequence thread now // if (bbcp_Config.Options & bbcp_COMPRESS) {seqFile = new bbcp_File(Path, 0, 0); if ((retc = bbcp_Thread_Start(bbcp_doWrite, (void *)seqFile, &tid))<0) {bbcp_Emsg("RecvFile",retc,"starting disk thread for",Path); _exit(100); } link_tid[dlcount++] = tid; DEBUG("Thread " <<tid <<" assigned to sequencer as stream " <<i); } // Start the parent process monitor. It is stopped at exit. // Parent_Monitor.Start(); // If a periodic progress message is wanted, start a progress thread // if (bbcp_Config.Progint) {pmp = new bbcp_ProgMon(); pmp->Start(outFile, cxp, bbcp_Config.Progint, fp->Info.size-startoff); } // Write the whole file // if (bbcp_Config.Options & bbcp_COMPRESS) retc = outFile->Write_All(bbcp_APool, 1); else retc = outFile->Write_All(bbcp_BPool, bbcp_Config.Streams); DEBUG("File write ended; rc=" <<retc); // Wait for the expansion thread to end // if (bbcp_Config.Options & bbcp_COMPRESS) {if (tretc = (long)bbcp_Thread_Wait(cxp->TID)) retc = 128; DEBUG("File expansion ended; rc=" <<tretc); } // Kill the progress monitor // if (pmp) {DEBUG("Deleting progress monitor"); delete pmp; } // Make sure each thread has terminated normally // for (i = 0; i < dlcount; i++) {if (tretc = (long)bbcp_Thread_Wait(link_tid[i])) retc = 128; DEBUG("Thread " <<link_tid[i] <<" stream " <<i <<" ended; rc=" <<tretc); } // Make sure that all of the bytes were transfered // if (!retc && strncmp(Path, "/dev/null/", 10)) {bbcp_FileInfo Info; if ((retc = fp->FSys()->Stat(Path, &Info)) < 0) {retc = -retc; bbcp_Emsg("RecvFile", retc, "finding", Path); } else if (Info.size != fp->Info.size && Info.mode && !(bbcp_Config.Options & bbcp_NOFSZCHK)) {const char *What = (Info.size < fp->Info.size ? "Not all" : "Too much"); retc = 29; bbcp_Fmsg("RecvFile",What,"data was transfered for",Path); DEBUG("src size=" <<fp->Info.size <<" snk size=" <<Info.size); } } DEBUG("Outfile " <<Path <<" closed"); // Report detailed I/O stats, if so wanted // Elapsed_Timer.Stop(); if (!retc && bbcp_Config.Options & bbcp_VERBOSE) {double ttime; Elapsed_Timer.Report(ttime); Report(ttime, fp, outFile, cxp); } // All done // Parent_Monitor.Stop(); delete outFile; if (cxp) delete(cxp); if (seqFile) delete(seqFile); retc = fp->Finalize(retc); close(1); close(2); DEBUG("Process " <<getpid() <<" exiting with rc=" <<retc); exit(retc); return(retc); // some compilers insist on a return in int functions }
int bbcp_Node::SendFile(bbcp_FileSpec *fp) { const char *Act = "opening"; int i, retc, tretc = 0, Mode = 0; pid_t Child[2] = {0,0}; bbcp_File *inFile; bbcp_ProcMon *TLimit = 0; bbcp_ZCX *cxp; pthread_t tid, link_tid[BBCP_MAXSTREAMS+1]; // Set open options (check for pipes) // if (bbcp_Config.Options & bbcp_XPIPE) {if (fp->Info.Otype == 'p') Mode = S_IFIFO; else Act = "running"; } // Send the file in a sub-process so that we don't muck with this one // DEBUG("Sending file " <<fp->targpath <<"; offset=" <<fp->targetsz); if ((Child[0] = bbcp_OS.Fork()) < 0) return bbcp_Emsg("SendFile", errno, "forking to send", fp->pathname); if (Child[0]) {char buff[128]; Parent_Monitor.Start(); retc = bbcp_OS.Waitpid(Child); Parent_Monitor.Stop(); if (bbcp_Config.Options & bbcp_BLAB) write(STDERR_FILENO, buff, Usage("Source", buff, sizeof(buff))); return retc; } /******************************************************************************* (file)->inFile->CPool->CStage[0]->CStage[1]->BPool->data_link[i]->(net) *******************************************************************************/ // Set Concurrency // bbcp_Thread_MT(bbcp_Config.MTLevel); // Request direct I/O if so wanted // if (bbcp_Config.Options & bbcp_IDIO) {fp->FSys()->DirectIO(1); DEBUG("Direct input requested.");} // Open the input file and set starting offset // if (!(inFile = fp->FSys()->Open(fp->pathname,O_RDONLY,Mode,fp->fileargs))) {bbcp_Emsg("SendFile", errno, Act, fp->pathname); exit(2); } if (fp->targetsz && ((retc = inFile->Seek(fp->targetsz)) < 0)) return bbcp_Emsg("SendFile",retc,"setting read offset for",fp->pathname); // If compression is wanted, set up the compression objects // if (bbcp_Config.Options & bbcp_COMPRESS && !(cxp = setup_CX(1, inFile->ioFD()))) return -ECANCELED; // Start a thread for each data link we have // for (i = 0; i < dlcount; i++) {if ((retc = bbcp_Thread_Start(bbcp_Buff2Net, (void *)data_link[i], &tid))<0) {bbcp_Emsg("SendFile",retc,"starting net thread for",fp->pathname); _exit(100); } link_tid[i] = tid; if (i >= iocount) {DEBUG("Thread " <<tid <<" assigned to data clocker");} else {DEBUG("Thread " <<tid <<" assigned to stream " <<i);} } // Start the parent monitor // Parent_Monitor.Start(); // Start the Transfer Time Limit // if (bbcp_Config.TimeLimit) {TLimit = new bbcp_ProcMon(); TLimit->Start(bbcp_Config.TimeLimit, &bbcp_BPool); } // Read the whole file // if (bbcp_Config.Options & bbcp_COMPRESS) retc=inFile->Read_All(bbcp_APool,1); else retc = inFile->Read_All(bbcp_BPool, bbcp_Config.Bfact); DEBUG("File read ended; rc=" <<retc); // Wait for compression thread to end // if (bbcp_Config.Options & bbcp_COMPRESS) {if (tretc = (long)bbcp_Thread_Wait(cxp->TID)) retc = 128; DEBUG("File compression ended; rc=" <<tretc); delete cxp; } // Make sure each link thread has terminated normally. // for (i = 0; i < iocount; i++) {if (tretc = (long)bbcp_Thread_Wait(link_tid[i])) retc = 128; DEBUG("Thread " <<link_tid[i] <<" stream " <<i <<" ended; rc=" <<tretc); } // All done // if (TLimit) delete TLimit; Parent_Monitor.Stop(); delete inFile; close(1); close(2); DEBUG("Process " <<getpid() <<" exiting with rc=" <<retc); exit(retc); return(retc); // some compilers insist on a return in int functions }
int bbcp_Thread_Run(void *(*proc)(void *), void *arg, pthread_t *tid) {int retc = bbcp_Thread_Start(proc, arg, tid); if (!retc) pthread_detach(*tid); return retc; }