压缩文件夹路径末尾没有分割符,压缩失败问题对应

Signed-off-by: hanhaibin <hanhaibin@huawei.com>
This commit is contained in:
hanhaibin 2022-03-09 06:13:11 +08:00
parent 10038d18cb
commit 0c4a503903
8 changed files with 196 additions and 77 deletions

6
tools/zip/BUILD.gn Normal file → Executable file
View File

@ -17,6 +17,7 @@ import("//foundation/appexecfwk/standard/appexecfwk.gni")
config("zip_config") {
include_dirs = [
"include",
"//utils/native/base/include",
"//third_party/libuv/include",
"//third_party/node/src",
"//third_party/zlib",
@ -52,18 +53,17 @@ ohos_shared_library("zlib") {
"${common_path}:libappexecfwk_common",
"//third_party/libuv:uv_static",
"//third_party/zlib:libz",
"//utils/native/base:utils",
]
external_deps = [
"ability_base:want",
"ability_runtime:task_dispatcher",
"bundle_framework:appexecfwk_base",
"bundle_framework:appexecfwk_core",
"eventhandler:libeventhandler",
"hilog_native:libhilog_base",
"hiviewdfx_hilog_native:libhilog",
"ipc:ipc_core",
"napi:ace_napi",
"utils_base:utils",
]
install_enable = true

5
tools/zip/include/file_path.h Normal file → Executable file
View File

@ -51,7 +51,8 @@ public:
static bool CreateDirectory(const FilePath &fullPath);
static bool DirectoryExists(const FilePath &path);
static bool PathIsValid(const FilePath &path);
static bool IsDir(const FilePath &path);
static bool GetZipAllDirFiles(const std::string &path, std::vector<std::string> &files);
// Returns a FilePath by appending a separator and the supplied path
// component to this object's path. Append takes care to avoid adding
// excessive separators if this object's path already ends with a separator.
@ -60,6 +61,7 @@ public:
// it is an error to pass an absolute path.
FilePath Append(const std::string &component);
FilePath Append(FilePath &component);
void AppendSeparator(void);
// If IsParent(child) holds, appends to path (if non-NULL) the
// relative path to child and returns true.
bool AppendRelativePath(const FilePath &child, FilePath *path);
@ -70,7 +72,6 @@ public:
FilePath BaseName();
bool IsAbsolute();
std::string Value();
private:
std::string path_;

View File

@ -181,15 +181,15 @@ napi_value CompressStrategyInit(napi_env env, napi_value exports)
napi_value MemLevelInit(napi_env env, napi_value exports)
{
APP_LOGI("%{public}s called.", __func__);
const int MEM_LEVEL_MIN_MEMLEVEL = 1;
const int MEM_LEVEL_DEFAULT_MEMLEVEL = 8;
const int MEM_LEVEL_MAX_MEMLEVEL = 9;
const int MEM_LEVEL_MIN = 1;
const int MEM_LEVEL_DEFAULT = 8;
const int MEM_LEVEL_MAX = 9;
napi_value memLevel = nullptr;
napi_create_object(env, &memLevel);
SetNamedProperty(env, memLevel, "MEM_LEVEL_MIN_MEMLEVEL", MEM_LEVEL_MIN_MEMLEVEL);
SetNamedProperty(env, memLevel, "MEM_LEVEL_DEFAULT_MEMLEVEL", MEM_LEVEL_DEFAULT_MEMLEVEL);
SetNamedProperty(env, memLevel, "MEM_LEVEL_MAX_MEMLEVEL", MEM_LEVEL_MAX_MEMLEVEL);
SetNamedProperty(env, memLevel, "MEM_LEVEL_MIN", MEM_LEVEL_MIN);
SetNamedProperty(env, memLevel, "MEM_LEVEL_DEFAULT", MEM_LEVEL_DEFAULT);
SetNamedProperty(env, memLevel, "MEM_LEVEL_MAX", MEM_LEVEL_MAX);
napi_property_descriptor properties[] = {
DECLARE_NAPI_PROPERTY("MemLevel", memLevel),

67
tools/zip/src/file_path.cpp Normal file → Executable file
View File

@ -16,8 +16,13 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include "zip_utils.h"
#include "directory_ex.h"
#include "app_log_wrapper.h"
using namespace std;
using namespace OHOS::AppExecFwk;
namespace OHOS {
namespace AAFwk {
namespace LIBZIP {
@ -138,8 +143,9 @@ FilePath FilePath::DirName()
}
newPath.StripTrailingSeparatorsInternal();
if (!newPath.path_.length())
if (!newPath.path_.length()) {
newPath.path_ = kCurrentDirectory;
}
return newPath;
}
@ -237,13 +243,25 @@ bool FilePath::CreateDirectory(const FilePath &fullPath)
// static
bool FilePath::DirectoryExists(const FilePath &path)
{
struct stat fileInfo;
if (stat(const_cast<FilePath &>(path).Value().c_str(), &fileInfo) == 0) {
return S_ISDIR(fileInfo.st_mode);
}
APP_LOGI("!!!stat returns an error.!!!");
return false;
}
bool FilePath::IsDir(const FilePath &path)
{
std::string mPath(const_cast<FilePath &>(path).Value());
if (mPath.empty() || mPath == kCurrentDirectory || mPath == kParentDirectory) {
return true;
} else {
struct stat fileInfo;
int ret = stat(mPath.c_str(), &fileInfo);
return (ret == 0 && S_ISDIR(fileInfo.st_mode));
}
}
bool FilePath::PathIsValid(const FilePath &path)
{
@ -295,6 +313,14 @@ FilePath FilePath::Append(FilePath &component)
return Append(component.path_);
}
void FilePath::AppendSeparator(void)
{
if (path_.empty()) {
path_ = SEPARATOR;
} else {
path_ += SEPARATOR;
}
}
// If IsParent(child) holds, appends to path (if non-NULL) the
// relative path to child and returns true.
bool FilePath::AppendRelativePath(const FilePath &child, FilePath *path)
@ -340,7 +366,44 @@ bool FilePath::AppendRelativePath(const FilePath &child, FilePath *path)
}
return true;
}
bool FilePath::GetZipAllDirFiles(const std::string &path, std::vector<std::string> &files)
{
std::string pathStringWithDelimiter;
if (path.empty() || path == kCurrentDirectory || path == kParentDirectory) {
return true;
}
DIR *dir = opendir(path.c_str());
if (dir == nullptr) {
return false;
}
bool result = false;
while (true) {
result = true;
struct dirent *ptr = readdir(dir);
if (ptr == nullptr) {
break;
}
// current dir OR parent dir
if ((strcmp(ptr->d_name, kCurrentDirectory) == 0) || (strcmp(ptr->d_name, kParentDirectory) == 0)) {
continue;
} else if (ptr->d_type == DT_DIR) {
pathStringWithDelimiter = IncludeTrailingPathDelimiter(path) + string(ptr->d_name);
std::vector<std::string> itemFiles;
result = GetZipAllDirFiles(pathStringWithDelimiter, itemFiles);
if (itemFiles.empty()) {
files.push_back(pathStringWithDelimiter);
} else {
files.insert(files.end(), itemFiles.begin(), itemFiles.end());
}
} else {
files.push_back(IncludeTrailingPathDelimiter(path) + string(ptr->d_name));
}
}
closedir(dir);
return result;
}
} // namespace LIBZIP
} // namespace AAFwk
} // namespace OHOS

73
tools/zip/src/zip.cpp Normal file → Executable file
View File

@ -47,6 +47,13 @@ const char HIDDEN_SEPARATOR = '.';
callback(result); \
}
#define ZIP_WRITER_IS_NULL(zipWriter, logContent, callback, error) \
if (!(zipWriter)) { \
APP_LOGI( logContent ); \
CALLING_CALL_BACK(callback, error) \
return false; \
}
struct UnzipParam {
CALLBACK callback = nullptr;
FilterCallback filterCB = nullptr;
@ -72,18 +79,20 @@ bool ExcludeHiddenFilesFilter(const FilePath &filePath)
return !IsHiddenFile(filePath);
}
std::vector<FileAccessor::DirectoryContentEntry> ListDirectoryContent(const FilePath &filePath)
std::vector<FileAccessor::DirectoryContentEntry> ListDirectoryContent(const FilePath &filePath, bool& isSuccess)
{
FilePath curPath = filePath;
std::vector<FileAccessor::DirectoryContentEntry> fileDirectoryVector;
std::vector<std::string> filelist;
GetDirFiles(curPath.Value(), filelist);
APP_LOGI("filelist ========filelist.size=%{public}zu", filelist.size());
for (size_t i = 0; i < filelist.size(); i++) {
std::string str(filelist[i]);
if (!str.empty()) {
fileDirectoryVector.push_back(
FileAccessor::DirectoryContentEntry(FilePath(str), FilePath::DirectoryExists(FilePath(str))));
isSuccess = FilePath::GetZipAllDirFiles(curPath.Value(), filelist);
if (isSuccess) {
APP_LOGI("ListDirectoryContent filelist =====filelist.size=%{public}zu====", filelist.size());
for (size_t i = 0; i < filelist.size(); i++) {
std::string str(filelist[i]);
if (!str.empty()) {
fileDirectoryVector.push_back(
FileAccessor::DirectoryContentEntry(FilePath(str), FilePath::DirectoryExists(FilePath(str))));
}
}
}
return fileDirectoryVector;
@ -118,35 +127,44 @@ ZipParams::ZipParams(const FilePath &srcDir, const FilePath &destFile) : srcDir_
ZipParams::ZipParams(const FilePath &srcDir, int destFd) : srcDir_(srcDir), destFd_(destFd)
{}
FilePath FilePathEndIsSeparator(FilePath paramPath)
{
bool endIsSeparator = EndsWith(paramPath.Value(), SEPARATOR);
if (FilePath::IsDir(paramPath)) {
if (!endIsSeparator) {
paramPath.AppendSeparator();
}
}
return paramPath;
}
bool Zip(const ZipParams &params, const OPTIONS &options, CALLBACK callback)
{
const std::vector<FilePath> *filesToAdd = &params.GetFilesTozip();
std::vector<FilePath> allRelativeFiles;
FilePath paramPath = params.SrcDir();
bool endIsSeparator = EndsWith(paramPath.Value(), SEPARATOR);
FilePath paramPath = FilePathEndIsSeparator(params.SrcDir());
if (filesToAdd->empty()) {
filesToAdd = &allRelativeFiles;
std::list<FileAccessor::DirectoryContentEntry> entries;
if (endIsSeparator) {
if (EndsWith(paramPath.Value(), SEPARATOR)) {
entries.push_back(FileAccessor::DirectoryContentEntry(params.SrcDir(), true));
FilterCallback filterCallback = params.GetFilterCallback();
for (auto iter = entries.begin(); iter != entries.end(); ++iter) {
const FilePath &constEntryPath = iter->path;
if (iter != entries.begin() && ((!params.GetIncludeHiddenFiles() && IsHiddenFile(constEntryPath)) ||
(filterCallback && !filterCallback(constEntryPath)))) {
if (iter != entries.begin() && ((!params.GetIncludeHiddenFiles() && IsHiddenFile(iter->path)) ||
(filterCallback && !filterCallback(iter->path)))) {
continue;
}
if (iter != entries.begin()) {
FilePath relativePath;
FilePath entryPath = constEntryPath;
FilePath paramsSrcPath = params.SrcDir();
bool success = paramsSrcPath.AppendRelativePath(entryPath, &relativePath);
if (success) {
if (paramsSrcPath.AppendRelativePath(iter->path, &relativePath)) {
allRelativeFiles.push_back(relativePath);
}
}
if (iter->isDirectory) {
std::vector<FileAccessor::DirectoryContentEntry> subEntries = ListDirectoryContent(constEntryPath);
bool isSuccess = false;
std::vector<FileAccessor::DirectoryContentEntry> subEntries =
ListDirectoryContent(iter->path, isSuccess);
entries.insert(entries.end(), subEntries.begin(), subEntries.end());
}
}
@ -155,20 +173,15 @@ bool Zip(const ZipParams &params, const OPTIONS &options, CALLBACK callback)
}
}
std::unique_ptr<ZipWriter> zipWriter = nullptr;
FilePath rootPath = (endIsSeparator == false) ? FilePath(paramPath.DirName().Value() + SEPARATOR) : params.SrcDir();
if (params.DestFd() != kInvalidPlatformFile) {
zipWriter = ZipWriter::CreateWithFd(params.DestFd(), rootPath);
if (!zipWriter) {
CALLING_CALL_BACK(callback, ERROR_CODE_STREAM_ERROR)
return false;
}
zipWriter = ZipWriter::CreateWithFd(params.DestFd(), paramPath);
ZIP_WRITER_IS_NULL(zipWriter, "!!! ZipWriter::CreateWithFd ReturnValue is Null !!!",
callback, ERROR_CODE_STREAM_ERROR);
}
if (!zipWriter) {
zipWriter = ZipWriter::Create(params.DestFile(), rootPath);
if (!zipWriter) {
CALLING_CALL_BACK(callback, ERROR_CODE_STREAM_ERROR)
return false;
}
zipWriter = ZipWriter::Create(params.DestFile(), paramPath);
ZIP_WRITER_IS_NULL(zipWriter, "!!! ZipWriter::Create ReturnValue is Null !!!",
callback, ERROR_CODE_STREAM_ERROR);
}
return zipWriter->WriteEntries(*filesToAdd, options, callback);
}
@ -244,7 +257,7 @@ bool UnzipWithFilterCallback(
if (!FilePath::PathIsValid(srcFile)) {
CALLING_CALL_BACK(unzipParam.callback, ERROR_CODE_DATA_ERROR)
APP_LOGI("%{public}s called, Failed to open.", __func__);
APP_LOGI("%{public}s called,PathIsValid return value is false.", __func__);
return false;
}

34
tools/zip/src/zip_writer.cpp Normal file → Executable file
View File

@ -47,8 +47,8 @@ bool AddFileContentToZip(zipFile zip_file, FilePath &file_path)
"%{public}s called, filePath is invalid!!! file_path=%{public}s", __func__, file_path.Value().c_str());
return false;
}
if (!FilePath::PathIsValid(file_path)) {
APP_LOGI("!!! %{public}s called PathIsValid returns false !!!", __func__);
return false;
}
@ -65,12 +65,13 @@ bool AddFileContentToZip(zipFile zip_file, FilePath &file_path)
if (num_bytes > 0) {
if (zipWriteInFileInZip(zip_file, buf, num_bytes) != ZIP_OK) {
APP_LOGI("%{public}s called, Could not write data to zip for path:%{public}s ",
__func__,
file_path.Value().c_str());
__func__, file_path.Value().c_str());
fclose(fp);
fp = nullptr;
return false;
}
} else {
break;
}
}
fclose(fp);
@ -79,11 +80,16 @@ bool AddFileContentToZip(zipFile zip_file, FilePath &file_path)
}
bool OpenNewFileEntry(
zipFile zip_file, FilePath &path, bool is_directory, struct tm *last_modified, const OPTIONS &options)
zipFile zip_file, FilePath &path, bool isDirectory, struct tm *lastModified, const OPTIONS &options)
{
APP_LOGI("%{public}s called", __func__);
std::string strPath = path.Value();
return ZipOpenNewFileInZip(zip_file, strPath, options, last_modified);
if (isDirectory) {
strPath += SEPARATOR;
}
return ZipOpenNewFileInZip(zip_file, strPath, options, lastModified);
}
bool CloseNewFileEntry(zipFile zip_file)
@ -105,9 +111,9 @@ bool AddFileEntryToZip(zipFile zip_file, FilePath &relativePath, FilePath &absol
}
bool success = AddFileContentToZip(zip_file, absolutePath);
if (!CloseNewFileEntry(zip_file)) {
APP_LOGI("!!! CloseNewFileEntry returnValule is false !!!");
return false;
}
return success;
}
@ -187,7 +193,6 @@ bool ZipWriter::FlushEntriesIfNeeded(bool force, const OPTIONS &options, CALLBAC
if (pendingEntries_.size() < g_MaxPendingEntriesCount && !force) {
return true;
}
std::string rootDir = rootDir_.Value();
if (EndsWith(rootDir_.Value(), SEPARATOR)) {
rootDir = rootDir.substr(0, rootDir.size() - 1);
@ -201,18 +206,19 @@ bool ZipWriter::FlushEntriesIfNeeded(bool force, const OPTIONS &options, CALLBAC
relativePaths.insert(relativePaths.begin(), pendingEntries_.begin(), pendingEntries_.begin() + entry_count);
for (auto iter = pendingEntries_.begin(); iter != pendingEntries_.begin() + entry_count; ++iter) {
// The FileAccessor requires absolute paths.
absolutePaths.push_back(FilePath(rootDir_.Value() + iter->Value()));
if (FilePath::IsDir(rootDir_)) {
absolutePaths.push_back(FilePath(rootDir_.Value() + iter->Value()));
} else {
absolutePaths.push_back(FilePath(rootDir_.Value()));
}
}
pendingEntries_.erase(pendingEntries_.begin(), pendingEntries_.begin() + entry_count);
// We don't know which paths are files and which ones are directories, and
// we want to avoid making a call to file_accessor_ for each entry. Open the
// files instead, invalid files are returned for directories.
for (size_t i = 0; i < absolutePaths.size(); i++) {
FilePath &relativePath = relativePaths[i];
FilePath &absolutePath = absolutePaths[i];
if (FilePath::PathIsValid(absolutePath)) {
bool isValid = FilePath::PathIsValid(absolutePath);
bool isDir = FilePath::IsDir(absolutePath);
if (isValid && !isDir) {
if (!AddFileEntryToZip(zipFile_, relativePath, absolutePath, options)) {
CALLING_CALL_BACK(callback, ERROR_CODE_ERRNO)
APP_LOGI("%{public}s called, Failed to write file", __func__);

2
tools/zip/test/BUILD.gn Normal file → Executable file
View File

@ -14,7 +14,7 @@
import("//build/test.gni")
import("//foundation/appexecfwk/standard/appexecfwk.gni")
module_output_path = "bundle_framework/zip"
module_output_path = "appexecfwk_standard/tools"
config("module_private_config") {
visibility = [ ":*" ]

74
tools/zip/test/unittest/zip_test.cpp Normal file → Executable file
View File

@ -23,6 +23,10 @@ namespace AAFwk {
namespace LIBZIP {
using namespace testing::ext;
namespace {
define BASE_PATH "/data/accounts/account_0/appdata/"\
"com.example.zlib/com.example.zlib/com.example.zlib.MainAbility/files/"
} // namespac
class ZipTest : public testing::Test {
public:
ZipTest()
@ -58,14 +62,14 @@ void UnzipCallBack(int result)
}
/**
* @tc.number:
* @tc.name:
* @tc.number: AAFwk_LIBZIP_zip_0100_8file
* @tc.name: zip_0100_8file
* @tc.desc:
*/
HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0100_fourfile, Function | MediumTest | Level1)
HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0100_8file, Function | MediumTest | Level1)
{
std::string src = "/ziptest/zipdata/";
std::string dest = "/ziptest/result/fourfile.zip";
std::string src = BASE_PATH + "test";
std::string dest = BASE_PATH + "result/8file.zip";
OPTIONS options;
Zip(FilePath(src), FilePath(dest), options, ZipCallBack, false);
@ -73,14 +77,14 @@ HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0100_fourfile, Function | MediumTest | Level1
}
/**
* @tc.number:
* @tc.name:
* @tc.number: AAFwk_LIBZIP_zip_0200_1file
* @tc.name: zip_0200_1file
* @tc.desc:
*/
HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0200_singlefile, Function | MediumTest | Level1)
HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0200_1file, Function | MediumTest | Level1)
{
std::string src = "/ziptest/zipdata/zip1/zip1-1/zip1-1.cpp";
std::string dest = "/ziptest/result/singlefile.zip";
std::string src = BASE_PATH + "test/01";
std::string dest = BASE_PATH + "result/1file.zip";
OPTIONS options;
Zip(FilePath(src), FilePath(dest), options, ZipCallBack, false);
@ -88,30 +92,62 @@ HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0200_singlefile, Function | MediumTest | Leve
}
/**
* @tc.number:
* @tc.name:
* @tc.number: AAFwk_LIBZIP_zip_0100_zip1file
* @tc.name: zip_0100_zip1file
* @tc.desc:
*/
HWTEST_F(ZipTest, AAFwk_LIBZIP_unzip_0100, Function | MediumTest | Level1)
HWTEST_F(ZipTest, AAFwk_LIBZIP_zip_0100_zip1file, Function | MediumTest | Level1)
{
std::string dest = "/ziptest/unzipdir/fourfile/";
std::string src = "/ziptest/result/fourfile.zip";
std::string src = BASE_PATH + "test/01/zip1.txt";
std::string dest = BASE_PATH + "result/zip1file.zip";
OPTIONS options;
Zip(FilePath(src), FilePath(dest), options, ZipCallBack, false);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
}
/**
* @tc.number: AAFwk_LIBZIP_unzip_0100_8file
* @tc.name: unzip_0100_8file
* @tc.desc:
*/
HWTEST_F(ZipTest, AAFwk_LIBZIP_unzip_0100_8file, Function | MediumTest | Level1)
{
std::string src = BASE_PATH + "result/8file.zip";
std::string dest = BASE_PATH + "unzip/01";
OPTIONS options;
Unzip(FilePath(src), FilePath(dest), options, UnzipCallBack);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
}
HWTEST_F(ZipTest, AAFwk_LIBZIP_unzip_single_0200, Function | MediumTest | Level1)
/**
* @tc.number: AAFwk_LIBZIP_unzip_single_0200_1file
* @tc.name: unzip_single_0200_1file
* @tc.desc:
*/
HWTEST_F(ZipTest, AAFwk_LIBZIP_unzip_single_0200_1file, Function | MediumTest | Level1)
{
std::string src = "/ziptest/result/singlefile.zip";
std::string dest = "/ziptest/unzipdir/single/";
std::string src = BASE_PATH + "result/1file.zip";
std::string dest = BASE_PATH + "unzip/02";
OPTIONS options;
Unzip(FilePath(src), FilePath(dest), options, UnzipCallBack);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
}
/**
* @tc.number: AAFwk_LIBZIP_zip_0100_zip1file
* @tc.name: zip_0100_zip1file
* @tc.desc:
*/
HWTEST_F(ZipTest, AAFwk_LIBZIP_unzip_0100_zip1file, Function | MediumTest | Level1)
{
std::string src = BASE_PATH + "result/zip1file.zip";
std::string dest = BASE_PATH + "unzip/zip1file";
OPTIONS options;
Unzip(FilePath(src), FilePath(dest), options, UnzipCallBack);
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
}
} // namespace LIBZIP
} // namespace AAFwk
} // namespace OHOS