Add code for accessing tar archives 72/68772/3
authorKrzysztof Opasiak <k.opasiak@samsung.com>
Mon, 9 May 2016 11:20:25 +0000 (13:20 +0200)
committerKrzysztof Opasiak <k.opasiak@samsung.com>
Fri, 3 Jun 2016 18:03:58 +0000 (20:03 +0200)
Add implementation of data source for accessing tar files.
This is needed to flash tar.gz file using lthor.

Change-Id: Id5abbf258d41f37c569c65753bb8866bb9a84b6a
Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
libthor/thor_internal.h
libthor/thor_tar.c [new file with mode: 0644]

index 9e743864b1eb8f7a2ed5b006747d96547a4b47c3..05f7671f00f8b4dbcad64f3517984d2e85b3fe88 100644 (file)
@@ -46,5 +46,7 @@ struct thor_device_handle {
 
 int t_file_get_data_src(const char *path, struct thor_data_src **data);
 
+int t_tar_get_data_src(const char *path, struct thor_data_src **data);
+
 #endif /* THOR_INTERNAL_H__ */
 
diff --git a/libthor/thor_tar.c b/libthor/thor_tar.c
new file mode 100644 (file)
index 0000000..b74e126
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * libthor - Tizen Thor communication protocol
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <archive.h>
+#include <archive_entry.h>
+#include <errno.h>
+#include <string.h>
+
+#include "thor.h"
+#include "thor_internal.h"
+
+struct tar_data_src {
+       struct thor_data_src src;
+       struct archive *ar;
+       struct archive_entry *ae;
+       size_t total_size;
+};
+
+static size_t tar_get_file_length(struct thor_data_src *src)
+{
+       struct tar_data_src *tardata =
+               container_of(src, struct tar_data_src, src);
+
+       return archive_entry_size(tardata->ae);
+}
+
+static size_t tar_get_size(struct thor_data_src *src)
+{
+       struct tar_data_src *tardata =
+               container_of(src, struct tar_data_src, src);
+
+       return tardata->total_size;
+}
+
+static size_t tar_get_data_block(struct thor_data_src *src,
+                                void *data, size_t len)
+{
+       struct tar_data_src *tardata =
+               container_of(src, struct tar_data_src, src);
+
+       return archive_read_data(tardata->ar, data, len);
+}
+
+static const char *tar_get_file_name(struct thor_data_src *src)
+{
+       struct tar_data_src *tardata =
+               container_of(src, struct tar_data_src, src);
+
+       return archive_entry_pathname(tardata->ae);
+}
+
+static int tar_next_file(struct thor_data_src *src)
+{
+       struct tar_data_src *tardata =
+               container_of(src, struct tar_data_src, src);
+       int ret;
+
+       ret = archive_read_next_header2(tardata->ar, tardata->ae);
+       if (ret == ARCHIVE_OK)
+               return 1;
+
+       if (ret == ARCHIVE_EOF)
+               return 0;
+
+       return -EINVAL;
+}
+
+static void tar_release(struct thor_data_src *src)
+{
+       struct tar_data_src *tardata =
+               container_of(src, struct tar_data_src, src);
+
+       archive_read_close(tardata->ar);
+       archive_read_finish(tardata->ar);
+       archive_entry_free(tardata->ae);
+       free(tardata);
+}
+
+static int tar_prep_read(const char *path, struct archive **archive,
+                        struct archive_entry **aentry)
+{
+       struct archive *ar;
+       struct archive_entry *ae;
+       int ret;
+
+       ar = archive_read_new();
+       if (!ar)
+               return -ENOMEM;
+
+       ae = archive_entry_new();
+       if (!ae)
+               goto read_finish;
+
+       archive_read_support_format_tar(ar);
+       archive_read_support_compression_gzip(ar);
+       archive_read_support_compression_bzip2(ar);
+
+       if (!strcmp(path, "-"))
+               ret = archive_read_open_FILE(ar, stdin);
+       else
+               ret = archive_read_open_filename(ar, path, 512);
+
+       if (ret)
+               goto cleanup;
+
+       *archive = ar;
+       *aentry = ae;
+       return 0;
+cleanup:
+       archive_entry_free(ae);
+read_finish:
+       archive_read_finish(ar);
+       return ret;
+}
+
+static int tar_calculate_total(const char *path, struct tar_data_src *tardata)
+{
+       struct archive *ar;
+       struct archive_entry *ae;
+       int ret;
+
+       /*
+        * Yes this is very ugly but libarchive doesn't
+        * allow to reset position :(
+        */
+       ret = tar_prep_read(path, &ar, &ae);
+       if (ret)
+               goto out;
+
+       tardata->total_size = 0;
+       while (1) {
+               ret = archive_read_next_header2(ar, ae);
+               if (ret == ARCHIVE_EOF) {
+                       break;
+               } else if (ret != ARCHIVE_OK) {
+                       tardata->total_size = -EINVAL;
+                       goto cleanup;
+               }
+
+               tardata->total_size += archive_entry_size(ae);
+       }
+
+       ret = 0;
+cleanup:
+       archive_read_close(ar);
+       archive_read_finish(ar);
+       archive_entry_free(ae);
+out:
+       return ret;
+}
+
+int t_tar_get_data_src(const char *path, struct thor_data_src **data)
+{
+       struct tar_data_src *tdata;
+       int ret;
+
+       tdata = calloc(1, sizeof(*tdata));
+       if (!tdata)
+               return -ENOMEM;
+
+       /* open the tar archive */
+       ret = tar_prep_read(path, &tdata->ar, &tdata->ae);
+       if (ret)
+               goto free_tdata;
+
+       tdata->src.get_file_length = tar_get_file_length;
+       tdata->src.get_size = tar_get_size;
+       tdata->src.get_block = tar_get_data_block;
+       tdata->src.get_name = tar_get_file_name;
+       tdata->src.next_file = tar_next_file;
+       tdata->src.release = tar_release;
+
+       ret = tar_calculate_total(path, tdata);
+       if (ret < 0)
+               goto read_close;
+
+       *data = &tdata->src;
+       return 0;
+
+read_close:
+       archive_read_close(tdata->ar);
+       archive_entry_free(tdata->ae);
+free_tdata:
+       free(tdata);
+       return ret;
+}
+