ftp.nice.ch/pub/next/developer/languages/c/djgpp-NS.s.tar.gz#/djgpp/go32/ustat.c

This is ustat.c in view mode; [Download] [Up]

#include <string.h>
#include <errno.h>
#include <dir.h>
#include <sys/stat.h>
#include <ctype.h>

#include "ustat.h"

/*
 * An improved version of stat(). This version ensures that "." and ".."
 * appear to exist in all directories, including Novell network drives, and
 * that the root directory also returns the correct result.
 *
 * This function replaces any \'s with /'s in the input string, it should
 * really take a copy of the string first, but this isn't necessary for go32
 * which uses a transfer buffer between the program and the DOS extender
 * anyway.
 *
 * Chris Boucher ccb@southampton.ac.uk
 */


/*
 * I found the following function on SIMTEL20, it dates back to 1987 but
 * there's no mention of who the author was. I've modified/fixed it quite
 * a bit. It neatly avoids any problems with "." and ".." on Novell networks.
 */
static int rootpath(const char *relpath, char *fullpath);


int unixlike_stat(char *name, struct stat *buf) {
	static char path[2 * MAXPATH];
	char *s = name;
	int len;

	/* First off, try the standard stat(), if that works then all is well. */
	if (stat(name, buf) == 0) {
		return 0;
	}

	/* Swap all \'s for /'s. */
	while (*s) {
		if (*s == '\\') *s = '/';
		s++;
	}

	/* Convert path name into root based cannonical form. */
	if (rootpath(name, path) != 0) {
		errno = ENOENT;
		return -1;
	}

	/* DOS doesn't stat "/" correctly, so fake it here. */
	if (strcmp(path + 1, ":/") == 0
	    || strcmp(path+1, ":") == 0) {
		buf->st_dev = 0;
		buf->st_ino = 0;
		buf->st_mode = S_IREAD | S_IWRITE | S_IFDIR;
		buf->st_uid = buf->st_gid = 0;
		buf->st_nlink = 1;
		buf->st_rdev = 0;
		buf->st_size = 0;
		buf->st_atime = buf->st_mtime = buf->st_ctime = 0;
		return 0;
	}

	/* Now modify the string so that "dir/" works. */
	len = strlen(path);
	if (path[len - 1] == '/') path[len - 1] = '\0';
	return stat(path, buf);
}


/*
 * rootpath  --  convert a pathname argument to root based cannonical form.
 *
 * rootpath determines the current directory, appends the path argument (which
 * may affect which disk the current directory is relative to), and qualifies
 * "." and ".." references.  The result is a complete, simple, path name with
 * drive specifier.
 *
 * If the relative path the user specifies does not include a drive spec., the
 * default drive will be used as the base.  (The default drive will never be
 * changed.)
 *
 *  entry: relpath  -- pointer to the pathname to be expanded
 *         fullpath -- must point to a working buffer, see warning
 *   exit: fullpath -- the full path which results
 * return: -1 if an error occurs, 0 otherwise
 *
 * warning: fullpath must point to a working buffer large enough to hold the
 *          longest possible relative path argument plus the longest possible
 *          current directory path.
 */
static int rootpath(const char *relpath, char *fullpath) {
	register char *lead, *follow, *s;
	char tempchar;
	int drivenum;

	/* Extract drive spec. */
	if ((*relpath != '\0') && (relpath[1] == ':')) {
		drivenum = toupper(*relpath) - 'A';
		relpath += 2;
	}
	else {
		drivenum = getdisk();
	}

	/* Fill in the drive path. */
	strcpy(fullpath, " :/");
	fullpath[0] = drivenum + 'A';

	/* Get cwd for drive - also checks that drive exists. */
	if (getcurdir(drivenum + 1, fullpath + 3) == -1) {
		return -1;		/* No such drive - give up. */
	}

	/* Swap all \'s for /'s. */
	s = fullpath;
	while (*s) {
		if (*s == '\\') *s = '/';
		s++;
	}

	/* Append relpath to fullpath/base. */
	if (*relpath == '/') {				/* relpath starts at base... */
		strcpy(fullpath + 2, relpath);	/* ...so ignore cwd. */
	}
	else {								/* relpath is relative to cwd. */
		if (*relpath != '\0') {
			if (strlen(fullpath) > 3) {
				strcat(fullpath, "/");	/* Add a '/' to end of cwd. */
			}
			strcat(fullpath, relpath);	/* Add relpath to end of cwd. */
		}
	}

	/* Convert path to cannonical form. */
	lead = fullpath;
	while (*lead != '\0') {
		/* Mark next path segment. */
		follow = lead;
		lead = (char *)strchr(follow + 1, '/');
		if (lead == 0) {
			lead = fullpath + strlen(fullpath);
		}
		tempchar = *lead;
		*lead = '\0';

		/* "." segment? */
		if (strcmp(follow + 1, ".") == 0) {
			*lead = tempchar;
			strcpy(follow, lead);		/* Remove "." segment. */
			lead = follow;
		}

		/* ".." segment? */
		else if (strcmp(follow + 1, "..") == 0) {
			*lead = tempchar;
			do {
				if (--follow < fullpath) {
					follow = fullpath + 2;
					break;
				}
			} while (*follow != '/');
			strcpy(follow, lead);		/* Remove ".." segment. */
			lead = follow;
		}

		/* Normal segment. */
		else {
			*lead = tempchar;
		}
	}

	if (strlen(fullpath) == 2) {		/* 'D:' or some such. */
		strcat(fullpath, "/");
	}

	/* All done. */
	return 0;
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.