fix
diff --git a/ChangeLog b/ChangeLog
index 963df14..f246add 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2004-09-16  Miklos Szeredi <miklos@szeredi.hu>
+
+	* Check memory allocation failures in libfuse
+	
 2004-09-14  Miklos Szeredi <miklos@szeredi.hu>
 
 	* Check temporary file creation failure in do_getdir().  Bug
diff --git a/include/fuse.h b/include/fuse.h
index 845e645..81ef0d4 100644
--- a/include/fuse.h
+++ b/include/fuse.h
@@ -231,8 +231,9 @@
  * operations are called. 
  *
  * @param f the FUSE handle
+ * @return 0 if no error occured, -1 otherwise
  */
-void fuse_loop(struct fuse *f);
+int fuse_loop(struct fuse *f);
 
 /**
  * Exit from event loop
@@ -252,8 +253,9 @@
  * the application.
  *
  * @param f the FUSE handle
+ * @return 0 if no error occured, -1 otherwise
  */
-void fuse_loop_mt(struct fuse *f);
+int fuse_loop_mt(struct fuse *f);
 
 /**
  * Get the current context
@@ -284,7 +286,7 @@
 typedef void (*fuse_processor_t)(struct fuse *, struct fuse_cmd *, void *);
 struct fuse_cmd *__fuse_read_cmd(struct fuse *f);
 void __fuse_process_cmd(struct fuse *f, struct fuse_cmd *cmd);
-void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data);
+int __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data);
 int __fuse_exited(struct fuse* f);
 
 #ifdef __cplusplus
diff --git a/lib/fuse.c b/lib/fuse.c
index 659643b..a207fc0 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -159,14 +159,18 @@
     abort();
 }
 
-static void hash_name(struct fuse *f, struct node *node, fino_t parent,
-                      const char *name)
+static int hash_name(struct fuse *f, struct node *node, fino_t parent,
+                     const char *name)
 {
     size_t hash = name_hash(f, parent, name);
     node->parent = parent;
     node->name = strdup(name);
+    if (node->name == NULL)
+        return -1;
+
     node->name_next = f->name_table[hash];
-    f->name_table[hash] = node;    
+    f->name_table[hash] = node;
+    return 0;
 }
 
 static void unhash_name(struct fuse *f, struct node *node)
@@ -210,14 +214,20 @@
     }
 
     node = (struct node *) calloc(1, sizeof(struct node));
+    if (node == NULL)
+        return NULL;
+
     node->mode = mode;
     node->rdev = rdev;
     node->open_count = 0;
     node->is_hidden = 0;
     node->ino = next_ino(f);
     node->generation = f->generation;
+    if (hash_name(f, node, parent, name) == -1) {
+        free(node);
+        return NULL;
+    }
     hash_ino(f, node);
-    hash_name(f, node, parent, name);
 
   out:
     node->version = version;
@@ -361,14 +371,18 @@
     if (newnode != NULL) {
         if (hide) {
             fprintf(stderr, "fuse: hidden file got created during hiding\n");
-            err = -1;
+            err = -EBUSY;
             goto out;
         }
         unhash_name(f, newnode);
     }
         
     unhash_name(f, node);
-    hash_name(f, node, newdir, newname);
+    if (hash_name(f, node, newdir, newname) == -1) {
+        err = -ENOMEM;
+        goto out;
+    }
+        
     if (hide)
         node->is_hidden = 1;
 
@@ -464,15 +478,20 @@
 
     outsize = sizeof(struct fuse_out_header) + argsize;
     outbuf = (char *) malloc(outsize);
-    out = (struct fuse_out_header *) outbuf;
-    memset(out, 0, sizeof(struct fuse_out_header));
-    out->unique = in->unique;
-    out->error = error;
-    if (argsize != 0)
-        memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
-
-    res = send_reply_raw(f, outbuf, outsize, locked);
-    free(outbuf);
+    if (outbuf == NULL) {
+        fprintf(stderr, "fuse: failed to allocate reply buffer\n");
+        res = -ENOMEM;
+    } else {
+        out = (struct fuse_out_header *) outbuf;
+        memset(out, 0, sizeof(struct fuse_out_header));
+        out->unique = in->unique;
+        out->error = error;
+        if (argsize != 0)
+            memcpy(outbuf + sizeof(struct fuse_out_header), arg, argsize);
+        
+        res = send_reply_raw(f, outbuf, outsize, locked);
+        free(outbuf);
+    }
 
     return res;
 }
@@ -538,22 +557,18 @@
 {
     char newname[64];
     char *newpath;
-    int err = -1;
+    int err = -EBUSY;
 
-    if (!f->op.rename || !f->op.unlink)
-        return -EBUSY;
-
-    newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
-    if (newpath) {
-        err = f->op.rename(oldpath, newpath);
-        if (!err)
-            err = rename_node(f, dir, oldname, dir, newname, 1);
-        free(newpath);
+    if (f->op.rename && f->op.unlink) {
+        newpath = hidden_name(f, dir, oldname, newname, sizeof(newname));
+        if (newpath) {
+            int res = f->op.rename(oldpath, newpath);
+            if (res == 0)
+                err = rename_node(f, dir, oldname, dir, newname, 1);
+            free(newpath);
+        }
     }
-    if (err)
-        return -EBUSY;
-    
-    return 0;
+    return err;
 }
 
 static int lookup_path(struct fuse *f, fino_t ino, int version,  char *name,
@@ -569,15 +584,19 @@
         memset(arg, 0, sizeof(struct fuse_entry_out));
         convert_stat(&buf, &arg->attr);
         node = find_node(f, ino, name, &arg->attr, version);
-        arg->ino = node->ino;
-        arg->generation = node->generation;
-        arg->entry_valid = ENTRY_REVALIDATE_TIME;
-        arg->entry_valid_nsec = 0;
-        arg->attr_valid = ATTR_REVALIDATE_TIME;
-        arg->attr_valid_nsec = 0;
-        if (f->flags & FUSE_DEBUG) {
-            printf("   INO: %li\n", arg->ino);
-            fflush(stdout);
+        if (node == NULL)
+            res = -ENOMEM;
+        else {
+            arg->ino = node->ino;
+            arg->generation = node->generation;
+            arg->entry_valid = ENTRY_REVALIDATE_TIME;
+            arg->entry_valid_nsec = 0;
+            arg->attr_valid = ATTR_REVALIDATE_TIME;
+            arg->attr_valid_nsec = 0;
+            if (f->flags & FUSE_DEBUG) {
+                printf("   INO: %li\n", arg->ino);
+                fflush(stdout);
+            }
         }
     }
     return res;
@@ -950,7 +969,7 @@
                 if (res == 0) {
                     res = f->op.rename(oldpath, newpath);
                     if (res == 0)
-                        rename_node(f, olddir, oldname, newdir, newname, 0);
+                        res = rename_node(f, olddir, oldname, newdir, newname, 0);
                 }
             }
             free(newpath);
@@ -1096,42 +1115,46 @@
     int res;
     char *path;
     char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + arg->size);
-    struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-    char *buf = outbuf + sizeof(struct fuse_out_header);
-    size_t size;
-    size_t outsize;
-
-    res = -ENOENT;
-    path = get_path(f, in->ino);
-    if (path != NULL) {
-        if (f->flags & FUSE_DEBUG) {
-            printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
-                   arg->offset);
-            fflush(stdout);
+    if (outbuf == NULL)
+        send_reply(f, in, -ENOMEM, NULL, 0);
+    else {
+        struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+        char *buf = outbuf + sizeof(struct fuse_out_header);
+        size_t size;
+        size_t outsize;
+        
+        res = -ENOENT;
+        path = get_path(f, in->ino);
+        if (path != NULL) {
+            if (f->flags & FUSE_DEBUG) {
+                printf("READ[%u] %u bytes from %llu\n", arg->fh, arg->size,
+                       arg->offset);
+                fflush(stdout);
+            }
+            
+            res = -ENOSYS;
+            if (f->op.read)
+                res = f->op.read(path, buf, arg->size, arg->offset);
+            free(path);
         }
-
-        res = -ENOSYS;
-        if (f->op.read)
-            res = f->op.read(path, buf, arg->size, arg->offset);
-        free(path);
-    }
-    
-    size = 0;
-    if (res >= 0) {
-        size = res;
-        res = 0;
-        if (f->flags & FUSE_DEBUG) {
-            printf("   READ[%u] %u bytes\n", arg->fh, size);
-            fflush(stdout);
+        
+        size = 0;
+        if (res >= 0) {
+            size = res;
+            res = 0;
+            if (f->flags & FUSE_DEBUG) {
+                printf("   READ[%u] %u bytes\n", arg->fh, size);
+                fflush(stdout);
+            }
         }
+        memset(out, 0, sizeof(struct fuse_out_header));
+        out->unique = in->unique;
+        out->error = res;
+        outsize = sizeof(struct fuse_out_header) + size;
+        
+        send_reply_raw(f, outbuf, outsize, 0);
+        free(outbuf);
     }
-    memset(out, 0, sizeof(struct fuse_out_header));
-    out->unique = in->unique;
-    out->error = res;
-    outsize = sizeof(struct fuse_out_header) + size;
-    
-    send_reply_raw(f, outbuf, outsize, 0);
-    free(outbuf);
 }
 
 static void do_write(struct fuse *f, struct fuse_in_header *in,
@@ -1263,21 +1286,25 @@
 {
     int res;
     char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
-    struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-    char *value = outbuf + sizeof(struct fuse_out_header);
-
-    res = common_getxattr(f, in, name, value, size);
-    size = 0;
-    if (res > 0) {
-        size = res;
-        res = 0;
+    if (outbuf == NULL)
+        send_reply(f, in, -ENOMEM, NULL, 0);
+    else {
+        struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+        char *value = outbuf + sizeof(struct fuse_out_header);
+        
+        res = common_getxattr(f, in, name, value, size);
+        size = 0;
+        if (res > 0) {
+            size = res;
+            res = 0;
+        }
+        memset(out, 0, sizeof(struct fuse_out_header));
+        out->unique = in->unique;
+        out->error = res;
+        
+        send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
+        free(outbuf);
     }
-    memset(out, 0, sizeof(struct fuse_out_header));
-    out->unique = in->unique;
-    out->error = res;
-
-    send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
-    free(outbuf);
 }
 
 static void do_getxattr_size(struct fuse *f, struct fuse_in_header *in,
@@ -1327,21 +1354,25 @@
 {
     int res;
     char *outbuf = (char *) malloc(sizeof(struct fuse_out_header) + size);
-    struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
-    char *list = outbuf + sizeof(struct fuse_out_header);
-
-    res = common_listxattr(f, in, list, size);
-    size = 0;
-    if (res > 0) {
-        size = res;
-        res = 0;
+    if (outbuf == NULL)
+        send_reply(f, in, -ENOMEM, NULL, 0);
+    else {
+        struct fuse_out_header *out = (struct fuse_out_header *) outbuf;
+        char *list = outbuf + sizeof(struct fuse_out_header);
+        
+        res = common_listxattr(f, in, list, size);
+        size = 0;
+        if (res > 0) {
+            size = res;
+            res = 0;
+        }
+        memset(out, 0, sizeof(struct fuse_out_header));
+        out->unique = in->unique;
+        out->error = res;
+        
+        send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
+        free(outbuf);
     }
-    memset(out, 0, sizeof(struct fuse_out_header));
-    out->unique = in->unique;
-    out->error = res;
-
-    send_reply_raw(f, outbuf, sizeof(struct fuse_out_header) + size, 0);
-    free(outbuf);
 }
 
 static void do_listxattr_size(struct fuse *f, struct fuse_in_header *in)
@@ -1525,7 +1556,16 @@
     void *inarg;
 
     cmd = (struct fuse_cmd *) malloc(sizeof(struct fuse_cmd));
+    if (cmd == NULL) {
+        fprintf(stderr, "fuse: failed to allocate cmd in read\n");
+        return NULL;
+    }
     cmd->buf = (char *) malloc(FUSE_MAX_IN);
+    if (cmd->buf == NULL) {
+        fprintf(stderr, "fuse: failed to allocate read buffer\n");
+        free(cmd);
+        return NULL;
+    }
     in = (struct fuse_in_header *) cmd->buf;
     inarg = cmd->buf + sizeof(struct fuse_in_header);
 
@@ -1563,16 +1603,16 @@
     return cmd;
 }
 
-void fuse_loop(struct fuse *f)
+int fuse_loop(struct fuse *f)
 {
     if (f == NULL)
-        return;
+        return -1;
 
     while (1) {
         struct fuse_cmd *cmd;
 
         if (__fuse_exited(f))
-            return;
+            return 0;
 
         cmd = __fuse_read_cmd(f);
         if (cmd == NULL)
@@ -1580,6 +1620,7 @@
 
         __fuse_process_cmd(f, cmd);
     }
+    return 0;
 }
 
 int fuse_invalidate(struct fuse *f, const char *path)
@@ -1668,12 +1709,15 @@
         return 0;
 }
 
-static void parse_lib_opts(struct fuse *f, const char *opts)
+static int parse_lib_opts(struct fuse *f, const char *opts)
 {
     if (opts) {
         char *xopts = strdup(opts);
         char *s = xopts;
         char *opt;
+
+        if (xopts == NULL)
+            return -1;
         
         while((opt = strsep(&s, ","))) {
             if (strcmp(opt, "debug") == 0)
@@ -1685,6 +1729,7 @@
         }
         free(xopts);
     }
+    return 0;
 }
 
 struct fuse *fuse_new(int fd, const char *opts, const struct fuse_operations *op)
@@ -1693,13 +1738,15 @@
     struct node *root;
 
     f = (struct fuse *) calloc(1, sizeof(struct fuse));
+    if (f == NULL)
+        goto out;
 
-    if (check_version(f) == -1) {
-        free(f);
-        return NULL;
-    }
+    if (check_version(f) == -1)
+        goto out_free;
 
-    parse_lib_opts(f, opts);
+    if (parse_lib_opts(f, opts) == -1)
+        goto out_free;
+
     f->fd = fd;
     f->ctr = 0;
     f->generation = 0;
@@ -1707,9 +1754,15 @@
     f->name_table_size = 14057;
     f->name_table = (struct node **)
         calloc(1, sizeof(struct node *) * f->name_table_size);
+    if (f->name_table == NULL)
+        goto out_free;
+
     f->ino_table_size = 14057;
     f->ino_table = (struct node **)
         calloc(1, sizeof(struct node *) * f->ino_table_size);
+    if (f->ino_table == NULL)
+        goto out_free_name_table;
+
     pthread_mutex_init(&f->lock, NULL);
     f->numworker = 0;
     f->numavail = 0;
@@ -1720,15 +1773,33 @@
     f->exited = 0;
 
     root = (struct node *) calloc(1, sizeof(struct node));
+    if (root == NULL)
+        goto out_free_ino_table;
+
     root->mode = 0;
     root->rdev = 0;
     root->name = strdup("/");
+    if (root->name == NULL)
+        goto out_free_root;
+
     root->parent = 0;
     root->ino = FUSE_ROOT_INO;
     root->generation = 0;
     hash_ino(f, root);
 
     return f;
+
+ out_free_root:
+    free(root);
+ out_free_ino_table:
+    free(f->ino_table);
+ out_free_name_table:
+    free(f->name_table);
+ out_free:
+    free(f);
+ out:
+    fprintf(stderr, "fuse: failed to allocate fuse object\n");
+    return NULL;
 }
 
 void fuse_destroy(struct fuse *f)
diff --git a/lib/fuse_mt.c b/lib/fuse_mt.c
index 71196a9..8bac5ff 100644
--- a/lib/fuse_mt.c
+++ b/lib/fuse_mt.c
@@ -25,12 +25,23 @@
     fuse_processor_t proc;
 };
 
-static void start_thread(struct fuse_worker *w, pthread_t *thread_id);
+static int start_thread(struct fuse_worker *w, pthread_t *thread_id);
 
 static void *do_work(void *data)
 {
     struct fuse_worker *w = (struct fuse_worker *) data;
     struct fuse *f = w->f;
+    struct fuse_context *ctx;
+
+    ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
+    if (ctx == NULL) {
+        fprintf(stderr, "fuse: failed to allocate fuse context\n");
+        pthread_mutex_lock(&f->lock);
+        f->numavail --;
+        pthread_mutex_unlock(&f->lock);
+        return NULL;
+    }
+    pthread_setspecific(f->context_key, ctx);
 
     pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
     pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@@ -48,11 +59,19 @@
         if (f->numavail == 0 && f->numworker < FUSE_MAX_WORKERS) {
             pthread_mutex_lock(&f->lock);
             if (f->numworker < FUSE_MAX_WORKERS) {
+                /* FIXME: threads should be stored in a list instead
+                   of an array */
+                int res;
                 pthread_t *thread_id = &w->threads[f->numworker];
                 f->numavail ++;
                 f->numworker ++;
                 pthread_mutex_unlock(&f->lock);
-                start_thread(w, thread_id);
+                res = start_thread(w, thread_id);
+                if (res == -1) {
+                    pthread_mutex_lock(&f->lock);
+                    f->numavail --;
+                    pthread_mutex_unlock(&f->lock);
+                }
             } else
                 pthread_mutex_unlock(&f->lock);
         }
@@ -63,7 +82,7 @@
     return NULL;
 }
 
-static void start_thread(struct fuse_worker *w, pthread_t *thread_id)
+static int start_thread(struct fuse_worker *w, pthread_t *thread_id)
 {
     sigset_t oldset;
     sigset_t newset;
@@ -76,23 +95,16 @@
     pthread_sigmask(SIG_SETMASK, &oldset, NULL);
     if (res != 0) {
         fprintf(stderr, "Error creating thread: %s\n", strerror(res));
-        exit(1);
+        return -1;
     }
     
     pthread_detach(*thread_id);
+    return 0;
 }
 
 static struct fuse_context *mt_getcontext(struct fuse *f)
 {
-    struct fuse_context *ctx;
-
-    ctx = (struct fuse_context *) pthread_getspecific(f->context_key);
-    if (ctx == NULL) {
-        ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
-        pthread_setspecific(f->context_key, ctx);
-    }
-
-    return ctx;
+    return (struct fuse_context *) pthread_getspecific(f->context_key);
 }
 
 static void mt_freecontext(void *data)
@@ -100,13 +112,17 @@
     free(data);
 }
 
-void __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
+int __fuse_loop_mt(struct fuse *f, fuse_processor_t proc, void *data)
 {
     struct fuse_worker *w;
     int res;
     int i;
 
     w = malloc(sizeof(struct fuse_worker));    
+    if (w == NULL) {
+        fprintf(stderr, "fuse: failed to allocate worker structure\n");
+        return -1;
+    }
     memset(w, 0, sizeof(struct fuse_worker));
     w->f = f;
     w->data = data;
@@ -116,7 +132,7 @@
     res = pthread_key_create(&f->context_key, mt_freecontext);
     if (res != 0) {
         fprintf(stderr, "Failed to create thread specific key\n");
-        exit(1);
+        return -1;
     }
     f->getcontext = mt_getcontext;
     do_work(w);
@@ -127,12 +143,13 @@
     pthread_mutex_unlock(&f->lock);
     pthread_key_delete(f->context_key);
     free(w);
+    return 0;
 }
 
-void fuse_loop_mt(struct fuse *f)
+int fuse_loop_mt(struct fuse *f)
 {
     if (f == NULL)
-        return;
+        return -1;
 
-    __fuse_loop_mt(f, (fuse_processor_t) __fuse_process_cmd, NULL);
+    return __fuse_loop_mt(f, (fuse_processor_t) __fuse_process_cmd, NULL);
 }
diff --git a/lib/helper.c b/lib/helper.c
index b75855a..70c4bd8 100644
--- a/lib/helper.c
+++ b/lib/helper.c
@@ -119,18 +119,23 @@
     return 0;
 }
 
-static void add_option_to(const char *opt, char **optp)
+static int add_option_to(const char *opt, char **optp)
 {
     unsigned len = strlen(opt);
     if (*optp) {
         unsigned oldlen = strlen(*optp);
         *optp = realloc(*optp, oldlen + 1 + len + 1);
+        if (*optp == NULL)
+            return -1;
         (*optp)[oldlen] = ',';
         strcpy(*optp + oldlen + 1, opt);
     } else {
         *optp = malloc(len + 1);
+        if (*optp == NULL)
+            return -1;
         strcpy(*optp, opt);
     }
+    return 0;
 }
 
 static void add_options(char **lib_optp, char **kernel_optp, const char *opts)
@@ -138,12 +143,22 @@
     char *xopts = strdup(opts);
     char *s = xopts;
     char *opt;
-    
+
+    if (xopts == NULL) {
+        fprintf(stderr, "fuse: memory allocation failed\n");
+        exit(1);
+    }
+
     while((opt = strsep(&s, ",")) != NULL) {
+        int res;
         if (fuse_is_lib_option(opt))
-            add_option_to(opt, lib_optp);
+            res = add_option_to(opt, lib_optp);
         else
-            add_option_to(opt, kernel_optp);
+            res = add_option_to(opt, kernel_optp);
+        if (res == -1) {
+            fprintf(stderr, "fuse: memory allocation failed\n");
+            exit(1);
+        }
     }
     free(xopts);
 }
@@ -168,6 +183,10 @@
         basename++;
 
     fsname_opt = malloc(strlen(basename) + 64);
+    if (fsname_opt == NULL) {
+        fprintf(stderr, "fuse: memory allocation failed\n");
+        exit(1);
+    }
     sprintf(fsname_opt, "fsname=%s", basename);
     add_options(&lib_opts, &kernel_opts, fsname_opt);
     free(fsname_opt);
@@ -213,8 +232,13 @@
                 else
                     invalid_option(argv, argctr);
             }
-        } else if (fuse_mountpoint == NULL)
+        } else if (fuse_mountpoint == NULL) {
             fuse_mountpoint = strdup(argv[argctr]);
+            if (fuse_mountpoint == NULL) {
+                fprintf(stderr, "fuse: memory allocation failed\n");
+                exit(1);
+            }
+        }
         else
             invalid_option(argv, argctr);
     }