Commit cd2bcc4c authored by Steve French's avatar Steve French

Merge http://cifs.bkbits.net/linux-2.5cifs

into steveft21.ltcsamba:/usr/src/bk/linux-2.5cifs
parents 0f089059 3ae3d4d5
......@@ -1263,6 +1263,7 @@ typedef struct dfs_referral_level_3 {
__u16 ServerType; /* 0x0001 = CIFS server */
__u16 ReferralFlags; /* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
__u16 TimeToLive;
__u16 Proximity;
__u16 DfsPathOffset;
__u16 DfsAlternatePathOffset;
__u16 NetworkAddressOffset;
......
......@@ -127,13 +127,15 @@ extern int CIFSSMBUnixQPathInfo(const int xid,
extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
unsigned char **targetUNCs,
int *number_of_UNC_in_array,
unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage);
extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path,
const struct nls_table *nls_codepage);
extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
unsigned int *pnum_referrals, unsigned char ** preferrals);
extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
struct statfs *FSData,
const struct nls_table *nls_codepage);
......
......@@ -1625,15 +1625,18 @@ int
CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
const unsigned char *searchName,
unsigned char **targetUNCs,
int *number_of_UNC_in_array,
unsigned int *number_of_UNC_in_array,
const struct nls_table *nls_codepage)
{
/* TRANS2_GET_DFS_REFERRAL */
TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
struct dfs_referral_level_3 * referrals = NULL;
int rc = 0;
int bytes_returned;
int name_len;
unsigned int i;
char * temp;
*number_of_UNC_in_array = 0;
*targetUNCs = NULL;
......@@ -1701,6 +1704,76 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
cFYI(1, ("Send error in GetDFSRefer = %d", rc));
} else { /* decode response */
/* BB Add logic to parse referrals here */
pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
cFYI(1,
("Decoding GetDFSRefer response. BCC: %d Offset %d",
pSMBr->ByteCount, pSMBr->DataOffset));
if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512)) /* BB also check enough total bytes returned */
rc = -EIO; /* bad smb */
else {
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof start of data block */ +
pSMBr->DataOffset +
(char *) &pSMBr->hdr.Protocol);
cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
/* BB This field is actually two bytes in from start of
data block so we could do safety check that DataBlock
begins at address of pSMBr->NumberOfReferrals */
*number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
/* BB Fix below so can return more than one referral */
if(*number_of_UNC_in_array > 1)
*number_of_UNC_in_array = 1;
/* get the length of the strings describing refs */
name_len = 0;
for(i=0;i<*number_of_UNC_in_array;i++) {
/* make sure that DfsPathOffset not past end */
referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
if(referrals->DfsPathOffset > pSMBr->DataCount) {
/* if invalid referral, stop here and do
not try to copy any more */
*number_of_UNC_in_array = i;
break;
}
temp = ((char *)referrals) + referrals->DfsPathOffset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
} else {
name_len += strnlen(temp,pSMBr->DataCount);
}
referrals++;
/* BB add check that referral pointer does not fall off end PDU */
}
/* BB add check for name_len bigger than bcc */
*targetUNCs =
kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
/* copy the ref strings */
referrals =
(struct dfs_referral_level_3 *)
(8 /* sizeof data hdr */ +
pSMBr->DataOffset +
(char *) &pSMBr->hdr.Protocol);
for(i=0;i<*number_of_UNC_in_array;i++) {
temp = ((char *)referrals) + referrals->DfsPathOffset;
if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
cifs_strfromUCS_le(*targetUNCs,
(wchar_t *) temp, name_len, nls_codepage);
} else {
strncpy(*targetUNCs,temp,name_len);
}
/* BB update target_uncs pointers */
referrals++;
}
temp = *targetUNCs;
temp[name_len] = 0;
}
}
if (pSMB)
buf_release(pSMB);
......
......@@ -571,11 +571,32 @@ find_unc(__u32 new_target_ip_addr, char *uncName, char *userName)
int
connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage)
{
unsigned char *referrals = NULL;
unsigned int num_referrals;
int rc = 0;
rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage,
&num_referrals, &referrals);
/* BB Add in code to: if valid refrl, if not ip address contact
the helper that resolves tcp names, mount to it, try to
tcon to it unmount it if fail */
/* BB free memory for referrals string BB */
return rc;
}
int
get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
const char *old_path, const struct nls_table *nls_codepage,
unsigned int *pnum_referrals, unsigned char ** preferrals)
{
char *temp_unc;
int rc = 0;
int num_referrals = 0;
unsigned char *referrals = NULL;
*pnum_referrals = 0;
if (pSesInfo->ipc_tid == 0) {
temp_unc = kmalloc(2 /* for slashes */ +
......@@ -594,11 +615,10 @@ connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
kfree(temp_unc);
}
if (rc == 0)
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &referrals,
&num_referrals, nls_codepage);
return -ENODEV; /* BB remove and add return code processing */
rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
pnum_referrals, nls_codepage);
return rc;
}
int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info)
......
......@@ -53,10 +53,6 @@ cifs_get_inode_info_unix(struct inode **pinode,
/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
if (rc) {
if (rc == -EREMOTE) {
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path =
kmalloc(strnlen
(pTcon->treeName,
......@@ -180,11 +176,6 @@ cifs_get_inode_info(struct inode **pinode,
/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
if (rc) {
if (rc == -EREMOTE) {
/* BB add call to new func rc = GetDFSReferral(); */
/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
&referrals,
&num_referrals,
cifs_sb->local_nls); */
tmp_path =
kmalloc(strnlen
(pTcon->treeName,
......
......@@ -113,6 +113,9 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
/* BB Should we be using page symlink ops here? */
if (rc == 0) {
/* BB Add special case check for Samba DFS symlinks */
target_path[PATH_MAX-1] = 0;
rc = vfs_follow_link(nd, target_path);
}
......@@ -186,7 +189,10 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
struct cifs_sb_info *cifs_sb;
struct cifsTconInfo *pTcon;
char *full_path = NULL;
char *tmp_path = NULL;
char * tmpbuffer;
unsigned char * referrals = NULL;
int num_referrals = 0;
int len;
__u16 fid;
......@@ -206,6 +212,7 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
FreeXid(xid);
return -ENOMEM;
}
/* 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,
......@@ -224,8 +231,36 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
if(CIFSSMBClose(xid, pTcon, fid)) {
cFYI(1,("Error closing junction point (open for ioctl)"));
}
if(rc == -EIO) {
/* Query if DFS Junction */
tmp_path =
kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
GFP_KERNEL);
if (tmp_path) {
strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
strncat(tmp_path, full_path, MAX_PATHCONF);
rc = get_dfs_path(xid, pTcon->ses, tmp_path,
cifs_sb->local_nls, &num_referrals, &referrals);
cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
if((num_referrals == 0) && (rc == 0))
rc = -EACCES;
else {
cFYI(1,("num referral: %d",num_referrals));
if(referrals) {
cFYI(1,("referral string: %s ",referrals));
strncpy(tmpbuffer, referrals, len-1);
}
}
kfree(tmp_path);
if(referrals) {
kfree(referrals);
}
}
/* BB add code like else decode referrals then memcpy to
tmpbuffer and free referrals string array BB */
}
}
}
/* BB Anything else to do to handle recursive links? */
/* BB Should we be using page ops here? */
......@@ -238,10 +273,12 @@ cifs_readlink(struct dentry *direntry, char *pBuffer, int buflen)
rc));
}
if (tmpbuffer)
if (tmpbuffer) {
kfree(tmpbuffer);
if (full_path)
}
if (full_path) {
kfree(full_path);
}
FreeXid(xid);
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