Esempio n. 1
0
BOOL CDownload::OpenDownload()
{
	if ( m_sName.IsEmpty() )
		return TRUE;	// Download has no name yet, postponing

	if ( IsFileOpen() )
		return TRUE;	// Already opened

	SetModified();

	if ( ( IsTorrent() && ! ( m_oSHA1 || m_oTiger || m_oED2K || m_oMD5 ) ) ?
		 Open( m_pTorrent ) :
		 Open( this ) )
		return TRUE;

	if ( m_nSize != SIZE_UNKNOWN && ! Downloads.IsSpaceAvailable( m_nSize, Downloads.dlPathIncomplete ) )
	{
		CString strFileError;
		strFileError.Format( LoadString( IDS_DOWNLOAD_DISK_SPACE ), (LPCTSTR)m_sName, (LPCTSTR)Settings.SmartVolume( m_nSize ) );
		SetFileError( ERROR_DISK_FULL, strFileError );

		theApp.Message( MSG_ERROR, L"%s", (LPCTSTR)strFileError );
	}

	return FALSE;
}
Esempio n. 2
0
/*
 * Write data in buffer to disk cache file.
 *
 * This thread is a consumer for the double buffer thread.
 * A conumser must wait until the buffer is not empty, retrieve its
 * data, and then notify the producer that the buffer is not full.
 */
int
DiskCacheWrite(
	FileInfo_t *file,
	int fd)
{
	CircularBuffer_t *writer;
	boolean_t checksum;	/* use checksum enabled on file */
	boolean_t multivolume;	/* staging a multivolume file */
	boolean_t verify;	/* staging a file for data verification */
	sam_ioctl_swrite_t swrite;
	int position;		/* block position for debugging */
	char *out;		/* output buffer pointer */
	int nbytes;
	int nwritten;

/* FIXME comments */
	int copy;
	boolean_t closeDiskcache;
	/* LINTED variable unused in function */
	time_t endTime;
	/* LINTED variable unused in function */
	int secs;

	/* Wait for file to stage. */
	ThreadStateWait(&IoThread->io_writeReady);

	writer = IoThread->io_writer;

	copy = file->copy;

	memset(&swrite, 0, sizeof (sam_ioctl_swrite_t));

	if (GET_FLAG(file->flags, FI_DCACHE)) {
		swrite.offset += file->write_off;
	}

	checksum = ifChecksum(file);
	verify = ifVerify(file);
	multivolume = ifMultiVolume(file);

	dataToWrite = IoThread->io_size;

	cancel = B_FALSE;
	readErrno = 0;
	position = 0;		/* block written to disk for file */

	Trace(TR_FILES, "Write disk inode: %d.%d offset: %lld len: %lld",
	    file->id.ino, file->id.gen, swrite.offset, dataToWrite);

	while (DATA_TO_WRITE()) {

		/*
		 * Wait until the write buffer is not empty.
		 * Retrieve data at 'out' position.
		 * If archive read thread found an error during a read
		 * from media, positioning failure or tar header validation
		 * the error flag will be set in io thead control structure.
		 */
		out = CircularIoAvail(writer, &nbytes, &readErrno);
		if (readErrno != 0) {
			SetErrno = readErrno;
			Trace(TR_ERR,
			    "Error in writer buffer, slot:%d readErrno:%d",
			    CircularIoSlot(IoThread->io_writer, out),
			    readErrno);
			break;
		}

		/* If not a full block of data left to write. */
		if (dataToWrite < nbytes) {
			nbytes = dataToWrite;
		}

		Trace(TR_DEBUG,
		    "Write block: %d buf: %d [0x%x] offset: %lld len: %d",
		    position, CircularIoSlot(IoThread->io_writer, out),
		    (int)out, swrite.offset, nbytes);

		swrite.buf.ptr = out;
		swrite.nbyte = nbytes;

		/* Accumulate checksum value. */
		if (checksum == B_TRUE) {
			Checksum(out, nbytes);
		}

		/* Write data block to disk cache. */
		if (verify == B_FALSE) {
			nwritten = ioctl(fd, F_SWRITE, &swrite);

			if (nwritten != nbytes) {
				Trace(TR_ERR,
				    "Write error: %d fd: %d nbyte: %d "
				    "offset: %lld",
				    errno, fd, swrite.nbyte, swrite.offset);
				/*
				 * Cancel stage request, this will be picked
				 * up in the reader and doublebuffer threads.
				 */
				Trace(TR_MISC,
				    "Cancelled(write error) inode: %d.%d",
				    file->id.ino, file->id.gen);
				SET_FLAG(IoThread->io_flags, IO_cancel);

				if (errno == ECANCELED) {
					cancel = B_TRUE;
					SET_FLAG(file->flags, FI_CANCEL);
				} else {
					readErrno = errno;
					SET_FLAG(file->flags, FI_WRITE_ERROR);
				}
			}
		}

		/*
		 * Wait for checksum thread to complete on the data block
		 * before allowing the double buffer thread to reuse
		 * the 'out' buffer.
		 */
		if (checksum == B_TRUE && nbytes > 0) {
			ChecksumWait();
		}

		/*
		 * Write complete.  Advance write buffer's 'out'
		 * pointer and notify double buffer thread that the buffer
		 * is not empty.
		 */
		CircularIoAdvanceOut(writer);

		file->stage_size += nbytes;
		swrite.offset += nbytes;
		dataToWrite -= nbytes;
		ASSERT_WAIT_FOR_DBX(dataToWrite >= 0);

		position++;

		Trace(TR_DEBUG, "Wrote %d bytes left: %lld (%d/%d)",
		    nbytes, dataToWrite, readErrno, cancel);
	}

	Trace(TR_FILES, "Write disk complete inode: %d.%d",
	    file->id.ino, file->id.gen);

	/*
	 * If no error AND cancel request, close disk cache file.
	 * If no error AND no more VSNs,   close disk cache file.
	 * If error OR more VSNs to stage, save disk cache information.
	 */

	/*
	 * There are a number of scenarios under which to determine
	 * whether to close the disk cache file or leave it open for
	 * a future request.
	 *
	 * If no error AND cancel,		close disk cache file.
	 * If no error AND not multivolume,	close disk cache file.
	 * If no error AND multivolume AND stage_n, close disk cache file.
	 * If error OR more VSNs to stage, 	save disk cache information.
	 */

	/* If no error AND cancel, close disk cache file. */
	if (readErrno == 0 && cancel == B_TRUE) {
		closeDiskcache = B_TRUE;

	/* If no error AND not multivolume, close disk cache file. */
	} else if (readErrno == 0 && multivolume == 0) {
		closeDiskcache = B_TRUE;

	/* If no error AND multivolume AND stage_n, close disk cache file. */
	} else if (readErrno == 0 && multivolume != 0 &&
	    GET_FLAG(file->flags, FI_STAGE_NEVER) &&
	    file->stage_size == file->len) {

		closeDiskcache = B_TRUE;

	/* Else, an error OR more VSNs to stage, save disk cache information. */
	} else {
		/*
		 * If no device available or interrupted system call,
		 * close disk cache.
		 */
		if (readErrno == ENODEV || readErrno == EINTR) {
			closeDiskcache = B_TRUE;
		} else {
			closeDiskcache = B_FALSE;
		}
	}

	/*
	 * Checksumming may have found an error.
	 */
	if (closeDiskcache == B_TRUE && checksum == B_TRUE) {
		/*
		 * Do not check for checksum error if request was
		 * cancelled or an I/O error occurred.
		 */
		if (cancel == B_FALSE && readErrno == 0) {

			readErrno = ChecksumCompare(fd, &file->id);

			if (readErrno != 0) {
				closeDiskcache = B_FALSE;
				swrite.offset = 0;

				if (verify == B_TRUE) {
					SetErrno = 0;	/* set for trace */
					Trace(TR_ERR, "Unable to verify "
					    "inode: %d.%d copy: %d errno: %d",
					    file->id.ino, file->id.gen,
					    copy + 1, readErrno);

					closeDiskcache = B_TRUE;
				}
			} else {
				if (verify == B_TRUE) {
					setVerify(file);
				}
			}

		} else {
			if (verify == B_TRUE) {
				SetErrno = 0;	/* set for trace */
				Trace(TR_ERR, "Unable to verify "
				    "inode: %d.%d copy: %d errno: %d",
				    file->id.ino, file->id.gen,
				    copy + 1, errno);
			}
		}
		checksum = B_FALSE;
	}

	if (closeDiskcache == B_TRUE) {
		(void) close(fd);
		CLEAR_FLAG(file->flags, FI_DCACHE);
		NumOpenFiles--;

	} else {
		SetFileError(file, fd, swrite.offset, readErrno);
		if (checksum == B_TRUE && multivolume != 0) {
			file->csum_val = ChecksumGetVal();
		}
	}

	/* Done writing staged file. */
	ThreadStatePost(&IoThread->io_writeDone);

	return (file->error);
}
Esempio n. 3
0
BOOL CDownload::SeedTorrent()
{
	if ( IsMoving() || IsCompleted() )
		return FALSE;

	ASSERT( IsFileOpen() == FALSE );
	if ( IsFileOpen() )
		return FALSE;

	ASSERT( m_pTorrent.GetCount() );

	augment::auto_ptr< CFragmentedFile > pFragmentedFile( new CFragmentedFile );
	if ( ! pFragmentedFile.get() )
		return FALSE;	// Out of memory

	if ( ! pFragmentedFile->Open( m_pTorrent, FALSE ) )
	{
		SetFileError( pFragmentedFile->GetFileError(), pFragmentedFile->GetFileErrorString() );
		return FALSE;
	}

	AttachFile( pFragmentedFile.release() );

	if ( IsSingleFileTorrent() )
	{
		// Refill missing hashes for single-file torrent
		const CBTInfo::CBTFile* pBTFile = m_pTorrent.m_pFiles.GetHead();
		if ( ! m_pTorrent.m_oSHA1 && pBTFile->m_oSHA1 )
			m_pTorrent.m_oSHA1 = pBTFile->m_oSHA1;
		if ( ! m_pTorrent.m_oTiger && pBTFile->m_oTiger )
			m_pTorrent.m_oTiger = pBTFile->m_oTiger;
		if ( ! m_pTorrent.m_oED2K && pBTFile->m_oED2K )
			m_pTorrent.m_oED2K = pBTFile->m_oED2K;
		if ( ! m_pTorrent.m_oMD5 && pBTFile->m_oMD5 )
			m_pTorrent.m_oMD5 = pBTFile->m_oMD5;

		// Refill missed hash for library file
		CQuickLock oLock( Library.m_pSection );
		if ( CLibraryFile* pLibraryFile = LibraryMaps.LookupFileByPath( pBTFile->FindFile() ) )
		{
			if ( ! pLibraryFile->m_oBTH && m_oBTH )
			{
				Library.RemoveFile( pLibraryFile );
				pLibraryFile->m_oBTH = m_oBTH;
				Library.AddFile( pLibraryFile );
			}
		}
	}

	// Refill missing hashes
	if ( ! m_oSHA1 && m_pTorrent.m_oSHA1 )
		m_oSHA1 = m_pTorrent.m_oSHA1;
	if ( ! m_oTiger && m_pTorrent.m_oTiger )
		 m_oTiger = m_pTorrent.m_oTiger;
	if ( ! m_oED2K && m_pTorrent.m_oED2K )
		m_oED2K = m_pTorrent.m_oED2K;
	if ( ! m_oMD5 && m_pTorrent.m_oMD5 )
		m_oMD5 = m_pTorrent.m_oMD5;

	GenerateTorrentDownloadID();

	m_bSeeding = TRUE;
	m_bComplete = true;
	m_tCompleted = GetTickCount();
	m_bVerify = TRI_TRUE;

	memset( m_pTorrentBlock, TRI_TRUE, m_nTorrentBlock );
	m_nTorrentSuccess = m_nTorrentBlock;

	MakeComplete();
	ResetVerification();

	return TRUE;
}
Esempio n. 4
0
/*
 * Stage all files in the stream.
 */
static void
copyStream()
{
	int rval;
	FileInfo_t *file;
	int dcache;
	boolean_t reject;

	StageInit(Stream->vsn);

	/* Set loading flag for this stream. */
	PthreadMutexLock(&Stream->mutex);
	SET_FLAG(Stream->flags, SR_LOADING);
	PthreadMutexUnlock(&Stream->mutex);

	rval = LoadVolume();

	/* Reject if mount/open failed. */
	if (rval != 0) {
		PthreadMutexLock(&Stream->mutex);
		removeDcachedFile(Stream, rval);

		if (rval == ENODEV) {
			Stream->context = 0;
			PthreadMutexUnlock(&Stream->mutex);
			rejectRequest(0, B_TRUE);
			SET_FLAG(Instance->ci_flags, CI_shutdown);
		} else {
			PthreadMutexUnlock(&Stream->mutex);
			SendCustMsg(HERE, 19017, Stream->vsn);
			rejectRequest(rval, B_TRUE);
		}

		StageEnd();
		return;
	}

	/* VSN load has completed. */
	checkBuffers(Stream->vsn);

	PthreadMutexLock(&Stream->mutex);
	CLEAR_FLAG(Stream->flags, SR_LOADING);

	Instance->ci_seqnum = Stream->seqnum;
	reject = B_FALSE;

	/*
	 * Copy all files in stage stream request.  The files have
	 * been ordered to eliminate backward media positioning.
	 */

	while (STREAM_IS_VALID() && reject == B_FALSE) {

		/* Stop staging if parent died. */
		if (getppid() == 1) {
			SetErrno = 0;		/* set for trace */
			Trace(TR_ERR, "Detected stager daemon exit");

			Stream->first = EOS;
			SET_FLAG(Instance->ci_flags, CI_shutdown);
			break;
		}

		file = GetFile(Stream->first);

		PthreadMutexLock(&file->mutex);
		PthreadMutexUnlock(&Stream->mutex);

		/*
		 * If the first vsn, clear bytes read count.
		 * And if multivolume and stage -n set, initialize
		 * residual length.
		 */
		if (file->vsn_cnt == 0) {
			file->read = 0;
			if (GET_FLAG(file->flags, FI_MULTIVOL) &&
			    GET_FLAG(file->flags, FI_STAGE_NEVER)) {
				file->residlen = file->len;
			} else {
				file->residlen = 0;
			}
		}

		SET_FLAG(file->flags, FI_ACTIVE);

		PthreadMutexUnlock(&file->mutex);

		/* Set file in io control structure for archive read thread. */
		setIoThread(file);

		/* Log stage start. */
		file->eq = IoThread->io_drive;
		LogIt(LOG_STAGE_START, file);

		/*
		 * Check if last request was canceled.  If the last request
		 * was canceled, invalidate i/o buffers and clear cancel
		 * flag in the control structure.
		 */
		if (GET_FLAG(IoThread->io_flags, IO_cancel)) {
			ResetBuffers();
			CLEAR_FLAG(IoThread->io_flags, IO_cancel);
		}

		/*
		 * Next archive file.  If disk archive, we may be opening
		 * a disk archive tarball.
		 */
		if ((rval = NextArchiveFile()) == 0) {
			/* Prepare filesystem to receive staged file. */
			dcache = DiskCacheOpen(file);

		} else {
			/* Unable to open disk archive.  Error request. */
			Trace(TR_ERR, "Unable to open disk archive "
			    "copy: %d inode: %d.%d errno: %d",
			    file->copy + 1, file->id.ino, file->id.gen, errno);
			dcache = -1;
			file->error = errno;
			SendErrorResponse(file);
		}

		if (dcache >= 0 && rval == 0) {
			/*
			 * Notify reader thread that next file in stream
			 * is ready to be staged.
			 */
			ThreadStatePost(&IoThread->io_readReady);

			/* Write data to disk cache. */
			rval = DiskCacheWrite(file, dcache);

			if (rval != 0) {
				SendErrorResponse(file);

				/* Check if number of stream errors exceeded. */
				reject = ifMaxStreamErrors(file);
			}

			ThreadStateWait(&IoThread->io_readDone);

		} else if (rval != 0 && dcache >= 0) {
			/* Setup for error handling. */
			SetFileError(file, dcache, 0, EIO);
			SendErrorResponse(file);
		}

		EndArchiveFile();

		/* Remove file from stream before marking it as done. */
		PthreadMutexLock(&Stream->mutex);
		Stream->first = file->next;

		/* Device not available. */
		if (file->error == ENODEV) {
			SetErrno = 0;	/* set for trace */
			Trace(TR_ERR, "No device available");

			reject = B_TRUE;
			if (NumOpenFiles <= 0 && Instance->ci_first == NULL) {
				SET_FLAG(Instance->ci_flags, CI_shutdown);
				Instance->ci_busy = B_TRUE;
			}
		}

		/* Mark file staging as done. */
		SetStageDone(file);
		Stream->count--;

		if (Stream->first == EOS) {
			Stream->last = EOS;
		}

	}

	/* Reject rest of stages in this stream. */
	if (reject == B_TRUE) {
		if (Stream->first > EOS) {
			removeDcachedFile(Stream, ENODEV);
		}
		PthreadMutexUnlock(&Stream->mutex);
		rejectRequest(ENODEV, B_FALSE);
		PthreadMutexLock(&Stream->mutex);
	}

	/* Remove copy request, no one is waiting on it. */
	RemoveMapFile(copyRequestPath, Request, sizeof (CopyRequestInfo_t));
	Request = NULL;

	/* Ready to unload.  Mark stream as done. */
	SET_FLAG(Stream->flags, SR_DONE);
	PthreadMutexUnlock(&Stream->mutex);

	UnloadVolume();

	/*
	 * Unmap pages of memory.  Stream's memory
	 * mapped file is removed in parent.
	 */
	UnMapFile(Stream, sizeof (StreamInfo_t));
	Stream = NULL;

	StageEnd();
}