summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2020-09-04 19:26:31 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2020-09-16 09:34:35 +0200
commit0a0cbefc6ebb6174aad3e6f0b8a6dea87aed49da (patch)
tree7b1a69382f7480e442620b6176c1673abcf81b3c
parent4b994ac359757098ebc09263fff9e2290a58de71 (diff)
Remodel file extraction tools to use libfstream
This commit rewrites the libtar write paths to use libfstream insead of a FILE pointer. Also, the libcommon file extraction function is remodeled to use libfstream. In accordance, rdsquashfs, sqfs2tar and sqfsdiff have some minor adjustments made to work with the ported libtar and libcommon. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--bin/rdsquashfs/Makemodule.am2
-rw-r--r--bin/rdsquashfs/fill_files.c30
-rw-r--r--bin/rdsquashfs/rdsquashfs.c14
-rw-r--r--bin/sqfs2tar/Makemodule.am5
-rw-r--r--bin/sqfs2tar/sqfs2tar.c21
-rw-r--r--bin/sqfs2tar/sqfs2tar.h2
-rw-r--r--bin/sqfs2tar/write_tree.c2
-rw-r--r--bin/sqfsdiff/Makemodule.am4
-rw-r--r--bin/sqfsdiff/extract.c13
-rw-r--r--include/common.h3
-rw-r--r--include/tar.h15
-rw-r--r--lib/common/data_reader_dump.c57
-rw-r--r--lib/tar/Makemodule.am3
-rw-r--r--lib/tar/padd_file.c6
-rw-r--r--lib/tar/write_header.c30
-rw-r--r--lib/tar/write_retry.c35
16 files changed, 86 insertions, 156 deletions
diff --git a/bin/rdsquashfs/Makemodule.am b/bin/rdsquashfs/Makemodule.am
index e4f3b96..094771c 100644
--- a/bin/rdsquashfs/Makemodule.am
+++ b/bin/rdsquashfs/Makemodule.am
@@ -4,7 +4,7 @@ rdsquashfs_SOURCES += bin/rdsquashfs/restore_fstree.c bin/rdsquashfs/describe.c
rdsquashfs_SOURCES += bin/rdsquashfs/fill_files.c bin/rdsquashfs/dump_xattrs.c
rdsquashfs_SOURCES += bin/rdsquashfs/stat.c
rdsquashfs_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
-rdsquashfs_LDADD = libcommon.a libcompat.a libsquashfs.la
+rdsquashfs_LDADD = libcommon.a libfstream.a libcompat.a libsquashfs.la
rdsquashfs_LDADD += libfstree.a $(LZO_LIBS) $(PTHREAD_LIBS)
dist_man1_MANS += bin/rdsquashfs/rdsquashfs.1
diff --git a/bin/rdsquashfs/fill_files.c b/bin/rdsquashfs/fill_files.c
index b75afbf..63ad640 100644
--- a/bin/rdsquashfs/fill_files.c
+++ b/bin/rdsquashfs/fill_files.c
@@ -135,29 +135,31 @@ static int gen_file_list_dfs(const sqfs_tree_node_t *n)
static int fill_files(sqfs_data_reader_t *data, int flags)
{
+ int ret, openflags;
+ ostream_t *fp;
size_t i;
- FILE *fp;
+
+ openflags = OSTREAM_OPEN_OVERWRITE;
+
+ if (flags & UNPACK_NO_SPARSE)
+ openflags |= OSTREAM_OPEN_SPARSE;
for (i = 0; i < num_files; ++i) {
- fp = fopen(files[i].path, "wb");
- if (fp == NULL) {
- fprintf(stderr, "unpacking %s: %s\n",
- files[i].path, strerror(errno));
+ fp = ostream_open_file(files[i].path, openflags);
+ if (fp == NULL)
return -1;
- }
if (!(flags & UNPACK_QUIET))
printf("unpacking %s\n", files[i].path);
- if (sqfs_data_reader_dump(files[i].path, data, files[i].inode,
- fp, block_size,
- (flags & UNPACK_NO_SPARSE) == 0)) {
- fclose(fp);
- return -1;
- }
+ ret = sqfs_data_reader_dump(files[i].path, data, files[i].inode,
+ fp, block_size);
+ if (ret == 0)
+ ret = ostream_flush(fp);
- fflush(fp);
- fclose(fp);
+ sqfs_destroy(fp);
+ if (ret)
+ return -1;
}
return 0;
diff --git a/bin/rdsquashfs/rdsquashfs.c b/bin/rdsquashfs/rdsquashfs.c
index 1c11afa..5b6ce19 100644
--- a/bin/rdsquashfs/rdsquashfs.c
+++ b/bin/rdsquashfs/rdsquashfs.c
@@ -115,18 +115,28 @@ int main(int argc, char **argv)
if (stat_file(n))
goto out;
break;
- case OP_CAT:
+ case OP_CAT: {
+ ostream_t *fp;
+
if (!S_ISREG(n->inode->base.mode)) {
fprintf(stderr, "/%s: not a regular file\n",
opt.cmdpath);
goto out;
}
+ fp = ostream_open_stdout();
+ if (fp == NULL)
+ goto out;
+
if (sqfs_data_reader_dump(opt.cmdpath, data, n->inode,
- stdout, super.block_size, false)) {
+ fp, super.block_size)) {
+ sqfs_destroy(fp);
goto out;
}
+
+ sqfs_destroy(fp);
break;
+ }
case OP_UNPACK:
if (opt.unpack_root != NULL) {
if (mkdir_p(opt.unpack_root))
diff --git a/bin/sqfs2tar/Makemodule.am b/bin/sqfs2tar/Makemodule.am
index f8d95cc..cd00508 100644
--- a/bin/sqfs2tar/Makemodule.am
+++ b/bin/sqfs2tar/Makemodule.am
@@ -2,8 +2,9 @@ sqfs2tar_SOURCES = bin/sqfs2tar/sqfs2tar.c bin/sqfs2tar/sqfs2tar.h
sqfs2tar_SOURCES += bin/sqfs2tar/options.c bin/sqfs2tar/write_tree.c
sqfs2tar_SOURCES += bin/sqfs2tar/xattr.c
sqfs2tar_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
-sqfs2tar_LDADD = libcommon.a libutil.a libsquashfs.la libtar.a libcompat.a
-sqfs2tar_LDADD += libfstree.a $(LZO_LIBS) $(PTHREAD_LIBS)
+sqfs2tar_LDADD = libcommon.a libutil.a libsquashfs.la libtar.a
+sqfs2tar_LDADD += libfstream.a libcompat.a libfstree.a
+sqfs2tar_LDADD += $(LZO_LIBS) $(PTHREAD_LIBS)
dist_man1_MANS += bin/sqfs2tar/sqfs2tar.1
bin_PROGRAMS += sqfs2tar
diff --git a/bin/sqfs2tar/sqfs2tar.c b/bin/sqfs2tar/sqfs2tar.c
index 8c5f631..c5d1201 100644
--- a/bin/sqfs2tar/sqfs2tar.c
+++ b/bin/sqfs2tar/sqfs2tar.c
@@ -9,7 +9,7 @@
sqfs_xattr_reader_t *xr;
sqfs_data_reader_t *data;
sqfs_super_t super;
-FILE *out_file = NULL;
+ostream_t *out_file = NULL;
static sqfs_file_t *file;
@@ -63,8 +63,7 @@ static int terminate_archive(void)
memset(buffer, '\0', sizeof(buffer));
- return write_retry("adding archive terminator", out_file,
- buffer, sizeof(buffer));
+ return ostream_append(out_file, buffer, sizeof(buffer));
}
static sqfs_tree_node_t *tree_merge(sqfs_tree_node_t *lhs,
@@ -118,13 +117,7 @@ int main(int argc, char **argv)
process_args(argc, argv);
-#ifdef _WIN32
- _setmode(_fileno(stdout), _O_BINARY);
- out_file = stdout;
-#else
- out_file = freopen(NULL, "wb", stdout);
-#endif
-
+ out_file = ostream_open_stdout();
if (out_file == NULL) {
perror("changing stdout to binary mode");
goto out_dirs;
@@ -133,7 +126,7 @@ int main(int argc, char **argv)
file = sqfs_open_file(filename, SQFS_FILE_OPEN_READ_ONLY);
if (file == NULL) {
perror(filename);
- goto out_dirs;
+ goto out_ostrm;
}
ret = sqfs_super_read(&super, file);
@@ -244,8 +237,10 @@ int main(int argc, char **argv)
if (terminate_archive())
goto out;
+ if (ostream_flush(out_file))
+ goto out;
+
status = EXIT_SUCCESS;
- fflush(out_file);
out:
if (root != NULL)
sqfs_dir_tree_destroy(root);
@@ -262,6 +257,8 @@ out_cmp:
sqfs_destroy(cmp);
out_fd:
sqfs_destroy(file);
+out_ostrm:
+ sqfs_destroy(out_file);
out_dirs:
for (i = 0; i < num_subdirs; ++i)
free(subdirs[i]);
diff --git a/bin/sqfs2tar/sqfs2tar.h b/bin/sqfs2tar/sqfs2tar.h
index 6eee2b1..70f51ef 100644
--- a/bin/sqfs2tar/sqfs2tar.h
+++ b/bin/sqfs2tar/sqfs2tar.h
@@ -37,7 +37,7 @@ void process_args(int argc, char **argv);
extern sqfs_xattr_reader_t *xr;
extern sqfs_data_reader_t *data;
extern sqfs_super_t super;
-extern FILE *out_file;
+extern ostream_t *out_file;
char *assemble_tar_path(char *name, bool is_dir);
diff --git a/bin/sqfs2tar/write_tree.c b/bin/sqfs2tar/write_tree.c
index 28e1cf0..e460481 100644
--- a/bin/sqfs2tar/write_tree.c
+++ b/bin/sqfs2tar/write_tree.c
@@ -105,7 +105,7 @@ static int write_tree_dfs(const sqfs_tree_node_t *n)
if (S_ISREG(sb.st_mode)) {
if (sqfs_data_reader_dump(name, data, n->inode, out_file,
- super.block_size, false)) {
+ super.block_size)) {
free(name);
return -1;
}
diff --git a/bin/sqfsdiff/Makemodule.am b/bin/sqfsdiff/Makemodule.am
index b5de502..8331f25 100644
--- a/bin/sqfsdiff/Makemodule.am
+++ b/bin/sqfsdiff/Makemodule.am
@@ -4,8 +4,8 @@ sqfsdiff_SOURCES += bin/sqfsdiff/compare_dir.c bin/sqfsdiff/node_compare.c
sqfsdiff_SOURCES += bin/sqfsdiff/compare_files.c bin/sqfsdiff/super.c
sqfsdiff_SOURCES += bin/sqfsdiff/extract.c
sqfsdiff_CFLAGS = $(AM_CFLAGS) $(PTHREAD_CFLAGS)
-sqfsdiff_LDADD = libcommon.a libsquashfs.la libcompat.a $(LZO_LIBS) libfstree.a
-sqfsdiff_LDADD += $(PTHREAD_LIBS)
+sqfsdiff_LDADD = libcommon.a libsquashfs.la libfstream.a libcompat.a
+sqfsdiff_LDADD += $(LZO_LIBS) libfstree.a $(PTHREAD_LIBS)
dist_man1_MANS += bin/sqfsdiff/sqfsdiff.1
bin_PROGRAMS += sqfsdiff
diff --git a/bin/sqfsdiff/extract.c b/bin/sqfsdiff/extract.c
index 979572a..0c68918 100644
--- a/bin/sqfsdiff/extract.c
+++ b/bin/sqfsdiff/extract.c
@@ -10,7 +10,7 @@ static int extract(sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode,
const char *prefix, const char *path, size_t block_size)
{
char *ptr, *temp;
- FILE *fp;
+ ostream_t *fp;
temp = alloca(strlen(prefix) + strlen(path) + 2);
sprintf(temp, "%s/%s", prefix, path);
@@ -21,19 +21,20 @@ static int extract(sqfs_data_reader_t *data, const sqfs_inode_generic_t *inode,
return -1;
*ptr = '/';
- fp = fopen(temp, "wb");
+ fp = ostream_open_file(temp, OSTREAM_OPEN_OVERWRITE |
+ OSTREAM_OPEN_SPARSE);
if (fp == NULL) {
perror(temp);
return -1;
}
- if (sqfs_data_reader_dump(path, data, inode, fp, block_size, true)) {
- fclose(fp);
+ if (sqfs_data_reader_dump(path, data, inode, fp, block_size)) {
+ sqfs_destroy(fp);
return -1;
}
- fflush(fp);
- fclose(fp);
+ ostream_flush(fp);
+ sqfs_destroy(fp);
return 0;
}
diff --git a/include/common.h b/include/common.h
index 196f774..8639558 100644
--- a/include/common.h
+++ b/include/common.h
@@ -28,6 +28,7 @@
#include "sqfs/dir.h"
#include "sqfs/io.h"
+#include "fstream.h"
#include "compat.h"
#include "fstree.h"
#include "tar.h"
@@ -111,7 +112,7 @@ char *sqfs_tree_node_get_path(const sqfs_tree_node_t *node);
int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data,
const sqfs_inode_generic_t *inode,
- FILE *fp, size_t block_size, bool allow_sparse);
+ ostream_t *fp, size_t block_size);
sqfs_file_t *sqfs_get_stdin_file(FILE *fp, const sparse_map_t *map,
sqfs_u64 size);
diff --git a/include/tar.h b/include/tar.h
index f235d08..38ec656 100644
--- a/include/tar.h
+++ b/include/tar.h
@@ -9,6 +9,7 @@
#include "config.h"
#include "compat.h"
+#include "fstream.h"
#include <stdbool.h>
#include <stdint.h>
@@ -122,11 +123,11 @@ typedef struct {
The counter is an incremental record counter used if additional
headers need to be generated.
*/
-int write_tar_header(FILE *fp, const struct stat *sb, const char *name,
+int write_tar_header(ostream_t *fp, const struct stat *sb, const char *name,
const char *slink_target, const tar_xattr_t *xattr,
unsigned int counter);
-int write_hard_link(FILE *fp, const struct stat *sb, const char *name,
+int write_hard_link(ostream_t *fp, const struct stat *sb, const char *name,
const char *target, unsigned int counter);
/* calcuate and skip the zero padding */
@@ -145,7 +146,7 @@ void clear_header(tar_header_decoded_t *hdr);
Write zero bytes to an output file to padd it to the tar record size.
Returns 0 on success. On failure, prints error message to stderr.
*/
-int padd_file(FILE *fp, sqfs_u64 size);
+int padd_file(ostream_t *fp, sqfs_u64 size);
/*
@@ -156,12 +157,4 @@ int padd_file(FILE *fp, sqfs_u64 size);
*/
int read_retry(const char *errstr, FILE *fp, void *buffer, size_t size);
-/*
- A wrapper around the write() system call. It retries the write if it is
- interrupted by a signal or only part of the data was written. Returns 0
- on success. Writes to stderr on failure using 'errstr' as a perror style
- error prefix.
-*/
-int write_retry(const char *errstr, FILE *fp, const void *data, size_t size);
-
#endif /* TAR_H */
diff --git a/lib/common/data_reader_dump.c b/lib/common/data_reader_dump.c
index d832388..7902c25 100644
--- a/lib/common/data_reader_dump.c
+++ b/lib/common/data_reader_dump.c
@@ -11,33 +11,9 @@
#include <stdio.h>
#include <errno.h>
-static int append_block(FILE *fp, const sqfs_u8 *data, size_t size)
-{
- const sqfs_u8 *ptr = data;
- size_t ret;
-
- while (size > 0) {
- if (ferror(fp)) {
- fputs("writing data block: error writing to file\n",
- stderr);
- }
-
- if (feof(fp)) {
- fputs("writing data block: unexpected end of file\n",
- stderr);
- }
-
- ret = fwrite(ptr, 1, size, fp);
- ptr += ret;
- size -= ret;
- }
-
- return 0;
-}
-
int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data,
const sqfs_inode_generic_t *inode,
- FILE *fp, size_t block_size, bool allow_sparse)
+ ostream_t *fp, size_t block_size)
{
size_t i, diff, chunk_size;
sqfs_u64 filesz;
@@ -46,23 +22,12 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data,
sqfs_inode_get_file_size(inode, &filesz);
-#if defined(_POSIX_VERSION) && (_POSIX_VERSION >= 200112L)
- if (allow_sparse) {
- int fd = fileno(fp);
-
- if (ftruncate(fd, filesz))
- goto fail_sparse;
- }
-#else
- allow_sparse = false;
-#endif
-
for (i = 0; i < sqfs_inode_get_file_block_count(inode); ++i) {
diff = (filesz < block_size) ? filesz : block_size;
- if (SQFS_IS_SPARSE_BLOCK(inode->extra[i]) && allow_sparse) {
- if (fseek(fp, diff, SEEK_CUR) < 0)
- goto fail_sparse;
+ if (SQFS_IS_SPARSE_BLOCK(inode->extra[i])) {
+ if (ostream_append_sparse(fp, diff))
+ return -1;
} else {
err = sqfs_data_reader_get_block(data, inode, i,
&chunk_size, &chunk);
@@ -71,7 +36,7 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data,
return -1;
}
- err = append_block(fp, chunk, chunk_size);
+ err = ostream_append(fp, chunk, chunk_size);
free(chunk);
if (err)
@@ -89,16 +54,12 @@ int sqfs_data_reader_dump(const char *name, sqfs_data_reader_t *data,
return -1;
}
- if (append_block(fp, chunk, chunk_size)) {
- free(chunk);
- return -1;
- }
-
+ err = ostream_append(fp, chunk, chunk_size);
free(chunk);
+
+ if (err)
+ return -1;
}
return 0;
-fail_sparse:
- perror("creating sparse output file");
- return -1;
}
diff --git a/lib/tar/Makemodule.am b/lib/tar/Makemodule.am
index fe18895..7ba0454 100644
--- a/lib/tar/Makemodule.am
+++ b/lib/tar/Makemodule.am
@@ -3,8 +3,7 @@ libtar_a_SOURCES += lib/tar/number.c lib/tar/checksum.c lib/tar/cleanup.c
libtar_a_SOURCES += lib/tar/read_sparse_map.c lib/tar/read_sparse_map_old.c
libtar_a_SOURCES += lib/tar/base64.c lib/tar/urldecode.c lib/tar/internal.h
libtar_a_SOURCES += lib/tar/padd_file.c lib/tar/read_retry.c include/tar.h
-libtar_a_SOURCES += lib/tar/write_retry.c lib/tar/pax_header.c
-libtar_a_SOURCES += lib/tar/read_sparse_map_new.c
+libtar_a_SOURCES += lib/tar/pax_header.c lib/tar/read_sparse_map_new.c
libtar_a_CFLAGS = $(AM_CFLAGS)
libtar_a_CPPFLAGS = $(AM_CPPFLAGS)
diff --git a/lib/tar/padd_file.c b/lib/tar/padd_file.c
index dd945a3..1173096 100644
--- a/lib/tar/padd_file.c
+++ b/lib/tar/padd_file.c
@@ -10,7 +10,7 @@
#include <stdlib.h>
#include <stdio.h>
-int padd_file(FILE *fp, sqfs_u64 size)
+int padd_file(ostream_t *fp, sqfs_u64 size)
{
size_t padd_sz = size % TAR_RECORD_SIZE;
int status = -1;
@@ -25,10 +25,8 @@ int padd_file(FILE *fp, sqfs_u64 size)
if (buffer == NULL)
goto fail_errno;
- if (write_retry("padding output file to block size",
- fp, buffer, padd_sz)) {
+ if (ostream_append(fp, buffer, padd_sz))
goto out;
- }
status = 0;
out:
diff --git a/lib/tar/write_header.c b/lib/tar/write_header.c
index aaf9f08..3caa1b3 100644
--- a/lib/tar/write_header.c
+++ b/lib/tar/write_header.c
@@ -53,7 +53,7 @@ static void write_number_signed(char *dst, sqfs_s64 value, int digits)
}
}
-static int write_header(FILE *fp, const struct stat *sb, const char *name,
+static int write_header(ostream_t *fp, const struct stat *sb, const char *name,
const char *slink_target, int type)
{
int maj = 0, min = 0;
@@ -88,10 +88,10 @@ static int write_header(FILE *fp, const struct stat *sb, const char *name,
update_checksum(&hdr);
- return write_retry("writing tar header record", fp, &hdr, sizeof(hdr));
+ return ostream_append(fp, &hdr, sizeof(hdr));
}
-static int write_gnu_header(FILE *fp, const struct stat *orig,
+static int write_gnu_header(ostream_t *fp, const struct stat *orig,
const char *payload, size_t payload_len,
int type, const char *name)
{
@@ -104,10 +104,8 @@ static int write_gnu_header(FILE *fp, const struct stat *orig,
if (write_header(fp, &sb, name, NULL, type))
return -1;
- if (write_retry("writing GNU extension header",
- fp, payload, payload_len)) {
+ if (ostream_append(fp, payload, payload_len))
return -1;
- }
return padd_file(fp, payload_len);
}
@@ -136,7 +134,7 @@ static size_t prefix_digit_len(size_t len)
return ndigit;
}
-static int write_schily_xattr(FILE *fp, const struct stat *orig,
+static int write_schily_xattr(ostream_t *fp, const struct stat *orig,
const char *name, const tar_xattr_t *xattr)
{
static const char *prefix = "SCHILY.xattr.";
@@ -161,15 +159,20 @@ static int write_schily_xattr(FILE *fp, const struct stat *orig,
len = strlen(prefix) + strlen(it->key) + it->value_len + 3;
len += prefix_digit_len(len);
- fprintf(fp, PRI_SZ " %s%s=", len, prefix, it->key);
- fwrite(it->value, 1, it->value_len, fp);
- fputc('\n', fp);
+ if (ostream_printf(fp, PRI_SZ " %s%s=",
+ len, prefix, it->key) < 0) {
+ return -1;
+ }
+ if (ostream_append(fp, it->value, it->value_len))
+ return -1;
+ if (ostream_append(fp, "\n", 1))
+ return -1;
}
return padd_file(fp, total_size);
}
-int write_tar_header(FILE *fp, const struct stat *sb, const char *name,
+int write_tar_header(ostream_t *fp, const struct stat *sb, const char *name,
const char *slink_target, const tar_xattr_t *xattr,
unsigned int counter)
{
@@ -228,7 +231,7 @@ out_skip:
return 1;
}
-int write_hard_link(FILE *fp, const struct stat *sb, const char *name,
+int write_hard_link(ostream_t *fp, const struct stat *sb, const char *name,
const char *target, unsigned int counter)
{
tar_header_t hdr;
@@ -274,6 +277,5 @@ int write_hard_link(FILE *fp, const struct stat *sb, const char *name,
write_number(hdr.devminor, 0, sizeof(hdr.devminor));
update_checksum(&hdr);
- return write_retry("writing tar hard link record",
- fp, &hdr, sizeof(hdr));
+ return ostream_append(fp, &hdr, sizeof(hdr));
}
diff --git a/lib/tar/write_retry.c b/lib/tar/write_retry.c
deleted file mode 100644
index f4f3166..0000000
--- a/lib/tar/write_retry.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: LGPL-3.0-or-later */
-/*
- * write_retry.c
- *
- * Copyright (C) 2019 David Oberhollenzer <goliath@infraroot.at>
- */
-#include "config.h"
-
-#include <errno.h>
-#include <stdio.h>
-
-#include "tar.h"
-
-int write_retry(const char *errstr, FILE *fp, const void *data, size_t size)
-{
- size_t ret;
-
- while (size > 0) {
- if (feof(fp)) {
- fprintf(stderr, "%s: write truncated\n", errstr);
- return -1;
- }
-
- if (ferror(fp)) {
- fprintf(stderr, "%s: error writing to file\n", errstr);
- return -1;
- }
-
- ret = fwrite(data, 1, size, fp);
- data = (const char *)data + ret;
- size -= ret;
- }
-
- return 0;
-}