changeset 295:3dd74b16df82

fc-fsio: pathname recursion handling revamped
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sat, 01 Mar 2014 08:01:08 +0000
parents 797468042b32
children 792f164b63a6
files rvinterf/etmsync/Makefile rvinterf/etmsync/fsbasics.c rvinterf/etmsync/fscmdtab.c rvinterf/etmsync/fspath.c rvinterf/etmsync/fsread.c rvinterf/etmsync/fswrite.c rvinterf/include/ffslimits.h
diffstat 7 files changed, 158 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/rvinterf/etmsync/Makefile	Sat Mar 01 04:04:20 2014 +0000
+++ b/rvinterf/etmsync/Makefile	Sat Mar 01 08:01:08 2014 +0000
@@ -4,7 +4,8 @@
 INSTBIN=/usr/local/bin
 
 FSIO_OBJS=	connect.o dispatch.o fdcmd.o fileio.o fsbasics.o fscmdtab.o \
-		fserr.o fsiomain.o fsread.o fswrite.o interf.o launchrvif.o
+		fserr.o fsiomain.o fspath.o fsread.o fswrite.o interf.o \
+		launchrvif.o
 
 all:	${PROGS}
 
--- a/rvinterf/etmsync/fsbasics.c	Sat Mar 01 04:04:20 2014 +0000
+++ b/rvinterf/etmsync/fsbasics.c	Sat Mar 01 08:01:08 2014 +0000
@@ -11,6 +11,7 @@
 #include "ffs.h"
 #include "tmffs2.h"
 #include "limits.h"
+#include "ffslimits.h"
 #include "localtypes.h"
 #include "localstruct.h"
 #include "exitcodes.h"
@@ -75,7 +76,7 @@
 	return(0);
 }
 
-do_readdir(state, namebuf)
+do_readdir(state, namebuf, namebuflen)
 	u_char *state;
 	char *namebuf;
 {
@@ -101,8 +102,12 @@
 	if (rvi_msg[5] != 4)
 		goto malformed;
 	slen = rvi_msg[10];
-	if (slen < 2 || slen > TMFFS_STRING_SIZE)
+	if (slen < 2 || rvi_msg_len != slen + 12)
 		goto malformed;
+	if (slen > namebuflen) {
+		printf("error: readdir response exceeds provided buffer\n");
+		return(ERROR_TARGET);
+	}
 	if (rvi_msg[11 + slen - 1])	/* must be terminating NUL */
 		goto malformed;
 	bcopy(rvi_msg + 6, state, 4);
@@ -114,7 +119,7 @@
 	char **argv;
 {
 	u_char state[4];
-	char namebuf[TMFFS_STRING_SIZE];
+	char namebuf[256];
 	int nument, i, rc;
 
 	rc = do_opendir(argv[1], state, &nument);
@@ -125,7 +130,7 @@
 		return(0);
 	}
 	for (i = 0; i < nument; i++) {
-		rc = do_readdir(state, namebuf);
+		rc = do_readdir(state, namebuf, sizeof namebuf);
 		if (rc)
 			return(rc);
 		printf("%s\n", namebuf);
--- a/rvinterf/etmsync/fscmdtab.c	Sat Mar 01 04:04:20 2014 +0000
+++ b/rvinterf/etmsync/fscmdtab.c	Sat Mar 01 08:01:08 2014 +0000
@@ -5,6 +5,7 @@
 #include "cmdtab.h"
 
 extern int cmd_cpout();
+extern int cmd_cpout_file();
 extern int cmd_delete();
 extern int cmd_exec();
 extern int cmd_exit();
@@ -19,6 +20,7 @@
 
 struct cmdtab cmdtab[] = {
 	{"cpout", 2, 2, cmd_cpout},
+	{"cpout-file", 2, 2, cmd_cpout_file},
 	{"delete", 1, 1, cmd_delete},
 	{"exec", 1, 1, cmd_exec},
 	{"exit", 0, 0, cmd_exit},
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rvinterf/etmsync/fspath.c	Sat Mar 01 08:01:08 2014 +0000
@@ -0,0 +1,70 @@
+/*
+ * FFS pathname manipulation functions
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include "ffs.h"
+#include "limits.h"
+#include "ffslimits.h"
+#include "exitcodes.h"
+
+validate_ffs_pathname(cand)
+	char *cand;
+{
+	char *cp;
+	int depth, c;
+
+	cp = cand;
+	if (*cp++ != '/') {
+		fprintf(stderr, "error: FFS pathnames must be absolute\n");
+		return(-1);
+	}
+	for (depth = 0; *cp; depth++) {
+		if (*cp == '/') {
+			fprintf(stderr,
+		"error: FFS pathname must not contain duplicate slashes\n");
+			return(-1);
+		}
+		for (c = 0; *cp && *cp != '/'; cp++)
+			c++;
+		if (c > MAX_FN_COMPONENT) {
+			fprintf(stderr,
+				"error: FFS pathname component is too long\n");
+			return(-1);
+		}
+		if (!*cp)
+			continue;
+		cp++;
+		if (!*cp) {
+			fprintf(stderr,
+		"error: FFS pathname must not end with a trailing slash\n");
+			return(-1);
+		}
+	}
+	if (depth > MAX_NAME_DEPTH) {
+		fprintf(stderr, "error: FFS pathname exceeds depth limit\n");
+		return(-1);
+	}
+	return(depth);
+}
+
+char *
+pathname_for_ffs_child(parent, childbuf)
+	char *parent, *childbuf;
+{
+	int depth;
+	char *cp;
+
+	depth = validate_ffs_pathname(parent);
+	if (depth < 0 || depth >= MAX_NAME_DEPTH)
+		return(0);
+	strcpy(childbuf, parent);
+	cp = index(childbuf, '\0');
+	if (depth)
+		*cp++ = '/';
+	return(cp);
+}
--- a/rvinterf/etmsync/fsread.c	Sat Mar 01 04:04:20 2014 +0000
+++ b/rvinterf/etmsync/fsread.c	Sat Mar 01 08:01:08 2014 +0000
@@ -14,10 +14,13 @@
 #include "ffs.h"
 #include "tmffs2.h"
 #include "limits.h"
+#include "ffslimits.h"
 #include "localtypes.h"
 #include "localstruct.h"
 #include "exitcodes.h"
 
+extern char *pathname_for_ffs_child();
+
 void
 ll_print_line(pathname, stat)
 	char *pathname;
@@ -44,27 +47,16 @@
 	}
 }
 
-void
-mk_ffs_child_path_from_readdir(dirpath, rdname, buf)
-	char *dirpath, *rdname, *buf;
-{
-	char *tailp;
-
-	tailp = index(dirpath, '\0') - 1;
-	if (*tailp == '/')
-		sprintf(buf, "%s%s", dirpath, rdname);
-	else
-		sprintf(buf, "%s/%s", dirpath, rdname);
-}
-
 cmd_ll(argc, argv)
 	char **argv;
 {
 	struct stat_info stat;
 	u_char rdstate[4];
-	char rdbuf[TMFFS_STRING_SIZE], childpath[TMFFS_STRING_SIZE*2];
+	char rdbuf[MAX_FN_COMPONENT+1], childpath[MAX_FULL_PATHNAME+1], *childp;
 	int nument, i, rc;
 
+	if (validate_ffs_pathname(argv[1]) < 0)
+		return(ERROR_USAGE);	/* err msg already printed */
 	rc = do_xlstat(argv[1], &stat);
 	if (rc)
 		return(rc);
@@ -79,11 +71,20 @@
 		printf("<empty dir>\n");
 		return(0);
 	}
+	childp = pathname_for_ffs_child(argv[1], childpath);
+	if (!childp) {
+		printf("error: non-empty dir at the limit of pathname depth\n");
+		return(ERROR_TARGET);
+	}
 	for (i = 0; i < nument; i++) {
-		rc = do_readdir(rdstate, rdbuf);
+		rc = do_readdir(rdstate, rdbuf, MAX_FN_COMPONENT+1);
 		if (rc)
 			return(rc);
-		mk_ffs_child_path_from_readdir(argv[1], rdbuf, childpath);
+		if (index(rdbuf, '/')) {
+			printf("error: readdir result contains a slash\n");
+			return(ERROR_TARGET);
+		}
+		strcpy(childp, rdbuf);
 		rc = do_xlstat(childpath, &stat);
 		if (rc) {
 			printf("xlstat failed on %s\n", childpath);
@@ -148,7 +149,7 @@
 		return(rc);
 	switch (stat.type) {
 	case OT_FILE:
-		return cpout_file(ffspath, &stat, hostpath);
+		return cpout_file(ffspath, hostpath);
 	case OT_DIR:
 		return cpout_dir(ffspath, hostpath);
 	case OT_LINK:
@@ -160,9 +161,8 @@
 	}
 }
 
-cpout_file(ffspath, stat, hostpath)
+cpout_file(ffspath, hostpath)
 	char *ffspath, *hostpath;
-	struct stat_info *stat;
 {
 	int tfd;
 	FILE *of;
@@ -224,9 +224,10 @@
 	char *ffspath_dir, *hostpath_dir;
 {
 	u_char rdstate[4];
-	char rdbuf[TMFFS_STRING_SIZE], ffspath_child[TMFFS_STRING_SIZE*2];
+	char rdbuf[MAX_FN_COMPONENT+1], ffspath_child[MAX_FULL_PATHNAME+1];
+	char *childp;
 	char hostpath_child[MAXPATHLEN];
-	int nument, i, rc;
+	int nument, i, rc, childerr;
 
 	printf("dir %s\n", ffspath_dir);
 	rc = host_mkdir(hostpath_dir);
@@ -235,15 +236,26 @@
 	rc = do_opendir(ffspath_dir, rdstate, &nument);
 	if (rc)
 		return(rc);
+	if (!nument)
+		return(0);
+	childp = pathname_for_ffs_child(ffspath_dir, ffspath_child);
+	if (!childp) {
+		printf("error: non-empty dir at the limit of pathname depth\n");
+		return(ERROR_TARGET);
+	}
+	childerr = 0;
 	for (i = 0; i < nument; i++) {
 		rc = do_readdir(rdstate, rdbuf);
 		if (rc)
 			return(rc);
-		mk_ffs_child_path_from_readdir(ffspath_dir, rdbuf,
-						ffspath_child);
+		if (index(rdbuf, '/')) {
+			printf("error: readdir result contains a slash\n");
+			return(ERROR_TARGET);
+		}
+		strcpy(childp, rdbuf);
 		if (rdbuf[0] == '.') {
 			printf("skipping %s\n", ffspath_child);
-			return(0);
+			continue;
 		}
 		if (strlen(hostpath_dir) + strlen(rdbuf) + 2 >
 		    sizeof hostpath_child) {
@@ -253,14 +265,24 @@
 		}
 		sprintf(hostpath_child, "%s/%s", hostpath_dir, rdbuf);
 		rc = cpout_object(ffspath_child, hostpath_child);
-		if (rc)
+		if (rc && rc != ERROR_TARGET)
 			return(rc);
+		if (rc)
+			childerr = rc;
 	}
-	return(0);
+	return(childerr);
 }
 
 cmd_cpout(argc, argv)
 	char **argv;
 {
+	if (validate_ffs_pathname(argv[1]) < 0)
+		return(ERROR_USAGE);	/* err msg already printed */
 	return cpout_object(argv[1], argv[2]);
 }
+
+cmd_cpout_file(argc, argv)
+	char **argv;
+{
+	return cpout_file(argv[1], argv[2]);
+}
--- a/rvinterf/etmsync/fswrite.c	Sat Mar 01 04:04:20 2014 +0000
+++ b/rvinterf/etmsync/fswrite.c	Sat Mar 01 08:01:08 2014 +0000
@@ -186,6 +186,11 @@
 cmd_fwrite(argc, argv)
 	char **argv;
 {
+	if (strlen(argv[1]) >= TMFFS_STRING_SIZE) {
+		fprintf(stderr,
+			"error: pathname arg exceeds string length limit\n");
+		return(ERROR_USAGE);
+	}
 	if (!strcmp(argv[2], "ascii"))
 		return do_short_fwrite(argv[1], argv[3], strlen(argv[3]));
 	else if (!strcmp(argv[2], "hex"))
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rvinterf/include/ffslimits.h	Sat Mar 01 08:01:08 2014 +0000
@@ -0,0 +1,22 @@
+/*
+ * Limits on FFS filenames and pathnames
+ *
+ * The deepest pathname allowed is one of the form /1/2/3/4/5/6, where the
+ * last component may be a file, a directory or a symlink; if this last
+ * component is a directory, it has to be empty, because any child of
+ * that directory would violate the depth limit.
+ *
+ * The proper FFS pathname form begins with a slash (all pathnames must
+ * be absolute, no Unix processes in the fw means no current directories),
+ * has exactly one slash in each separating place (no double slashes),
+ * and no trailing slash except in the special case of the root directory,
+ * whose full pathname is "/".
+ *
+ * Each component name is [1,20] characters long; combining this limit
+ * with the maximum depth of 6 puts the maximum length of a properly-formed
+ * full pathname at 126 characters.
+ */
+
+#define	MAX_FN_COMPONENT	20
+#define	MAX_NAME_DEPTH		6
+#define	MAX_FULL_PATHNAME	((MAX_FN_COMPONENT+1) * MAX_NAME_DEPTH)