CString FileSystem::MakeCanonicalPath(const char* path) { int len = strlen(path); if (!strncmp("\\\\?\\", path, 4) || len == 0) { return path; } std::vector<CString> components = Util::SplitStr(path, "\\/"); for (uint32 i = 1; i < components.size(); i++) { if (!strcmp(components[i], "..")) { components.erase(components.begin() + i - 1, components.begin() + i + 1); i -= 2; } else if (!strcmp(components[i], ".")) { components.erase(components.begin() + i); i--; } } StringBuilder result; result.Reserve(strlen(path)); if (!strncmp("\\\\", path, 2)) { result.Append("\\\\"); } bool first = true; for (CString& comp : components) { if (comp.Length() > 0) { if (!first) { result.Append("\\"); } result.Append(comp); first = false; } } if ((path[len - 1] == '\\' || path[len - 1] == '/' || (len > 3 && !strcmp(path + len - 3, "\\..")) || (len > 2 && !strcmp(path + len - 2, "\\."))) && result[result.Length() - 1] != '\\') { result.Append("\\"); } return *result; }
void NntpProcessor::SendSegment() { detail("[%i] Sending segment %s (%i=%lli:%i)", m_id, *m_filename, m_part, (long long)m_offset, m_size); if (m_speed > 0) { m_start = Util::GetCurrentTicks(); } BString<1024> fullFilename("%s/%s", m_dataDir, *m_filename); BString<1024> cacheFileDir("%s/%s", m_cacheDir, *m_filename); BString<1024> cacheFileName("%i=%lli-%i", m_part, (long long)m_offset, m_size); BString<1024> cacheFullFilename("%s/%s", *cacheFileDir, *cacheFileName); BString<1024> cacheKey("%s/%s", *m_filename, *cacheFileName); const char* cachedData = nullptr; int cachedSize; if (m_cache) { m_cache->Find(cacheKey, cachedData, cachedSize); } DiskFile cacheFile; bool readCache = !cachedData && m_cacheDir && cacheFile.Open(cacheFullFilename, DiskFile::omRead); bool writeCache = !cachedData && m_cacheDir && !readCache; StringBuilder cacheMem; if (m_cache && !cachedData) { cacheMem.Reserve((int)(m_size * 1.1)); } CString errmsg; if (writeCache && !FileSystem::ForceDirectories(cacheFileDir, errmsg)) { error("Could not create directory %s: %s", *cacheFileDir, *errmsg); } if (writeCache && !cacheFile.Open(cacheFullFilename, DiskFile::omWrite)) { error("Could not create file %s: %s", *cacheFullFilename, *FileSystem::GetLastErrorMessage()); } if (!cachedData && !readCache && !FileSystem::FileExists(fullFilename)) { m_connection->WriteLine(CString::FormatStr("430 Article not found\r\n")); return; } YEncoder encoder(fullFilename, m_part, m_offset, m_size, [proc = this, writeCache, &cacheFile, &cacheMem](const char* buf, int size) { if (proc->m_cache) { cacheMem.Append(buf); } if (writeCache) { cacheFile.Write(buf, size); } proc->SendData(buf, size); }); if (!cachedData && !readCache && !encoder.OpenFile(errmsg)) { m_connection->WriteLine(CString::FormatStr("403 %s\r\n", *errmsg)); return; } m_connection->WriteLine(CString::FormatStr("%i, 0 %s\r\n", m_sendHeaders ? 222 : 220, m_messageid)); if (m_sendHeaders) { m_connection->WriteLine(CString::FormatStr("Message-ID: %s\r\n", m_messageid)); m_connection->WriteLine(CString::FormatStr("Subject: \"%s\"\r\n", FileSystem::BaseFileName(m_filename))); m_connection->WriteLine("\r\n"); } if (cachedData) { SendData(cachedData, cachedSize); } else if (readCache) { cacheFile.Seek(0, DiskFile::soEnd); int size = (int)cacheFile.Position(); CharBuffer buf(size); cacheFile.Seek(0); if (cacheFile.Read((char*)buf, size) != size) { error("Could not read file %s: %s", *cacheFullFilename, *FileSystem::GetLastErrorMessage()); } if (m_cache) { cacheMem.Append(buf, size); } SendData(buf, size); } else { encoder.WriteSegment(); } if (!cachedData && cacheMem.Length() > 0) { m_cache->Append(cacheKey, cacheMem, cacheMem.Length()); } m_connection->WriteLine(".\r\n"); }