Subversion Repositories SvarDOS

Rev

Rev 614 | Rev 1963 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 * This file is part of the pkg (SvarDOS) project.
 * Copyright (C) Mateusz Viste 2012-2024
 */

#include <ctype.h>    /* toupper() */
#include <stdio.h>
#include <string.h>    /* strlen() */
#include <stdlib.h>    /* free() */
#include <unistd.h>    /* rmdir(), unlink() */
#include <direct.h>  /* watcom needs this for the rmdir() prototype */

#include "helpers.h"   /* slash2backslash() */
#include "kprintf.h"

#include "pkgrem.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, const 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, path); /* "Out of memory! Could not store directory %s!" */
    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(const char *pkgname, const char *dosdir) {
  char fpath[256];
  char buff[256];
  FILE *flist;
  int lastdirsep;
  struct dirliststruct *dirlist = NULL; /* used to remember directories to remove */

  /* open the (legacy) listing file at %DOSDIR%\packages\pkgname.lst
   * if not exists then fall back to appinfo\pkgname.lsm */
  sprintf(fpath, "%s\\packages\\%s.lst", dosdir, pkgname);
  flist = fopen(fpath, "rb");
  if (flist == NULL) {
    sprintf(fpath, "%s\\appinfo\\%s.lsm", dosdir, pkgname);
    flist = fopen(fpath, "rb");
    if (flist == NULL) {
      kitten_printf(4, 0, pkgname); /* "Package %s is not installed, so not removed." */
      puts("");
      return(-1);
    }
  }

  /* remove all files/folders listed in pkgname.lsm but NOT pkgname.lsm */
  while (freadtokval(flist, buff, sizeof(buff), NULL, 0) == 0) {
    int x;

    /* skip empty lines */
    if (buff[0] == 0) continue;

    /* change all slash to backslash */
    slash2backslash(buff);

    /* skip garbage */
    if ((buff[1] != ':') || (buff[2] != '\\')) continue;

    /* trim out CRC information (if present) */
    trimfnamecrc(buff);

    /* remember the path part for removal later */
    lastdirsep = -1;
    for (x = 1; buff[x] != 0; x++) {
      if ((buff[x] == '\\') && (buff[x - 1] != ':')) lastdirsep = x;
    }
    if (lastdirsep > 0) {
      buff[lastdirsep] = 0;
      dirlist = rememberpath(dirlist, buff);
      buff[lastdirsep] = '\\';
    }

    /* if it's a directory, skip it */
    if (buff[strlen(buff) - 1] == '\\') continue;

    /* do not delete pkgname.lst at this point because I am using it (will be
     * deleted later) */
    if (strcasecmp(buff, fpath) == 0) continue;

    /* remove it */
    kitten_printf(4, 4, buff); /* "removing %s" */
    puts("");
    unlink(buff);
  }

  /* close the lsm file */
  fclose(flist);

  /* iterate over 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;
      }
    }
    /* printf("RMDIR %s\n", dirlist->dirname); */
    rmdir(dirlist->dirname);
    /* free the allocated memory for this entry */
    dirlistpos = dirlist;
    dirlist = dirlistpos->next;
    free(dirlistpos);
  }

  /* remove the lst file */
  kitten_printf(4, 4, fpath); /* "removing %s" */
  puts("");
  unlink(fpath);

  kitten_printf(4, 5, pkgname); /* "Package %s has been removed." */
  puts("");
  return(0);
}