bool UploadManager::prepareFile(UserConnection& aSource, const string& aType, const string& aFile, int64_t aStartPos, int64_t aBytes, bool listRecursive) { if(aFile.empty() || aStartPos < 0 || aBytes < -1 || aBytes == 0) { aSource.fileNotAvail("Invalid request"); return false; } InputStream* is = 0; int64_t start = 0; int64_t bytesLeft = 0; int64_t size = 0; bool userlist = (aFile == Transfer::USER_LIST_NAME_BZ || aFile == Transfer::USER_LIST_NAME); bool free = userlist; bool leaves = false; bool partList = false; string sourceFile; try { if(aType == Transfer::TYPE_FILE) { sourceFile = ShareManager::getInstance()->toReal(aFile); if(aFile == Transfer::USER_LIST_NAME) { // Unpack before sending... string bz2 = File(sourceFile, File::READ, File::OPEN).read(); string xml; CryptoManager::getInstance()->decodeBZ2(reinterpret_cast<const uint8_t*>(bz2.data()), bz2.size(), xml); // Clear to save some memory... string().swap(bz2); is = new MemoryInputStream(xml); start = 0; bytesLeft = size = xml.size(); } else { File* f = new File(sourceFile, File::READ, File::OPEN); start = aStartPos; size = f->getSize(); bytesLeft = (aBytes == -1) ? size : aBytes; if(size < (start + bytesLeft)) { aSource.fileNotAvail(); delete f; return false; } free = free || (size <= (int64_t)(SETTING(FREE_SLOTS_SIZE) * 1024) ); f->setPos(start); is = f; if((start + bytesLeft) < size) { is = new LimitedInputStream<true>(is, aBytes); } } } else if(aType == Transfer::TYPE_TTHL) { sourceFile = ShareManager::getInstance()->toReal(aFile); MemoryInputStream* mis = ShareManager::getInstance()->getTree(aFile); if(!mis) { aSource.fileNotAvail(); return false; } start = 0; bytesLeft = size = mis->getSize(); is = mis; leaves = true; free = true; } else { aSource.fileNotAvail("Unknown file type"); return false; } } catch(const ShareException& e) { aSource.fileNotAvail(e.getError()); return false; } catch(const Exception& e) { LogManager::getInstance()->message(STRING(UNABLE_TO_SEND_FILE) + sourceFile + ": " + e.getError()); aSource.fileNotAvail(); return false; } Lock l(cs); bool extraSlot = false; if(!aSource.isSet(UserConnection::FLAG_HASSLOT)) { bool hasReserved = (reservedSlots.find(aSource.getUser()) != reservedSlots.end()); bool isFavorite = aSource.getUser()->getFavoriteGrantSlot(); if(!(hasReserved || isFavorite || getFreeSlots() > 0 || getAutoSlot())) { bool supportsFree = aSource.isSet(UserConnection::FLAG_SUPPORTS_MINISLOTS); bool allowedFree = aSource.isSet(UserConnection::FLAG_HASEXTRASLOT) || aSource.isSet(UserConnection::FLAG_OP) || getFreeExtraSlots() > 0; if(free && supportsFree && allowedFree) { extraSlot = true; } else { delete is; aSource.maxedOut(); // Check for tth root identifier string tFile = aFile; if (tFile.compare(0, 4, "TTH/") == 0) tFile = ShareManager::getInstance()->toVirtual(TTHValue(aFile.substr(4))); addFailedUpload(aSource, tFile + " (" + Util::toString((aStartPos*1000/(size+10))/10.0)+"% of " + Util::formatBytes(size) + " done)"); aSource.disconnect(); return false; } } else { clearUserFiles(aSource.getUser()); // this user is using a full slot, nix them. } setLastGrant(GET_TICK()); } Upload* u = new Upload(aSource); u->setStream(is); if(aBytes == -1) u->setSize(size); else u->setSize(start + bytesLeft); u->setStartPos(start); u->setSourceFile(sourceFile); if(userlist) u->setFlag(Upload::FLAG_USER_LIST); if(leaves) u->setFlag(Upload::FLAG_TTH_LEAVES); if(partList) u->setFlag(Upload::FLAG_PARTIAL_LIST); uploads.push_back(u); if(!aSource.isSet(UserConnection::FLAG_HASSLOT)) { if(extraSlot) { if(!aSource.isSet(UserConnection::FLAG_HASEXTRASLOT)) { aSource.setFlag(UserConnection::FLAG_HASEXTRASLOT); extra++; } } else { if(aSource.isSet(UserConnection::FLAG_HASEXTRASLOT)) { aSource.unsetFlag(UserConnection::FLAG_HASEXTRASLOT); extra--; } aSource.setFlag(UserConnection::FLAG_HASSLOT); running++; } reservedSlots.erase(aSource.getUser()); } return true; }