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;
}