diff options
Diffstat (limited to 'lib/libalpm/util.c')
-rw-r--r-- | lib/libalpm/util.c | 258 |
1 files changed, 142 insertions, 116 deletions
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index fbb320ef..5070cb93 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -24,22 +24,17 @@ #include "config.h" -#include <stdio.h> #include <stdlib.h> -#include <stdarg.h> -#include <string.h> #include <unistd.h> #include <ctype.h> #include <dirent.h> -#include <fcntl.h> #include <time.h> #include <syslog.h> #include <errno.h> #include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> #include <sys/wait.h> #include <locale.h> /* setlocale */ +#include <fnmatch.h> /* libarchive */ #include <archive.h> @@ -131,48 +126,50 @@ int _alpm_makepath_mode(const char *path, mode_t mode) int _alpm_copyfile(const char *src, const char *dest) { - FILE *in, *out; - size_t len; char *buf; - int ret = 0; + int in, out, ret = 1; + ssize_t nread; + struct stat st; - in = fopen(src, "rb"); - if(in == NULL) { - return 1; - } - out = fopen(dest, "wb"); - if(out == NULL) { - fclose(in); - return 1; - } + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, ret = 1; goto cleanup); + OPEN(in, src, O_RDONLY); + do { + out = open(dest, O_WRONLY | O_CREAT, 0000); + } while(out == -1 && errno == EINTR); + if(in < 0 || out < 0) { + goto cleanup; + } - /* do the actual file copy */ - while((len = fread(buf, 1, ALPM_BUFFER_SIZE, in))) { - size_t nwritten = 0; - nwritten = fwrite(buf, 1, len, out); - if((nwritten != len) || ferror(out)) { - ret = -1; - goto cleanup; - } + if(fstat(in, &st) || fchmod(out, st.st_mode)) { + goto cleanup; } - /* chmod dest to permissions of src, as long as it is not a symlink */ - struct stat statbuf; - if(!stat(src, &statbuf)) { - if(! S_ISLNK(statbuf.st_mode)) { - fchmod(fileno(out), statbuf.st_mode); + /* do the actual file copy */ + while((nread = read(in, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + ssize_t nwrite = 0; + if(nread < 0) { + continue; } - } else { - /* stat was unsuccessful */ - ret = 1; + do { + nwrite = write(out, buf + nwrite, nread); + if(nwrite >= 0) { + nread -= nwrite; + } else if(errno != EINTR) { + goto cleanup; + } + } while(nread > 0); } + ret = 0; cleanup: - fclose(in); - fclose(out); free(buf); + if(in >= 0) { + CLOSE(in); + } + if(out >= 0) { + CLOSE(out); + } return ret; } @@ -295,9 +292,7 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, oldmask = umask(0022); /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -311,18 +306,11 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, } while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { - const struct stat *st; - const char *entryname; /* the name of the file in the archive */ + const char *entryname; + mode_t mode; - st = archive_entry_stat(entry); entryname = archive_entry_pathname(entry); - if(S_ISREG(st->st_mode)) { - archive_entry_set_perm(entry, 0644); - } else if(S_ISDIR(st->st_mode)) { - archive_entry_set_perm(entry, 0755); - } - /* If specific files were requested, skip entries that don't match. */ if(list) { char *entry_prefix = strdup(entryname); @@ -343,6 +331,13 @@ int _alpm_unpack(alpm_handle_t *handle, const char *archive, const char *prefix, } } + mode = archive_entry_mode(entry); + if(S_ISREG(mode)) { + archive_entry_set_perm(entry, 0644); + } else if(S_ISDIR(mode)) { + archive_entry_set_perm(entry, 0755); + } + /* Extract the archive entry. */ int readret = archive_read_extract(_archive, entry, 0); if(readret == ARCHIVE_WARN) { @@ -369,7 +364,7 @@ cleanup: _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } return ret; @@ -498,9 +493,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] int retval = 0; /* save the cwd so we can restore it later */ - do { - cwdfd = open(".", O_RDONLY); - } while(cwdfd == -1 && errno == EINTR); + OPEN(cwdfd, ".", O_RDONLY); if(cwdfd < 0) { _alpm_log(handle, ALPM_LOG_ERROR, _("could not get current working directory\n")); } @@ -534,12 +527,12 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] if(pid == 0) { /* this code runs for the child only (the actual chroot/exec) */ - close(1); - close(2); + 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]); + CLOSE(pipefd[0]); + CLOSE(pipefd[1]); /* use fprintf instead of _alpm_log to send output through the parent */ if(chroot(handle->root) != 0) { @@ -553,6 +546,7 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] } umask(0022); execv(path, argv); + /* execv only returns if there was an error */ fprintf(stderr, _("call to execv failed (%s)\n"), strerror(errno)); exit(1); } else { @@ -560,10 +554,10 @@ int _alpm_run_chroot(alpm_handle_t *handle, const char *path, char *const argv[] int status; FILE *pipe_file; - close(pipefd[1]); + CLOSE(pipefd[1]); pipe_file = fdopen(pipefd[0], "r"); if(pipe_file == NULL) { - close(pipefd[0]); + CLOSE(pipefd[0]); retval = 1; } else { while(!feof(pipe_file)) { @@ -605,7 +599,7 @@ cleanup: _alpm_log(handle, ALPM_LOG_ERROR, _("could not restore working directory (%s)\n"), strerror(errno)); } - close(cwdfd); + CLOSE(cwdfd); } return retval; @@ -741,49 +735,51 @@ int _alpm_lstat(const char *path, struct stat *buf) #ifdef HAVE_LIBSSL static int md5_file(const char *path, unsigned char output[16]) { - FILE *f; - size_t n; MD5_CTX ctx; unsigned char *buf; + ssize_t n; + int fd; - CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - if((f = fopen(path, "rb")) == NULL) { + OPEN(fd, path, O_RDONLY); + if(fd < 0) { free(buf); return 1; } MD5_Init(&ctx); - while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { + while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + if(n < 0) { + continue; + } MD5_Update(&ctx, buf, n); } - MD5_Final(output, &ctx); - - memset(&ctx, 0, sizeof(MD5_CTX)); + CLOSE(fd); free(buf); - if(ferror(f) != 0) { - fclose(f); + if(n < 0) { return 2; } - fclose(f); + MD5_Final(output, &ctx); return 0; } /* third param is so we match the PolarSSL definition */ static int sha2_file(const char *path, unsigned char output[32], int is224) { - FILE *f; - size_t n; SHA256_CTX ctx; unsigned char *buf; + ssize_t n; + int fd; - CALLOC(buf, ALPM_BUFFER_SIZE, sizeof(unsigned char), return 1); + MALLOC(buf, (size_t)ALPM_BUFFER_SIZE, return 1); - if((f = fopen(path, "rb")) == NULL) { + OPEN(fd, path, O_RDONLY); + if(fd < 0) { free(buf); return 1; } @@ -794,7 +790,10 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) SHA256_Init(&ctx); } - while((n = fread(buf, 1, ALPM_BUFFER_SIZE, f)) > 0) { + while((n = read(fd, buf, ALPM_BUFFER_SIZE)) > 0 || errno == EINTR) { + if(n < 0) { + continue; + } if(is224) { SHA224_Update(&ctx, buf, n); } else { @@ -802,25 +801,24 @@ static int sha2_file(const char *path, unsigned char output[32], int is224) } } - if(is224) { - SHA224_Final(output, &ctx); - } else { - SHA256_Final(output, &ctx); - } - - memset(&ctx, 0, sizeof(SHA256_CTX)); + CLOSE(fd); free(buf); - if(ferror(f) != 0) { - fclose(f); + if(n < 0) { return 2; } - fclose(f); + if(is224) { + SHA224_Final(output, &ctx); + } else { + SHA256_Final(output, &ctx); + } return 0; } #endif +static const char *hex_digits = "0123456789abcdef"; + /** Get the md5 sum of file. * @param filename name of the file * @return the checksum on success, NULL on error @@ -834,8 +832,7 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename) ASSERT(filename != NULL, return NULL); - /* allocate 32 chars plus 1 for null */ - CALLOC(md5sum, 33, sizeof(char), return NULL); + MALLOC(md5sum, (size_t)33, return NULL); /* defined above for OpenSSL, otherwise defined in md5.h */ ret = md5_file(filename, output); @@ -846,10 +843,12 @@ char SYMEXPORT *alpm_compute_md5sum(const char *filename) /* 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]); + int pos = i * 2; + /* high 4 bits are first digit, low 4 are second */ + md5sum[pos] = hex_digits[output[i] >> 4]; + md5sum[pos + 1] = hex_digits[output[i] & 0x0f]; } - + md5sum[32] = '\0'; return md5sum; } @@ -866,8 +865,7 @@ char SYMEXPORT *alpm_compute_sha256sum(const char *filename) ASSERT(filename != NULL, return NULL); - /* allocate 64 chars plus 1 for null */ - CALLOC(sha256sum, 65, sizeof(char), return NULL); + MALLOC(sha256sum, (size_t)65, return NULL); /* defined above for OpenSSL, otherwise defined in sha2.h */ ret = sha2_file(filename, output, 0); @@ -878,10 +876,12 @@ char SYMEXPORT *alpm_compute_sha256sum(const char *filename) /* Convert the result to something readable */ for (i = 0; i < 32; i++) { - /* sprintf is acceptable here because we know our output */ - sprintf(sha256sum +(i * 2), "%02x", output[i]); + int pos = i * 2; + /* high 4 bits are first digit, low 4 are second */ + sha256sum[pos] = hex_digits[output[i] >> 4]; + sha256sum[pos + 1] = hex_digits[output[i] & 0x0f]; } - + sha256sum[64] = '\0'; return sha256sum; } @@ -914,16 +914,16 @@ int _alpm_test_checksum(const char *filepath, const char *expected, /* Note: does NOT handle sparse files on purpose for speed. */ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) { - char *i = NULL; - int64_t offset; - int done = 0; - /* ensure we start populating our line buffer at the beginning */ b->line_offset = b->line; while(1) { + size_t block_remaining; + char *eol; + /* have we processed this entire block? */ if(b->block + b->block_size == b->block_offset) { + int64_t offset; if(b->ret == ARCHIVE_EOF) { /* reached end of archive on the last read, now we are out of data */ goto cleanup; @@ -933,20 +933,20 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) b->ret = archive_read_data_block(a, (void *)&b->block, &b->block_size, &offset); b->block_offset = b->block; + block_remaining = b->block_size; /* error, cleanup */ if(b->ret < ARCHIVE_OK) { goto cleanup; } + } else { + block_remaining = b->block + b->block_size - b->block_offset; } - /* 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; - } + /* look through the block looking for EOL characters */ + eol = memchr(b->block_offset, '\n', block_remaining); + if(!eol) { + eol = memchr(b->block_offset, '\0', block_remaining); } /* allocate our buffer, or ensure our existing one is big enough */ @@ -956,8 +956,10 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) b->line_size = b->block_size + 1; b->line_offset = b->line; } else { - size_t needed = (size_t)((b->line_offset - b->line) - + (i - b->block_offset) + 1); + /* note: we know eol > b->block_offset and b->line_offset > b->line, + * so we know the result is unsigned and can fit in size_t */ + size_t new = eol ? (size_t)(eol - b->block_offset) : block_remaining; + size_t needed = (size_t)((b->line_offset - b->line) + new + 1); if(needed > b->max_line_size) { b->ret = -ERANGE; goto cleanup; @@ -974,11 +976,11 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) } } - if(done) { - size_t len = (size_t)(i - b->block_offset); + if(eol) { + size_t len = (size_t)(eol - b->block_offset); memcpy(b->line_offset, b->block_offset, len); b->line_offset[len] = '\0'; - b->block_offset = ++i; + b->block_offset = eol + 1; /* this is the main return point; from here you can read b->line */ return ARCHIVE_OK; } else { @@ -986,7 +988,7 @@ int _alpm_archive_fgets(struct archive *a, struct archive_read_buffer *b) size_t len = (size_t)(b->block + b->block_size - b->block_offset); memcpy(b->line_offset, b->block_offset, len); b->line_offset += len; - b->block_offset = i; + b->block_offset = b->block + b->block_size; /* there was no new data, return what is left; saved ARCHIVE_EOF will be * returned on next call */ if(len == 0) { @@ -1103,8 +1105,12 @@ off_t _alpm_strtoofft(const char *line) return (off_t)result; } -time_t _alpm_parsedate(const char *line) +alpm_time_t _alpm_parsedate(const char *line) { + char *end; + long long result; + errno = 0; + if(isalpha((unsigned char)line[0])) { /* initialize to null in case of failure */ struct tm tmp_tm; @@ -1112,9 +1118,24 @@ time_t _alpm_parsedate(const char *line) setlocale(LC_TIME, "C"); strptime(line, "%a %b %e %H:%M:%S %Y", &tmp_tm); setlocale(LC_TIME, ""); - return mktime(&tmp_tm); + return (alpm_time_t)mktime(&tmp_tm); + } + + result = strtoll(line, &end, 10); + if (result == 0 && end == line) { + /* line was not a number */ + errno = EINVAL; + return 0; + } else if (errno == ERANGE) { + /* line does not fit in long long */ + return 0; + } else if (*end) { + /* line began with a number but has junk left over at the end */ + errno = EINVAL; + return 0; } - return (time_t)atol(line); + + return (alpm_time_t)result; } /** @@ -1168,6 +1189,11 @@ int _alpm_access(alpm_handle_t *handle, const char *dir, const char *file, int a return ret; } +int _alpm_fnmatch(const void *pattern, const void *string) +{ + return fnmatch(pattern, string, 0); +} + #ifndef HAVE_STRNDUP /* A quick and dirty implementation derived from glibc */ static size_t strnlen(const char *s, size_t max) |