Subject: Second patch for lseek() sparse file extension
To: None <tech-kern@NetBSD.org>
From: Reinoud Zandijk <reinoud@netbsd.org>
List: tech-kern
Date: 09/21/2006 20:47:49
--tsOsTdHNUZQcU9Ye
Content-Type: multipart/mixed; boundary="3MwIy2ne0vdjdPXF"
Content-Disposition: inline


--3MwIy2ne0vdjdPXF
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Dear folks,

2nd try that ought to be complete. I had to change the VOP_SEEK() a bit 
since i was worried about FS layering and got wierd results at times; thus 
i pass the vattr down so it reflects the top vnode and not the bottom 
vnode. This might be important for some file systems and it saves 
duplicating and thus error-prone ness.

I've also added and updated src/regress/os/fs/lseek to test for normal 
lseek() behaviour and to test the SEEK_DATA and SEEK_HOLE extension if it 
is defined.

If all is ok, i'd like to commit this.

With regards,
Reinoud


--3MwIy2ne0vdjdPXF
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=DIFFS

Index: include/stdio.h
===================================================================
RCS file: /cvsroot/src/include/stdio.h,v
retrieving revision 1.64
diff -u -r1.64 stdio.h
--- include/stdio.h	10 May 2006 21:09:45 -0000	1.64
+++ include/stdio.h	21 Sep 2006 18:37:52 -0000
@@ -203,6 +203,12 @@
 #ifndef SEEK_END
 #define	SEEK_END	2	/* set file offset to EOF plus offset */
 #endif
+#ifndef SEEK_DATA
+#define	SEEK_DATA	3	/* Set file pointer to next data past offset */
+#endif
+#ifndef SEEK_HOLE
+#define	SEEK_HOLE	4	/* Set file pointer to next hole past offset */
+#endif
 
 #define	stdin	(&__sF[0])
 #define	stdout	(&__sF[1])
Index: lib/libc/sys/lseek.2
===================================================================
RCS file: /cvsroot/src/lib/libc/sys/lseek.2,v
retrieving revision 1.22
diff -u -r1.22 lseek.2
--- lib/libc/sys/lseek.2	13 May 2004 10:20:58 -0000	1.22
+++ lib/libc/sys/lseek.2	21 Sep 2006 18:37:53 -0000
@@ -29,7 +29,7 @@
 .\"
 .\"     @(#)lseek.2	8.3 (Berkeley) 4/19/94
 .\"
-.Dd April 19, 1994
+.Dd September 21, 2006
 .Dt LSEEK 2
 .Os
 .Sh NAME
@@ -86,6 +86,29 @@
 file plus
 .Fa offset
 bytes.
+.It
+If
+.Fa whence
+is
+.Dv SEEK_DATA ,
+the offset is set to the next non-hole region which file offset is
+greater or equal to the provided
+.Fa offset
+in bytes. If specifying an
+.Fa offset
+of 0 bytes, there is guaranteed to be a data region for easy programming.
+.It
+If
+.Fa whence
+is
+.Dv SEEK_HOLE ,
+the offset is set to the next hole region which file offset is
+greater or equal to the provided
+.Fa offset
+in bytes. If specifying an
+.Fa offset
+within the boundaries of the file, there is a guaranteed virtual hole at the
+end of the file for easy programming.
 .El
 .Pp
 The
@@ -121,6 +144,9 @@
 .It Bq Er EINVAL
 .Fa whence
 is not a proper value, or the resulting file offset would be invalid.
+.It Bq Er ENXIO
+No more data regions or hole regions are present past the supplied
+.Fa offset
 .El
 .Sh SEE ALSO
 .Xr dup 2 ,
@@ -129,8 +155,18 @@
 The
 .Fn lseek
 function conforms to
-.St -p1003.1-90 .
+.St -p1003.1-90 . The
+.Dv SEEK_DATA
+and
+.Dv SEEK_HOLE
+conform to the Solaris 10 implemention.
 .Sh BUGS
 This document's use of
 .Fa whence
 is incorrect English, but is maintained for historical reasons.
+.Sh HISTORY
+The
+.Dv SEEK_DATA
+and
+.Dv SEEK_HOLE
+functionality was added in NetBSD 5.0
Index: share/man/man9/vnodeops.9
===================================================================
RCS file: /cvsroot/src/share/man/man9/vnodeops.9,v
retrieving revision 1.51
diff -u -r1.51 vnodeops.9
--- share/man/man9/vnodeops.9	16 Sep 2006 08:54:22 -0000	1.51
+++ share/man/man9/vnodeops.9	21 Sep 2006 18:37:54 -0000
@@ -146,7 +146,8 @@
 .Fn VOP_FSYNC "struct vnode *vp" "struct ucred *cred" "int flags" \
 "off_t offlo" "off_t offhi" "struct lwp *l"
 .Ft int
-.Fn VOP_SEEK "struct vnode *vp" "off_t oldoff" "off_t newoff" \
+.Fn VOP_SEEK "struct vnode *vp" "off_t oldoffset" "int whence" \
+"off_t givenoffset" "off_t *newoffset" "struct vattr *vattr" \
 "struct ucred *cred"
 .Ft int
 .Fn VOP_REMOVE "struct vnode *vp" "struct vnode *vp" \
@@ -828,18 +829,33 @@
 and
 .Xr fsync 2
 system calls.
-.It Fn VOP_SEEK "vp" "oldoff" "newoff" "cred"
-Test if the file is seekable for the specified offset
-.Fa newoff .
+.It Fn VOP_SEEK "vp" "oldoffset" "whence" "givenoffset" "*newoffset" "*vattr" \
+"*cred"
+Implements the
+.Xr lseek 1
+function on a node. It tests if the file is seekable for the specified offset
+.Fa givenoffset
+with the method 
+.Fa whence .
 The argument
 .Fa vp
 is the locked vnode of the file to test.
-For most filesystems this function simply tests if
-.Fa newoff
-is valid.
-If the specified
-.Fa newoff
-is less than zero, the function returns error code EINVAL.
+Filesystems should return the new offset in
+.Fa *newoffset
+and return EINVAL if the resulting offset is invalid. If
+.Fa *newoffset
+is
+.Dv NULL
+no value needs to be returned. If
+.Fa *vattr
+is
+.Dv NULL
+, only
+.Dv SEEK_SET
+and
+.Dv SEEK_CUR
+are valid operations for
+.Fa whence .
 .It Fn VOP_REMOVE "dvp" "vp" "cnp"
 Remove a file.
 The argument
@@ -1462,6 +1478,9 @@
 .It Bq Er EIO
 a read error occurred while reading the directory or reading the
 contents of a symbolic link
+.It Bq Er ENXIO
+a seek for a data segment or hole segment in a file indicated no more segments
+from the given offset are defined.
 .It Bq Er EROFS
 the filesystem is read-only
 .El
Index: sys/fs/ptyfs/ptyfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/ptyfs/ptyfs_vnops.c,v
retrieving revision 1.16
diff -u -r1.16 ptyfs_vnops.c
--- sys/fs/ptyfs/ptyfs_vnops.c	23 Jul 2006 22:06:10 -0000	1.16
+++ sys/fs/ptyfs/ptyfs_vnops.c	21 Sep 2006 18:37:57 -0000
@@ -128,7 +128,7 @@
 #define ptyfs_revoke	genfs_revoke
 #define	ptyfs_mmap	genfs_eopnotsupp
 #define	ptyfs_fsync	genfs_nullop
-#define	ptyfs_seek	genfs_nullop
+#define	ptyfs_seek	genfs_seek
 #define	ptyfs_remove	genfs_eopnotsupp
 #define	ptyfs_link	genfs_abortop
 #define	ptyfs_rename	genfs_eopnotsupp
Index: sys/fs/union/union_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/fs/union/union_vnops.c,v
retrieving revision 1.16
diff -u -r1.16 union_vnops.c
--- sys/fs/union/union_vnops.c	14 May 2006 21:31:52 -0000	1.16
+++ sys/fs/union/union_vnops.c	21 Sep 2006 18:37:57 -0000
@@ -1207,8 +1207,11 @@
 {
 	struct vop_seek_args /* {
 		struct vnode *a_vp;
-		off_t  a_oldoff;
-		off_t  a_newoff;
+		off_t a_oldoffset;
+		int a_whence;
+		off_t a_givenoffset;
+		off_t *a_newoffset;
+		struct vattr *a_vattr;
 		kauth_cred_t a_cred;
 	} */ *ap = v;
 	struct vnode *ovp = OTHERVP(ap->a_vp);
Index: sys/kern/vfs_syscalls.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_syscalls.c,v
retrieving revision 1.270
diff -u -r1.270 vfs_syscalls.c
--- sys/kern/vfs_syscalls.c	13 Sep 2006 10:07:42 -0000	1.270
+++ sys/kern/vfs_syscalls.c	21 Sep 2006 18:38:00 -0000
@@ -2118,7 +2118,7 @@
 	struct file *fp;
 	struct vnode *vp;
 	struct vattr vattr;
-	off_t newoff;
+	off_t newoffset;
 	int error;
 
 	if ((fp = fd_getfile(fdp, SCARG(uap, fd))) == NULL)
@@ -2131,29 +2131,17 @@
 		error = ESPIPE;
 		goto out;
 	}
-
-	switch (SCARG(uap, whence)) {
-	case SEEK_CUR:
-		newoff = fp->f_offset + SCARG(uap, offset);
-		break;
-	case SEEK_END:
-		error = VOP_GETATTR(vp, &vattr, cred, l);
-		if (error)
-			goto out;
-		newoff = SCARG(uap, offset) + vattr.va_size;
-		break;
-	case SEEK_SET:
-		newoff = SCARG(uap, offset);
-		break;
-	default:
-		error = EINVAL;
-		goto out;
-	}
-	if ((error = VOP_SEEK(vp, fp->f_offset, newoff, cred)) != 0)
+	error = VOP_GETATTR(vp, &vattr, cred, l);
+	if (error)
 		goto out;
 
-	*(off_t *)retval = fp->f_offset = newoff;
- out:
+	error = VOP_SEEK(vp, fp->f_offset, SCARG(uap, whence),
+	    SCARG(uap, offset), &newoffset, &vattr, cred);
+
+	if (error == 0)
+		*(off_t *)retval = fp->f_offset = newoffset;
+
+out:
 	FILE_UNUSE(fp, l);
 	return (error);
 }
@@ -2199,7 +2187,8 @@
 	 * XXX This works because no file systems actually
 	 * XXX take any action on the seek operation.
 	 */
-	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
+	error = VOP_SEEK(vp, fp->f_offset, SEEK_SET, offset, NULL, NULL, fp->f_cred);
+	if (error != 0)
 		goto out;
 
 	/* dofileread() will unuse the descriptor for us */
@@ -2252,7 +2241,8 @@
 	 * XXX This works because no file systems actually
 	 * XXX take any action on the seek operation.
 	 */
-	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
+	error = VOP_SEEK(vp, fp->f_offset, SEEK_SET, offset, NULL, NULL, fp->f_cred);
+	if (error != 0)
 		goto out;
 
 	/* dofilereadv() will unuse the descriptor for us */
@@ -2305,7 +2295,8 @@
 	 * XXX This works because no file systems actually
 	 * XXX take any action on the seek operation.
 	 */
-	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
+	error = VOP_SEEK(vp, fp->f_offset, SEEK_SET, offset, NULL, NULL, fp->f_cred);
+	if (error != 0)
 		goto out;
 
 	/* dofilewrite() will unuse the descriptor for us */
@@ -2358,7 +2349,8 @@
 	 * XXX This works because no file systems actually
 	 * XXX take any action on the seek operation.
 	 */
-	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
+	error = VOP_SEEK(vp, fp->f_offset, SEEK_SET, offset, NULL, NULL, fp->f_cred);
+	if (error != 0)
 		goto out;
 
 	/* dofilewritev() will unuse the descriptor for us */
Index: sys/kern/vnode_if.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vnode_if.c,v
retrieving revision 1.66
diff -u -r1.66 vnode_if.c
--- sys/kern/vnode_if.c	13 Jul 2006 12:00:25 -0000	1.66
+++ sys/kern/vnode_if.c	21 Sep 2006 18:38:00 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: vnode_if.c,v 1.66 2006/07/13 12:00:25 martin Exp $	*/
+/*	$NetBSD$	*/
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
@@ -40,7 +40,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vnode_if.c,v 1.66 2006/07/13 12:00:25 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 
 /*
@@ -741,8 +741,11 @@
 };
 int
 VOP_SEEK(struct vnode *vp,
-    off_t oldoff,
-    off_t newoff,
+    off_t oldoffset,
+    int whence,
+    off_t givenoffset,
+    off_t *newoffset,
+    struct vattr *vattr,
     kauth_cred_t cred)
 {
 	struct vop_seek_args a;
@@ -750,8 +753,11 @@
 #endif
 	a.a_desc = VDESC(vop_seek);
 	a.a_vp = vp;
-	a.a_oldoff = oldoff;
-	a.a_newoff = newoff;
+	a.a_oldoffset = oldoffset;
+	a.a_whence = whence;
+	a.a_givenoffset = givenoffset;
+	a.a_newoffset = newoffset;
+	a.a_vattr = vattr;
 	a.a_cred = cred;
 	return (VCALL(vp, VOFFSET(vop_seek), &a));
 }
Index: sys/kern/vnode_if.src
===================================================================
RCS file: /cvsroot/src/sys/kern/vnode_if.src,v
retrieving revision 1.50
diff -u -r1.50 vnode_if.src
--- sys/kern/vnode_if.src	14 May 2006 21:15:12 -0000	1.50
+++ sys/kern/vnode_if.src	21 Sep 2006 18:38:00 -0000
@@ -266,13 +266,16 @@
 };
 
 #
-# Needs work: Is newoff right?  What's it mean?
 # XXX Locking protocol?
+# XXX kauth_cred_t cred is not used
 #
 vop_seek {
 	IN struct vnode *vp;
-	IN off_t oldoff;
-	IN off_t newoff;
+	IN off_t oldoffset;
+	IN int whence;
+	IN off_t givenoffset;
+	OUT off_t *newoffset;
+	IN struct vattr *vattr;
 	IN kauth_cred_t cred;
 };
 
Index: sys/miscfs/deadfs/dead_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/deadfs/dead_vnops.c,v
retrieving revision 1.39
diff -u -r1.39 dead_vnops.c
--- sys/miscfs/deadfs/dead_vnops.c	14 May 2006 21:31:52 -0000	1.39
+++ sys/miscfs/deadfs/dead_vnops.c	21 Sep 2006 18:38:00 -0000
@@ -64,7 +64,7 @@
 int	dead_poll(void *);
 #define dead_mmap	genfs_badop
 #define dead_fsync	genfs_nullop
-#define dead_seek	genfs_nullop
+#define dead_seek	genfs_nullop	/* no size -> genfs_nullop allowed */
 #define dead_remove	genfs_badop
 #define dead_link	genfs_badop
 #define dead_rename	genfs_badop
Index: sys/miscfs/genfs/genfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/genfs/genfs_vnops.c,v
retrieving revision 1.129
diff -u -r1.129 genfs_vnops.c
--- sys/miscfs/genfs/genfs_vnops.c	15 Sep 2006 15:51:12 -0000	1.129
+++ sys/miscfs/genfs/genfs_vnops.c	21 Sep 2006 18:38:01 -0000
@@ -50,6 +50,7 @@
 #include <sys/mman.h>
 #include <sys/file.h>
 #include <sys/kauth.h>
+#include <sys/unistd.h>
 
 #include <miscfs/genfs/genfs.h>
 #include <miscfs/genfs/genfs_node.h>
@@ -90,15 +91,50 @@
 {
 	struct vop_seek_args /* {
 		struct vnode *a_vp;
-		off_t a_oldoff;
-		off_t a_newoff;
-		kauth_cred_t cred;
-	} */ *ap = v;
+		off_t a_oldoffset;
+		int a_whence;
+		off_t a_givenoffset;
+		off_t *a_newoffset;
+		struct vattr *a_vattr;
+		kauth_cred_t a_cred;
+	}; */ *ap = v;
+	off_t newoffset;
 
-	if (ap->a_newoff < 0)
-		return (EINVAL);
+	/* initialise return value with old offset */
+	newoffset = ap->a_oldoffset;
+	switch (ap->a_whence) {
+	case SEEK_CUR:
+		newoffset = ap->a_oldoffset + ap->a_givenoffset;
+		break;
+	case SEEK_END:
+		newoffset = ap->a_givenoffset + ap->a_vattr->va_size;
+		break;
+	case SEEK_SET:
+		newoffset = ap->a_givenoffset;
+		break;
+	case SEEK_DATA:
+		/* if at start, there is one data block */
+		if (ap->a_givenoffset != 0)
+			return ENXIO;
+		newoffset = 0;
+		break;
+	case SEEK_HOLE:
+		/* there exists one virtual hole at the end of the file */
+		if (ap->a_givenoffset > ap->a_vattr->va_size)
+			return ENXIO;
+		newoffset = ap->a_vattr->va_size;
+		break;
+	default:
+		return EINVAL;
+	}
 
-	return (0);
+	if (newoffset < 0)
+		return EINVAL;
+
+	if (ap->a_newoffset)
+		*(ap->a_newoffset) = newoffset;
+
+	return 0;
 }
 
 int
Index: sys/miscfs/kernfs/kernfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/kernfs/kernfs_vnops.c,v
retrieving revision 1.125
diff -u -r1.125 kernfs_vnops.c
--- sys/miscfs/kernfs/kernfs_vnops.c	23 Jun 2006 20:54:21 -0000	1.125
+++ sys/miscfs/kernfs/kernfs_vnops.c	21 Sep 2006 18:38:01 -0000
@@ -190,7 +190,7 @@
 #define	kernfs_poll	genfs_poll
 #define kernfs_revoke	genfs_revoke
 #define	kernfs_fsync	genfs_nullop
-#define	kernfs_seek	genfs_nullop
+#define	kernfs_seek	genfs_seek
 #define	kernfs_remove	genfs_eopnotsupp
 int	kernfs_link(void *);
 #define	kernfs_rename	genfs_eopnotsupp
Index: sys/miscfs/procfs/procfs_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/procfs/procfs_vnops.c,v
retrieving revision 1.134
diff -u -r1.134 procfs_vnops.c
--- sys/miscfs/procfs/procfs_vnops.c	20 Sep 2006 08:09:05 -0000	1.134
+++ sys/miscfs/procfs/procfs_vnops.c	21 Sep 2006 18:38:01 -0000
@@ -184,7 +184,7 @@
 #define	procfs_poll	genfs_poll
 #define procfs_revoke	genfs_revoke
 #define	procfs_fsync	genfs_nullop
-#define	procfs_seek	genfs_nullop
+#define	procfs_seek	genfs_seek
 #define	procfs_remove	genfs_eopnotsupp
 int	procfs_link(void *);
 #define	procfs_rename	genfs_eopnotsupp
Index: sys/miscfs/specfs/specdev.h
===================================================================
RCS file: /cvsroot/src/sys/miscfs/specfs/specdev.h,v
retrieving revision 1.30
diff -u -r1.30 specdev.h
--- sys/miscfs/specfs/specdev.h	14 May 2006 21:32:21 -0000	1.30
+++ sys/miscfs/specfs/specdev.h	21 Sep 2006 18:38:01 -0000
@@ -120,7 +120,7 @@
 #define spec_revoke	genfs_revoke
 #define	spec_mmap	genfs_mmap
 int	spec_fsync(void *);
-#define	spec_seek	genfs_nullop		/* XXX should query device */
+#define	spec_seek	genfs_seek		/* XXX should query device */
 #define	spec_remove	genfs_badop
 #define	spec_link	genfs_badop
 #define	spec_rename	genfs_badop
Index: sys/sys/fcntl.h
===================================================================
RCS file: /cvsroot/src/sys/sys/fcntl.h,v
retrieving revision 1.33
diff -u -r1.33 fcntl.h
--- sys/sys/fcntl.h	29 Nov 2005 22:52:02 -0000	1.33
+++ sys/sys/fcntl.h	21 Sep 2006 18:38:02 -0000
@@ -247,15 +247,21 @@
 #endif
 
 /* Always ensure that these are consistent with <stdio.h> and <unistd.h>! */
-#ifndef	SEEK_SET
+#ifndef SEEK_SET
 #define	SEEK_SET	0	/* set file offset to offset */
 #endif
-#ifndef	SEEK_CUR
+#ifndef SEEK_CUR
 #define	SEEK_CUR	1	/* set file offset to current plus offset */
 #endif
-#ifndef	SEEK_END
+#ifndef SEEK_END
 #define	SEEK_END	2	/* set file offset to EOF plus offset */
 #endif
+#ifndef SEEK_DATA
+#define	SEEK_DATA	3	/* Set file pointer to next data past offset */
+#endif
+#ifndef SEEK_HOLE
+#define	SEEK_HOLE	4	/* Set file pointer to next hole past offset */
+#endif
 
 /*
  * posix_advise advisories.
Index: sys/sys/unistd.h
===================================================================
RCS file: /cvsroot/src/sys/sys/unistd.h,v
retrieving revision 1.35
diff -u -r1.35 unistd.h
--- sys/sys/unistd.h	14 Aug 2006 18:17:48 -0000	1.35
+++ sys/sys/unistd.h	21 Sep 2006 18:38:02 -0000
@@ -108,6 +108,8 @@
 #define	SEEK_SET	0	/* set file offset to offset */
 #define	SEEK_CUR	1	/* set file offset to current plus offset */
 #define	SEEK_END	2	/* set file offset to EOF plus offset */
+#define	SEEK_DATA	3	/* Set file pointer to next data past offset */
+#define	SEEK_HOLE	4	/* Set file pointer to next hole past offset */
 
 #if defined(_NETBSD_SOURCE)
 /* whence values for lseek(2); renamed by POSIX 1003.1 */
Index: sys/sys/vnode_if.h
===================================================================
RCS file: /cvsroot/src/sys/sys/vnode_if.h,v
retrieving revision 1.62
diff -u -r1.62 vnode_if.h
--- sys/sys/vnode_if.h	13 Jul 2006 12:00:26 -0000	1.62
+++ sys/sys/vnode_if.h	21 Sep 2006 18:38:02 -0000
@@ -1,4 +1,4 @@
-/*	$NetBSD: vnode_if.h,v 1.62 2006/07/13 12:00:26 martin Exp $	*/
+/*	$NetBSD$	*/
 
 /*
  * Warning: DO NOT EDIT! This file is automatically generated!
@@ -224,12 +224,16 @@
 struct vop_seek_args {
 	const struct vnodeop_desc *a_desc;
 	struct vnode *a_vp;
-	off_t a_oldoff;
-	off_t a_newoff;
+	off_t a_oldoffset;
+	int a_whence;
+	off_t a_givenoffset;
+	off_t *a_newoffset;
+	struct vattr *a_vattr;
 	kauth_cred_t a_cred;
 };
 extern const struct vnodeop_desc vop_seek_desc;
-int VOP_SEEK(struct vnode *, off_t, off_t, kauth_cred_t);
+int VOP_SEEK(struct vnode *, off_t, int, off_t, off_t *, struct vattr *, 
+    kauth_cred_t);
 
 struct vop_remove_args {
 	const struct vnodeop_desc *a_desc;

--3MwIy2ne0vdjdPXF--

--tsOsTdHNUZQcU9Ye
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2.1 (NetBSD)

iQEVAwUBRRLeToKcNwBDyKpoAQJikQgAmf39PAO5dGdO9Wv1nYdUtWemaTtwKg9B
lCsxQX1NbN2rZGdU5pTI5rl3jgWe5pyUD2L6SjWqjjluW531NBEIGfEWNfEByI7M
LWq0rtLXrO3sfYxqowlrQonqVRpH5PhC5o5mMEYrLAepme7RuApp4YL3ZeSzU+My
6Bf3OcY4nX/A90lo2noUku1IkuJ2HuB2Ggr0+PmYM247cB88nbCAfjY8VGaQ4fj9
TRaqn04gAhQgMVEQFukNa+tP8WkccA/bl5zZr/nDKh1Mb9otMybdN/2fWDyZOIcP
hrYhI1ds7I0bjOB7LVskMduP32Ev/p9vSa5sgdJOLme3dFaWGGPr3w==
=ZJDa
-----END PGP SIGNATURE-----

--tsOsTdHNUZQcU9Ye--