Subversion Repositories SvarDOS

Compare Revisions

Ignore whitespace Rev 218 → Rev 219

/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