From 7f8ed420f80c91176dfd27c8089f22cab5c9ba78 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 28 Sep 2007 22:28:55 +0000 Subject: [PATCH] [CIFS] CIFS support for named pipes (part 1) This allows cifs to mount to ipc shares (IPC$) which will allow user space applications to layer over authenticated cifs connections (useful for Wine and others that would want to put DCE/RPC over CIFS or run CIFS named pipes) Acked-by: Rob Shearman Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 2 ++ fs/cifs/connect.c | 18 ++++++++++++++++-- fs/cifs/dir.c | 2 +- fs/cifs/inode.c | 22 ++++++++++++++++++---- fs/cifs/misc.c | 1 - 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index bb468de4f47..f55be8efa26 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -291,6 +291,7 @@ struct cifsTconInfo { FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; + unsigned ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ unsigned retry:1; unsigned nocase:1; unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol @@ -341,6 +342,7 @@ struct cifsFileInfo { struct list_head llist; /* list of byte range locks we have. */ unsigned closePend:1; /* file is marked to close */ unsigned invalidHandle:1; /* file closed via session abend */ + unsigned messageMode:1 /* for pipes: is message or byte mode */ atomic_t wrtPending; /* handle in use - defer close */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ char *search_resume_name; /* BB removeme BB */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e43cb880f54..21cac15ed9a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2186,8 +2186,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational */ - CIFSSMBQFSDeviceInfo(xid, tcon); - CIFSSMBQFSAttributeInfo(xid, tcon); + if (!tcon->ipc) { + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); + } /* tell server which Unix caps we support */ if (tcon->ses->capabilities & CAP_UNIX) @@ -3385,6 +3387,18 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = pByteArea(smb_buffer_response); length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); /* skip service field (NB: this field is always ASCII) */ + if (length == 3) { + if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && + (bcc_ptr[2] == 'C')) { + cFYI(1, ("IPC connection")); + tcon->ipc = 1; + } + } else if (length == 2) { + if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { + /* the most common case */ + cFYI(1, ("disk share connection")); + } + } bcc_ptr += length + 1; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index db5287abc30..99321ab439d 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -3,7 +3,7 @@ * * vfs operations that deal with dentries * - * Copyright (C) International Business Machines Corp., 2002,2005 + * Copyright (C) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 552d68b9d6f..ece17ca00d0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -115,7 +115,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode = le64_to_cpu(findData.Permissions); /* since we set the inode type below we need to mask off to avoid strange results if bits set above */ - inode->i_mode &= ~S_IFMT; + inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -575,19 +575,33 @@ int cifs_get_inode_info(struct inode **pinode, return rc; } +static const struct inode_operations cifs_ipc_inode_ops = { + .lookup = cifs_lookup, +}; + /* gets root inode */ void cifs_read_inode(struct inode *inode) { - int xid; + int xid, rc; struct cifs_sb_info *cifs_sb; cifs_sb = CIFS_SB(inode->i_sb); xid = GetXid(); if (cifs_sb->tcon->unix_ext) - cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); + rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); else - cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + if (rc && cifs_sb->tcon->ipc) { + cFYI(1, ("ipc connection - fake read inode")); + inode->i_mode |= S_IFDIR; + inode->i_nlink = 2; + inode->i_op = &cifs_ipc_inode_ops; + inode->i_fop = &simple_dir_operations; + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + } + /* can not call macro FreeXid here since in a void func */ _FreeXid(xid); } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0bcec0844be..51ec681fe74 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -169,7 +169,6 @@ cifs_buf_get(void) void cifs_buf_release(void *buf_to_free) { - if (buf_to_free == NULL) { /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/ return;