Commit 2868fd35 authored by Steve French's avatar Steve French

Merge bk://linux.bkbits.net/linux-2.5

into hostme.bitkeeper.com:/repos/c/cifs/linux-2.5cifs
parents ddac3ee3 cf3035f7
......@@ -1687,6 +1687,83 @@ struct data_blob {
void (*free) (struct data_blob * data_blob);
};
#ifdef CIFS_POSIX
/*
For better POSIX semantics from Linux client, (even better
than the existing CIFS Unix Extensions) we need updated PDUs for:
1) PosixCreateX - to set and return the mode, inode#, device info and
perhaps add a CreateDevice - to create Pipes and other special .inodes
Also note POSIX open flags
2) Close - to return the last write time to do cache across close more safely
3) PosixQFSInfo - to return statfs info
4) FindFirst return unique inode number - what about resume key, two forms short (matches readdir) and full (enough info to cache inodes)
5) Mkdir - set mode
And under consideration:
6) FindClose2 (return nanosecond timestamp ??)
7) Use nanosecond timestamps throughout all time fields if
corresponding attribute flag is set
8) sendfile - handle based copy
9) Direct i/o
10) "POSIX ACL" support
11) Misc fcntls?
what about fixing 64 bit alignment
There are also various legacy SMB/CIFS requests used as is
From existing Lanman and NTLM dialects:
--------------------------------------
NEGOTIATE
SESSION_SETUP_ANDX (BB which?)
TREE_CONNECT_ANDX (BB which wct?)
TREE_DISCONNECT (BB add volume timestamp on response)
LOGOFF_ANDX
DELETE (note delete open file behavior)
DELETE_DIRECTORY
READ_AND_X
WRITE_AND_X
LOCKING_AND_X (note posix lock semantics)
RENAME (note rename across dirs and open file rename posix behaviors)
NT_RENAME (for hardlinks) Is this good enough for all features?
FIND_CLOSE2
TRANSACTION2 (18 cases)
SMB_SET_FILE_END_OF_FILE_INFO2 SMB_SET_PATH_END_OF_FILE_INFO2
(BB verify that never need to set allocation size)
SMB_SET_FILE_BASIC_INFO2 (setting times - BB can it be done via Unix ext?)
COPY (note support for copy across directories) - FUTURE, OPTIONAL
setting/getting OS/2 EAs - FUTURE (BB can this handle
setting Linux xattrs perfectly) - OPTIONAL
dnotify - FUTURE, OPTIONAL
quota - FUTURE, OPTIONAL
Note that various requests implemented for NT interop such as
NT_TRANSACT (IOCTL) QueryReparseInfo
are unneeded to servers compliant with the CIFS POSIX extensions
From CIFS Unix Extensions:
-------------------------
T2 SET_PATH_INFO (SMB_SET_FILE_UNIX_LINK) for symlinks
T2 SET_PATH_INFO (SMB_SET_FILE_BASIC_INFO2)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_LINK)
T2 QUERY_PATH_INFO (SMB_QUERY_FILE_UNIX_BASIC) - BB check for missing inode fields
Actually need QUERY_FILE_UNIX_INFO since has inode num
BB what about a) blksize/blkbits/blocks
b) i_version
c) i_rdev
d) notify mask?
e) generation
f) size_seqcount
T2 FIND_FIRST/FIND_NEXT FIND_FILE_UNIX
TRANS2_GET_DFS_REFERRAL - OPTIONAL but recommended
T2_QFS_INFO QueryDevice/AttributeInfo - OPTIONAL
*/
#endif
#pragma pack() /* resume default structure packing */
#endif /* _CIFSPDU_H */
......@@ -37,13 +37,24 @@
#include "cifs_unicode.h"
#include "cifs_debug.h"
#ifdef CIFS_POSIX
static struct {
int index;
char *name;
} protocols[] = {
{CIFS_PROT, "\2NT LM 0.12"},
{CIFS_PROT, "\2POSIX 2"},
{BAD_PROT, "\2"}
};
#else
static struct {
int index;
char *name;
} protocols[] = {
{CIFS_PROT, "\2NT LM 0.12"},
{BAD_PROT, "\2"}
};
#endif
/* Mark as invalid, all open files on tree connections since they
......@@ -987,60 +998,59 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
int
CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName,
const __u16 target_tid, const char *toName, const int flags,
const struct nls_table *nls_codepage)
const __u16 target_tid, const char *toName, const int flags,
const struct nls_table *nls_codepage)
{
int rc = 0;
COPY_REQ *pSMB = NULL;
COPY_RSP *pSMBr = NULL;
int bytes_returned;
int name_len, name_len2;
int rc = 0;
COPY_REQ *pSMB = NULL;
COPY_RSP *pSMBr = NULL;
int bytes_returned;
int name_len, name_len2;
cFYI(1, ("In CIFSSMBCopy"));
cFYI(1, ("In CIFSSMBCopy"));
copyRetry:
rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
(void **) &pSMBr);
if (rc)
return rc;
pSMB->BufferFormat = 0x04;
pSMB->BufferFormat = 0x04;
pSMB->Tid2 = target_tid;
if(flags & COPY_TREE)
pSMB->Flags |= COPY_TREE;
pSMB->Flags = cpu_to_le16(pSMB->Flags);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len =
cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, 530
/* find define for this maxpathcomponent */
, nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 =
cifs_strtoUCS((wchar_t *) & pSMB->
OldFileName[name_len + 2], toName, 530,
nls_codepage);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fromName, 530);
name_len++; /* trailing null */
strncpy(pSMB->OldFileName, fromName, name_len);
name_len2 = strnlen(toName, 530);
name_len2++; /* trailing null */
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
name_len2++; /* trailing null */
name_len2++; /* signature byte */
}
pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName,
fromName,
530 /* find define for this maxpathcomponent */,
nls_codepage);
name_len++; /* trailing null */
name_len *= 2;
pSMB->OldFileName[name_len] = 0x04; /* pad */
/* protocol requires ASCII signature byte on Unicode string */
pSMB->OldFileName[name_len + 1] = 0x00;
name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
OldFileName[name_len + 2], toName, 530,
nls_codepage);
name_len2 += 1 /* trailing null */ + 1 /* Signature word */ ;
name_len2 *= 2; /* convert to bytes */
} else { /* BB improve the check for buffer overruns BB */
name_len = strnlen(fromName, 530);
name_len++; /* trailing null */
strncpy(pSMB->OldFileName, fromName, name_len);
name_len2 = strnlen(toName, 530);
name_len2++; /* trailing null */
pSMB->OldFileName[name_len] = 0x04; /* 2nd buffer format */
strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
name_len2++; /* trailing null */
name_len2++; /* signature byte */
}
pSMB->ByteCount = 1 /* 1st signature byte */ + name_len + name_len2;
pSMB->hdr.smb_buf_length += pSMB->ByteCount;
pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
......
......@@ -53,10 +53,12 @@ build_path_from_dentry(struct dentry *direntry)
namelen += (1 + temp->d_name.len);
temp = temp->d_parent;
}
namelen += 1; /* allow for trailing null */
full_path = kmalloc(namelen, GFP_KERNEL);
namelen--;
full_path = kmalloc(namelen+1, GFP_KERNEL);
if(full_path == NULL)
return full_path;
full_path[namelen] = 0; /* trailing null */
for (temp = direntry; !IS_ROOT(temp);) {
namelen -= 1 + temp->d_name.len;
if (namelen < 0) {
......@@ -142,10 +144,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
if(nd) {
cFYI(1,("In create for inode %p dentry->inode %p nd flags = 0x%x for %s",inode, direntry->d_inode, nd->flags,full_path));
if(nd) {
if ((nd->intent.open.flags & O_ACCMODE) == O_RDONLY)
desiredAccess = GENERIC_READ;
else if ((nd->intent.open.flags & O_ACCMODE) == O_WRONLY)
......@@ -173,6 +177,12 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
oplock = REQ_OPLOCK;
buf = kmalloc(sizeof(FILE_ALL_INFO),GFP_KERNEL);
if(buf == NULL) {
kfree(full_path);
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBOpen(xid, pTcon, full_path, disposition,
desiredAccess, CREATE_NOT_DIR,
&fileHandle, &oplock, buf, cifs_sb->local_nls);
......@@ -273,8 +283,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if (pTcon->ses->capabilities & CAP_UNIX) {
if(full_path == NULL)
rc = -ENOMEM;
if (full_path && (pTcon->ses->capabilities & CAP_UNIX)) {
rc = CIFSSMBUnixSetPerms(xid, pTcon,
full_path, mode, current->euid, current->egid,
device_number, cifs_sb->local_nls);
......@@ -298,7 +310,8 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev
struct dentry *
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct nameidata *nd)
{
int rc, xid;
int xid;
int rc = 0; /* to get around spurious gcc warning, set to zero here */
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct inode *newInode = NULL;
......@@ -321,6 +334,11 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return ERR_PTR(-ENOMEM);
}
if (direntry->d_inode != NULL) {
cFYI(1, (" non-NULL inode in lookup"));
} else {
......@@ -347,10 +365,10 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name
rc = 0;
d_add(direntry, NULL);
} else {
cERROR(1,
("Error 0x%x or (%d decimal) on cifs_get_inode_info in lookup",
rc, rc));
/* BB special case check for Access Denied - watch security exposure of returning dir info implicitly via different rc if file exists or not but no access BB */
cERROR(1,("Error 0x%x or on cifs_get_inode_info in lookup",rc));
/* BB special case check for Access Denied - watch security
exposure of returning dir info implicitly via different rc
if file exists or not but no access BB */
}
if (full_path)
......
......@@ -40,8 +40,13 @@ int cifs_directory_notify(unsigned long arg, struct file * file)
cifs_sb = CIFS_SB(file->f_dentry->d_sb);
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(file->f_dentry);
cFYI(1,("cifs dir notify on file %s",full_path));
/* CIFSSMBNotify */
if(full_path == NULL) {
rc = -ENOMEM;
} else {
cFYI(1,("cifs dir notify on file %s",full_path));
/* CIFSSMBNotify(xid, pTcon, full_path, cifs_sb->local_nls);*/
}
FreeXid(xid);
return rc;
}
......
......@@ -81,6 +81,10 @@ cifs_open(struct inode *inode, struct file *file)
}
full_path = build_path_from_dentry(file->f_dentry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
......@@ -150,8 +154,6 @@ cifs_open(struct inode *inode, struct file *file)
cFYI(1, ("cifs_open returned 0x%x ", rc));
cFYI(1, ("oplock: %d ", oplock));
} else {
if(file->private_data)
kfree(file->private_data);
file->private_data =
kmalloc(sizeof (struct cifsFileInfo), GFP_KERNEL);
if (file->private_data) {
......@@ -286,6 +288,11 @@ static int cifs_reopen_file(struct inode *inode, struct file *file)
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(file->f_dentry);
if(full_path == NULL) {
up(&pCifsFile->fh_sem);
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, (" inode = 0x%p file flags are 0x%x for %s", inode, file->f_flags,full_path));
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
......@@ -634,26 +641,22 @@ cifs_partialpagewrite(struct page *page,unsigned from, unsigned to)
int bytes_written = 0;
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
struct inode *inode = page->mapping->host;
struct inode *inode;
struct cifsInodeInfo *cifsInode;
struct cifsFileInfo *open_file = NULL;
struct list_head *tmp;
struct list_head *tmp1;
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
/* figure out which file struct to use
if (file->private_data == NULL) {
return -EBADF;
}
*/
if (!mapping) {
return -EFAULT;
} else if(!mapping->host) {
return -EFAULT;
}
inode = page->mapping->host;
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
offset += (loff_t)from;
write_data = kmap(page);
write_data += from;
......
......@@ -346,7 +346,10 @@ cifs_unlink(struct inode *inode, struct dentry *direntry)
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBDelFile(xid, pTcon, full_path, cifs_sb->local_nls);
if (!rc) {
......@@ -428,6 +431,10 @@ cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
/* BB add setting the equivalent of mode via CreateX w/ACLs */
rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls);
if (rc) {
......@@ -481,6 +488,10 @@ cifs_rmdir(struct inode *inode, struct dentry *direntry)
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
rc = CIFSSMBRmDir(xid, pTcon, full_path, cifs_sb->local_nls);
......@@ -527,6 +538,10 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
fromName = build_path_from_dentry(source_direntry);
toName = build_path_from_dentry(target_direntry);
if((fromName == NULL) || (toName == NULL)) {
rc = -ENOMEM;
goto cifs_rename_exit;
}
rc = CIFSSMBRename(xid, pTcon, fromName, toName,
cifs_sb_source->local_nls);
......@@ -549,6 +564,8 @@ cifs_rename(struct inode *source_inode, struct dentry *source_direntry,
CIFSSMBClose(xid, pTcon, netfid);
}
}
cifs_rename_exit:
if (fromName)
kfree(fromName);
if (toName)
......@@ -587,6 +604,10 @@ cifs_revalidate(struct dentry *direntry)
cifs_sb = CIFS_SB(direntry->d_sb);
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1,
("Revalidate: %s inode 0x%p count %d dentry: 0x%p d_time %ld jiffies %ld",
full_path, direntry->d_inode,
......@@ -731,6 +752,10 @@ cifs_setattr(struct dentry *direntry, struct iattr *attrs)
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cifsInode = CIFS_I(direntry->d_inode);
/* BB check if we need to refresh inode from server now ? BB */
......
......@@ -48,6 +48,11 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
fromName = build_path_from_dentry(old_file);
toName = build_path_from_dentry(direntry);
if((fromName == NULL) || (toName == NULL)) {
rc = -ENOMEM;
goto cifs_hl_exit;
}
if (cifs_sb_target->tcon->ses->capabilities & CAP_UNIX)
rc = CIFSUnixCreateHardLink(xid, pTcon, fromName, toName,
cifs_sb_target->local_nls);
......@@ -70,6 +75,7 @@ cifs_hardlink(struct dentry *old_file, struct inode *inode,
cifsInode = CIFS_I(old_file->d_inode);
cifsInode->time = 0; /* will force revalidate to go get info when needed */
cifs_hl_exit:
if (fromName)
kfree(fromName);
if (toName)
......@@ -91,6 +97,10 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
xid = GetXid();
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, ("Full path: %s inode = 0x%p", full_path, inode));
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
......@@ -150,6 +160,11 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname)
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1, ("Full path: %s ", full_path));
cFYI(1, ("symname is %s", symname));
......@@ -205,6 +220,11 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
cifs_sb = CIFS_SB(inode->i_sb);
pTcon = cifs_sb->tcon;
full_path = build_path_from_dentry(direntry);
if(full_path == NULL) {
FreeXid(xid);
return -ENOMEM;
}
cFYI(1,
("Full path: %s inode = 0x%p pBuffer = 0x%p buflen = %d",
full_path, inode, pBuffer, buflen));
......
......@@ -187,22 +187,26 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return -EIO;
}
/* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
down(&ses->server->tcpSem);
if (ses->server->tcpStatus == CifsExiting) {
return -ENOENT;
rc = -ENOENT;
goto out_unlock;
} else if (ses->server->tcpStatus == CifsNeedReconnect) {
cFYI(1,("tcp session dead - return to caller to retry"));
return -EAGAIN;
rc = -EAGAIN;
goto out_unlock;
} else if (ses->status != CifsGood) {
/* check if SMB session is bad because we are setting it up */
if((in_buf->Command != SMB_COM_SESSION_SETUP_ANDX) &&
(in_buf->Command != SMB_COM_NEGOTIATE)) {
return -EAGAIN;
rc = -EAGAIN;
goto out_unlock;
} /* else ok - we are setting up session */
}
/* make sure that we sign in the same order that we send on this socket
and avoid races inside tcp sendmsg code that could cause corruption
of smb data */
down(&ses->server->tcpSem);
midQ = AllocMidQEntry(in_buf, ses);
if (midQ == NULL) {
up(&ses->server->tcpSem);
......@@ -288,7 +292,6 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
return rc;
}
if (receive_len > CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE) {
cERROR(1,
("Frame too large received. Length: %d Xid: %d",
......@@ -342,4 +345,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
- BB add background daemon to clean up Mid entries from
killed processes & test killing process with active mid */
return rc;
out_unlock:
up(&ses->server->tcpSem);
return rc;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment