view dcclib/fnm2path.c @ 0:c7f6b056b673

First import of vendor version
author Peter Gervai <grin@grin.hu>
date Tue, 10 Mar 2009 13:49:58 +0100
parents
children
line wrap: on
line source

/* Distributed Checksum Clearinghouse
 *
 * Copyright (c) 2008 by Rhyolite Software, LLC
 *
 * This agreement is not applicable to any entity which sells anti-spam
 * solutions to others or provides an anti-spam solution as part of a
 * security solution sold to other entities, or to a private network
 * which employs the DCC or uses data provided by operation of the DCC
 * but does not provide corresponding data to other users.
 *
 * Permission to use, copy, modify, and distribute this software without
 * changes for any purpose with or without fee is hereby granted, provided
 * that the above copyright notice and this permission notice appear in all
 * copies and any distributed versions or copies are either unchanged
 * or not called anything similar to "DCC" or "Distributed Checksum
 * Clearinghouse".
 *
 * Parties not eligible to receive a license under this agreement can
 * obtain a commercial license to use DCC by contacting Rhyolite Software
 * at sales@rhyolite.com.
 *
 * A commercial license would be for Distributed Checksum and Reputation
 * Clearinghouse software.  That software includes additional features.  This
 * free license for Distributed ChecksumClearinghouse Software does not in any
 * way grant permision to use Distributed Checksum and Reputation Clearinghouse
 * software
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND RHYOLITE SOFTWARE, LLC DISCLAIMS ALL
 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL RHYOLITE SOFTWARE, LLC
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 *
 * Rhyolite Software DCC 1.3.103-1.26 $Revision$
 */

#include "dcc_defs.h"
#ifdef DCC_WIN32
#include <direct.h>
#endif

DCC_PATH dcc_homedir;
int dcc_homedir_len = 2;		/* (ensure comparisons fail) */


#ifndef DCC_WIN32
static u_char
trimpath(DCC_PATH path, const DCC_PATH tmp)
{
	const char *s;
	char c, *t, *p;


	/* trim "//", "/./", "../", "/../", or trailing "/" */
	s = tmp;
	if (s[0] == '.' && s[1] == '/')
		s += 2;
	t = path;
	for (;;) {
		c = *s++;
		if (c != '/') {
			*t = c;
			if (c == '\0')
				break;
			++t;
			continue;
		}

		/* check character after '/' */
		c = *s;
		if (c == '/')		/* discard first '/' in "//" */
			continue;
		if (c == '\0'		/* discard trailing '/' */
		    && t != path)
			continue;

		if (c != '.') {
			*t++ = '/';
			continue;
		}

		/* we have seen "/." */
		c = *++s;
		if (c == '/')		/* discard "/." in "/./" */
			continue;

		/* trim trailing "/." */
		if (c == '\0')
			continue;

		if (c != '.'
		    || (*(s+1) != '/' && *(s+1) != '\0')) {
			*t++ = '/';
			*t++ = '.';
			continue;
		}

		/* we have "/../" or "/..\0", so remove last name in target */
		*t = '\0';
		p = strrchr(path, '/');
		if (p) {
			t = p;
			if (t == path)	/* convert "/.." to "/" */
				++t;
		} else {
			t = path;
		}
		++s;			/* advance to '\0' or 2nd '/' */
	}
	if (path[0] == '\0') {
		path[0] = tmp[0] == '/' ? '/' : '.';
		path[1] = '\0';
	}

	return 1;
}
#endif



/* make a relative pathname from a file name and an optional suffix */
u_char					/* 0=too long */
fnm2rel(DCC_PATH new_path, const char *nm, const char *suffix)
{
#ifdef DCC_WIN32
	return fnm2abs(new_path, nm, suffix);
#else
	DCC_PATH tmp;
	int i;
	const char *p, *p1;

	/* the answer is the input pathname if it is null */
	if (!nm || *nm == '\0') {
		new_path[0] = '\0';
		return 0;
	}

	if (suffix) {
		p = tmp;
		i = snprintf(tmp, sizeof(tmp), "%s%s", nm, suffix);
	} else {
		p = nm;
		i = strlen(p);
	}
	if (i >= ISZ(tmp)) {
		/* too long */
		new_path[0] = '\0';
		return 0;
	}
	if (p[dcc_homedir_len] == '/'
	    && !strncmp(p, dcc_homedir, dcc_homedir_len)) {
		p1 = p + dcc_homedir_len;
		do {
			++p1;
		} while (*p1 == '/');
		if (*p1 != '\0')
			p = p1;
	}

	return trimpath(new_path, p);
#endif
}



/* make pathname from an optional suffix and a file name relative to
 *	a path or the home directory */
u_char					/* 0=too long */
fnm2abs(DCC_PATH path,			/* put it here */
	const char *nm, const char *suffix)
{
	DCC_PATH tmp;
	int i;
#ifdef DCC_WIN32
	char *p;
	DWORD lasterror;
#endif

	/* the answer is the input pathname if it is null */
	if (!nm || *nm == '\0') {
		path[0] = '\0';
		return 0;
	}

	if (!suffix)
		suffix = "";

#ifdef DCC_WIN32
	i = snprintf(tmp, sizeof(DCC_PATH), "%s%s", nm, suffix);
	if (i >= ISZ(DCC_PATH)) {
		path[0] = '\0';
		return 0;
	}
	lasterror = GetLastError();
	GetFullPathName(tmp, sizeof(DCC_PATH), path, &p);
	SetLastError(lasterror);
	return 1;
#else
	if (nm[0] == '/' || dcc_homedir[0] == '\0') {
		i = snprintf(tmp, sizeof(tmp), "%s%s", nm, suffix);
	} else {
		i = snprintf(tmp, sizeof(tmp), "%s/%s%s",
			     dcc_homedir, nm, suffix);
	}
	if (i >= ISZ(tmp)) {
		/* too long */
		path[0] = '\0';
		return 0;
	}

	return trimpath(path, tmp);
#endif
}



/* make an absolute pathname from a file name for printing */
const char *
fnm2abs_err(DCC_PATH path, const char *nm)
{
	static DCC_PATH pathbuf;

	if (!path)			/* obviously not thread safe */
		path = pathbuf;

	return fnm2abs(path, nm, 0) ? path : nm;
}



/* make a relative pathname from a file name that must be good */
void
fnm2rel_good(DCC_PATH path, const char *nm, const char* suffix)
{
	if (!fnm2rel(path, nm, suffix))
		dcc_logbad(EX_SOFTWARE, "\"%s%s\" is too long",
			   nm, suffix ? suffix : "");
}



/* remove initial substring of the home directory */
const char *
path2fnm(const char *path)
{
	const char *p;

	if (path[dcc_homedir_len] != '/'
	    || strncmp(path, dcc_homedir, dcc_homedir_len))
		return path;

	p = path+dcc_homedir_len;
	do {
		++p;
	} while (*p == '/');
	if (*p == '\0')
		return path;
	return p;
}



/* change to the DCC home directory */
u_char					/* 0=failed 1=ok */
dcc_cdhome(DCC_EMSG emsg, const char *newdir, u_char rdonly)
{
	DCC_PATH tmp;
	u_char result;

	result = 1;
	if (!newdir)
		newdir = DCC_HOMEDIR;

	if (*newdir == '\0') {
		dcc_pemsg(EX_NOINPUT, emsg,
			  "invalid null DCC home directory");
		newdir = DCC_HOMEDIR;
		result = 0;
	}

	if (!fnm2abs(tmp, newdir, 0)) {
		dcc_pemsg(EX_NOINPUT, emsg,
			  "bad DCC home directory \"%s\"", newdir);
		result = 0;
	}
#ifdef DCC_WIN32
	if (!SetCurrentDirectory(tmp)) {
		dcc_pemsg(EX_NOINPUT, emsg, "SetCurrentDirectory(%s): %s" ,
			  tmp, ERROR_STR());
		return 0;
	}
	if (!getcwd(dcc_homedir, sizeof(dcc_homedir))) {
		BUFCPY(dcc_homedir, tmp);
		dcc_homedir_len = strlen(dcc_homedir);
	}
#else
	if (0 > chdir(tmp)) {
		dcc_pemsg(EX_NOINPUT, emsg, "chdir(%s): %s",
			  tmp, ERROR_STR());
		result = 0;
	} else if (tmp[0] == '/'
		   || !getcwd(dcc_homedir, sizeof(dcc_homedir))) {
		BUFCPY(dcc_homedir, tmp);
		dcc_homedir_len = strlen(dcc_homedir);
	}

	if (!rdonly && 0 > access(dcc_homedir, W_OK)) {
		if ((errno == EACCES || errno == EPERM)
		    && dcc_real_uid != dcc_effective_uid) {
#ifdef HAVE_EACCESS
			dcc_get_priv();
			if (0 > eaccess(dcc_homedir, W_OK)) {
				dcc_pemsg(EX_NOINPUT, emsg, "%s: %s",
					  dcc_homedir, ERROR_STR());
				result = 0;
			}
			dcc_rel_priv();
#endif
		} else {
			dcc_pemsg(EX_NOINPUT, emsg, "%s: %s",
				  dcc_homedir, ERROR_STR());
			result = 0;
		}
	}
#endif /* !DCC_WIN32 */

	return result;
}