add fuse_invalidate() to library API
diff --git a/ChangeLog b/ChangeLog
index e64b898..085a01f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-07-29  Miklos Szeredi <miklos@szeredi.hu>
+
+	* Add fuse_invalidate() to library API
+
 2004-07-26  Miklos Szeredi <miklos@szeredi.hu>
 
 	* Check permissions in setattr if 'default_permissions' flag is
diff --git a/example/hello.c b/example/hello.c
index da2a9ee..040c835 100644
--- a/example/hello.c
+++ b/example/hello.c
@@ -60,10 +60,18 @@
 
 static int hello_read(const char *path, char *buf, size_t size, off_t offset)
 {
+    size_t len;
     if(strcmp(path, hello_path) != 0)
         return -ENOENT;
     
-    memcpy(buf, hello_str + offset, size);
+    len = strlen(hello_str);
+    if (offset < len) {
+        if (offset + size > len)
+            size = len - offset;
+        memcpy(buf, hello_str + offset, size);
+    } else
+        size = 0;
+
     return size;
 }
 
diff --git a/include/fuse.h b/include/fuse.h
index 726b681..845e645 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -171,6 +171,16 @@
  */
 struct fuse *fuse_get(void);
 
+/**
+ * Invalidate cached data of a file.
+ *
+ * Useful if the 'kernel_cache' mount option is given, since in that
+ * case the cache is not invalidated on file open.
+ *
+ * @return 0 on success or -errno on failure
+ */
+int fuse_invalidate(struct fuse *f, const char *path);
+
 /* ----------------------------------------------------------- *
  * More detailed API                                           *
  * ----------------------------------------------------------- */
diff --git a/kernel/dev.c b/kernel/dev.c
index a12820d..07c19ee 100644
--- a/kernel/dev.c
+++ b/kernel/dev.c
@@ -422,6 +422,7 @@
 	struct inode *inode = ilookup(fc->sb, uh->ino);
 	if (!inode)
 		return -ENOENT;
+	fuse_sync_inode(inode);
 	invalidate_inode_pages(inode->i_mapping);
 	iput(inode);
 	return 0;
@@ -433,6 +434,7 @@
 	int err = -ENOENT;
 	if (inode) {
 		if (INO_FI(inode)) {
+			fuse_sync_inode(inode);
 			invalidate_inode_pages(inode);
 			err = 0;
 		}
@@ -453,7 +455,7 @@
 		return -EINVAL;
 	}
 
-	if (copy_from_user(&uh, buf, sizeof(struct fuse_out_header)))
+	if (copy_from_user(&uh, buf, sizeof(struct fuse_user_header)))
 		return -EFAULT;
 	
 	switch (uh.opcode) {
diff --git a/lib/fuse.c b/lib/fuse.c
index 80c1488..671fbcc 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -225,6 +225,37 @@
     return node;
 }
 
+static int path_lookup(struct fuse *f, const char *path, fino_t *inop)
+{
+    fino_t ino;
+    int err;
+    char *s;
+    char *name;
+    char *tmp = strdup(path);
+    if (!tmp)
+        return -ENOMEM;
+
+    pthread_mutex_lock(&f->lock);
+    ino = FUSE_ROOT_INO;
+    err = 0;
+    for  (s = tmp; (name = strsep(&s, "/")) != NULL; ) {
+        if (name[0]) {
+            struct node *node = __lookup_node(f, ino, name);
+            if (node == NULL) {
+                err = -ENOENT;
+                break;
+            }
+            ino = node->ino;
+        }
+    }
+    pthread_mutex_unlock(&f->lock);
+    free(tmp);
+    if (!err)
+        *inop = ino;
+    
+    return err;
+}
+
 static char *add_name(char *buf, char *s, const char *name)
 {
     size_t len = strlen(name);
@@ -1544,6 +1575,40 @@
     }
 }
 
+int fuse_invalidate(struct fuse *f, const char *path)
+{
+    int res;
+    int err;
+    fino_t ino;
+    struct fuse_user_header h;
+
+    err = path_lookup(f, path, &ino);
+    if (err) {
+        if (err == -ENOENT)
+            return 0;
+        else
+            return err;
+    }
+
+    memset(&h, 0, sizeof(struct fuse_user_header));
+    h.opcode = FUSE_INVALIDATE;
+    h.ino = ino;
+    
+    if ((f->flags & FUSE_DEBUG)) {
+        printf("INVALIDATE ino: %li\n", ino);
+        fflush(stdout);
+    }
+
+    res = write(f->fd, &h, sizeof(struct fuse_user_header));
+    if (res == -1) {
+        if (errno != ENOENT) {
+            perror("fuse: writing device");
+            return -errno;
+        }
+    }
+    return 0;
+}
+
 void fuse_exit(struct fuse *f)
 {
     f->exited = 1;