/pkginst/build.bat |
---|
0,0 → 1,33 |
@echo off |
if not exist tmp\nul mkdir tmp |
REM reuse FDNPKG code |
copy /y ..\crc32.c tmp\ |
copy /y ..\fileexst.c tmp\ |
copy /y ..\getdelim.c tmp\ |
copy /y ..\helpers.c tmp\ |
copy /y ..\inf.c tmp\ |
copy /y ..\libunzip.c tmp\ |
copy /y ..\loadconf.c tmp\ |
copy /y ..\lsm.c tmp\ |
copy /y ..\parsecmd.c tmp\ |
copy /y ..\pkginst.c tmp\ |
copy /y ..\pkgrem.c tmp\ |
copy /y ..\readenv.c tmp\ |
copy /y ..\rtrim.c tmp\ |
copy /y ..\showinst.c tmp\ |
REM add a few fdinst-specific things |
copy /y fdinst.c tmp\ |
copy /y kprintf0.c tmp\ |
wcl -0 -lr -ml -os -wx -we -d0 -i=..\ -i=..\zlib\ -DNOREPOS -DNOLZMA -fe=fdinst.exe tmp\*.c ..\zlib\zlib_l.lib |
if ERRORLEVEL 1 goto gameover |
del tmp\*.c |
rmdir tmp |
upx --8086 -9 fdinst.exe |
:gameover |
/pkginst/crc32.c |
---|
0,0 → 1,128 |
/* |
* $Id: crc32.c,v 1.1.1.1 1996/02/18 21:38:12 ylo Exp $ |
* $Log: crc32.c,v $ |
* Revision 1.1.1.1 1996/02/18 21:38:12 ylo |
* Imported ssh-1.2.13. |
* |
* Revision 1.2 1995/07/13 01:21:34 ylo |
* Added cvs log. |
* |
* $Endlog$ |
*/ |
/* The implementation here was originally done by Gary S. Brown. I have |
borrowed the tables directly, and made some minor changes to the |
crc32-function (including changing the interface). */ |
#include "crc32.h" |
/* ============================================================= */ |
/* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or */ |
/* code or tables extracted from it, as desired without restriction. */ |
/* */ |
/* First, the polynomial itself and its table of feedback terms. The */ |
/* polynomial is */ |
/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ |
/* */ |
/* Note that we take it "backwards" and put the highest-order term in */ |
/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ |
/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ |
/* the MSB being 1. */ |
/* */ |
/* Note that the usual hardware shift register implementation, which */ |
/* is what we're using (we're merely optimizing it by doing eight-bit */ |
/* chunks at a time) shifts bits into the lowest-order term. In our */ |
/* implementation, that means shifting towards the right. Why do we */ |
/* do it this way? Because the calculated CRC must be transmitted in */ |
/* order from highest-order term to lowest-order term. UARTs transmit */ |
/* characters in order from LSB to MSB. By storing the CRC this way, */ |
/* we hand it to the UART in the order low-byte to high-byte; the UART */ |
/* sends each low-bit to hight-bit; and the result is transmission bit */ |
/* by bit from highest- to lowest-order term without requiring any bit */ |
/* shuffling on our part. Reception works similarly. */ |
/* */ |
/* The feedback terms table consists of 256, 32-bit entries. Notes: */ |
/* */ |
/* The table can be generated at runtime if desired; code to do so */ |
/* is shown later. It might not be obvious, but the feedback */ |
/* terms simply represent the results of eight shift/xor opera- */ |
/* tions for all combinations of data and CRC register values. */ |
/* */ |
/* The values must be right-shifted by eight bits by the "updcrc" */ |
/* logic; the shift must be unsigned (bring in zeroes). On some */ |
/* hardware you could probably optimize the shift in assembler by */ |
/* using byte-swap instructions. */ |
/* polynomial $edb88320 */ |
/* */ |
/* -------------------------------------------------------------------- */ |
const unsigned long crc32_tab[256] = { |
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, |
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, |
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, |
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, |
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, |
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, |
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, |
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, |
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, |
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, |
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, |
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, |
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, |
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, |
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, |
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, |
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, |
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, |
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, |
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, |
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, |
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, |
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, |
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, |
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, |
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, |
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, |
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, |
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, |
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, |
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, |
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, |
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, |
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, |
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, |
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, |
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, |
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, |
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, |
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, |
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, |
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, |
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, |
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, |
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, |
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, |
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, |
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, |
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, |
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, |
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, |
0x2d02ef8dL |
}; |
/* Return a 32-bit CRC of the contents of the buffer. */ |
unsigned long crc32_init(void) { |
return(0xFFFFFFFFlu); |
} |
void crc32_feed(unsigned long *crc32val, const unsigned char *s, unsigned int len) { |
unsigned long i; |
for (i = 0; i < len; i++) *crc32val = crc32_tab[(*crc32val ^ s[i]) & 0xff] ^ (*crc32val >> 8); |
} |
void crc32_finish(unsigned long *crc32val) { |
*crc32val ^= 0xFFFFFFFFlu; |
} |
/pkginst/crc32.h |
---|
0,0 → 1,25 |
/* |
* $Id: crc32.h,v 1.1.1.1 1996/02/18 21:38:11 ylo Exp $ |
* $Log: crc32.h,v $ |
* Revision 1.1.1.1 1996/02/18 21:38:11 ylo |
* Imported ssh-1.2.13. |
* |
* Revision 1.2 1995/07/13 01:21:45 ylo |
* Removed "Last modified" header. |
* Added cvs log. |
* |
* $Endlog$ |
*/ |
#ifndef CRC32_H_SENTINEL |
#define CRC32_H_SENTINEL |
unsigned long crc32_init(void); |
/* This computes a 32 bit CRC of the data in the buffer, and returns the |
CRC. The polynomial used is 0xedb88320. */ |
void crc32_feed(unsigned long *crc32val, const unsigned char *buf, unsigned int len); |
void crc32_finish(unsigned long *crc32val); |
#endif /* CRC32_H_SENTINEL */ |
/pkginst/fdinst.c |
---|
0,0 → 1,174 |
/* |
* FDINST - lightweigth FreeDOS package installer |
* Copyright (C) 2015-2017 Mateusz Viste |
* |
* Permission is hereby granted, free of charge, to any person obtaining a |
* copy of this software and associated documentation files (the "Software"), |
* to deal in the Software without restriction, including without limitation |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
* and/or sell copies of the Software, and to permit persons to whom the |
* Software is furnished to do so, subject to the following conditions: |
* |
* The above copyright notice and this permission notice shall be included in |
* all copies or substantial portions of the Software. |
* |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
* IN THE SOFTWARE. |
*/ |
#include <stdio.h> /* printf() */ |
#include <stdlib.h> /* malloc() and friends */ |
#include <string.h> /* strcasecmp() */ |
#include "libunzip.h" |
#include "pkginst.h" |
#include "pkgrem.h" |
#include "readenv.h" |
#include "version.h" |
enum ACTIONTYPES { |
ACTION_INSTALL, |
ACTION_REMOVE, |
ACTION_HELP |
}; |
static int showhelp(void) { |
printf("FDINST v" PVER " Copyright (C) " PDATE " Mateusz Viste\n" |
"\n" |
"FDINST is a lightweigth package installer for FreeDOS. It is an alternative\n" |
"to FDNPKG, when only basic, local install/remove actions are necessary. FDINST\n" |
"is a 16-bit, 8086-compatible application running in real mode.\n" |
"\n" |
"Usage: FDINST install package.zip\n" |
" FDINST remove package\n" |
"\n" |
"FDINST is published under the MIT license, and shares most of its source code\n" |
"with FDNPKG to guarantee consistent behaviour of both tools. It also uses\n" |
"FDNPKG's configuration file.\n" |
); |
return(1); |
} |
static enum ACTIONTYPES parsearg(int argc, char **argv) { |
int extpos, i; |
enum ACTIONTYPES res = ACTION_HELP; |
/* I expect exactly 2 arguments (ie argc == 3) */ |
if (argc != 3) return(ACTION_HELP); |
/* look for valid actions */ |
if (strcasecmp(argv[1], "install") == 0) { |
res = ACTION_INSTALL; |
} else if (strcasecmp(argv[1], "remove") == 0) { |
res = ACTION_REMOVE; |
} |
/* the argument should never be empty */ |
if (argv[2][0] == 0) return(ACTION_INSTALL); |
/* for 'install', validate that the extension is '.zip' */ |
if (res == ACTION_INSTALL) { |
/* find where the file's extension starts */ |
extpos = 0; |
for (i = 0; argv[2][i] != 0; i++) { |
if (argv[2][i] == '.') extpos = i + 1; |
} |
if (extpos == 0) return(ACTION_HELP); |
} |
/* return the result */ |
return(res); |
} |
static int pkginst(char *file, int flags, char *dosdir, char *tempdir, struct customdirs *dirlist, char *mapdrv) { |
char pkgname[32]; |
int t, lastpathdelim = -1, u = 0; |
char *buffmem1k; |
struct ziplist *zipfileidx; |
FILE *zipfilefd; |
for (t = 0; file[t] != 0; t++) { |
if ((file[t] == '/') || (file[t] == '\\')) lastpathdelim = t; |
} |
/* copy the filename into pkgname (without path elements) */ |
for (t = lastpathdelim + 1; file[t] != 0; t++) pkgname[u++] = file[t]; |
pkgname[u] = 0; /* terminate the string */ |
/* truncate the file's extension (.zip) */ |
for (t = u; t > 0; t--) { |
if (pkgname[t] == '.') { |
pkgname[t] = 0; |
break; |
} |
} |
/* allocate some memory for pkginst_preparepackage() to do its job */ |
buffmem1k = malloc(1024); |
if (buffmem1k == NULL) { |
puts("ERROR: Out of memory"); |
return(1); |
} |
/* prepare the zip file and install it */ |
zipfileidx = pkginstall_preparepackage(NULL, pkgname, tempdir, file, flags, NULL, &zipfilefd, NULL, 0, NULL, dosdir, dirlist, buffmem1k, mapdrv); |
free(buffmem1k); |
if (zipfileidx != NULL) { |
int res = 0; |
if (pkginstall_installpackage(pkgname, dosdir, dirlist, zipfileidx, zipfilefd, mapdrv) != 0) res = 1; |
fclose(zipfilefd); |
return(res); |
} else { |
fclose(zipfilefd); |
return(1); |
} |
} |
int main(int argc, char **argv) { |
int res, flags; |
enum ACTIONTYPES action; |
char *dosdir, *tempdir, *cfgfile; |
struct customdirs *dirlist; |
char *mapdrv = ""; |
action = parsearg(argc, argv); |
if (action == ACTION_HELP) return(showhelp()); |
/* allocate some bits for cfg file's location */ |
cfgfile = malloc(256); |
if (cfgfile == NULL) { |
puts("ERROR: Out of memory"); |
return(1); |
} |
/* read all necessary environment variables */ |
if (readenv(&dosdir, &tempdir, cfgfile, 256) != 0) { |
free(cfgfile); |
return(1); |
} |
/* load configuration */ |
flags = 0; |
dirlist = NULL; |
if (loadconf(cfgfile, NULL, 0, NULL, NULL, &dirlist, &flags, NULL, NULL, &mapdrv) < 0) return(5); |
/* free the cfgfile buffer, I won't need the config file's location any more */ |
free(cfgfile); |
cfgfile = NULL; |
switch (action) { |
case ACTION_INSTALL: |
res = pkginst(argv[2], flags, dosdir, tempdir, dirlist, mapdrv); |
break; |
case ACTION_REMOVE: |
res = pkgrem(argv[2], dosdir, mapdrv); |
break; |
default: |
res = showhelp(); |
break; |
} |
if (res != 0) return(1); |
return(0); |
} |
/pkginst/fileexst.c |
---|
0,0 → 1,19 |
/* |
* fileexists checks whether a file exists or not. |
* returns 0 if file not found, non-zero otherwise. |
*/ |
#include <stdio.h> |
#include "fileexst.h" |
#include "version.h" |
int fileexists(char *filename) { |
FILE *fd; |
fd = fopen(filename, "rb"); |
if (fd != NULL) { /* file exists */ |
fclose(fd); |
return(1); |
} else { |
return(0); |
} |
} |
/pkginst/fileexst.h |
---|
0,0 → 1,11 |
/* |
* fileexists checks whether a file exists or not. |
* returns 0 if file not found, non-zero otherwise. |
*/ |
#ifndef fileexists_sentinel |
#define fileexists_sentinel |
int fileexists(char *filename); |
#endif |
/pkginst/getdelim.c |
---|
0,0 → 1,116 |
/* getdelim.c --- Implementation of replacement getdelim function. |
Copyright (C) 1994, 1996, 1997, 1998, 2001, 2003, 2005 Free |
Software Foundation, Inc. |
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, 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 |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
02110-1301, USA. */ |
/* Ported from glibc by Simon Josefsson. */ |
#ifdef HAVE_CONFIG_H |
# include <config.h> |
#endif |
#include "getdelim.h" |
#include <limits.h> |
#include <stdlib.h> |
#include <errno.h> |
#ifndef SIZE_MAX |
# define SIZE_MAX ((size_t) -1) |
#endif |
#ifndef SSIZE_MAX |
# define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2)) |
#endif |
#if !HAVE_FLOCKFILE |
# undef flockfile |
# define flockfile(x) ((void) 0) |
#endif |
#if !HAVE_FUNLOCKFILE |
# undef funlockfile |
# define funlockfile(x) ((void) 0) |
#endif |
/* Read up to (and including) a DELIMITER from FP into *LINEPTR (and |
NUL-terminate it). *LINEPTR is a pointer returned from malloc (or |
NULL), pointing to *N characters of space. It is realloc'ed as |
necessary. Returns the number of characters read (not including |
the null terminator), or -1 on error or EOF. */ |
ssize_t getdelim(char **lineptr, size_t *n, int delimiter, FILE *fp) { |
ssize_t result; |
size_t cur_len = 0; |
if ((lineptr == NULL) || (n == NULL) || (fp == NULL)) { |
errno = EINVAL; |
return(-1); |
} |
flockfile (fp); |
if ((*lineptr == NULL) || (*n == 0)) { |
*n = 120; |
*lineptr = (char *)malloc(*n); |
if (*lineptr == NULL) { |
result = -1; |
goto unlock_return; |
} |
} |
for (;;) { |
int i; |
i = getc(fp); |
if (i == EOF) { |
result = -1; |
break; |
} |
/* Make enough space for len+1 (for final NUL) bytes. */ |
if (cur_len + 1 >= *n) { |
size_t needed_max = SSIZE_MAX < SIZE_MAX ? (size_t) SSIZE_MAX + 1 : SIZE_MAX; |
size_t needed = 2 * *n + 1; /* Be generous. */ |
char *new_lineptr; |
if (needed_max < needed) needed = needed_max; |
if (cur_len + 1 >= needed) { |
result = -1; |
goto unlock_return; |
} |
new_lineptr = (char *) realloc (*lineptr, needed); |
if (new_lineptr == NULL) { |
result = -1; |
goto unlock_return; |
} |
*lineptr = new_lineptr; |
*n = needed; |
} |
(*lineptr)[cur_len] = i; |
cur_len++; |
if (i == delimiter) break; |
} |
(*lineptr)[cur_len] = '\0'; |
if (cur_len != 0) result = cur_len; |
/* result = cur_len ? cur_len : result; */ /* this one have been replaced by the line above for reading simplicity */ |
unlock_return: |
funlockfile(fp); |
return(result); |
} |
/pkginst/getdelim.h |
---|
0,0 → 1,28 |
/* getdelim.h --- Prototype for replacement getdelim function. |
Copyright (C) 2005 Free Software Foundation, Inc. |
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, 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 |
along with this program; if not, write to the Free Software |
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
02110-1301, USA. */ |
/* Written by Simon Josefsson. */ |
/* Get size_t, FILE, ssize_t. And getdelim, if available. */ |
# include <stddef.h> |
# include <stdio.h> |
# include <sys/types.h> |
#if !HAVE_DECL_GETDELIM |
ssize_t getdelim (char **lineptr, size_t *n, int delimiter, FILE *stream); |
#endif /* !HAVE_GETDELIM */ |
/pkginst/helpers.c |
---|
0,0 → 1,287 |
/* |
* This file is part of fdnpkg |
* Copyright (C) 2012-2017 Mateusz Viste |
* |
* It contains a few helper function... |
*/ |
#include <ctype.h> /* tolower() */ |
#include <string.h> /* */ |
#include <stdio.h> /* sprintf() */ |
#include <stdlib.h> /* atoi() */ |
#include <sys/stat.h> /* mkdir() */ |
#include "version.h" |
#ifdef __WATCOMC__ |
#include <direct.h> /* provides the mkdir() prototype */ |
#define MAKEDIR(x) mkdir(x); |
#else |
#define MAKEDIR(x) mkdir(x, S_IWUSR); /* S_IWUSR is to make the directory READONLY bit NOT set */ |
#endif |
#include "helpers.h" |
/* translates a version string into a array of integer values. The array must be 8-position long. |
returns 0 if parsing was successful, non-zero otherwise. |
Accepted formats follow: |
300.12.1 |
1 |
12.2.34.2-4.5 |
1.2c |
1.01 |
2013-12-31 */ |
static int versiontointarr(char *verstr, int *arr) { |
int i, vlen, dotcounter = 1, firstcharaftersep = 0; |
char *digits[8]; |
char verstrcopy[16]; |
/* fill the array with zeroes first */ |
for (i = 0; i < 8; i++) arr[i] = 0; |
/* first extensively validate the input */ |
if (verstr == NULL) return(-1); |
vlen = strlen(verstr); |
if (vlen == 0) return(-1); |
if (vlen > 15) return(-1); |
if ((verstr[0] < '0') || (verstr[0] > '9')) return(-1); /* a version string must start with a 0..9 digit */ |
if ((tolower(verstr[vlen - 1]) >= 'a') && (tolower(verstr[vlen - 1]) <= 'z') && (vlen > 1)) { /* remove any letter from the end, and use it as a (very) minor differenciator */ |
vlen -= 1; |
arr[7] = tolower(verstr[vlen]); |
} |
if ((verstr[vlen - 1] < '0') || (verstr[vlen - 1] > '9')) return(-1); /* a version string must end with a 0..9 digit */ |
digits[0] = verstrcopy; |
for (i = 0; i < vlen; i++) { |
verstrcopy[i] = verstr[i]; |
switch (verstr[i]) { |
case '.': |
case '-': |
if (i == 0) return(-1); |
if (verstrcopy[i-1] == 0) return(-1); /* do not allow two separators in a row */ |
if (dotcounter > 6) return(-1); |
digits[dotcounter++] = &verstrcopy[i + 1]; |
verstrcopy[i] = 0; |
firstcharaftersep = 1; |
break; |
case '0': |
/* if this is a zero right after a separator, and trailed with a digit |
* (as in '1.01'), then enforce a separator first */ |
if ((firstcharaftersep != 0) && (verstr[i+1] >= '0') && (verstr[i+1] <= '9')) { |
if (dotcounter > 6) return(-1); |
digits[dotcounter++] = &verstrcopy[i + 1]; |
verstrcopy[i] = 0; |
} |
break; |
case '1': |
case '2': |
case '3': |
case '4': |
case '5': |
case '6': |
case '7': |
case '8': |
case '9': |
firstcharaftersep = 0; |
break; |
default: /* do not allow any character different than 0..9 or '.' */ |
return(-1); |
break; |
} |
} |
verstrcopy[i] = 0; |
/* now that we know the input is sane, let's process it */ |
for (i = 0; i < dotcounter; i++) { |
int tmpint; |
tmpint = atoi(digits[i]); |
if ((tmpint < 0) || (tmpint > 32000)) return(-1); |
arr[i] = tmpint; |
} |
return(0); |
} |
/* compares version strings v1 and v2. Returns 1 if v2 is newer than v1, 0 otherwise, and -1 if comparison is unable to tell */ |
int isversionnewer(char *v1, char *v2) { |
int x1[8], x2[8], i; |
if ((v1 == NULL) || (v2 == NULL)) return(-1); /* if input is invalid (NULL), don't continue */ |
if (strcasecmp(v1, v2) == 0) return(0); /* if both versions are the same, don't continue */ |
/* check versions of the decimal format 1.23... */ |
if ((versiontointarr(v1, x1) != 0) || (versiontointarr(v2, x2) != 0)) return(-1); |
for (i = 0; i < 8; i++) { |
if (x2[i] > x1[i]) return(1); |
if (x2[i] < x1[i]) return(0); |
} |
return(0); |
} |
/* change all / to \ in a string */ |
void slash2backslash(char *str) { |
int x; |
for (x = 0; str[x] != 0; x++) { |
if (str[x] == '/') str[x] = '\\'; |
} |
} |
/* change all \ to / in a string */ |
void backslash2slash(char *str) { |
int x; |
for (x = 0; str[x] != 0; x++) { |
if (str[x] == '\\') str[x] = '/'; |
} |
} |
void removeDoubleBackslashes(char *str) { |
char *curpos; |
int x; |
for (;;) { |
curpos = fdnpkg_strcasestr(str, "\\\\"); |
if (curpos == NULL) return; /* job done */ |
for (x = 1; curpos[x] != 0; x++) { |
curpos[x - 1] = curpos[x]; |
} |
curpos[x - 1] = 0; |
} |
} |
/* converts a string to all lowercase */ |
void strtolower(char *mystring) { |
int x; |
for (x = 0; mystring[x] != 0; x++) mystring[x] = tolower(mystring[x]); |
} |
/* Find the first occurrence of find in s, ignore case. */ |
char *fdnpkg_strcasestr(const char *s, const char *find) { |
char c, sc; |
size_t len; |
if ((c = *find++) != 0) { |
c = tolower((unsigned char)c); |
len = strlen(find); |
do { |
do { |
if ((sc = *s++) == 0) return(NULL); |
} while ((char)tolower((unsigned char)sc) != c); |
} while (strncasecmp(s, find, len) != 0); |
s--; |
} |
return((char *)s); |
} |
/* Creates directories recursively */ |
void mkpath(char *dirs) { |
int x; |
char savechar; |
for (x = 0; dirs[x] != 0; x++) { |
if (((dirs[x] == '/') || (dirs[x] == '\\')) && (x > 0)) { |
if (dirs[x - 1] != ':') { /* avoid d:\ stuff */ |
savechar = dirs[x]; |
dirs[x] = 0; |
/* make the dir */ |
MAKEDIR(dirs); |
dirs[x] = savechar; |
} |
} |
} |
} |
/* remap drive, if needed (hack for situations where fdinst is used to |
* install an OS to a drive that will change its letter post-install) */ |
void mapdrives(char *s, char *mapdrv) { |
int i = 0; |
if (mapdrv == NULL) return; |
if ((s == NULL) || (s[0] == 0) || (s[1] != ':')) return; |
while (mapdrv[i] != 0) { |
if (toupper(mapdrv[i]) == toupper(s[0])) { |
s[0] = toupper(mapdrv[i + 1]); |
return; |
} |
i += 2; |
} |
} |
/* */ |
void unmapdrives(char *s, char *mapdrv) { |
int i = 0; |
if (mapdrv == NULL) return; |
if ((s == NULL) || (s[0] == 0) || (s[1] != ':')) return; |
while (mapdrv[i] != 0) { |
if (toupper(mapdrv[i + 1]) == toupper(s[0])) { |
s[0] = toupper(mapdrv[i]); |
return; |
} |
i += 2; |
} |
} |
/* returns a pointer to the start of the filename, out of a path\to\file string, and |
fills respath with the local folder where the file should be placed. */ |
char *computelocalpath(char *longfilename, char *respath, char *dosdir, struct customdirs *dirlist) { |
int x, lastsep = 0, firstsep = -1; |
char savedchar; |
char *shortfilename, *pathstart; |
pathstart = longfilename; |
for (x = 0; longfilename[x] != 0; x++) { |
if ((longfilename[x] == '/') || (longfilename[x] == '\\')) { |
lastsep = x; |
if (firstsep < 0) firstsep = x; |
} |
} |
shortfilename = &longfilename[lastsep + 1]; |
/* look for possible custom path */ |
if (firstsep > 0) { |
savedchar = longfilename[firstsep]; |
longfilename[firstsep] = 0; |
for (; dirlist != NULL; dirlist = dirlist->next) { |
if (fdnpkg_strcasestr(longfilename, dirlist->name) == longfilename) { /* found! */ |
/* sprintf(respath, "%s\\%s", dirlist->location, &longfilename[firstsep + 1]); */ |
pathstart = &longfilename[firstsep + 1]; |
dosdir = dirlist->location; |
break; |
} |
} |
longfilename[firstsep] = savedchar; /* restore longfilename as it was */ |
} |
/* apply the default (DOSDIR) path */ |
savedchar = longfilename[lastsep + 1]; |
longfilename[lastsep + 1] = 0; |
sprintf(respath, "%s\\%s", dosdir, pathstart); |
slash2backslash(respath); |
removeDoubleBackslashes(respath); |
longfilename[lastsep + 1] = savedchar; |
return(shortfilename); |
} |
/* detect local paths (eg. C:\REPO). Returns 1 if the url looks like a local path, zero otherwise. */ |
int detect_localpath(char *url) { |
if (url[0] != 0) { |
if (url[1] != 0) { |
if ((url[1] == ':') && ((url[2] == '\\') || (url[2] == '/'))) return(1); |
} |
} |
return(0); |
} |
/* analyzes a filename string and returns the pointer to the file's extension |
* (which can be empty) */ |
char *getfext(char *fname) { |
char *res = NULL; |
for (; *fname != 0; fname++) { |
if (*fname == '.') res = fname + 1; |
} |
/* if no dot found, then point to the string's null terminator */ |
if (res == NULL) return(fname); |
return(res); |
} |
/pkginst/helpers.h |
---|
0,0 → 1,23 |
/* |
* This file is part of fdnpkg |
* Copyright (C) 2012-2017 Mateusz Viste |
* |
* It contains a few helper function... |
*/ |
#ifndef helpers_sentinel |
#define helpers_sentinel |
#include "loadconf.h" /* required for the customdirs struct */ |
int isversionnewer(char *v1, char *v2); |
void slash2backslash(char *str); |
void backslash2slash(char *str); |
void strtolower(char *mystring); |
char *fdnpkg_strcasestr(const char *s, const char *find); |
void mkpath(char *dirs); |
void mapdrives(char *s, char *mapdrv); |
void unmapdrives(char *s, char *mapdrv); |
char *computelocalpath(char *longfilename, char *respath, char *dosdir, struct customdirs *dirlist); |
void removeDoubleBackslashes(char *str); |
int detect_localpath(char *url); |
char *getfext(char *fname); |
#endif |
/pkginst/inf.c |
---|
0,0 → 1,85 |
/* This file is part of the FDNPKG project. It is an adaptation of the |
* "zpipe.c" example of zlib's inflate() and deflate() usage. |
* |
* Not copyrighted -- provided to the public domain |
* original version 1.4 11 December 2005 Mark Adler |
* adaptations for FDNPKG integration by Mateusz Viste, 2015 |
*/ |
#include <stdio.h> |
#include <string.h> |
#include "crc32.h" |
#include "zlib\zlib.h" |
#include "inf.h" |
#define CHUNK 16384 |
/* Decompress from file source to file dest until stream ends or EOF. |
* inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be allocated |
* for processing, Z_DATA_ERROR if the deflate data is invalid or incomplete, |
* Z_VERSION_ERROR if the version of zlib.h and the version of the library |
* linked do not match, or Z_ERRNO if there is an error reading or writing the |
* files. */ |
int inf(FILE *source, FILE *dest, unsigned char *buff32K, unsigned long *cksum, long streamlen) { |
int ret; |
unsigned int have; |
z_stream strm; |
unsigned char *in = buff32K; |
unsigned char *out = buff32K + CHUNK; |
/* allocate inflate state */ |
strm.zalloc = Z_NULL; |
strm.zfree = Z_NULL; |
strm.opaque = Z_NULL; |
strm.avail_in = 0; |
strm.next_in = Z_NULL; |
ret = inflateInit2(&strm, -15); /* according to the zlib doc, passing -15 to inflateInit2() means "this is a raw deflate stream" (as opposed to a zlib- or gz- wrapped stream) */ |
if (ret != Z_OK) return(ret); |
/* decompress until deflate stream ends or end of file */ |
do { |
strm.avail_in = fread(in, 1, (streamlen > CHUNK ? CHUNK : streamlen), source); |
if (ferror(source)) { |
(void)inflateEnd(&strm); |
return(Z_ERRNO); |
} |
streamlen -= strm.avail_in; |
if (strm.avail_in == 0) break; |
strm.next_in = in; |
/* run inflate() on input until output buffer not full */ |
do { |
strm.avail_out = CHUNK; |
strm.next_out = out; |
ret = inflate(&strm, Z_NO_FLUSH); |
switch (ret) { |
case Z_NEED_DICT: |
ret = Z_DATA_ERROR; /* and fall through */ |
case Z_DATA_ERROR: |
case Z_MEM_ERROR: |
(void)inflateEnd(&strm); |
return(ret); |
} |
have = CHUNK - strm.avail_out; |
if ((fwrite(out, 1, have, dest) != have) || (ferror(dest))) { |
(void)inflateEnd(&strm); |
return(Z_ERRNO); |
} |
/* feed the CRC32 */ |
crc32_feed(cksum, out, have); |
} while (strm.avail_out == 0); |
/* done when inflate() says it's done */ |
} while (ret != Z_STREAM_END); |
/* clean up and return */ |
(void)inflateEnd(&strm); |
if (Z_STREAM_END) { |
return(Z_OK); |
} else { |
return(Z_DATA_ERROR); |
} |
} |
/pkginst/inf.h |
---|
0,0 → 1,13 |
#ifndef INF_H |
#define INF_H |
/* Decompress from file source to file dest until stream ends or EOF. |
* inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be allocated |
* for processing, Z_DATA_ERROR if the deflate data is invalid or incomplete, |
* Z_VERSION_ERROR if the version of zlib.h and the version of the library |
* linked do not match, or Z_ERRNO if there is an error reading or writing the |
* files. */ |
int inf(FILE *source, FILE *dest, unsigned char *buff32k, unsigned long *cksum, long streamlen); |
#endif |
/pkginst/kprintf0.c |
---|
0,0 → 1,24 |
/* |
* This file provides dummy functions that simulate kitten-enabled routines |
* without actually having kitten. |
* |
* Copyright (C) 2015-2016 Mateusz Viste |
*/ |
#include <stdio.h> /* vprintf() */ |
#include <stdarg.h> /* va_list, va_start()... */ |
#include "kprintf.h" |
void kitten_printf(short x, short y, char *fmt, ...) { |
va_list args; |
va_start(args, fmt); |
vprintf(fmt, args); |
va_end(args); |
x = y; |
} |
void kitten_puts(short x, short y, char *fmt) { |
x = y; |
puts(fmt); |
} |
/pkginst/libunzip.c |
---|
0,0 → 1,358 |
/* |
* This file is part of the FDNPKG project |
* http://fdnpkg.sourceforge.net |
* |
* Copyright (C) 2012-2016 Mateusz Viste. All rights reserved. |
* |
* Simple library providing functions to unzip files from zip archives. |
*/ |
#include <stdio.h> /* printf(), FILE, fclose()... */ |
#include <stdlib.h> /* NULL */ |
#include <string.h> /* memset() */ |
#include <time.h> /* mktime() */ |
#include <utime.h> /* utime() */ |
#include <unistd.h> /* unlink() */ |
#include "crc32.h" |
#include "kprintf.h" |
#include "parsecmd.h" |
#ifndef NOLZMA |
#include "lzmadec.h" /* LZMA support */ |
#endif |
#include "inf.h" /* DEFLATE support */ |
#include "version.h" |
#include "libunzip.h" /* include self for control */ |
/* converts a "DOS format" timestamp into unix timestamp. The DOS timestamp is constructed an array of 4 bytes, that contains following data at the bit level: |
* HHHHHMMM MMMSSSSS YYYYYYYM MMMDDDDD |
* where: |
* day of month is always within 1-31 range; |
* month is always within 1-12 range; |
* year starts from 1980 and continues for 127 years |
* seconds are actually not 0-59 but rather 0-29 as there are only 32 possible values – to get actual seconds multiply this field by 2; |
* minutes are always within 0-59 range; |
* hours are always within 0-23 range. */ |
static time_t dostime2unix(unsigned char *buff) { |
struct tm curtime; |
time_t result; |
memset(&curtime, 0, sizeof(curtime)); /* make sure to set everything in curtime to 0's */ |
curtime.tm_sec = (buff[0] & 31) << 1; /* seconds (0..60) */ |
curtime.tm_min = (((buff[1] << 8) | buff[0]) >> 5) & 63 ; /* minutes after the hour (0..59) */ |
curtime.tm_hour = (buff[1] >> 3); /* hours since midnight (0..23) */ |
curtime.tm_mday = buff[2] & 31; /* day of the month (1..31) */ |
curtime.tm_mon = ((((buff[3] << 8) | buff[2]) >> 5) & 15) - 1; /* months since January (0, 11) */ |
curtime.tm_year = (buff[3] >> 1) + 80; /* years since 1900 */ |
curtime.tm_wday = 0; /* days since Sunday (0..6) - leave 0, mktime() will set it */ |
curtime.tm_yday = 0; /* days since January 1 (0..365]) - leave 0, mktime() will set it */ |
curtime.tm_isdst = -1; /* Daylight Saving Time flag. Positive if DST is in effect, zero if not and negative if no information is available */ |
result = mktime(&curtime); |
if (result == (time_t)-1) return(0); |
return(result); |
} |
#ifndef NOLZMA |
/* this is a wrapper on malloc(), used as a callback by lzmadec */ |
static void *SzAlloc(void *p, size_t size) { |
p = p; /* for gcc to not complain */ |
if (size == 0) return(0); |
return(malloc(size)); |
} |
/* this is a wrapper on free(), used as a callback by lzmadec */ |
static void SzFree(void *p, void *address) { |
p = p; /* for gcc to not complain */ |
free(address); |
} |
#endif |
/* opens a zip file and provides the list of files in the archive. |
returns a pointer to a ziplist (linked list) with all records, or NULL on error. |
The ziplist is allocated automatically, and must be freed via zip_freelist. */ |
struct ziplist *zip_listfiles(FILE *fd) { |
struct ziplist *reslist = NULL; |
struct ziplist *newentry; |
unsigned long entrysig; |
unsigned short filenamelen, extrafieldlen, filecommentlen; |
unsigned long compfilelen; |
int centraldirectoryfound = 0; |
unsigned int ux; |
unsigned char hdrbuff[64]; |
rewind(fd); /* make sure the file cursor is at the very beginning of the file */ |
for (;;) { /* read entry after entry */ |
int x, eofflag; |
long longbuff; |
entrysig = 0; |
eofflag = 0; |
/* read the entry signature first */ |
for (x = 0; x < 32; x += 8) { |
if ((longbuff = fgetc(fd)) == EOF) { |
eofflag = 1; |
break; |
} |
entrysig |= (longbuff << x); |
} |
if (eofflag != 0) break; |
/* printf("sig: 0x%08x\n", entrysig); */ |
if (entrysig == 0x04034b50ul) { /* local file */ |
unsigned int generalpurposeflags; |
/* read and parse the zip header */ |
fread(hdrbuff, 1, 26, fd); |
/* read filename's length so I can allocate the proper amound of mem */ |
filenamelen = hdrbuff[23]; |
filenamelen <<= 8; |
filenamelen |= hdrbuff[22]; |
/* create new entry and link it into the list */ |
newentry = calloc(sizeof(struct ziplist) + filenamelen, 1); |
if (newentry == NULL) { |
kitten_puts(8, 0, "Out of memory!"); |
zip_freelist(&reslist); |
break; |
} |
newentry->nextfile = reslist; |
newentry->flags = 0; |
reslist = newentry; |
/* read further areas of the header, and fill zip entry */ |
generalpurposeflags = hdrbuff[3]; /* parse the general */ |
generalpurposeflags <<= 8; /* purpose flags and */ |
generalpurposeflags |= hdrbuff[2]; /* save them for later */ |
newentry->compmethod = hdrbuff[4] | (hdrbuff[5] << 8); |
newentry->timestamp = dostime2unix(&hdrbuff[6]); |
newentry->crc32 = 0; |
for (x = 13; x >= 10; x--) { |
newentry->crc32 <<= 8; |
newentry->crc32 |= hdrbuff[x]; |
} |
newentry->compressedfilelen = 0; |
for (x = 17; x >= 14; x--) { |
newentry->compressedfilelen <<= 8; |
newentry->compressedfilelen |= hdrbuff[x]; |
} |
newentry->filelen = 0; |
for (x = 21; x >= 18; x--) { |
newentry->filelen <<= 8; |
newentry->filelen |= hdrbuff[x]; |
} |
extrafieldlen = hdrbuff[25]; |
extrafieldlen <<= 8; |
extrafieldlen |= hdrbuff[24]; |
/* printf("Filename len: %d / extrafield len: %d / compfile len: %ld / filelen: %ld\n", filenamelen, extrafieldlen, newentry->compressedfilelen, newentry->filelen); */ |
/* check general purpose flags */ |
if ((generalpurposeflags & 1) != 0) newentry->flags |= ZIP_FLAG_ENCRYPTED; |
/* parse the filename */ |
for (ux = 0; ux < filenamelen; ux++) newentry->filename[ux] = fgetc(fd); /* store filename */ |
if (newentry->filename[filenamelen - 1] == '/') newentry->flags |= ZIP_FLAG_ISADIR; /* if filename ends with / it's a dir. Note that ZIP forbids the usage of '\' in ZIP paths anyway */ |
/* printf("Filename: %s (%ld bytes compressed)\n", newentry->filename, newentry->compressedfilelen); */ |
newentry->dataoffset = ftell(fd) + extrafieldlen; |
/* skip rest of fields and data */ |
fseek(fd, (extrafieldlen + newentry->compressedfilelen), SEEK_CUR); |
} else if (entrysig == 0x02014b50ul) { /* central directory */ |
centraldirectoryfound = 1; |
/* parse header now */ |
fread(hdrbuff, 1, 42, fd); |
filenamelen = hdrbuff[22] | (hdrbuff[23] << 8); |
extrafieldlen = hdrbuff[24] | (hdrbuff[25] << 8); |
filecommentlen = hdrbuff[26] | (hdrbuff[27] << 8); |
compfilelen = 0; |
for (x = 17; x >= 14; x--) { |
compfilelen <<= 8; |
compfilelen |= hdrbuff[x]; |
} |
/* printf("central dir\n"); */ |
/* skip rest of fields and data */ |
fseek(fd, (filenamelen + extrafieldlen + compfilelen + filecommentlen), SEEK_CUR); |
} else if (entrysig == 0x08074b50ul) { /* Data descriptor header */ |
/* no need to read the header we just have to skip it */ |
fseek(fd, 12, SEEK_CUR); /* the header is 3x4 bytes (CRC + compressed len + uncompressed len) */ |
} else { /* unknown sig */ |
kitten_printf(8, 1, "unknown zip sig: 0x%08lx", entrysig); |
puts(""); |
zip_freelist(&reslist); |
break; |
} |
} |
/* if we got no central directory record, the file is incomplete */ |
if (centraldirectoryfound == 0) zip_freelist(&reslist); |
return(reslist); |
} |
/* unzips a file. zipfd points to the open zip file, curzipnode to the entry to extract, and fulldestfilename is the destination file where to unzip it. returns 0 on success, non-zero otherwise. */ |
int zip_unzip(FILE *zipfd, struct ziplist *curzipnode, char *fulldestfilename) { |
#define buffsize 32 * 1024l /* MUST be at least 32K */ |
FILE *filefd; |
unsigned long cksum; |
int extract_res; |
unsigned char *buff; |
struct utimbuf filetimestamp; |
/* first of all, check we support the compression method */ |
switch (curzipnode->compmethod) { |
case 0: /* stored */ |
case 8: /* deflated */ |
#ifndef NOLZMA |
case 14: /* lzma */ |
#endif |
break; |
default: /* unsupported compression method, sorry */ |
return(-1); |
break; |
} |
/* open the dst file */ |
filefd = fopen(fulldestfilename, "wb"); |
if (filefd == NULL) return(-2); /* failed to open the dst file */ |
/* allocate buffers for data I/O */ |
buff = malloc(buffsize); |
if (buff == NULL) { |
fclose(filefd); |
unlink(fulldestfilename); /* remove the failed file once it is closed */ |
return(-6); |
} |
if (fseek(zipfd, curzipnode->dataoffset, SEEK_SET) != 0) { /* set the reading position inside the zip file */ |
free(buff); |
fclose(filefd); |
unlink(fulldestfilename); /* remove the failed file once it is closed */ |
return(-7); |
} |
extract_res = -255; |
cksum = crc32_init(); /* init the crc32 */ |
if (curzipnode->compmethod == 0) { /* if the file is stored, copy it over */ |
long i, toread; |
extract_res = 0; /* assume we will succeed */ |
for (i = 0; i < curzipnode->filelen;) { |
toread = curzipnode->filelen - i; |
if (toread > buffsize) toread = buffsize; |
if (fread(buff, toread, 1, zipfd) != 1) extract_res = -3; /* read a chunk of data */ |
crc32_feed(&cksum, buff, toread); /* update the crc32 checksum */ |
if (fwrite(buff, toread, 1, filefd) != 1) extract_res = -4; /* write data chunk to dst file */ |
i += toread; |
} |
} else if (curzipnode->compmethod == 8) { /* if the file is deflated, inflate it */ |
extract_res = inf(zipfd, filefd, buff, &cksum, curzipnode->compressedfilelen); |
#ifndef NOLZMA |
} else if (curzipnode->compmethod == 14) { /* LZMA */ |
#define lzmaoutbufflen 32768u |
long bytesread, bytesreadtotal = 0, byteswritetotal = 0; |
SizeT buffoutreslen; |
ISzAlloc g_alloc; |
ELzmaStatus lzmastatus; |
SRes lzmaresult; |
CLzmaDec lzmahandle; |
unsigned char lzmahdr[LZMA_PROPS_SIZE]; /* 5 bytes of properties */ |
unsigned char *lzmaoutbuff; |
extract_res = -5; /* assume we will fail. if we don't - then we will update this flag */ |
lzmaoutbuff = malloc(lzmaoutbufflen); |
if (lzmaoutbuff == NULL) { |
free(buff); |
fclose(filefd); /* close the dst file */ |
return(-33); |
} |
fread(lzmahdr, 4, 1, zipfd); /* load the 4 bytes long 'zip-lzma header */ |
bytesreadtotal = 4; /* remember we read 4 bytes already */ |
/* lzma properties should be exactly 5 bytes long. If it's not, it's either not valid lzma, or some version that wasn't existing yet when I wrote these words. Also, check that the lzma content is at least 9 bytes long and that our previous malloc() calls suceeded. */ |
if ((lzmahdr[2] == 5) && (lzmahdr[3] == 0) && (curzipnode->compressedfilelen >= 9)) { |
extract_res = 0; /* since we got so far, let's assume we will succeed now */ |
g_alloc.Alloc = SzAlloc; /* these will be used as callbacks by lzma to manage memory */ |
g_alloc.Free = SzFree; |
fread(lzmahdr, sizeof(lzmahdr), 1, zipfd); /* load the lzma header */ |
bytesreadtotal += sizeof(lzmahdr); |
/* Note, that in a 'normal' lzma stream we would have now 8 bytes with the uncompressed length of the file. Here we don't. ZIP cut this information out, since it stores it already in its own header. */ |
memset(&lzmahandle, 0, sizeof(lzmahandle)); /* reset the whole lzmahandle structure - not doing this leads to CRASHES!!! */ |
LzmaDec_Init(&lzmahandle); |
lzmaresult = LzmaDec_Allocate(&lzmahandle, lzmahdr, LZMA_PROPS_SIZE, &g_alloc); /* forget not to LzmaDec_Free() later! */ |
if (lzmaresult != 0) extract_res = -13; |
while (extract_res == 0) { |
bytesread = buffsize; |
if (bytesread > curzipnode->compressedfilelen - bytesreadtotal) bytesread = curzipnode->compressedfilelen - bytesreadtotal; |
buffoutreslen = lzmaoutbufflen; |
/* printf("Will read %d bytes from input stream\n", bytesread); */ |
fread(buff, bytesread, 1, zipfd); /* read stuff from input stream */ |
fseek(zipfd, 0 - bytesread, SEEK_CUR); /* get back to the position at the start of our chunk of data */ |
lzmaresult = LzmaDec_DecodeToBuf(&lzmahandle, lzmaoutbuff, &buffoutreslen, buff, (SizeT *)&bytesread, LZMA_FINISH_ANY, &lzmastatus); |
bytesreadtotal += bytesread; |
/* printf("expanded %ld bytes into %ld (total read: %ld bytes)\n", (long)bytesread, (long)buffoutreslen, (long)bytesreadtotal); */ |
fseek(zipfd, bytesread, SEEK_CUR); /* go forward to the position next to the input we processed */ |
if (lzmaresult != SZ_OK) { |
extract_res = -20; |
if (lzmaresult == SZ_ERROR_DATA) extract_res = -21; /* DATA ERROR */ |
if (lzmaresult == SZ_ERROR_MEM) extract_res = -22; /* MEMORY ALLOC ERROR */ |
if (lzmaresult == SZ_ERROR_UNSUPPORTED) extract_res = -23; /* UNSUPPORTED PROPERTY */ |
if (lzmaresult == SZ_ERROR_INPUT_EOF) extract_res = -24; /* NEED MORE INPUT */ |
break; |
} |
/* check that we haven't got TOO MUCH decompressed data, and trim if necessary. It happens that LZMA provides a few bytes more than it should at the end of the stream. */ |
if (byteswritetotal + (long)buffoutreslen > curzipnode->filelen) { |
buffoutreslen = curzipnode->filelen - byteswritetotal; |
} |
byteswritetotal += buffoutreslen; |
fwrite(lzmaoutbuff, buffoutreslen, 1, filefd); /* write stuff to output file */ |
crc32_feed(&cksum, lzmaoutbuff, buffoutreslen); |
/* if (lzmastatus == LZMA_STATUS_FINISHED_WITH_MARK) puts("lzma says we are done!"); */ |
if ((lzmastatus == LZMA_STATUS_FINISHED_WITH_MARK) || (bytesreadtotal >= curzipnode->compressedfilelen)) { |
extract_res = 0; /* looks like we succeeded! */ |
break; |
} |
} |
LzmaDec_Free(&lzmahandle, &g_alloc); /* this will free all the stuff we allocated via LzmaDec_Allocate() */ |
/* printf("Processed %d bytes of input into %d bytes of output. CRC32: %08lX\n", bytesreadtotal, byteswritetotal, crc32); */ |
} |
free(lzmaoutbuff); |
#endif |
} |
/* clean up memory, close the dst file and terminates crc32 */ |
free(buff); |
fclose(filefd); /* close the dst file */ |
crc32_finish(&cksum); |
/* printf("extract_res=%d / cksum_expected=%08lX / cksum_obtained=%08lX\n", extract_res, curzipnode->crc32, cksum); */ |
if (extract_res != 0) { /* was the extraction process successful? */ |
unlink(fulldestfilename); /* remove the failed file */ |
return(extract_res); |
} |
if (cksum != curzipnode->crc32) { /* is the crc32 ok after extraction? */ |
unlink(fulldestfilename); /* remove the failed file */ |
return(-9); |
} |
/* Set the timestamp of the new file to what was set in the zip file */ |
filetimestamp.actime = curzipnode->timestamp; |
filetimestamp.modtime = curzipnode->timestamp; |
utime(fulldestfilename, &filetimestamp); |
return(0); |
} |
/* Call this to free a ziplist computed by zip_listfiles() */ |
void zip_freelist(struct ziplist **ziplist) { |
struct ziplist *zipentrytobefreed; |
while (*ziplist != NULL) { /* iterate through the linked list and free all nodes */ |
zipentrytobefreed = *ziplist; |
*ziplist = zipentrytobefreed->nextfile; |
/* free the node entry */ |
free(zipentrytobefreed); |
} |
*ziplist = NULL; |
} |
/pkginst/libunzip.h |
---|
0,0 → 1,35 |
/* |
* This file is part of the FDNPKG project |
* http://fdnpkg.sourceforge.net |
* |
* Copyright (C) 2012-2016 Mateusz Viste. All rights reserved. |
* |
* Simple library providing functions to unzip files from zip archives. |
*/ |
#ifndef libunzip_sentinel |
#define libunzip_sentinel |
#include <time.h> /* required for the time_t definition */ |
#define ZIP_FLAG_ISADIR 1 |
#define ZIP_FLAG_ENCRYPTED 2 |
struct ziplist { |
long filelen; |
long compressedfilelen; |
unsigned long crc32; |
long dataoffset; /* offset in the file where compressed data starts */ |
struct ziplist *nextfile; |
time_t timestamp; /* the timestamp of the file */ |
short compmethod; |
unsigned char flags; /* zero for files, non-zero for directories */ |
char filename[1]; /* must be last element (gets expanded at runtime) */ |
}; |
struct ziplist *zip_listfiles(FILE *fd); |
int zip_unzip(FILE *zipfd, struct ziplist *curzipnode, char *fulldestfilename); |
void zip_freelist(struct ziplist **ziplist); |
#endif |
/pkginst/loadconf.c |
---|
0,0 → 1,422 |
/* |
* This file is part of FDNPKG. |
* |
* Loads the list of repositories from the config file specified in %FDNPKG%. |
* Returns the amount of repositories found (and loaded) on success, or -1 on failure. |
* |
* Copyright (C) 2012-2016 Mateusz Viste |
*/ |
#include <stdio.h> /* printf(), fclose(), fopen()... */ |
#include <string.h> /* strcasecmp() */ |
#include <stdlib.h> /* malloc(), free() */ |
#include "crc32.h" /* crc32() */ |
#include "fdnpkg.h" /* PKGINST_NOSOURCE, PKGINST_SKIPLINKS... */ |
#include "helpers.h" /* slash2backslash(), removeDoubleBackslashes()... */ |
#include "kprintf.h" |
#include "loadconf.h" |
#include "parsecmd.h" |
#include "version.h" |
void freeconf(char **repolist, int repscount, struct customdirs **dirlist) { |
int x; |
struct customdirs *curpos; |
/* free repolist */ |
for (x = 0; x < repscount; x++) free(repolist[x]); |
/* free the linked list of custom dirs */ |
while (*dirlist != NULL) { |
curpos = *dirlist; |
if (curpos->name != NULL) free(curpos->name); |
if (curpos->location != NULL) free(curpos->location); |
*dirlist = (*dirlist)->next; |
free(curpos); |
} |
*dirlist = NULL; |
} |
static int checkfordoubledrepos(char **repolist, int repocount) { |
int x, y; |
for (x = 0; x < (repocount - 1); x++) { |
for (y = x + 1; y < repocount; y++) { |
if (strcmp(repolist[x], repolist[y]) == 0) { |
kitten_printf(7, 14, "Error: repository '%s' is listed twice!", repolist[x]); |
puts(""); |
return(-1); |
} |
} |
} |
return(0); |
} |
static int checkfordoubledirlist(struct customdirs *dirlist) { |
struct customdirs *curpos; |
for (; dirlist != NULL; dirlist = dirlist->next) { |
for (curpos = dirlist->next; curpos != NULL; curpos = curpos->next) { |
if (strcasecmp(curpos->name, dirlist->name) == 0) { |
kitten_printf(7, 0, "Error: custom dir '%s' is listed twice!", curpos->name); |
puts(""); |
return(-1); |
} |
} |
} |
return(0); |
} |
/* validates dirlist entries: check that they are absolute paths and are not using restricted names */ |
static int validatedirlist(struct customdirs *dirlist) { |
for (; dirlist != NULL; dirlist = dirlist->next) { |
/* the location must be at least 3 characters long to be a valid absolute path (like 'c:\')*/ |
if (strlen(dirlist->location) < 3) { |
kitten_printf(7, 15, "Error: custom dir '%s' is not a valid absolute path!", dirlist->name); |
puts(""); |
return(-1); |
} |
/* is it a valid absolute path? should start with [a..Z]:\ */ |
if ((dirlist->location[1] != ':') || |
((dirlist->location[2] != '/') && (dirlist->location[2] != '\\')) || |
(((dirlist->location[0] < 'a') || (dirlist->location[0] > 'z')) && ((dirlist->location[0] < 'A') || (dirlist->location[0] > 'Z')))) { |
kitten_printf(7, 15, "Error: custom dir '%s' is not a valid absolute path!", dirlist->name); |
puts(""); |
return(-1); |
} |
/* check for forbidden names */ |
if ((strcasecmp(dirlist->name, "appinfo") == 0) || |
(strcasecmp(dirlist->name, "bin") == 0) || |
(strcasecmp(dirlist->name, "doc") == 0) || |
(strcasecmp(dirlist->name, "help") == 0) || |
(strcasecmp(dirlist->name, "nls") == 0) || |
(strcasecmp(dirlist->name, "packages") == 0)) { |
kitten_printf(7, 16, "Error: custom dir '%s' is a reserved name!", dirlist->name); |
puts(""); |
return(-1); |
} |
} |
return(0); |
} |
/* add (and allocates) a new custom dir entry to dirlist. Returns 0 on success, |
or non-zero on failure (failures happen on out of memory events). */ |
static int addnewdir(struct customdirs **dirlist, char *name, char *location) { |
struct customdirs *newentry; |
newentry = malloc(sizeof(struct customdirs)); |
if (newentry == NULL) return(-1); |
newentry->name = malloc(strlen(name) + 1); |
if (newentry->name == NULL) { |
free(newentry); |
return(-1); |
} |
newentry->location = malloc(strlen(location) + 1); |
if (newentry->location == NULL) { |
free(newentry->name); |
free(newentry); |
return(-1); |
} |
strcpy(newentry->name, name); |
strcpy(newentry->location, location); |
newentry->next = *dirlist; |
*dirlist = newentry; |
return(0); |
} |
int loadconf(char *cfgfile, char **repolist, int maxreps, unsigned long *crc32val, long *maxcachetime, struct customdirs **dirlist, int *flags, char **proxy, int *proxyport, char **mapdrv) { |
int bytebuff, parserstate = 0; |
FILE *fd; |
#define BUFFSIZE 1024 |
unsigned char *fbuff; |
#define maxtok 16 |
char token[maxtok]; |
#define maxval 1024 |
char value[maxval]; |
int curtok = 0, curval = 0, nline = 1; |
int repocount = 0; |
int buffread; |
fd = fopen(cfgfile, "r"); |
if (fd == NULL) { |
kitten_printf(7, 1, "Error: Could not open config file '%s'!", cfgfile); |
puts(""); |
return(-1); |
} |
/* compute the CRC32 of the configuration file (if crc32val not NULL) */ |
if (crc32val != NULL) { |
fbuff = malloc(BUFFSIZE); |
if (fbuff == NULL) { |
fclose(fd); |
kitten_printf(2, 14, "Out of memory! (%s)", "fbuff malloc"); |
puts(""); |
puts(""); |
return(-1); |
} |
*crc32val = crc32_init(); |
while ((buffread = fread(fbuff, sizeof(char), BUFFSIZE, fd)) > 0) { |
if (buffread > 0) crc32_feed(crc32val, fbuff, buffread); |
} |
crc32_finish(crc32val); |
free(fbuff); |
} |
/* rewind the file, to start reading it again */ |
rewind(fd); |
/* read the config file line by line */ |
do { |
bytebuff = fgetc(fd); |
if (bytebuff != '\r') { |
switch (parserstate) { |
case 0: /* Looking for start of line */ |
if ((bytebuff == EOF) || (bytebuff == ' ') || (bytebuff == '\t')) break; |
if (bytebuff == '\n') { |
nline += 1; |
break; |
} |
if (bytebuff == '#') { |
parserstate = 9; |
} else { |
token[0] = bytebuff; |
curtok = 1; |
parserstate = 1; |
} |
break; |
case 1: /* Looking for token end */ |
if ((bytebuff == EOF) || (bytebuff == '\n')) { |
kitten_printf(7, 2, "Warning: token without value on line #%d", nline); |
puts(""); |
if (bytebuff == '\n') nline += 1; |
parserstate = 0; |
break; |
} |
if ((bytebuff == ' ') || (bytebuff == '\t')) { |
token[curtok] = 0; |
parserstate = 2; |
} else { |
token[curtok] = bytebuff; |
curtok += 1; |
if (curtok >= maxtok) { |
parserstate = 9; /* ignore the line */ |
kitten_printf(7, 3, "Warning: Config file token overflow on line #%d", nline); |
puts(""); |
} |
} |
break; |
case 2: /* Looking for value start */ |
if ((bytebuff == EOF) || (bytebuff == '\n')) { |
kitten_printf(7, 4, "Warning: token with empty value on line #%d", nline); |
puts(""); |
if (bytebuff == '\n') nline += 1; |
parserstate = 0; |
break; |
} |
if ((bytebuff != ' ') && (bytebuff != '\t')) { |
value[0] = bytebuff; |
curval = 1; |
parserstate = 3; |
} |
break; |
case 3: /* Looking for value end */ |
if ((bytebuff == EOF) || (bytebuff == '\n')) { |
parserstate = 0; |
value[curval] = 0; |
if ((value[curval - 1] == ' ') || (value[curval - 1] == '\t')) { |
kitten_printf(7, 5, "Warning: trailing white-space(s) after value on line #%d", nline); |
puts(""); |
while ((value[curval - 1] == ' ') || (value[curval - 1] == '\t')) value[--curval] = 0; |
} |
/* Interpret the token/value pair now! */ |
/* printf("token='%s' ; value = '%s'\n", token, value); */ |
if (strcasecmp(token, "REPO") == 0) { /* Repository declaration */ |
if (maxreps == 0) { |
/* simply ignore if the app explicitely wishes to load no repositories */ |
} else if (repocount >= maxreps) { |
kitten_printf(7, 6, "Dropped a repository: too many configured (max=%d)", maxreps); |
puts(""); |
} else { |
char pathdelimchar; |
/* add a trailing path delimiter (slash or backslash) to the url if not there already */ |
if (detect_localpath(value) != 0) { |
pathdelimchar = '\\'; |
} else { |
pathdelimchar = '/'; |
} |
if ((value[curval - 1] != '/') && (value[curval - 1] != '\\')) { |
value[curval++] = pathdelimchar; |
value[curval] = 0; |
} |
/* copy the value into the repository list */ |
repolist[repocount] = strdup(value); |
if (repolist[repocount] == NULL) { |
kitten_printf(2, 14, "Out of memory! (%s)", "repolist malloc"); |
puts(""); |
freeconf(repolist, repocount, dirlist); |
fclose(fd); |
return(-1); |
} |
repocount += 1; |
} |
} else if (strcasecmp(token, "MAPDRIVES") == 0) { |
*mapdrv = strdup(value); |
if ((*mapdrv != NULL) && strlen(*mapdrv) & 1) { |
free(*mapdrv); |
*mapdrv = NULL; |
} |
if (*mapdrv == NULL) *mapdrv = ""; |
} else if (strcasecmp(token, "MAXCACHETIME") == 0) { |
long tmpint = atol(value); |
if ((tmpint >= 0) && (tmpint < 1209600l)) { /* min 0s / max 2 weeks */ |
if (maxcachetime != NULL) *maxcachetime = tmpint; |
} else { |
kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "maxcachetime", nline); |
puts(""); |
} |
} else if (strcasecmp(token, "INSTALLSOURCES") == 0) { |
int tmpint = atoi(value); /* must be 0/1 */ |
if (tmpint == 0) { |
*flags |= PKGINST_NOSOURCE; |
} else if (tmpint == 1) { |
/* do nothing */ |
} else { |
kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "installsources", nline); |
puts(""); |
} |
} else if (strcasecmp(token, "SKIPLINKS") == 0) { |
int tmpint = atoi(value); /* must be 0/1 */ |
if (tmpint == 0) { |
/* do nothing */ |
} else if (tmpint == 1) { |
*flags |= PKGINST_SKIPLINKS; |
} else { |
kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "skiplinks", nline); |
puts(""); |
} |
} else if (strcasecmp(token, "HTTP_PROXY") == 0) { |
if (value[0] != 0) { |
if (proxy != NULL) *proxy = strdup(value); |
} else { |
kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "http_proxy", nline); |
puts(""); |
} |
} else if (strcasecmp(token, "HTTP_PROXYPORT") == 0) { |
int tmpint = atoi(value); |
if (tmpint != 0) { |
if (proxyport != NULL) *proxyport = tmpint; |
} else { |
kitten_printf(7, 10, "Warning: Ignored an illegal '%s' value at line #%d", "http_proxyport", nline); |
puts(""); |
} |
} else if (strcasecmp(token, "DIR") == 0) { /* custom repository entry */ |
char *argv[2], *evar, *evar_content, *realLocation; |
#define realLocation_len 512 |
int x, y; |
if (parsecmd(value, argv, 2) != 2) { |
kitten_printf(7, 11, "Warning: Invalid 'DIR' directive found at line #%d", nline); |
puts(""); |
} |
realLocation = malloc(realLocation_len); |
if (realLocation == NULL) { |
kitten_printf(2, 14, "Out of memory! (%s)", "malloc realLocation"); |
puts(""); |
freeconf(repolist, repocount, dirlist); |
fclose(fd); |
return(-1); |
} |
realLocation[0] = 0; /* force it to be empty, since we might use strcat() on this later! */ |
/* resolve possible env variables */ |
evar = NULL; |
y = 0; |
for (x = 0; argv[1][x] != 0; x++) { |
if (evar == NULL) { /* searching for % and copying */ |
if (argv[1][x] == '%') { |
evar = &argv[1][x+1]; |
} else { |
if (y + 1 > realLocation_len) { |
kitten_printf(7, 12, "Error: DIR path too long at line #%d", nline); |
puts(""); |
freeconf(repolist, repocount, dirlist); |
free(realLocation); |
fclose(fd); |
return(-1); |
} |
realLocation[y] = argv[1][x]; /* copy over */ |
y++; |
realLocation[y] = 0; /* make sure to terminate the string at any time */ |
} |
} else { /* reading a % variable */ |
if (argv[1][x] == '%') { |
argv[1][x] = 0; |
evar_content = getenv(evar); |
if (evar_content == NULL) { |
kitten_printf(7, 13, "Error: Found inexisting environnement variable '%s' at line #%d", evar, nline); |
puts(""); |
freeconf(repolist, repocount, dirlist); |
free(realLocation); |
fclose(fd); |
return(-1); |
} |
if (strlen(evar_content) + y + 1 > realLocation_len) { |
kitten_printf(7, 12, "Error: DIR path too long at line #%d", nline); |
puts(""); |
freeconf(repolist, repocount, dirlist); |
free(realLocation); |
fclose(fd); |
return(-1); |
} |
strcat(realLocation, evar_content); |
y += strlen(evar_content); |
evar = NULL; |
} |
} |
} |
/* add the entry to the list */ |
slash2backslash(realLocation); |
removeDoubleBackslashes(realLocation); |
if (realLocation[strlen(realLocation) - 1] != '\\') strcat(realLocation, "\\"); /* make sure to end dirs with a backslash */ |
if (addnewdir(dirlist, argv[0], realLocation) != 0) { |
kitten_printf(2, 14, "Out of memory! (%s)", "addnewdir"); |
puts(""); |
freeconf(repolist, repocount, dirlist); |
free(realLocation); |
fclose(fd); |
return(-1); |
} |
free(realLocation); |
} else { /* unknown token */ |
kitten_printf(7, 8, "Warning: Unknown token '%s' at line #%d", token, nline); |
puts(""); |
} |
/* interpretation done */ |
if (bytebuff == '\n') nline += 1; |
} else { |
value[curval] = bytebuff; |
curval += 1; |
if ((curval + 1) >= maxval) { |
parserstate = 9; /* ignore the line */ |
kitten_printf(7, 9, "Warning: Config file value overflow on line #%d", nline); |
puts(""); |
} |
} |
break; |
case 9: /* Got comment, ignoring the rest of line */ |
if (bytebuff == EOF) break; |
if (bytebuff == '\n') { |
nline += 1; |
parserstate = 0; |
} |
break; |
} |
} |
} while (bytebuff != EOF); |
fclose(fd); |
/* Look out for doubled repositories */ |
if (checkfordoubledrepos(repolist, repocount) != 0) return(-1); |
if (checkfordoubledirlist(*dirlist) != 0) return(-1); |
if (validatedirlist(*dirlist) != 0) return(-1); |
return(repocount); |
} |
/pkginst/loadconf.h |
---|
0,0 → 1,23 |
/* |
* This file is part of FDNPKG. |
* |
* Copyright (C) 2012-2016 Mateusz Viste |
*/ |
#ifndef loadrepolist_sentinel |
#define loadrepolist_sentinel |
struct customdirs { |
char *name; |
char *location; |
struct customdirs *next; |
}; |
/* Loads the list of repositories from the config file specified in %FDNPKG%. |
* Returns the amount of repositories found (and loaded) on success, or -1 on failure. */ |
int loadconf(char *cfgfile, char **repolist, int maxreps, unsigned long *crc32val, long *maxcachetime, struct customdirs **dirlist, int *nosourceflag, char **proxy, int *proxyport, char **mapdrv); |
/* Free the memory allocated at configuration load. */ |
void freeconf(char **repolist, int repscount, struct customdirs **dirlist); |
#endif |
/pkginst/lsm.c |
---|
0,0 → 1,77 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2013-2016 Mateusz Viste, All rights reserved. |
*/ |
#include <stdio.h> /* fopen, fclose... */ |
#include <string.h> /* strcasecmp() */ |
#include "lsm.h" /* include self for control */ |
#include "rtrim.h" |
#include "version.h" |
/* reads a line from a file descriptor, and writes it to *line, the *line array is filled no more than maxlen bytes. returns the number of byte read on success, or a negative value on failure (reaching EOF is considered an error condition) */ |
static int readline_fromfile(FILE *fd, char *line, int maxlen) { |
int bytebuff, linelen = 0; |
for (;;) { |
bytebuff = fgetc(fd); |
if (bytebuff == EOF) { |
line[linelen] = 0; |
if (linelen == 0) return(-1); |
return(linelen); |
} |
if (bytebuff < 0) return(-1); |
if (bytebuff == '\r') continue; /* ignore CR */ |
if (bytebuff == '\n') { |
line[linelen] = 0; |
return(linelen); |
} |
if (linelen < maxlen) line[linelen++] = bytebuff; |
} |
} |
/* Loads metadata from an LSM file. Returns 0 on success, non-zero on error. */ |
int readlsm(char *filename, char *version, int version_maxlen) { |
char linebuff[128]; |
char *valuestr; |
int x; |
FILE *fd; |
/* reset fields to be read to empty values */ |
version[0] = 0; |
/* open the file */ |
fd = fopen(filename, "rb"); |
if (fd == NULL) return(-1); |
/* check the file's header */ |
if (readline_fromfile(fd, linebuff, 64) < 0) { |
fclose(fd); |
return(-1); |
} |
if (strcasecmp(linebuff, "begin3") != 0) { |
fclose(fd); |
return(-1); |
} |
/* read the LSM file line by line */ |
while (readline_fromfile(fd, linebuff, 127) >= 0) { |
for (x = 0;; x++) { |
if (linebuff[x] == 0) { |
x = -1; |
break; |
} else if (linebuff[x] == ':') { |
break; |
} |
} |
if (x > 0) { |
linebuff[x] = 0; |
valuestr = linebuff + x + 1; |
trim(linebuff); |
trim(valuestr); |
if (strcasecmp(linebuff, "version") == 0) { |
snprintf(version, version_maxlen, "%s", valuestr); |
version[version_maxlen] = 0; /* snprintf is supposed to terminate string itself, but the DJGPP doesn't */ |
} |
} |
} |
fclose(fd); |
return(0); |
} |
/pkginst/lsm.h |
---|
0,0 → 1,10 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2013-2016 Mateusz Viste, All rights reserved. |
*/ |
#ifndef readlsm_h_sentinel |
#define readlsm_h_sentinel |
/* Loads metadata from an LSM file. Returns 0 on success, non-zero on error. */ |
int readlsm(char *filename, char *version, int version_maxlen); |
#endif |
/pkginst/parsecmd.c |
---|
0,0 → 1,37 |
/* This file provides functions for parsing commands and their arguments |
Warning: parsecmd() will modify the cmdline string, so it won't be |
readable anymore in any other way other than via ptrtable[]. |
This function returns the number of arguments that have been parsed, |
or -1 on parsing error. |
Copyright (C) 2012-2016 Mateusz Viste */ |
#include "version.h" |
int parsecmd(char *cmdline, char **ptrtable, int maxargs) { |
int x = 0, argc = 0, state = 0; |
for (;;) { |
switch (cmdline[x]) { /* detect delimiter and non-delimiter chars */ |
case 0x0: /* detect end of string */ |
return(argc); /* return number of arguments */ |
case ' ': /* space */ |
case 0x9: /* tab */ |
case 0xA: /* LF */ |
case 0xD: /* CR */ |
if (state != 0) { /* if awaiting for argument end */ |
cmdline[x] = 0; /* terminate the substring */ |
state = 0; /* switch to 'waiting for argument end' state */ |
} |
break; |
default: /* anything that is not a delimiter */ |
if (state == 0) { /* if awaiting for argument start */ |
if (argc == maxargs) return(-1); /* look out for arg overflow */ |
ptrtable[argc] = &cmdline[x]; /* save the address of the substring */ |
argc += 1; /* increment the arguments count */ |
state = 1; /* switch to 'waiting for argument' state */ |
} |
} |
x += 1; /* move to the next character of cmdline */ |
} |
} |
/pkginst/parsecmd.h |
---|
0,0 → 1,15 |
/* This file provides functions for parsing commands and their arguments |
Warning: parsecmd() will modify the cmdline string, so it won't be |
readable anymore in any other way other than via ptrtable[]. |
This function returns the number of arguments that have been parsed, |
or -1 on parsing error. |
Copyright (C) 2012-2016 Mateusz Viste */ |
#ifndef PARSECMD_H_SENTINEL |
#define PARSECMD_H_SENTINEL |
int parsecmd(char *cmdline, char **ptrtable, int maxargs); |
#endif |
/pkginst/pkginst.c |
---|
0,0 → 1,520 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2012-2021 Mateusz Viste |
* Changes by TK Chia |
*/ |
#include <ctype.h> /* toupper() */ |
#include <stdio.h> |
#include <stdlib.h> /* system() */ |
#include <string.h> /* strcpy() */ |
#include <unistd.h> /* read() */ |
#include <sys/types.h> /* struct utimbuf */ |
#include "crc32.h" /* all CRC32 related stuff */ |
#include "fdnpkg.h" /* PKGINST_NOSOURCE, PKGINST_SKIPLINKS... */ |
#include "http.h" |
#include "helpers.h" /* slash2backslash(), strtolower() */ |
#include "fileexst.h" |
#include "kprintf.h" |
#include "libunzip.h" /* zip_listfiles()... */ |
#include "showinst.h" /* pkg_loadflist() */ |
#include "pkginst.h" /* include self for control */ |
#include "version.h" |
/* return 1 if fname looks like a link filename, 0 otherwise */ |
static int islinkfile(char *fname) { |
char *link1 = "LINKS\\"; |
char *link2 = "links\\"; |
int x; |
for (x = 0; ; x++) { |
if (link1[x] == 0) return(1); |
if ((fname[x] != link1[x]) && (fname[x] != link2[x])) return(0); |
} |
} |
/* validate a filename (8+3, no weird characters, etc). returns 0 on success, |
* nonzero otherwise. */ |
static int validfilename(char *fname) { |
int i, i2; |
char *validchars = "!#$%&'()-@^_`{}~"; |
int elemlen = 0; |
int elemmaxlen = 8; /* switches from 8 to 3 depending wheter I am analyzing |
a filename or an extension */ |
/* look for invalid chars in the entire string, and check the length of the |
* element at the same time */ |
for (i = 0; fname[i] != 0; i++) { |
/* director separators are threated specially */ |
if (fname[i] == '\\') { |
elemlen = 0; |
elemmaxlen = 8; |
continue; |
} |
/* '.' switches the check into extension mode */ |
if (fname[i] == '.') { |
if (elemlen == 0) return(-1); /* a file must have a base name */ |
if (elemmaxlen == 3) return(-2); /* a file cannot have two extensions */ |
elemlen = 0; |
elemmaxlen = 3; |
continue; |
} |
/* check that the element is not too long */ |
if (++elemlen > elemmaxlen) return(-3); |
/* look for valid characters */ |
if ((fname[i] >= 'a') && (fname[i] <= 'z')) continue; |
if ((fname[i] >= 'A') && (fname[i] <= 'Z')) continue; |
if ((fname[i] >= '0') && (fname[i] <= '9')) continue; |
if ((fname[i] & 128) != 0) continue; /* high bytes are okay (NLS) */ |
/* look for other valid characters */ |
for (i2 = 0; validchars[i2] != 0; i2++) { |
if (fname[i] == validchars[i2]) break; |
} |
if (validchars[i2] != 0) continue; |
/* if we are here, then the character is invalid */ |
return(-4); |
} |
/* all checks passed */ |
return(0); |
} |
/* processes a link file - that is, reads the target inside, and overwrite |
* the file with new content */ |
static void processlinkfile(char *linkfile, char *dosdir, struct customdirs *dirlist, char *buff) { |
char origtarget[512]; |
int x; |
char *shortfile; |
unsigned char comstub[] = { /* machine code of a COM stub launcher */ |
0xBC,0x00,0x00,0xBB,0x00,0x10,0xB4,0x4A,0xCD,0x21,0xBB,0x2A,0x01,0x8C,0x5F,0x04, |
0x8C,0x5F,0x08,0x8C,0x5F,0x0C,0xB8,0x00,0x4B,0xBA,0x38,0x01,0xCD,0x21,0xB0,0x7F, |
0x72,0x04,0xB4,0x4D,0xCD,0x21,0xB4,0x4C,0xCD,0x21,0x00,0x00,0x80,0x00,0x00,0x00, |
0x5C,0x00,0x00,0x00,0x6C,0x00,0x00,0x00}; /* read comlink.asm for details */ |
const unsigned stack_paras = 12; |
unsigned alloc_paras, alloc_bytes; |
FILE *fd; |
/* open the link file and read the original target */ |
fd = fopen(linkfile, "r"); |
if (fd == NULL) { |
kitten_printf(3, 21, "Error: Failed to open link file '%s' for read access.", linkfile); |
puts(""); |
return; |
} |
x = fread(origtarget, 1, sizeof(origtarget) - 1, fd); |
origtarget[x] = 0; |
fclose(fd); |
/* validate the original target (ltrim to first \r or \n) */ |
for (x = 0; origtarget[x] != 0; x++) { |
if ((origtarget[x] == '\r') || (origtarget[x] == '\n')) { |
origtarget[x] = 0; |
break; |
} |
} |
/* translate the original target to a local path */ |
shortfile = computelocalpath(origtarget, buff, dosdir, dirlist); |
/* compute the amount of memory the stub should leave for itself: |
- 16 paragraphs needed for the PSP |
- sizeof(comstub) bytes needed for code and data |
- strlen(shortfile) + 1 for the command line |
- stack_paras paragraphs for the stack */ |
alloc_paras = 16 + (sizeof(comstub) + strlen(shortfile) + 16) / 16 + stack_paras; |
alloc_bytes = 16 * alloc_paras; |
comstub[1] = alloc_bytes & 0xff; |
comstub[2] = alloc_bytes >> 8; |
comstub[4] = alloc_paras & 0xff; |
comstub[5] = alloc_paras >> 8; |
/* write new content into the link file */ |
fd = fopen(linkfile, "wb"); |
if (fd == NULL) { |
kitten_printf(3, 22, "Error: Failed to open link file '%s' for write access.", linkfile); |
puts(""); |
return; |
} |
fwrite(comstub, 1, sizeof(comstub), fd); |
fprintf(fd, "%s%s%c", buff, shortfile, 0); |
fclose(fd); |
} |
/* returns 0 if pkgname is not installed, non-zero otherwise */ |
int is_package_installed(char *pkgname, char *dosdir, char *mapdrv) { |
char fname[512]; |
sprintf(fname, "%s\\packages\\%s.lst", dosdir, pkgname); |
mapdrives(fname, mapdrv); |
if (fileexists(fname) != 0) { /* file exists -> package is installed */ |
return(1); |
} else { |
return(0); |
} |
} |
/* checks that pkgname is NOT installed. return 0 on success, non-zero otherwise. */ |
int validate_package_not_installed(char *pkgname, char *dosdir, char *mapdrv) { |
if (is_package_installed(pkgname, dosdir, mapdrv) != 0) { |
kitten_printf(3, 18, "Package %s is already installed! You might want to use the 'update' action.", pkgname); |
puts(""); |
return(-1); |
} |
return(0); |
} |
/* find a filename in a flist linked list, and returns a pointer to it */ |
static struct flist_t *findfileinlist(struct flist_t *flist, char *fname) { |
while (flist != NULL) { |
if (strcmp(flist->fname, fname) == 0) return(flist); |
flist = flist->next; |
} |
return(NULL); |
} |
/* prepare a package for installation. this is mandatory before actually installing it! |
* returns a pointer to the zip file's index on success, NULL on failure. the *zipfile pointer is updated with a file descriptor to the open zip file to install. */ |
struct ziplist *pkginstall_preparepackage(struct pkgdb *pkgdb, char *pkgname, char *tempdir, char *localfile, int flags, char **repolist, FILE **zipfd, char *proxy, int proxyport, char *downloadingstring, char *dosdir, struct customdirs *dirlist, char *buffmem1k, char *mapdrv) { |
char *fname; |
char *zipfile; |
char *appinfofile; |
int appinfopresence; |
char *shortfile; |
struct ziplist *ziplinkedlist, *curzipnode, *prevzipnode; |
struct flist_t *flist; |
fname = buffmem1k; |
zipfile = buffmem1k + 256; |
appinfofile = buffmem1k + 512; |
strtolower(pkgname); /* convert pkgname to lower case, because the http repo is probably case sensitive */ |
sprintf(appinfofile, "appinfo\\%s.lsm", pkgname); /* Prepare the appinfo/xxxx.lsm filename string for later use */ |
/* check if not already installed, if already here, print a message "you might want to use update instead" |
* of course this must not be done if we are in the process of upgrading said package */ |
if (((flags & PKGINST_UPDATE) == 0) && (validate_package_not_installed(pkgname, dosdir, mapdrv) != 0)) { |
return(NULL); |
} |
if (localfile != NULL) { /* if it's a local file, then we will have to skip all the network stuff */ |
strcpy(zipfile, localfile); |
} else { |
zipfile[0] = 0; |
} |
#ifndef NOREPOS |
if (zipfile[0] == 0) { /* need to download the package from a repository */ |
char *instrepo; |
struct pkgdb *pkgnode, *lastnode; |
struct pkgrepo *pkgrepo; |
int repoid; |
unsigned long zipfilecrc, remotecrc; |
unsigned char *buff; |
int buffreadres; |
char *pkgext; /* zip or zib */ |
/* look into the db to find the package */ |
pkgnode = findpkg(pkgdb, pkgname, &lastnode); |
if (pkgnode == NULL) { /* no such package found in repositories */ |
kitten_printf(3, 1, "No package '%s' found in online repositories.", pkgname); |
puts(""); |
return(NULL); |
} |
/* if found - check the list of repositories */ |
if (pkgnode->repolist == NULL) { |
kitten_printf(3, 2, "Package '%s' is not available in repositories.", pkgname); |
puts(""); |
return(NULL); |
} |
if (pkgnode->repolist->nextrepo != NULL) { /* available from more than 1 repo.. */ |
char userchoicestr[8]; |
int userchoice, latestver_repoid = 1; |
struct pkgrepo *xrepo, *latestver = pkgnode->repolist; |
/* check out if we are able to find out the newest version */ |
repoid = 2; /* setting to 2, because we start iterating at the second repo entry */ |
for (xrepo = pkgnode->repolist->nextrepo; xrepo != NULL; xrepo = xrepo->nextrepo) { |
int versionnewerres = isversionnewer(latestver->version, xrepo->version); |
if (versionnewerres > 0) { |
latestver = xrepo; |
latestver_repoid = repoid; |
} else if (versionnewerres < 0) { /* unable to tell which version is newer */ |
latestver_repoid = -1; |
break; |
} |
repoid += 1; |
} |
if (latestver_repoid > 0) { |
repoid = latestver_repoid; |
} else { /* newest version could not be figured out, so let's ask the user to choose */ |
puts(""); |
kitten_printf(3, 3, "%s is available from several repositories. Choose which one to use:", pkgname); |
puts(""); |
repoid = 1; |
for (xrepo = pkgnode->repolist; xrepo != NULL; xrepo = xrepo->nextrepo) { |
printf(" %d) %s %s (%s)\n", repoid, pkgnode->name, xrepo->version, repolist[xrepo->repo]); |
repoid += 1; |
} |
for (;;) { |
kitten_printf(3, 4, "Your choice:"); |
printf(" "); |
fgets(userchoicestr, 6, stdin); |
userchoice = atoi(userchoicestr); |
if ((userchoice < 1) || (userchoice >= repoid)) { |
kitten_puts(3, 5, "Invalid choice!"); |
} else { |
break; |
} |
} |
repoid = userchoice; |
} |
} else { /* available only from one repository - get it there */ |
repoid = 1; |
} |
pkgrepo = pkgnode->repolist; |
for (; repoid > 1; repoid--) pkgrepo = pkgrepo->nextrepo; |
instrepo = repolist[pkgrepo->repo]; |
/* select the package extension: zip or zib */ |
if ((flags & PKGINST_NOSOURCE) && (pkgrepo->crc32zib != 0)) { /* use zib if available and if no sources needed */ |
pkgext = "zib"; /* zib is the same thing as zip, but binary-only (no sources) */ |
remotecrc = pkgrepo->crc32zib; |
} else { /* otherwise use the full-blown zip package */ |
pkgext = "zip"; |
remotecrc = pkgrepo->crc32zip; |
} |
/* if it's a network repo, download the package from repoid into the temp directory */ |
if (detect_localpath(instrepo) == 0) { |
sprintf(fname, "%s%s.%s", instrepo, pkgname, pkgext); |
sprintf(zipfile, "%s\\fdnpkg.tmp", tempdir); |
kitten_printf(3, 6, "Downloading package %s...", fname); |
puts(""); |
if (http_get(fname, zipfile, proxy, proxyport, downloadingstring) <= 0) { |
kitten_puts(3, 7, "Error downloading package. Aborted."); |
return(NULL); |
} |
} else { /* else it's an on-disk repo, so we can use the package right from there */ |
sprintf(zipfile, "%s%s.%s", instrepo, pkgname, pkgext); |
} |
/* check the CRC of the downloaded file */ |
buff = malloc(4096); /* use a 4K buffer to compute file's CRC */ |
if (buff == NULL) { |
kitten_puts(3, 15, "Error: Out of memory while computing the CRC of the package!"); |
return(NULL); |
} |
*zipfd = fopen(zipfile, "rb"); |
if (*zipfd == NULL) { |
kitten_puts(3, 14, "Error: Failed to open the downloaded package. Installation aborted."); |
free(buff); |
return(NULL); |
} |
zipfilecrc = crc32_init(); |
while ((buffreadres = read(fileno(*zipfd), buff, 4096)) > 0) { |
crc32_feed(&zipfilecrc, buff, buffreadres); |
} |
crc32_finish(&zipfilecrc); |
fclose(*zipfd); |
free(buff); |
if (zipfilecrc != remotecrc) { |
kitten_puts(3, 13, "Error: Downloaded package had wrong CRC. Installation aborted."); |
return(NULL); |
} |
} /* if (zipfile[0] == 0) */ |
#endif |
/* Now let's check the content of the zip file */ |
*zipfd = fopen(zipfile, "rb"); |
if (*zipfd == NULL) { |
kitten_puts(3, 8, "Error: Invalid zip archive! Package not installed."); |
return(NULL); |
} |
ziplinkedlist = zip_listfiles(*zipfd); |
if (ziplinkedlist == NULL) { |
kitten_puts(3, 8, "Error: Invalid zip archive! Package not installed."); |
fclose(*zipfd); |
return(NULL); |
} |
/* if updating, load the list of files belonging to the current package */ |
if ((flags & PKGINST_UPDATE) != 0) { |
flist = pkg_loadflist(pkgname, dosdir); |
} else { |
flist = NULL; |
} |
/* Verify that there's no collision with existing local files, look for the appinfo presence, get rid of sources if required, and rename BAT links into COM files */ |
appinfopresence = 0; |
prevzipnode = NULL; |
for (curzipnode = ziplinkedlist; curzipnode != NULL;) { |
/* change all slashes to backslashes, and switch into all-lowercase */ |
slash2backslash(curzipnode->filename); |
strtolower(curzipnode->filename); |
/* remove 'directory' ZIP entries to avoid false alerts about directory already existing */ |
if ((curzipnode->flags & ZIP_FLAG_ISADIR) != 0) { |
curzipnode->filename[0] = 0; /* mark it "empty", will be removed in a short moment */ |
} |
/* if --nosource specified, skip sources */ |
if ((flags & PKGINST_NOSOURCE) != 0) { |
if (fdnpkg_strcasestr(curzipnode->filename, "source\\") == curzipnode->filename) { /* drop this file */ |
curzipnode->filename[0] = 0; /* in fact, we just mark the file as 'empty' on the filename.. see below */ |
} |
} |
/* is it a "link file"? */ |
if (fdnpkg_strcasestr(curzipnode->filename, "links\\") == curzipnode->filename) { |
/* skip links, if that's what the user wants */ |
if ((flags & PKGINST_SKIPLINKS) != 0) { |
curzipnode->filename[0] = 0; /* in fact, we just mark the file as 'empty' on the filename.. see later below */ |
} else { |
/* if it's a *.BAT link, then rename it to *.COM */ |
char *ext = getfext(curzipnode->filename); |
if (strcasecmp(ext, "bat") == 0) sprintf(ext, "com"); |
} |
} |
if (curzipnode->filename[0] == 0) { /* ignore empty filenames (maybe it was empty originally, or has been emptied because it's a dropped source or link) */ |
if (prevzipnode == NULL) { /* take the item out of the list */ |
ziplinkedlist = curzipnode->nextfile; |
free(curzipnode); /* free the item */ |
curzipnode = ziplinkedlist; |
} else { |
prevzipnode->nextfile = curzipnode->nextfile; |
free(curzipnode); /* free the item */ |
curzipnode = prevzipnode->nextfile; |
} |
continue; /* go to the next item */ |
} |
/* validate that the file has a valid filename (8+3, no shady chars...) */ |
if (validfilename(curzipnode->filename) != 0) { |
kitten_puts(3, 23, "Error: Package contains an invalid filename:"); |
printf(" %s\n", curzipnode->filename); |
zip_freelist(&ziplinkedlist); |
fclose(*zipfd); |
return(NULL); |
} |
/* look out for collisions with already existing files (unless we are |
* updating the package and the local file belongs to it */ |
shortfile = computelocalpath(curzipnode->filename, fname, dosdir, dirlist); |
mapdrives(fname, mapdrv); |
strcat(fname, shortfile); |
if ((findfileinlist(flist, fname) == NULL) && (fileexists(fname) != 0)) { |
kitten_puts(3, 9, "Error: Package contains a file that already exists locally:"); |
printf(" %s\n", fname); |
zip_freelist(&ziplinkedlist); |
fclose(*zipfd); |
return(NULL); |
} |
/* abort if any entry is encrypted */ |
if ((curzipnode->flags & ZIP_FLAG_ENCRYPTED) != 0) { |
kitten_printf(3, 20, "Error: Package contains an encrypted file:"); |
puts(""); |
printf(" %s\n", curzipnode->filename); |
zip_freelist(&ziplinkedlist); |
fclose(*zipfd); |
return(NULL); |
} |
/* abort if any file is compressed with an unsupported method */ |
if ((curzipnode->compmethod != 0/*store*/) && (curzipnode->compmethod != 8/*deflate*/) && (curzipnode->compmethod != 14/*lzma*/)) { /* unsupported compression method */ |
kitten_printf(8, 2, "Error: Package contains a file compressed with an unsupported method (%d):", curzipnode->compmethod); |
puts(""); |
printf(" %s\n", curzipnode->filename); |
zip_freelist(&ziplinkedlist); |
fclose(*zipfd); |
return(NULL); |
} |
if (strcmp(curzipnode->filename, appinfofile) == 0) appinfopresence = 1; |
prevzipnode = curzipnode; |
curzipnode = curzipnode->nextfile; |
} |
/* if appinfo file not found, this is not a real FreeDOS package */ |
if (appinfopresence != 1) { |
kitten_printf(3, 12, "Error: Package do not contain the %s file! Not a valid FreeDOS package.", appinfofile); |
puts(""); |
zip_freelist(&ziplinkedlist); |
fclose(*zipfd); |
return(NULL); |
} |
return(ziplinkedlist); |
} |
/* install a package that has been prepared already. returns 0 on success, |
* or a negative value on error, or a positive value on warning */ |
int pkginstall_installpackage(char *pkgname, char *dosdir, struct customdirs *dirlist, struct ziplist *ziplinkedlist, FILE *zipfd, char *mapdrv) { |
char *buff; |
char *fulldestfilename; |
char packageslst[64]; |
char *shortfile; |
long filesextractedsuccess = 0, filesextractedfailure = 0; |
struct ziplist *curzipnode; |
FILE *lstfd; |
sprintf(packageslst, "packages\\%s.lst", pkgname); /* Prepare the packages/xxxx.lst filename string for later use */ |
buff = malloc(512); |
fulldestfilename = malloc(1024); |
if ((buff == NULL) || (fulldestfilename == NULL)) { |
kitten_puts(8, 0, "Out of memory!"); |
zip_freelist(&ziplinkedlist); |
free(buff); |
free(fulldestfilename); |
return(-1); |
} |
/* create the %DOSDIR%/packages directory, just in case it doesn't exist yet */ |
sprintf(buff, "%s\\packages\\", dosdir); |
mkpath(buff); |
/* open the lst file */ |
sprintf(buff, "%s\\%s", dosdir, packageslst); |
mapdrives(buff, mapdrv); |
lstfd = fopen(buff, "wb"); /* opening it in binary mode, because I like to have control over line terminators (CR/LF) */ |
if (lstfd == NULL) { |
kitten_printf(3, 10, "Error: Could not create %s!", buff); |
puts(""); |
zip_freelist(&ziplinkedlist); |
free(buff); |
free(fulldestfilename); |
return(-2); |
} |
/* write list of files in zip into the lst, and create the directories structure */ |
for (curzipnode = ziplinkedlist; curzipnode != NULL; curzipnode = curzipnode->nextfile) { |
int unzip_result; |
if ((curzipnode->flags & ZIP_FLAG_ISADIR) != 0) continue; /* skip directories */ |
if (strcasecmp(curzipnode->filename, packageslst) == 0) continue; /* skip silently the package.lst file, if found */ |
shortfile = computelocalpath(curzipnode->filename, buff, dosdir, dirlist); /* substitute paths to custom dirs */ |
/* log the filename to packages\pkg.lst (with original, unmapped drive) */ |
fprintf(lstfd, "%s%s\r\n", buff, shortfile); |
/* remap drive letter, if needed (AFTER writing to lstfd) */ |
mapdrives(buff, mapdrv); |
/* create the path, just in case it doesn't exist yet */ |
mkpath(buff); |
sprintf(fulldestfilename, "%s%s", buff, shortfile); |
/* Now unzip the file */ |
unzip_result = zip_unzip(zipfd, curzipnode, fulldestfilename); |
if (unzip_result != 0) { |
kitten_printf(8, 3, "Error while extracting '%s' to '%s'!", curzipnode->filename, fulldestfilename); |
printf(" [%d]\n", unzip_result); |
filesextractedfailure += 1; |
} else { |
printf(" %s -> %s\n", curzipnode->filename, buff); |
filesextractedsuccess += 1; |
} |
/* if it's a LINK file, recompute a new content */ |
if (islinkfile(curzipnode->filename) != 0) { |
unmapdrives(buff, mapdrv); |
processlinkfile(fulldestfilename, dosdir, dirlist, buff); |
} |
} |
fclose(lstfd); |
/* free the ziplist and close file descriptor */ |
zip_freelist(&ziplinkedlist); |
free(buff); |
free(fulldestfilename); |
kitten_printf(3, 19, "Package %s installed: %ld files extracted, %ld errors.", pkgname, filesextractedsuccess, filesextractedfailure); |
puts(""); |
return(filesextractedfailure); |
} |
/pkginst/pkginst.h |
---|
0,0 → 1,17 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2012-2017 Mateusz Viste |
*/ |
#ifndef pkginst_sentinel |
#define pkginst_sentinel |
#include "pkgdb.h" |
#include "loadconf.h" /* required for struct customdirs */ |
int is_package_installed(char *pkgname, char *dosdir, char *mapdrv); |
struct ziplist *pkginstall_preparepackage(struct pkgdb *pkgdb, char *pkgname, char *tempdir, char *localfile, int nosourceflag, char **repolist, FILE **zipfd, char *proxy, int proxyport, char *downloadingstring, char *dosdir, struct customdirs *dirlist, char *buffmem1k, char *mapdrv); |
int pkginstall_installpackage(char *pkgname, char *dosdir, struct customdirs *dirlist, struct ziplist *ziplinkedlist, FILE *zipfd, char *mapdrv); |
int validate_package_not_installed(char *pkgname, char *dosdir, char *mapdrv); |
#endif |
/pkginst/pkgrem.c |
---|
0,0 → 1,184 |
/* |
* This file is part of the FDNPKG project. |
* Copyright (C) Mateusz Viste 2012-2016. All rights reserved. |
*/ |
#include <ctype.h> /* toupper() */ |
#include <stdio.h> |
#include <string.h> /* strlen() */ |
#include <stdlib.h> /* free() */ |
#include <unistd.h> /* rmdir(), unlink() */ |
#ifdef __WATCOMC__ |
#include <direct.h> /* watcom needs this for the rmdir() prototype */ |
#endif |
#include "fileexst.h" |
#include "getdelim.h" |
#include "helpers.h" /* slash2backslash() */ |
#include "kprintf.h" |
#include "pkgrem.h" |
#include "rtrim.h" |
#include "version.h" |
struct dirliststruct { |
struct dirliststruct *next; |
char dirname[2]; /* this must be the last item in the structure */ |
}; |
/* adds a directory to dirlist, if not already present */ |
static struct dirliststruct *rememberdir(struct dirliststruct *dirlist, char *path) { |
struct dirliststruct *res; |
/* if already present, do nothing */ |
for (res = dirlist; res != NULL; res = res->next) { |
if (strcasecmp(res->dirname, path) == 0) return(dirlist); |
} |
/* not in the list yet - add it */ |
res = malloc(sizeof(struct dirliststruct) + strlen(path)); |
if (res == NULL) { /* out of memory */ |
kitten_printf(4, 3, "Out of memory! Could not store directory %s!", path); |
puts(""); |
return(NULL); |
} |
strcpy(res->dirname, path); |
res->next = dirlist; |
return(res); |
} |
/* explode a path into subdirectories, and remember each one inside dirlist */ |
static struct dirliststruct *rememberpath(struct dirliststruct *dirlist, char *path) { |
int x, gameover = 0; |
/* iterate on the path, and add each subdirectory */ |
for (x = 0;; x++) { |
switch (path[x]) { |
case 0: |
gameover = 1; |
case '/': |
case '\\': |
path[x] = 0; |
dirlist = rememberdir(dirlist, path); |
path[x] = '\\'; |
} |
if (gameover != 0) break; |
} |
return(dirlist); |
} |
/* removes a package from the system. Returns 0 on success, non-zero otherwise */ |
int pkgrem(char *pkgname, char *dosdir, char *mapdrv) { |
char fpath[512]; |
char shellcmd[512]; |
char *lineptr; |
FILE *flist; |
int getdelimlen; |
int lastdirsep; |
int x; |
size_t getdelimcount = 0; |
struct dirliststruct *dirlist = NULL; /* used to remember directories to remove */ |
char pkglistfile[512]; |
/* Check if the file %DOSDIR%\packages\pkgname.lst exists (if not, the package is not installed) */ |
sprintf(fpath, "%s\\packages\\%s.lst", dosdir, pkgname); |
mapdrives(fpath, mapdrv); |
if (fileexists(fpath) == 0) { /* file does not exist */ |
kitten_printf(4, 0, "Package %s is not installed, so not removed.", pkgname); |
puts(""); |
return(-1); |
} |
/* open the file %DOSDIR%\packages\pkgname.lst */ |
flist = fopen(fpath, "r"); |
if (flist == NULL) { |
kitten_puts(4, 1, "Error opening lst file!"); |
return(-2); |
} |
sprintf(pkglistfile, "packages\\%s.lst", pkgname); |
/* remove all files/folders listed in pkgname.lst but NOT pkgname.lst */ |
for (;;) { |
/* read line from file */ |
lineptr = NULL; |
getdelimlen = getdelim(&lineptr, &getdelimcount, '\n', flist); |
if (getdelimlen < 0) { |
free(lineptr); |
break; |
} |
rtrim(lineptr); /* right-trim the filename */ |
slash2backslash(lineptr); /* change all / to \ */ |
if ((lineptr[0] == 0) || (lineptr[0] == '\r') || (lineptr[0] == '\n')) { |
free(lineptr); /* free the memory occupied by the line */ |
continue; /* skip empty lines */ |
} |
/* remap drive */ |
mapdrives(lineptr, mapdrv); |
/* remember the path part for removal later */ |
lastdirsep = -1; |
for (x = 1; lineptr[x] != 0; x++) { |
if ((lineptr[x] == '\\') && (lineptr[x - 1] != ':')) lastdirsep = x; |
} |
if (lastdirsep > 0) { |
lineptr[lastdirsep] = 0; |
dirlist = rememberpath(dirlist, lineptr); |
lineptr[lastdirsep] = '\\'; |
} |
/* if it's a directory, skip it */ |
if (lineptr[strlen(lineptr) - 1] == '\\') { |
free(lineptr); /* free the memory occupied by the line */ |
continue; |
} |
/* it's a file - remove it */ |
if (strcasecmp(pkglistfile, lineptr) != 0) { /* never delete pkgname.lst at this point - it will be deleted later */ |
if ((lineptr[0] == '\\') || (lineptr[1] == ':')) { /* this is an absolute path */ |
sprintf(shellcmd, "%s", lineptr); |
} else { /* else it's a relative path starting at %dosdir% */ |
sprintf(shellcmd, "%s\\%s", dosdir, lineptr); |
} |
kitten_printf(4, 4, "removing %s", shellcmd); |
puts(""); |
unlink(shellcmd); |
} |
free(lineptr); /* free the memory occupied by the line */ |
} |
/* close the file */ |
fclose(flist); |
/* iterate through dirlist and remove directories if empty, from longest to shortest */ |
while (dirlist != NULL) { |
struct dirliststruct *dirlistpos, *previousdir; |
/* find the longest path, and put it on top */ |
previousdir = dirlist; |
for (dirlistpos = dirlist->next; dirlistpos != NULL; dirlistpos = dirlistpos->next) { |
if (strlen(dirlistpos->dirname) > strlen(dirlist->dirname)) { |
previousdir->next = dirlistpos->next; |
dirlistpos->next = dirlist; |
dirlist = dirlistpos; |
dirlistpos = previousdir; |
} else { |
previousdir = dirlistpos; |
} |
} |
if ((dirlist->dirname[0] == '\\') || (dirlist->dirname[1] == ':')) { /* this is an absolute path */ |
sprintf(shellcmd, "%s", dirlist->dirname); |
} else { /* else it's a relative path starting at %dosdir% */ |
sprintf(shellcmd, "%s\\%s", dosdir, dirlist->dirname); |
} |
/* printf("RMDIR %s\n", shellcmd); */ |
rmdir(shellcmd); |
/* free the allocated memory for this entry */ |
dirlistpos = dirlist; |
dirlist = dirlistpos->next; |
free(dirlistpos); |
} |
/* remove %DOSDIR%\packages\pkgname.lst */ |
unlink(fpath); |
kitten_printf(4, 5, "Package %s has been removed.", pkgname); |
puts(""); |
return(0); |
} |
/pkginst/pkgrem.h |
---|
0,0 → 1,9 |
/* |
* This file is part of the FDNPKG project. |
* Copyright (C) Mateusz Viste 2012-2016. All rights reserved. |
*/ |
#ifndef pkgrem_sentinel |
#define pkgrem_sentinel |
int pkgrem(char *pkgname, char *dosdir, char *mapdrv); |
#endif |
/pkginst/readenv.c |
---|
0,0 → 1,46 |
/* |
* This file is part of FDNPKG. |
* |
* Reads environment variables that will be used by FDNPKG and FDINST. |
* Returns 0 on success, non-zero otherwise. |
* |
* Copyright (C) 2012-2016 Mateusz Viste |
*/ |
#include <stdio.h> /* snprintf() */ |
#include <stdlib.h> /* getenv() */ |
#include "kprintf.h" /* kprintf(), kputs() */ |
#include "readenv.h" |
int readenv(char **dosdir, char **tempdir, char *cfgfile, int cfgfilemaxlen) { |
char *cfg; |
/* check if %DOSDIR% is set, and retrieve it */ |
*dosdir = getenv("DOSDIR"); |
if (*dosdir == NULL) { |
kitten_puts(2, 2, "%DOSDIR% not set! You should make it point to the FreeDOS main directory."); |
kitten_puts(2, 3, "Example: SET DOSDIR=C:\\FDOS"); |
return(-1); |
} |
/* check if %TEMP% is set, and retrieve it */ |
*tempdir = getenv("TEMP"); |
if (*tempdir == NULL) { |
kitten_puts(2, 0, "%TEMP% not set! You should make it point to a writeable directory."); |
kitten_puts(2, 1, "Example: SET TEMP=C:\\TEMP"); |
return(-2); |
} |
/* look for the FDNPKG.CFG env. variable */ |
cfg = getenv("FDNPKG.CFG"); |
cfgfilemaxlen -= 1; /* make room for the null terminator */ |
if (cfg != NULL) { |
snprintf(cfgfile, cfgfilemaxlen, "%s", cfg); |
} else { /* not set, so fallback to hardcoded location */ |
snprintf(cfgfile, cfgfilemaxlen, "%s\\bin\\fdnpkg.cfg", *dosdir); |
} |
return(0); |
} |
/pkginst/readenv.h |
---|
0,0 → 1,15 |
/* |
* This file is part of FDNPKG. |
* |
* Reads environment variables that will be used by FDNPKG and FDINST. |
* Returns 0 on success, non-zero otherwise. |
* |
* Copyright (C) 2012-2016 Mateusz Viste |
*/ |
#ifndef READENV_H_SENTINEL |
#define READENV_H_SENTINEL |
int readenv(char **dosdir, char **tempdir, char *cfgfile, int cfgfilemaxlen); |
#endif |
/pkginst/rtrim.c |
---|
0,0 → 1,47 |
/* |
* Right trim any space, tab, cr or lf |
* Copyright (C) 2012-2016 Mateusz Viste |
*/ |
#include "rtrim.h" |
void rtrim(char *str) { |
int x, realendofstr = 0; |
for (x = 0; str[x] != 0; x++) { |
switch (str[x]) { |
case ' ': |
case '\t': |
case '\r': |
case '\n': |
break; |
default: |
realendofstr = x + 1; |
break; |
} |
} |
str[realendofstr] = 0; |
} |
void trim(char *str) { |
int x, y, firstchar = -1, lastchar = -1; |
for (x = 0; str[x] != 0; x++) { |
switch (str[x]) { |
case ' ': |
case '\t': |
case '\n': |
case '\r': |
break; |
default: |
if (firstchar < 0) firstchar = x; |
lastchar = x; |
break; |
} |
} |
str[lastchar + 1] = 0; /* right trim */ |
if (firstchar > 0) { /* left trim (shift to the left ) */ |
y = 0; |
for (x = firstchar; str[x] != 0; x++) str[y++] = str[x]; |
str[y] = 0; |
} |
} |
/pkginst/rtrim.h |
---|
0,0 → 1,14 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2012-2016 Mateusz Viste |
* |
* trim spaces, tabs, cr's and lf's from both left and right ends of a string |
*/ |
#ifndef trim_sentinel |
#define trim_sentinel |
void rtrim(char *str); |
void trim(char *str); |
#endif |
/pkginst/showinst.c |
---|
0,0 → 1,275 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2013-2017 Mateusz Viste. All rights reserved. |
*/ |
#include <stdio.h> |
#include <ctype.h> /* tolower() */ |
#include <stdlib.h> /* atoi(), qsort() - not using it after all, redefining it manually later */ |
#include <string.h> /* strlen() */ |
#include <sys/types.h> |
/* opendir() and friends */ |
#ifdef __WATCOMC__ |
#include <direct.h> |
#else |
#include <dirent.h> |
#endif |
#include "fdnpkg.h" /* PKGINST_UPDATE */ |
#include "fileexst.h" |
#include "getdelim.h" |
#include "helpers.h" /* fdnpkg_strcasestr(), slash2backslash()... */ |
#include "kprintf.h" |
#include "libunzip.h" /* zip_freelist()... */ |
#include "lsm.h" |
#include "pkgdb.h" |
#include "pkginst.h" |
#include "pkgrem.h" |
#include "rtrim.h" |
#include "showinst.h" /* include self for control */ |
#include "version.h" |
/* this is a wrapper around strcasecmp(), to be used by qsort() */ |
static int strcompare(const void *str1, const void *str2) { |
char **s1 = (char **)str1; |
char **s2 = (char **)str2; |
return(strcasecmp(*s1, *s2)); |
} |
/* clears current line */ |
static void clrline(void) { |
printf("\r \r"); |
} |
static int loadinstpkglist(char **packagelist, char **packagelist_ver, int packagelist_maxlen, char *filterstr, char *dosdir) { |
DIR *dp; |
int packagelist_len = 0, x; |
struct dirent *ep; |
#define verstr_maxlen 64 |
char pkgdir[512], lsmfilename[1024], verstr[verstr_maxlen]; |
sprintf(pkgdir, "%s\\packages", dosdir); |
dp = opendir(pkgdir); |
if (dp != NULL) { |
while ((ep = readdir(dp)) != NULL) { |
if (ep->d_name[0] != '.') { /* ignore '.', '..', and hidden directories */ |
if (strlen(ep->d_name) > 4) { |
int tlen = strlen(ep->d_name); |
if ((ep->d_name[tlen - 4] != '.') || (tolower(ep->d_name[tlen - 3]) != 'l') || (tolower(ep->d_name[tlen - 2]) != 's') || (tolower(ep->d_name[tlen - 1]) != 't')) continue; /* if it's not an .lst file, skip it silently */ |
if (filterstr != NULL) { |
if (fdnpkg_strcasestr(ep->d_name, filterstr) == NULL) continue; /* if it's not matching the non-NULL filter, skip it */ |
} |
if (packagelist_len >= packagelist_maxlen) { |
closedir(dp); |
return(-1); /* if not enough place in the list - return an error */ |
} |
packagelist[packagelist_len] = strdup(ep->d_name); |
packagelist[packagelist_len][strlen(packagelist[packagelist_len]) - 4] = 0; /* cut out the .lst extension */ |
packagelist_len += 1; |
} |
} |
} |
closedir(dp); |
qsort(packagelist, packagelist_len, sizeof (char **), strcompare); /* sort the package list */ |
for (x = 0; x < packagelist_len; x++) { |
/* for each package, load the metadata from %DOSDIR\APPINFO\*.lsm */ |
sprintf(lsmfilename, "%s\\appinfo\\%s.lsm", dosdir, packagelist[x]); |
if (readlsm(lsmfilename, verstr, verstr_maxlen) != 0) sprintf(verstr, "(unknown version)"); |
packagelist_ver[x] = strdup(verstr); |
} |
return(packagelist_len); |
} else { |
kitten_printf(9, 0, "Error: Could not access the %s directory.", pkgdir); |
puts(""); |
return(-1); |
} |
} |
#define packagelist_maxlen 1024 |
void showinstalledpkgs(char *filterstr, char *dosdir) { |
char *packagelist[packagelist_maxlen]; |
char *packagelist_ver[packagelist_maxlen]; |
int packagelist_len, x; |
/* load the list of packages */ |
packagelist_len = loadinstpkglist(packagelist, packagelist_ver, packagelist_maxlen, filterstr, dosdir); /* Populate the packages list */ |
if (packagelist_len < 0) return; |
if (packagelist_len == 0) { |
kitten_puts(5, 0, "No package matched the search."); |
return; |
} |
/* iterate through all packages */ |
for (x = 0; x < packagelist_len; x++) { |
/* print the package/version couple on screen */ |
printf("%s %s\n", packagelist[x], packagelist_ver[x]); |
} |
} |
/* displays the list of available updates for local packages (or a single package if pkg is not NULL). Returns 0 if some updates are found, non zero otherwise. */ |
int checkupdates(char *dosdir, struct pkgdb *pkgdb, char **repolist, char *pkg, char *tempdir, int flags, struct customdirs *dirlist, char *proxy, int proxyport, char *downloadingstring, char *mapdrv) { |
struct pkgdb *curpkg; |
struct pkgrepo *currepo; |
char *packagelist[packagelist_maxlen]; |
char *packagelist_ver[packagelist_maxlen]; |
int packagelist_len, x, foundupdate = 0, totalupdatesfound = 0; |
int packages_updated = 0, packages_updatefailed = 0; |
packagelist_len = loadinstpkglist(packagelist, packagelist_ver, packagelist_maxlen, NULL, dosdir); |
for (x = 0; x < packagelist_len; x++) { |
if (pkg != NULL) { |
if (strcasecmp(pkg, packagelist[x]) != 0) continue; /* if we got asked for a specific package, skip all other packages. */ |
} else { /* else display a progress so slower PCs don't think we are freezed */ |
long percprogress = x; /* long, just in case we have more than 3'200 packages installed... */ |
percprogress *= 100; |
percprogress /= packagelist_len; |
kitten_printf(10, 7, "Looking for updates..."); |
printf(" %ld%% (%s) \r", percprogress, packagelist[x]); /* empty spaces trailing for flushing the previous content on the line */ |
} |
for (curpkg = pkgdb; curpkg != NULL; curpkg = curpkg->nextpkg) { /* iterate through packages */ |
if (strcasecmp(curpkg->name, packagelist[x]) == 0) { |
foundupdate = 0; |
for (currepo = curpkg->repolist; currepo != NULL; currepo = currepo->nextrepo) { /* check for possible newer version in every repo */ |
if (isversionnewer(packagelist_ver[x], currepo->version) > 0) { /* isversionnewer() returns 1 if version is newer */ |
if (foundupdate == 0) { |
foundupdate = 1; |
totalupdatesfound += 1; |
if (pkg == NULL) { |
clrline(); |
kitten_printf(10, 0, "%s (local version: %s)", packagelist[x], packagelist_ver[x]); |
puts(""); |
} |
} |
if (pkg == NULL) { |
clrline(); |
printf(" "); |
kitten_printf(10, 1, "version %s at %s", currepo->version, repolist[currepo->repo]); |
puts(""); |
} |
} |
} |
/* actually upgrade the package, if requested so */ |
if (foundupdate != 0) { |
if (flags & PKGINST_UPDATE) { |
FILE *zipfilefd; |
struct ziplist *zipfileidx; |
char buffmem1k[1024]; |
clrline(); |
kitten_printf(10, 3, "An update of '%s' has been found. Update in progress...", packagelist[x]); |
puts(""); |
packages_updatefailed += 1; /* increment the updatefailed counter - later we will decrement it if we're okay */ |
zipfileidx = pkginstall_preparepackage(pkgdb, packagelist[x], tempdir, NULL, flags, repolist, &zipfilefd, proxy, proxyport, downloadingstring, dosdir, dirlist, buffmem1k, mapdrv); |
if (zipfileidx != NULL) { |
if (pkgrem(packagelist[x], dosdir, mapdrv) != 0) { |
/* ooops, package removal failed... */ |
zip_freelist(&zipfileidx); |
} else { /* pkgrem == 0 */ |
pkginstall_installpackage(packagelist[x], dosdir, dirlist, zipfileidx, zipfilefd, mapdrv); |
packages_updated += 1; |
packages_updatefailed -= 1; /* decrement the updatefailed counter to leverage the fact we incremented it without reason earlier */ |
} |
fclose(zipfilefd); |
} |
} |
puts(""); /* add a line feed to visually separate packages */ |
} |
break; /* get out of the loop to get over the next local package */ |
} |
} |
} |
if (pkg == NULL) { |
clrline(); |
kitten_printf(10, 5, "%d package update(s) found.", totalupdatesfound); |
puts(""); |
if (flags & PKGINST_UPDATE) { |
kitten_printf(10, 4, "%d package(s) updated, %d package(s) failed.", packages_updated, packages_updatefailed); |
puts(""); |
} |
} |
if (foundupdate != 0) { |
return(0); |
} else { |
return(-1); |
} |
} |
/* frees a linked list of filenames */ |
void pkg_freeflist(struct flist_t *flist) { |
while (flist != NULL) { |
struct flist_t *victim = flist; |
flist = flist->next; |
free(victim); |
} |
} |
/* returns a linked list of the files that belong to package pkgname */ |
struct flist_t *pkg_loadflist(char *pkgname, char *dosdir) { |
struct flist_t *res = NULL, *newnode; |
FILE *fd; |
char *lineptr; |
char buff[512]; |
int getdelimlen, fnamelen; |
size_t getdelimcount = 0; |
sprintf(buff, "%s\\packages\\%s.lst", dosdir, pkgname); |
if (fileexists(buff) == 0) { /* file does not exist */ |
kitten_printf(9, 1, "Error: Local package %s not found.", pkgname); |
puts(""); |
return(NULL); |
} |
fd = fopen(buff, "rb"); |
if (fd == NULL) { |
kitten_puts(4, 1, "Error opening lst file!"); |
return(NULL); |
} |
/* iterate through all lines of the file */ |
for (;;) { |
lineptr = NULL; |
getdelimlen = getdelim(&lineptr, &getdelimcount, '\n', fd); |
if (getdelimlen < 0) { /* EOF */ |
free(lineptr); |
break; |
} |
rtrim(lineptr); /* right-trim the filename */ |
slash2backslash(lineptr); /* change all / to \ */ |
if ((lineptr[0] == 0) || (lineptr[0] == '\r') || (lineptr[0] == '\n')) continue; /* skip empty lines */ |
if (lineptr[strlen(lineptr) - 1] == '\\') continue; /* skip directories */ |
if ((lineptr[0] == '\\') || (lineptr[1] == ':')) { /* this is an absolute path */ |
fnamelen = snprintf(buff, sizeof(buff), "%s", lineptr); |
} else { /* else it's a relative path starting at %dosdir% */ |
fnamelen = snprintf(buff, sizeof(buff), "%s\\%s\n", dosdir, lineptr); |
} |
free(lineptr); /* free the memory occupied by the line */ |
/* add the new node to the result */ |
newnode = malloc(sizeof(struct flist_t) + fnamelen); |
if (newnode == NULL) { |
kitten_printf(2, 14, "Out of memory! (%s)", "malloc failure"); |
continue; |
} |
newnode->next = res; |
strcpy(newnode->fname, buff); |
res = newnode; |
} |
fclose(fd); |
return(res); |
} |
/* Prints files owned by a package */ |
void listfilesofpkg(char *pkgname, char *dosdir) { |
struct flist_t *flist, *flist_ptr; |
/* load the list of files belonging to pkgname */ |
flist = pkg_loadflist(pkgname, dosdir); |
/* display each filename on screen */ |
for (flist_ptr = flist; flist_ptr != NULL; flist_ptr = flist_ptr->next) { |
printf("%s\n", flist_ptr->fname); |
} |
/* free the list of files */ |
pkg_freeflist(flist); |
} |
/pkginst/showinst.h |
---|
0,0 → 1,16 |
/* |
* This file is part of FDNPKG |
* Copyright (C) 2013-2017 Mateusz Viste |
*/ |
#include "fdnpkg.h" |
#include "pkgdb.h" |
#ifndef showinst_h_sentinel |
#define showinst_h_sentinel |
void pkg_freeflist(struct flist_t *flist); |
struct flist_t *pkg_loadflist(char *pkgname, char *dosdir); |
void showinstalledpkgs(char *filterstr, char *dosdir); |
int checkupdates(char *dosdir, struct pkgdb *pkgdb, char **repolist, char *pkg, char *tempdir, int flags, struct customdirs *dirlist, char *proxy, int proxyport, char *downloadingstring, char *mapdrv); |
void listfilesofpkg(char *pkgname, char *dosdir); |
#endif |