/[osn-commons]/trunk/uar/uar.c
ViewVC logotype

Diff of /trunk/uar/uar.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 39 by rakinar2, Thu Aug 8 19:13:26 2024 UTC revision 40 by rakinar2, Sat Aug 10 14:44:20 2024 UTC
# Line 17  Line 17 
17  #include <sys/types.h>  #include <sys/types.h>
18  #include <time.h>  #include <time.h>
19  #include <unistd.h>  #include <unistd.h>
20    #include <utime.h>
21    
22  #if defined(__linux__)  #if defined(__linux__)
23  #    include <linux/limits.h>  #    include <linux/limits.h>
# Line 66  struct uar_archive Line 67  struct uar_archive
67      struct uar_file **files;      struct uar_file **files;
68      struct uar_file *root;      struct uar_file *root;
69      enum uar_error ecode;      enum uar_error ecode;
     bool is_stream;  
     uint8_t *buffer; /* Deprecated */  
70      FILE *stream;      FILE *stream;
71      uint64_t stream_size;      uint64_t stream_size;
72      int last_errno;      int last_errno;
73      char *err_file;      char *err_file;
74        uint64_t data_start;
75      uar_create_callback_t create_callback;      uar_create_callback_t create_callback;
76        uar_extract_callback_t extract_callback;
77  };  };
78    
79  void  void
# Line 82  uar_set_create_callback (struct uar_arch Line 83  uar_set_create_callback (struct uar_arch
83      uar->create_callback = callback;      uar->create_callback = callback;
84  }  }
85    
86    void
87    uar_set_extract_callback (struct uar_archive *uar,
88                              uar_extract_callback_t callback)
89    {
90        uar->extract_callback = callback;
91    }
92    
93  static void  static void
94  uar_set_error (struct uar_archive *uar, enum uar_error ecode,  uar_set_error (struct uar_archive *uar, enum uar_error ecode,
95                 const char *err_file)                 const char *err_file)
# Line 156  uar_create (void) Line 164  uar_create (void)
164      if (uar == NULL)      if (uar == NULL)
165          return NULL;          return NULL;
166    
     uar->is_stream = false;  
     uar->buffer = NULL;  
167      uar->ecode = UAR_SUCCESS;      uar->ecode = UAR_SUCCESS;
168      uar->header.size = 0;      uar->header.size = 0;
169      memcpy (uar->header.magic, UAR_MAGIC, 4);      memcpy (uar->header.magic, UAR_MAGIC, 4);
# Line 214  uar_initialize (struct uar_archive *uar) Line 220  uar_initialize (struct uar_archive *uar)
220  bool  bool
221  uar_stream_write (struct uar_archive *uar, const char *filename)  uar_stream_write (struct uar_archive *uar, const char *filename)
222  {  {
223      if (uar == NULL || !uar->is_stream || uar->stream == NULL)      if (uar == NULL || uar->stream == NULL)
224          return false;          return false;
225    
226      FILE *stream = fopen (filename, "wb");      FILE *stream = fopen (filename, "wb");
# Line 322  uar_stream_create (void) Line 328  uar_stream_create (void)
328      if (uar == NULL)      if (uar == NULL)
329          return NULL;          return NULL;
330    
     uar->is_stream = true;  
331      uar->stream = tmpfile ();      uar->stream = tmpfile ();
332    
333      if (uar->stream == NULL)      if (uar->stream == NULL)
# Line 347  uar_stream_add_file (struct uar_archive Line 352  uar_stream_add_file (struct uar_archive
352                       const char *fs_filename, struct stat *stinfo)                       const char *fs_filename, struct stat *stinfo)
353  {  {
354      assert (uar != NULL && "uar is NULL");      assert (uar != NULL && "uar is NULL");
     assert (uar->is_stream && "uar is not in stream mode");  
355      assert (uar_filename != NULL && "uar_filename is NULL");      assert (uar_filename != NULL && "uar_filename is NULL");
356      assert (fs_filename != NULL && "fs_filename is NULL");      assert (fs_filename != NULL && "fs_filename is NULL");
357    
# Line 691  uar_stream_add_entry (struct uar_archive Line 695  uar_stream_add_entry (struct uar_archive
695                        const char *fs_name, struct stat *stinfo)                        const char *fs_name, struct stat *stinfo)
696  {  {
697      assert (uar != NULL && "uar is NULL");      assert (uar != NULL && "uar is NULL");
     assert (uar->is_stream && "uar is not in stream mode");  
698      assert (uar_name != NULL && "uar_name is NULL");      assert (uar_name != NULL && "uar_name is NULL");
699      assert (fs_name != NULL && "fs_name is NULL");      assert (fs_name != NULL && "fs_name is NULL");
700    
# Line 798  uar_stream_open (const char *filename) Line 801  uar_stream_open (const char *filename)
801      if (uar == NULL)      if (uar == NULL)
802          return NULL;          return NULL;
803    
     uar->is_stream = true;  
804      uar->stream = stream;      uar->stream = stream;
805    
806      fseek (stream, 0, SEEK_END);      fseek (stream, 0, SEEK_END);
# Line 838  uar_stream_open (const char *filename) Line 840  uar_stream_open (const char *filename)
840              return uar;              return uar;
841          }          }
842    
843      uint64_t read_size = sizeof (struct uar_header)      uint64_t file_block_size
844                           + (uar->header.nfiles * sizeof (struct uar_file));          = sizeof (struct uar_header)
845              + (uar->header.nfiles * sizeof (struct uar_file));
846        uint64_t data_block_start = file_block_size;
847    
848      for (uint64_t i = 0; i < uar->header.nfiles; i++)      for (uint64_t i = 0; i < uar->header.nfiles; i++)
849          {          {
# Line 865  uar_stream_open (const char *filename) Line 869  uar_stream_open (const char *filename)
869               */               */
870    
871              if (file->namelen > PATH_MAX || file->namelen == 0              if (file->namelen > PATH_MAX || file->namelen == 0
872                  || read_size + file->namelen > ((uint64_t) size))                  || file_block_size + file->namelen > ((uint64_t) size))
873                  {                  {
874                      /* At a later stage, we might want to rather call a callback                      /* At a later stage, we might want to rather call a callback
875                         function instead. */                         function instead. */
# Line 874  uar_stream_open (const char *filename) Line 878  uar_stream_open (const char *filename)
878                      return uar;                      return uar;
879                  }                  }
880    
881                data_block_start += file->namelen;
882              file->name = malloc (file->namelen + 1);              file->name = malloc (file->namelen + 1);
883    
884              if (file->name == NULL)              if (file->name == NULL)
# Line 899  uar_stream_open (const char *filename) Line 904  uar_stream_open (const char *filename)
904              if (file->type == UF_LINK)              if (file->type == UF_LINK)
905                  {                  {
906                      if (file->data.link.loclen > PATH_MAX                      if (file->data.link.loclen > PATH_MAX
907                          || read_size + file->data.link.loclen                          || file_block_size + file->data.link.loclen
908                                 > ((uint64_t) size))                                 > ((uint64_t) size))
909                          {                          {
910                              uar_set_error (uar, UAR_INVALID_ARCHIVE, NULL);                              uar_set_error (uar, UAR_INVALID_ARCHIVE, NULL);
# Line 908  uar_stream_open (const char *filename) Line 913  uar_stream_open (const char *filename)
913                              return uar;                              return uar;
914                          }                          }
915    
916                        data_block_start += file->data.link.loclen;
917                      file->data.link.loc = malloc (file->data.link.loclen + 1);                      file->data.link.loc = malloc (file->data.link.loclen + 1);
918    
919                      if (file->data.link.loc == NULL)                      if (file->data.link.loc == NULL)
# Line 935  uar_stream_open (const char *filename) Line 941  uar_stream_open (const char *filename)
941              uar->files[i] = file;              uar->files[i] = file;
942          }          }
943    
944        uar->data_start = data_block_start;
945      return uar;      return uar;
946  }  }
947    
948  struct uar_archive *  static bool
949  uar_open (const char *filename)  uar_stream_extract_file (struct uar_archive *uar, struct uar_file *file,
950                             const char *path)
951  {  {
952      struct uar_archive *uar = NULL;      FILE *stream = fopen (path, "wb");
953      FILE *stream = NULL;      uint8_t buffer[1024];
954      int cerrno;      uint64_t size = file->data.size;
955    
956      errno = 0;      if (stream == NULL)
957      uar = uar_create ();          {
958                uar_set_error (uar, UAR_SYSCALL_ERROR, path);
959                perror ("fopen");
960    
961      if (uar == NULL)              if (uar->extract_callback != NULL)
962          return NULL;                  uar->extract_callback (uar, file, file->name, path,
963                                           UAR_ELEVEL_WARNING, strerror (errno));
964    
965      stream = fopen (filename, "rb");              return false;
966            }
967    
968      if (stream == NULL)      if (fseek (uar->stream, uar->data_start + file->offset, SEEK_SET) != 0)
969          {          {
970              uar_set_error (uar, UAR_IO_ERROR, NULL);              uar_set_error (uar, UAR_SYSCALL_ERROR, path);
             goto uar_open_ret;  
         }  
971    
972      fseek (stream, 0, SEEK_END);              if (uar->extract_callback != NULL)
973      size_t size = ftell (stream);                  uar->extract_callback (uar, file, file->name, path,
974      fseek (stream, 0, SEEK_SET);                                         UAR_ELEVEL_WARNING, strerror (errno));
975    
976      if (fread (&uar->header, sizeof (struct uar_header), 1, stream) != 1)              fclose (stream);
977          {              return false;
             uar_set_error (uar, UAR_IO_ERROR, NULL);  
             goto uar_open_ret;  
978          }          }
979    
980      if (memcmp (uar->header.magic, UAR_MAGIC, 4) != 0)      while (size > 0)
981          {          {
982              uar_set_error (uar, UAR_INVALID_MAGIC, NULL);              size_t read_size = size > sizeof (buffer) ? sizeof (buffer) : size;
             goto uar_open_ret;  
         }  
983    
984      uint64_t filearr_size = uar->header.nfiles * sizeof (struct uar_file);              if (fread (buffer, 1, read_size, uar->stream) != read_size)
985                    {
986                        uar_set_error (uar, UAR_SYSCALL_ERROR, path);
987    
988      if (filearr_size > size)                      if (uar->extract_callback != NULL)
989          {                          uar->extract_callback (uar, file, file->name, path,
990              uar_set_error (uar, UAR_IO_ERROR, NULL);                                                 UAR_ELEVEL_WARNING,
991              goto uar_open_ret;                                                 strerror (errno));
992    
993                        fclose (stream);
994                        return false;
995                    }
996    
997                if (fwrite (buffer, 1, read_size, stream) != read_size)
998                    {
999                        uar_set_error (uar, UAR_SYSCALL_ERROR, path);
1000    
1001                        if (uar->extract_callback != NULL)
1002                            uar->extract_callback (uar, file, file->name, path,
1003                                                   UAR_ELEVEL_WARNING,
1004                                                   strerror (errno));
1005    
1006                        fclose (stream);
1007                        return false;
1008                    }
1009    
1010                size -= read_size;
1011          }          }
1012    
1013      if (uar->header.size > size)      if (fchmod (fileno (stream), file->mode) != 0)
1014          {          {
1015              uar_set_error (uar, UAR_IO_ERROR, NULL);              uar_set_error (uar, UAR_SYSCALL_ERROR, path);
             goto uar_open_ret;  
         }  
1016    
1017      uar->files = calloc (uar->header.nfiles, sizeof (struct uar_file *));              if (uar->extract_callback != NULL)
1018                    uar->extract_callback (uar, file, file->name, path,
1019                                           UAR_ELEVEL_WARNING, strerror (errno));
1020    
1021      if (uar->files == NULL)              fclose (stream);
1022          {              return false;
             uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL);  
             goto uar_open_ret;  
1023          }          }
1024    
1025        fclose (stream);
1026        return true;
1027    }
1028    
1029    bool
1030    uar_stream_extract (struct uar_archive *uar, const char *dest)
1031    {
1032      for (uint64_t i = 0; i < uar->header.nfiles; i++)      for (uint64_t i = 0; i < uar->header.nfiles; i++)
1033          {          {
1034              struct uar_file *file = malloc (sizeof (struct uar_file));              struct uar_file *file = uar->files[i];
1035                char *name = file->name;
1036                size_t diff = 0;
1037                bool is_root = strcmp (file->name, "/") == 0;
1038    
1039              if (file == NULL)              if (!is_root)
1040                  {                  {
1041                      uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL);                      if (name[0] == '/')
1042                      goto uar_open_ret;                          diff += 1;
1043    
1044                        if (strncmp (name, "./", 2) == 0)
1045                            diff += 2;
1046                        else if (strncmp (name, "../", 3) == 0)
1047                            diff += 3;
1048                        else if (strcmp (name, "..") == 0)
1049                            diff += 2;
1050                        else if (strcmp (name, ".") == 0)
1051                            diff += 1;
1052                  }                  }
1053    
1054              if (fread (file, sizeof (struct uar_file), 1, stream) != 1)              char *path
1055                    = is_root ? (char *) dest
1056                              : path_concat (dest, file->name + diff, strlen (dest),
1057                                             file->namelen - diff);
1058    
1059                if (path == NULL)
1060                  {                  {
1061                      uar_set_error (uar, UAR_IO_ERROR, NULL);                      uar_set_error (uar, UAR_OUT_OF_MEMORY, file->name);
1062                      goto uar_open_ret;                      return false;
1063                  }                  }
1064    
1065              if (file->namelen > PATH_MAX)              if (!is_root)
1066                  {                  {
1067                      uar_set_error (uar, UAR_INVALID_PATH, NULL);                      switch (file->type)
1068                      goto uar_open_ret;                          {
1069                            case UF_FILE:
1070                                if (!uar_stream_extract_file (uar, file, path))
1071                                    {
1072                                        free (path);
1073                                        return false;
1074                                    }
1075                                break;
1076                            case UF_DIR:
1077                                if (mkdir (path, file->mode) != 0)
1078                                    {
1079                                        uar_set_error (uar, UAR_SYSCALL_ERROR,
1080                                                       path);
1081    
1082                                        if (uar->extract_callback != NULL)
1083                                            uar->extract_callback (
1084                                                uar, file, file->name, path,
1085                                                UAR_ELEVEL_WARNING,
1086                                                strerror (errno));
1087    
1088                                        free (path);
1089                                        return false;
1090                                    }
1091                                break;
1092                            case UF_LINK:
1093                                if (symlink (file->data.link.loc, path) != 0)
1094                                    {
1095                                        uar_set_error (uar, UAR_SYSCALL_ERROR,
1096                                                       path);
1097    
1098                                        if (uar->extract_callback != NULL)
1099                                            uar->extract_callback (
1100                                                uar, file, file->name, path,
1101                                                UAR_ELEVEL_WARNING,
1102                                                strerror (errno));
1103    
1104                                        free (path);
1105                                        return false;
1106                                    }
1107                                break;
1108                            default:
1109                                uar_set_error (uar, UAR_INVALID_FILE, file->name);
1110    
1111                                if (uar->extract_callback != NULL)
1112                                    uar->extract_callback (uar, file, file->name,
1113                                                           path, UAR_ELEVEL_WARNING,
1114                                                           strerror (errno));
1115    
1116                                free (path);
1117                                return false;
1118                            }
1119                  }                  }
1120    
1121              file->name = malloc (file->namelen + 1);              struct utimbuf times
1122                    = { .actime = time (NULL), .modtime = file->mtime };
1123    
1124              if (file->name == NULL)              if (utime (path, &times) != 0)
1125                  {                  {
1126                      uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL);                      uar_set_error (uar, UAR_SYSCALL_ERROR, path);
1127                      goto uar_open_ret;  
1128                        if (uar->extract_callback != NULL)
1129                            uar->extract_callback (uar, file, file->name, path,
1130                                                   UAR_ELEVEL_WARNING,
1131                                                   strerror (errno));
1132    
1133                        if (!is_root)
1134                            free (path);
1135    
1136                        return false;
1137                  }                  }
1138    
1139              if (fread (file->name, 1, file->namelen, stream) != file->namelen)              if (chown (path, file->uid, file->gid) != 0)
1140                  {                  {
1141                      uar_set_error (uar, UAR_IO_ERROR, file->name);                      uar_set_error (uar, UAR_SYSCALL_ERROR, path);
                     goto uar_open_ret;  
                 }  
1142    
1143              file->name[file->namelen] = 0;                      if (uar->extract_callback != NULL)
1144              uar->files[i] = file;                          uar->extract_callback (uar, file, file->name, path,
1145          }                                                 UAR_ELEVEL_WARNING,
1146                                                   strerror (errno));
1147    
1148      uar->buffer = malloc (uar->header.size + 1);                      if (!is_root)
1149                            free (path);
1150    
1151      if (uar->buffer == NULL)                      return false;
1152          {                  }
             uar_set_error (uar, UAR_OUT_OF_MEMORY, NULL);  
             goto uar_open_ret;  
         }  
1153    
1154      if (fread (uar->buffer, 1, uar->header.size, stream) != uar->header.size)              if (uar->extract_callback != NULL)
1155          {                  uar->extract_callback (uar, file, file->name, path,
1156              uar_set_error (uar, UAR_IO_ERROR, NULL);                                         UAR_ELEVEL_NONE, NULL);
1157              goto uar_open_ret;  
1158                if (!is_root)
1159                    free (path);
1160          }          }
1161    
1162  uar_open_ret:      return true;
     cerrno = errno;  
     fclose (stream);  
     errno = cerrno;  
     return uar;  
1163  }  }
1164    
1165  void  void
# Line 1077  uar_close (struct uar_archive *uar) Line 1181  uar_close (struct uar_archive *uar)
1181      if (uar == NULL)      if (uar == NULL)
1182          return;          return;
1183    
1184      if (uar->is_stream)      fclose (uar->stream);
         fclose (uar->stream);  
     else  
         free (uar->buffer);  
1185    
1186      for (uint64_t i = 0; i < uar->header.nfiles; i++)      for (uint64_t i = 0; i < uar->header.nfiles; i++)
1187          {          {
# Line 1171  uar_file_create (const char *name, uint6 Line 1272  uar_file_create (const char *name, uint6
1272      return file;      return file;
1273  }  }
1274    
1275  struct uar_file *  void
1276  uar_add_file (struct uar_archive *restrict uar, const char *name,  uar_file_set_mode (struct uar_file *file, mode_t mode)
               const char *path, struct stat *stinfo)  
1277  {  {
1278      assert (uar != NULL && "uar is NULL");      file->mode = mode;
     assert (name != NULL && "name is NULL");  
     assert (path != NULL && "path is NULL");  
     assert (!uar->is_stream && "uar in non-stream mode is not supported yet");  
   
     uint64_t namelen = strlen (name);  
     struct stat *file_stinfo = stinfo, st_stinfo = { 0 };  
   
     if (namelen >= PATH_MAX)  
         {  
             uar_set_error (uar, UAR_INVALID_PATH, path);  
             return NULL;  
         }  
   
     if (file_stinfo == NULL)  
         {  
             if (lstat (path, &st_stinfo) != 0)  
                 {  
                     uar_set_error (uar, UAR_IO_ERROR, path);  
                     return NULL;  
                 }  
   
             file_stinfo = &st_stinfo;  
         }  
   
     FILE *stream = fopen (path, "rb");  
   
     if (stream == NULL)  
         {  
             uar_set_error (uar, UAR_IO_ERROR, path);  
             return NULL;  
         }  
   
     fseek (stream, 0, SEEK_END);  
     long size = ftell (stream);  
   
     if (size < 0)  
         {  
             uar_set_error (uar, UAR_IO_ERROR, path);  
             fclose (stream);  
             return NULL;  
         }  
   
     fseek (stream, 0, SEEK_SET);  
   
     struct uar_file *file  
         = uar_file_create (name, namelen, size, uar->header.size);  
   
     if (file == NULL)  
         {  
             uar_set_error (uar, UAR_OUT_OF_MEMORY, path);  
             fclose (stream);  
             return NULL;  
         }  
   
     file->mtime = file_stinfo->st_mtime;  
     uar->header.size += size;  
   
     if (!uar_add_file_entry (uar, file))  
         {  
             uar_file_destroy (file);  
             fclose (stream);  
             return NULL;  
         }  
   
     uar->buffer = realloc (uar->buffer, uar->header.size);  
   
     if (uar->buffer == NULL)  
         {  
             uar_set_error (uar, UAR_OUT_OF_MEMORY, path);  
             fclose (stream);  
             return NULL;  
         }  
   
     if (size != 0 && fread (uar->buffer + file->offset, size, 1, stream) != 1)  
         {  
             uar_set_error (uar, UAR_IO_ERROR, path);  
             fclose (stream);  
             return NULL;  
         }  
   
     fclose (stream);  
     return file;  
1279  }  }
1280    
1281  struct uar_file *  static void
1282  uar_add_dir (struct uar_archive *uar, const char *dname, const char *path,  uar_debug_print_file_contents (const struct uar_archive *uar,
1283               bool (*callback) (struct uar_file *file, const char *fullname,                                 struct uar_file *file)
                                const char *fullpath))  
1284  {  {
1285      assert (uar != NULL && "uar is NULL");      printf ("    contents:\n");
1286      assert (dname != NULL && "dname is NULL");      printf ("==================\n");
1287      assert (path != NULL && "path is NULL");      fflush (stdout);
     assert (!uar->is_stream && "uar in non-stream mode is not supported yet");  
   
     char *name = (char *) dname;  
     bool free_name = false;  
     int cerrno;  
     uint64_t namelen;  
   
     if (strcmp (name, ".") == 0)  
         {  
             name = strdup ("/");  
             free_name = true;  
             namelen = 1;  
         }  
     else  
         namelen = strlen (name);  
   
     if (namelen >= PATH_MAX)  
         {  
             uar_set_error (uar, UAR_INVALID_PATH, path);  
             return NULL;  
         }  
   
     DIR *dir = opendir (path);  
     struct dirent *entry = NULL;  
   
     if (dir == NULL)  
         {  
             uar_set_error (uar, UAR_INVALID_FILE, path);  
             return NULL;  
         }  
   
     struct uar_file *dir_file  
         = uar_file_create (name, namelen, 0, uar->header.size);  
     uint64_t dir_size = 0;  
   
     dir_file->type = UF_DIR;  
1288    
1289      if (callback != NULL && !callback (dir_file, name, path))      if (fseek (uar->stream, uar->data_start + file->offset, SEEK_SET) != 0)
1290          {          {
1291              uar_set_error (uar, UAR_SUCCESS, NULL);              perror ("fseek");
1292              uar_file_destroy (dir_file);              return;
             return NULL;  
1293          }          }
1294    
1295      if (!uar_add_file_entry (uar, dir_file))      uint8_t buffer[1024];
         {  
             uar_file_destroy (dir_file);  
             return NULL;  
         }  
1296    
1297      while ((entry = readdir (dir)) != NULL)      while (file->data.size > 0)
1298          {          {
1299              if (strcmp (entry->d_name, ".") == 0              size_t size = file->data.size > sizeof (buffer) ? sizeof (buffer)
1300                  || strcmp (entry->d_name, "..") == 0)                                                              : file->data.size;
                 continue;  
   
             struct stat stinfo = { 0 };  
   
             if (256 + namelen >= PATH_MAX)  
                 {  
                     uar_set_error (uar, UAR_INVALID_PATH, path);  
                     uar_file_destroy (dir_file);  
                     closedir (dir);  
                     return NULL;  
                 }  
   
             uint64_t dnamelen = strlen (entry->d_name);  
   
             char *fullpath  
                 = path_concat (path, entry->d_name, strlen (path), dnamelen);  
             assert (fullpath != NULL);  
   
             char *fullname  
                 = path_concat (name, entry->d_name, namelen, dnamelen);  
             assert (fullname != NULL);  
1301    
1302              if (lstat (fullpath, &stinfo) != 0)              if (fread (buffer, 1, size, uar->stream) != size)
1303                  {                  {
1304                      uar_set_error (uar, UAR_IO_ERROR, fullpath);                      perror ("read");
1305                      goto uar_add_dir_error;                      return;
1306                  }                  }
1307    
1308              if (S_ISREG (stinfo.st_mode))              for (size_t i = 0; i < size; i++)
                 {  
                     struct uar_file *file  
                         = uar_add_file (uar, fullname, fullpath, &stinfo);  
   
                     if (file == NULL)  
                         {  
                             goto uar_add_dir_error;  
                         }  
   
                     if (callback != NULL  
                         && !callback (file, fullname, fullpath))  
                         {  
                             uar_set_error (uar, UAR_SUCCESS, NULL);  
                             goto uar_add_dir_error;  
                         }  
   
                     file->mode = stinfo.st_mode;  
                     dir_size += file->data.size;  
                 }  
             else if (S_ISDIR (stinfo.st_mode))  
1309                  {                  {
1310                      struct uar_file *direntry                      if (buffer[i] == '\n')
1311                          = uar_add_dir (uar, fullname, fullpath, callback);                          putchar ('\n');
1312                        else
1313                      if (direntry == NULL)                          putchar (buffer[i]);
                         {  
                             goto uar_add_dir_error;  
                         }  
   
                     direntry->mode = stinfo.st_mode;  
                     dir_size += direntry->data.size;  
1314                  }                  }
             else  
                 assert (false && "Not supported");  
   
             free (fullpath);  
             free (fullname);  
1315    
1316              continue;              file->data.size -= size;
   
         uar_add_dir_error:  
             cerrno = errno;  
             uar_file_destroy (dir_file);  
             free (fullpath);  
             free (fullname);  
             errno = cerrno;  
             goto uar_add_dir_end;  
         }  
   
     dir_file->data.size = dir_size;  
   
 uar_add_dir_end:  
     cerrno = errno;  
     closedir (dir);  
   
     if (free_name)  
         free (name);  
   
     errno = cerrno;  
     return dir_file;  
 }  
   
 void  
 uar_file_set_mode (struct uar_file *file, mode_t mode)  
 {  
     file->mode = mode;  
 }  
   
 static void  
 uar_debug_print_file_contents (const struct uar_archive *uar,  
                                struct uar_file *file)  
 {  
     printf ("    contents:\n");  
     printf ("==================\n");  
     fflush (stdout);  
   
     ssize_t size  
         = write (STDOUT_FILENO, uar->buffer + file->offset, file->data.size);  
   
     if (size == -1 || ((uint64_t) size) != file->data.size)  
         {  
             perror ("write");  
             return;  
1317          }          }
1318    
1319      putchar ('\n');      putchar ('\n');
# Line 1450  uar_debug_print (const struct uar_archiv Line 1330  uar_debug_print (const struct uar_archiv
1330      printf ("  flags: %u\n", uar->header.flags);      printf ("  flags: %u\n", uar->header.flags);
1331      printf ("  nfiles: %lu\n", uar->header.nfiles);      printf ("  nfiles: %lu\n", uar->header.nfiles);
1332      printf ("  size: %lu\n", uar->header.size);      printf ("  size: %lu\n", uar->header.size);
     printf ("  stream?: %i\n", uar->is_stream);  
1333    
1334      for (uint64_t i = 0; i < uar->header.nfiles; i++)      for (uint64_t i = 0; i < uar->header.nfiles; i++)
1335          {          {
# Line 1480  uar_debug_print (const struct uar_archiv Line 1359  uar_debug_print (const struct uar_archiv
1359  }  }
1360    
1361  bool  bool
1362  uar_write (struct uar_archive *uar, const char *filename)  uar_stream_iterate (struct uar_archive *uar,
1363  {                      bool (*callback) (struct uar_file *file, void *data),
1364      FILE *stream = fopen (filename, "wb");                      void *data)
   
     if (stream == NULL)  
         {  
             uar_set_error (uar, UAR_IO_ERROR, filename);  
             return false;  
         }  
   
     if (fwrite (&uar->header, sizeof (struct uar_header), 1, stream) != 1)  
         {  
             uar_set_error (uar, UAR_IO_ERROR, filename);  
             fclose (stream);  
             return false;  
         }  
   
     for (uint64_t i = 0; i < uar->header.nfiles; i++)  
         {  
             struct uar_file *file = uar->files[i];  
   
             if (fwrite (file, sizeof (struct uar_file), 1, stream) != 1)  
                 {  
                     uar_set_error (uar, UAR_IO_ERROR, file->name);  
                     fclose (stream);  
                     return false;  
                 }  
   
             if (fwrite (file->name, 1, file->namelen, stream) != file->namelen)  
                 {  
                     uar_set_error (uar, UAR_IO_ERROR, file->name);  
                     fclose (stream);  
                     return false;  
                 }  
         }  
   
     if (fwrite (uar->buffer, 1, uar->header.size, stream) != uar->header.size)  
         {  
             uar_set_error (uar, UAR_IO_ERROR, NULL);  
             fclose (stream);  
             return false;  
         }  
   
     fclose (stream);  
     return true;  
 }  
   
 bool  
 uar_extract (struct uar_archive *uar, const char *cwd,  
              bool (*callback) (struct uar_file *file))  
 {  
     if (cwd != NULL && chdir (cwd) != 0)  
         {  
             uar_set_error (uar, UAR_SYSTEM_ERROR, NULL);  
             return false;  
         }  
   
     for (uint64_t i = 0; i < uar->header.nfiles; i++)  
         {  
             struct uar_file *file = uar->files[i];  
   
             if (callback != NULL && !callback (file))  
                 return false;  
   
             char *name = file->name;  
   
             if (name[0] == '/')  
                 name += 2;  
   
             switch (file->type)  
                 {  
                 case UF_FILE:  
                     {  
                         FILE *stream = fopen (name, "wb");  
   
                         if (stream == NULL)  
                             {  
                                 uar_set_error (uar, UAR_IO_ERROR, name);  
                                 return false;  
                             }  
   
                         if (fwrite (uar->buffer + file->offset, 1,  
                                     file->data.size, stream)  
                             != file->data.size)  
                             {  
                                 uar_set_error (uar, UAR_IO_ERROR, name);  
                                 return false;  
                             }  
   
                         fchmod (fileno (stream), file->mode & 07777);  
                         fclose (stream);  
                     }  
                     break;  
   
                 case UF_DIR:  
                     if (file->namelen == 1 && file->name[0] == '/')  
                         continue;  
   
                     if (mkdir (name, file->mode) != 0)  
                         {  
                             uar_set_error (uar, UAR_SYSTEM_ERROR, name);  
                             return false;  
                         }  
   
                     break;  
   
                 default:  
                     assert (false && "unknown file type");  
                     return false;  
                 }  
         }  
   
     return true;  
 }  
   
 bool  
 uar_iterate (struct uar_archive *uar,  
              bool (*callback) (struct uar_file *file, void *data), void *data)  
1365  {  {
1366      for (uint64_t i = 0; i < uar->header.nfiles; i++)      for (uint64_t i = 0; i < uar->header.nfiles; i++)
1367          {          {

Legend:
Removed from v.39  
changed lines
  Added in v.40

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26