2005-03-14 20:51:43 -05:00
|
|
|
/*
|
|
|
|
* util.c
|
2006-10-15 15:31:03 -04:00
|
|
|
*
|
2011-01-05 23:45:15 -05:00
|
|
|
* Copyright (c) 2006-2011 Pacman Development Team <pacman-dev@archlinux.org>
|
2009-07-01 03:08:33 -04:00
|
|
|
* Copyright (c) 2002-2006 by Judd Vinet <jvinet@zeroflux.org>
|
2006-10-15 15:31:03 -04:00
|
|
|
* Copyright (c) 2005 by Aurelien Foret <orelien@chez.com>
|
|
|
|
* Copyright (c) 2005 by Christian Hamar <krics@linuxforum.hu>
|
|
|
|
* Copyright (c) 2006 by David Kimpe <dnaku@frugalware.org>
|
|
|
|
* Copyright (c) 2005, 2006 by Miklos Vajna <vmiklos@frugalware.org>
|
2007-11-16 21:18:45 -05:00
|
|
|
*
|
2005-03-14 20:51:43 -05:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2007-12-10 23:55:22 -05:00
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2005-03-14 20:51:43 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
2007-03-05 17:13:33 -05:00
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
2008-08-08 23:18:00 -04:00
|
|
|
#include <stdarg.h>
|
2005-03-14 20:51:43 -05:00
|
|
|
#include <string.h>
|
2007-04-29 12:47:02 -04:00
|
|
|
#include <unistd.h>
|
2005-03-14 20:51:43 -05:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <syslog.h>
|
2007-04-29 12:47:02 -04:00
|
|
|
#include <errno.h>
|
2011-04-01 18:36:08 -04:00
|
|
|
#include <limits.h>
|
2007-06-27 19:27:26 -04:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2009-07-08 05:08:32 -04:00
|
|
|
#include <sys/wait.h>
|
2011-02-01 10:59:12 -05:00
|
|
|
#include <locale.h> /* setlocale */
|
2007-04-29 12:47:02 -04:00
|
|
|
|
|
|
|
/* libarchive */
|
|
|
|
#include <archive.h>
|
|
|
|
#include <archive_entry.h>
|
2006-10-15 15:31:03 -04:00
|
|
|
|
2010-09-02 13:05:23 -04:00
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
#include <openssl/md5.h>
|
|
|
|
#else
|
|
|
|
#include "md5.h"
|
|
|
|
#endif
|
|
|
|
|
2007-03-05 17:13:33 -05:00
|
|
|
/* libalpm */
|
|
|
|
#include "util.h"
|
2005-03-14 20:51:43 -05:00
|
|
|
#include "log.h"
|
|
|
|
#include "alpm.h"
|
2007-08-20 13:28:51 -04:00
|
|
|
#include "alpm_list.h"
|
2009-07-08 05:08:32 -04:00
|
|
|
#include "handle.h"
|
2011-06-03 17:42:41 -04:00
|
|
|
#include "trans.h"
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-07-12 15:20:43 -04:00
|
|
|
#ifndef HAVE_STRSEP
|
2006-10-15 15:31:03 -04:00
|
|
|
/* This is a replacement for strsep which is not portable (missing on Solaris).
|
2007-01-23 22:02:53 -05:00
|
|
|
* Copyright (c) 2001 by François Gouget <fgouget_at_codeweavers.com> */
|
2006-10-15 15:31:03 -04:00
|
|
|
char* strsep(char** str, const char* delims)
|
|
|
|
{
|
|
|
|
char* token;
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(*str==NULL) {
|
2006-10-15 15:31:03 -04:00
|
|
|
/* No more tokens */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
token=*str;
|
2011-04-20 20:45:16 -04:00
|
|
|
while(**str!='\0') {
|
|
|
|
if(strchr(delims,**str)!=NULL) {
|
2006-10-15 15:31:03 -04:00
|
|
|
**str='\0';
|
|
|
|
(*str)++;
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
(*str)++;
|
|
|
|
}
|
|
|
|
/* There is no other token */
|
|
|
|
*str=NULL;
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-03-03 03:13:59 -05:00
|
|
|
int _alpm_makepath(const char *path)
|
2008-01-13 09:06:25 -05:00
|
|
|
{
|
2011-03-20 20:45:57 -04:00
|
|
|
return _alpm_makepath_mode(path, 0755);
|
2008-01-13 09:06:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* does the same thing as 'mkdir -p' */
|
|
|
|
int _alpm_makepath_mode(const char *path, mode_t mode)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2008-05-04 19:39:22 -04:00
|
|
|
/* A bit of pointer hell here. Descriptions:
|
|
|
|
* orig - a copy of path so we can safely butcher it with strsep
|
|
|
|
* str - the current position in the path string (after the delimiter)
|
|
|
|
* ptr - the original position of str after calling strsep
|
|
|
|
* incr - incrementally generated path for use in stat/mkdir call
|
|
|
|
*/
|
|
|
|
char *orig, *str, *ptr, *incr;
|
|
|
|
mode_t oldmask = umask(0000);
|
|
|
|
int ret = 0;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
|
|
|
orig = strdup(path);
|
2008-05-04 19:39:22 -04:00
|
|
|
incr = calloc(strlen(orig) + 1, sizeof(char));
|
2005-03-14 20:51:43 -05:00
|
|
|
str = orig;
|
|
|
|
while((ptr = strsep(&str, "/"))) {
|
|
|
|
if(strlen(ptr)) {
|
2008-05-04 19:39:22 -04:00
|
|
|
/* we have another path component- append the newest component to
|
|
|
|
* existing string and create one more level of dir structure */
|
|
|
|
strcat(incr, "/");
|
|
|
|
strcat(incr, ptr);
|
2008-06-15 20:15:36 -04:00
|
|
|
if(access(incr, F_OK)) {
|
2008-05-04 19:39:22 -04:00
|
|
|
if(mkdir(incr, mode)) {
|
|
|
|
ret = 1;
|
|
|
|
break;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-05-04 19:39:22 -04:00
|
|
|
free(orig);
|
|
|
|
free(incr);
|
2005-03-14 20:51:43 -05:00
|
|
|
umask(oldmask);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2008-04-28 23:23:31 -04:00
|
|
|
#define CPBUFSIZE 8 * 1024
|
|
|
|
|
2007-03-03 03:13:59 -05:00
|
|
|
int _alpm_copyfile(const char *src, const char *dest)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
|
|
|
FILE *in, *out;
|
|
|
|
size_t len;
|
2008-04-28 23:23:31 -04:00
|
|
|
char *buf;
|
|
|
|
int ret = 0;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2008-04-28 23:23:31 -04:00
|
|
|
in = fopen(src, "rb");
|
2005-03-14 20:51:43 -05:00
|
|
|
if(in == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2008-04-28 23:23:31 -04:00
|
|
|
out = fopen(dest, "wb");
|
2005-03-14 20:51:43 -05:00
|
|
|
if(out == NULL) {
|
2005-04-24 05:14:25 -04:00
|
|
|
fclose(in);
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2008-05-14 20:38:58 -04:00
|
|
|
CALLOC(buf, (size_t)CPBUFSIZE, (size_t)1, ret = 1; goto cleanup;);
|
2008-04-28 23:23:31 -04:00
|
|
|
|
2007-06-27 19:27:26 -04:00
|
|
|
/* do the actual file copy */
|
2008-04-28 23:23:31 -04:00
|
|
|
while((len = fread(buf, 1, CPBUFSIZE, in))) {
|
2010-06-27 07:13:01 -04:00
|
|
|
size_t nwritten = 0;
|
|
|
|
nwritten = fwrite(buf, 1, len, out);
|
|
|
|
if((nwritten != len) || ferror(out)) {
|
|
|
|
ret = -1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2007-06-27 19:27:26 -04:00
|
|
|
|
|
|
|
/* chmod dest to permissions of src, as long as it is not a symlink */
|
|
|
|
struct stat statbuf;
|
2007-06-28 10:59:34 -04:00
|
|
|
if(!stat(src, &statbuf)) {
|
2007-06-27 19:27:26 -04:00
|
|
|
if(! S_ISLNK(statbuf.st_mode)) {
|
2007-07-06 12:11:55 -04:00
|
|
|
fchmod(fileno(out), statbuf.st_mode);
|
2007-06-27 19:27:26 -04:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* stat was unsuccessful */
|
2008-04-28 23:23:31 -04:00
|
|
|
ret = 1;
|
2007-06-27 19:27:26 -04:00
|
|
|
}
|
|
|
|
|
2008-04-28 23:23:31 -04:00
|
|
|
cleanup:
|
|
|
|
fclose(in);
|
2007-07-06 12:11:55 -04:00
|
|
|
fclose(out);
|
2008-04-28 23:23:31 -04:00
|
|
|
FREE(buf);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Trim whitespace and newlines from a string
|
2007-05-18 02:24:59 -04:00
|
|
|
*/
|
2005-03-14 20:51:43 -05:00
|
|
|
char *_alpm_strtrim(char *str)
|
|
|
|
{
|
|
|
|
char *pch = str;
|
2005-03-19 13:15:31 -05:00
|
|
|
|
2005-03-25 16:13:23 -05:00
|
|
|
if(*str == '\0') {
|
|
|
|
/* string is empty, so we're done. */
|
2011-03-20 20:45:57 -04:00
|
|
|
return str;
|
2005-03-25 16:13:23 -05:00
|
|
|
}
|
|
|
|
|
2009-09-25 18:58:42 -04:00
|
|
|
while(isspace((unsigned char)*pch)) {
|
2005-03-14 20:51:43 -05:00
|
|
|
pch++;
|
|
|
|
}
|
|
|
|
if(pch != str) {
|
|
|
|
memmove(str, pch, (strlen(pch) + 1));
|
|
|
|
}
|
2005-03-19 13:15:31 -05:00
|
|
|
|
2005-03-25 16:13:23 -05:00
|
|
|
/* check if there wasn't anything but whitespace in the string. */
|
|
|
|
if(*str == '\0') {
|
2011-03-20 20:45:57 -04:00
|
|
|
return str;
|
2005-03-25 16:13:23 -05:00
|
|
|
}
|
|
|
|
|
2007-05-14 03:16:55 -04:00
|
|
|
pch = (str + (strlen(str) - 1));
|
2009-09-25 18:58:42 -04:00
|
|
|
while(isspace((unsigned char)*pch)) {
|
2005-03-14 20:51:43 -05:00
|
|
|
pch--;
|
|
|
|
}
|
|
|
|
*++pch = '\0';
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return str;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-06-27 23:25:04 -04:00
|
|
|
/* Compression functions */
|
2006-10-15 15:31:03 -04:00
|
|
|
|
2008-04-08 23:30:46 -04:00
|
|
|
/**
|
2009-10-10 16:49:24 -04:00
|
|
|
* @brief Unpack a specific file in an archive.
|
2008-04-08 23:30:46 -04:00
|
|
|
*
|
2011-06-07 17:06:16 -04:00
|
|
|
* @param handle the context handle
|
|
|
|
* @param archive the archive to unpack
|
|
|
|
* @param prefix where to extract the files
|
|
|
|
* @param filename a file within the archive to unpack
|
2009-01-18 08:01:24 -05:00
|
|
|
* @return 0 on success, 1 on failure
|
2008-04-08 23:30:46 -04:00
|
|
|
*/
|
2011-06-28 00:04:00 -04:00
|
|
|
int _alpm_unpack_single(alpm_handle_t *handle, const char *archive,
|
2011-06-07 17:06:16 -04:00
|
|
|
const char *prefix, const char *filename)
|
2009-10-10 16:49:24 -04:00
|
|
|
{
|
|
|
|
alpm_list_t *list = NULL;
|
|
|
|
int ret = 0;
|
2011-06-07 17:06:16 -04:00
|
|
|
if(filename == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2009-10-10 16:49:24 -04:00
|
|
|
}
|
2011-06-07 17:06:16 -04:00
|
|
|
list = alpm_list_add(list, (void *)filename);
|
|
|
|
ret = _alpm_unpack(handle, archive, prefix, list, 1);
|
2009-10-10 16:49:24 -04:00
|
|
|
alpm_list_free(list);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2009-10-10 16:49:24 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Unpack a list of files in an archive.
|
|
|
|
*
|
2011-06-07 17:06:16 -04:00
|
|
|
* @param handle the context handle
|
|
|
|
* @param archive the archive to unpack
|
|
|
|
* @param prefix where to extract the files
|
|
|
|
* @param list a list of files within the archive to unpack or NULL for all
|
2009-10-10 16:49:24 -04:00
|
|
|
* @param breakfirst break after the first entry found
|
|
|
|
*
|
|
|
|
* @return 0 on success, 1 on failure
|
|
|
|
*/
|
2011-06-28 00:04:00 -04:00
|
|
|
int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix,
|
2011-06-07 17:06:16 -04:00
|
|
|
alpm_list_t *list, int breakfirst)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2009-01-18 08:01:24 -05:00
|
|
|
int ret = 0;
|
2007-11-14 20:22:06 -05:00
|
|
|
mode_t oldmask;
|
|
|
|
struct archive *_archive;
|
2006-09-28 16:51:33 -04:00
|
|
|
struct archive_entry *entry;
|
2009-01-18 08:01:24 -05:00
|
|
|
char cwd[PATH_MAX];
|
|
|
|
int restore_cwd = 0;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2011-06-07 17:06:16 -04:00
|
|
|
if((_archive = archive_read_new()) == NULL) {
|
2011-07-01 12:01:39 -04:00
|
|
|
RET_ERR(handle, ALPM_ERR_LIBARCHIVE, 1);
|
2011-06-07 17:06:16 -04:00
|
|
|
}
|
2006-10-15 15:31:03 -04:00
|
|
|
|
2006-09-28 16:51:33 -04:00
|
|
|
archive_read_support_compression_all(_archive);
|
2006-11-14 02:58:42 -05:00
|
|
|
archive_read_support_format_all(_archive);
|
2006-10-15 15:31:03 -04:00
|
|
|
|
2007-08-14 10:14:35 -04:00
|
|
|
if(archive_read_open_filename(_archive, archive,
|
|
|
|
ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open file %s: %s\n"), archive,
|
2007-08-23 22:26:55 -04:00
|
|
|
archive_error_string(_archive));
|
2011-07-01 12:01:39 -04:00
|
|
|
RET_ERR(handle, ALPM_ERR_PKG_OPEN, 1);
|
2006-11-16 12:24:41 -05:00
|
|
|
}
|
2006-10-15 15:31:03 -04:00
|
|
|
|
2007-11-14 20:22:06 -05:00
|
|
|
oldmask = umask(0022);
|
2009-01-18 08:01:24 -05:00
|
|
|
|
|
|
|
/* save the cwd so we can restore it later */
|
|
|
|
if(getcwd(cwd, PATH_MAX) == NULL) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
|
2009-01-18 08:01:24 -05:00
|
|
|
} else {
|
|
|
|
restore_cwd = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* just in case our cwd was removed in the upgrade operation */
|
|
|
|
if(chdir(prefix) != 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
|
2011-06-07 17:06:16 -04:00
|
|
|
prefix, strerror(errno));
|
2009-01-18 08:01:24 -05:00
|
|
|
ret = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2006-11-14 02:58:42 -05:00
|
|
|
while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) {
|
2007-11-14 20:22:06 -05:00
|
|
|
const struct stat *st;
|
2007-07-01 20:12:36 -04:00
|
|
|
const char *entryname; /* the name of the file in the archive */
|
2007-11-14 20:22:06 -05:00
|
|
|
|
|
|
|
st = archive_entry_stat(entry);
|
2007-07-01 20:12:36 -04:00
|
|
|
entryname = archive_entry_pathname(entry);
|
2009-11-12 18:59:34 -05:00
|
|
|
|
2007-11-14 20:22:06 -05:00
|
|
|
if(S_ISREG(st->st_mode)) {
|
Use archive_entry_set_perm instead of archive_entry_set_mode
This patch fixes FS#12148 ('unstable' regular file).
I also changed the other archive_entry_set_mode usage in add.c to
archive_entry_set_perm.
Since I cannot find any relevant info in libarchive manual, I quote
Tim Kientzle (the author of libarchive) here, and I say thank you for
his help.
*** Tim Kientzle wrote *************************************
This is the problem in libalpm/util.c:
323 if(S_ISREG(st->st_mode)) {
324 archive_entry_set_mode(entry, 0644);
325 } else if(S_ISDIR(st->st_mode)) {
326 archive_entry_set_mode(entry, 0755);
327 }
Your example unstable.db.tar.gz is not empty. It has
one entry in it, called "./". That entry is marked
as a directory. But, when you call archive_entry_set_mode(),
you are changing the file type! archive_read_extract()
then creates the file /var/unstable as you requested.
(archive_read_extract() will replace an empty directory
with a file.)
You should either set the mode value correctly:
323 if(S_ISREG(st->st_mode)) {
324 archive_entry_set_mode(entry, IFREG | 0644);
325 } else if(S_ISDIR(st->st_mode)) {
326 archive_entry_set_mode(entry, IFDIR | 0755);
327 }
Or use archive_entry_set_perm(), which does not change
the file type:
323 if(S_ISREG(st->st_mode)) {
324 archive_entry_set_perm(entry, 0644);
325 } else if(S_ISDIR(st->st_mode)) {
326 archive_entry_set_perm(entry, 0755);
327 }
************************************************************
Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu>
Signed-off-by: Dan McGee <dan@archlinux.org>
2009-01-18 14:03:56 -05:00
|
|
|
archive_entry_set_perm(entry, 0644);
|
2008-01-13 05:08:59 -05:00
|
|
|
} else if(S_ISDIR(st->st_mode)) {
|
Use archive_entry_set_perm instead of archive_entry_set_mode
This patch fixes FS#12148 ('unstable' regular file).
I also changed the other archive_entry_set_mode usage in add.c to
archive_entry_set_perm.
Since I cannot find any relevant info in libarchive manual, I quote
Tim Kientzle (the author of libarchive) here, and I say thank you for
his help.
*** Tim Kientzle wrote *************************************
This is the problem in libalpm/util.c:
323 if(S_ISREG(st->st_mode)) {
324 archive_entry_set_mode(entry, 0644);
325 } else if(S_ISDIR(st->st_mode)) {
326 archive_entry_set_mode(entry, 0755);
327 }
Your example unstable.db.tar.gz is not empty. It has
one entry in it, called "./". That entry is marked
as a directory. But, when you call archive_entry_set_mode(),
you are changing the file type! archive_read_extract()
then creates the file /var/unstable as you requested.
(archive_read_extract() will replace an empty directory
with a file.)
You should either set the mode value correctly:
323 if(S_ISREG(st->st_mode)) {
324 archive_entry_set_mode(entry, IFREG | 0644);
325 } else if(S_ISDIR(st->st_mode)) {
326 archive_entry_set_mode(entry, IFDIR | 0755);
327 }
Or use archive_entry_set_perm(), which does not change
the file type:
323 if(S_ISREG(st->st_mode)) {
324 archive_entry_set_perm(entry, 0644);
325 } else if(S_ISDIR(st->st_mode)) {
326 archive_entry_set_perm(entry, 0755);
327 }
************************************************************
Signed-off-by: Nagy Gabor <ngaba@bibl.u-szeged.hu>
Signed-off-by: Dan McGee <dan@archlinux.org>
2009-01-18 14:03:56 -05:00
|
|
|
archive_entry_set_perm(entry, 0755);
|
2007-11-14 20:22:06 -05:00
|
|
|
}
|
2007-07-01 20:12:36 -04:00
|
|
|
|
2009-10-10 16:49:24 -04:00
|
|
|
/* If specific files were requested, skip entries that don't match. */
|
|
|
|
if(list) {
|
2011-06-27 11:10:08 -04:00
|
|
|
char *entry_prefix = strdup(entryname);
|
2011-06-29 09:22:24 -04:00
|
|
|
char *p = strstr(entry_prefix,"/");
|
2009-10-10 16:49:24 -04:00
|
|
|
if(p) {
|
|
|
|
*(p+1) = '\0';
|
|
|
|
}
|
2011-06-27 11:10:08 -04:00
|
|
|
char *found = alpm_list_find_str(list, entry_prefix);
|
|
|
|
free(entry_prefix);
|
2009-10-10 16:49:24 -04:00
|
|
|
if(!found) {
|
2011-04-20 20:45:16 -04:00
|
|
|
if(archive_read_data_skip(_archive) != ARCHIVE_OK) {
|
2009-10-10 16:49:24 -04:00
|
|
|
ret = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
continue;
|
2009-10-09 13:11:27 -04:00
|
|
|
} else {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "extracting: %s\n", entryname);
|
2007-11-14 20:22:06 -05:00
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2008-04-08 23:30:46 -04:00
|
|
|
|
|
|
|
/* Extract the archive entry. */
|
2007-11-14 20:22:06 -05:00
|
|
|
int readret = archive_read_extract(_archive, entry, 0);
|
|
|
|
if(readret == ARCHIVE_WARN) {
|
2007-07-01 20:12:36 -04:00
|
|
|
/* operation succeeded but a non-critical error was encountered */
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING, _("warning given when extracting %s (%s)\n"),
|
2007-07-01 20:12:36 -04:00
|
|
|
entryname, archive_error_string(_archive));
|
2007-11-14 20:22:06 -05:00
|
|
|
} else if(readret != ARCHIVE_OK) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not extract %s (%s)\n"),
|
2007-07-01 20:12:36 -04:00
|
|
|
entryname, archive_error_string(_archive));
|
2007-11-14 20:22:06 -05:00
|
|
|
ret = 1;
|
|
|
|
goto cleanup;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2009-10-10 16:49:24 -04:00
|
|
|
if(breakfirst) {
|
2006-10-15 15:31:03 -04:00
|
|
|
break;
|
2006-11-14 02:58:42 -05:00
|
|
|
}
|
2006-09-28 16:51:33 -04:00
|
|
|
}
|
2007-05-18 02:24:59 -04:00
|
|
|
|
2007-11-14 20:22:06 -05:00
|
|
|
cleanup:
|
|
|
|
umask(oldmask);
|
2006-11-14 02:58:42 -05:00
|
|
|
archive_read_finish(_archive);
|
2010-06-27 06:32:11 -04:00
|
|
|
if(restore_cwd && chdir(cwd) != 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
|
2011-06-07 17:06:16 -04:00
|
|
|
cwd, strerror(errno));
|
2009-01-18 08:01:24 -05:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2006-09-28 16:51:33 -04:00
|
|
|
}
|
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
/* does the same thing as 'rm -rf' */
|
2007-03-03 03:13:59 -05:00
|
|
|
int _alpm_rmrf(const char *path)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
|
|
|
int errflag = 0;
|
|
|
|
struct dirent *dp;
|
|
|
|
DIR *dirp;
|
|
|
|
char name[PATH_MAX];
|
2007-03-19 00:49:28 -04:00
|
|
|
struct stat st;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2007-11-04 19:02:25 -05:00
|
|
|
if(_alpm_lstat(path, &st) == 0) {
|
2007-03-19 00:49:28 -04:00
|
|
|
if(!S_ISDIR(st.st_mode)) {
|
2006-10-31 01:39:59 -05:00
|
|
|
if(!unlink(path)) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2006-10-31 01:39:59 -05:00
|
|
|
} else {
|
|
|
|
if(errno == ENOENT) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2006-10-31 01:39:59 -05:00
|
|
|
} else {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
2007-03-19 00:49:28 -04:00
|
|
|
} else {
|
2009-10-27 22:11:29 -04:00
|
|
|
dirp = opendir(path);
|
|
|
|
if(!dirp) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2006-10-31 01:39:59 -05:00
|
|
|
}
|
|
|
|
for(dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
|
|
|
|
if(dp->d_ino) {
|
|
|
|
sprintf(name, "%s/%s", path, dp->d_name);
|
2010-06-19 04:55:08 -04:00
|
|
|
if(strcmp(dp->d_name, "..") != 0 && strcmp(dp->d_name, ".") != 0) {
|
2006-10-31 01:39:59 -05:00
|
|
|
errflag += _alpm_rmrf(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
closedir(dirp);
|
|
|
|
if(rmdir(path)) {
|
|
|
|
errflag++;
|
|
|
|
}
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return errflag;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
int _alpm_logaction(alpm_handle_t *handle, const char *fmt, va_list args)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
2007-06-07 20:55:13 -04:00
|
|
|
int ret = 0;
|
2005-03-14 20:51:43 -05:00
|
|
|
|
2011-06-07 13:41:33 -04:00
|
|
|
if(handle->usesyslog) {
|
2008-08-08 23:18:00 -04:00
|
|
|
/* we can't use a va_list more than once, so we need to copy it
|
|
|
|
* so we can use the original when calling vfprintf below. */
|
|
|
|
va_list args_syslog;
|
|
|
|
va_copy(args_syslog, args);
|
|
|
|
vsyslog(LOG_WARNING, fmt, args_syslog);
|
|
|
|
va_end(args_syslog);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2011-06-07 13:41:33 -04:00
|
|
|
if(handle->logstream) {
|
2005-03-14 20:51:43 -05:00
|
|
|
time_t t;
|
|
|
|
struct tm *tm;
|
|
|
|
|
|
|
|
t = time(NULL);
|
|
|
|
tm = localtime(&t);
|
|
|
|
|
2007-01-25 20:33:03 -05:00
|
|
|
/* Use ISO-8601 date format */
|
2011-06-07 13:41:33 -04:00
|
|
|
fprintf(handle->logstream, "[%04d-%02d-%02d %02d:%02d] ",
|
2007-05-18 02:24:59 -04:00
|
|
|
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
|
2007-06-07 20:55:13 -04:00
|
|
|
tm->tm_hour, tm->tm_min);
|
2011-06-07 13:41:33 -04:00
|
|
|
ret = vfprintf(handle->logstream, fmt, args);
|
|
|
|
fflush(handle->logstream);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[])
|
2009-07-08 05:08:32 -04:00
|
|
|
{
|
|
|
|
char cwd[PATH_MAX];
|
|
|
|
pid_t pid;
|
2010-08-18 08:07:18 -04:00
|
|
|
int pipefd[2];
|
2009-07-08 05:08:32 -04:00
|
|
|
int restore_cwd = 0;
|
|
|
|
int retval = 0;
|
|
|
|
|
|
|
|
/* save the cwd so we can restore it later */
|
|
|
|
if(getcwd(cwd, PATH_MAX) == NULL) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n"));
|
2009-07-08 05:08:32 -04:00
|
|
|
} else {
|
|
|
|
restore_cwd = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* just in case our cwd was removed in the upgrade operation */
|
2011-06-03 13:33:18 -04:00
|
|
|
if(chdir(handle->root) != 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"),
|
2011-06-03 13:33:18 -04:00
|
|
|
handle->root, strerror(errno));
|
2009-07-08 05:08:32 -04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "executing \"%s\" under chroot \"%s\"\n",
|
2011-06-03 13:33:18 -04:00
|
|
|
path, handle->root);
|
2009-07-08 05:08:32 -04:00
|
|
|
|
|
|
|
/* Flush open fds before fork() to avoid cloning buffers */
|
|
|
|
fflush(NULL);
|
|
|
|
|
2010-08-18 08:07:18 -04:00
|
|
|
if(pipe(pipefd) == -1) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not create pipe (%s)\n"), strerror(errno));
|
2010-08-18 08:07:18 -04:00
|
|
|
retval = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2009-07-08 05:08:32 -04:00
|
|
|
/* fork- parent and child each have seperate code blocks below */
|
|
|
|
pid = fork();
|
|
|
|
if(pid == -1) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not fork a new process (%s)\n"), strerror(errno));
|
2009-07-08 05:08:32 -04:00
|
|
|
retval = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pid == 0) {
|
|
|
|
/* this code runs for the child only (the actual chroot/exec) */
|
2010-08-18 08:07:18 -04:00
|
|
|
close(1);
|
|
|
|
close(2);
|
|
|
|
while(dup2(pipefd[1], 1) == -1 && errno == EINTR);
|
|
|
|
while(dup2(pipefd[1], 2) == -1 && errno == EINTR);
|
|
|
|
close(pipefd[0]);
|
|
|
|
close(pipefd[1]);
|
|
|
|
|
|
|
|
/* use fprintf instead of _alpm_log to send output through the parent */
|
2011-06-03 13:33:18 -04:00
|
|
|
if(chroot(handle->root) != 0) {
|
2010-08-18 08:07:18 -04:00
|
|
|
fprintf(stderr, _("could not change the root directory (%s)\n"), strerror(errno));
|
2009-07-08 05:08:32 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if(chdir("/") != 0) {
|
2011-02-28 18:50:23 -05:00
|
|
|
fprintf(stderr, _("could not change directory to %s (%s)\n"),
|
|
|
|
"/", strerror(errno));
|
2009-07-08 05:08:32 -04:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
umask(0022);
|
2010-08-18 08:07:21 -04:00
|
|
|
execv(path, argv);
|
|
|
|
fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno));
|
2010-08-18 08:07:18 -04:00
|
|
|
exit(1);
|
2009-07-08 05:08:32 -04:00
|
|
|
} else {
|
|
|
|
/* this code runs for the parent only (wait on the child) */
|
|
|
|
int status;
|
2011-06-27 11:10:08 -04:00
|
|
|
FILE *pipe_file;
|
2010-08-18 08:07:18 -04:00
|
|
|
|
|
|
|
close(pipefd[1]);
|
2011-06-27 11:10:08 -04:00
|
|
|
pipe_file = fdopen(pipefd[0], "r");
|
|
|
|
if(pipe_file == NULL) {
|
2010-08-18 08:07:18 -04:00
|
|
|
close(pipefd[0]);
|
2009-07-08 05:08:32 -04:00
|
|
|
retval = 1;
|
|
|
|
} else {
|
2011-06-27 11:10:08 -04:00
|
|
|
while(!feof(pipe_file)) {
|
2010-08-18 08:07:18 -04:00
|
|
|
char line[PATH_MAX];
|
2011-06-27 11:10:08 -04:00
|
|
|
if(fgets(line, PATH_MAX, pipe_file) == NULL)
|
2010-08-18 08:07:18 -04:00
|
|
|
break;
|
2011-06-07 13:41:33 -04:00
|
|
|
alpm_logaction(handle, "%s", line);
|
2011-07-01 12:01:39 -04:00
|
|
|
EVENT(handle->trans, ALPM_TRANS_EVT_SCRIPTLET_INFO, line, NULL);
|
2010-08-18 08:07:18 -04:00
|
|
|
}
|
2011-06-27 11:10:08 -04:00
|
|
|
fclose(pipe_file);
|
2010-08-18 08:07:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
while(waitpid(pid, &status, 0) == -1) {
|
|
|
|
if(errno != EINTR) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("call to waitpid failed (%s)\n"), strerror(errno));
|
2010-08-18 08:07:18 -04:00
|
|
|
retval = 1;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* report error from above after the child has exited */
|
|
|
|
if(retval != 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not open pipe (%s)\n"), strerror(errno));
|
2010-08-18 08:07:18 -04:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
/* check the return status, make sure it is 0 (success) */
|
|
|
|
if(WIFEXITED(status)) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "call to waitpid succeeded\n");
|
2010-08-18 08:07:18 -04:00
|
|
|
if(WEXITSTATUS(status) != 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("command failed to execute correctly\n"));
|
2010-08-18 08:07:18 -04:00
|
|
|
retval = 1;
|
2009-07-08 05:08:32 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
cleanup:
|
2010-06-27 06:32:11 -04:00
|
|
|
if(restore_cwd && chdir(cwd) != 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_ERROR, _("could not change directory to %s (%s)\n"), cwd, strerror(errno));
|
2009-07-08 05:08:32 -04:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return retval;
|
2009-07-08 05:08:32 -04:00
|
|
|
}
|
|
|
|
|
2011-06-28 00:04:00 -04:00
|
|
|
int _alpm_ldconfig(alpm_handle_t *handle)
|
2005-03-14 20:51:43 -05:00
|
|
|
{
|
|
|
|
char line[PATH_MAX];
|
|
|
|
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "running ldconfig\n");
|
2009-07-08 05:08:32 -04:00
|
|
|
|
2011-06-03 13:33:18 -04:00
|
|
|
snprintf(line, PATH_MAX, "%setc/ld.so.conf", handle->root);
|
2008-06-15 20:15:36 -04:00
|
|
|
if(access(line, F_OK) == 0) {
|
2011-06-03 13:33:18 -04:00
|
|
|
snprintf(line, PATH_MAX, "%ssbin/ldconfig", handle->root);
|
2008-06-15 20:15:36 -04:00
|
|
|
if(access(line, X_OK) == 0) {
|
2010-08-18 08:07:21 -04:00
|
|
|
char *argv[] = { "ldconfig", NULL };
|
2011-06-03 13:33:18 -04:00
|
|
|
_alpm_run_chroot(handle, "/sbin/ldconfig", argv);
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2005-03-14 20:51:43 -05:00
|
|
|
}
|
|
|
|
|
2007-02-13 03:15:38 -05:00
|
|
|
/* Helper function for comparing strings using the
|
|
|
|
* alpm "compare func" signature */
|
|
|
|
int _alpm_str_cmp(const void *s1, const void *s2)
|
|
|
|
{
|
2011-03-20 20:45:57 -04:00
|
|
|
return strcmp(s1, s2);
|
2007-02-13 03:15:38 -05:00
|
|
|
}
|
|
|
|
|
2008-02-16 11:47:22 -05:00
|
|
|
/** Find a filename in a registered alpm cachedir.
|
2011-06-07 14:15:43 -04:00
|
|
|
* @param handle the context handle
|
2008-02-16 11:47:22 -05:00
|
|
|
* @param filename name of file to find
|
2007-08-20 13:28:51 -04:00
|
|
|
* @return malloced path of file, NULL if not found
|
|
|
|
*/
|
2011-06-28 00:04:00 -04:00
|
|
|
char *_alpm_filecache_find(alpm_handle_t *handle, const char *filename)
|
2007-08-20 13:28:51 -04:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
char *retpath;
|
|
|
|
alpm_list_t *i;
|
2011-02-04 09:42:52 -05:00
|
|
|
struct stat buf;
|
2007-08-20 13:28:51 -04:00
|
|
|
|
|
|
|
/* Loop through the cache dirs until we find a matching file */
|
2011-06-07 14:15:43 -04:00
|
|
|
for(i = alpm_option_get_cachedirs(handle); i; i = alpm_list_next(i)) {
|
2011-03-25 11:57:20 -04:00
|
|
|
snprintf(path, PATH_MAX, "%s%s", (char *)alpm_list_getdata(i),
|
2007-08-20 13:28:51 -04:00
|
|
|
filename);
|
2011-02-04 09:42:52 -05:00
|
|
|
if(stat(path, &buf) == 0 && S_ISREG(buf.st_mode)) {
|
2007-08-20 13:28:51 -04:00
|
|
|
retpath = strdup(path);
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "found cached pkg: %s\n", retpath);
|
2011-03-20 20:45:57 -04:00
|
|
|
return retpath;
|
2007-08-20 13:28:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* package wasn't found in any cachedir */
|
2011-06-07 17:06:16 -04:00
|
|
|
return NULL;
|
2007-08-20 13:28:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Check the alpm cachedirs for existance and find a writable one.
|
|
|
|
* If no valid cache directory can be found, use /tmp.
|
2011-06-07 14:15:43 -04:00
|
|
|
* @param handle the context handle
|
2007-08-20 13:28:51 -04:00
|
|
|
* @return pointer to a writable cache directory.
|
|
|
|
*/
|
2011-06-28 00:04:00 -04:00
|
|
|
const char *_alpm_filecache_setup(alpm_handle_t *handle)
|
2007-08-20 13:28:51 -04:00
|
|
|
{
|
|
|
|
struct stat buf;
|
|
|
|
alpm_list_t *i, *tmp;
|
|
|
|
char *cachedir;
|
|
|
|
|
|
|
|
/* Loop through the cache dirs until we find a writeable dir */
|
2011-06-07 14:15:43 -04:00
|
|
|
for(i = alpm_option_get_cachedirs(handle); i; i = alpm_list_next(i)) {
|
2007-08-20 13:28:51 -04:00
|
|
|
cachedir = alpm_list_getdata(i);
|
|
|
|
if(stat(cachedir, &buf) != 0) {
|
|
|
|
/* cache directory does not exist.... try creating it */
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING, _("no %s cache exists, creating...\n"),
|
2007-08-20 13:28:51 -04:00
|
|
|
cachedir);
|
|
|
|
if(_alpm_makepath(cachedir) == 0) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", cachedir);
|
2011-03-20 20:45:57 -04:00
|
|
|
return cachedir;
|
2007-08-20 13:28:51 -04:00
|
|
|
}
|
|
|
|
} else if(S_ISDIR(buf.st_mode) && (buf.st_mode & S_IWUSR)) {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", cachedir);
|
2011-03-20 20:45:57 -04:00
|
|
|
return cachedir;
|
2011-06-03 17:42:41 -04:00
|
|
|
} else {
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "skipping cachedir: %s\n", cachedir);
|
2007-08-20 13:28:51 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we didn't find a valid cache directory. use /tmp. */
|
2011-06-03 17:42:41 -04:00
|
|
|
tmp = alpm_list_add(NULL, "/tmp/");
|
2011-06-07 14:15:43 -04:00
|
|
|
alpm_option_set_cachedirs(handle, tmp);
|
2011-06-03 17:42:41 -04:00
|
|
|
alpm_list_free(tmp);
|
2011-07-01 12:01:38 -04:00
|
|
|
_alpm_log(handle, ALPM_LOG_DEBUG, "using cachedir: %s\n", "/tmp/");
|
|
|
|
_alpm_log(handle, ALPM_LOG_WARNING, _("couldn't create package cache, using /tmp instead\n"));
|
2011-06-03 17:42:41 -04:00
|
|
|
return "/tmp/";
|
2007-08-20 13:28:51 -04:00
|
|
|
}
|
|
|
|
|
2007-11-04 19:02:25 -05:00
|
|
|
/** lstat wrapper that treats /path/dirsymlink/ the same as /path/dirsymlink.
|
|
|
|
* Linux lstat follows POSIX semantics and still performs a dereference on
|
|
|
|
* the first, and for uses of lstat in libalpm this is not what we want.
|
|
|
|
* @param path path to file to lstat
|
|
|
|
* @param buf structure to fill with stat information
|
|
|
|
* @return the return code from lstat
|
|
|
|
*/
|
|
|
|
int _alpm_lstat(const char *path, struct stat *buf)
|
|
|
|
{
|
|
|
|
int ret;
|
2011-06-09 14:34:13 -04:00
|
|
|
size_t len = strlen(path);
|
2007-11-04 19:02:25 -05:00
|
|
|
|
|
|
|
/* strip the trailing slash if one exists */
|
2011-06-09 14:34:13 -04:00
|
|
|
if(len != 0 && path[len - 1] == '/') {
|
|
|
|
char *newpath = strdup(path);
|
|
|
|
newpath[len - 1] = '\0';
|
|
|
|
ret = lstat(newpath, buf);
|
|
|
|
free(newpath);
|
|
|
|
} else {
|
|
|
|
ret = lstat(path, buf);
|
2007-11-04 19:02:25 -05:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2007-11-04 19:02:25 -05:00
|
|
|
}
|
|
|
|
|
2010-09-02 13:05:23 -04:00
|
|
|
#ifdef HAVE_LIBSSL
|
|
|
|
static int md5_file(const char *path, unsigned char output[16])
|
|
|
|
{
|
2011-01-02 13:25:33 -05:00
|
|
|
FILE *f;
|
|
|
|
size_t n;
|
|
|
|
MD5_CTX ctx;
|
|
|
|
unsigned char *buf;
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-06-07 17:06:16 -04:00
|
|
|
CALLOC(buf, 8192, sizeof(unsigned char), return 1);
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
if((f = fopen(path, "rb")) == NULL) {
|
|
|
|
free(buf);
|
2011-03-20 20:45:57 -04:00
|
|
|
return 1;
|
2011-01-02 13:25:33 -05:00
|
|
|
}
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
MD5_Init(&ctx);
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
while((n = fread(buf, 1, sizeof(buf), f)) > 0) {
|
|
|
|
MD5_Update(&ctx, buf, n);
|
|
|
|
}
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
MD5_Final(output, &ctx);
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
memset(&ctx, 0, sizeof(MD5_CTX));
|
|
|
|
free(buf);
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
if(ferror(f) != 0) {
|
|
|
|
fclose(f);
|
2011-03-20 20:45:57 -04:00
|
|
|
return 2;
|
2011-01-02 13:25:33 -05:00
|
|
|
}
|
2010-09-02 13:05:23 -04:00
|
|
|
|
2011-01-02 13:25:33 -05:00
|
|
|
fclose(f);
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2010-09-02 13:05:23 -04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-07-25 17:49:32 -04:00
|
|
|
/** Get the md5 sum of file.
|
|
|
|
* @param filename name of the file
|
|
|
|
* @return the checksum on success, NULL on error
|
|
|
|
* @addtogroup alpm_misc
|
|
|
|
*/
|
2008-08-26 06:57:08 -04:00
|
|
|
char SYMEXPORT *alpm_compute_md5sum(const char *filename)
|
2007-07-25 17:49:32 -04:00
|
|
|
{
|
|
|
|
unsigned char output[16];
|
|
|
|
char *md5sum;
|
|
|
|
int ret, i;
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
ASSERT(filename != NULL, return NULL);
|
2007-07-25 17:49:32 -04:00
|
|
|
|
|
|
|
/* allocate 32 chars plus 1 for null */
|
2011-06-16 14:16:37 -04:00
|
|
|
CALLOC(md5sum, 33, sizeof(char), return NULL);
|
2010-09-02 13:05:23 -04:00
|
|
|
/* defined above for OpenSSL, otherwise defined in md5.h */
|
2007-07-25 17:49:32 -04:00
|
|
|
ret = md5_file(filename, output);
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(ret > 0) {
|
2011-06-07 17:06:16 -04:00
|
|
|
return NULL;
|
2007-07-25 17:49:32 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert the result to something readable */
|
|
|
|
for (i = 0; i < 16; i++) {
|
|
|
|
/* sprintf is acceptable here because we know our output */
|
|
|
|
sprintf(md5sum +(i * 2), "%02x", output[i]);
|
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return md5sum;
|
2007-07-25 17:49:32 -04:00
|
|
|
}
|
|
|
|
|
2008-02-26 18:50:17 -05:00
|
|
|
int _alpm_test_md5sum(const char *filepath, const char *md5sum)
|
|
|
|
{
|
|
|
|
char *md5sum2;
|
|
|
|
int ret;
|
|
|
|
|
2008-08-26 06:57:08 -04:00
|
|
|
md5sum2 = alpm_compute_md5sum(filepath);
|
2008-02-26 18:50:17 -05:00
|
|
|
|
|
|
|
if(md5sum == NULL || md5sum2 == NULL) {
|
|
|
|
ret = -1;
|
|
|
|
} else if(strcmp(md5sum, md5sum2) != 0) {
|
|
|
|
ret = 1;
|
|
|
|
} else {
|
|
|
|
ret = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
FREE(md5sum2);
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2008-02-26 18:50:17 -05:00
|
|
|
}
|
|
|
|
|
2010-12-14 23:26:23 -05:00
|
|
|
/* Note: does NOT handle sparse files on purpose for speed. */
|
|
|
|
int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b)
|
2008-03-25 22:23:14 -04:00
|
|
|
{
|
2010-12-14 23:26:23 -05:00
|
|
|
char *i = NULL;
|
|
|
|
int64_t offset;
|
|
|
|
int done = 0;
|
|
|
|
|
2011-03-21 09:52:24 -04:00
|
|
|
/* ensure we start populating our line buffer at the beginning */
|
|
|
|
b->line_offset = b->line;
|
|
|
|
|
2010-12-14 23:26:23 -05:00
|
|
|
while(1) {
|
|
|
|
/* have we processed this entire block? */
|
|
|
|
if(b->block + b->block_size == b->block_offset) {
|
|
|
|
if(b->ret == ARCHIVE_EOF) {
|
|
|
|
/* reached end of archive on the last read, now we are out of data */
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* zero-copy - this is the entire next block of data. */
|
2011-03-25 11:57:20 -04:00
|
|
|
b->ret = archive_read_data_block(a, (void *)&b->block,
|
2010-12-14 23:26:23 -05:00
|
|
|
&b->block_size, &offset);
|
|
|
|
b->block_offset = b->block;
|
|
|
|
|
2011-06-22 19:17:38 -04:00
|
|
|
/* error, cleanup */
|
|
|
|
if(b->ret < ARCHIVE_OK) {
|
2010-12-14 23:26:23 -05:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2008-03-25 22:23:14 -04:00
|
|
|
}
|
2010-12-14 23:26:23 -05:00
|
|
|
|
|
|
|
/* loop through the block looking for EOL characters */
|
|
|
|
for(i = b->block_offset; i < (b->block + b->block_size); i++) {
|
|
|
|
/* check if read value was null or newline */
|
|
|
|
if(*i == '\0' || *i == '\n') {
|
|
|
|
done = 1;
|
|
|
|
break;
|
|
|
|
}
|
2008-03-25 22:23:14 -04:00
|
|
|
}
|
|
|
|
|
2010-12-14 23:26:23 -05:00
|
|
|
/* allocate our buffer, or ensure our existing one is big enough */
|
|
|
|
if(!b->line) {
|
|
|
|
/* set the initial buffer to the read block_size */
|
2011-06-22 19:17:38 -04:00
|
|
|
CALLOC(b->line, b->block_size + 1, sizeof(char), b->ret = -ENOMEM; goto cleanup);
|
2010-12-14 23:26:23 -05:00
|
|
|
b->line_size = b->block_size + 1;
|
|
|
|
b->line_offset = b->line;
|
|
|
|
} else {
|
2011-01-07 22:06:06 -05:00
|
|
|
size_t needed = (size_t)((b->line_offset - b->line)
|
|
|
|
+ (i - b->block_offset) + 1);
|
2010-12-14 23:26:23 -05:00
|
|
|
if(needed > b->max_line_size) {
|
2011-06-22 19:17:38 -04:00
|
|
|
b->ret = -ERANGE;
|
|
|
|
goto cleanup;
|
2010-12-14 23:26:23 -05:00
|
|
|
}
|
|
|
|
if(needed > b->line_size) {
|
|
|
|
/* need to realloc + copy data to fit total length */
|
|
|
|
char *new;
|
2011-06-22 19:17:38 -04:00
|
|
|
CALLOC(new, needed, sizeof(char), b->ret = -ENOMEM; goto cleanup);
|
2010-12-14 23:26:23 -05:00
|
|
|
memcpy(new, b->line, b->line_size);
|
|
|
|
b->line_size = needed;
|
|
|
|
b->line_offset = new + (b->line_offset - b->line);
|
|
|
|
free(b->line);
|
|
|
|
b->line = new;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(done) {
|
2011-01-07 22:06:06 -05:00
|
|
|
size_t len = (size_t)(i - b->block_offset);
|
2010-12-14 23:26:23 -05:00
|
|
|
memcpy(b->line_offset, b->block_offset, len);
|
|
|
|
b->line_offset[len] = '\0';
|
|
|
|
b->block_offset = ++i;
|
|
|
|
/* this is the main return point; from here you can read b->line */
|
2011-03-20 20:45:57 -04:00
|
|
|
return ARCHIVE_OK;
|
2010-12-14 23:26:23 -05:00
|
|
|
} else {
|
|
|
|
/* we've looked through the whole block but no newline, copy it */
|
2011-01-07 22:06:06 -05:00
|
|
|
size_t len = (size_t)(b->block + b->block_size - b->block_offset);
|
2010-12-14 23:26:23 -05:00
|
|
|
memcpy(b->line_offset, b->block_offset, len);
|
|
|
|
b->line_offset += len;
|
|
|
|
b->block_offset = i;
|
2011-06-22 19:17:38 -04:00
|
|
|
/* there was no new data, return what is left; saved ARCHIVE_EOF will be
|
|
|
|
* returned on next call */
|
|
|
|
if(len == 0) {
|
|
|
|
b->line_offset[0] = '\0';
|
|
|
|
return ARCHIVE_OK;
|
|
|
|
}
|
2010-12-14 23:26:23 -05:00
|
|
|
}
|
|
|
|
}
|
2008-03-25 22:23:14 -04:00
|
|
|
|
2010-12-14 23:26:23 -05:00
|
|
|
cleanup:
|
|
|
|
{
|
|
|
|
int ret = b->ret;
|
|
|
|
FREE(b->line);
|
|
|
|
memset(b, 0, sizeof(b));
|
2011-03-20 20:45:57 -04:00
|
|
|
return ret;
|
2010-12-14 23:26:23 -05:00
|
|
|
}
|
2008-03-25 22:23:14 -04:00
|
|
|
}
|
|
|
|
|
2010-10-27 02:41:01 -04:00
|
|
|
int _alpm_splitname(const char *target, char **name, char **version,
|
|
|
|
unsigned long *name_hash)
|
2010-10-11 00:05:07 -04:00
|
|
|
{
|
|
|
|
/* the format of a db entry is as follows:
|
|
|
|
* package-version-rel/
|
2010-10-27 02:41:01 -04:00
|
|
|
* package-version-rel/desc (we ignore the filename portion)
|
2010-10-11 00:05:07 -04:00
|
|
|
* package name can contain hyphens, so parse from the back- go back
|
|
|
|
* two hyphens and we have split the version from the name.
|
|
|
|
*/
|
2010-10-27 02:41:01 -04:00
|
|
|
const char *pkgver, *end;
|
2010-10-11 00:05:07 -04:00
|
|
|
|
2010-10-27 02:41:01 -04:00
|
|
|
if(target == NULL) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return -1;
|
2010-10-11 00:05:07 -04:00
|
|
|
}
|
|
|
|
|
2010-10-27 02:41:01 -04:00
|
|
|
/* remove anything trailing a '/' */
|
|
|
|
end = strchr(target, '/');
|
|
|
|
if(!end) {
|
|
|
|
end = target + strlen(target);
|
2010-10-11 00:05:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* do the magic parsing- find the beginning of the version string
|
|
|
|
* by doing two iterations of same loop to lop off two hyphens */
|
2010-10-27 02:41:01 -04:00
|
|
|
for(pkgver = end - 1; *pkgver && *pkgver != '-'; pkgver--);
|
|
|
|
for(pkgver = pkgver - 1; *pkgver && *pkgver != '-'; pkgver--);
|
|
|
|
if(*pkgver != '-' || pkgver == target) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return -1;
|
2010-10-11 00:05:07 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* copy into fields and return */
|
2010-10-27 02:41:01 -04:00
|
|
|
if(version) {
|
|
|
|
if(*version) {
|
|
|
|
FREE(*version);
|
|
|
|
}
|
|
|
|
/* version actually points to the dash, so need to increment 1 and account
|
|
|
|
* for potential end character */
|
|
|
|
STRNDUP(*version, pkgver + 1, end - pkgver - 1, return -1);
|
2010-10-11 00:05:07 -04:00
|
|
|
}
|
2011-01-19 13:20:32 -05:00
|
|
|
|
2010-10-27 02:41:01 -04:00
|
|
|
if(name) {
|
|
|
|
if(*name) {
|
|
|
|
FREE(*name);
|
|
|
|
}
|
|
|
|
STRNDUP(*name, target, pkgver - target, return -1);
|
|
|
|
if(name_hash) {
|
|
|
|
*name_hash = _alpm_hash_sdbm(*name);
|
|
|
|
}
|
2010-10-11 00:05:07 -04:00
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return 0;
|
2010-10-11 00:05:07 -04:00
|
|
|
}
|
|
|
|
|
2010-12-14 12:56:32 -05:00
|
|
|
/**
|
|
|
|
* Hash the given string to an unsigned long value.
|
|
|
|
* This is the standard sdbm hashing algorithm.
|
|
|
|
* @param str string to hash
|
|
|
|
* @return the hash value of the given string
|
|
|
|
*/
|
|
|
|
unsigned long _alpm_hash_sdbm(const char *str)
|
|
|
|
{
|
|
|
|
unsigned long hash = 0;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
if(!str) {
|
2011-03-20 20:45:57 -04:00
|
|
|
return hash;
|
2010-12-14 12:56:32 -05:00
|
|
|
}
|
|
|
|
while((c = *str++)) {
|
|
|
|
hash = c + (hash << 6) + (hash << 16) - hash;
|
|
|
|
}
|
|
|
|
|
2011-03-20 20:45:57 -04:00
|
|
|
return hash;
|
2010-12-14 12:56:32 -05:00
|
|
|
}
|
|
|
|
|
2011-01-07 21:35:43 -05:00
|
|
|
long _alpm_parsedate(const char *line)
|
|
|
|
{
|
|
|
|
if(isalpha((unsigned char)line[0])) {
|
|
|
|
/* initialize to null in case of failure */
|
|
|
|
struct tm tmp_tm = { 0 };
|
|
|
|
setlocale(LC_TIME, "C");
|
|
|
|
strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm);
|
|
|
|
setlocale(LC_TIME, "");
|
2011-03-20 20:45:57 -04:00
|
|
|
return mktime(&tmp_tm);
|
2011-01-07 21:35:43 -05:00
|
|
|
}
|
2011-03-20 20:45:57 -04:00
|
|
|
return atol(line);
|
2011-01-07 21:35:43 -05:00
|
|
|
}
|
|
|
|
|
2011-01-19 13:00:39 -05:00
|
|
|
#ifndef HAVE_STRNDUP
|
|
|
|
/* A quick and dirty implementation derived from glibc */
|
|
|
|
static size_t strnlen(const char *s, size_t max)
|
|
|
|
{
|
|
|
|
register const char *p;
|
|
|
|
for(p = s; *p && max--; ++p);
|
2011-03-20 20:45:57 -04:00
|
|
|
return (p - s);
|
2011-01-19 13:00:39 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
char *strndup(const char *s, size_t n)
|
|
|
|
{
|
|
|
|
size_t len = strnlen(s, n);
|
|
|
|
char *new = (char *) malloc(len + 1);
|
|
|
|
|
2011-04-20 20:45:16 -04:00
|
|
|
if(new == NULL)
|
2011-01-19 13:00:39 -05:00
|
|
|
return NULL;
|
|
|
|
|
|
|
|
new[len] = '\0';
|
2011-03-20 20:45:57 -04:00
|
|
|
return (char *)memcpy(new, s, len);
|
2011-01-19 13:00:39 -05:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-03-14 20:51:43 -05:00
|
|
|
/* vim: set ts=2 sw=2 noet: */
|