VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / cifs / cifssmb.c
index b4da800..dc9e0fd 100644 (file)
 #include "cifs_unicode.h"
 #include "cifs_debug.h"
 
+#ifdef CONFIG_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
@@ -143,7 +154,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
                return rc;
 
        *request_buf = cifs_buf_get();
-       if (request_buf == 0) {
+       if (*request_buf == 0) {
+               /* BB should we add a retry in here if not a writepage? */
                return -ENOMEM;
        }
     /* Although the original thought was we needed the response buf for  */
@@ -154,6 +166,12 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 
        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
                        wct /*wct */ );
+
+#ifdef CONFIG_CIFS_STATS
+        if(tcon != NULL) {
+                atomic_inc(&tcon->num_smbs_sent);
+        }
+#endif
        return rc;
 }
 
@@ -172,7 +190,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                rc = -EIO;
                return rc;
        }
-       rc = smb_init(SMB_COM_NEGOTIATE, 0, 0 /* no tcon yet */ ,
+       rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
                      (void **) &pSMB, (void **) &pSMBr);
        if (rc)
                return rc;
@@ -297,8 +315,6 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
                return 0;  
        }
 
-/* BB remove (from server) list of shares - but with smp safety  BB */
-/* BB is ses active - do we need to check here - but how? BB */
        if((tcon->ses == 0) || (tcon->ses->server == 0)) {    
                up(&tcon->tconSem);
                return -EIO;
@@ -347,7 +363,7 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
                return -EBUSY;
        }
 
-       rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, 0 /* no tcon anymore */,
+       rc = smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL /* no tcon anymore */,
                 (void **) &pSMB, (void **) &smb_buffer_response);
 
        if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
@@ -365,8 +381,12 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
                         smb_buffer_response, &length, 0);
        if (ses->server) {
                atomic_dec(&ses->server->socketUseCount);
-               if (atomic_read(&ses->server->socketUseCount) == 0)
+               if (atomic_read(&ses->server->socketUseCount) == 0) {
+                       spin_lock(&GlobalMid_Lock);
                        ses->server->tcpStatus = CifsExiting;
+                       spin_unlock(&GlobalMid_Lock);
+                       rc = -ESHUTDOWN;
+               }
        }
        if (pSMB)
                cifs_buf_release(pSMB);
@@ -418,7 +438,13 @@ DelFileRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Error in RMFile = %d", rc));
-       }
+       } 
+#ifdef CONFIG_CIFS_STATS
+        else {
+               atomic_inc(&tcon->num_deletes);
+        }
+#endif
+
        if (pSMB)
                cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -465,6 +491,12 @@ RmDirRetry:
        if (rc) {
                cFYI(1, ("Error in RMDir = %d", rc));
        }
+#ifdef CONFIG_CIFS_STATS
+        else {
+               atomic_inc(&tcon->num_rmdirs);
+        }
+#endif
+
        if (pSMB)
                cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -510,6 +542,11 @@ MkDirRetry:
        if (rc) {
                cFYI(1, ("Error in Mkdir = %d", rc));
        }
+#ifdef CONFIG_CIFS_STATS
+        else {
+               atomic_inc(&tcon->num_mkdirs);
+        }
+#endif
        if (pSMB)
                cifs_buf_release(pSMB);
        if (rc == -EAGAIN)
@@ -606,6 +643,10 @@ openRetry:
                    pfile_info->EndOfFile = pSMBr->EndOfFile;
                    pfile_info->NumberOfLinks = cpu_to_le32(1);
                }
+
+#ifdef CONFIG_CIFS_STATS
+               atomic_inc(&tcon->num_opens);
+#endif
        }
        if (pSMB)
                cifs_buf_release(pSMB);
@@ -728,7 +769,7 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
        if (rc) {
-               cERROR(1, ("Send error in write = %d", rc));
+               cFYI(1, ("Send error in write = %d", rc));
                *nbytes = 0;
        } else
                *nbytes = le16_to_cpu(pSMBr->Count);
@@ -777,14 +818,20 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
        pSMB->AndXCommand = 0xFF;       /* none */
        pSMB->Fid = smb_file_id; /* netfid stays le */
 
-       pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
-       temp = cpu_to_le64(len);
-       pSMB->Locks[0].LengthLow = (__u32)(len & 0xFFFFFFFF);
-       pSMB->Locks[0].LengthHigh =  (__u32)(len>>32);
-       temp = cpu_to_le64(offset);
-       pSMB->Locks[0].OffsetLow = (__u32)(offset & 0xFFFFFFFF);
-       pSMB->Locks[0].OffsetHigh = (__u32)(offset>>32);
-       pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
+       if(numLock != 0) {
+               pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
+               /* BB where to store pid high? */
+               temp = cpu_to_le64(len);
+               pSMB->Locks[0].LengthLow = (__u32)(temp & 0xFFFFFFFF);
+               pSMB->Locks[0].LengthHigh =  (__u32)(temp>>32);
+               temp = cpu_to_le64(offset);
+               pSMB->Locks[0].OffsetLow = (__u32)(temp & 0xFFFFFFFF);
+               pSMB->Locks[0].OffsetHigh = (__u32)(temp>>32);
+               pSMB->ByteCount = sizeof (LOCKING_ANDX_RANGE);
+       } else {
+               /* oplock break */
+               pSMB->ByteCount = 0;
+       }
        pSMB->hdr.smb_buf_length += pSMB->ByteCount;
        pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
 
@@ -792,7 +839,7 @@ CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
                         (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
 
        if (rc) {
-               cERROR(1, ("Send error in Lock = %d", rc));
+               cFYI(1, ("Send error in Lock = %d", rc));
        }
        if (pSMB)
                cifs_buf_release(pSMB);
@@ -892,7 +939,6 @@ renameRetry:
        }
 
        pSMB->ByteCount = 1 /* 1st signature byte */  + name_len + name_len2;
-    /* we could also set search attributes but not needed */
        pSMB->hdr.smb_buf_length += pSMB->ByteCount;
        pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
 
@@ -900,7 +946,14 @@ renameRetry:
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
        if (rc) {
                cFYI(1, ("Send error in rename = %d", rc));
+       } 
+
+#ifdef CONFIG_CIFS_STATS
+         else {
+               atomic_inc(&tcon->num_renames);
        }
+#endif
+
        if (pSMB)
                cifs_buf_release(pSMB);
 
@@ -976,7 +1029,11 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        if (rc) {
                cFYI(1,("Send error in Rename (by file handle) = %d", rc));
        }
-
+#ifdef CONFIG_CIFS_STATS
+         else {
+               atomic_inc(&pTcon->num_t2renames);
+       }
+#endif
        if (pSMB)
                cifs_buf_release(pSMB);
 
@@ -986,6 +1043,76 @@ int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon,
        return rc;
 }
 
+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)
+{
+       int rc = 0;
+       COPY_REQ *pSMB = NULL;
+       COPY_RSP *pSMBr = NULL;
+       int bytes_returned;
+       int name_len, name_len2;
+
+       cFYI(1, ("In CIFSSMBCopy"));
+copyRetry:
+       rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
+                       (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       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);
+
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+               (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Send error in copy = %d with %d files copied",
+                       rc, pSMBr->CopyCount));
+       }
+       if (pSMB)
+               cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto copyRetry;
+
+       return rc;
+}
 
 int
 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
@@ -1356,9 +1483,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
 
        pSMB->TotalParameterCount = 0 ;
        pSMB->TotalDataCount = 0;
-       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxParameterCount = cpu_to_le32(2);
        /* BB find exact data count max from sess structure BB */
-       pSMB->MaxDataCount = cpu_to_le16(4000);
+       pSMB->MaxDataCount = cpu_to_le32(4000);
        pSMB->MaxSetupCount = 4;
        pSMB->Reserved = 0;
        pSMB->ParameterOffset = 0;
@@ -1485,6 +1612,8 @@ QPathInfoRetry:
        } else {                /* decode response */
                pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
                /* BB also check enough total bytes returned */
+               /* BB we need to improve the validity checking
+               of these trans2 responses */
                if ((pSMBr->ByteCount < 40) || (pSMBr->DataOffset > 512)) 
                        rc = -EIO;      /* bad smb */
                else if (pFindData){
@@ -1938,7 +2067,7 @@ CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
        if (ses == NULL)
                return -ENODEV;
 getDFSRetry:
-       rc = smb_init(SMB_COM_TRANSACTION2, 15, 0, (void **) &pSMB,
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
                      (void **) &pSMBr);
        if (rc)
                return rc;
@@ -2158,7 +2287,7 @@ QFSInfoRetry:
 }
 
 int
-CIFSSMBQFSAttributeInfo(int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
                        const struct nls_table *nls_codepage)
 {
 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
@@ -2211,6 +2340,11 @@ QFSAttributeRetry:
                            (FILE_SYSTEM_ATTRIBUTE_INFO
                             *) (((char *) &pSMBr->hdr.Protocol) +
                                 pSMBr->DataOffset);
+                       response_data->Attributes = le32_to_cpu(response_data->Attributes);
+                       response_data->MaxPathNameComponentLength = 
+                               le32_to_cpu(response_data->MaxPathNameComponentLength);
+                       response_data->FileSystemNameLen = 
+                               le32_to_cpu(response_data->FileSystemNameLen);
                        memcpy(&tcon->fsAttrInfo, response_data,
                               sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
                }
@@ -2225,7 +2359,7 @@ QFSAttributeRetry:
 }
 
 int
-CIFSSMBQFSDeviceInfo(int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
                     const struct nls_table *nls_codepage)
 {
 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
@@ -2280,6 +2414,10 @@ QFSDeviceRetry:
                            (FILE_SYSTEM_DEVICE_INFO
                             *) (((char *) &pSMBr->hdr.Protocol) +
                                 pSMBr->DataOffset);
+                       response_data->DeviceType = 
+                               le32_to_cpu(response_data->DeviceType);
+                       response_data->DeviceCharacteristics = 
+                               le32_to_cpu(response_data->DeviceCharacteristics);
                        memcpy(&tcon->fsDevInfo, response_data,
                               sizeof (FILE_SYSTEM_DEVICE_INFO));
                }
@@ -2290,12 +2428,11 @@ QFSDeviceRetry:
        if (rc == -EAGAIN)
                goto QFSDeviceRetry;
 
-
        return rc;
 }
 
 int
-CIFSSMBQFSUnixInfo(int xid, struct cifsTconInfo *tcon,
+CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
                   const struct nls_table *nls_codepage)
 {
 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
@@ -2348,6 +2485,12 @@ QFSUnixRetry:
                            (FILE_SYSTEM_UNIX_INFO
                             *) (((char *) &pSMBr->hdr.Protocol) +
                                 pSMBr->DataOffset);
+                       response_data->MajorVersionNumber =
+                               le16_to_cpu(response_data->MajorVersionNumber);
+                       response_data->MinorVersionNumber =
+                               le16_to_cpu(response_data->MinorVersionNumber);
+                       response_data->Capability =
+                               le64_to_cpu(response_data->Capability);
                        memcpy(&tcon->fsUnixInfo, response_data,
                               sizeof (FILE_SYSTEM_UNIX_INFO));
                }
@@ -2369,7 +2512,7 @@ QFSUnixRetry:
    in Samba which this routine can run into */
 
 int
-CIFSSMBSetEOF(int xid, struct cifsTconInfo *tcon, char *fileName,
+CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
              __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
 {
        struct smb_com_transaction2_spi_req *pSMB = NULL;
@@ -2511,7 +2654,7 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
                (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
                        pSMB->DataOffset);
        pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset); /* now safe to change to le */
-       parm_data->FileSize = size;
+       parm_data->FileSize = cpu_to_le64(size);
        pSMB->Fid = fid;
        if(SetAllocation) {
                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
@@ -2549,8 +2692,9 @@ CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size,
 }
 
 int
-CIFSSMBSetTimes(int xid, struct cifsTconInfo *tcon, char *fileName,
-               FILE_BASIC_INFO * data, const struct nls_table *nls_codepage)
+CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+               const FILE_BASIC_INFO * data, 
+               const struct nls_table *nls_codepage)
 {
        TRANSACTION2_SPI_REQ *pSMB = NULL;
        TRANSACTION2_SPI_RSP *pSMBr = NULL;
@@ -2627,6 +2771,89 @@ SetTimesRetry:
        return rc;
 }
 
+
+int
+CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
+               FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage)
+{
+       TRANSACTION2_SPI_REQ *pSMB = NULL;
+       TRANSACTION2_SPI_RSP *pSMBr = NULL;
+       int name_len;
+       int rc = 0;
+       int bytes_returned = 0;
+       char *data_offset;
+
+       cFYI(1, ("In SetTimesLegacy"));
+
+SetTimesRetryLegacy:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                   cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+                                 /* find define for this maxpathcomponent */
+                                 , nls_codepage);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {                /* BB improve the check for buffer overruns BB */
+               name_len = strnlen(fileName, 530);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, fileName, name_len);
+       }
+/* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info
+       in parent function, from the better and ususal FILE_BASIC_INFO */
+       pSMB->ParameterCount = 6 + name_len;
+       pSMB->DataCount = sizeof (FILE_INFO_STANDARD);
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+       pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+       data_offset = (char *) (&pSMB->hdr.Protocol) + pSMB->DataOffset;
+       pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+       pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+       pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+
+       pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+       pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       /* I doubt that passthrough levels apply to this old
+       preNT info level */
+/*     if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
+               pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
+       else*/
+               pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
+       pSMB->Reserved4 = 0;
+       pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+       memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD));
+       pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("SetPathInfo (times legacy) returned %d", rc));
+       }
+
+       if (pSMB)
+               cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto SetTimesRetryLegacy;
+
+       return rc;
+}
+
 int
 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
                    char *fileName, __u64 mode, __u64 uid, __u64 gid,
@@ -2693,6 +2920,23 @@ setPermsRetry:
        data_offset->DevMajor = cpu_to_le64(MAJOR(device));
        data_offset->DevMinor = cpu_to_le64(MINOR(device));
        data_offset->Permissions = cpu_to_le64(mode);
+    
+       if(S_ISREG(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FILE);
+       else if(S_ISDIR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_DIR);
+       else if(S_ISLNK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
+       else if(S_ISCHR(mode))
+               data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
+       else if(S_ISBLK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
+       else if(S_ISFIFO(mode))
+               data_offset->Type = cpu_to_le32(UNIX_FIFO);
+       else if(S_ISSOCK(mode))
+               data_offset->Type = cpu_to_le32(UNIX_SOCKET);
+
+
        pSMB->ByteCount = cpu_to_le16(pSMB->ByteCount);
        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -2706,3 +2950,448 @@ setPermsRetry:
                goto setPermsRetry;
        return rc;
 }
+
+int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
+                       const int notify_subdirs, const __u16 netfid,
+                       __u32 filter, const struct nls_table *nls_codepage)
+{
+       int rc = 0;
+       struct smb_com_transaction_change_notify_req * pSMB = NULL;
+       struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
+       int bytes_returned;
+
+       cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
+       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_le32(2);
+       /* BB find exact data count max from sess structure BB */
+       pSMB->MaxDataCount = 0; /* same in little endian or be */
+       pSMB->MaxSetupCount = 4;
+       pSMB->Reserved = 0;
+       pSMB->ParameterOffset = 0;
+       pSMB->DataCount = 0;
+       pSMB->DataOffset = 0;
+       pSMB->SetupCount = 4; /* single byte does not need le conversion */
+       pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       if(notify_subdirs)
+               pSMB->WatchTree = 1; /* one byte - no le conversion needed */
+       pSMB->Reserved2 = 0;
+       pSMB->CompletionFilter = cpu_to_le32(filter);
+       pSMB->Fid = netfid; /* file handle always le */
+       pSMB->ByteCount = 0;
+
+       pSMB->hdr.smb_buf_length += pSMB->ByteCount;
+       rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
+                       (struct smb_hdr *) pSMBr, &bytes_returned, 0);
+       if (rc) {
+               cFYI(1, ("Error in Notify = %d", rc));
+       }
+       if (pSMB)
+               cifs_buf_release(pSMB);
+/*             if (rc == -EAGAIN)
+                       goto NotifyRetry; */
+       return rc;      
+}
+#ifdef CONFIG_CIFS_XATTR
+ssize_t
+CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
+                const unsigned char *searchName,
+                char * EAData, size_t buf_size,
+                const struct nls_table *nls_codepage)
+{
+               /* BB assumes one setup word */
+       TRANSACTION2_QPI_REQ *pSMB = NULL;
+       TRANSACTION2_QPI_RSP *pSMBr = NULL;
+       int rc = 0;
+       int bytes_returned;
+       int name_len;
+       struct fea * temp_fea;
+       char * temp_ptr;
+
+       cFYI(1, ("In Query All EAs path %s", searchName));
+QAllEAsRetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                   cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+                                 /* find define for this maxpathcomponent */
+                                 , nls_codepage);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {        /* BB improve the check for buffer overruns BB */
+               name_len = strnlen(searchName, 530);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, searchName, name_len);
+       }
+
+       pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
+           name_len /* includes null */ ;
+       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 = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       pSMB->DataCount = 0;
+       pSMB->DataOffset = 0;
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+       pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+       pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
+       pSMB->Reserved4 = 0;
+       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);
+       if (rc) {
+               cFYI(1, ("Send error in QueryAllEAs = %d", rc));
+       } else {                /* decode response */
+               pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+               /* BB also check enough total bytes returned */
+               /* BB we need to improve the validity checking
+               of these trans2 responses */
+               if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) 
+                       rc = -EIO;      /* bad smb */
+          /* else if (pFindData){
+                       memcpy((char *) pFindData,
+                              (char *) &pSMBr->hdr.Protocol +
+                              pSMBr->DataOffset, kl);
+               }*/ else {
+                       /* check that length of list is not more than bcc */
+                       /* check that each entry does not go beyond length
+                          of list */
+                       /* check that each element of each entry does not
+                          go beyond end of list */
+                       struct fealist * ea_response_data;
+                       rc = 0;
+                       /* validate_trans2_offsets() */
+                       /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
+                       ea_response_data = (struct fealist *)
+                               (((char *) &pSMBr->hdr.Protocol) +
+                               pSMBr->DataOffset);
+                       ea_response_data->list_len = 
+                               cpu_to_le32(ea_response_data->list_len);
+                       cFYI(1,("ea length %d",ea_response_data->list_len));
+                       name_len = ea_response_data->list_len;
+                       if(name_len <= 8) {
+                       /* returned EA size zeroed at top of function */
+                               cFYI(1,("empty EA list returned from server"));
+                       } else {
+                               /* account for ea list len */
+                               name_len -= 4;
+                               temp_fea = ea_response_data->list;
+                               temp_ptr = (char *)temp_fea;
+                               while(name_len > 0) {
+                                       name_len -= 4;
+                                       temp_ptr += 4;
+                                       rc += temp_fea->name_len;
+                               /* account for prefix user. and trailing null */
+                                       rc = rc + 5 + 1; 
+                                       if(rc<buf_size) {
+                                               memcpy(EAData,"user.",5);
+                                               EAData+=5;
+                                               memcpy(EAData,temp_ptr,temp_fea->name_len);
+                                               EAData+=temp_fea->name_len;
+                                               /* null terminate name */
+                                               *EAData = 0;
+                                               EAData = EAData + 1;
+                                       } else if(buf_size == 0) {
+                                               /* skip copy - calc size only */
+                                       } else {
+                                               /* stop before overrun buffer */
+                                               rc = -ERANGE;
+                                               break;
+                                       }
+                                       name_len -= temp_fea->name_len;
+                                       temp_ptr += temp_fea->name_len;
+                                       /* account for trailing null */
+                                       name_len--;
+                                       temp_ptr++;
+                                       temp_fea->value_len = cpu_to_le16(temp_fea->value_len);
+                                       name_len -= temp_fea->value_len;
+                                       temp_ptr += temp_fea->value_len;
+                                       /* BB check that temp_ptr is still within smb BB*/
+                               /* no trailing null to account for in value len */
+                                       /* go on to next EA */
+                                       temp_fea = (struct fea *)temp_ptr;
+                               }
+                       }
+               }
+       }
+       if (pSMB)
+               cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto QAllEAsRetry;
+
+       return rc;
+}
+
+ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
+               const unsigned char * searchName,const unsigned char * ea_name,
+               unsigned char * ea_value, size_t buf_size, 
+               const struct nls_table *nls_codepage)
+{
+       TRANSACTION2_QPI_REQ *pSMB = NULL;
+       TRANSACTION2_QPI_RSP *pSMBr = NULL;
+       int rc = 0;
+       int bytes_returned;
+       int name_len;
+       struct fea * temp_fea;
+       char * temp_ptr;
+
+       cFYI(1, ("In Query EA path %s", searchName));
+QEARetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                   cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, 530
+                                 /* find define for this maxpathcomponent */
+                                 , nls_codepage);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {        /* BB improve the check for buffer overruns BB */
+               name_len = strnlen(searchName, 530);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, searchName, name_len);
+       }
+
+       pSMB->TotalParameterCount = 2 /* level */  + 4 /* reserved */  +
+           name_len /* includes null */ ;
+       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 = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       pSMB->ParameterOffset = cpu_to_le16(offsetof(
+        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
+       pSMB->DataCount = 0;
+       pSMB->DataOffset = 0;
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
+       pSMB->ByteCount = pSMB->TotalParameterCount + 1 /* pad */ ;
+       pSMB->TotalParameterCount = cpu_to_le16(pSMB->TotalParameterCount);
+       pSMB->ParameterCount = pSMB->TotalParameterCount;
+       pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
+       pSMB->Reserved4 = 0;
+       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);
+       if (rc) {
+               cFYI(1, ("Send error in Query EA = %d", rc));
+       } else {                /* decode response */
+               pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+               /* BB also check enough total bytes returned */
+               /* BB we need to improve the validity checking
+               of these trans2 responses */
+               if ((pSMBr->ByteCount < 4) || (pSMBr->DataOffset > 512)) 
+                       rc = -EIO;      /* bad smb */
+          /* else if (pFindData){
+                       memcpy((char *) pFindData,
+                              (char *) &pSMBr->hdr.Protocol +
+                              pSMBr->DataOffset, kl);
+               }*/ else {
+                       /* check that length of list is not more than bcc */
+                       /* check that each entry does not go beyond length
+                          of list */
+                       /* check that each element of each entry does not
+                          go beyond end of list */
+                       struct fealist * ea_response_data;
+                       rc = -ENOENT;
+                       /* validate_trans2_offsets() */
+                       /* BB to check if(start of smb + pSMBr->DataOffset > &bcc+ bcc)*/
+                       ea_response_data = (struct fealist *)
+                               (((char *) &pSMBr->hdr.Protocol) +
+                               pSMBr->DataOffset);
+                       ea_response_data->list_len = 
+                               cpu_to_le32(ea_response_data->list_len);
+                       cFYI(1,("ea length %d",ea_response_data->list_len));
+                       name_len = ea_response_data->list_len;
+                       if(name_len <= 8) {
+                       /* returned EA size zeroed at top of function */
+                               cFYI(1,("empty EA list returned from server"));
+                       } else {
+                               /* account for ea list len */
+                               name_len -= 4;
+                               temp_fea = ea_response_data->list;
+                               temp_ptr = (char *)temp_fea;
+                               /* loop through checking if we have a matching
+                               name and then return the associated value */
+                               while(name_len > 0) {
+                                       name_len -= 4;
+                                       temp_ptr += 4;
+                                       temp_fea->value_len = cpu_to_le16(temp_fea->value_len);
+                               /* BB validate that value_len falls within SMB, 
+                               even though maximum for name_len is 255 */ 
+                                       if(memcmp(temp_fea->name,ea_name,
+                                                 temp_fea->name_len) == 0) {
+                                               /* found a match */
+                                               rc = temp_fea->value_len;
+                               /* account for prefix user. and trailing null */
+                                               if(rc<=buf_size) {
+                                                       memcpy(ea_value,
+                                                               temp_fea->name+temp_fea->name_len+1,
+                                                               rc);
+                                                       /* ea values, unlike ea names,
+                                                       are not null terminated */
+                                               } else if(buf_size == 0) {
+                                               /* skip copy - calc size only */
+                                               } else {
+                                                       /* stop before overrun buffer */
+                                                       rc = -ERANGE;
+                                               }
+                                               break;
+                                       }
+                                       name_len -= temp_fea->name_len;
+                                       temp_ptr += temp_fea->name_len;
+                                       /* account for trailing null */
+                                       name_len--;
+                                       temp_ptr++;
+                                       name_len -= temp_fea->value_len;
+                                       temp_ptr += temp_fea->value_len;
+                               /* no trailing null to account for in value len */
+                                       /* go on to next EA */
+                                       temp_fea = (struct fea *)temp_ptr;
+                               }
+                       } 
+               }
+       }
+       if (pSMB)
+               cifs_buf_release(pSMB);
+       if (rc == -EAGAIN)
+               goto QEARetry;
+
+       return rc;
+}
+
+int
+CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
+               const char * ea_name, const void * ea_value, 
+               const __u16 ea_value_len, const struct nls_table *nls_codepage)
+{
+       struct smb_com_transaction2_spi_req *pSMB = NULL;
+       struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
+       struct fealist *parm_data;
+       int name_len;
+       int rc = 0;
+       int bytes_returned = 0;
+
+       cFYI(1, ("In SetEA"));
+SetEARetry:
+       rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
+                     (void **) &pSMBr);
+       if (rc)
+               return rc;
+
+       if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
+               name_len =
+                   cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, 530
+                                 /* find define for this maxpathcomponent */
+                                 , nls_codepage);
+               name_len++;     /* trailing null */
+               name_len *= 2;
+       } else {                /* BB improve the check for buffer overruns BB */
+               name_len = strnlen(fileName, 530);
+               name_len++;     /* trailing null */
+               strncpy(pSMB->FileName, fileName, name_len);
+       }
+
+       pSMB->ParameterCount = 6 + name_len;
+
+       /* done calculating parms using name_len of file name,
+       now use name_len to calculate length of ea name
+       we are going to create in the inode xattrs */
+       if(ea_name == NULL)
+               name_len = 0;
+       else
+               name_len = strnlen(ea_name,255);
+
+       pSMB->DataCount = sizeof(*parm_data) + ea_value_len + name_len + 1;
+       pSMB->MaxParameterCount = cpu_to_le16(2);
+       pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
+       pSMB->MaxSetupCount = 0;
+       pSMB->Reserved = 0;
+       pSMB->Flags = 0;
+       pSMB->Timeout = 0;
+       pSMB->Reserved2 = 0;
+       pSMB->ParameterOffset = offsetof(struct smb_com_transaction2_spi_req,
+                                     InformationLevel) - 4;
+       pSMB->DataOffset = pSMB->ParameterOffset + pSMB->ParameterCount;
+       pSMB->InformationLevel =
+               cpu_to_le16(SMB_SET_FILE_EA);
+
+       parm_data =
+               (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
+                                      pSMB->DataOffset);
+       pSMB->ParameterOffset = cpu_to_le16(pSMB->ParameterOffset);
+       pSMB->DataOffset = cpu_to_le16(pSMB->DataOffset);
+       pSMB->SetupCount = 1;
+       pSMB->Reserved3 = 0;
+       pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
+       pSMB->ByteCount = 3 /* pad */  + pSMB->ParameterCount + pSMB->DataCount;
+       pSMB->DataCount = cpu_to_le16(pSMB->DataCount);
+       parm_data->list_len = (__u32)(pSMB->DataCount);
+       parm_data->list[0].EA_flags = 0;
+       /* we checked above that name len is less than 255 */
+       parm_data->list[0].name_len = (__u8)name_len;;
+       /* EA names are always ASCII */
+       strncpy(parm_data->list[0].name,ea_name,name_len);
+       parm_data->list[0].name[name_len] = 0;
+       parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
+       /* caller ensures that ea_value_len is less than 64K but
+       we need to ensure that it fits within the smb */
+
+       /*BB add length check that it would fit in negotiated SMB buffer size BB */
+       /* if(ea_value_len > buffer_size - 512 (enough for header)) */
+       if(ea_value_len)
+               memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
+
+       pSMB->TotalDataCount = pSMB->DataCount;
+       pSMB->ParameterCount = cpu_to_le16(pSMB->ParameterCount);
+       pSMB->TotalParameterCount = pSMB->ParameterCount;
+       pSMB->Reserved4 = 0;
+       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);
+       if (rc) {
+               cFYI(1, ("SetPathInfo (EA) returned %d", rc));
+       }
+
+       if (pSMB)
+               cifs_buf_release(pSMB);
+
+       if (rc == -EAGAIN)
+               goto SetEARetry;
+
+       return rc;
+}
+
+#endif