Commit Diff


commit - f96f265a4a599a3a77fc85419281063454271d1f
commit + 7ee9de09935049e0aa2c5b3f87c821833edda1fe
blob - 9f0db8fb1c41e00eff1e5a7be402ce6d2792f47e
blob + 51a88157347e91e52d0ed7f33d0bcba2f740042b
--- ftp.c
+++ ftp.c
@@ -34,6 +34,10 @@
 #include <readline/history.h>
 #endif
 
+#ifndef nitems
+#define nitems(_a)	(sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
 #include "9pclib.h"
 #include "kamid.h"
 #include "utils.h"
@@ -49,6 +53,7 @@ struct tls_config	*tlsconf;
 struct tls		*ctx;
 int			 sock;
 struct evbuffer		*buf;
+struct evbuffer		*dirbuf;
 uint32_t		 msize;
 
 #define PWDFID		0
@@ -170,7 +175,7 @@ recv_msg(void)
 }
 
 static uint64_t
-np_read64(void)
+np_read64(struct evbuffer *buf)
 {
 	uint64_t n;
 
@@ -179,7 +184,7 @@ np_read64(void)
 }
 
 static uint32_t
-np_read32(void)
+np_read32(struct evbuffer *buf)
 {
 	uint32_t n;
 
@@ -188,7 +193,7 @@ np_read32(void)
 }
 
 static uint16_t
-np_read16(void)
+np_read16(struct evbuffer *buf)
 {
 	uint16_t n;
 
@@ -197,7 +202,7 @@ np_read16(void)
 }
 
 static uint16_t
-np_read8(void)
+np_read8(struct evbuffer *buf)
 {
 	uint8_t n;
 
@@ -206,12 +211,12 @@ np_read8(void)
 }
 
 static char *
-np_readstr(void)
+np_readstr(struct evbuffer *buf)
 {
 	uint16_t	 len;
 	char		*str;
 
-	len = np_read16();
+	len = np_read16(buf);
 	assert(EVBUFFER_LENGTH(buf) >= len);
 
 	if ((str = calloc(1, len+1)) == NULL)
@@ -221,13 +226,13 @@ np_readstr(void)
 }
 
 static void
-np_read_qid(struct qid *qid)
+np_read_qid(struct evbuffer *buf, struct qid *qid)
 {
 	assert(EVBUFFER_LENGTH(buf) >= QIDSIZE);
 
-	qid->type = np_read8();
-	qid->vers = np_read32();
-	qid->path = np_read64();
+	qid->type = np_read8(buf);
+	qid->vers = np_read32(buf);
+	qid->path = np_read64(buf);
 }
 
 static void
@@ -235,14 +240,14 @@ expect(uint8_t type)
 {
 	uint8_t t;
 
-	t = np_read8();
+	t = np_read8(buf);
 	if (t == type)
 		return;
 
 	if (t == Terror) {
 		char *err;
 
-		err = np_readstr();
+		err = np_readstr(buf);
 		errx(1, "expected %s, got error %s",
 		    pp_msg_type(type), err);
 	}
@@ -258,7 +263,7 @@ expect2(uint8_t type, uint16_t tag)
 
 	expect(type);
 
-	t = np_read16();
+	t = np_read16(buf);
 	if (t == tag)
 		return;
 
@@ -275,8 +280,8 @@ do_version(void)
 	recv_msg();
 	expect2(Rversion, NOTAG);
 
-	msize = np_read32();
-	version = np_readstr();
+	msize = np_read32(buf);
+	version = np_readstr(buf);
 
 	if (msize > MSIZE9P)
 		errx(1, "got unexpected msize: %d", msize);
@@ -302,11 +307,58 @@ do_attach(const char *path)
 	do_send();
 	recv_msg();
 	expect2(Rattach, iota_tag);
-	np_read_qid(&qid);
+	np_read_qid(buf, &qid);
+
 	ASSERT_EMPTYBUF();
 }
 
+static uint32_t
+do_open(uint32_t fid, uint8_t mode)
+{
+	struct qid qid;
+	uint32_t iounit;
+
+	topen(fid, mode);
+	do_send();
+	recv_msg();
+	expect2(Ropen, iota_tag);
+
+	np_read_qid(buf, &qid);
+	iounit = np_read32(buf);
+
+	ASSERT_EMPTYBUF();
+
+	return iounit;
+}
+
 static void
+do_clunk(uint32_t fid)
+{
+	tclunk(fid);
+	do_send();
+	recv_msg();
+	expect2(Rclunk, iota_tag);
+
+	ASSERT_EMPTYBUF();
+}
+
+static void
+dup_fid(int fid, int nfid)
+{
+	uint16_t nwqid;
+
+	twalk(fid, nfid, NULL, 0);
+	do_send();
+	recv_msg();
+	expect2(Rwalk, iota_tag);
+
+	nwqid = np_read16(buf);
+	assert(nwqid == 0);
+
+	ASSERT_EMPTYBUF();
+}
+
+static void
 do_connect(const char *connspec, const char *path)
 {
 	int handshake;
@@ -358,8 +410,97 @@ do_connect(const char *connspec, const char *path)
 	do_attach(path);
 
 	free(host);
+}
+
+static void
+cmd_ls(int argc, const char **argv)
+{
+	uint64_t off = 0;
+	uint32_t len;
+
+	if (argc != 0) {
+		printf("ls don't take arguments (yet)\n");
+		return;
+	}
+
+	dup_fid(PWDFID, 1);
+	do_open(1, KOREAD);
+
+	evbuffer_drain(dirbuf, EVBUFFER_LENGTH(dirbuf));
+
+	for (;;) {
+		tread(1, off, BUFSIZ);
+		do_send();
+		recv_msg();
+		expect2(Rread, iota_tag);
+
+		len = np_read32(buf);
+		if (len == 0)
+			break;
+
+		evbuffer_add_buffer(dirbuf, buf);
+		off += len;
+
+		ASSERT_EMPTYBUF();
+	}
+
+	while (EVBUFFER_LENGTH(dirbuf) != 0) {
+		struct qid	 qid;
+		uint64_t	 len;
+		uint16_t	 size;
+		char		*name;
+
+		size = np_read16(dirbuf);
+		assert(size <= EVBUFFER_LENGTH(dirbuf));
+
+		np_read16(dirbuf); /* skip type */
+		np_read32(dirbuf); /* skip dev */
+
+		np_read_qid(dirbuf, &qid);
+		printf("%s ", pp_qid_type(qid.type));
+
+		np_read32(dirbuf); /* skip mode */
+		np_read32(dirbuf); /* skip atime */
+		np_read32(dirbuf); /* skip mtime */
+
+		len = np_read64(dirbuf);
+		printf("%llu ", (unsigned long long)len);
+
+		name = np_readstr(dirbuf);
+		printf("%s\n", name);
+		free(name);
+
+		free(np_readstr(dirbuf)); /* skip uid */
+		free(np_readstr(dirbuf)); /* skip gid */
+		free(np_readstr(dirbuf)); /* skip muid */
+	}
+
+	do_clunk(1);
 }
 
+static void
+excmd(int argc, const char **argv)
+{
+	struct cmd {
+		const char	*name;
+		void		(*fn)(int, const char **);
+	} cmds[] = {
+		{"ls",		cmd_ls},
+	};
+	size_t i;
+
+	if (argc == 0)
+		return;
+	for (i = 0; i < nitems(cmds); ++i) {
+		if (!strcmp(cmds[i].name, *argv)) {
+			cmds[i].fn(argc-1, argv+1);
+			return;
+		}
+	}
+
+	log_warnx("unknown command %s", *argv);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -396,14 +537,27 @@ main(int argc, char **argv)
 	if ((buf = evbuffer_new()) == NULL)
 		fatal("evbuffer_new");
 
+	if ((dirbuf = evbuffer_new()) == NULL)
+		fatal("evbuferr_new");
+
 	do_connect(argv[0], argv[1]);
 
+	/* cmd_ls(0, NULL); */
+
 	for (;;) {
-		char *line;
+		int argc = 0;
+		char *line, *argv[16] = {0}, **ap;
 
 		if ((line = read_line("kamiftp> ")) == NULL)
 			break;
-		printf("read: %s\n", line);
+
+		for (argc = 0, ap = argv; ap < &argv[15] &&
+		    (*ap = strsep(&line, " \t")) != NULL;) {
+			if (**ap != '\0')
+				ap++, argc++;
+		}
+		excmd(argc, argv);
+
 		free(line);
 	}