removed libtar support in favour of libarchive
This commit is contained in:
parent
54008798ef
commit
cf6da173f6
20
configure.ac
20
configure.ac
|
@ -157,13 +157,25 @@ dnl Check for zlib
|
|||
AC_CHECK_LIB([z], [gzsetparams], [AC_CHECK_HEADER([zlib.h], [LIBZ='-lz'])])
|
||||
if test -n "$LIBZ"; then
|
||||
LDFLAGS="$LDFLAGS $LIBZ"
|
||||
else
|
||||
AC_MSG_ERROR("missing zlib headers/libraries");
|
||||
fi
|
||||
|
||||
dnl Check for libtar
|
||||
AC_CHECK_LIB([tar], [tar_open], [AC_CHECK_HEADER([libtar.h], [LIBTAR='-ltar'])])
|
||||
if test -n "$LIBTAR"; then
|
||||
dnl Check for bzip2
|
||||
AC_CHECK_LIB([bz2], [BZ2_bzCompress], [AC_CHECK_HEADER([bzlib.h], [LIBBZ2='-lbz2'])])
|
||||
if test -n "$LIBBZ2"; then
|
||||
LDFLAGS="$LDFLAGS $LIBBZ2"
|
||||
else
|
||||
AC_MSG_ERROR("missing bzip2 headers/libraries");
|
||||
fi
|
||||
|
||||
dnl Check for libarchive
|
||||
AC_CHECK_LIB([archive], [archive_read_data], [AC_CHECK_HEADER([archive.h], [LIBARCHIVE='-larchive'])])
|
||||
if test -n "$LIBARCHIVE"; then
|
||||
CFLAGS="$CFLAGS"
|
||||
LDFLAGS="$LDFLAGS $LIBTAR"
|
||||
LDFLAGS="$LDFLAGS $LIBARCHIVE"
|
||||
else
|
||||
AC_MSG_ERROR("missing libarchive headers/libraries");
|
||||
fi
|
||||
|
||||
CFLAGS="$CFLAGS $ENV_CFLAGS"
|
||||
|
|
|
@ -26,9 +26,7 @@
|
|||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <zlib.h>
|
||||
#include <libintl.h>
|
||||
#include <libtar.h>
|
||||
/* pacman */
|
||||
#include "util.h"
|
||||
#include "error.h"
|
||||
|
@ -275,7 +273,8 @@ int _alpm_add_prepare(pmtrans_t *trans, pmdb_t *db, PMList **data)
|
|||
int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
||||
{
|
||||
int i, ret = 0, errors = 0;
|
||||
TAR *tar = NULL;
|
||||
register struct archive *archive;
|
||||
struct archive_entry *entry;
|
||||
char expath[PATH_MAX];
|
||||
time_t t;
|
||||
PMList *targ, *lp;
|
||||
|
@ -288,12 +287,6 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
}
|
||||
|
||||
for(targ = trans->packages; targ; targ = targ->next) {
|
||||
tartype_t gztype = {
|
||||
(openfunc_t)_alpm_gzopen_frontend,
|
||||
(closefunc_t)gzclose,
|
||||
(readfunc_t)gzread,
|
||||
(writefunc_t)gzwrite
|
||||
};
|
||||
unsigned short pmo_upgrade;
|
||||
char pm_install[PATH_MAX];
|
||||
pmpkg_t *info = (pmpkg_t *)targ->data;
|
||||
|
@ -380,21 +373,28 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
_alpm_log(PM_LOG_FLOW1, _("extracting files"));
|
||||
|
||||
/* Extract the .tar.gz package */
|
||||
if(tar_open(&tar, info->data, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
|
||||
if((archive = archive_read_new()) == NULL) {
|
||||
RET_ERR(PM_ERR_LIBARCHIVE_ERROR, -1);
|
||||
}
|
||||
archive_read_support_compression_all(archive);
|
||||
archive_read_support_format_all(archive);
|
||||
|
||||
if(archive_read_open_file(archive, info->data, 10240) != ARCHIVE_OK) {
|
||||
RET_ERR(PM_ERR_PKG_OPEN, -1);
|
||||
}
|
||||
|
||||
for(i = 0; !th_read(tar); i++) {
|
||||
chdir(handle->root);
|
||||
for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
|
||||
int nb = 0;
|
||||
int notouch = 0;
|
||||
char *md5_orig = NULL;
|
||||
char pathname[PATH_MAX];
|
||||
struct stat buf;
|
||||
|
||||
STRNCPY(pathname, th_get_pathname(tar), PATH_MAX);
|
||||
STRNCPY(pathname, archive_entry_pathname(entry), PATH_MAX);
|
||||
|
||||
if(!strcmp(pathname, ".PKGINFO") || !strcmp(pathname, ".FILELIST")) {
|
||||
tar_skip_regfile(tar);
|
||||
archive_read_data_skip(archive);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -413,7 +413,7 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
*/
|
||||
if(_alpm_list_is_strin(pathname, handle->noextract)) {
|
||||
alpm_logaction(_("notice: %s is in NoExtract -- skipping extraction"), pathname);
|
||||
tar_skip_regfile(tar);
|
||||
archive_read_data_skip(archive);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -442,7 +442,8 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
/* extract the package's version to a temporary file and md5 it */
|
||||
temp = strdup("/tmp/alpm_XXXXXX");
|
||||
fd = mkstemp(temp);
|
||||
if(tar_extract_file(tar, temp)) {
|
||||
archive_entry_set_pathname(entry, temp);
|
||||
if(archive_read_extract(archive, entry, ARCHIVE_EXTRACT_FLAGS) != ARCHIVE_OK) {
|
||||
alpm_logaction(_("could not extract %s (%s)"), pathname, strerror(errno));
|
||||
errors++;
|
||||
unlink(temp);
|
||||
|
@ -490,9 +491,11 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
char newpath[PATH_MAX];
|
||||
snprintf(newpath, PATH_MAX, "%s.pacorig", expath);
|
||||
if(rename(expath, newpath)) {
|
||||
archive_entry_set_pathname(entry, expath);
|
||||
_alpm_log(PM_LOG_ERROR, _("could not rename %s (%s)"), pathname, strerror(errno));
|
||||
alpm_logaction(_("error: could not rename %s (%s)"), expath, strerror(errno));
|
||||
}
|
||||
archive_entry_set_pathname(entry, expath);
|
||||
if(_alpm_copyfile(temp, expath)) {
|
||||
_alpm_log(PM_LOG_ERROR, _("could not copy %s to %s (%s)"), temp, pathname, strerror(errno));
|
||||
alpm_logaction(_("error: could not copy %s to %s (%s)"), temp, expath, strerror(errno));
|
||||
|
@ -534,6 +537,7 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
_alpm_log(PM_LOG_ERROR, _("could not copy %s to %s (%s)"), temp, pathname, strerror(errno));
|
||||
errors++;
|
||||
}
|
||||
archive_entry_set_pathname(entry, expath);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -561,9 +565,10 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
*/
|
||||
unlink(expath);
|
||||
}
|
||||
if(tar_extract_file(tar, expath)) {
|
||||
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)"), pathname, strerror(errno));
|
||||
alpm_logaction(_("error: could not extract %s (%s)"), pathname, strerror(errno));
|
||||
archive_entry_set_pathname(entry, expath);
|
||||
if(archive_read_extract(archive, entry, ARCHIVE_EXTRACT_FLAGS) != ARCHIVE_OK) {
|
||||
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)"), expath, strerror(errno));
|
||||
alpm_logaction(_("error: could not extract %s (%s)"), expath, strerror(errno));
|
||||
errors++;
|
||||
}
|
||||
/* calculate an md5 hash if this is in info->backup */
|
||||
|
@ -590,7 +595,7 @@ int _alpm_add_commit(pmtrans_t *trans, pmdb_t *db)
|
|||
}
|
||||
}
|
||||
}
|
||||
tar_close(tar);
|
||||
archive_read_finish(archive);
|
||||
|
||||
if(errors) {
|
||||
ret = 1;
|
||||
|
|
|
@ -379,7 +379,8 @@ extern enum __pmerrno_t {
|
|||
PM_ERR_FILE_CONFLICTS,
|
||||
/* Misc */
|
||||
PM_ERR_USER_ABORT,
|
||||
PM_ERR_INTERNAL_ERROR
|
||||
PM_ERR_INTERNAL_ERROR,
|
||||
PM_ERR_LIBARCHIVE_ERROR
|
||||
} pm_errno;
|
||||
|
||||
char *alpm_strerror(int err);
|
||||
|
|
|
@ -111,6 +111,8 @@ char *alpm_strerror(int err)
|
|||
return _("user aborted");
|
||||
case PM_ERR_INTERNAL_ERROR:
|
||||
return _("internal error");
|
||||
case PM_ERR_LIBARCHIVE_ERROR:
|
||||
return _("libarchive error");
|
||||
default:
|
||||
return _("unexpected error");
|
||||
}
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <libintl.h>
|
||||
#include <libtar.h>
|
||||
#include <zlib.h>
|
||||
/* pacman */
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
@ -247,14 +245,9 @@ pmpkg_t *_alpm_pkg_load(char *pkgfile)
|
|||
int config = 0;
|
||||
int filelist = 0;
|
||||
int scriptcheck = 0;
|
||||
TAR *tar = NULL;
|
||||
register struct archive *archive;
|
||||
struct archive_entry *entry;
|
||||
pmpkg_t *info = NULL;
|
||||
tartype_t gztype = {
|
||||
(openfunc_t)_alpm_gzopen_frontend,
|
||||
(closefunc_t)gzclose,
|
||||
(readfunc_t)gzread,
|
||||
(writefunc_t)gzwrite
|
||||
};
|
||||
|
||||
if(pkgfile == NULL || strlen(pkgfile) == 0) {
|
||||
RET_ERR(PM_ERR_WRONG_ARGS, NULL);
|
||||
|
@ -269,23 +262,30 @@ pmpkg_t *_alpm_pkg_load(char *pkgfile)
|
|||
goto error;
|
||||
}
|
||||
|
||||
if(tar_open(&tar, pkgfile, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
|
||||
if((archive = archive_read_new()) == NULL) {
|
||||
RET_ERR(PM_ERR_LIBARCHIVE_ERROR, NULL);
|
||||
}
|
||||
|
||||
archive_read_support_compression_all(archive);
|
||||
archive_read_support_format_all(archive);
|
||||
if(archive_read_open_file(archive, pkgfile, 10240) != ARCHIVE_OK) {
|
||||
pm_errno = PM_ERR_NOT_A_FILE;
|
||||
goto error;
|
||||
}
|
||||
for(i = 0; !th_read(tar); i++) {
|
||||
for(i = 0; archive_read_next_header(archive, &entry) == ARCHIVE_OK; i++) {
|
||||
if(config && filelist && scriptcheck) {
|
||||
/* we have everything we need */
|
||||
break;
|
||||
}
|
||||
if(!strcmp(th_get_pathname(tar), ".PKGINFO")) {
|
||||
if(!strcmp(archive_entry_pathname(entry), ".PKGINFO")) {
|
||||
char *descfile;
|
||||
int fd;
|
||||
|
||||
/* extract this file into /tmp. it has info for us */
|
||||
descfile = strdup("/tmp/alpm_XXXXXX");
|
||||
fd = mkstemp(descfile);
|
||||
tar_extract_file(tar, descfile);
|
||||
_alpm_archive_read_entry_data_into_fd(archive, fd);
|
||||
close(fd);
|
||||
/* parse the info file */
|
||||
if(parse_descfile(descfile, info, 0) == -1) {
|
||||
_alpm_log(PM_LOG_ERROR, _("could not parse the package description file"));
|
||||
|
@ -300,10 +300,10 @@ pmpkg_t *_alpm_pkg_load(char *pkgfile)
|
|||
FREE(descfile);
|
||||
close(fd);
|
||||
continue;
|
||||
} else if(!strcmp(th_get_pathname(tar), "._install") || !strcmp(th_get_pathname(tar), ".INSTALL")) {
|
||||
} else if(!strcmp(archive_entry_pathname(entry), "._install") || !strcmp(archive_entry_pathname(entry), ".INSTALL")) {
|
||||
info->scriptlet = 1;
|
||||
scriptcheck = 1;
|
||||
} else if(!strcmp(th_get_pathname(tar), ".FILELIST")) {
|
||||
} else if(!strcmp(archive_entry_pathname(entry), ".FILELIST")) {
|
||||
/* Build info->files from the filelist */
|
||||
FILE *fp;
|
||||
char *fn;
|
||||
|
@ -316,7 +316,8 @@ pmpkg_t *_alpm_pkg_load(char *pkgfile)
|
|||
}
|
||||
fn = strdup("/tmp/alpm_XXXXXX");
|
||||
fd = mkstemp(fn);
|
||||
tar_extract_file(tar, fn);
|
||||
_alpm_archive_read_entry_data_into_fd(archive, fd);
|
||||
close(fd);
|
||||
fp = fopen(fn, "r");
|
||||
while(!feof(fp)) {
|
||||
if(fgets(str, PATH_MAX, fp) == NULL) {
|
||||
|
@ -339,19 +340,18 @@ pmpkg_t *_alpm_pkg_load(char *pkgfile)
|
|||
if(!filelist) {
|
||||
/* no .FILELIST present in this package.. build the filelist the */
|
||||
/* old-fashioned way, one at a time */
|
||||
expath = strdup(th_get_pathname(tar));
|
||||
expath = strdup(archive_entry_pathname(entry));
|
||||
info->files = _alpm_list_add(info->files, expath);
|
||||
}
|
||||
}
|
||||
|
||||
if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
|
||||
if(archive_read_data_skip(archive)) {
|
||||
_alpm_log(PM_LOG_ERROR, _("bad package file in %s"), pkgfile);
|
||||
goto error;
|
||||
}
|
||||
expath = NULL;
|
||||
}
|
||||
tar_close(tar);
|
||||
tar = NULL;
|
||||
archive_read_finish(archive);
|
||||
|
||||
if(!config) {
|
||||
_alpm_log(PM_LOG_ERROR, _("missing package info file in %s"), pkgfile);
|
||||
|
@ -367,9 +367,7 @@ pmpkg_t *_alpm_pkg_load(char *pkgfile)
|
|||
|
||||
error:
|
||||
FREEPKG(info);
|
||||
if(tar) {
|
||||
tar_close(tar);
|
||||
}
|
||||
archive_read_finish(archive);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
#endif
|
||||
#include <dirent.h>
|
||||
#include <libintl.h>
|
||||
#include <libtar.h>
|
||||
#include <zlib.h>
|
||||
/* pacman */
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
@ -110,27 +108,27 @@ static pmsyncpkg_t *find_pkginsync(char *needle, PMList *haystack)
|
|||
PMList *_alpm_sync_load_dbarchive(char *archive)
|
||||
{
|
||||
PMList *lp = NULL;
|
||||
TAR *tar = NULL;
|
||||
tartype_t gztype = {
|
||||
(openfunc_t)_alpm_gzopen_frontend,
|
||||
(closefunc_t)gzclose,
|
||||
(readfunc_t)gzread,
|
||||
(writefunc_t)gzwrite
|
||||
};
|
||||
register struct archive *_archive;
|
||||
struct archive_entry *entry;
|
||||
|
||||
if(tar_open(&tar, archive, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
|
||||
if((_archive = archive_read_new()) == NULL) {
|
||||
pm_errno = PM_ERR_LIBARCHIVE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
archive_read_support_compression_all(_archive);
|
||||
archive_read_support_format_all(_archive);
|
||||
|
||||
if(archive_read_open_file(_archive, archive, 10240) != ARCHIVE_OK) {
|
||||
pm_errno = PM_ERR_NOT_A_FILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
tar_close(tar);
|
||||
archive_read_finish(_archive);
|
||||
|
||||
return(lp);
|
||||
|
||||
error:
|
||||
if(tar) {
|
||||
tar_close(tar);
|
||||
}
|
||||
archive_read_finish(_archive);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -36,47 +36,12 @@
|
|||
#ifdef CYGWIN
|
||||
#include <limits.h> /* PATH_MAX */
|
||||
#endif
|
||||
#include <zlib.h>
|
||||
#include <libtar.h>
|
||||
/* pacman */
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "error.h"
|
||||
#include "alpm.h"
|
||||
|
||||
/* borrowed and modified from Per Liden's pkgutils (http://crux.nu) */
|
||||
long _alpm_gzopen_frontend(char *pathname, int oflags, int mode)
|
||||
{
|
||||
char* gzoflags;
|
||||
int fd;
|
||||
gzFile gzf;
|
||||
|
||||
switch (oflags & O_ACCMODE) {
|
||||
case O_WRONLY:
|
||||
gzoflags = "w";
|
||||
break;
|
||||
case O_RDONLY:
|
||||
gzoflags = "r";
|
||||
break;
|
||||
case O_RDWR:
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((fd = open(pathname, oflags, mode)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
if((oflags & O_CREAT) && fchmod(fd, mode)) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
if(!(gzf = gzdopen(fd, gzoflags))) {
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (long)gzf;
|
||||
}
|
||||
|
||||
/* does the same thing as 'mkdir -p' */
|
||||
int _alpm_makepath(char *path)
|
||||
{
|
||||
|
@ -207,40 +172,56 @@ int _alpm_lckrm(char *file)
|
|||
|
||||
int _alpm_unpack(char *archive, const char *prefix, const char *fn)
|
||||
{
|
||||
TAR *tar = NULL;
|
||||
register struct archive *_archive;
|
||||
struct archive_entry *entry;
|
||||
char expath[PATH_MAX];
|
||||
tartype_t gztype = {
|
||||
(openfunc_t) _alpm_gzopen_frontend,
|
||||
(closefunc_t)gzclose,
|
||||
(readfunc_t) gzread,
|
||||
(writefunc_t)gzwrite
|
||||
};
|
||||
|
||||
if((_archive = archive_read_new()) == NULL) {
|
||||
pm_errno = PM_ERR_LIBARCHIVE_ERROR;
|
||||
return(1);
|
||||
}
|
||||
archive_read_support_compression_all(_archive);
|
||||
archive_read_support_format_all(_archive);
|
||||
/* open the .tar.gz package */
|
||||
if(tar_open(&tar, archive, &gztype, O_RDONLY, 0, TAR_GNU) == -1) {
|
||||
if(archive_read_open_file(_archive, archive, 10240) != ARCHIVE_OK) {
|
||||
perror(archive);
|
||||
return(1);
|
||||
}
|
||||
while(!th_read(tar)) {
|
||||
if(fn && strcmp(fn, th_get_pathname(tar))) {
|
||||
if(TH_ISREG(tar) && tar_skip_regfile(tar)) {
|
||||
_alpm_log(PM_LOG_ERROR, _("bad tar archive: %s"), archive);
|
||||
tar_close(tar);
|
||||
while(!archive_read_next_header(_archive, &entry) == ARCHIVE_OK) {
|
||||
if(fn && strcmp(fn, archive_entry_pathname(entry))) {
|
||||
if(archive_read_data_skip(_archive) != ARCHIVE_OK) {
|
||||
_alpm_log(PM_LOG_ERROR, _("bad archive: %s"), archive);
|
||||
return(1);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
snprintf(expath, PATH_MAX, "%s/%s", prefix, th_get_pathname(tar));
|
||||
if(tar_extract_file(tar, expath)) {
|
||||
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)"), th_get_pathname(tar), strerror(errno));
|
||||
snprintf(expath, PATH_MAX, "%s/%s", prefix, archive_entry_pathname(entry));
|
||||
if(archive_read_extract(_archive, entry, ARCHIVE_EXTRACT_FLAGS) != ARCHIVE_OK) {
|
||||
_alpm_log(PM_LOG_ERROR, _("could not extract %s (%s)"), archive_entry_pathname(entry), archive_error_string(_archive));
|
||||
return(1);
|
||||
}
|
||||
if(fn) break;
|
||||
}
|
||||
tar_close(tar);
|
||||
archive_read_finish(_archive);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
int _alpm_archive_read_entry_data_into_fd(struct archive *archive, int fd)
|
||||
{
|
||||
register size_t length;
|
||||
char cache[10240];
|
||||
|
||||
if(fd == -1) {
|
||||
return ARCHIVE_RETRY;
|
||||
}
|
||||
while((length = archive_read_data(archive, &cache, sizeof(cache))) > 0) {
|
||||
write(fd, cache, length);
|
||||
}
|
||||
|
||||
return ARCHIVE_OK;
|
||||
}
|
||||
|
||||
/* does the same thing as 'rm -rf' */
|
||||
int _alpm_rmrf(char *path)
|
||||
{
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#define _ALPM_UTIL_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <archive.h>
|
||||
#include <archive_entry.h>
|
||||
|
||||
#define FREE(p) do { if (p) { free(p); p = NULL; } } while(0)
|
||||
|
||||
|
@ -34,7 +36,8 @@
|
|||
|
||||
#define _(str) dgettext("libalpm", str)
|
||||
|
||||
long _alpm_gzopen_frontend(char *pathname, int oflags, int mode);
|
||||
#define ARCHIVE_EXTRACT_FLAGS ARCHIVE_EXTRACT_OWNER | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_TIME
|
||||
|
||||
int _alpm_makepath(char *path);
|
||||
int _alpm_copyfile(char *src, char *dest);
|
||||
char *_alpm_strtoupper(char *str);
|
||||
|
@ -43,6 +46,7 @@ int _alpm_lckmk(char *file);
|
|||
int _alpm_lckrm(char *file);
|
||||
int _alpm_unpack(char *archive, const char *prefix, const char *fn);
|
||||
int _alpm_rmrf(char *path);
|
||||
int _alpm_archive_read_entry_data_into_fd(struct archive *archive, int fd);
|
||||
int _alpm_logaction(unsigned char usesyslog, FILE *f, char *fmt, ...);
|
||||
int _alpm_ldconfig(char *root);
|
||||
int _alpm_runscriptlet(char *util, char *installfn, char *script, char *ver, char *oldver);
|
||||
|
|
Loading…
Reference in New Issue