From 84686c9a670afef51251076065d1877b580a13a4 Mon Sep 17 00:00:00 2001 From: Shivani Agarwal Date: Thu, 22 Jun 2023 07:08:45 +0000 Subject: [PATCH] Replace existing use of libxml2 library with expat library. --- CMakeLists.txt | 4 +- ci/Dockerfile.fedora | 4 +- ci/Dockerfile.photon | 4 +- ci/Dockerfile.photon-3.0 | 4 +- cmake/FindExpat.cmake | 13 + cmake/FindLibxml2.cmake | 13 - cmake/FindPackageHandleStandardArgs.cmake | 6 +- plugins/metalink/CMakeLists.txt | 2 +- plugins/metalink/includes.h | 2 +- plugins/metalink/metalink.c | 14 +- plugins/metalink/prototypes.h | 44 ++- plugins/metalink/utils.c | 405 ++++++++++++---------- tdnf.spec.in | 8 +- 13 files changed, 292 insertions(+), 231 deletions(-) create mode 100644 cmake/FindExpat.cmake delete mode 100644 cmake/FindLibxml2.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index e665dc83..5de7f517 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,10 +62,10 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) find_package(PkgConfig REQUIRED) pkg_check_modules(RPM REQUIRED rpm) find_package(OpenSSL REQUIRED) -pkg_check_modules(LIBXML2 REQUIRED libxml-2.0) +pkg_check_modules(EXPAT REQUIRED expat) pkg_check_modules(SQLITE3 sqlite3) include_directories(${RPM_INCLUDE_DIRS}) -include_directories(${LIBXML2_INCLUDE_DIRS}) +include_directories(${EXPAT_INCLUDE_DIRS}) ### External dependency: libsolv find_package(LibSolv REQUIRED ext) diff --git a/ci/Dockerfile.fedora b/ci/Dockerfile.fedora index 70bf5f8a..8fe6b129 100644 --- a/ci/Dockerfile.fedora +++ b/ci/Dockerfile.fedora @@ -2,10 +2,10 @@ FROM fedora:34 RUN dnf -y upgrade RUN dnf -y install gcc make cmake libcurl-devel rpm-devel rpm-build \ - libsolv-devel popt-devel sed createrepo_c glib2-devel libxml2 \ + libsolv-devel popt-devel sed createrepo_c glib2-devel expat \ findutils python3-pytest python3-requests python3-urllib3 \ python3-pyOpenSSL python3 python3-devel valgrind gpgme-devel \ - libxml2-devel openssl-devel sqlite-devel rpm-sign which python3-pip \ + expat-devel openssl-devel sqlite-devel rpm-sign which python3-pip \ shadow-utils sudo e2fsprogs util-linux RUN pip3 install flake8 diff --git a/ci/Dockerfile.photon b/ci/Dockerfile.photon index e7beda9b..b93955e2 100644 --- a/ci/Dockerfile.photon +++ b/ci/Dockerfile.photon @@ -4,10 +4,10 @@ RUN tdnf update -y RUN tdnf remove -y toybox RUN tdnf install -y --enablerepo=photon-debuginfo \ build-essential cmake curl-devel rpm-build \ - libsolv-devel popt-devel sed createrepo_c glib libxml2 \ + libsolv-devel popt-devel sed createrepo_c glib expat-libs \ findutils python3 python3-pip python3-setuptools \ python3-devel valgrind gpgme-devel glibc-debuginfo \ - libxml2-devel openssl-devel zlib-devel sqlite-devel \ + expat-devel openssl-devel zlib-devel sqlite-devel \ python3-requests python3-urllib3 python3-pyOpenSSL \ sudo shadow which e2fsprogs util-linux diff --git a/ci/Dockerfile.photon-3.0 b/ci/Dockerfile.photon-3.0 index 9af39b56..cfa4e14c 100644 --- a/ci/Dockerfile.photon-3.0 +++ b/ci/Dockerfile.photon-3.0 @@ -4,9 +4,9 @@ RUN tdnf update -y RUN tdnf remove -y toybox RUN tdnf install -y --enablerepo=photon-debuginfo \ build-essential cmake curl-devel rpm-build \ - libsolv-devel popt-devel sed createrepo_c glib libxml2 \ + libsolv-devel popt-devel sed createrepo_c glib expat-libs \ findutils python3 python3-setuptools python3-devel \ - valgrind gpgme-devel glibc-debuginfo libxml2-devel \ + valgrind gpgme-devel glibc-debuginfo expat-devel \ openssl-devel zlib-devel sqlite-devel python3-requests \ python3-urllib3 python3-pyOpenSSL python3-pip \ sudo shadow which e2fsprogs util-linux diff --git a/cmake/FindExpat.cmake b/cmake/FindExpat.cmake new file mode 100644 index 00000000..5eaa27d3 --- /dev/null +++ b/cmake/FindExpat.cmake @@ -0,0 +1,13 @@ +# - Try to find expat +# Once done this will define +# EXPAT_INCLUDE_DIRS - The expat include directories +# EXPAT_LIBRARIES - The libraries needed to use expat-devel + +find_path(EXPAT_INCLUDE_DIR expat.h) +find_library(EXPAT_LIBRARY NAMES libexpat.so) + +find_package_handle_standard_args(expat DEFAULT_MSG + EXPAT_LIBRARY EXPAT_INCLUDE_DIR) + +set(EXPAT_LIBRARIES ${EXPAT_LIBRARY}) +set(EXPAT_INCLUDE_DIRS ${EXPAT_INCLUDE_DIR}) diff --git a/cmake/FindLibxml2.cmake b/cmake/FindLibxml2.cmake deleted file mode 100644 index d65a8361..00000000 --- a/cmake/FindLibxml2.cmake +++ /dev/null @@ -1,13 +0,0 @@ -# - Try to find libxml2 -# Once done this will define -# LIBXML2_INCLUDE_DIRS - The libxml2 include directories -# LIBXML2_LIBRARIES - The libraries needed to use libxml2-devel - -find_path(LIBXML2_INCLUDE_DIR libxml/parser.h) -find_library(LIBXML2_LIBRARY NAMES libxml2.so) - -find_package_handle_standard_args(libxml2 DEFAULT_MSG - LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) - -set(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY}) -set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR}) diff --git a/cmake/FindPackageHandleStandardArgs.cmake b/cmake/FindPackageHandleStandardArgs.cmake index 2fa8fbc0..bd552939 100644 --- a/cmake/FindPackageHandleStandardArgs.cmake +++ b/cmake/FindPackageHandleStandardArgs.cmake @@ -47,10 +47,10 @@ # # Example for mode 1: # -# FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibXml2 DEFAULT_MSG LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR) +# FIND_PACKAGE_HANDLE_STANDARD_ARGS(Expat DEFAULT_MSG EXPAT_LIBRARY EXPAT_INCLUDE_DIR) # -# LibXml2 is considered to be found, if both LIBXML2_LIBRARY and -# LIBXML2_INCLUDE_DIR are valid. Then also LIBXML2_FOUND is set to TRUE. +# Expat is considered to be found, if both EXPAT_LIBRARY and +# EXPAT_INCLUDE_DIR are valid. Then also EXPAT_FOUND is set to TRUE. # If it is not found and REQUIRED was used, it fails with FATAL_ERROR, # independent whether QUIET was used or not. # If it is found, success will be reported, including the content of . diff --git a/plugins/metalink/CMakeLists.txt b/plugins/metalink/CMakeLists.txt index 3ee28e57..e432e51c 100644 --- a/plugins/metalink/CMakeLists.txt +++ b/plugins/metalink/CMakeLists.txt @@ -25,7 +25,7 @@ add_library(${PROJECT_NAME} SHARED ) target_link_libraries(${PROJECT_NAME} - ${LIBXML2_LIBRARIES} + ${EXPAT_LIBRARIES} ${LIB_TDNF} ) diff --git a/plugins/metalink/includes.h b/plugins/metalink/includes.h index 585790d0..25c88a62 100644 --- a/plugins/metalink/includes.h +++ b/plugins/metalink/includes.h @@ -22,7 +22,7 @@ #include #include -#include +#include //libcurl #include diff --git a/plugins/metalink/metalink.c b/plugins/metalink/metalink.c index 4a5383ca..a962d156 100644 --- a/plugins/metalink/metalink.c +++ b/plugins/metalink/metalink.c @@ -117,7 +117,7 @@ TDNFParseAndGetURLFromMetalink( TDNF_ML_CTX *ml_ctx ) { - int fd = -1; + FILE* file = NULL; uint32_t dwError = 0; if (!pTdnf || @@ -128,14 +128,14 @@ TDNFParseAndGetURLFromMetalink( BAIL_ON_TDNF_ERROR(dwError); } - fd = open(pszFile, O_RDONLY); - if (fd < 0) + file = fopen(pszFile, "r"); + if (file == NULL) { dwError = errno; BAIL_ON_TDNF_SYSTEM_ERROR_UNCOND(dwError); } - dwError = TDNFMetalinkParseFile(ml_ctx, fd, TDNF_REPO_METADATA_FILE_NAME); + dwError = TDNFMetalinkParseFile(ml_ctx, file, TDNF_REPO_METADATA_FILE_NAME); if (dwError) { pr_err("Unable to parse metalink, ERROR: code=%d\n", dwError); @@ -146,9 +146,9 @@ TDNFParseAndGetURLFromMetalink( TDNFSortListOnPreference(&ml_ctx->urls); cleanup: - if (fd >= 0) + if (file != NULL) { - close(fd); + fclose(file); } return dwError; error: @@ -442,4 +442,4 @@ TDNFMetalinkRepoMDDownloadEnd( return dwError; error: goto cleanup; -} \ No newline at end of file +} diff --git a/plugins/metalink/prototypes.h b/plugins/metalink/prototypes.h index f311a0be..267793ef 100644 --- a/plugins/metalink/prototypes.h +++ b/plugins/metalink/prototypes.h @@ -14,7 +14,7 @@ uint32_t TDNFMetalinkParseFile( TDNF_ML_CTX *ml_ctx, - int fd, + FILE *file, const char *filename ); @@ -23,31 +23,49 @@ TDNFMetalinkFree( TDNF_ML_CTX *ml_ctx ); -uint32_t +char * +TDNFSearchTag( + const char **attr, + const char *type + ); + +void +TDNFXmlParseStartElement( + void *userData, + const char *name, + const char **attrs + ); + +void TDNFXmlParseData( - TDNF_ML_CTX *ml_ctx, - xmlNode *node, - const char *filename + void *userData, + const char *val, + int len + ); + +void +TDNFXmlParseEndElement( + void *userData, + const char *name ); uint32_t TDNFParseFileTag( - TDNF_ML_CTX *ml_ctx, - xmlNode *node, - const char *filename + void *userData ); uint32_t TDNFParseHashTag( - TDNF_ML_CTX *ml_ctx, - xmlNode *node + void *userData, + const char *val, + int len ); - uint32_t TDNFParseUrlTag( - TDNF_ML_CTX *ml_ctx, - xmlNode *node + void *userData, + const char *val, + int len ); uint32_t diff --git a/plugins/metalink/utils.c b/plugins/metalink/utils.c index 8e9761e9..fd16aa20 100644 --- a/plugins/metalink/utils.c +++ b/plugins/metalink/utils.c @@ -20,11 +20,12 @@ #include "includes.h" -#define ATTR_NAME (xmlChar*)"name" -#define ATTR_PROTOCOL (xmlChar*)"protocol" -#define ATTR_TYPE (xmlChar*)"type" -#define ATTR_LOCATION (xmlChar*)"location" -#define ATTR_PREFERENCE (xmlChar*)"preference" +#define MIN_URL_LENGTH 4 +#define ATTR_NAME (char*)"name" +#define ATTR_PROTOCOL (char*)"protocol" +#define ATTR_TYPE (char*)"type" +#define ATTR_LOCATION (char*)"location" +#define ATTR_PREFERENCE (char*)"preference" typedef struct _hash_op { char *hash_type; @@ -60,6 +61,16 @@ static int hashTypeComparator(const void * p1, const void * p2) return strcmp(*((const char **)p1), *((const char **)p2)); } +// Structure to hold element information +struct MetalinkElementInfo { + uint32_t dwError; + TDNF_ML_CTX *ml_ctx; + const char *filename; + const char *startElement; + const char *endElement; + const char **attributes; +}; + int TDNFGetResourceType( const char *resource_type, @@ -485,48 +496,58 @@ TDNFMetalinkFree( TDNF_SAFE_FREE_MEMORY(ml_ctx); } +char * +TDNFSearchTag( + const char **attr, + const char *type + ) +{ + for (int i = 0; attr[i]; i += 2) + { + if((!strcmp(attr[i], type)) && (attr[i + 1] != NULL)) + { + return (char *)attr[i + 1]; + } + } + + return NULL; +} + uint32_t TDNFParseFileTag( - TDNF_ML_CTX *ml_ctx, - xmlNode *node, - const char *filename + void *userData ) { uint32_t dwError = 0; - xmlChar* xmlPropValue = NULL; const char *name = NULL; + struct MetalinkElementInfo* elementInfo = (struct MetalinkElementInfo*)userData; - if(!ml_ctx || !node || IsNullOrEmptyString(filename)) + if(!elementInfo || !elementInfo->ml_ctx || IsNullOrEmptyString(elementInfo->filename)) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_ERROR(dwError); } - xmlPropValue = xmlGetProp(node, ATTR_NAME); - if (!xmlPropValue) + name = TDNFSearchTag(elementInfo->attributes, ATTR_NAME); + + if (!name) { pr_err("%s: Missing attribute \"name\" of file element", __func__); dwError = ERROR_TDNF_METALINK_PARSER_MISSING_FILE_ATTR; BAIL_ON_TDNF_ERROR(dwError); } - name = (const char*)xmlPropValue; - if (strcmp(name, filename)) + if (strcmp(name, elementInfo->filename)) { pr_err("%s: Invalid filename from metalink file:%s", __func__, name); dwError = ERROR_TDNF_METALINK_PARSER_INVALID_FILE_NAME; BAIL_ON_TDNF_ERROR(dwError); } - dwError = TDNFAllocateString(name, &(ml_ctx->filename)); + dwError = TDNFAllocateString(name, &(elementInfo->ml_ctx->filename)); BAIL_ON_TDNF_ERROR(dwError); cleanup: - if(xmlPropValue) - { - xmlFree(xmlPropValue); - xmlPropValue = NULL; - } return dwError; error: goto cleanup; @@ -534,33 +555,33 @@ TDNFParseFileTag( uint32_t TDNFParseHashTag( - TDNF_ML_CTX *ml_ctx, - xmlNode *node + void *userData, + const char *val, + int len ) { uint32_t dwError = 0; - xmlChar* xmlPropValue = NULL; - xmlChar* xmlContValue = NULL; const char *type = NULL; - const char *value = NULL; + char *value = NULL; TDNF_ML_HASH_INFO *ml_hash_info = NULL; + struct MetalinkElementInfo* elementInfo = (struct MetalinkElementInfo*)userData; - if(!ml_ctx || !node) + if(!elementInfo || !elementInfo->ml_ctx) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_ERROR(dwError); } - //Get Hash Properties. - xmlPropValue = xmlGetProp(node, ATTR_TYPE); - if (!xmlPropValue) + //Get Hash Properties + type = TDNFSearchTag(elementInfo->attributes, ATTR_TYPE); + + if (!type) { dwError = ERROR_TDNF_METALINK_PARSER_MISSING_HASH_ATTR; pr_err("XML Parser Error:HASH element doesn't have attribute \"type\""); BAIL_ON_TDNF_ERROR(dwError); } - type = (const char*)xmlPropValue; dwError = TDNFAllocateMemory(1, sizeof(TDNF_ML_HASH_INFO), (void**)&ml_hash_info); BAIL_ON_TDNF_ERROR(dwError); @@ -569,33 +590,25 @@ TDNFParseHashTag( BAIL_ON_TDNF_ERROR(dwError); //Get Hash Content. - xmlContValue = xmlNodeGetContent(node); - if(!xmlContValue) + TDNFAllocateStringN(val, len, &value); + + if(!value) { dwError = ERROR_TDNF_METALINK_PARSER_MISSING_HASH_CONTENT; pr_err("XML Parser Error:HASH value is not present in HASH element"); BAIL_ON_TDNF_ERROR(dwError); } - value = (const char*)xmlContValue; dwError = TDNFAllocateString(value, &(ml_hash_info->value)); BAIL_ON_TDNF_ERROR(dwError); //Append hash info in ml_ctx hash list. - dwError = TDNFAppendList(&(ml_ctx->hashes), ml_hash_info); + dwError = TDNFAppendList(&(elementInfo->ml_ctx->hashes), ml_hash_info); BAIL_ON_TDNF_ERROR(dwError); cleanup: - if(xmlPropValue) - { - xmlFree(xmlPropValue); - xmlPropValue = NULL; - } - - if(xmlContValue) - { - xmlFree(xmlContValue); - xmlContValue = NULL; + if(value != NULL){ + TDNF_SAFE_FREE_MEMORY(value); } return dwError; @@ -610,18 +623,19 @@ TDNFParseHashTag( uint32_t TDNFParseUrlTag( - TDNF_ML_CTX *ml_ctx, - xmlNode *node + void *userData, + const char *val, + int len ) { uint32_t dwError = 0; - xmlChar* xmlPropValue = NULL; - xmlChar* xmlContValue = NULL; - const char *value = NULL; + char *value = NULL; + char *prefval = NULL; int prefValue = 0; TDNF_ML_URL_INFO *ml_url_info = NULL; + struct MetalinkElementInfo* elementInfo = (struct MetalinkElementInfo*)userData; - if(!ml_ctx || !node) + if(!elementInfo || !elementInfo->ml_ctx) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_ERROR(dwError); @@ -631,83 +645,70 @@ TDNFParseUrlTag( (void**)&ml_url_info); BAIL_ON_TDNF_ERROR(dwError); - if ((xmlPropValue = xmlGetProp(node, ATTR_PROTOCOL))) - { - value = (const char*)xmlPropValue; - dwError = TDNFAllocateString(value, &(ml_url_info->protocol)); - BAIL_ON_TDNF_ERROR(dwError); - xmlFree(xmlPropValue); - xmlPropValue = NULL; - } - if ((xmlPropValue = xmlGetProp(node, ATTR_TYPE))) - { - value = (const char*)xmlPropValue; - dwError = TDNFAllocateString(value, &(ml_url_info->type)); - BAIL_ON_TDNF_ERROR(dwError); - xmlFree(xmlPropValue); - xmlPropValue = NULL; - } - if ((xmlPropValue = xmlGetProp(node, ATTR_LOCATION))) - { - value = (const char*)xmlPropValue; - dwError = TDNFAllocateString(value, &(ml_url_info->location)); - BAIL_ON_TDNF_ERROR(dwError); - xmlFree(xmlPropValue); - xmlPropValue = NULL; - } - if ((xmlPropValue = xmlGetProp(node, ATTR_PREFERENCE))) + for (int i = 0; elementInfo->attributes[i]; i += 2) { - value = (const char*)xmlPropValue; - if(sscanf(value, "%d", &prefValue) != 1) + if ((!strcmp(elementInfo->attributes[i], ATTR_PROTOCOL)) && (elementInfo->attributes[i + 1] != NULL)) { - dwError = ERROR_TDNF_INVALID_PARAMETER; - pr_err("XML Parser Warning: Preference is invalid value: %s\n", value); - BAIL_ON_TDNF_ERROR(dwError); + value = (char *)elementInfo->attributes[i + 1]; + dwError = TDNFAllocateString(value, &(ml_url_info->protocol)); + BAIL_ON_TDNF_ERROR(dwError); } - xmlFree(xmlPropValue); - xmlPropValue = NULL; - - if (prefValue < 0 || prefValue > 100) + if ((!strcmp(elementInfo->attributes[i], ATTR_TYPE)) && (elementInfo->attributes[i + 1] != NULL)) { - dwError = ERROR_TDNF_METALINK_PARSER_MISSING_URL_ATTR; - pr_err("XML Parser Warning: Bad value (\"%s\") of \"preference\"" - "attribute in url element (should be in range 0-100)", value); - BAIL_ON_TDNF_ERROR(dwError); + value = (char *)elementInfo->attributes[i + 1]; + dwError = TDNFAllocateString(value, &(ml_url_info->type)); + BAIL_ON_TDNF_ERROR(dwError); } - else + if ((!strcmp(elementInfo->attributes[i], ATTR_LOCATION)) && (elementInfo->attributes[i + 1] != NULL)) { - ml_url_info->preference = prefValue; + value = (char *)elementInfo->attributes[i + 1]; + dwError = TDNFAllocateString(value, &(ml_url_info->location)); + BAIL_ON_TDNF_ERROR(dwError); } + if ((!strcmp(elementInfo->attributes[i], ATTR_PREFERENCE)) && (elementInfo->attributes[i + 1] != NULL)) + { + prefval = (char *)elementInfo->attributes[i + 1]; + if(sscanf(prefval, "%d", &prefValue) != 1) + { + dwError = ERROR_TDNF_INVALID_PARAMETER; + pr_err("XML Parser Warning: Preference is invalid value: %s\n", prefval); + BAIL_ON_TDNF_ERROR(dwError); + } + + if (prefValue < 0 || prefValue > 100) + { + dwError = ERROR_TDNF_METALINK_PARSER_MISSING_URL_ATTR; + pr_err("XML Parser Warning: Bad value (\"%s\") of \"preference\"" + "attribute in url element (should be in range 0-100)", value); + BAIL_ON_TDNF_ERROR(dwError); + } + else + { + ml_url_info->preference = prefValue; + } + } } //Get URL Content. - xmlContValue = xmlNodeGetContent(node); - if(!xmlContValue) + TDNFAllocateStringN(val, len, &value); + + if(!value) { dwError = ERROR_TDNF_METALINK_PARSER_MISSING_URL_CONTENT; pr_err("URL is no present in URL element"); BAIL_ON_TDNF_ERROR(dwError); } - value = (const char*)xmlContValue; dwError = TDNFAllocateString(value, &(ml_url_info->url)); BAIL_ON_TDNF_ERROR(dwError); //Append url info in ml_ctx url list. - dwError = TDNFAppendList(&(ml_ctx->urls), ml_url_info); + dwError = TDNFAppendList(&(elementInfo->ml_ctx->urls), ml_url_info); BAIL_ON_TDNF_ERROR(dwError); cleanup: - if(xmlPropValue) - { - xmlFree(xmlPropValue); - xmlPropValue = NULL; - } - - if(xmlContValue) - { - xmlFree(xmlContValue); - xmlContValue = NULL; + if(value != NULL){ + TDNF_SAFE_FREE_MEMORY(value); } return dwError; @@ -720,128 +721,168 @@ TDNFParseUrlTag( goto cleanup; } -uint32_t +void +TDNFXmlParseStartElement( + void *userData, + const char *name, + const char **attrs + ) +{ + struct MetalinkElementInfo* elementInfo = (struct MetalinkElementInfo*)userData; + + if(elementInfo->dwError != 0) + { + BAIL_ON_TDNF_ERROR(elementInfo->dwError); + } + + // Set the start element name and attribute + elementInfo->startElement = name; + elementInfo->attributes = attrs; + +cleanup: + return; +error: + goto cleanup; +} + +void TDNFXmlParseData( - TDNF_ML_CTX *ml_ctx, - xmlNode *node, - const char *filename + void *userData, + const char *val, + int len ) { - uint32_t dwError = 0; - xmlChar* xmlContValue = NULL; + struct MetalinkElementInfo* elementInfo = (struct MetalinkElementInfo*)userData; char *size = NULL; - if(!ml_ctx || !node || IsNullOrEmptyString(filename)) + if(!elementInfo || !elementInfo->ml_ctx || IsNullOrEmptyString(elementInfo->filename) || (elementInfo->dwError != 0)) { - dwError = ERROR_TDNF_INVALID_PARAMETER; - BAIL_ON_TDNF_ERROR(dwError); + elementInfo->dwError = ERROR_TDNF_INVALID_PARAMETER; + BAIL_ON_TDNF_ERROR(elementInfo->dwError); } - //Looping through all the nodes from root and parse all children nodes. - while(node) + if(!strcmp(elementInfo->startElement, TAG_NAME_FILE)) + { + elementInfo->dwError = TDNFParseFileTag(userData); + BAIL_ON_TDNF_ERROR(elementInfo->dwError); + } + else if(!strcmp(elementInfo->startElement, TAG_NAME_SIZE)) { - if(node->type == XML_ELEMENT_NODE) + //Get File Size. + TDNFAllocateStringN(val, len, &size); + + if(!size) { - if(!strcmp((const char*)node->name, TAG_NAME_FILE)) - { - dwError = TDNFParseFileTag(ml_ctx, node, filename); - BAIL_ON_TDNF_ERROR(dwError); - } - else if(!strcmp((const char*)node->name, TAG_NAME_SIZE)) - { - //Get File Size. - xmlContValue = xmlNodeGetContent(node); - if(!xmlContValue) - { - dwError = ERROR_TDNF_METALINK_PARSER_MISSING_FILE_SIZE; - pr_err("XML Parser Error:File size is missing: %s", size); - BAIL_ON_TDNF_ERROR(dwError); - } - size = (char*)xmlContValue; - if(sscanf(size, "%ld", &(ml_ctx->size)) != 1) - { - dwError = ERROR_TDNF_INVALID_PARAMETER; - pr_err("XML Parser Warning: size is invalid value: %s\n", size); - BAIL_ON_TDNF_ERROR(dwError); - } - } - else if(!strcmp((const char*)node->name, TAG_NAME_HASH)) - { - dwError = TDNFParseHashTag(ml_ctx, node); - BAIL_ON_TDNF_ERROR(dwError); - } - else if(!strcmp((const char*)node->name, TAG_NAME_URL)) - { - dwError = TDNFParseUrlTag(ml_ctx, node); - BAIL_ON_TDNF_ERROR(dwError); - } + elementInfo->dwError = ERROR_TDNF_METALINK_PARSER_MISSING_FILE_SIZE; + pr_err("XML Parser Error:File size is missing: %s", size); + BAIL_ON_TDNF_ERROR(elementInfo->dwError); } - if (node->children) { - TDNFXmlParseData(ml_ctx, node->children, filename); + if(sscanf(size, "%ld", &(elementInfo->ml_ctx->size)) != 1) + { + elementInfo->dwError = ERROR_TDNF_INVALID_PARAMETER; + pr_err("XML Parser Warning: size is invalid value: %s\n", size); + BAIL_ON_TDNF_ERROR(elementInfo->dwError); } - node = node->next; + } + else if(!strcmp(elementInfo->startElement, TAG_NAME_HASH)) + { + elementInfo->dwError = TDNFParseHashTag(userData, val, len); + BAIL_ON_TDNF_ERROR(elementInfo->dwError); + } + else if(!strcmp(elementInfo->startElement, TAG_NAME_URL) && len > MIN_URL_LENGTH) + { + elementInfo->dwError = TDNFParseUrlTag(userData, val, len); + BAIL_ON_TDNF_ERROR(elementInfo->dwError); } cleanup: - if(xmlContValue) - { - xmlFree(xmlContValue); - xmlContValue = NULL; + if(size != NULL){ + TDNF_SAFE_FREE_MEMORY(size); } - return dwError; + return; error: goto cleanup; } +void +TDNFXmlParseEndElement( + void *userData, + const char *name + ) +{ + struct MetalinkElementInfo* elementInfo = (struct MetalinkElementInfo*)userData; + elementInfo->endElement = name; + + if(elementInfo->dwError != 0) + BAIL_ON_TDNF_ERROR(elementInfo->dwError); + +cleanup: + return; +error: + goto cleanup; +} + uint32_t TDNFMetalinkParseFile( TDNF_ML_CTX *ml_ctx, - int fd, + FILE *file, const char *filename ) { uint32_t dwError = 0; - xmlDoc *doc = NULL; - xmlNode *root_element = NULL; + struct stat st = {0}; + size_t file_size = 0; + char *buffer = NULL; + struct MetalinkElementInfo elementInfo = {0}; - if(!ml_ctx || (fd <= 0) || IsNullOrEmptyString(filename)) + XML_Parser parser = XML_ParserCreate(NULL); + if(!ml_ctx || (file == NULL) || IsNullOrEmptyString(filename) || (parser == NULL)) { dwError = ERROR_TDNF_INVALID_PARAMETER; BAIL_ON_TDNF_ERROR(dwError); } - //Read The File and get the doc object. - doc = xmlReadFd(fd, NULL, NULL, 0); + elementInfo.ml_ctx = ml_ctx; + elementInfo.filename = filename; - if (doc == NULL) - { - pr_err("%s: Error while reading xml from fd:%d \n", __func__, fd); - dwError = ERROR_TDNF_METALINK_PARSER_INVALID_DOC_OBJECT; - BAIL_ON_TDNF_ERROR(dwError); + XML_SetElementHandler(parser, TDNFXmlParseStartElement, TDNFXmlParseEndElement); + XML_SetCharacterDataHandler(parser, TDNFXmlParseData); + XML_SetUserData(parser, &elementInfo); + + // Get file information using fstat + if (fstat(fileno(file), &st) == -1) { + pr_err("Error getting file information"); + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR_UNCOND(dwError); } - //Get the root element from parsed xml tree. - root_element = xmlDocGetRootElement(doc); + // Get the file size from the stat structure + file_size = st.st_size; - if (root_element == NULL) - { - pr_err("%s: Error to fetch root element of xml tree\n", __func__); - dwError = ERROR_TDNF_METALINK_PARSER_INVALID_ROOT_ELEMENT; - BAIL_ON_TDNF_ERROR(dwError); + // Allocate memory for the buffer + dwError = TDNFAllocateMemory(file_size + 1, sizeof(char*), (void **)&buffer); + BAIL_ON_TDNF_ERROR(dwError); + + // Read the file into the buffer + if (fread(buffer, 1, file_size, file) != file_size) { + pr_err("Failed to read the metalink file %s.\n", filename); + dwError = errno; + BAIL_ON_TDNF_SYSTEM_ERROR_UNCOND(dwError); } - // Parsing - dwError = TDNFXmlParseData(ml_ctx, root_element, filename); + buffer[file_size] = '\0'; + dwError = XML_Parse(parser, buffer, file_size + 1, XML_TRUE); BAIL_ON_TDNF_ERROR(dwError); -cleanup: - if(doc != NULL) + if(elementInfo.dwError != 0) { - xmlFreeDoc(doc); - doc = NULL; + dwError = elementInfo.dwError; + BAIL_ON_TDNF_ERROR(elementInfo.dwError); } - xmlCleanupParser(); +cleanup: + TDNF_SAFE_FREE_MEMORY(buffer); + XML_ParserFree(parser); return dwError; error: goto cleanup; diff --git a/tdnf.spec.in b/tdnf.spec.in index 143c976c..9bd13453 100644 --- a/tdnf.spec.in +++ b/tdnf.spec.in @@ -15,7 +15,7 @@ Requires: rpm-libs >= 4.16.1.3-1 Requires: curl-libs Requires: %{name}-cli-libs = %{version}-%{release} Requires: libsolv >= 0.7.19 -Requires: libxml2 +Requires: expat-libs Requires: zlib BuildRequires: popt-devel @@ -23,13 +23,13 @@ BuildRequires: rpm-devel BuildRequires: openssl-devel >= 1.1.1 BuildRequires: libsolv-devel >= 0.7.19 BuildRequires: curl-devel -BuildRequires: libxml2-devel +BuildRequires: expat-devel BuildRequires: zlib-devel BuildRequires: systemd BuildRequires: systemd-rpm-macros #metalink plugin -BuildRequires: libxml2-devel +BuildRequires: expat-devel #repogpgcheck plugin BuildRequires: gpgme-devel @@ -287,6 +287,8 @@ systemctl try-restart %{name}-cache-updateinfo.timer >/dev/null 2>&1 || : %{_unitdir}/%{name}-automatic-notifyonly.service %changelog +* Fri Jun 09 2023 Shivani Agarwal 3.3.1-4 +- Remove libxml2 dependency and add expat dependency * Mon Jun 27 2022 Shreenidhi Shedi 3.3.1-3 - Exclude debug symbols properly * Fri Jun 17 2022 Shreenidhi Shedi 3.3.1-2