summaryrefslogtreecommitdiff
path: root/smbnetfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'smbnetfs.c')
-rw-r--r--smbnetfs.c952
1 files changed, 952 insertions, 0 deletions
diff --git a/smbnetfs.c b/smbnetfs.c
new file mode 100644
index 000000000..af1d61880
--- /dev/null
+++ b/smbnetfs.c
@@ -0,0 +1,952 @@
+/*
+
+ Copyright (C) 1997, 2002, 2004 Free Software Foundation, Inc.
+ Written by Giuseppe Scrivano <gscrivano@quipo.it>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "smb.h"
+#include <stddef.h>
+#include <sys/mman.h>
+#include <hurd/fsys.h>
+#include <dirent.h>
+#include <sys/time.h>
+#include <maptime.h>
+#include <cthreads.h>
+
+/* Returned directory entries are aligned to blocks this many bytes long.
+ Must be a power of two. */
+#define DIRENT_ALIGN 4
+#define DIRENT_NAME_OFFS offsetof (struct dirent, d_name)
+/* Length is structure before the name + the name + '\0', all
+ padded to a four-byte alignment. */
+#define DIRENT_LEN(name_len) ((DIRENT_NAME_OFFS + (name_len) + 1 + (DIRENT_ALIGN - 1)) & ~(DIRENT_ALIGN - 1))
+
+struct smb_credentials credentials;
+static volatile struct mapped_time_value *maptime;
+static struct mutex smb_mutex;
+char *netfs_server_name = "smbfs";
+char *netfs_server_version = "0.1";
+int netfs_maxsymlinks = 0;
+
+struct netnode
+{
+ struct node *node;
+ char *filename;
+ struct netnode *parent;
+ struct netnode *next;
+};
+
+static struct netnode *nodes;
+
+/* Free the memory used by the nodes. */
+void
+clear_nodes ()
+{
+ if (!nodes)
+ return;
+ struct netnode *pt = nodes;
+ struct netnode *pt2 = 0;
+
+ for (;;)
+ {
+ pt2 = pt;
+ if (pt2)
+ {
+ pt = pt->next;
+ free (pt2->node);
+ free (pt2->filename);
+ free (pt2);
+ }
+ else
+ {
+ break;
+ }
+ }
+ nodes = 0;
+}
+void
+append_node_to_list(struct netnode *n)
+{
+ n->next=nodes;
+ nodes=n;
+}
+/* Create a new node and initialize it with default values. */
+int
+create_node(struct node **node)
+{
+ struct netnode *n = malloc (sizeof (struct netnode));
+ if(!n)
+ return ENOMEM;
+ *node = n->node = netfs_make_node (n);
+ if (!(*node))
+ {
+ free (n);
+ return ENOMEM;
+ }
+ append_node_to_list(n);
+ return 0;
+}
+
+struct netnode *
+search_node (char *filename, struct node *dir)
+{
+ struct netnode *pt = nodes;
+ while (pt)
+ {
+ if ((pt->parent) && (dir == pt->parent->node))
+ {
+ if (!strcmp (pt->filename, filename))
+ {
+ return pt;
+ }
+ }
+ pt = pt->next;
+ }
+ return 0;
+}
+
+void
+remove_node (struct node *np)
+{
+ struct netnode *pt;
+ struct netnode *prevpt;
+
+ for ( pt=nodes, prevpt=0 ; pt ; pt=pt->next )
+ {
+ if (pt->node == np)
+ {
+ free (pt->node);
+ free (pt->filename);
+ free (pt);
+ if (prevpt)
+ prevpt->next = pt->next;
+ else
+ nodes = pt->next;
+ break;
+ }
+ else
+ prevpt = pt;
+ }
+}
+
+void
+create_root_node ()
+{
+ struct node *node;
+ int err=create_node(&node);
+ if(err)
+ return;
+ netfs_root_node = node;
+ node->nn->parent = 0;
+ node->nn->filename = malloc(strlen(credentials.share)+1);
+ if(node->nn->filename)
+ strcpy(node->nn->filename,credentials.share);
+
+ netfs_validate_stat (node,0);
+
+ }
+
+
+int
+add_node (char *filename, struct node *top ,struct netnode** nn)
+{
+ int err;
+ struct netnode *n;
+ struct node *newnode;
+ io_statbuf_t st;
+ n = search_node (filename, top);
+ if (n)
+ {
+ *nn=n;
+ return 0;
+ }
+
+ err=create_node (&newnode);
+ if(err)
+ return err;
+ n = newnode->nn;
+ n->node = newnode;
+ if(top)
+ n->parent = top->nn;
+ else
+ n->parent = 0;
+ n->filename = malloc ( strlen(top->nn->filename) + strlen (filename) + 1);
+ if(!n->filename)
+ return 0;
+ sprintf (n->filename, "%s/%s", top->nn->filename , filename);
+
+ mutex_lock (&smb_mutex);
+ err = smbc_stat(n->filename, &st);
+ mutex_unlock (&smb_mutex);
+
+ if(err)
+ return errno;
+
+ /* Consider only directories and regular files. */
+ if(((st.st_mode & S_IFDIR) == 0) && ((st.st_mode & S_IFREG) == 0))
+ err=-1;
+ if(err)
+ {
+ remove_node (newnode);
+ return errno;
+ }
+
+ *nn=n;
+ return 0;
+}
+
+error_t
+netfs_validate_stat (struct node * np, struct iouser *cred)
+{
+ mutex_lock (&smb_mutex);
+ int err = smbc_stat(np->nn->filename, &np->nn_stat);
+ mutex_unlock (&smb_mutex);
+ if(err)
+ return errno;
+
+ return 0;
+}
+
+error_t
+netfs_attempt_chown (struct iouser * cred, struct node * np, uid_t uid,
+ uid_t gid)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_chauthor (struct iouser * cred, struct node * np, uid_t author)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_chmod (struct iouser * cred, struct node * np, mode_t mode)
+{
+ int err;
+ mutex_lock (&smb_mutex);
+ err=smbc_chmod(np->nn->filename,mode);
+ mutex_unlock (&smb_mutex);
+ if(err)
+ return errno;
+ else
+ return 0;
+}
+
+error_t
+netfs_attempt_mksymlink (struct iouser * cred, struct node * np, char *name)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkdev (struct iouser * cred, struct node * np, mode_t type,dev_t indexes)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_set_translator (struct iouser * cred, struct node * np, char *argz,size_t argzlen)
+{
+ return 0;
+}
+
+error_t
+netfs_get_translator (struct node * node, char **argz, size_t * argz_len)
+{
+ return 0;
+}
+
+error_t
+netfs_attempt_chflags (struct iouser * cred, struct node * np, int flags)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_utimes (struct iouser * cred, struct node * np,
+ struct timespec * atime, struct timespec * mtime)
+{
+ int err;
+ struct timeval tv;
+ tv.tv_usec=0;/* Not used by samba. */
+ if(mtime)
+ tv.tv_sec=mtime->tv_sec;
+ else
+ maptime_read(maptime, &tv);
+ mutex_lock (&smb_mutex);
+ err=smbc_utimes(np->nn->filename,&tv);
+ mutex_unlock (&smb_mutex);
+ if(err)
+ return errno;
+ else
+ return 0;
+}
+
+error_t
+netfs_attempt_set_size (struct iouser * cred, struct node * np, loff_t size)
+{
+
+ mutex_lock (&smb_mutex);
+ int fd = smbc_open (np->nn->filename, O_WRONLY | O_CREAT, O_RDWR);
+ mutex_unlock (&smb_mutex);
+ int ret=0;
+ if (fd < 0)
+ {
+ return errno;
+ }
+ mutex_lock (&smb_mutex);
+ int current_filesize = smbc_lseek (fd, 0, SEEK_END);
+ mutex_unlock (&smb_mutex);
+ if(current_filesize<0)
+ {
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+ if(current_filesize<size)
+ {
+ /* FIXME. trunc here. */
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ fd = smbc_open (np->nn->filename, O_WRONLY | O_TRUNC, O_RDWR);
+ mutex_unlock (&smb_mutex);
+ current_filesize=0;
+ }
+ mutex_lock (&smb_mutex);
+ ret=smbc_lseek (fd, size, SEEK_SET);
+ mutex_unlock (&smb_mutex);
+ if (ret < 0)
+ {
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return 0;
+
+}
+
+error_t
+netfs_attempt_statfs (struct iouser * cred, struct node * np,
+ fsys_statfsbuf_t * st)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_sync (struct iouser * cred, struct node * np, int wait)
+{
+ return 0;
+}
+
+error_t
+netfs_attempt_syncfs (struct iouser * cred, int wait)
+{
+ return 0;
+}
+
+error_t
+netfs_attempt_lookup (struct iouser * user, struct node * dir, char *name,
+ struct node ** np)
+{
+ error_t err = 0;
+ if (*name == '\0' || strcmp (name, ".") == 0) /*Current directory */
+ {
+ netfs_nref (dir);/*Add a reference to current directory */
+ *np = dir;
+ mutex_unlock (&dir->lock);
+ return 0;
+ }
+ else if (strcmp (name, "..") == 0) /*Parent directory */
+ {
+ if (dir->nn->parent)
+ {
+ *np = dir->nn->parent->node;
+ if (*np)
+ {
+ netfs_nref (*np);
+ err=0;
+ }
+ else
+ err = ENOENT;
+ }
+ else
+ {
+ err = ENOENT;
+ *np = 0;
+ }
+ mutex_unlock (&dir->lock);
+ return err;
+ }
+ mutex_unlock (&dir->lock);
+
+ struct netnode *n;
+
+ err = add_node (name, dir,&n);
+ if(err)
+ return err;
+ *np = n->node;
+ netfs_nref (*np);
+ if (*np)
+ err = 0;
+ return err;
+}
+
+error_t
+netfs_attempt_unlink (struct iouser * user, struct node * dir, char *name)
+{
+ char *filename;
+
+ if (dir->nn->filename)
+ filename = malloc (strlen (dir->nn->filename) + strlen (name) + 2);
+ else
+ filename = malloc (strlen (credentials.share) + strlen (name) + 1);
+ if (!filename)
+ return ENOMEM;
+
+ if (dir->nn->filename)
+ sprintf (filename, "%s/%s", dir->nn->filename, name);
+ else
+ sprintf (filename, "%s/%s", credentials.share, name);
+
+ mutex_lock (&smb_mutex);
+ error_t err = smbc_unlink (filename);
+ mutex_unlock (&smb_mutex);
+
+ free (filename);
+ if(err)
+ return errno;
+ else
+ return 0;
+}
+
+error_t
+netfs_attempt_rename (struct iouser * user, struct node * fromdir,
+ char *fromname, struct node * todir, char *toname,
+ int excl)
+{
+ char *filename; /* Origin file name. */
+ char *filename2; /* Destination file name. */
+
+ if (fromdir->nn->filename)
+ filename =malloc ( strlen (fromdir->nn->filename) +strlen (fromname) + 2);
+ else
+ filename = malloc (strlen (credentials.share) + strlen (fromname) + 1);
+ if (!filename)
+ return ENOMEM;
+
+ if (todir->nn->filename)
+ filename2 =malloc ( strlen (todir->nn->filename) +strlen (toname) + 2);
+ else
+ filename2 = malloc (strlen (credentials.share) + strlen (toname) + 1);
+
+ if (!filename2)
+ {
+ free (filename);
+ return ENOMEM;
+ }
+
+ if (fromdir->nn->filename)
+ sprintf (filename, "%s/%s", fromdir->nn->filename,fromname);
+ else
+ sprintf (filename, "%s/%s", credentials.share, fromname);
+
+ if (todir->nn->filename)
+ sprintf (filename, "%s/%s", todir->nn->filename, toname);
+ else
+ sprintf (filename, "%s/%s", credentials.share, toname);
+
+ mutex_lock (&smb_mutex);
+ error_t err = smbc_rename (filename, filename2);
+ mutex_unlock (&smb_mutex);
+
+ free (filename);
+ free (filename2);
+ return err?errno:0;
+}
+
+error_t
+netfs_attempt_mkdir (struct iouser * user, struct node * dir, char *name,
+ mode_t mode)
+{
+ char *filename;
+ error_t err;
+
+ if (dir->nn->filename)
+ filename = malloc (strlen (dir->nn->filename) + strlen (name) + 2);
+ else
+ filename = malloc (strlen (credentials.share) + strlen (name) + 1);
+ if (!filename)
+ return ENOMEM;
+
+ if (dir->nn->filename)
+ sprintf (filename, "%s/%s", dir->nn->filename,name);
+ else
+ sprintf (filename, "%s/%s", credentials.share, name);
+
+ mutex_lock (&smb_mutex);
+ err = smbc_mkdir (filename, mode);
+ mutex_unlock (&smb_mutex);
+
+ free(filename);
+ return err?errno:0;
+}
+
+error_t
+netfs_attempt_rmdir (struct iouser * user, struct node * dir, char *name)
+{
+ char *filename;
+
+ if (dir->nn->filename)
+ filename = malloc (strlen (dir->nn->filename) +strlen (name) + 2);
+ else
+ filename = malloc (strlen (credentials.share) + strlen (name) + 1);
+ if (!filename)
+ return ENOMEM;
+
+ if (dir->nn->filename)
+ sprintf (filename, "%s/%s", dir->nn->filename, name);
+ else
+ sprintf (filename, "%s/%s", credentials.share, name);
+
+ mutex_lock (&smb_mutex);
+ error_t err = smbc_rmdir (filename);
+ mutex_unlock (&smb_mutex);
+
+ free(filename);
+ return err?errno:0;
+}
+
+error_t
+netfs_attempt_link (struct iouser * user, struct node * dir,
+ struct node * file, char *name, int excl)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_mkfile (struct iouser * user, struct node * dir, mode_t mode,
+ struct node ** np)
+{
+ mutex_unlock (&dir->lock);
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_attempt_create_file (struct iouser * user, struct node * dir,
+ char *name, mode_t mode, struct node ** np)
+{
+ *np = 0;
+ error_t err=0;
+ char *filename;
+ if (dir->nn->filename)
+ filename = malloc ( strlen (dir->nn->filename) +strlen (name) + 2);
+ else
+ filename = malloc (strlen (credentials.share) + strlen (name) + 1);
+ if (!filename)
+ return ENOMEM;
+
+ if (dir->nn->filename)
+ sprintf (filename, "%s/%s", dir->nn->filename,name);
+ else
+ sprintf (filename, "%s/%s", credentials.share, name);
+
+ mutex_lock (&smb_mutex);
+ int fd = smbc_open (filename,O_WRONLY | O_CREAT , O_RDWR);
+ if (fd < 0)
+ {
+ mutex_unlock (&smb_mutex);
+ mutex_unlock (&dir->lock);
+ return errno;
+ }
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+
+ struct netnode *nn;
+ err=add_node (name, dir,&nn);
+ if(err)
+ {
+ mutex_unlock (&dir->lock);
+ return err;
+ }
+ *np = nn->node;
+
+ mutex_unlock (&dir->lock);
+ return 0;
+}
+
+error_t
+netfs_attempt_readlink (struct iouser * user, struct node * np, char *buf)
+{
+ return EOPNOTSUPP;
+}
+
+error_t
+netfs_check_open_permissions (struct iouser * user, struct node * np,
+ int flags, int newnode)
+{
+ error_t err;
+ io_statbuf_t nn_stat;
+
+ mutex_lock (&smb_mutex);
+ err = smbc_stat (np->nn->filename, &nn_stat);
+ mutex_unlock (&smb_mutex);
+
+ if (err)
+ {
+ return errno;
+ }
+
+ if (flags & O_READ)
+ err = !(S_IREAD & nn_stat.st_mode);
+ if (flags & O_WRITE)
+ err |= !(S_IWRITE & nn_stat.st_mode);
+ if (flags & O_EXEC)
+ err |= !(S_IEXEC & nn_stat.st_mode);
+
+ return err?EPERM:0;
+}
+
+error_t
+netfs_attempt_read (struct iouser * cred, struct node * np, loff_t offset,
+ size_t * len, void *data)
+{
+ mutex_lock (&smb_mutex);
+ int fd = smbc_open (np->nn->filename, O_RDONLY, O_RDWR);
+ mutex_unlock (&smb_mutex);
+
+ int ret = 0;
+
+ if (fd < 0)
+ {
+ *len = 0;
+ return errno;
+ }
+ mutex_lock (&smb_mutex);
+ ret = smbc_lseek (fd, offset, SEEK_SET);
+ mutex_unlock (&smb_mutex);
+
+ if ((ret < 0) || (ret != offset))
+ {
+ *len = 0;
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+ mutex_lock (&smb_mutex);
+ ret = smbc_read (fd, data, *len);
+ mutex_unlock (&smb_mutex);
+ if (ret < 0)
+ {
+ *len = 0;
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+ *len=ret;
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return 0;
+}
+
+error_t
+netfs_attempt_write (struct iouser * cred, struct node * np, loff_t offset,
+ size_t * len, void *data)
+{
+ mutex_lock (&smb_mutex);
+ int fd = smbc_open (np->nn->filename, O_WRONLY, O_RDWR);
+ mutex_unlock (&smb_mutex);
+ int ret=0;
+ if (fd < 0)
+ {
+ *len = 0;
+ return errno;
+ }
+ mutex_lock (&smb_mutex);
+ ret = smbc_lseek (fd, offset, SEEK_SET) < 0;
+ mutex_unlock (&smb_mutex);
+ if ((ret < 0) || (ret != offset))
+ {
+ *len = 0;
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+ mutex_lock (&smb_mutex);
+ ret = smbc_write (fd, data, *len);
+ mutex_unlock (&smb_mutex);
+ if (ret < 0)
+ {
+ *len = 0;
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+ *len=ret;
+ mutex_lock (&smb_mutex);
+ smbc_close (fd);
+ mutex_unlock (&smb_mutex);
+
+ return 0;
+}
+
+error_t
+netfs_report_access (struct iouser * cred, struct node * np, int *types)
+{
+ *types = 0;
+ if(fshelp_access(&np->nn_stat, S_IREAD, cred) == 0)
+ *types |= O_READ;
+ if(fshelp_access(&np->nn_stat, S_IWRITE, cred) == 0)
+ *types |= O_WRITE;
+ if(fshelp_access(&np->nn_stat, S_IEXEC, cred) == 0)
+ *types |= O_EXEC;
+ return 0;
+}
+
+struct iouser *
+netfs_make_user (uid_t * uids, int nuids, uid_t * gids, int ngids)
+{
+ return 0;
+}
+
+void
+netfs_node_norefs (struct node *np)
+{
+ remove_node (np);
+}
+
+error_t
+netfs_get_dirents (struct iouser *cred, struct node *dir, int entry,
+ int nentries, char **data,
+ mach_msg_type_number_t * datacnt, vm_size_t bufsize,
+ int *amt)
+{
+ if (!dir)
+ return ENOTDIR;
+ io_statbuf_t st;
+ struct smbc_dirent * dirent;
+ int size = 0, dd;
+ int nreturningentries=0;
+ int err=0;
+ int add_dir_entry_size=0;
+ char *p = 0;
+
+ mutex_lock (&smb_mutex);
+ dd = smbc_opendir (dir->nn->filename);
+ mutex_unlock (&smb_mutex);
+
+ if (dd<0)
+ return ENOTDIR;
+
+ mutex_lock (&smb_mutex);
+ err=smbc_lseekdir(dd, entry);
+ mutex_unlock (&smb_mutex);
+
+ if(err)
+ {
+ if(errno == EINVAL)
+ {
+ *datacnt=0;
+ *amt=0;
+ mutex_lock (&smb_mutex);
+ smbc_closedir(dd);
+ mutex_unlock (&smb_mutex);
+ return 0;
+ }
+ return errno;
+ }
+
+ int addSize (char *filename)
+ {
+ if(nentries == -1 || nreturningentries < nentries)
+ {
+ size_t new_size = size + DIRENT_LEN (strlen (filename));
+ if (bufsize > 0 && new_size > bufsize)
+ return 1;
+ size = new_size;
+ nreturningentries++;
+ return 0;
+ }
+ else
+ return 1;
+ }
+ for(;;)
+ {
+ mutex_lock (&smb_mutex);
+ dirent = smbc_readdir(dd);
+ mutex_unlock (&smb_mutex);
+ if(!dirent)
+ break;
+ if( (dirent->smbc_type == SMBC_DIR) || (dirent->smbc_type == SMBC_FILE) )/* Add only files and directories. */
+ if(addSize(dirent->name))/* bufsize or nentries reached. */
+ break;
+
+ }
+ if(size > *datacnt) /* if the supplied buffer isn't large enough. */
+ {
+ *data = mmap (0, size, PROT_READ|PROT_WRITE, MAP_ANONYMOUS, 0, 0);
+ }
+ if (!(*data) || (*data == (void *) -1))
+ {
+ mutex_lock (&smb_mutex);
+ smbc_closedir(dd);
+ mutex_unlock (&smb_mutex);
+ return ENOMEM;
+ }
+ mutex_lock (&smb_mutex);
+ err=smbc_lseekdir(dd, entry);
+ mutex_unlock (&smb_mutex);
+ if(err)
+ {
+ if(errno == EINVAL)
+ {
+ *datacnt=0;
+ *amt=0;
+ mutex_lock (&smb_mutex);
+ smbc_closedir(dd);
+ mutex_unlock (&smb_mutex);
+ return 0;
+ }
+ return errno;
+ }
+
+ add_dir_entry_size=size;
+ p = *data;
+ int count=0;
+ int add_dir_entry (const char *name, ino_t fileno, int type)
+ {
+ if(count < nreturningentries)
+ {
+ struct dirent hdr;
+ size_t name_len = strlen (name);
+ size_t sz = DIRENT_LEN (name_len);
+
+ if (sz > add_dir_entry_size)
+ return 1;
+
+ add_dir_entry_size -= sz;
+
+ hdr.d_fileno = fileno;
+ hdr.d_reclen = sz;
+ hdr.d_type = type;
+ hdr.d_namlen = name_len;
+
+ memcpy (p, &hdr, DIRENT_NAME_OFFS);
+ strcpy (p + DIRENT_NAME_OFFS, name);
+ p += sz;
+ ++count;
+ return 0;
+ }
+ else
+ return 1;
+ }
+
+ for(;;)
+ {
+ mutex_lock (&smb_mutex);
+ dirent = smbc_readdir(dd);
+ mutex_unlock(&smb_mutex);
+ if(!dirent)
+ break;
+ int type = 0;
+ if (dirent->smbc_type == SMBC_DIR)
+ type = DT_DIR;
+ else if (dirent->smbc_type == SMBC_FILE)
+ type = DT_REG;
+ else
+ continue;
+ char *stat_file_name;
+ stat_file_name=malloc(strlen(dir->nn->filename)+strlen(dirent->name)+2);
+ if(!stat_file_name)
+ {
+ mutex_lock (&smb_mutex);
+ smbc_closedir(dd);
+ mutex_unlock (&smb_mutex);
+ return ENOMEM;
+ }
+ if(!strcmp(dirent->name,"."))
+ {
+ sprintf(stat_file_name,"%s",dir->nn->filename);
+ mutex_lock (&smb_mutex);
+ err=smbc_stat(stat_file_name, &st);
+ mutex_unlock (&smb_mutex);
+ }
+ else if(!strcmp(dirent->name,".."))
+ {
+ if(dir->nn->parent)
+ sprintf(stat_file_name,"%s/%s",dir->nn->filename,dirent->name);
+ else
+ st.st_ino=0;
+ }
+ else
+ {
+ sprintf(stat_file_name,"%s/%s",dir->nn->filename,dirent->name);
+ mutex_lock (&smb_mutex);
+ err=smbc_stat(stat_file_name, &st);
+ mutex_unlock(&smb_mutex);
+ }
+
+ free(stat_file_name);
+ if(err)
+ {
+ mutex_lock (&smb_mutex);
+ smbc_closedir(dd);
+ mutex_unlock (&smb_mutex);
+ return errno;
+ }
+
+ err=add_dir_entry (dirent->name, st.st_ino, type);
+ if (err)
+ break;
+ }
+
+ *datacnt=size;
+ *amt=nreturningentries;
+ mutex_lock (&smb_mutex);
+ smbc_closedir(dd);
+ mutex_unlock (&smb_mutex);
+ return 0;
+}
+
+void
+smbfs_init ()
+{
+ int err;
+ nodes = 0;
+ err = maptime_map(0,0, &maptime);
+ if(err)
+ return;
+
+ create_root_node ();
+}
+
+void
+smbfs_terminate ()
+{
+ mutex_init (&smb_mutex);
+ clear_nodes ();
+}