patch-2.0.37 linux/fs/ncpfs/dir.c

Next file: linux/fs/ncpfs/inode.c
Previous file: linux/fs/ncpfs/Makefile
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.36/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
@@ -5,6 +5,8 @@
  *
  */
 
+#include <linux/config.h>
+
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
@@ -103,7 +105,14 @@
 static inline int
 ncp_preserve_case(struct inode *i)
 {
-	return (ncp_namespace(i) == NW_NS_OS2);
+	return
+#ifdef CONFIG_NCPFS_OS2_NS
+	(ncp_namespace(i) == NW_NS_OS2) || 
+#endif	/* CONFIG_NCPFS_OS2_NS */
+#ifdef CONFIG_NCPFS_NFS_NS
+	(ncp_namespace(i) == NW_NS_NFS) ||
+#endif	/* CONFIG_NCPFS_NFS_NS */
+	0;
 }
 
 static struct file_operations ncp_dir_operations = {
@@ -157,7 +166,7 @@
 ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
 {
 	return ncp_single_volume(server)
-		? info->finfo.i.dirEntNum : (ino_t)info;
+		? (info->finfo.i.dirEntNum == server->root.finfo.i.dirEntNum)?0:info->finfo.i.dirEntNum: (ino_t)info;
 }
 
 static inline int
@@ -937,6 +946,7 @@
 {
 	struct nw_file_info finfo;
 	__u8 _name[len+1];
+	int error;
 
 	*result = NULL;
 
@@ -961,15 +971,18 @@
 	}
 
 	lock_super(dir->i_sb);
-	if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
+	if ((error = ncp_open_create_file_or_subdir(NCP_SERVER(dir),
 					   NCP_ISTRUCT(dir), _name,
 					   OC_MODE_CREATE|OC_MODE_OPEN|
 					   OC_MODE_REPLACE,
 					   0, AR_READ|AR_WRITE,
-					   &finfo) != 0)
+					   &finfo)) != 0)
 	{
 		unlock_super(dir->i_sb);
 		iput(dir);
+		if (error == 0x87) {
+			return -ENAMETOOLONG;
+		} 
 		return -EACCES;
 	}
 
@@ -1095,6 +1108,65 @@
 	return error;
 }
 
+
+#ifdef CONFIG_NCPFS_STRONG
+/* try to delete a readonly file (NW R bit set) */
+
+static int
+ncp_force_unlink(struct inode *dir,char *name,int len)
+{
+        int res=0x9c,res2;
+        struct inode *_inode;
+        struct iattr ia;
+
+        /* remove the Read-Only flag on the NW server */
+
+        dir->i_count++;
+        res2=ncp_lookup(dir,name,len,&_inode);
+        if (res2)
+        {
+                goto leave_me; /* abort operation */
+        }
+        memset(&ia,0,sizeof(struct iattr));
+        ia.ia_mode = _inode->i_mode;
+        ia.ia_mode |= NCP_SERVER(dir)->m.file_mode & 0222;  /* set write bits */
+        ia.ia_valid = ATTR_MODE;
+
+        res2=ncp_notify_change(_inode,&ia);
+        if (res2)
+        {
+                iput(_inode);
+                goto leave_me;
+        }
+
+        /* now try again the delete operation */
+
+        res2 = ncp_del_file_or_subdir(NCP_SERVER(dir),NCP_ISTRUCT(dir),name);
+
+        res=res2; /* save status to use as return value */
+
+        res=res2;
+        if (res2)  /* delete failed, set R bit again */
+        {
+                memset(&ia,0,sizeof(struct iattr));
+                ia.ia_mode = _inode->i_mode;
+                ia.ia_mode &= ~(NCP_SERVER(dir)->m.file_mode & 0222);  /* clear write bits */
+                ia.ia_valid = ATTR_MODE;
+
+                res2=ncp_notify_change(_inode,&ia);
+                if (res2)
+                {
+                        iput(_inode);
+                        goto leave_me;
+                }
+        }
+        iput(_inode);
+
+ leave_me:
+        return(res);
+}
+#endif	/* CONFIG_NCPFS_STRONG */
+
 static int
 ncp_unlink(struct inode *dir, const char *name, int len)
 {
@@ -1126,14 +1198,21 @@
 			str_upper(_name);
 		}
 
-                if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
-						    NCP_ISTRUCT(dir),
-						    _name)) == 0)
-		{
-                        ncp_invalid_dir_cache(dir);
-		}
-		else
-		{
+                error = ncp_del_file_or_subdir(NCP_SERVER(dir),
+                                               NCP_ISTRUCT(dir),
+                                               _name);
+#ifdef CONFIG_NCPFS_STRONG
+		if (error == 0x9c && NCP_SERVER(dir)->m.flags & NCP_MOUNT_STRONG)  /* readonly */
+		{
+			error = ncp_force_unlink(dir,_name,len); /* special treatment */
+		}
+#endif	/* CONFIG_NCPFS_STRONG */
+
+		if (error == 0) {
+			ncp_invalid_dir_cache(dir);
+		} else if (error == 0xFF) {
+			error = -ENOENT;
+		} else {
 			error = -EACCES;
 		}
         }
@@ -1141,6 +1220,83 @@
 	return error;
 }
 
+#ifdef CONFIG_NCPFS_STRONG
+static int
+ncp_force_rename(struct inode *old_dir, const char *old_name, char *_old_name, int old_len,
+                 struct inode *new_dir, const char *new_name, char *_new_name, int new_len)
+{
+        int res=0x90,res2;
+        char _rename_old[old_len+1];
+        char _rename_new[new_len+1];
+        struct inode *_inode,*x_dir;
+        struct iattr ia;
+
+        strncpy(_rename_old,old_name,old_len);
+        _rename_old[old_len] = 0;
+        strncpy(_rename_new,new_name,new_len);
+        _rename_new[new_len] = 0;
+
+        /* remove the Read-Only flag on the NW server */
+
+        old_dir->i_count++;
+        res2=ncp_lookup(old_dir,_rename_old,old_len,&_inode);
+        if (res2)
+        {
+                goto leave_me;
+        }
+        memset(&ia,0,sizeof(struct iattr));
+        ia.ia_mode = _inode->i_mode;
+        ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222;  /* set write bits */
+        ia.ia_valid = ATTR_MODE;
+
+        res2=ncp_notify_change(_inode,&ia);
+        if (res2)
+        {
+                iput(_inode);
+                goto leave_me;
+        }
+
+        /* now try again the rename operation */
+        res2 = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
+                                             NCP_ISTRUCT(old_dir), _old_name,
+                                             NCP_ISTRUCT(new_dir), _new_name);
+
+        res=res2;
+        if (!res2)  /* rename succeeded, get a new inode for the new file */
+        {
+                x_dir=new_dir;
+                new_dir->i_count++;
+                iput(_inode);
+                res2=ncp_lookup(new_dir,_rename_new,new_len,&_inode);
+                if (res2)
+                {
+                        goto leave_me;
+                }
+        }
+        else
+        {
+                x_dir=old_dir;
+        }
+
+        memset(&ia,0,sizeof(struct iattr));
+        ia.ia_mode = _inode->i_mode;
+        ia.ia_mode &= ~(NCP_SERVER(x_dir)->m.file_mode & 0222);  /* clear write bits */
+        ia.ia_valid = ATTR_MODE;
+
+        res2=ncp_notify_change(_inode,&ia);
+        iput(_inode);
+        if (res2)
+        {
+                printk(KERN_INFO "ncpfs: ncp_notify_change (2) failed: %08x\n",res2);
+                goto leave_me;
+        }
+
+ leave_me:
+        return(res);
+}
+#endif	/* CONFIG_NCPFS_STRONG */
+
+
 static int
 ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
            struct inode *new_dir, const char *new_name, int new_len,
@@ -1197,14 +1353,26 @@
 					    NCP_ISTRUCT(old_dir), _old_name,
 					    NCP_ISTRUCT(new_dir), _new_name);
 
-        if (res == 0)
+#ifdef CONFIG_NCPFS_STRONG
+	if (res == 0x90 && NCP_SERVER(old_dir)->m.flags & NCP_MOUNT_STRONG) /* file is readonly */
 	{
-                ncp_invalid_dir_cache(old_dir);
-                ncp_invalid_dir_cache(new_dir);
-        }
+		res=ncp_force_rename(old_dir,old_name,_old_name,old_len,new_dir,new_name,_new_name,new_len);
+	}
+#endif	/* CONFIG_NCPFS_STRONG */
+
+	if (res == 0)
+	{
+		ncp_invalid_dir_cache(old_dir);
+		ncp_invalid_dir_cache(new_dir);
+	}
 	else
 	{
-		res = -EACCES;
+		if (res == 0x9E)
+			res = -ENAMETOOLONG;
+		else if (res == 0xFF)
+			res = -ENOENT;
+		else
+			res = -EACCES;
 	}
 	
  finished:

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov