summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/libmisc/untar/untar.c57
-rw-r--r--testsuites/libtests/tar01/init.c199
-rw-r--r--testsuites/libtests/tar01/tar01.doc1
-rw-r--r--testsuites/libtests/tar01/tar01.scn54
-rw-r--r--testsuites/libtests/tar01/tar01.tarbin10240 -> 10240 bytes
5 files changed, 282 insertions, 29 deletions
diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
index a2f09fb99f..8888ab2c57 100644
--- a/cpukit/libmisc/untar/untar.c
+++ b/cpukit/libmisc/untar/untar.c
@@ -126,30 +126,25 @@ Make_Path(const rtems_printer *printer, char *path)
*p = '\0';
if (p[1] == '\0') {
- /* Speculatively unlink the last component so that it can be re-created */
- unlink(path);
return 0;
}
if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
- if (errno == EEXIST || errno == EISDIR) {
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
struct stat sb;
-
- if (stat(path, &sb) != 0) {
+ if (lstat(path, &sb) != 0) {
+ Print_Error(printer, "lstat", path);
+ return -1;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ path);
return -1;
}
-
- if (!S_ISDIR(sb.st_mode)) {
- if (unlink(path) != 0) {
- Print_Error(printer, "unlink", path);
- return -1;
- }
-
- if (mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
- Print_Error(printer, "mkdir (unlink)", path);
- return -1;
- }
- }
+ } else {
+ Print_Error(printer, "mkdir", path);
+ return -1;
}
}
@@ -206,6 +201,12 @@ Untar_ProcessHeader(
if (Make_Path(ctx->printer, ctx->file_path) != 0) {
retval = UNTAR_FAIL;
+ } else {
+ /*
+ * Speculatively unlink. This should unlink everything but non-empty
+ * directories or write protected stuff.
+ */
+ unlink(ctx->file_path);
}
if (ctx->linkflag == SYMTYPE) {
@@ -225,8 +226,22 @@ Untar_ProcessHeader(
rtems_printf(ctx->printer, "untar: dir: %s\n", ctx->file_path);
r = mkdir(ctx->file_path, ctx->mode);
if (r != 0) {
- Print_Error(ctx->printer, "mkdir", ctx->file_path);
- retval = UNTAR_FAIL;
+ if (errno == EEXIST) {
+ /* If it exists already: Check whether it is a directory */
+ struct stat sb;
+ if (lstat(ctx->file_path, &sb) != 0) {
+ Print_Error(ctx->printer, "lstat", ctx->file_path);
+ retval = UNTAR_FAIL;
+ } else if (!S_ISDIR(sb.st_mode)) {
+ rtems_printf(ctx->printer,
+ "untar: mkdir: %s: exists but is not a directory\n",
+ ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
+ } else {
+ Print_Error(ctx->printer, "mkdir", ctx->file_path);
+ retval = UNTAR_FAIL;
+ }
}
}
@@ -426,7 +441,9 @@ Untar_FromFile_Print(
*/
if ((out_fd = creat(ctx.file_path, ctx.mode)) == -1) {
- (void) lseek(fd, SEEK_CUR, 512UL * ctx.nblocks);
+ /* Couldn't create that file. Abort. */
+ retval = UNTAR_FAIL;
+ break;
} else {
for (i = 0; i < ctx.nblocks; i++) {
n = read(fd, bufr, 512);
diff --git a/testsuites/libtests/tar01/init.c b/testsuites/libtests/tar01/init.c
index 4cad67a6ae..2deff3a482 100644
--- a/testsuites/libtests/tar01/init.c
+++ b/testsuites/libtests/tar01/init.c
@@ -7,6 +7,33 @@
* http://www.rtems.org/license/LICENSE.
*/
+/*
+ * Note on the used tar file: Generate the file on a system that supports
+ * symlinks with the following commands (tested on Linux - you might have to
+ * adapt on other systems):
+ *
+ * export WORK=some_work_directory
+ * rm -r ${WORK}
+ * mkdir -p ${WORK}/home/abc/def
+ * mkdir -p ${WORK}/home/dir
+ * cd ${WORK}
+ * echo "#! joel" > home/abc/def/test_script
+ * echo "ls -las /dev" >> home/abc/def/test_script
+ * chmod 755 home/abc/def/test_script
+ * echo "This is a test of loading an RTEMS filesystem from an" > home/test_file
+ * echo "initial tar image." >> home/test_file
+ * echo "Hello world" >> home/dir/file
+ * ln -s home/test_file symlink
+ * tar cf tar01.tar --format=ustar \
+ * symlink \
+ * home/test_file \
+ * home/abc/def/test_script \
+ * home/dir
+ *
+ * Note that "home/dir" is in the archive as separate directory. "home/abc" is
+ * only in the archive as a parent of the file "test_script".
+ */
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -95,6 +122,84 @@ void test_untar_from_memory(void)
}
+static void assert_file_content(
+ const char *name,
+ const char *expected_content,
+ ssize_t expected_size
+)
+{
+ char buf[16];
+ int fd;
+ int rd;
+
+ fd = open(name, O_RDONLY);
+ rtems_test_assert( fd >= 0 );
+ do {
+ rd = read(fd, buf, sizeof(buf));
+ rtems_test_assert( rd >= 0 );
+ if (rd > 0) {
+ rtems_test_assert( expected_size - rd >= 0 );
+ rtems_test_assert( memcmp(buf, expected_content, rd) == 0 );
+ expected_content += rd;
+ expected_size -= rd;
+ }
+ } while(rd > 0);
+ rtems_test_assert( expected_size == 0 );
+ close(fd);
+}
+
+static void assert_content_like_expected(void)
+{
+ const char *directories[] = {
+ "home",
+ "home/abc",
+ "home/abc/def",
+ "home/dir",
+ };
+ const char *symlinks[] = {
+ "symlink",
+ };
+ const struct {
+ const char *name;
+ const char *content;
+ } files[] = {
+ {
+ .name = "home/abc/def/test_script",
+ .content = "#! joel\nls -las /dev\n",
+ }, {
+ .name = "home/test_file",
+ .content = "This is a test of loading an RTEMS filesystem from an\n"
+ "initial tar image.\n",
+ }, {
+ .name = "home/dir/file",
+ .content = "Hello world\n",
+ }
+ };
+ size_t i;
+ struct stat st;
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(directories); ++i) {
+ lstat(directories[i], &st);
+ rtems_test_assert( S_ISDIR(st.st_mode) );
+ }
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(symlinks); ++i) {
+ lstat(symlinks[i], &st);
+ rtems_test_assert( S_ISLNK(st.st_mode) );
+ }
+
+ for(i = 0; i < RTEMS_ARRAY_SIZE(files); ++i) {
+ lstat(files[i].name, &st);
+ rtems_test_assert( S_ISREG(st.st_mode) );
+
+ assert_file_content(
+ files[i].name,
+ files[i].content,
+ strlen(files[i].content)
+ );
+ }
+}
+
void test_untar_from_file(void)
{
int fd;
@@ -119,13 +224,105 @@ void test_untar_from_file(void)
rv = chdir( "/dest" );
rtems_test_assert( rv == 0 );
- /* Untar it */
+ /* Case 1: Untar it into empty directory */
rv = Untar_FromFile( "/test.tar" );
printf("Untaring from file - ");
if (rv != UNTAR_SUCCESSFUL) {
printf ("error: untar failed: %i\n", rv);
exit(1);
}
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 2: Most files exist */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file into existing structure with one missing file - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 3: An empty directory exists where a file should be */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+ rv = mkdir("/dest/home/test_file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ rtems_test_assert( rv == 0 );
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; overwrite empty directory with file - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
+ printf ("successful\n");
+
+ /* Case 4: A file exists where a parent directory should be created */
+ rv = unlink("/dest/home/abc/def/test_script");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/abc/def");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/abc");
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/abc", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; file exists where parent dir should be created - ");
+ if (rv != UNTAR_FAIL) {
+ printf ("error: untar didn't fail like expected: %i\n", rv);
+ exit(1);
+ }
+ printf ("expected fail\n");
+ /* cleanup so that the next one works */
+ rv = unlink("/dest/home/abc");
+ rtems_test_assert( rv == 0 );
+
+ /* Case 5: A non-empty directory exists where a file should be created */
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+ rv = mkdir("/dest/home/test_file", S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/test_file/file",
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; non-empty dir where file should be created - ");
+ if (rv != UNTAR_FAIL) {
+ printf ("error: untar didn't fail like expected: %i\n", rv);
+ exit(1);
+ }
+ printf ("expected fail\n");
+ /* cleanup so that the next one works */
+ rv = unlink("/dest/home/test_file/file");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/test_file");
+ rtems_test_assert( rv == 0 );
+
+ /* Case 6: A file exists where a directory is explicitly in the archive */
+ rv = unlink("/dest/home/dir/file");
+ rtems_test_assert( rv == 0 );
+ rv = unlink("/dest/home/dir");
+ rtems_test_assert( rv == 0 );
+ fd = creat("/dest/home/dir", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ rtems_test_assert( fd >= 0 );
+ close(fd);
+
+ rv = Untar_FromFile( "/test.tar" );
+ printf("Untar from file; overwrite file with explicit directory - ");
+ if (rv != UNTAR_SUCCESSFUL) {
+ printf ("error: untar failed: %i\n", rv);
+ exit(1);
+ }
+ assert_content_like_expected();
printf ("successful\n");
/******************/
diff --git a/testsuites/libtests/tar01/tar01.doc b/testsuites/libtests/tar01/tar01.doc
index 060f98a813..adffdca291 100644
--- a/testsuites/libtests/tar01/tar01.doc
+++ b/testsuites/libtests/tar01/tar01.doc
@@ -20,3 +20,4 @@ directives:
concepts:
+ exercise these routines
++ check whether existing files are overwritten or not overwritten like expected
diff --git a/testsuites/libtests/tar01/tar01.scn b/testsuites/libtests/tar01/tar01.scn
index 68fa951881..dd72f9517b 100644
--- a/testsuites/libtests/tar01/tar01.scn
+++ b/testsuites/libtests/tar01/tar01.scn
@@ -1,9 +1,24 @@
-*** TAR01 TEST ***
-Untaring from memory - successful
+*** BEGIN OF TEST TAR 1 ***
+*** TEST VERSION: 6.0.0.e1efb4eb8a9d6dd5f6f37dafc9feb0a9e6a888f1
+*** TEST STATE: EXPECTED_PASS
+*** TEST BUILD: RTEMS_POSIX_API
+*** TEST TOOLS: 10.3.1 20210409 (RTEMS 6, RSB ad54d1dd3cf8249d9d39deb1dd28b2f294df062d-modified, Newlib eb03ac1)
+Untaring from memory - untar: memory at 0x11ece8 (10240)
+untar: symlink: home/test_file -> symlink
+untar: file: home/test_file (s:73,m:0644)
+untar: file: home/abc/def/test_script (s:21,m:0755)
+untar: dir: home/dir
+untar: file: home/dir/file (s:12,m:0644)
+successful
========= /home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /home/abc/def/test_script: mode: 0755 want: 0755
========= /symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
@@ -11,35 +26,58 @@ initial tar image.
Copy tar image to test.tar
Untaring from file - successful
+Untar from file into existing structure with one missing file - successful
+Untar from file; overwrite empty directory with file - successful
+Untar from file; file exists where parent dir should be created - expected fail
+Untar from file; non-empty dir where file should be created - expected fail
+Untar from file; overwrite file with explicit directory - successful
========= /dest/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-Untaring chunks from memory - untar: dir: home
-untar: file: home/test_file (73)
+Untaring chunks from memory - untar: symlink: home/test_file -> symlink
+untar: file: home/test_file (s:73,m:0644)
+untar: file: home/abc/def/test_script (s:21,m:0755)
+untar: dir: home/dir
+untar: file: home/dir/file (s:12,m:0644)
successful
========= /dest2/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest2/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest2/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest2/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-Untaring chunks from tgz- untar: dir: home
-untar: file: home/test_file (73)
-successful
+Untaring chunks from tgz - successful
========= /dest3/home/test_file =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
+========= /dest3/home/abc/def/test_script =========
+(0)#! joel
+ls -las /dev
+
+ /dest3/home/abc/def/test_script: mode: 0755 want: 0755
========= /dest3/symlink =========
(0)This is a test of loading an RTEMS filesystem from an
initial tar image.
-*** END OF TAR01 TEST ***
+
+
+*** END OF TEST TAR 1 ***
diff --git a/testsuites/libtests/tar01/tar01.tar b/testsuites/libtests/tar01/tar01.tar
index 6c6952ef18..9874f426d1 100644
--- a/testsuites/libtests/tar01/tar01.tar
+++ b/testsuites/libtests/tar01/tar01.tar
Binary files differ