summary refs log tree commit diff
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2005-11-18 20:25:31 -0800
committerSteve French <sfrench@us.ibm.com>2005-11-18 20:25:31 -0800
commit86c96b4bb70dac67d6815e09a0949427d439b280 (patch)
treef36ac16583ea9f935fcbed006a8edd99cf83852f /fs/cifs
parentc119b87d596cdd99ac20095ae2ae90b525418605 (diff)
downloadlinux-86c96b4bb70dac67d6815e09a0949427d439b280.tar.gz
[CIFS] Fix mknod of block and chardev over SFU mounts
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifspdu.h10
-rw-r--r--fs/cifs/dir.c32
-rw-r--r--fs/cifs/inode.c33
3 files changed, 62 insertions, 13 deletions
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 48a05b9df7eb..33e1859fd2f6 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -603,7 +603,9 @@ typedef struct smb_com_logoff_andx_rsp {
 	__u16 ByteCount;
 } __attribute__((packed)) LOGOFF_ANDX_RSP;
 
-typedef union smb_com_tree_disconnect {	/* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */
+typedef union smb_com_tree_disconnect {	/* as an altetnative can use flag on 
+					tree_connect PDU to effect disconnect */
+					/* tdis is probably simplest SMB PDU */
 	struct {
 		struct smb_hdr hdr;	/* wct = 0 */
 		__u16 ByteCount;	/* bcc = 0 */
@@ -2025,6 +2027,12 @@ typedef struct {
 } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO;   /* level 0x104 FF response data area */
 
 
+struct win_dev {
+	unsigned char type[8]; /* IntxCHR or IntxBLK */
+	__le64 major;
+	__le64 minor;	
+} __attribute__((packed));
+
 struct gea {
 	unsigned char name_len;
 	char name[1];
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c
index 8dfe717a332a..16b21522e8fe 100644
--- a/fs/cifs/dir.c
+++ b/fs/cifs/dir.c
@@ -292,7 +292,8 @@ cifs_create_out:
 	return rc;
 }
 
-int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) 
+int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, 
+		dev_t device_number) 
 {
 	int rc = -EPERM;
 	int xid;
@@ -368,7 +369,34 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
 
 			if(!rc) {
 				/* BB Do not bother to decode buf since no
-				   local inode yet to put timestamps in */
+				   local inode yet to put timestamps in,
+				   but we can reuse it safely */
+				int bytes_written;
+				struct win_dev *pdev;
+				pdev = (struct win_dev *)buf;
+				if(S_ISCHR(mode)) {
+					memcpy(pdev->type, "IntxCHR", 8);
+					pdev->major =
+					      cpu_to_le64(MAJOR(device_number));
+					pdev->minor = 
+					      cpu_to_le64(MINOR(device_number));
+					rc = CIFSSMBWrite(xid, pTcon,
+						fileHandle,
+						sizeof(struct win_dev),
+						0, &bytes_written, (char *)pdev,
+						NULL, 0);
+				} else if(S_ISBLK(mode)) {
+					memcpy(pdev->type, "IntxBLK", 8);
+					pdev->major =
+					      cpu_to_le64(MAJOR(device_number));
+					pdev->minor =
+					      cpu_to_le64(MINOR(device_number));
+					rc = CIFSSMBWrite(xid, pTcon,
+						fileHandle,
+						sizeof(struct win_dev),
+						0, &bytes_written, (char *)pdev,
+						NULL, 0);
+				} /* else if(S_ISFIFO */
 				CIFSSMBClose(xid, pTcon, fileHandle);
 				d_drop(direntry);
 			}
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f0586c0d7bdb..d7b85dfb0df3 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -210,7 +210,7 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
 	int oplock = FALSE;
 	__u16 netfid;
 	struct cifsTconInfo *pTcon = cifs_sb->tcon;
-	char buf[8];
+	char buf[24];
 	unsigned int bytes_read;
 	char * pbuf;
 
@@ -232,30 +232,43 @@ static int decode_sfu_inode(struct inode * inode, __u64 size,
 			/* Read header */
 		rc = CIFSSMBRead(xid, pTcon,
 			         netfid,
-				 8 /* length */, 0 /* offset */,
+				 24 /* length */, 0 /* offset */,
 				 &bytes_read, &pbuf);
-		if((rc == 0) && (bytes_read == 8)) {
+		if((rc == 0) && (bytes_read >= 8)) {
 			if(memcmp("IntxBLK", pbuf, 8) == 0) {
 				cFYI(1,("Block device"));
 				inode->i_mode |= S_IFBLK;
+				if(bytes_read == 24) {
+					/* we have enough to decode dev num */
+					__u64 mjr; /* major */
+					__u64 mnr; /* minor */
+					mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
+					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
+					inode->i_rdev = MKDEV(mjr, mnr);
+				}
 			} else if(memcmp("IntxCHR", pbuf, 8) == 0) {
 				cFYI(1,("Char device"));
 				inode->i_mode |= S_IFCHR;
+				if(bytes_read == 24) {
+					/* we have enough to decode dev num */
+					__u64 mjr; /* major */
+					__u64 mnr; /* minor */
+					mjr = le64_to_cpu(*(__le64 *)(pbuf+8));
+					mnr = le64_to_cpu(*(__le64 *)(pbuf+16));
+					inode->i_rdev = MKDEV(mjr, mnr);
+                                }
 			} else if(memcmp("IntxLNK", pbuf, 7) == 0) {
 				cFYI(1,("Symlink"));
 				inode->i_mode |= S_IFLNK;
-			} 
+			} else {
+				inode->i_mode |= S_IFREG; /* file? */
+				rc = -EOPNOTSUPP; 
+			}
 		} else {
 			inode->i_mode |= S_IFREG; /* then it is a file */
 			rc = -EOPNOTSUPP; /* or some unknown SFU type */	
 		}
-		
 		CIFSSMBClose(xid, pTcon, netfid);
-	
-
-	/* inode->i_rdev = MKDEV(le64_to_cpu(DevMajor),
-                            le64_to_cpu(DevMinor) & MINORMASK);*/
-/*	inode->i_mode |= S_IFBLK; */
 	}
 	return rc;