/*
 * access.c  -  File access routines
 *
 * Copyright (C) 1998-2003 Gero Kuhlmann <gero@gkminix.han.de>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: access.c,v 1.4 2003/01/25 23:29:44 gkminix Exp $
 */

#include <common.h>
#include <nblib.h>
#include "privlib.h"



/*
 * Extract path elements from string
 */
struct paths {
	struct paths *next;
	char         *name;
};

static struct paths *extractpath(str)
char *str;
{
  struct paths *plist = NULL;
  struct paths *pp;
  char *cp;
  size_t len;

  while (str != NULL) {
	cp = strchr(str, ':');
	len = (cp == NULL) ? strlen(str) : cp - str;
	if (len > 0) {
		pp = (struct paths *)nbmalloc(sizeof(struct paths));
		pp->name = (char *)nbmalloc(len + 2);
		strncpy(pp->name, str, len);
		pp->name[len] = '\0';
		pp->next = plist;
		plist = pp;
	}
	if (cp != NULL)
		cp++;
	str = cp;
  }
  return(plist);
}



/*
 * Actually normalize a path
 */
static struct paths *donorm(pathname, maindir)
char *pathname;
char *maindir;
{
  struct paths *pathlist, *dirlist, *pp, *dp, *np;
  struct paths *newlist = NULL;
  size_t len;

  /* Extract path elements */
  pathlist = extractpath(pathname);
  dirlist = extractpath(maindir);

  /* If dirlist is empty, use the local directory as the default */
  if (dirlist == NULL) {
	dirlist = (struct paths *)nbmalloc(sizeof(struct paths));
	copystr(&(dirlist->name), ".");
	dirlist->next = NULL;
  }

  /* Make all relative paths absolute to the elements in dirlist */
  while (pathlist != NULL) {
	pp = pathlist;
	pathlist = pp->next;
	if (pp->name[0] == '/' || pp->name[0] == '.') {
		pp->next = newlist;
		newlist = pp;
	} else {
		dp = dirlist;
		while (dp != NULL) {
			len = strlen(pp->name) + strlen(dp->name) + 1;
			np = (struct paths *)nbmalloc(sizeof(struct paths));
			np->name = (char *)nbmalloc(len + 2);
			sprintf(np->name, "%s/%s", dp->name, pp->name);
			np->next = newlist;
			newlist = np;
			dp = dp->next;
		}
		free(pp->name);
		free(pp);
	}
  }

  /* Delete directory list, we don't need it anymore */
  while (dirlist != NULL) {
	dp = dirlist;
	dirlist = dirlist->next;
	free(dp->name);
	free(dp);
  }

  /* Normalize all paths which are relative to the netboot directory */
  dp = NULL;
  np = newlist;
  while (np != NULL) {
	if (!strncmp(np->name, "//", 2)) {
		len = strlen(np->name) + strlen(netbootdir) - 1;
		pp = (struct paths *)nbmalloc(sizeof(struct paths));
		pp->name = (char *)nbmalloc(len + 2);
		sprintf(pp->name, "%s%s", netbootdir, &(np->name[1]));
		pp->next = np->next;
		if (dp == NULL)
			newlist = pp;
		else
			dp->next = pp;
		free(np->name);
		free(np);
		np = pp;
	}
	dp = np;
	np = np->next;
  }
  return(newlist);
}



/*
 * Normalize a path name.
 */
void setpath(pathname, maindir)
char **pathname;
char  *maindir;
{
  struct paths *pathlist, *pp;
  size_t retlen;
  char *newname, *cp;

  /* Normalize path names */
  if (*pathname == NULL || (pathlist = donorm(*pathname, maindir)) == NULL)
	return;
  free(*pathname);

  /* Determine length of return string */
  retlen = 0;
  pp = pathlist;
  while (pp != NULL) {
	retlen += strlen(pp->name) + 1;
	pp = pp->next;
  }

  /* Generate return string */
  newname = NULL;
  if (pathlist != NULL) {
	cp = newname = (char *)nbmalloc(retlen + 1);
	while (pathlist != NULL) {
		pp = pathlist;
		strcpy(cp, pp->name);
		cp += strlen(pp->name);
		if (pp->next != NULL) {
			*(cp++) = ':';
			*cp     = '\0';
		}
		pathlist = pathlist->next;
		free(pp->name);
		free(pp);
	}
  }
  *pathname = newname;
}



/*
 * Check if a file is readable, and determine it's normalized path name
 */
void checkaccess(filename, maindir)
char **filename;
char  *maindir;
{
  struct paths *pathlist, *pp;
  char *retname;

  /* Actually normalize the file name */
  if (*filename == NULL || (pathlist = donorm(*filename, maindir)) == NULL)
	return;
  free(*filename);

  /* Scan through the normalized file list */
  retname = NULL;
  while (pathlist != NULL) {
	pp = pathlist;
	if (retname == NULL && access(pp->name, R_OK) >= 0)
		copystr(&retname, pp->name);
	pathlist = pathlist->next;
	free(pp->name);
	free(pp);
  }
  *filename = retname;
}



syntax highlighted by Code2HTML, v. 0.9.1