Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions 3rdparty/pzip/include/pzip/file_task.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ class FileTask {
fs::file_status status; // 文件状态
uintmax_t fileSize = 0; // 原始文件大小
ZipFileHeader header; // ZIP 头信息
bool isSymlink = false; // 是否是符号链接
std::string symlinkTarget; // 符号链接目标路径

// 压缩器(由 Archiver 管理)
z_stream* compressor = nullptr;
Expand Down
15 changes: 15 additions & 0 deletions 3rdparty/pzip/src/archiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ Error Archiver::compress(FileTask* task) {
return Error();
}

if (task->isSymlink) {
const auto& target = task->symlinkTarget;
task->write(reinterpret_cast<const uint8_t*>(target.data()), target.size());
task->header.crc32 = ::crc32(0, reinterpret_cast<const Bytef*>(target.data()), target.size());
return Error();
}

std::ifstream file(task->path, std::ios::binary);
if (!file.is_open()) {
return Error(ErrorCode::FILE_OPEN_ERROR, "Cannot open file: " + task->path.string());
Expand Down Expand Up @@ -271,6 +278,14 @@ void Archiver::populateHeader(FileTask* task) {
h.uncompressedSize = 0;
h.compressedSize = 0;
h.crc32 = 0;
} else if (task->isSymlink) {
// 符号链接:存储链接目标
h.method = ZIP_METHOD_STORE;
h.flags &= ~ZIP_FLAG_DATA_DESCRIPTOR;
h.uncompressedSize = task->symlinkTarget.size();
h.compressedSize = task->symlinkTarget.size();
// 设置 Unix 符号链接属性
h.externalAttr = static_cast<uint32_t>(S_IFLNK | 0777) << 16;
} else {
h.method = ZIP_METHOD_DEFLATE;
h.flags |= ZIP_FLAG_DATA_DESCRIPTOR;
Expand Down
40 changes: 33 additions & 7 deletions 3rdparty/pzip/src/file_task.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,29 @@ Error FileTask::reset(const fs::path& filePath, const fs::path& relativeTo) {

bufferUsed_ = 0;
written_ = 0;
isSymlink = false;
symlinkTarget.clear();

// 设置新文件信息
path = filePath;

std::error_code ec;
status = fs::status(path, ec);
// 使用 symlink_status 不跟随符号链接
status = fs::symlink_status(path, ec);
if (ec) {
return Error(ErrorCode::FILE_NOT_FOUND, "Cannot stat file: " + path.string());
}

if (fs::is_regular_file(status)) {
// 检测符号链接
isSymlink = fs::is_symlink(status);
if (isSymlink) {
// 读取符号链接目标
symlinkTarget = fs::read_symlink(path, ec).string();
if (ec) {
return Error(ErrorCode::FILE_READ_ERROR, "Cannot read symlink target: " + path.string());
}
fileSize = symlinkTarget.size();
} else if (fs::is_regular_file(status)) {
fileSize = fs::file_size(path, ec);
if (ec) {
return Error(ErrorCode::FILE_READ_ERROR, "Cannot get file size: " + path.string());
Expand All @@ -105,13 +117,27 @@ Error FileTask::reset(const fs::path& filePath, const fs::path& relativeTo) {
header = ZipFileHeader();

// 设置相对路径名
// 注意:fs::relative() 会解析符号链接,所以使用 path 迭代器手动计算
if (!relativeTo.empty()) {
fs::path relPath = fs::relative(path, relativeTo, ec);
if (ec) {
// 如果无法计算相对路径,使用文件名
header.name = path.filename().string();
} else {
// 使用 path 迭代器跳过共同前缀
auto pathIt = path.begin();
auto relIt = relativeTo.begin();

while (pathIt != path.end() && relIt != relativeTo.end() && *pathIt == *relIt) {
++pathIt;
++relIt;
}

// 构建相对路径
fs::path relPath;
for (; pathIt != path.end(); ++pathIt) {
relPath /= *pathIt;
}

if (!relPath.empty()) {
header.name = utils::toZipPath(relPath);
} else {
header.name = utils::toZipPath(path.filename());
}
} else {
header.name = utils::toZipPath(path.filename());
Expand Down