patch-1.3.7 linux/fs/smbfs/dir.c
Next file: linux/fs/smbfs/file.c
Previous file: linux/fs/smbfs/README
Back to the patch index
Back to the overall index
- Lines: 941
- Date:
Sat Jul 1 19:00:18 1995
- Orig file:
v1.3.6/linux/fs/smbfs/dir.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.6/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
@@ -0,0 +1,940 @@
+/*
+ * dir.c
+ *
+ * Copyright (C) 1995 by Paal-Kr. Engstad and Volker Lendecke
+ *
+ */
+
+#include <linux/config.h>
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/smb_fs.h>
+#include <asm/segment.h>
+#include <linux/errno.h>
+
+#define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
+#define ROUND_UP(x) (((x)+3) & ~3)
+
+static int
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
+
+static int
+smb_readdir(struct inode *inode, struct file *filp,
+ void *dirent, filldir_t filldir);
+
+static int
+get_pname(struct inode *dir, const char *name, int len,
+ char **res_path, int *res_len);
+
+static int
+get_pname_static(struct inode *dir, const char *name, int len,
+ char *path, int *res_len);
+
+static struct inode *
+smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo);
+
+static void
+put_pname(char *path);
+
+static struct smb_inode_info *
+smb_find_inode(struct smb_server *server, const char *path);
+
+static int
+smb_lookup(struct inode *dir, const char *__name,
+ int len, struct inode **result);
+
+static int
+smb_create(struct inode *dir, const char *name, int len, int mode,
+ struct inode **result);
+
+static int
+smb_mkdir(struct inode *dir, const char *name, int len, int mode);
+
+static int
+smb_rmdir(struct inode *dir, const char *name, int len);
+
+static int
+smb_unlink(struct inode *dir, const char *name, int len);
+
+static int
+smb_rename(struct inode *old_dir, const char *old_name, int old_len,
+ struct inode *new_dir, const char *new_name, int new_len);
+
+static inline void str_upper(char *name)
+{
+ while (*name) {
+ if (*name >= 'a' && *name <= 'z')
+ *name -= ('a' - 'A');
+ name++;
+ }
+}
+
+static inline void str_lower(char *name)
+{
+ while (*name) {
+ if (*name >= 'A' && *name <= 'Z')
+ *name += ('a' - 'A');
+ name ++;
+ }
+}
+
+static struct file_operations smb_dir_operations = {
+ NULL, /* lseek - default */
+ smb_dir_read, /* read - bad */
+ NULL, /* write - bad */
+ smb_readdir, /* readdir */
+ NULL, /* select - default */
+ smb_ioctl, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* fsync */
+};
+
+struct inode_operations smb_dir_inode_operations =
+{
+ &smb_dir_operations, /* default directory file ops */
+ smb_create, /* create */
+ smb_lookup, /* lookup */
+ NULL, /* link */
+ smb_unlink, /* unlink */
+ NULL, /* symlink */
+ smb_mkdir, /* mkdir */
+ smb_rmdir, /* rmdir */
+ NULL, /* mknod */
+ smb_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL, /* permission */
+ NULL /* smap */
+};
+
+
+static int
+smb_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
+{
+ return -EISDIR;
+}
+
+/*
+ * Description:
+ * smb_readdir provides a listing in the form of filling the dirent structure.
+ * Note that dirent resides in the user space. This is to support reading of a
+ * directory "stream".
+ * Arguments:
+ * inode --- Pointer to to the directory.
+ * filp --- The directory stream. (filp->f_pos indicates
+ * position in the stream.)
+ * dirent --- Will hold count directory entries. (Is in user space.)
+ * count --- Number of entries to be read. Should indicate the total
+ * buffer space available for filling with dirents.
+ * Return values:
+ * < 0 --- An error occured (linux/errno.h).
+ * = 0 ---
+ * > 0 --- Success, amount of bytes written to dirent.
+ * Notes:
+ * Since we want to reduce directory lookups we revert into a
+ * dircache. It is taken rather directly out of the nfs_readdir.
+ */
+
+/* In smbfs, we have unique inodes across all mounted filesystems, for
+ all inodes that are in memory. That's why it's enough to index the
+ directory cache by the inode number. */
+
+static unsigned long c_ino = 0;
+static int c_size;
+static int c_seen_eof;
+static int c_last_returned_index;
+static struct smb_dirent* c_entry = NULL;
+
+static int
+smb_readdir1(struct inode *inode, const struct file *filp,
+ struct smb_dirent *ret,ino_t *ino)
+{
+ int result, i = 0;
+ struct smb_dirent *entry = NULL;
+ struct smb_server *server = SMB_SERVER(inode);
+
+ DDPRINTK("smb_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
+ DDPRINTK("smb_readdir: inode->i_ino = %ld, c_ino = %ld\n",
+ inode->i_ino, c_ino);
+
+ if (!inode || !S_ISDIR(inode->i_mode)) {
+ printk("smb_readdir: inode is NULL or not a directory\n");
+ return -EBADF;
+ }
+
+ if (c_entry == NULL)
+ {
+ i = sizeof (struct smb_dirent) * SMB_READDIR_CACHE_SIZE;
+ c_entry = (struct smb_dirent *) smb_kmalloc(i, GFP_KERNEL);
+ for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
+ c_entry[i].path =
+ (char *) smb_kmalloc(SMB_MAXNAMELEN + 1,
+ GFP_KERNEL);
+ if (c_entry[i].path == NULL) {
+ DPRINTK("smb_readdir: could not alloc path\n");
+ }
+ }
+ }
+
+ if (filp->f_pos == 0) {
+ smb_invalid_dir_cache(inode->i_ino);
+ }
+
+ if (inode->i_ino == c_ino) {
+ for (i = 0; i < c_size; i++) {
+ if (filp->f_pos == c_entry[i].f_pos) {
+ entry = &c_entry[i];
+ c_last_returned_index = i;
+ break;
+ }
+ }
+ if ((entry == NULL) && c_seen_eof)
+ return 0;
+ }
+
+ if (entry == NULL) {
+ DPRINTK("smb_readdir: Not found in cache.\n");
+ result = smb_proc_readdir(server, inode,
+ filp->f_pos, SMB_READDIR_CACHE_SIZE,
+ c_entry);
+
+ if (result < 0) {
+ c_ino = 0;
+ return result;
+ }
+
+ if (result > 0) {
+ c_seen_eof = (result < SMB_READDIR_CACHE_SIZE);
+ c_ino = inode->i_ino;
+ c_size = result;
+ entry = c_entry;
+ c_last_returned_index = 0;
+ for (i = 0; i < c_size; i++) {
+
+ switch (server->case_handling)
+ {
+ case CASE_UPPER:
+ str_upper(c_entry[i].path); break;
+ case CASE_LOWER:
+ str_lower(c_entry[i].path); break;
+ case CASE_DEFAULT:
+ break;
+ }
+ }
+ }
+ }
+
+ if (entry) {
+
+ /* We found it. For getwd(), we have to return the
+ correct inode in d_ino if the inode is currently in
+ use. Otherwise the inode number does not
+ matter. */
+
+ int path_len;
+ struct smb_inode_info *ino_info;
+ char complete_path[SMB_MAXPATHLEN];
+
+
+
+ i = strlen(entry->path);
+ if ((result = get_pname_static(inode, entry->path, i,
+ complete_path,
+ &path_len)) < 0)
+ return result;
+
+ ino_info = smb_find_inode(server, complete_path);
+
+ /* Some programs seem to be confused about a zero
+ inode number, so we set it to one. Thanks to
+ Gordon Chaffee for this one. */
+ if (ino_info == NULL) {
+ ino_info = (struct smb_inode_info *) 1;
+ }
+
+ DDPRINTK("smb_readdir: entry->path = %s\n", entry->path);
+ DDPRINTK("smb_readdir: entry->f_pos = %ld\n", entry->f_pos);
+
+ *ino = (ino_t)ino_info; /* use the pointer as the
+ inode - dangerous if we have
+ 64 bit pointers! FIXME */
+
+ *ret = *entry;
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+smb_readdir(struct inode *inode, struct file *filp,
+ void *dirent, filldir_t filldir)
+{
+ struct smb_dirent d;
+ ino_t ino;
+
+ while (smb_readdir1(inode,filp,&d,&ino) == 1) {
+ if (filldir(dirent,d.path,strlen(d.path)+1,
+ filp->f_pos,ino) < 0) {
+ return 0;
+ }
+ filp->f_pos++;
+ }
+ return 0;
+}
+
+void
+smb_init_dir_cache(void)
+{
+ c_ino = 0;
+ c_entry = NULL;
+}
+
+void
+smb_invalid_dir_cache(unsigned long ino)
+{
+ if (ino == c_ino) {
+ c_ino = 0;
+ c_seen_eof = 0;
+ }
+}
+
+void
+smb_free_dir_cache(void)
+{
+ int i;
+
+ DPRINTK("smb_free_dir_cache: enter\n");
+
+ if (c_entry == NULL)
+ return;
+
+ for (i = 0; i < SMB_READDIR_CACHE_SIZE; i++) {
+ smb_kfree_s(c_entry[i].path, NAME_MAX + 1);
+ }
+
+ smb_kfree_s(c_entry,
+ sizeof(struct smb_dirent) * SMB_READDIR_CACHE_SIZE);
+ c_entry = NULL;
+
+ DPRINTK("smb_free_dir_cache: exit\n");
+}
+
+
+/* get_pname_static: it expects the res_path to be a preallocated
+ string of len SMB_MAXPATHLEN. */
+
+static int
+get_pname_static(struct inode *dir, const char *name, int len,
+ char *path, int *res_len)
+{
+ char *parentname = SMB_INOP(dir)->finfo.path;
+ int parentlen = SMB_INOP(dir)->finfo.len;
+
+#if 1
+ if (parentlen != strlen(parentname)) {
+ printk("get_pname: parent->finfo.len = %d instead of %d\n",
+ parentlen, strlen(parentname));
+ parentlen = strlen(parentname);
+ }
+
+#endif
+ DDPRINTK("get_pname_static: parentname = %s, len = %d\n",
+ parentname, parentlen);
+
+ if (len > SMB_MAXNAMELEN) {
+ return -ENAMETOOLONG;
+ }
+
+ /* Fast cheat for . */
+ if (len == 0 || (len == 1 && name[0] == '.')) {
+
+ memcpy(path, parentname, parentlen + 1);
+ *res_len = parentlen;
+ return 0;
+ }
+
+ /* Hmm, what about .. ? */
+ if (len == 2 && name[0] == '.' && name[1] == '.') {
+
+ char *pos = strrchr(parentname, '\\');
+
+ if ( (pos == NULL)
+ && (parentlen == 0)) {
+
+ /* We're at the top */
+
+ path[0] = '\\';
+ path[1] = '\0';
+ *res_len = 2;
+ return 0;
+ }
+
+
+ if (pos == NULL) {
+ printk("smb_make_name: Bad parent SMB-name: %s",
+ parentname);
+ return -ENODATA;
+ }
+
+ len = pos - parentname;
+
+ memcpy(path, parentname, len);
+ path[len] = '\0';
+ }
+ else
+ {
+ if (len + parentlen + 2 > SMB_MAXPATHLEN)
+ return -ENAMETOOLONG;
+
+ memcpy(path, parentname, parentlen);
+ path[parentlen] = '\\';
+ memcpy(path + parentlen + 1, name, len);
+ path[parentlen + 1 + len] = '\0';
+ len = parentlen + len + 1;
+ }
+
+ switch (SMB_SERVER(dir)->case_handling)
+ {
+ case CASE_UPPER:
+ str_upper(path);
+ break;
+ case CASE_LOWER:
+ str_lower(path);
+ break;
+ case CASE_DEFAULT:
+ break;
+ }
+
+ *res_len = len;
+
+ DDPRINTK("get_pname: path = %s, *pathlen = %d\n",
+ path, *res_len);
+ return 0;
+}
+
+static int
+get_pname(struct inode *dir, const char *name, int len,
+ char **res_path, int *res_len)
+{
+ char result[SMB_MAXPATHLEN];
+ int result_len;
+ int res;
+
+ if ((res = get_pname_static(dir,name,len,result,&result_len) != 0)) {
+ return res;
+ }
+
+ if ((*res_path = smb_kmalloc(result_len+1, GFP_KERNEL)) == NULL) {
+ printk("get_pname: Out of memory while allocating name.");
+ return -ENOMEM;
+ }
+
+ strcpy(*res_path, result);
+ *res_len = result_len;
+ return 0;
+}
+
+static void
+put_pname(char *path)
+{
+ smb_kfree_s(path, 0);
+}
+
+/* Insert a NEW smb_inode_info into the inode tree of our filesystem,
+ under dir. The caller must assure that it's not already there. We
+ assume that path is allocated for us. */
+
+static struct inode *
+smb_iget(struct inode *dir, char *path, struct smb_dirent *finfo)
+{
+ struct smb_dirent newent = { 0 };
+ struct inode *inode;
+ int error, len;
+ struct smb_inode_info *new_inode_info;
+ struct smb_inode_info *root;
+
+ if (!dir) {
+ printk("smb_iget: dir is NULL\n");
+ return NULL;
+ }
+
+ if (!path) {
+ printk("smb_iget: path is NULL\n");
+ return NULL;
+ }
+
+ len = strlen(path);
+
+ if (!finfo) {
+ error = smb_proc_getattr(&(SMB_SBP(dir->i_sb)->s_server),
+ path, len, &newent);
+ if (error) {
+ printk("smb_iget: getattr error = %d\n", -error);
+ return NULL;
+ }
+ finfo = &newent;
+ DPRINTK("smb_iget: Read finfo:\n");
+ DPRINTK("smb_iget: finfo->attr = 0x%X\n", finfo->attr);
+ }
+
+ new_inode_info = smb_kmalloc(sizeof(struct smb_inode_info),
+ GFP_KERNEL);
+
+ if (new_inode_info == NULL) {
+ printk("smb_iget: could not alloc mem for %s\n", path);
+ return NULL;
+ }
+
+ new_inode_info->state = INODE_LOOKED_UP;
+ new_inode_info->nused = 0;
+ new_inode_info->dir = SMB_INOP(dir);
+
+ new_inode_info->finfo = *finfo;
+ new_inode_info->finfo.opened = 0;
+ new_inode_info->finfo.path = path;
+ new_inode_info->finfo.len = len;
+
+ SMB_INOP(dir)->nused += 1;
+
+ /* We have to link the new inode_info into the doubly linked
+ list of inode_infos to make a complete linear search
+ possible. */
+
+ root = &(SMB_SERVER(dir)->root);
+
+ new_inode_info->prev = root;
+ new_inode_info->next = root->next;
+ root->next->prev = new_inode_info;
+ root->next = new_inode_info;
+
+ if (!(inode = iget(dir->i_sb, (int)new_inode_info))) {
+ printk("smb_iget: iget failed!");
+ return NULL;
+ }
+
+ return inode;
+}
+
+void
+smb_free_inode_info(struct smb_inode_info *i)
+{
+ if (i == NULL) {
+ printk("smb_free_inode: i == NULL\n");
+ return;
+ }
+
+ i->state = INODE_CACHED;
+ while ((i->nused == 0) && (i->state == INODE_CACHED)) {
+ struct smb_inode_info *dir = i->dir;
+
+ i->next->prev = i->prev;
+ i->prev->next = i->next;
+
+ smb_kfree_s(i->finfo.path, i->finfo.len+1);
+ smb_kfree_s(i, sizeof(struct smb_inode_info));
+
+ if (dir == NULL) return;
+
+ (dir->nused)--;
+ i = dir;
+ }
+}
+
+int
+smb_init_root(struct smb_server *server)
+{
+ struct smb_inode_info *root = &(server->root);
+ int result;
+
+ root->finfo.path = server->m.root_path;
+ root->finfo.len = strlen(root->finfo.path);
+ root->finfo.opened = 0;
+
+ root->state = INODE_LOOKED_UP;
+ root->nused = 1;
+ root->dir = NULL;
+ root->next = root->prev = root;
+
+ if (root->finfo.len == 0) {
+ result = smb_proc_getattr(server, "\\", 1, &(root->finfo));
+ }
+ else
+ {
+ result = smb_proc_getattr(server,
+ root->finfo.path, root->finfo.len,
+ &(root->finfo));
+ }
+ return result;
+}
+
+void
+smb_free_all_inodes(struct smb_server *server)
+{
+ /* Here nothing should be to do. I do not know whether it's
+ better to leave some memory allocated or be stuck in an
+ endless loop */
+#if 1
+ struct smb_inode_info *root = &(server->root);
+
+ if (root->next != root) {
+ printk("smb_free_all_inodes: INODES LEFT!!!\n");
+ }
+
+ while (root->next != root) {
+ printk("smb_free_all_inodes: freeing inode\n");
+ smb_free_inode_info(root->next);
+ /* In case we have an endless loop.. */
+ schedule();
+ }
+#endif
+
+ return;
+}
+
+/* This has to be called when a connection has gone down, so that all
+ file-handles we got from the server are invalid */
+
+void
+smb_invalidate_all_inodes(struct smb_server *server)
+{
+ struct smb_inode_info *ino = &(server->root);
+
+ do {
+ ino->finfo.opened = 0;
+ ino = ino->next;
+ } while (ino != &(server->root));
+
+ return;
+}
+
+
+/* We will search the inode that belongs to this name, currently by a
+ complete linear search through the inodes belonging to this
+ filesystem. This has to be fixed. */
+
+static struct smb_inode_info *
+smb_find_inode(struct smb_server *server, const char *path)
+{
+ struct smb_inode_info *result = &(server->root);
+
+ if (path == NULL)
+ return NULL;
+
+ do {
+ if (strcmp(result->finfo.path, path) == 0)
+ return result;
+ result = result->next;
+
+ } while (result != &(server->root));
+
+ return NULL;
+}
+
+
+static int
+smb_lookup(struct inode *dir, const char *__name, int len,
+ struct inode **result)
+{
+ char *name = NULL;
+ struct smb_dirent finfo;
+ struct smb_inode_info *result_info;
+ int error;
+ int found_in_cache;
+
+ *result = NULL;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("smb_lookup: inode is NULL or not a directory.\n");
+ iput(dir);
+ return -ENOENT;
+ }
+
+ DDPRINTK("smb_lookup: %s\n", __name);
+
+ /* Fast cheat for . */
+ if (len == 0 || (len == 1 && __name[0] == '.')) {
+ *result = dir;
+ return 0;
+ }
+
+ /* Now we will have to build up an SMB filename. */
+ if ((error = get_pname(dir, __name, len, &name, &len)) < 0) {
+ iput(dir);
+ return error;
+ }
+
+ result_info = smb_find_inode(SMB_SERVER(dir), name);
+
+ if (result_info != 0) {
+
+ if (result_info->state == INODE_CACHED)
+ result_info->state = INODE_LOOKED_UP;
+
+ put_pname(name);
+
+ /* Here we convert the inode_info address into an
+ inode number */
+
+ *result = iget(dir->i_sb, (int)result_info);
+ iput(dir);
+
+ if (*result == NULL) {
+ return -EACCES;
+ } else {
+ return 0;
+ }
+ }
+
+ /* Ok, now we have made our name. We have to build a new
+ smb_inode_info struct and insert it into the tree, if it is
+ a name that exists on the server */
+
+ /* If the file is in the dir cache, we do not have to ask the
+ server. */
+
+ found_in_cache = 0;
+
+ if (dir->i_ino == c_ino) {
+ int first = c_last_returned_index - 1;
+ int i;
+
+ if (first < 0) {
+ first = c_size - 1;
+ }
+
+ i = first;
+ do {
+ DDPRINTK("smb_lookup: trying index: %d, name: %s\n",
+ i, c_entry[i].path);
+ if (strcmp(c_entry[i].path, __name) == 0) {
+ DPRINTK("smb_lookup: found in cache!\n");
+ finfo = c_entry[i];
+ finfo.path = NULL; /* It's not ours! */
+ found_in_cache = 1;
+ break;
+ }
+ i = (i + 1) % c_size;
+
+ } while (i != first);
+ }
+
+ if (found_in_cache == 0) {
+ error = smb_proc_getattr(SMB_SERVER(dir), name, len, &finfo);
+ if (error < 0) {
+ put_pname(name);
+ iput(dir);
+ return error;
+ }
+ }
+
+ if (!(*result = smb_iget(dir, name, &finfo))) {
+ put_pname(name);
+ iput(dir);
+ return -EACCES;
+ }
+
+ DDPRINTK("smb_lookup: %s => %lu\n", name, (unsigned long)result_info);
+ iput(dir);
+ return 0;
+}
+
+static int
+smb_create(struct inode *dir, const char *name, int len, int mode,
+ struct inode **result)
+{
+ int error;
+ char *path = NULL;
+ struct smb_dirent entry;
+
+ *result = NULL;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("smb_create: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+
+ /* Now we will have to build up an SMB filename. */
+ if ((error = get_pname(dir, name, len, &path, &len)) < 0) {
+ iput(dir);
+ return error;
+ }
+
+ entry.attr = 0;
+ entry.ctime = CURRENT_TIME;
+ entry.size = 0;
+
+ error = smb_proc_create(SMB_SERVER(dir), path, len, &entry);
+ if (error < 0) {
+ put_pname(path);
+ iput(dir);
+ return error;
+ }
+
+ smb_invalid_dir_cache(dir->i_ino);
+
+ if (!(*result = smb_iget(dir, path, &entry)) < 0) {
+ put_pname(path);
+ iput(dir);
+ return error;
+ }
+ iput(dir);
+ return 0;
+}
+
+static int
+smb_mkdir(struct inode *dir, const char *name, int len, int mode)
+{
+ int error;
+ char path[SMB_MAXPATHLEN];
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("smb_mkdir: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+
+ /* Now we will have to build up an SMB filename. */
+ if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
+ iput(dir);
+ return error;
+ }
+
+ if ((error = smb_proc_mkdir(SMB_SERVER(dir), path, len)) == 0) {
+ smb_invalid_dir_cache(dir->i_ino);
+ }
+
+ iput(dir);
+ return error;
+}
+
+static int
+smb_rmdir(struct inode *dir, const char *name, int len)
+{
+ int error;
+ char path[SMB_MAXPATHLEN];
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("smb_rmdir: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
+ iput(dir);
+ return error;
+ }
+ if (smb_find_inode(SMB_SERVER(dir), path) != NULL) {
+ error = -EBUSY;
+ } else {
+ if ((error = smb_proc_rmdir(SMB_SERVER(dir), path, len)) == 0)
+ smb_invalid_dir_cache(dir->i_ino);
+ }
+ iput(dir);
+ return error;
+}
+
+static int
+smb_unlink(struct inode *dir, const char *name, int len)
+{
+ int error;
+ char path[SMB_MAXPATHLEN];
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("smb_unlink: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if ((error = get_pname_static(dir, name, len, path, &len)) < 0) {
+ iput(dir);
+ return error;
+ }
+ if (smb_find_inode(SMB_SERVER(dir), path) != NULL) {
+ error = -EBUSY;
+ } else {
+ if ((error = smb_proc_unlink(SMB_SERVER(dir), path, len)) == 0)
+ smb_invalid_dir_cache(dir->i_ino);
+ }
+
+ iput(dir);
+ return error;
+}
+
+static int
+smb_rename(struct inode *old_dir, const char *old_name, int old_len,
+ struct inode *new_dir, const char *new_name, int new_len)
+{
+ int res;
+ char old_path[SMB_MAXPATHLEN], new_path[SMB_MAXPATHLEN];
+
+ if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
+ printk("smb_rename: old inode is NULL or not a directory\n");
+ res = -ENOENT;
+ goto finished;
+ }
+
+ if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
+ printk("smb_rename: new inode is NULL or not a directory\n");
+ res = -ENOENT;
+ goto finished;
+ }
+
+ res = get_pname_static(old_dir, old_name, old_len, old_path, &old_len);
+ if (res < 0) {
+ goto finished;
+ }
+
+ res = get_pname_static(new_dir, new_name, new_len, new_path, &new_len);
+ if (res < 0) {
+ goto finished;
+ }
+
+ if ( (smb_find_inode(SMB_SERVER(old_dir), old_path) != NULL)
+ || (smb_find_inode(SMB_SERVER(new_dir), new_path) != NULL)) {
+ res = -EBUSY;
+ goto finished;
+ }
+
+ res = smb_proc_mv(SMB_SERVER(old_dir), old_path, old_len,
+ new_path, new_len);
+
+ if (res == 0) {
+ smb_invalid_dir_cache(old_dir->i_ino);
+ smb_invalid_dir_cache(new_dir->i_ino);
+ }
+
+ finished:
+ iput(old_dir);
+ iput(new_dir);
+ return res;
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this