+Version 0.60
+------------
+Fix oops in readpages caused by not setting address space operations in inode in
+rare code path.
+
+Version 0.59
+------------
+Includes support for deleting of open files and renaming over existing files (per POSIX
+requirement). Add readlink support for Windows junction points (directory symlinks).
+
Version 0.58
------------
Changed read and write to go through pagecache. Added additional address space operations.
Build instructions:
==================
-extract the kernel from http://www.cifs.bkbits.net/linux-2.5 or
-http://www.cifs.bkbits.net/linux-2.4
+Get the kernel source e.g. http://linux.bkbits.net/linux-2.5 or http://www.kernel.org
+http://cifs.bkbits.net/linux-2.4
make menuconfig (or make xconfig)
select cifs from within the network filesystem choices
save and exit
from their defaults. For more information on these see the manual pages
("man smb.conf") on the Samba server system. Note that the cifs vfs, unlike the
smbfs vfs, does not read the smb.conf on the client system (the few optional settings
-are passed in on mount via -o parameters instead).
+are passed in on mount via -o parameters instead). Note that Samba 2.2.7 or later
+includes a fix that allows the CIFS VFS to delete open files (required for strict
+POSIX compliance). Windows Servers already supported this feature.
Use instructions:
================
and Windows NT, 2000 and XP and many other SMB/CIFS servers) and servers must support
either "pure-TCP" (port 445 TCP/IP CIFS connections) or RFC 1001/1002 support for
"Netbios-Over-TCP/IP." Neither of these is likely to be a problem as most servers
-support this. IPv6 support is planned for the future.
+support this. IPv6 support is planned for the future.
Misc /proc/fs/cifs Flags and Debug Info
=======================================
ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
length =
sprintf(buf,
- "\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s Capabilities: 0x%x\n",
+ "\n%d) Name: %s Domain: %s HowManyMounts: %d ServerOS: %s ServerNOS: %s\n\tCapabilities: 0x%x",
i, ses->serverName, ses->serverDomain, atomic_read(&ses->inUse),
ses->serverOS, ses->serverNOS, ses->capabilities);
buf += length;
tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
length =
sprintf(buf,
- "\n%d) %s UseCount: %d on FS: %s with characteristics: 0x%x Attributes: 0x%x and PathComponentLengthMax: %d",
+ "\n%d) %s UseCount: %d on FS: %s with characteristics: 0x%x Attributes: 0x%x\n\tPathComponentLengthMax: %d",
i, tcon->treeName,
atomic_read(&tcon->useCount),
tcon->nativeFileSystem,
#define ATTR_NOT_CONTENT_INDEXED 0x2000
#define ATTR_ENCRYPTED 0x4000
#define ATTR_POSIX_SEMANTICS 0x01000000
+#define ATTR_BACKUP_SEMANTICS 0x02000000
+#define ATTR_DELETE_ON_CLOSE 0x04000000
#define ATTR_SEQUENTIAL_SCAN 0x08000000
#define ATTR_RANDOM_ACCESS 0x10000000
#define ATTR_NO_BUFFERING 0x20000000
#define FILE_OVERWRITE_IF 0x00000005
/* CreateOptions */
-#define CREATE_NOT_FILE 0x00000001 /* if set, indicates must not be file */
-#define CREATE_NOT_DIR 0x00000040 /* if set, indicates must not be directory */
+#define CREATE_NOT_FILE 0x00000001 /* if set must not be file */
+#define CREATE_WRITE_THROUGH 0x00000002
+#define CREATE_NOT_DIR 0x00000040 /* if set must not be directory */
+#define CREATE_RANDOM_ACCESS 0x00000800
+#define CREATE_DELETE_ON_CLOSE 0x00001000
+#define OPEN_REPARSE_POINT 0x00200000
/* ImpersonationLevel flags */
#define SECURITY_ANONYMOUS 0
/* followed by NewFileName */
} RENAME_REQ;
-#define CREATE_HARD_LINK 0x103
+#define CREATE_HARD_LINK 0x103
+#define MOVEFILE_COPY_ALLOWED 0x0002
+#define MOVEFILE_REPLACE_EXISTING 0x0001
+
typedef struct smb_com_nt_rename_req { /* A5 - also used for create hardlink */
struct smb_hdr hdr; /* wct = 4 */
__u16 SearchAttributes; /* target file attributes */
__u16 ByteCount; /* bct = 0 */
} CREATE_DIRECTORY_RSP;
-typedef struct smb_com_nt_transaction_ioctl_req {
+typedef struct smb_com_transaction_ioctl_req {
struct smb_hdr hdr; /* wct = 23 */
__u8 MaxSetupCount;
__u16 Reserved;
__u32 ParameterOffset;
__u32 DataCount;
__u32 DataOffset;
- __u8 SetupCount; /* four setup words follow subcommand */
+ __u8 SetupCount; /* four setup words follow subcommand */
/* SNIA spec incorrectly included spurious pad here */
- __u16 SubCommand; /* 2 = IOCTL/FSCTL */
+ __u16 SubCommand;/* 2 = IOCTL/FSCTL */
__u32 FunctionCode;
__u16 Fid;
- __u8 IsFSCTLFlag; /* 1 = File System Control, 0 = device control (IOCTL) */
- __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share) */
+ __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/
+ __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/
__u16 ByteCount;
__u8 Pad[3];
__u8 Data[1];
__u8 Pad[3];
} TRANSACT_IOCTL_RSP;
+struct reparse_data {
+ __u32 ReparseTag;
+ __u16 ReparseDataLength;
+ __u16 Reserved;
+ __u16 AltNameOffset;
+ __u16 AltNameLen;
+ __u16 TargetNameOffset;
+ __u16 TargetNameLen;
+ char LinkNamesBuf[1];
+};
+
typedef union smb_com_transaction2 {
struct {
struct smb_hdr hdr; /* wct = 14+ */
#define SMB_QUERY_FILE_UNIX_BASIC 0x200
#define SMB_QUERY_FILE_UNIX_LINK 0x201
-#define SMB_SET_FILE_BASIC_INFO 0x101
+#define SMB_SET_FILE_BASIC_INFO 0x101
#define SMB_SET_FILE_DISPOSITION_INFO 0x102
#define SMB_SET_FILE_ALLOCATION_INFO 0x103
#define SMB_SET_FILE_END_OF_FILE_INFO 0x104
/* Find File infolevels */
#define SMB_FIND_FILE_DIRECTORY_INFO 0x101
#define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102
-#define SMB_FIND_FILE_NAMES_INFO 0x103
+#define SMB_FIND_FILE_NAMES_INFO 0x103
#define SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x104
#define SMB_FIND_FILE_UNIX 0x202
const unsigned char *searchName,
char *syminfo, const int buflen,
const struct nls_table *nls_codepage);
+extern int CIFSSMBQueryReparseLinkInfo(const int xid,
+ const struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char *symlinkinfo, const int buflen, __u16 fid,
+ const struct nls_table *nls_codepage);
extern int CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
const char *fileName, const int disposition,
int
CIFSSMBOpen(const int xid, const struct cifsTconInfo *tcon,
const char *fileName, const int openDisposition,
- const int access_flags, const int omode, __u16 * netfid,
+ const int access_flags, const int create_options, __u16 * netfid,
int *pOplock, const struct nls_table *nls_codepage)
{
int rc = -EACCES;
pSMB->FileAttributes = cpu_to_le32(pSMB->FileAttributes);
pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
pSMB->CreateDisposition = cpu_to_le32(openDisposition);
- pSMB->CreateOptions = cpu_to_le32(CREATE_NOT_DIR); /* BB what are these? BB */
+ pSMB->CreateOptions = cpu_to_le32(create_options);
pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ?? BB */
pSMB->SecurityFlags =
cpu_to_le32(SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY);
int bytes_returned;
int name_len;
- cFYI(1, ("\nIn QPathSymLinkInfo (Unix) the path %s", searchName));
+ cFYI(1, ("\nIn QPathSymLinkInfo (Unix) for path %s", searchName));
rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
} else { /* decode response */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
- if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
+ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
+ /* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
pSMBr->
DataCount));
}
- symlinkinfo[buflen] = 0; /* just in case so the calling code does not go off the end of the buffer */
+ symlinkinfo[buflen] = 0;
+ /* just in case so calling code does not go off the end of buffer */
+ }
+ }
+ if (pSMB)
+ buf_release(pSMB);
+ return rc;
+}
+
+
+
+int
+CIFSSMBQueryReparseLinkInfo(const int xid, const struct cifsTconInfo *tcon,
+ const unsigned char *searchName,
+ char *symlinkinfo, const int buflen,__u16 fid,
+ const struct nls_table *nls_codepage)
+{
+ int rc = 0;
+ int bytes_returned;
+ int name_len;
+ struct smb_com_transaction_ioctl_req * pSMB;
+ struct smb_com_transaction_ioctl_rsp * pSMBr;
+
+ cFYI(1, ("\nIn Windows reparse style QueryLink info for path %s", searchName));
+ rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
+ (void **) &pSMBr);
+ if (rc)
+ return rc;
+
+ pSMB->TotalParameterCount = 0 ;
+ pSMB->TotalDataCount = 0;
+ pSMB->MaxParameterCount = cpu_to_le16(2);
+ pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
+ pSMB->MaxSetupCount = 4;
+ pSMB->Reserved = 0;
+ pSMB->ParameterOffset = 0;
+ pSMB->DataCount = 0;
+ pSMB->DataOffset = 0;
+ pSMB->SetupCount = 4;
+ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
+ pSMB->ParameterCount = pSMB->TotalParameterCount;
+ pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
+ pSMB->IsFsctl = 1; /* FSCTL */
+ pSMB->IsRootFlag = 0;
+ pSMB->Fid = fid; /* file handle always le */
+ pSMB->ByteCount = 0;
+
+ rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+ (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+ if (rc) {
+ cFYI(1, ("\nSend error in QueryReparseLinkInfo = %d\n", rc));
+ } else { /* decode response */
+ pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+ pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
+ if ((pSMBr->ByteCount < 2) || (pSMBr->DataOffset > 512))
+ /* BB also check enough total bytes returned */
+ rc = -EIO; /* bad smb */
+ else {
+ if(pSMBr->DataCount && (pSMBr->DataCount < 2048)) {
+ /* could also validata reparse tag && better check name length */
+ struct reparse_data * reparse_buf = (struct reparse_data *)
+ ((char *)&pSMBr->hdr.Protocol + pSMBr->DataOffset);
+ if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+ name_len = UniStrnlen((wchar_t *)
+ (reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset),
+ min(buflen/2, reparse_buf->TargetNameLen / 2));
+ cifs_strfromUCS_le(symlinkinfo,
+ (wchar_t *) (reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset),
+ name_len, nls_codepage);
+ } else { /* ASCII names */
+ strncpy(symlinkinfo,reparse_buf->LinkNamesBuf +
+ reparse_buf->TargetNameOffset,
+ min(buflen, (int)reparse_buf->TargetNameLen));
+ }
+ } else {
+ rc = -EIO;
+ cFYI(1,("\nInvalid return data count on get reparse info ioctl"));
+ }
+ symlinkinfo[buflen] = 0; /* just in case so the caller
+ does not go off the end of the buffer */
+ cFYI(1,("\nreadlink result - %s ",symlinkinfo));
}
}
if (pSMB)
if (rc < 0) {
cFYI(1, ("Error connecting to socket. %d\n", rc));
sock_release(*csocket);
+ *csocket = NULL;
return rc;
}
}
("Error connecting to socket (via ipv6). %d\n",
rc));
sock_release(*csocket);
+ *csocket = NULL;
return rc;
}
}
/* BB add processing for setting the equivalent of mode - e.g. via CreateX with ACLs */
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OVERWRITE_IF, GENERIC_ALL
- /* 0x20197 was used previously */ , mode,
+ /* 0x20197 was used previously */ , CREATE_NOT_DIR,
&fileHandle, &oplock, cifs_sb->local_nls);
if (rc) {
cFYI(1, ("\ncifs_create returned 0x%x ", rc));
/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */
if (direntry->d_inode) {
- cFYI(1,
- ("In cifs_d_revalidate, name = %s and inode = 0x%p with count %d with time %ld and dentry 0x%p with time %ld\n",
- direntry->d_name.name, direntry->d_inode,
- direntry->d_inode->i_count.counter,
- direntry->d_inode->i_atime.tv_sec, direntry, direntry->d_time));
if (cifs_revalidate(direntry)) {
/* unlock_kernel(); */
return 0;
#include "cifs_debug.h"
#include "cifs_fs_sb.h"
-
-
int
cifs_open(struct inode *inode, struct file *file)
{
oplock = FALSE;
/* BB pass O_SYNC flag through on file attributes .. BB */
- rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
- -1 /* i.e. dummy value, ignored for time being */,
- &netfid, &oplock, cifs_sb->local_nls);
+ rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,
+ CREATE_NOT_DIR, &netfid, &oplock, cifs_sb->local_nls);
if (rc) {
cFYI(1, ("\ncifs_open returned 0x%x ", rc));
cFYI(1, (" oplock: %d ", oplock));
pCifsFile->pfile = file; /* needed for writepage */
list_add(&pCifsFile->tlist,&pTcon->openFileList);
pCifsInode = CIFS_I(file->f_dentry->d_inode);
- list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+ if(pCifsInode->openFileList.next)
+ list_add(&pCifsFile->flist,&pCifsInode->openFileList);
if(file->f_flags & O_CREAT) {
/* time to set mode which we can not set earlier due
to problems creating new read-only files */
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
if (pSMBFile) {
- list_del(&pSMBFile->flist);
+ if(pSMBFile->flist.next)
+ list_del(&pSMBFile->flist);
list_del(&pSMBFile->tlist);
rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
kfree(file->private_data);
cFYI(1, (" File inode "));
tmp_inode->i_op = &cifs_file_inode_ops;
tmp_inode->i_fop = &cifs_file_ops;
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(tmp_inode->i_mode)) {
cFYI(1, (" Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
cFYI(1, (" File inode "));
tmp_inode->i_op = &cifs_file_inode_ops;
tmp_inode->i_fop = &cifs_file_ops;
+ tmp_inode->i_data.a_ops = &cifs_addr_ops;
} else if (S_ISDIR(tmp_inode->i_mode)) {
cFYI(1, (" Directory inode"));
tmp_inode->i_op = &cifs_dir_inode_ops;
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
- /* BB Should we close the file if it is already open from our client? */
-
full_path = build_path_from_dentry(direntry);
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
if (!rc) {
direntry->d_inode->i_nlink--;
+ } else if (rc == -ETXTBSY) {
+ int oplock = FALSE;
+ __u16 netfid;
+
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, DELETE,
+ CREATE_NOT_DIR | CREATE_DELETE_ON_CLOSE,
+ &netfid, &oplock, cifs_sb->local_nls);
+ if(rc==0) {
+ CIFSSMBClose(xid, pTcon, netfid);
+ /* BB In the future chain close with the NTCreateX to narrow window */
+ direntry->d_inode->i_nlink--;
+ }
}
cifsInode = CIFS_I(direntry->d_inode);
cifsInode->time = 0; /* will force revalidate to get info when needed */
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
+ if(rc == -EEXIST) {
+ cifs_unlink(target_inode, target_direntry);
+ rc = CIFSSMBRename(xid, pTcon, fromName, toName,
+ cifs_sb_source->local_nls);
+ }
if (fromName)
kfree(fromName);
if (toName)
struct inode *inode = direntry->d_inode;
int rc = -EACCES;
int xid;
+ int oplock = FALSE;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
char tmpbuffer[256];
+ __u16 fid;
xid = GetXid();
cifs_sb = CIFS_SB(inode->i_sb);
/* BB add read reparse point symlink code and Unix extensions symlink code here BB */
if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
- tmpbuffer,
- sizeof (tmpbuffer) - 1,
- cifs_sb->local_nls);
+ tmpbuffer,
+ sizeof (tmpbuffer) - 1,
+ cifs_sb->local_nls);
else {
- /* rc = CIFSSMBQueryReparseLinkInfo */
- /* BB Add code to Query ReparsePoint info */
+ rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
+ OPEN_REPARSE_POINT,&fid, &oplock, cifs_sb->local_nls);
+ if(!rc) {
+ rc = CIFSSMBQueryReparseLinkInfo(xid, pTcon, full_path,
+ tmpbuffer,
+ sizeof(tmpbuffer) - 1,
+ fid,
+ cifs_sb->local_nls);
+ if(CIFSSMBClose(xid, pTcon, fid)) {
+ cFYI(1,("Error closing junction point (open for ioctl)"));
+ }
+ }
+
}
/* BB Anything else to do to handle recursive links? */
/* BB Should we be using page ops here? */
ERRHRD, ERRgeneral, NT_STATUS_DISK_CORRUPT_ERROR}, {
ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_INVALID}, { /* mapping changed since shell does lookup on * and expects file not found */
ERRDOS, ERRbadfile, NT_STATUS_OBJECT_NAME_NOT_FOUND}, {
- ERRDOS, 183, NT_STATUS_OBJECT_NAME_COLLISION}, {
+ ERRDOS, ERRalreadyexists, NT_STATUS_OBJECT_NAME_COLLISION}, {
ERRHRD, ERRgeneral, NT_STATUS_HANDLE_NOT_WAITABLE}, {
ERRDOS, ERRbadfid, NT_STATUS_PORT_DISCONNECTED}, {
ERRHRD, ERRgeneral, NT_STATUS_DEVICE_ALREADY_ATTACHED}, {
ERRHRD, ERRgeneral, NT_STATUS_EA_CORRUPT_ERROR}, {
ERRDOS, ERRlock, NT_STATUS_FILE_LOCK_CONFLICT}, {
ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED}, {
- ERRDOS, ERRnoaccess, NT_STATUS_DELETE_PENDING}, {
+ ERRDOS, ERRbadfile, NT_STATUS_DELETE_PENDING}, {
ERRDOS, ERRunsup, NT_STATUS_CTL_FILE_NOT_SUPPORTED}, {
ERRHRD, ERRgeneral, NT_STATUS_UNKNOWN_REVISION}, {
ERRHRD, ERRgeneral, NT_STATUS_REVISION_MISMATCH}, {
{
int idx = 0;
- printk("\nStatus code returned: 0x%08x", status_code);
+ printk("\nStatus code returned: 0x%08x ", status_code);
while (nt_errs[idx].nt_errstr != NULL) {
if (((nt_errs[idx].nt_errcode) & 0xFFFFFF) ==