Browse Source

Enable reading of files in UFS

cat /dev/ufs/0/inodes/<fileinode>/data

Also handle file offsets better when dumping files or directories.
Quite a few todos here.

Signed-off-by: Graham MacDonald <grahamamacdonald@gmail.com>
Graham MacDonald 6 years ago
parent
commit
bc13347b00

+ 1 - 0
sys/include/ufs/freebsd_util.h

@@ -102,6 +102,7 @@ typedef int64_t intmax_t;	/* FIXME: This should probably be moved to <u.h> or re
 #define	EINVAL		22		/* Invalid argument */
 #define	EFBIG		27		/* File too large */
 #define	ENOSPC		28		/* No space left on device */
+#define	EOVERFLOW	84		/* Value too large to be stored in data type */
 
 #define	EJUSTRETURN	(-2)		/* don't modify regs, just return */
 

+ 5 - 2
sys/include/ufs/inode.h

@@ -36,6 +36,8 @@
  */
 
 typedef struct ufs2_dinode ufs2_dinode;
+typedef struct ufsmount ufsmount;
+typedef struct vnode vnode;
 
 /*
  * This must agree with the definition in <ufs/ufs/dir.h>.
@@ -61,8 +63,8 @@ typedef struct ufs2_dinode ufs2_dinode;
 struct inode {
 	// TODO HARVEY Replace when snapshot code re-enabled
 	//TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
-	struct	vnode  *i_vnode;/* Vnode associated with this inode. */
-	struct 	ufsmount *i_ump;/* Ufsmount point associated with this inode. */
+	vnode  *i_vnode;/* Vnode associated with this inode. */
+	ufsmount *i_ump;/* Ufsmount point associated with this inode. */
 	struct	 dquot *i_dquot[MAXQUOTAS]; /* Dquot structures. */
 	union {
 		struct dirhash *dirhash; /* Hashing for large directories. */
@@ -154,6 +156,7 @@ typedef struct Indir {
 } Indir;
 
 /* Convert between inode pointers and vnode pointers. */
+// TODO HARVEY Just remove these 2 macros
 #define	VTOI(vp)	((inode *)(vp)->data)
 #define	ITOV(ip)	((ip)->i_vnode)
 

+ 1 - 14
sys/src/9/port/devufs.c

@@ -338,19 +338,6 @@ dumpinode(void *a, int32_t n, int64_t offset, vnode *vn)
 	return n;
 }
 
-static int
-dumpinodedata(void *a, int32_t n, int64_t offset, vnode *vn)
-{
-	char *buf = malloc(READSTR);
-
-	writeinodedata(buf, READSTR, vn);
-	n = readstr(offset, a, n, buf);
-
-	free(buf);
-
-	return n;
-}
-
 static int32_t
 ufsread(Chan *c, void *a, int32_t n, int64_t offset)
 {
@@ -377,7 +364,7 @@ ufsread(Chan *c, void *a, int32_t n, int64_t offset)
 	case Qinodedata:
 	{
 		vnode *vn = (vnode*)c->aux;
-		n = dumpinodedata(a, n, offset, vn);
+		n = writeinodedata(a, n, offset, vn);
 		break;
 	}
 

+ 6 - 5
sys/src/9/ufs/ffs_extern.h

@@ -68,11 +68,12 @@ int	ffs_flushfiles(MountPoint *, int, thread *);
 //int	ffs_isblock(struct fs *, uint8_t *, ufs1_daddr_t);
 //int	ffs_isfreeblock(struct fs *, uint8_t *, ufs1_daddr_t);
 void	ffs_load_inode(Buf *, inode *, Fs *, ino_t);
-/*int	ffs_own_mount(const struct mount *mp);
-int	ffs_reallocblks(struct vop_reallocblks_args *);
-int	ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
-	    ufs2_daddr_t, int, int, int, struct ucred *, struct buf **);
-int	ffs_reload(struct mount *, struct thread *, int);*/
+//int	ffs_own_mount(const struct mount *mp);
+//int	ffs_reallocblks(struct vop_reallocblks_args *);
+//int	ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
+//	    ufs2_daddr_t, int, int, int, struct ucred *, struct buf **);
+int	ffs_read();
+//int	ffs_reload(struct mount *, struct thread *, int);
 int	ffs_sbupdate(ufsmount *, int, int);
 //void	ffs_setblock(struct fs *, uint8_t *, ufs1_daddr_t);
 int	ffs_snapblkfree(Fs *, vnode *, ufs2_daddr_t, long, ino_t, Vtype,

+ 67 - 53
sys/src/9/ufs/ffs_vnops.c

@@ -67,16 +67,18 @@
 #include "dat.h"
 #include "port/portfns.h"
 
-#include <ufs/libufsdat.h>
-#include <ufs/freebsd_util.h>
+#include "ufsdat.h"
+#include "ufs/libufsdat.h"
+#include "ufsfns.h"
+#include "ufs/freebsd_util.h"
+#include "ufs/fs.h"
+#include "ufs/quota.h"
+#include "ufs/inode.h"
+#include "ufs/dinode.h"
+#include "ufs/ufsmount.h"
 
 //#include <ufs/ufs/extattr.h>
-//#include <ufs/ufs/quota.h>
-//#include <ufs/ufs/inode.h>
 //#include <ufs/ufs/ufs_extern.h>
-//#include <ufs/ufs/ufsmount.h>
-
-//#include <ufs/ffs/fs.h>
 //#include <ufs/ffs/ffs_extern.h>
 
 /*#define	ALIGNED_TO(ptr, s)	\
@@ -378,34 +380,27 @@ ffs_lock (struct vop_lock1_args *ap)
 #endif
 }
 
+#endif // 0
+
 /*
  * Vnode op for reading.
  */
-static int 
-ffs_read (struct vop_read_args *ap)
+int 
+ffs_read(vnode *vp, Uio *uio)
 {
-	struct vnode *vp;
-	struct inode *ip;
-	struct uio *uio;
-	struct fs *fs;
-	struct buf *bp;
+	inode *ip;
+	Fs *fs;
+	Buf *bp;
 	ufs_lbn_t lbn, nextlbn;
 	off_t bytesinfile;
 	long size, xfersize, blkoffset;
-	ssize_t orig_resid;
+	int64_t orig_resid;
 	int error;
-	int seqcount;
-	int ioflag;
+	//int seqcount;
+	//int ioflag;
 
-	vp = ap->a_vp;
-	uio = ap->a_uio;
-	ioflag = ap->a_ioflag;
-	if (ap->a_ioflag & IO_EXT)
-#ifdef notyet
-		return (ffs_extread(vp, uio, ioflag));
-#else
-		panic("ffs_read+IO_EXT");
-#endif
+
+	// TODO HARVEY Keep or delete?
 #ifdef DIRECTIO
 	if ((ioflag & IO_DIRECT) != 0) {
 		int workdone;
@@ -416,33 +411,38 @@ ffs_read (struct vop_read_args *ap)
 	}
 #endif
 
-	seqcount = ap->a_ioflag >> IO_SEQSHIFT;
-	ip = VTOI(vp);
+	//seqcount = ap->a_ioflag >> IO_SEQSHIFT;
+	ip = vp->data;
 
+	// TODO HARVEY Add as to runtime check
 #ifdef INVARIANTS
 	if (uio->uio_rw != UIO_READ)
 		panic("ffs_read: mode");
 
-	if (vp->v_type == VLNK) {
-		if ((int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
-			panic("ffs_read: short symlink");
-	} else if (vp->v_type != VREG && vp->v_type != VDIR)
+	if (vp->v_type != VREG && vp->v_type != VDIR)
 		panic("ffs_read: type %d",  vp->v_type);
 #endif
-	orig_resid = uio->uio_resid;
-	KASSERT(orig_resid >= 0, ("ffs_read: uio->uio_resid < 0"));
+
+	orig_resid = uio->resid;
+	if (orig_resid < 0) {
+		print("ffs_read: uio->resid < 0\n");
+	}
 	if (orig_resid == 0)
-		return (0);
-	KASSERT(uio->uio_offset >= 0, ("ffs_read: uio->uio_offset < 0"));
-	fs = ITOFS(ip);
-	if (uio->uio_offset < ip->i_size &&
-	    uio->uio_offset >= fs->fs_maxfilesize)
+		return 0;
+	if (uio->offset < 0) {
+		print("ffs_read: uio->offset < 0\n");
+	}
+
+	fs = ip->i_ump->um_fs;
+	if (uio->offset < ip->i_size &&
+	    uio->offset >= fs->fs_maxfilesize)
 		return (EOVERFLOW);
 
-	for (error = 0, bp = nil; uio->uio_resid > 0; bp = nil) {
-		if ((bytesinfile = ip->i_size - uio->uio_offset) <= 0)
+	for (error = 0, bp = nil; uio->resid > 0; bp = nil) {
+		if ((bytesinfile = ip->i_size - uio->offset) <= 0)
 			break;
-		lbn = lblkno(fs, uio->uio_offset);
+
+		lbn = lblkno(fs, uio->offset);
 		nextlbn = lbn + 1;
 
 		/*
@@ -452,7 +452,7 @@ ffs_read (struct vop_read_args *ap)
 		 * depending ).
 		 */
 		size = blksize(fs, ip, lbn);
-		blkoffset = blkoff(fs, uio->uio_offset);
+		blkoffset = blkoff(fs, uio->offset);
 
 		/*
 		 * The amount we want to transfer in this iteration is
@@ -466,11 +466,12 @@ ffs_read (struct vop_read_args *ap)
 		 * or the file doesn't have a whole block more of data,
 		 * then use the lesser number.
 		 */
-		if (uio->uio_resid < xfersize)
-			xfersize = uio->uio_resid;
+		if (uio->resid < xfersize)
+			xfersize = uio->resid;
 		if (bytesinfile < xfersize)
 			xfersize = bytesinfile;
 
+#if 0
 		if (lblktosize(fs, nextlbn) >= ip->i_size) {
 			/*
 			 * Don't do readahead if this is the end of the file.
@@ -501,16 +502,16 @@ ffs_read (struct vop_read_args *ap)
 			error = breadn_flags(vp, lbn, size, &nextlbn,
 			    &nextsize, 1, NOCRED, GB_UNMAPPED, &bp);
 		} else {
+#endif // 0
 			/*
 			 * Failing all of the above, just read what the
 			 * user asked for. Interestingly, the same as
 			 * the first option above.
 			 */
-			error = bread_gb(vp, lbn, size, NOCRED,
-			    GB_UNMAPPED, &bp);
-		}
+			error = bread(vp, lbn, size, /*NOCRED, GB_UNMAPPED,*/ &bp);
+		//}
 		if (error) {
-			brelse(bp);
+			releasebuf(bp);
 			bp = nil;
 			break;
 		}
@@ -522,13 +523,18 @@ ffs_read (struct vop_read_args *ap)
 		 * then we want to ensure that we do not uiomove bad
 		 * or uninitialized data.
 		 */
-		size -= bp->b_resid;
+		size -= bp->resid;
 		if (size < xfersize) {
 			if (size == 0)
 				break;
 			xfersize = size;
 		}
 
+		error = uiomove((char *)bp->data + blkoffset, xfersize, uio);
+		if (error)
+			break;
+
+#if 0
 		if (buf_mapped(bp)) {
 			error = vn_io_fault_uiomove((char *)bp->b_data +
 			    blkoffset, (int)xfersize, uio);
@@ -538,19 +544,24 @@ ffs_read (struct vop_read_args *ap)
 		}
 		if (error)
 			break;
+#endif // 0
 
-		vfs_bio_brelse(bp, ioflag);
+		// TODO HARVEY See if there's anything in ioflag we should honour
+		releasebuf(bp);
+		//vfs_bio_brelse(bp, ioflag);
 	}
-
 	/*
 	 * This can only happen in the case of an error
 	 * because the loop above resets bp to NULL on each iteration
 	 * and on normal completion has not set a new value into it.
 	 * so it must have come from a 'break' statement
 	 */
+	// TODO HARVEY See if there's anything in ioflag we should honour
 	if (bp != nil)
-		vfs_bio_brelse(bp, ioflag);
+		releasebuf(bp);//, ioflag);
 
+#if 0
+	// TODO HARVEY Update i_flag
 	if ((error == 0 || uio->uio_resid != orig_resid) &&
 	    (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0 &&
 	    (ip->i_flag & IN_ACCESS) == 0) {
@@ -558,9 +569,12 @@ ffs_read (struct vop_read_args *ap)
 		ip->i_flag |= IN_ACCESS;
 		VI_UNLOCK(vp);
 	}
+#endif // 0
 	return (error);
 }
 
+#if 0
+
 /*
  * Vnode op for writing.
  */

+ 48 - 11
sys/src/9/ufs/ufs_harvey_external.c

@@ -225,23 +225,52 @@ writeinode(char *buf, int buflen, vnode *vn)
 }
 
 int
-writeinodedata(char *buf, int buflen, vnode *vn)
+writeinodedata(char *buf, int32_t n, int64_t offset, vnode *vn)
 {
 	Proc *up = externup();
-	int i = 0;
 
 	if (vn->type == VREG) {
-		i += snprint(buf + i, buflen - i, "file\n");
-		return i;
-	}
+		uint64_t size = vn->data->i_size;
+		if (offset >= size) {
+			return 0;
+		}
+		if (offset + n > size) {
+			n = size - offset;
+		}
+
+		Uio* uio = newuio(n);
+		if (waserror()) {
+			releaseuio(uio);
+			nexterror();
+		}
+
+		uio->resid = vn->data->i_size;
+		uio->offset = offset;
+
+		int rcode = ffs_read(vn, uio);
+		if (rcode) {
+			error("error reading file");
+		}
+
+		packuio(uio);
 
-	if (vn->type == VDIR) {
-		Uio* uio = newuio(DIRBLKSIZ);
+
+		uio->dest = bl2mem((uint8_t*)buf, uio->dest, n);
+
+		poperror();
+		releaseuio(uio);
+		return n;
+	
+	} else if (vn->type == VDIR) {
+		Uio* uio = newuio(n);
 		if (waserror()) {
 			releaseuio(uio);
 			nexterror();
 		}
 
+		// We don't set uio->offset here - that's accounted for when
+		// writing the directory strings, since that's where the offset
+		// is really relative to.
 		uio->resid = vn->data->i_size;
 
 		int rcode = ufs_readdir(vn, uio);
@@ -252,22 +281,30 @@ writeinodedata(char *buf, int buflen, vnode *vn)
 		packuio(uio);
 
 		// Iterate over all files
+		int i = 0, offseti = 0;
 		int64_t diroffset = 0;
 		int64_t endoffset = uio->offset - uio->resid;
 		while (uio->offset >= 0 && diroffset < endoffset) {
 			Dirent* dir = (Dirent*)(uio->dest->rp + diroffset);
 
-			i += snprint(buf + i, buflen - i, "%s\t%llu\n", dir->name, (uint64_t)dir->fileno);
+			int len = snprint(buf + i, n - i, "%s\t%llu\n", dir->name, (uint64_t)dir->fileno);
+
+			// Only progress if we've passed the offset.  This will
+			// continually overwrite until that point.
+			if (offseti >= offset) {
+				i += len;
+			}
+			offseti += len;
 			diroffset += dir->reclen;
 		}
 
 		poperror();
 		releaseuio(uio);
 		return i;
-	}
 
-	i += snprint(buf + i, buflen - i, "unsupported inode type (%d)\n", vn->type);
-	return i;
+	} else {
+		return snprint(buf, n, "unsupported inode type (%d)\n", vn->type);
+	}
 }
 
 vnode *

+ 4 - 0
sys/src/9/ufs/ufs_harvey_internal.c

@@ -105,6 +105,7 @@ breadmp(MountPoint *mp, daddr_t blkno, size_t size, Buf **buf)
 		return 1;
 	}
 
+	b->resid = size - bytesRead;
 	*buf = b;
 	return 0;
 }
@@ -130,13 +131,16 @@ bread(vnode *vn, daddr_t lblkno, size_t size, Buf **buf)
 	MountPoint *mp = vn->mount;
 	Chan *c = mp->chan;
 	int64_t offset = dbtob(pblkno);
+
 	int32_t bytesRead = c->dev->read(c, b->data, size, offset);
+
 	if (bytesRead != size) {
 		releasebuf(b);
 		print("bread returned wrong size\n");
 		return 1;
 	}
 
+	b->resid = size - bytesRead;
 	*buf = b;
 	return 0;
 }

+ 2 - 2
sys/src/9/ufs/ufs_vnops.c

@@ -41,9 +41,9 @@
 #include "port/portfns.h"
 
 #include "ufsdat.h"
-#include <ufs/libufsdat.h>
+#include "ufs/libufsdat.h"
 #include "ufsfns.h"
-#include <ufs/freebsd_util.h>
+#include "ufs/freebsd_util.h"
 
 #include "ufs/quota.h"
 #include "ufs/inode.h"

+ 4 - 0
sys/src/9/ufs/ufsdat.h

@@ -37,6 +37,10 @@ typedef struct Buf {
 	unsigned char*	data;
 	size_t		bcount;		/* Requested size of buffer */
 	int64_t		offset;		/* Offset into file. */
+
+	// Number of bytes remaining in I/O.  After an I/O operation
+ 	// completes, b_resid is usually 0 indicating 100% success.
+	int64_t		resid;
 } Buf;
 
 

+ 1 - 1
sys/src/9/ufs/ufsfns.h

@@ -28,7 +28,7 @@ int		lookuppath(MountPoint *mp, char *path, vnode **vn);
 int		writestats(char *buf, int buflen, MountPoint *mp);
 int		writesuperblock(char *buf, int buflen, MountPoint *mp);
 int		writeinode(char *buf, int buflen, vnode *vn);
-int		writeinodedata(char *buf, int buflen, vnode *vn);
+int		writeinodedata(char *buf, int32_t n, int64_t offset, vnode *vn);
 
 // Misc
 int		ffs_init();