libzip 中的符号链接
Symbolic links in libzip
我在 Linux 的 C++ 应用程序中使用 libzip,它需要能够 zip/unzip 包含符号 link 的目录。我想添加 link 本身而不跟随它。使用 readlink() 读出 link 并将其添加到 zip 存档中,在使用 unzip 解压缩时会生成一个毫无意义的标准文件。
解决方案不需要移植,只会在Linux下使用。 linux zip 命令有一个 --symlinks 标志,所以 zip 标准应该支持它。系统调用并不是一个真正的选择,文件的数量非常大,这使得应用程序非常慢。
是否可以使用 libzip 添加 symlinks,如何添加?
谢谢,
桑德
根据文档:否
根据其 webpage, libzip is based on zlib. The zip program used in Linux, etc, is info-zip,它不使用 zlib,而是自包含的(并且包含 zlib 中没有的功能)。
是的,这是可能的。
下面是我用于压缩 C 代码文件列表的函数。
要压缩的文件存储在 cJSON 结构中,没有设置 uid/gid 并且 files/directories 相对于目录 "base"(因为这是我的应用程序)。
函数 returns 0 表示成功。
int list_zip_it(char * upload_zip_name,char * base, cJSON * filelist)
{
int result=0;
int error_n = 0;
struct zip *archive = zip_open(upload_zip_name, ZIP_TRUNCATE | ZIP_CREATE, &error_n);
if(!archive)
{
printf(stderr,"could not open or create archive\n");
return -1;
}
mode_t mode=0;
cJSON * item;
cJSON_ArrayForEach(item,filelist)
{
char * path=NULL;
path=item->valuestring;
// stat the item
struct stat sb;
if (stat(path, &sb) == 0 ) mode=sb.st_mode;
zip_uint32_t attr=0;
attr=((mode ) << 16L);
char rel_file[1024];
if (strncmp(path,CI_PROJECT_DIR,strlen(base))==0 )
{
snprintf(rel_file,1024,"%s",path+strlen(base)+1);
printf("archive filename: %s\n",rel_file);
}
else
{
fprintf(stderr,"filename outside base-derectory\n");
continue;
}
if (S_ISDIR(mode))
{
int index = (int)zip_add_dir(archive, rel_file);
if (index>0) zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
else if (S_ISLNK(mode)) // symlink
{
char link[1024];//=calloc(1, 1024);
memset(link, 0, 1024);
ssize_t size_link=readlink(path , link, 1023);
if (size_link > 0)
{
struct zip_source *source = zip_source_buffer(archive , link, ( zip_uint64_t)size_link,0);
if (source)
{
int index = (int)zip_add(archive, rel_file, source);
if (index>0) zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
else
{
printf(stderr,"failed to create source buffer: %s \n", zip_strerror(archive) );
zip_source_free(source);
}
}
else error("failed to read link: %s \n",path );
}
else if (S_ISREG(mode))
{
struct zip_source *source = zip_source_file(archive, path, 0, 0);
if(source == NULL)
{
error("failed to create source buffer: %s \n", zip_strerror(archive) );
result=1;
break;
}
// todo calculate filename relative to project_dir
int index = (int)zip_add(archive, rel_file, source);
if(index < 0 )
{
int zep,sep;
zip_error_get(archive, &zep, &sep);
if (zep== ZIP_ER_EXISTS )
{
fprintf(stderr,"failed to add file to archive: %s \n", zip_strerror(archive) );
zip_source_free(source);
}
else
{
fprintf(stderr,"failed to add file to archive: %s \n", zip_strerror(archive) );
zip_source_free(source);
result=1;
break;
}
}
else
{
zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
}
}
zip_close(archive);
return result;
}
我在 Linux 的 C++ 应用程序中使用 libzip,它需要能够 zip/unzip 包含符号 link 的目录。我想添加 link 本身而不跟随它。使用 readlink() 读出 link 并将其添加到 zip 存档中,在使用 unzip 解压缩时会生成一个毫无意义的标准文件。
解决方案不需要移植,只会在Linux下使用。 linux zip 命令有一个 --symlinks 标志,所以 zip 标准应该支持它。系统调用并不是一个真正的选择,文件的数量非常大,这使得应用程序非常慢。
是否可以使用 libzip 添加 symlinks,如何添加?
谢谢, 桑德
根据文档:否
根据其 webpage, libzip is based on zlib. The zip program used in Linux, etc, is info-zip,它不使用 zlib,而是自包含的(并且包含 zlib 中没有的功能)。
是的,这是可能的。
下面是我用于压缩 C 代码文件列表的函数。 要压缩的文件存储在 cJSON 结构中,没有设置 uid/gid 并且 files/directories 相对于目录 "base"(因为这是我的应用程序)。
函数 returns 0 表示成功。
int list_zip_it(char * upload_zip_name,char * base, cJSON * filelist)
{
int result=0;
int error_n = 0;
struct zip *archive = zip_open(upload_zip_name, ZIP_TRUNCATE | ZIP_CREATE, &error_n);
if(!archive)
{
printf(stderr,"could not open or create archive\n");
return -1;
}
mode_t mode=0;
cJSON * item;
cJSON_ArrayForEach(item,filelist)
{
char * path=NULL;
path=item->valuestring;
// stat the item
struct stat sb;
if (stat(path, &sb) == 0 ) mode=sb.st_mode;
zip_uint32_t attr=0;
attr=((mode ) << 16L);
char rel_file[1024];
if (strncmp(path,CI_PROJECT_DIR,strlen(base))==0 )
{
snprintf(rel_file,1024,"%s",path+strlen(base)+1);
printf("archive filename: %s\n",rel_file);
}
else
{
fprintf(stderr,"filename outside base-derectory\n");
continue;
}
if (S_ISDIR(mode))
{
int index = (int)zip_add_dir(archive, rel_file);
if (index>0) zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
else if (S_ISLNK(mode)) // symlink
{
char link[1024];//=calloc(1, 1024);
memset(link, 0, 1024);
ssize_t size_link=readlink(path , link, 1023);
if (size_link > 0)
{
struct zip_source *source = zip_source_buffer(archive , link, ( zip_uint64_t)size_link,0);
if (source)
{
int index = (int)zip_add(archive, rel_file, source);
if (index>0) zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
else
{
printf(stderr,"failed to create source buffer: %s \n", zip_strerror(archive) );
zip_source_free(source);
}
}
else error("failed to read link: %s \n",path );
}
else if (S_ISREG(mode))
{
struct zip_source *source = zip_source_file(archive, path, 0, 0);
if(source == NULL)
{
error("failed to create source buffer: %s \n", zip_strerror(archive) );
result=1;
break;
}
// todo calculate filename relative to project_dir
int index = (int)zip_add(archive, rel_file, source);
if(index < 0 )
{
int zep,sep;
zip_error_get(archive, &zep, &sep);
if (zep== ZIP_ER_EXISTS )
{
fprintf(stderr,"failed to add file to archive: %s \n", zip_strerror(archive) );
zip_source_free(source);
}
else
{
fprintf(stderr,"failed to add file to archive: %s \n", zip_strerror(archive) );
zip_source_free(source);
result=1;
break;
}
}
else
{
zip_file_set_external_attributes(archive, index, 0, ZIP_OPSYS_UNIX, attr);
}
}
}
zip_close(archive);
return result;
}