File:  [MW Coherent from dump] / coherent / d / bin / dos / dos2.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:39 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*#define DEBUG 1*/
/* dos.c */

#include "dos0.h"

/*
 * Convert an MS-DOS filename and path
 * to a NUL-terminated COHERENT filename in cohfile[].
 * Return a pointer to the NUL terminator.
 */
char *
cohname(name, dp) register char *name; DIR *dp;
{
	register char *cp;

	if (dp == root)
		cp = cohfile;
	else {
		cp = cohname(dp->d_dname, dp->d_parent);
		*cp++ = '/';
		*cp = '\0';
	}
	cp = lcname(cp, name, 8);
	name += 8;
	if (*name != ' ') {
		*cp++ = '.';
		cp = lcname(cp, name, 3);
	}
	return cp;
}

/*
 * Change the COHERENT time of the given file to the MS-DOS time of mdp.
 * There should be a COHERENT function which converts struct tm to time_t,
 * but in the meantime this does it by hand.  What a pain.
 */
void
cohtime(file, mdp) char *file; MDIR *mdp;
{
	time_t cohtime, times[2];
	static short mdays[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

	settz();
	cohtime = ((10 * 365L) + 2);		/* days 1/1/70 to 1/1/80 */
	cohtime += (m_year(mdp) * 365L);	/* to 1/1/year */
	if (m_month(mdp) > 2)			/* leap year adjust */
		cohtime += ((m_year(mdp)+4)/4);
	else
		cohtime += ((m_year(mdp)+3)/4);
	cohtime += mdays[m_month(mdp)-1];		/* to mon/1/year */
	cohtime += (m_day(mdp)-1);		/* to mon/day/year */
	cohtime *= 24L;				/* hours */
	cohtime += m_hour(mdp);
	cohtime *= 60L;
	cohtime += m_min(mdp);			/* minutes */
	cohtime *= 60L;
	cohtime += m_sec(mdp) * 2;		/* seconds */
	cohtime += timezone;
	times[0] = times[1] = cohtime;
	if (utime(file, times) == -1)
		fatal("cannot set time of file \"%s\"", file);
}

/*
 * Find or create an MS-DOS directory.
 * Return a pointer to the DIR.
 * Failure is always fatal.
 */
DIR *
creatdir(name) char *name;
{
	register MDIR *mdp;
	register char *cp;
	DIR *dp, *ndp;

	/* Check if directory exists. */

	if ((mdp = find(name, root, &dp)) != NULL) {
		if (!isdir(mdp))
		{
			if (mdp->m_attr & MVOLUME)
				fatal("\"%s\" is the volume name, not a subdirectory", name);
			else
				fatal("\"%s\" is an MS-DOS file, not a subdirectory", name);
		}

		return dp;
	}

	/* Directory does not exist, create it. */
	dbprintf(("creatdir(%s)\n", name));
	if ((cp = strrchr(name, '/')) == NULL) {
		dp = root;
		mdp = creatfile(name, dp);	/* create the dir in root */
	} else {
		*cp = '\0';			/* NUL-terminate dirname */
		dp = creatdir(name);		/* create the parent */
		*cp = '/';			/* restore the / */
		mdp = creatfile(cp + 1, dp);	/* create the directory */
	}
	if (vflag)
		fprintf(stderr, "r %s/\n", name);
	mdp->m_attr = MSUBDIR;
	ndp = newdir(dp, mdp, mdirsize);
	readmdir(ndp);
	mdp->m_cluster = ndp->d_cluster = freecluster();
	mdp = ndp->d_dir;
	mdirinit(mdp, ndp, ".          ", MSUBDIR, ndp->d_cluster);
	mdirinit(++mdp, ndp, "..         ", MSUBDIR, dp->d_cluster);
	return ndp;
}

/*
 * Create an empty MS-DOS file.
 * Delete the old one if it exists.
 * Return a pointer to the initialized MDIR entry
 * (name initialized, attribute==0, cluster==0, size==0L).
 * Failure is always fatal.
 */
MDIR *
creatfile(name, dp) char *name; DIR *dp;
{
	register MDIR *mdp;
	unsigned short n, ofiles, next;

	/* Check if file exists. */
	dbprintf(("creatfile(%s, %s)\n", name, dp->d_dname));
	if ((mdp = find(name, dp, &dp)) != NULL) {
		if isdir(mdp)
			fatal("\"%s\" is an MS-DOS subdirectory", name);
		deletefile(mdp, dp);		/* delete the old one */
	}

	/* Find a slot for the file. */
	for (mdp = dp->d_dir; mdp < dp->d_edp; mdp++)
		if (mdp->m_name[0] == MEMPTY || mdp->m_name[0] == MFREE)
			break;
	if (mdp == dp->d_edp) {
		/* Out of directory space.  Fatal on root. */
		if (dp == root)
			fatal("replace: out of root directory space for \"%s\"", name);
		/* Add a cluster to a subdirectory. */
		for (n = dp->d_cluster; (next = getcluster(n)) <= CLMAX; n = next)
			;
		putcluster(n, freecluster());
		dp->d_dirblocks += clsize;
		ofiles = dp->d_files;
		dp->d_files += mdirsize;
		if ((dp->d_dir = (MDIR *)realloc(dp->d_dir, dp->d_dirblocks * ssize)) == NULL)
			fatal("replace: out of space to grow subdirectory");
		dbprintf(("creatfile: grow \"%s\" dp=%x at d_dir=%x\n", dp->d_dname, dp, dp->d_dir));
		dp->d_edp = dp->d_dir + dp->d_files;
		for (mdp = dp->d_dir + ofiles + 1; mdp < dp->d_edp; mdp++)
			mdp->m_name[0] = MFREE;
		mdp = dp->d_dir + ofiles;
	}
	mdirinit(mdp, dp, dosname(name), MARCHIV, 0);
	return mdp;
}

/*
 * Delete specified files.
 */
void
delete(nargs, args) short nargs; char *args[];
{
	register MDIR *mdp;
	register char **ap;
	DIR *dp;

	if (nargs == 0)
		fatal("delete: must specify files");
	for (ap = args; *ap != NULL; ap++) {
		if (vflag)
			fprintf(stderr, "d %s\n", *ap);
		if ((mdp = find(*ap, root, &dp)) == NULL)
			nonfatal("delete: \"%s\" not found", *ap);
		else {
			do {
				if isdir(mdp)
					deletedir(mdp, dp, cohn(mdp->m_name));
				else
					deletefile(mdp, dp);
 			} while (mdp = findnext(&dp));
		}
	}
}

/*
 * Delete a subdirectory.
 * Make sure it is empty first.
 */
void
deletedir(mdp, dp, name) MDIR *mdp; DIR *dp; char *name;
{
	register MDIR *mdp2;
	register DIR **dpp;
	short c;

	/* Make sure subdirectory is empty. */
	for (mdp2 = dp->d_dir; mdp2 < dp->d_edp; mdp2++)
		if ((c = mdp2->m_name[0])!=MFREE && c!=MEMPTY && c!=MMDIR) {
		       nonfatal("delete: subdirectory \"%s\" not empty",name);
		       return;
		}

	/* Delete the subdirectory entry and free its MDIR. */
	deletefile(mdp, dp->d_parent);
	free(dp->d_dir);

	/* Remove the DIR from the chain and free it. */
	for (dpp = &(dp->d_parent->d_child); *dpp != NULL; dpp = &((*dpp)->d_sibling))
		if (*dpp == dp)
			break;
	if (*dpp == NULL)
		fatal("deletedir botch");
	*dpp = dp->d_sibling;
	free(dp);
}

/*
 * Delete a file.
 * Free the clusters in its FAT chain.
 * Free the directory entry.
 * Set the dirflag requiring the directory to be updated.
 */
void
deletefile(mdp, dp) MDIR *mdp; DIR *dp;
{
	register unsigned short n, next;

	if ((mdp->m_attr & MRONLY) && !fflag)
	{
		nonfatal("cannot delete %s\n", cohn(mdp->m_name));
		return;
	}

	dp->d_dirflag = 1;
	mdp->m_name[0] = MEMPTY;		/* zap the MDIR entry */
	if (mdp->m_cluster == 0)
		return;				/* no chain */
	for (n = mdp->m_cluster; n <= CLMAX; n = next) {
		next = getcluster(n);
		putcluster(n, CLFREE);
	}
	mdp->m_cluster = CLFREE;
}

/*
 * Return the size in clusters of the directory starting at n.
 */
unsigned short
dirclusters(mdp) MDIR *mdp;
{
	register unsigned short n, count;

	for (n = mdp->m_cluster, count = 1; (n = getcluster(n)) <= CLMAX; ++count)
		;
	return count;
}

/*
 * Map a COHERENT filename to an 11-character MS-DOS name (plus NUL terminator)
 * in the static buffer and return a pointer to it.
 * There is no good way, thanks to different filename lengths and '.'.
 * Special hacks: ".profile" -> "_PROFILE", "a.b.c" -> "A_B.C".
 */
char *
dosname(name) register char *name;
{
	register char *s, *dotp;
	char c;
	static char buf[16];

	dotp = strrchr(name, '.');
	if (dotp == name)
		dotp = NULL;
	for (s = buf; name != dotp && (c = *name) != '\0'; name++)
		if (s < &buf[8])		/* copy name */
			*s++ = (c == '.') ? '_' : c;
	while (s < &buf[8])
		*s++ = ' ';			/* space-pad name */
	if (name++ == dotp)
		for ( ; *name != '\0'; name++)
			if (s <= &buf[11])
				*s++ = *name;	/* copy extension */
	while (s < &buf[11])
		*s++ = ' ';			/* space-pad extension */
	*s = '\0';				/* NUL terminate */
	uppercase(buf);				/* map to UPPER */
	return buf;
}

/*
 * Set the time of an MS-DOS directory entry.
 * Use the mtime of file if kflag and file is not NULL,
 * otherwise use the current time.
 */
void
dostime(mdp, file) register MDIR *mdp; char *file;
{
	register struct tm *tmp;
	struct stat s;
	time_t t;

	if (kflag && file != NULL) {
		if (stat(file, &s) == -1)
			fatal("cannot stat \"%s\"", file);
		t = s.st_mtime;
	} else
		t = time(NULL);
	tmp = localtime(&t);
	mdp->m_time =
	   c_sec(tmp->tm_sec/2) | c_min(tmp->tm_min) | c_hour(tmp->tm_hour);
	mdp->m_date =
	   c_day(tmp->tm_mday)|c_month(tmp->tm_mon+1)|c_year(tmp->tm_year-80);
}

/*
 * creat a directory on a dos disk
 */
void
createdir(nargs, args) short nargs; char *args[];
{
	creatdir(*args);
}


/*
 * Extract files from MS-DOS file system.
 */
void
extract(nargs, args) short nargs; char *args[];
{
	register MDIR *mdp;
	register char **ap;
	char *argsd[512], *argsf[512];
	short dnargs = 0, fnargs = 0;
	char *tmp;
	DIR *dp;

	if ((clbuf = malloc(clsize * ssize)) == NULL)
		fatal("cluster buffer allocation failed");
	if (pflag && nargs!=1)
		fatal("extract: exactly one file required with 'p' option");
	if (nargs == 0)
		extractdir(root);
	else {
		if ((mdp = find(args[0], root, &dp)) == NULL)
			nonfatal("extract: file \"%s\" not found", *ap);
		else {
			do {
				cohname(mdp->m_name, dp);
				if (isdir(mdp)) {
					if (!sflag) {
						argsd[dnargs] =
						    malloc(strlen(cohfile)+1);
						strcpy(argsd[dnargs++],
								cohfile);
					}
				}
				else {
					argsf[fnargs] =
						malloc(strlen(cohfile) + 1);
					strcpy(argsf[fnargs++],cohfile);
				}
	 		} while (mdp = findnext(&dp));
			numargs = fnargs + (sflag ? 0 : dnargs);
			if (fnargs > 0) {
				for (ap = argsf; fnargs ; ap++, fnargs--) {
					isdir_keep = 0;
					mdp = find(*ap, root, &dp);
					base = basehold;
					strcpy(base,*ap);
					extractfile(mdp, dp);
				}
			}
			if ((!sflag) && (dnargs > 0)) {
				for (ap = argsd; dnargs ; ap++, dnargs--) {
					isdir_keep = 1;
					mdp = find(*ap, root, &dp);
					base = basehold;
					strcpy(base,*ap);
					extractdir(dp);
				}
			}
		}
	}
	free(clbuf);
}

/*
 * Extract a directory.
 * Extract subdirectories recursively unless sflag.
 */
void
extractdir(dp) register DIR *dp;
{
	register MDIR *mdp;
	DIR *dp2;
	unsigned char c;
	struct stat s;
	short freeflag;

	freeflag = 0;
	if (!sflag) {
		if (dp->d_dir == NULL) {
			readmdir(dp);		/* read the DOS directory */
			freeflag = 1;		/* and set a flag */
		}
		if (dp != root) {
			cohname(dp->d_dname, dp->d_parent);
			if (stat(cohfile, &s) == -1) {
				/* COHERENT directory not found, create it. */
				if (vflag)
					fprintf(stderr, "x %s/\n", cohfile);
				if (oldstyle)
					if (system(strcat(strcpy(cmd, "mkdir "), cohfile)) != 0)
						fatal("cannot create directory \"%s\"", cohfile);
			} else if ((s.st_mode & S_IFDIR) == 0)
				fatal("\"%s\" exists but is not a directory",
					cohfile);
		}
		for (dp2 = dp->d_child; dp2 != NULL; dp2 = dp2->d_sibling)
			extractdir(dp2);	/* extract subdirectory */
	}
	for (mdp = dp->d_dir; mdp < dp->d_edp; mdp++)
		if ((c = mdp->m_name[0]) != MEMPTY && c != MFREE && c != MMDIR && !isdir(mdp))
			extractfile(mdp, dp);
	if (freeflag) {
		free(dp->d_dir);
		dp->d_dir = dp->d_edp = NULL;
	}
}

/*
 * Extract a file.
 */
void
extractfile(mdp, dp) register MDIR *mdp; DIR *dp;
{
	register unsigned short cluster;
	short readsize, i;
	long size;
	FILE *ofp;
	char *tmp, tmp2[6], *mcohfile;

	if (mdp->m_attr & MVOLUME)
		return;

	tmp = &(mdp->m_name[8]);
	if (!oldstyle) {
		if (!bflag && (*tmp != ' ')) {
			tmp2[0] = '.';
			for (i=0; i< 3; i++) {
				if (tmp[i] != ' ')
					tmp2[i+1] = tolower(tmp[i]);
				else
					break;
			}
			tmp2[i+1] = '.';
			tmp2[i+2] = '\0';
			if (!aflag)
				aflag = (strstr(ext, tmp2) != NULL) ? 1 : 0;
		}
	}

dbprintf(("bflag=%d, aflag=%d, mdp->m_name=%s, tmp2=%s\n", bflag, aflag, mdp->m_name, tmp2));

	/* Convert filename to COHERENT format and open the output file. */
	cohname(mdp->m_name, dp);

	if (pflag)
			ofp = stdout;
	else if ((ofp = fopen(mcohfile = makef(cohfile, 1), "w")) == NULL)
		fatal("extract: cannot create file \"%s\"", mcohfile);

	if (vflag)
		fprintf(stderr, "x %s\n", mcohfile);

	/* Read the MS-DOS file and write it to the COHERENT file. */
	readsize = clsize * ssize;
	size = mdp->m_size;
	for(cluster= mdp->m_cluster; size > 0; cluster = getcluster(cluster)){
		if (cluster > CLMAX)
			fatal("extract: early EOF on file \"%s\"",mcohfile);
		if (diskread(clbuf, cltosec(cluster), clsize))
			fatal("extract: read error on file \"%s\"", mcohfile);
		if (size < readsize)
			readsize = size;
		foutput(mcohfile, ofp, clbuf, readsize);
		size -= readsize;
	}
	if (!pflag)
		fclose(ofp);
	if (kflag)
		cohtime(mcohfile, mdp);
}

/* end of dos2.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.