Я использую libzip в приложении c ++ для Linux, которое должно быть в состоянии архивировать / распаковывать каталоги, содержащие символические ссылки. Я хочу добавить саму ссылку, не переходя по ней. Считывание ссылки с помощью readlink () и добавление ее в zip-архив приводит к бессмысленному стандартному файлу при распаковке с помощью unzip.
Решение не должно быть переносимым, оно будет использоваться только под Linux. Команда linux zip имеет флаги —symlinks, поэтому стандарт zip должен ее поддерживать. Системные вызовы на самом деле не вариант, количество файлов довольно велико, и это делает приложение крайне медленным.
Можно ли добавить символические ссылки с помощью libzip и как?
Спасибо,
шлифовальная машинка
На основании документации: нет
Согласно его страница интернета, libzip основан на Zlib. Программа zip, используемая в Linux и т. Д., Info-ZIP, который не использует zlib, но является автономным (и содержит функции, отсутствующие в zlib).
Да, это возможно.
Ниже функция, которую я использую для архивирования списка файлов в c-коде.
Файлы для zip хранятся в структуре cJSON, без набора uid / gid и файлов / каталогов относительно «базы» каталогов (так как это мое приложение).
Функция возвращает 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;
}