Skip to content

Commit 68594e5

Browse files
Merge pull request fossology#3198 from Siemens-Healthineers/feat/ununpack/lzip
feat(ununpack): add support for lzip archive format Reviewed-by: kaushlendra-pratap.singh@siemens.com Tested-by: kaushlendra-pratap.singh@siemens.com
2 parents 4002952 + fe62cb0 commit 68594e5

File tree

14 files changed

+272
-5
lines changed

14 files changed

+272
-5
lines changed

cmake/FoPackaging.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ resources.")
212212
set(CPACK_DEBIAN_FOSSOLOGY-UNUNPACK_PACKAGE_DEPENDS
213213
"fossology-common, binutils, bzip2, cabextract, cpio, sleuthkit,
214214
genisoimage, poppler-utils, rpm, unrar-free, unzip, p7zip-full, p7zip,
215-
zstd")
215+
zstd, lzip")
216216

217217
set(CPACK_DEBIAN_FOSSOLOGY-UNUNPACK_PACKAGE_SECTION "utils")
218218
else()

src/ununpack/agent/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ foreach(FO_UNP_LIB ununpack ununpack_cov ununpack-sa)
3535
${FO_CWD}/ununpack-ar.c
3636
${FO_CWD}/ununpack-disk.c
3737
${FO_CWD}/ununpack-zstd.c
38+
${FO_CWD}/ununpack-lzip.c
3839
${FO_CWD}/utils.c
3940
${FO_CWD}/checksum.c)
4041
if(${FO_UNP_LIB} STREQUAL "ununpack-sa")

src/ununpack/agent/traverse.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ void TraverseChild (int Index, ContainerInfo *CI, char *NewDir)
189189
/* unpack a ZSTD: source file, source name and destination directory */
190190
rc = ExtractZstd(CI->Source, CI->Partname, Queue[Index].ChildRecurse);
191191
break;
192+
case CMD_LZIP:
193+
/* unpack an LZIP: source file and destination directory */
194+
rc = ExtractLzip(CI->Source, CI->Partname, Queue[Index].ChildRecurse);
195+
break;
192196
case CMD_DEFAULT:
193197
default:
194198
/* use the original name */
@@ -464,6 +468,7 @@ int Traverse (char *Filename, char *Basename,
464468
case CMD_PARTITION:
465469
case CMD_PACK:
466470
case CMD_ZSTD:
471+
case CMD_LZIP:
467472
CI.HasChild=1;
468473
IsContainer=1;
469474
strcat(Queue[Index].ChildRecurse,".dir");

src/ununpack/agent/ununpack-lzip.c

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
SPDX-FileCopyrightText: © 2025 Siemens Healthineers AG
3+
SPDX-FileContributor: Sushant Kumar <sushant.kumar@siemens-healthineers.com>
4+
5+
SPDX-License-Identifier: GPL-2.0-only
6+
*/
7+
8+
#include "ununpack.h"
9+
#include "externs.h"
10+
11+
/**
12+
* \file ununpack-lzip.c
13+
* \brief The universal unpacker - Code to unpack an lzip compressed file.
14+
**/
15+
16+
/**
17+
* \brief Given an lzip file, extract the contents to the directory.
18+
* \param Source Pathname of source file
19+
* \param OrigName Original name of file
20+
* \param Destination Unpack destination
21+
* \return 0 on success, non-zero on failure.
22+
**/
23+
int ExtractLzip(char *Source, const char *OrigName, char *Destination)
24+
{
25+
char Cmd[FILENAME_MAX * 4]; /* command to run */
26+
int rc;
27+
char TempSource[FILENAME_MAX];
28+
char CWD[FILENAME_MAX];
29+
char OutputName[FILENAME_MAX] = {'\0'};
30+
int i;
31+
32+
/* judge if the parameters are empty */
33+
if ((NULL == Source) || (!strcmp(Source, "")) || (NULL == Destination) ||
34+
(!strcmp(Destination, ""))) {
35+
return 1;
36+
}
37+
38+
if (getcwd(CWD, sizeof(CWD)) == NULL) {
39+
fprintf(stderr, "ERROR: directory name longer than %d characters\n",
40+
(int) sizeof(CWD));
41+
return (-1);
42+
}
43+
44+
i = 0;
45+
while (OrigName[i] != '\0') {
46+
if (OrigName[i] == '.') {
47+
const char *ext = &OrigName[i + 1];
48+
if (strncasecmp(ext, "lz", 2) == 0) {
49+
break;
50+
}
51+
else if (strncasecmp(ext, "tlz", 3) == 0) {
52+
/* Usually tlz implies tar.lz, stripping extension leaves base name.
53+
Subsequent file type detection will handle the resulting tar. */
54+
break;
55+
}
56+
}
57+
OutputName[i] = OrigName[i];
58+
i++;
59+
}
60+
/* Null terminate the output name explicitly */
61+
OutputName[i] = '\0';
62+
63+
if (Verbose > 1) {
64+
printf("CWD: %s\n", CWD);
65+
if (!Quiet) { fprintf(stderr, "Extracting lzip: %s\n", Source); }
66+
}
67+
68+
if (chdir(Destination) != 0) {
69+
fprintf(stderr, "ERROR %s.%d: Unable to change directory to %s\n",
70+
__FILE__, __LINE__, Destination);
71+
fprintf(stderr, "ERROR: errno is: %s\n", strerror(errno));
72+
}
73+
74+
if (TaintString(TempSource, FILENAME_MAX, Source, 1, NULL)) {
75+
return (-1);
76+
}
77+
memset(Cmd, '\0', sizeof(Cmd));
78+
79+
if (Verbose > 1) {
80+
printf("Extracting lzip with output name: %s\n", OutputName);
81+
}
82+
83+
/* lzip options:
84+
* -d, --decompress
85+
* -k, --keep (keep input file, consistent with how standard tools behave)
86+
* -f, --force (overwrite output if exists)
87+
* -o, --output (specify output filename)
88+
*/
89+
if (TempSource[0] != '/') {
90+
snprintf(Cmd, sizeof(Cmd),
91+
" (lzip --decompress --keep --force -o '%s/%s' "
92+
"'%s/%s') 2>/dev/null", Destination, OutputName,
93+
CWD, TempSource);
94+
}
95+
else {
96+
snprintf(Cmd, sizeof(Cmd),
97+
" (lzip --decompress --keep --force -o '%s/%s' "
98+
"'%s') 2>/dev/null", Destination, OutputName,
99+
TempSource);
100+
}
101+
102+
rc = WEXITSTATUS(system(Cmd));
103+
if (rc) {
104+
fprintf(stderr, "ERROR: Command failed (rc=%d): %s\n", rc, Cmd);
105+
}
106+
107+
if (chdir(CWD) != 0) {
108+
fprintf(stderr, "ERROR %s.%d: Unable to change directory to %s\n", __FILE__, __LINE__, CWD);
109+
fprintf(stderr, "ERROR: errno is: %s\n", strerror(errno));
110+
}
111+
return (rc);
112+
} /* ExtractLzip() */

src/ununpack/agent/ununpack-lzip.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
SPDX-FileCopyrightText: © 2025 Siemens Healthineers AG
3+
SPDX-FileContributor: Sushant Kumar <sushant.kumar@siemens-healthineers.com>
4+
5+
SPDX-License-Identifier: GPL-2.0-only
6+
*/
7+
8+
#ifndef UNUNPACK_LZIP_H
9+
#define UNUNPACK_LZIP_H
10+
11+
int ExtractLzip(char *Source, const char *OrigName, char *Destination);
12+
13+
#endif

src/ununpack/agent/ununpack.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "checksum.h"
3535
#include "ununpack-ar.h"
3636
#include "ununpack-disk.h"
37+
#include "ununpack-lzip.h"
3738
#include "ununpack-iso.h"
3839
#include "ununpack-zstd.h"
3940

@@ -63,6 +64,7 @@ enum cmdtype
6364
CMD_DISK, /** File system disk */
6465
CMD_DEB, /** Debian source package */
6566
CMD_ZSTD, /** Zstandard compressed file */
67+
CMD_LZIP, /** Lzip compressed file */
6668
CMD_DEFAULT /** Default action */
6769
};
6870

src/ununpack/agent/ununpack_globals.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ cmdlist CMD[] =
100100
/* 34 */{ "application/zstd", "zstd", "-d", ">/dev/null 2>&1", "zstd -lv '%s' > '%s'", CMD_ZSTD, 1, 0177000, 0177000, },
101101
/* 35 */{ "application/x-lz4", "zstd", "-d", ">/dev/null 2>&1", "", CMD_ZSTD, 1, 0177000, 0177000, },
102102
/* 36 */{ "application/x-lzma", "zstd", "-d", ">/dev/null 2>&1", "", CMD_ZSTD, 1, 0177000, 0177000, },
103-
/* 37 */{ "","","",">/dev/null 2>&1","",CMD_DEFAULT,1,0177000,0177000, },
103+
/* 37 */{ "application/x-lzip", "lzip", "-d", ">/dev/null 2>&1", "lzip -lv '%s' > '%s'", CMD_LZIP, 1, 0177000, 0177000, },
104+
/* 38 */{ "","","",">/dev/null 2>&1","",CMD_DEFAULT,1,0177000,0177000, },
104105
{ NULL,NULL,NULL,NULL,NULL,-1,-1,0177000,0177000, },
105106
};
106107
#endif

src/ununpack/agent/utils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,7 @@ void CheckCommands (int Show)
583583
case CMD_AR:
584584
case CMD_PARTITION:
585585
case CMD_ZSTD:
586+
case CMD_LZIP:
586587
CMD[i].Status = IsExe(CMD[i].Cmd,Quiet);
587588
break;
588589
default:

src/ununpack/agent_tests/Unit/run_tests.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ char *DBConfFile = NULL; ///< DB conf file location
2424
/* **** test suite ********************************************************** */
2525
/* ************************************************************************** */
2626
extern CU_TestInfo ExtractAR_testcases[]; ///< AR test cases
27+
extern CU_TestInfo ExtractLzip_testcases[]; ///< Lzip test cases
2728
extern CU_TestInfo ExtractZstd_testcases[]; ///< Zstd test cases
2829
extern CU_TestInfo ununpack_iso_testcases[]; ///< ISO test cases
2930
extern CU_TestInfo ununpack_disk_testcases[]; ///< Disk image test cases
@@ -47,6 +48,9 @@ CU_SuiteInfo suites[] =
4748
// ununpack-ar.c
4849
{"ExtractAR", NULL, NULL, NULL, NULL, ExtractAR_testcases},
4950

51+
// ununpack-lzip.c
52+
{"ExtractLzip", NULL, NULL, NULL, NULL, ExtractLzip_testcases},
53+
5054
// ununpack-zstd.c
5155
{"ExtractZstd", NULL, NULL, NULL, NULL, ExtractZstd_testcases},
5256

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
/*
2+
SPDX-FileCopyrightText: © 2025 Siemens Healthineers AG
3+
SPDX-FileContributor: Sushant Kumar <sushant.kumar@siemens-healthineers.com>
4+
5+
SPDX-License-Identifier: GPL-2.0-only
6+
*/
7+
8+
#include "run_tests.h"
9+
10+
/**
11+
* \file
12+
* \brief Unit test cases for ExtractLzip()
13+
*/
14+
15+
/* locals */
16+
static int Result = 0;
17+
18+
/**
19+
* @brief unpack lzip file
20+
* \test
21+
* -# Try to extract `.lz` file using ExtractLzip()
22+
* -# Check if the files are unpacked
23+
*/
24+
void testExtractLzipFile()
25+
{
26+
deleteTmpFiles("./test-result/");
27+
exists = file_dir_exists("./test-result/");
28+
FO_ASSERT_EQUAL(exists, 0); // not existing
29+
30+
MkDirs("./test-result/test.lz.dir/");
31+
Filename = "../testdata/test.lz";
32+
/* Ensure test.lz contains a file named 'data.tar' for this assertion */
33+
Result = ExtractLzip(Filename, "test.lz", "./test-result/test.lz.dir");
34+
35+
exists = file_dir_exists("./test-result/test.lz.dir/test");
36+
FO_ASSERT_EQUAL(exists, 1); // existing
37+
FO_ASSERT_EQUAL(Result, 0); // Extract lzip successfully
38+
}
39+
40+
/**
41+
* @brief unpack tlz (tar.lz) file
42+
* \test
43+
* -# Try to extract `.tlz` archives using ExtractLzip()
44+
* -# Check if the files are unpacked
45+
*/
46+
void testExtractTlzFile()
47+
{
48+
deleteTmpFiles("./test-result/");
49+
exists = file_dir_exists("./test-result/");
50+
FO_ASSERT_EQUAL(exists, 0);
51+
52+
MkDirs("./test-result/test.tlz.dir/");
53+
Filename = "../testdata/test.tlz";
54+
Result = ExtractLzip(Filename, "test.tlz", "./test-result/test.tlz.dir");
55+
56+
exists = file_dir_exists("./test-result/test.tlz.dir/test.tar");
57+
FO_ASSERT_EQUAL(exists, 1);
58+
FO_ASSERT_EQUAL(Result, 0);
59+
}
60+
61+
/**
62+
* @brief unpack tar.lz file
63+
* \test
64+
* -# Try to extract `.tar.lz` archives using ExtractLzip()
65+
* -# Check if the files are unpacked
66+
*/
67+
void testExtractTarLzFile()
68+
{
69+
deleteTmpFiles("./test-result/");
70+
exists = file_dir_exists("./test-result/");
71+
FO_ASSERT_EQUAL(exists, 0);
72+
73+
MkDirs("./test-result/test.tar.lz.dir/");
74+
Filename = "../testdata/test.tar.lz";
75+
Result = ExtractLzip(Filename, "test.tar.lz", "./test-result/test.tar.lz.dir");
76+
77+
exists = file_dir_exists("./test-result/test.tar.lz.dir/test.tar");
78+
FO_ASSERT_EQUAL(exists, 1);
79+
FO_ASSERT_EQUAL(Result, 0);
80+
}
81+
82+
/**
83+
* @brief abnormal parameters
84+
* \test
85+
* -# Call ExtractLzip() with empty parameters
86+
* -# Check if the function return NOT OK
87+
*/
88+
void testExtractLzipEmptyParameters()
89+
{
90+
deleteTmpFiles("./test-result/");
91+
exists = file_dir_exists("./test-result/");
92+
FO_ASSERT_EQUAL(exists, 0);
93+
94+
Result = ExtractLzip("", "", "");
95+
FO_ASSERT_EQUAL(Result, 1);
96+
}
97+
98+
/**
99+
* @brief abnormal parameters
100+
* \test
101+
* -# Try to extract non-existent archives using ExtractLzip()
102+
* -# Check if the function return NOT OK
103+
*/
104+
void testExtractLzipErrorParameters()
105+
{
106+
deleteTmpFiles("./test-result/");
107+
exists = file_dir_exists("./test-result/");
108+
FO_ASSERT_EQUAL(exists, 0);
109+
110+
MkDirs("./test-result/no_file.dir/");
111+
Filename = "../testdata/non_existent_file.lz";
112+
Result = ExtractLzip(Filename, "non_existent_file.lz", "./test-result/no_file.dir");
113+
FO_ASSERT_EQUAL(Result, 1);
114+
}
115+
116+
/* ************************************************************************** */
117+
/* **** cunit test cases **************************************************** */
118+
/* ************************************************************************** */
119+
120+
CU_TestInfo ExtractLzip_testcases[] =
121+
{
122+
{"Testing function ExtractLzip for .lz file:", testExtractLzipFile},
123+
{"Testing function ExtractLzip for .tlz file:", testExtractTlzFile},
124+
{"Testing function ExtractLzip for .tar.lz file:", testExtractTarLzFile},
125+
{"Testing function ExtractLzip for empty parameters:", testExtractLzipEmptyParameters},
126+
{"Testing function ExtractLzip for error parameters:", testExtractLzipErrorParameters},
127+
CU_TEST_INFO_NULL
128+
};

0 commit comments

Comments
 (0)