linux-bk/fs/cifs/cifssmb.c
<<
>>
Prefs
   1/*
   2 *   fs/cifs/cifssmb.c
   3 *
   4 *   Copyright (C) International Business Machines  Corp., 2002,2003
   5 *   Author(s): Steve French (sfrench@us.ibm.com)
   6 *
   7 *   Contains the routines for constructing the SMB PDUs themselves
   8 *
   9 *   This library is free software; you can redistribute it and/or modify
  10 *   it under the terms of the GNU Lesser General Public License as published
  11 *   by the Free Software Foundation; either version 2.1 of the License, or
  12 *   (at your option) any later version.
  13 *
  14 *   This library is distributed in the hope that it will be useful,
  15 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
  17 *   the GNU Lesser General Public License for more details.
  18 *
  19 *   You should have received a copy of the GNU Lesser General Public License
  20 *   along with this library; if not, write to the Free Software
  21 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  22 */
  23
  24 /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
  25 /* These are mostly routines that operate on a pathname, or on a tree id     */
  26 /* (mounted volume), but there are eight handle based routines which must be */
  27 /* treated slightly different for reconnection purposes since we never want  */
  28 /* to reuse a stale file handle and the caller knows the file handle */
  29
  30#include <linux/fs.h>
  31#include <linux/kernel.h>
  32#include <linux/vfs.h>
  33#include <linux/posix_acl_xattr.h>
  34#include <asm/uaccess.h>
  35#include "cifspdu.h"
  36#include "cifsglob.h"
  37#include "cifsproto.h"
  38#include "cifs_unicode.h"
  39#include "cifs_debug.h"
  40
  41#ifdef CONFIG_CIFS_POSIX
  42static struct {
  43        int index;
  44        char *name;
  45} protocols[] = {
  46        {CIFS_PROT, "\2NT LM 0.12"}, 
  47        {CIFS_PROT, "\2POSIX 2"},
  48        {BAD_PROT, "\2"}
  49};
  50#else
  51static struct {
  52        int index;
  53        char *name;
  54} protocols[] = {
  55        {CIFS_PROT, "\2NT LM 0.12"}, 
  56        {BAD_PROT, "\2"}
  57};
  58#endif
  59
  60
  61/* Mark as invalid, all open files on tree connections since they
  62   were closed when session to server was lost */
  63static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
  64{
  65        struct cifsFileInfo *open_file = NULL;
  66        struct list_head * tmp;
  67        struct list_head * tmp1;
  68
  69/* list all files open on tree connection and mark them invalid */
  70        write_lock(&GlobalSMBSeslock);
  71        list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
  72                open_file = list_entry(tmp,struct cifsFileInfo, tlist);
  73                if(open_file) {
  74                        open_file->invalidHandle = TRUE;
  75                }
  76        }
  77        write_unlock(&GlobalSMBSeslock);
  78        /* BB Add call to invalidate_inodes(sb) for all superblocks mounted to this tcon */
  79}
  80
  81static int
  82small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
  83         void **request_buf /* returned */)
  84{
  85        int rc = 0;
  86
  87        /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
  88           check for tcp and smb session status done differently
  89           for those three - in the calling routine */
  90        if(tcon) {
  91                if((tcon->ses) && (tcon->ses->server)){
  92                        struct nls_table *nls_codepage;
  93                                /* Give Demultiplex thread up to 10 seconds to 
  94                                        reconnect, should be greater than cifs socket
  95                                        timeout which is 7 seconds */
  96                        while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
  97                                wait_event_interruptible_timeout(tcon->ses->server->response_q,
  98                                        (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
  99                                if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
 100                                        /* on "soft" mounts we wait once */
 101                                        if((tcon->retry == FALSE) || 
 102                                           (tcon->ses->status == CifsExiting)) {
 103                                                cFYI(1,("gave up waiting on reconnect in smb_init"));
 104                                                return -EHOSTDOWN;
 105                                        } /* else "hard" mount - keep retrying until 
 106                                        process is killed or server comes back up */
 107                                } else /* TCP session is reestablished now */
 108                                        break;
 109                                 
 110                        }
 111                        
 112                        nls_codepage = load_nls_default();
 113                /* need to prevent multiple threads trying to
 114                simultaneously reconnect the same SMB session */
 115                        down(&tcon->ses->sesSem);
 116                        if(tcon->ses->status == CifsNeedReconnect)
 117                                rc = cifs_setup_session(0, tcon->ses, nls_codepage);
 118                        if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
 119                                mark_open_files_invalid(tcon);
 120                                rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
 121                                        nls_codepage);
 122                                up(&tcon->ses->sesSem);
 123                                if(rc == 0)
 124                                        atomic_inc(&tconInfoReconnectCount);
 125
 126                                cFYI(1, ("reconnect tcon rc = %d", rc));
 127                                /* Removed call to reopen open files here - 
 128                                        it is safer (and faster) to reopen files
 129                                        one at a time as needed in read and write */
 130
 131                                /* Check if handle based operation so we 
 132                                        know whether we can continue or not without
 133                                        returning to caller to reset file handle */
 134                                switch(smb_command) {
 135                                        case SMB_COM_READ_ANDX:
 136                                        case SMB_COM_WRITE_ANDX:
 137                                        case SMB_COM_CLOSE:
 138                                        case SMB_COM_FIND_CLOSE2:
 139                                        case SMB_COM_LOCKING_ANDX: {
 140                                                unload_nls(nls_codepage);
 141                                                return -EAGAIN;
 142                                        }
 143                                }
 144                        } else {
 145                                up(&tcon->ses->sesSem);
 146                        }
 147                        unload_nls(nls_codepage);
 148
 149                } else {
 150                        return -EIO;
 151                }
 152        }
 153        if(rc)
 154                return rc;
 155
 156        *request_buf = cifs_small_buf_get();
 157        if (*request_buf == 0) {
 158                /* BB should we add a retry in here if not a writepage? */
 159                return -ENOMEM;
 160        }
 161
 162        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,wct);
 163
 164#ifdef CONFIG_CIFS_STATS
 165        if(tcon != NULL) {
 166                atomic_inc(&tcon->num_smbs_sent);
 167        }
 168#endif /* CONFIG_CIFS_STATS */
 169        return rc;
 170}  
 171
 172static int
 173smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
 174         void **request_buf /* returned */ ,
 175         void **response_buf /* returned */ )
 176{
 177        int rc = 0;
 178
 179        /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
 180           check for tcp and smb session status done differently
 181           for those three - in the calling routine */
 182        if(tcon) {
 183                if((tcon->ses) && (tcon->ses->server)){
 184                        struct nls_table *nls_codepage;
 185                                /* Give Demultiplex thread up to 10 seconds to 
 186                                        reconnect, should be greater than cifs socket
 187                                        timeout which is 7 seconds */
 188                        while(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
 189                                wait_event_interruptible_timeout(tcon->ses->server->response_q,
 190                                        (tcon->ses->server->tcpStatus == CifsGood), 10 * HZ);
 191                                if(tcon->ses->server->tcpStatus == CifsNeedReconnect) {
 192                                        /* on "soft" mounts we wait once */
 193                                        if((tcon->retry == FALSE) || 
 194                                           (tcon->ses->status == CifsExiting)) {
 195                                                cFYI(1,("gave up waiting on reconnect in smb_init"));
 196                                                return -EHOSTDOWN;
 197                                        } /* else "hard" mount - keep retrying until 
 198                                        process is killed or server comes back up */
 199                                } else /* TCP session is reestablished now */
 200                                        break;
 201                                 
 202                        }
 203                        
 204                        nls_codepage = load_nls_default();
 205                /* need to prevent multiple threads trying to
 206                simultaneously reconnect the same SMB session */
 207                        down(&tcon->ses->sesSem);
 208                        if(tcon->ses->status == CifsNeedReconnect)
 209                                rc = cifs_setup_session(0, tcon->ses, nls_codepage);
 210                        if(!rc && (tcon->tidStatus == CifsNeedReconnect)) {
 211                                mark_open_files_invalid(tcon);
 212                                rc = CIFSTCon(0, tcon->ses, tcon->treeName, tcon,
 213                                        nls_codepage);
 214                                up(&tcon->ses->sesSem);
 215                                if(rc == 0)
 216                                        atomic_inc(&tconInfoReconnectCount);
 217
 218                                cFYI(1, ("reconnect tcon rc = %d", rc));
 219                                /* Removed call to reopen open files here - 
 220                                        it is safer (and faster) to reopen files
 221                                        one at a time as needed in read and write */
 222
 223                                /* Check if handle based operation so we 
 224                                        know whether we can continue or not without
 225                                        returning to caller to reset file handle */
 226                                switch(smb_command) {
 227                                        case SMB_COM_READ_ANDX:
 228                                        case SMB_COM_WRITE_ANDX:
 229                                        case SMB_COM_CLOSE:
 230                                        case SMB_COM_FIND_CLOSE2:
 231                                        case SMB_COM_LOCKING_ANDX: {
 232                                                unload_nls(nls_codepage);
 233                                                return -EAGAIN;
 234                                        }
 235                                }
 236                        } else {
 237                                up(&tcon->ses->sesSem);
 238                        }
 239                        unload_nls(nls_codepage);
 240
 241                } else {
 242                        return -EIO;
 243                }
 244        }
 245        if(rc)
 246                return rc;
 247
 248        *request_buf = cifs_buf_get();
 249        if (*request_buf == 0) {
 250                /* BB should we add a retry in here if not a writepage? */
 251                return -ENOMEM;
 252        }
 253    /* Although the original thought was we needed the response buf for  */
 254    /* potential retries of smb operations it turns out we can determine */
 255    /* from the mid flags when the request buffer can be resent without  */
 256    /* having to use a second distinct buffer for the response */
 257        *response_buf = *request_buf; 
 258
 259        header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon,
 260                        wct /*wct */ );
 261
 262#ifdef CONFIG_CIFS_STATS
 263        if(tcon != NULL) {
 264                atomic_inc(&tcon->num_smbs_sent);
 265        }
 266#endif /* CONFIG_CIFS_STATS */
 267        return rc;
 268}
 269
 270static int validate_t2(struct smb_t2_rsp * pSMB) 
 271{
 272        int rc = -EINVAL;
 273        int total_size;
 274        char * pBCC;
 275
 276        /* check for plausible wct, bcc and t2 data and parm sizes */
 277        /* check for parm and data offset going beyond end of smb */
 278        if(pSMB->hdr.WordCount >= 10) {
 279                if((le16_to_cpu(pSMB->t2_rsp.ParameterOffset) <= 1024) &&
 280                   (le16_to_cpu(pSMB->t2_rsp.DataOffset) <= 1024)) {
 281                        /* check that bcc is at least as big as parms + data */
 282                        /* check that bcc is less than negotiated smb buffer */
 283                        total_size = le16_to_cpu(pSMB->t2_rsp.ParameterCount);
 284                        if(total_size < 512) {
 285                                total_size+=le16_to_cpu(pSMB->t2_rsp.DataCount);
 286                                /* BCC le converted in SendReceive */
 287                                pBCC = (pSMB->hdr.WordCount * 2) + sizeof(struct smb_hdr) + 
 288                                        (char *)pSMB;
 289                                if((total_size <= (*(u16 *)pBCC)) && 
 290                                   (total_size < 
 291                                        CIFSMaxBufSize+MAX_CIFS_HDR_SIZE)) {
 292                                        return 0;
 293                                }
 294                                
 295                        }
 296                }
 297        }
 298        cifs_dump_mem("Invalid transact2 SMB: ",(char *)pSMB,
 299                sizeof(struct smb_t2_rsp) + 16);
 300        return rc;
 301}
 302int
 303CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
 304{
 305        NEGOTIATE_REQ *pSMB;
 306        NEGOTIATE_RSP *pSMBr;
 307        int rc = 0;
 308        int bytes_returned;
 309        struct TCP_Server_Info * server;
 310        u16 count;
 311
 312        if(ses->server)
 313                server = ses->server;
 314        else {
 315                rc = -EIO;
 316                return rc;
 317        }
 318        rc = smb_init(SMB_COM_NEGOTIATE, 0, NULL /* no tcon yet */ ,
 319                      (void **) &pSMB, (void **) &pSMBr);
 320        if (rc)
 321                return rc;
 322
 323        pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
 324        if (extended_security)
 325                pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;
 326
 327        count = strlen(protocols[0].name) + 1;
 328        strncpy(pSMB->DialectsArray, protocols[0].name, 30);    
 329    /* null guaranteed to be at end of source and target buffers anyway */
 330
 331        pSMB->hdr.smb_buf_length += count;
 332        pSMB->ByteCount = cpu_to_le16(count);
 333
 334        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
 335                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 336        if (rc == 0) {
 337                server->secMode = pSMBr->SecurityMode;  
 338                server->secType = NTLM; /* BB override default for NTLMv2 or krb*/
 339                /* one byte - no need to convert this or EncryptionKeyLen from le,*/
 340                server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount);
 341                /* probably no need to store and check maxvcs */
 342                server->maxBuf =
 343                        min(le32_to_cpu(pSMBr->MaxBufferSize),
 344                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
 345                server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
 346                cFYI(0, ("Max buf = %d ", ses->server->maxBuf));
 347                GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
 348                server->capabilities = le32_to_cpu(pSMBr->Capabilities);
 349                server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);  
 350        /* BB with UTC do we ever need to be using srvr timezone? */
 351                if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
 352                        memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
 353                               CIFS_CRYPTO_KEY_SIZE);
 354                } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC)
 355                           && (pSMBr->EncryptionKeyLength == 0)) {
 356                        /* decode security blob */
 357                } else
 358                        rc = -EIO;
 359
 360                /* BB might be helpful to save off the domain of server here */
 361
 362                if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && 
 363                        (server->capabilities & CAP_EXTENDED_SECURITY)) {
 364                        count = pSMBr->ByteCount;
 365                        if (count < 16)
 366                                rc = -EIO;
 367                        else if (count == 16) {
 368                                server->secType = RawNTLMSSP;
 369                                if (server->socketUseCount.counter > 1) {
 370                                        if (memcmp
 371                                                (server->server_GUID,
 372                                                pSMBr->u.extended_response.
 373                                                GUID, 16) != 0) {
 374                                                cFYI(1,
 375                                                        ("UID of server does not match previous connection to same ip address"));
 376                                                memcpy(server->
 377                                                        server_GUID,
 378                                                        pSMBr->u.
 379                                                        extended_response.
 380                                                        GUID, 16);
 381                                        }
 382                                } else
 383                                        memcpy(server->server_GUID,
 384                                               pSMBr->u.extended_response.
 385                                               GUID, 16);
 386                        } else {
 387                                rc = decode_negTokenInit(pSMBr->u.
 388                                                         extended_response.
 389                                                         SecurityBlob,
 390                                                         count - 16,
 391                                                         &server->secType);
 392                                if(rc == 1) {
 393                                /* BB Need to fill struct for sessetup here */
 394                                        rc = -EOPNOTSUPP;
 395                                } else {
 396                                        rc = -EINVAL;
 397                                }
 398                        }
 399                } else
 400                        server->capabilities &= ~CAP_EXTENDED_SECURITY;
 401                if(sign_CIFS_PDUs == FALSE) {        
 402                        if(server->secMode & SECMODE_SIGN_REQUIRED)
 403                                cERROR(1,
 404                                 ("Server requires /proc/fs/cifs/PacketSigningEnabled"));
 405                        server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
 406                } else if(sign_CIFS_PDUs == 1) {
 407                        if((server->secMode & SECMODE_SIGN_REQUIRED) == 0)
 408                                server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED);
 409                }
 410                                
 411        }
 412        if (pSMB)
 413                cifs_buf_release(pSMB);
 414        return rc;
 415}
 416
 417int
 418CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon)
 419{
 420        struct smb_hdr *smb_buffer;
 421        struct smb_hdr *smb_buffer_response; /* BB removeme BB */
 422        int rc = 0;
 423        int length;
 424
 425        cFYI(1, ("In tree disconnect"));
 426        /*
 427         *  If last user of the connection and
 428         *  connection alive - disconnect it
 429         *  If this is the last connection on the server session disconnect it
 430         *  (and inside session disconnect we should check if tcp socket needs 
 431         *  to be freed and kernel thread woken up).
 432         */
 433        if (tcon)
 434                down(&tcon->tconSem);
 435        else
 436                return -EIO;
 437
 438        atomic_dec(&tcon->useCount);
 439        if (atomic_read(&tcon->useCount) > 0) {
 440                up(&tcon->tconSem);
 441                return -EBUSY;
 442        }
 443
 444        /* No need to return error on this operation if tid invalidated and 
 445        closed on server already e.g. due to tcp session crashing */
 446        if(tcon->tidStatus == CifsNeedReconnect) {
 447                up(&tcon->tconSem);
 448                return 0;  
 449        }
 450
 451        if((tcon->ses == 0) || (tcon->ses->server == 0)) {    
 452                up(&tcon->tconSem);
 453                return -EIO;
 454        }
 455        rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, (void **)&smb_buffer);
 456        if (rc) {
 457                up(&tcon->tconSem);
 458                return rc;
 459        } else {
 460                smb_buffer_response = smb_buffer; /* BB removeme BB */
 461    }
 462        rc = SendReceive(xid, tcon->ses, smb_buffer, smb_buffer_response,
 463                         &length, 0);
 464        if (rc)
 465                cFYI(1, (" Tree disconnect failed %d", rc));
 466
 467        if (smb_buffer)
 468                cifs_small_buf_release(smb_buffer);
 469        up(&tcon->tconSem);
 470
 471        /* No need to return error on this operation if tid invalidated and 
 472        closed on server already e.g. due to tcp session crashing */
 473        if (rc == -EAGAIN)
 474                rc = 0;
 475
 476        return rc;
 477}
 478
 479int
 480CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
 481{
 482        struct smb_hdr *smb_buffer_response;
 483        LOGOFF_ANDX_REQ *pSMB;
 484        int rc = 0;
 485        int length;
 486
 487        cFYI(1, ("In SMBLogoff for session disconnect"));
 488        if (ses)
 489                down(&ses->sesSem);
 490        else
 491                return -EIO;
 492
 493        atomic_dec(&ses->inUse);
 494        if (atomic_read(&ses->inUse) > 0) {
 495                up(&ses->sesSem);
 496                return -EBUSY;
 497        }
 498        rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB);
 499        smb_buffer_response = (struct smb_hdr *)pSMB; /* BB removeme BB */
 500        
 501        if(ses->server) {
 502                if(ses->server->secMode & 
 503                   (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
 504                        pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 505        }
 506
 507        if (rc) {
 508                up(&ses->sesSem);
 509                return rc;
 510        }
 511
 512        pSMB->hdr.Uid = ses->Suid;
 513
 514        pSMB->AndXCommand = 0xFF;
 515        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
 516                         smb_buffer_response, &length, 0);
 517        if (ses->server) {
 518                atomic_dec(&ses->server->socketUseCount);
 519                if (atomic_read(&ses->server->socketUseCount) == 0) {
 520                        spin_lock(&GlobalMid_Lock);
 521                        ses->server->tcpStatus = CifsExiting;
 522                        spin_unlock(&GlobalMid_Lock);
 523                        rc = -ESHUTDOWN;
 524                }
 525        }
 526        if (pSMB)
 527                cifs_small_buf_release(pSMB);
 528        up(&ses->sesSem);
 529
 530        /* if session dead then we do not need to do ulogoff,
 531                since server closed smb session, no sense reporting 
 532                error */
 533        if (rc == -EAGAIN)
 534                rc = 0;
 535        return rc;
 536}
 537
 538int
 539CIFSSMBDelFile(const int xid, struct cifsTconInfo *tcon,
 540               const char *fileName, const struct nls_table *nls_codepage)
 541{
 542        DELETE_FILE_REQ *pSMB = NULL;
 543        DELETE_FILE_RSP *pSMBr = NULL;
 544        int rc = 0;
 545        int bytes_returned;
 546        int name_len;
 547
 548DelFileRetry:
 549        rc = smb_init(SMB_COM_DELETE, 1, tcon, (void **) &pSMB,
 550                      (void **) &pSMBr);
 551        if (rc)
 552                return rc;
 553
 554        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 555                name_len =
 556                    cifs_strtoUCS((wchar_t *) pSMB->fileName, fileName, PATH_MAX
 557                                  /* find define for this maxpathcomponent */
 558                                  , nls_codepage);
 559                name_len++;     /* trailing null */
 560                name_len *= 2;
 561        } else {                /* BB improve the check for buffer overruns BB */
 562                name_len = strnlen(fileName, PATH_MAX);
 563                name_len++;     /* trailing null */
 564                strncpy(pSMB->fileName, fileName, name_len);
 565        }
 566        pSMB->SearchAttributes =
 567            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM);
 568        pSMB->BufferFormat = 0x04;
 569        pSMB->hdr.smb_buf_length += name_len + 1;
 570        pSMB->ByteCount = cpu_to_le16(name_len + 1);
 571        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 572                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 573        if (rc) {
 574                cFYI(1, ("Error in RMFile = %d", rc));
 575        } 
 576#ifdef CONFIG_CIFS_STATS
 577        else {
 578                atomic_inc(&tcon->num_deletes);
 579        }
 580#endif
 581
 582        if (pSMB)
 583                cifs_buf_release(pSMB);
 584        if (rc == -EAGAIN)
 585                goto DelFileRetry;
 586
 587        return rc;
 588}
 589
 590int
 591CIFSSMBRmDir(const int xid, struct cifsTconInfo *tcon,
 592             const char *dirName, const struct nls_table *nls_codepage)
 593{
 594        DELETE_DIRECTORY_REQ *pSMB = NULL;
 595        DELETE_DIRECTORY_RSP *pSMBr = NULL;
 596        int rc = 0;
 597        int bytes_returned;
 598        int name_len;
 599
 600        cFYI(1, ("In CIFSSMBRmDir"));
 601RmDirRetry:
 602        rc = smb_init(SMB_COM_DELETE_DIRECTORY, 0, tcon, (void **) &pSMB,
 603                      (void **) &pSMBr);
 604        if (rc)
 605                return rc;
 606
 607        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 608                name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, dirName, PATH_MAX
 609                                /* find define for this maxpathcomponent */
 610                                , nls_codepage);
 611                name_len++;     /* trailing null */
 612                name_len *= 2;
 613        } else {                /* BB improve the check for buffer overruns BB */
 614                name_len = strnlen(dirName, PATH_MAX);
 615                name_len++;     /* trailing null */
 616                strncpy(pSMB->DirName, dirName, name_len);
 617        }
 618
 619        pSMB->BufferFormat = 0x04;
 620        pSMB->hdr.smb_buf_length += name_len + 1;
 621        pSMB->ByteCount = cpu_to_le16(name_len + 1);
 622        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 623                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 624        if (rc) {
 625                cFYI(1, ("Error in RMDir = %d", rc));
 626        }
 627#ifdef CONFIG_CIFS_STATS
 628        else {
 629                atomic_inc(&tcon->num_rmdirs);
 630        }
 631#endif
 632
 633        if (pSMB)
 634                cifs_buf_release(pSMB);
 635        if (rc == -EAGAIN)
 636                goto RmDirRetry;
 637        return rc;
 638}
 639
 640int
 641CIFSSMBMkDir(const int xid, struct cifsTconInfo *tcon,
 642             const char *name, const struct nls_table *nls_codepage)
 643{
 644        int rc = 0;
 645        CREATE_DIRECTORY_REQ *pSMB = NULL;
 646        CREATE_DIRECTORY_RSP *pSMBr = NULL;
 647        int bytes_returned;
 648        int name_len;
 649
 650        cFYI(1, ("In CIFSSMBMkDir"));
 651MkDirRetry:
 652        rc = smb_init(SMB_COM_CREATE_DIRECTORY, 0, tcon, (void **) &pSMB,
 653                      (void **) &pSMBr);
 654        if (rc)
 655                return rc;
 656
 657        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 658                name_len = cifs_strtoUCS((wchar_t *) pSMB->DirName, name, PATH_MAX
 659                                         /* find define for this maxpathcomponent */
 660                                         , nls_codepage);
 661                name_len++;     /* trailing null */
 662                name_len *= 2;
 663        } else {                /* BB improve the check for buffer overruns BB */
 664                name_len = strnlen(name, PATH_MAX);
 665                name_len++;     /* trailing null */
 666                strncpy(pSMB->DirName, name, name_len);
 667        }
 668
 669        pSMB->BufferFormat = 0x04;
 670        pSMB->hdr.smb_buf_length += name_len + 1;
 671        pSMB->ByteCount = cpu_to_le16(name_len + 1);
 672        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 673                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 674        if (rc) {
 675                cFYI(1, ("Error in Mkdir = %d", rc));
 676        }
 677#ifdef CONFIG_CIFS_STATS
 678        else {
 679                atomic_inc(&tcon->num_mkdirs);
 680        }
 681#endif
 682        if (pSMB)
 683                cifs_buf_release(pSMB);
 684        if (rc == -EAGAIN)
 685                goto MkDirRetry;
 686        return rc;
 687}
 688
 689int
 690CIFSSMBOpen(const int xid, struct cifsTconInfo *tcon,
 691            const char *fileName, const int openDisposition,
 692            const int access_flags, const int create_options, __u16 * netfid,
 693            int *pOplock, FILE_ALL_INFO * pfile_info, 
 694            const struct nls_table *nls_codepage)
 695{
 696        int rc = -EACCES;
 697        OPEN_REQ *pSMB = NULL;
 698        OPEN_RSP *pSMBr = NULL;
 699        int bytes_returned;
 700        int name_len;
 701        __u16 count;
 702
 703openRetry:
 704        rc = smb_init(SMB_COM_NT_CREATE_ANDX, 24, tcon, (void **) &pSMB,
 705                      (void **) &pSMBr);
 706        if (rc)
 707                return rc;
 708
 709        pSMB->AndXCommand = 0xFF;       /* none */
 710
 711        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
 712                count = 1;      /* account for one byte pad to word boundary */
 713                name_len =
 714                    cifs_strtoUCS((wchar_t *) (pSMB->fileName + 1),
 715                                  fileName, PATH_MAX
 716                                  /* find define for this maxpathcomponent */
 717                                  , nls_codepage);
 718                name_len++;     /* trailing null */
 719                name_len *= 2;
 720                pSMB->NameLength = cpu_to_le16(name_len);
 721        } else {                /* BB improve the check for buffer overruns BB */
 722                count = 0;      /* no pad */
 723                name_len = strnlen(fileName, PATH_MAX);
 724                name_len++;     /* trailing null */
 725                pSMB->NameLength = cpu_to_le16(name_len);
 726                strncpy(pSMB->fileName, fileName, name_len);
 727        }
 728        if (*pOplock & REQ_OPLOCK)
 729                pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK);
 730        else if (*pOplock & REQ_BATCHOPLOCK) {
 731                pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK);
 732        }
 733        pSMB->DesiredAccess = cpu_to_le32(access_flags);
 734        pSMB->AllocationSize = 0;
 735        pSMB->FileAttributes = cpu_to_le32(ATTR_NORMAL);
 736        /* XP does not handle ATTR_POSIX_SEMANTICS */
 737        /* but it helps speed up case sensitive checks for other
 738        servers such as Samba */
 739        if (tcon->ses->capabilities & CAP_UNIX)
 740                pSMB->FileAttributes |= cpu_to_le32(ATTR_POSIX_SEMANTICS);
 741
 742        /* if ((omode & S_IWUGO) == 0)
 743                pSMB->FileAttributes |= cpu_to_le32(ATTR_READONLY);*/
 744        /*  Above line causes problems due to vfs splitting create into two
 745                pieces - need to set mode after file created not while it is
 746                being created */
 747        pSMB->ShareAccess = cpu_to_le32(FILE_SHARE_ALL);
 748        pSMB->CreateDisposition = cpu_to_le32(openDisposition);
 749        pSMB->CreateOptions = cpu_to_le32(create_options);
 750        pSMB->ImpersonationLevel = cpu_to_le32(SECURITY_IMPERSONATION); /* BB ??*/
 751        pSMB->SecurityFlags =
 752            SECURITY_CONTEXT_TRACKING | SECURITY_EFFECTIVE_ONLY;
 753
 754        count += name_len;
 755        pSMB->hdr.smb_buf_length += count;
 756
 757        pSMB->ByteCount = cpu_to_le16(count);
 758        /* long_op set to 1 to allow for oplock break timeouts */
 759        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 760                         (struct smb_hdr *) pSMBr, &bytes_returned, 1);
 761        if (rc) {
 762                cFYI(1, ("Error in Open = %d", rc));
 763        } else {
 764                *pOplock = pSMBr->OplockLevel;  /* one byte no need to le_to_cpu */
 765                *netfid = pSMBr->Fid;   /* cifs fid stays in le */
 766                /* Let caller know file was created so we can set the mode. */
 767                /* Do we care about the CreateAction in any other cases? */
 768                if(cpu_to_le32(FILE_CREATE) == pSMBr->CreateAction)
 769                        *pOplock |= CIFS_CREATE_ACTION; 
 770                if(pfile_info) {
 771                    memcpy((char *)pfile_info,(char *)&pSMBr->CreationTime,
 772                        36 /* CreationTime to Attributes */);
 773                    /* the file_info buf is endian converted by caller */
 774                    pfile_info->AllocationSize = pSMBr->AllocationSize;
 775                    pfile_info->EndOfFile = pSMBr->EndOfFile;
 776                    pfile_info->NumberOfLinks = cpu_to_le32(1);
 777                }
 778
 779#ifdef CONFIG_CIFS_STATS
 780                atomic_inc(&tcon->num_opens);
 781#endif
 782        }
 783        if (pSMB)
 784                cifs_buf_release(pSMB);
 785        if (rc == -EAGAIN)
 786                goto openRetry;
 787        return rc;
 788}
 789
 790/* If no buffer passed in, then caller wants to do the copy
 791        as in the case of readpages so the SMB buffer must be
 792        freed by the caller */
 793
 794int
 795CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
 796            const int netfid, const unsigned int count,
 797            const __u64 lseek, unsigned int *nbytes, char **buf)
 798{
 799        int rc = -EACCES;
 800        READ_REQ *pSMB = NULL;
 801        READ_RSP *pSMBr = NULL;
 802        char *pReadData = NULL;
 803        int bytes_returned;
 804
 805        *nbytes = 0;
 806        rc = smb_init(SMB_COM_READ_ANDX, 12, tcon, (void **) &pSMB,
 807                      (void **) &pSMBr);
 808        if (rc)
 809                return rc;
 810
 811        /* tcon and ses pointer are checked in smb_init */
 812        if (tcon->ses->server == NULL)
 813                return -ECONNABORTED;
 814
 815        pSMB->AndXCommand = 0xFF;       /* none */
 816        pSMB->Fid = netfid;
 817        pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
 818        pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
 819        pSMB->Remaining = 0;
 820        pSMB->MaxCount = cpu_to_le16(count);
 821        pSMB->MaxCountHigh = 0;
 822        pSMB->ByteCount = 0;  /* no need to do le conversion since it is 0 */
 823
 824        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 825                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
 826        if (rc) {
 827                cERROR(1, ("Send error in read = %d", rc));
 828        } else {
 829                __u16 data_length = le16_to_cpu(pSMBr->DataLength);
 830                *nbytes = data_length;
 831                /*check that DataLength would not go beyond end of SMB */
 832                if ((data_length > CIFSMaxBufSize) 
 833                                || (data_length > count)) {
 834                        cFYI(1,("bad length %d for count %d",data_length,count));
 835                        rc = -EIO;
 836                        *nbytes = 0;
 837                } else {
 838                        pReadData =
 839                            (char *) (&pSMBr->hdr.Protocol) +
 840                            le16_to_cpu(pSMBr->DataOffset);
 841/*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
 842                                cERROR(1,("Faulting on read rc = %d",rc));
 843                                rc = -EFAULT;
 844                        }*/ /* can not use copy_to_user when using page cache*/
 845                        if(*buf)
 846                            memcpy(*buf,pReadData,data_length);
 847                }
 848        }
 849        if (pSMB) {
 850                if(*buf)
 851                        cifs_buf_release(pSMB);
 852                else
 853                        *buf = (char *)pSMB;
 854        }
 855
 856        /* Note: On -EAGAIN error only caller can retry on handle based calls 
 857                since file handle passed in no longer valid */
 858        return rc;
 859}
 860
 861int
 862CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
 863             const int netfid, const unsigned int count,
 864             const __u64 offset, unsigned int *nbytes, const char *buf,
 865             const char __user * ubuf, const int long_op)
 866{
 867        int rc = -EACCES;
 868        WRITE_REQ *pSMB = NULL;
 869        WRITE_RSP *pSMBr = NULL;
 870        int bytes_returned;
 871        unsigned bytes_sent;
 872        __u16 byte_count;
 873
 874        rc = smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB,
 875                      (void **) &pSMBr);
 876        if (rc)
 877                return rc;
 878        /* tcon and ses pointer are checked in smb_init */
 879        if (tcon->ses->server == NULL)
 880                return -ECONNABORTED;
 881
 882        pSMB->AndXCommand = 0xFF;       /* none */
 883        pSMB->Fid = netfid;
 884        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
 885        pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
 886        pSMB->Reserved = 0xFFFFFFFF;
 887        pSMB->WriteMode = 0;
 888        pSMB->Remaining = 0;
 889        /* BB can relax this if buffer is big enough in some cases - ie we can 
 890        send more  if LARGE_WRITE_X capability returned by the server and if
 891        our buffer is big enough or if we convert to iovecs on socket writes
 892        and eliminate the copy to the CIFS buffer */
 893        bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
 894        if (bytes_sent > count)
 895                bytes_sent = count;
 896        pSMB->DataLengthHigh = 0;
 897        pSMB->DataOffset =
 898            cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 899    if(buf)
 900            memcpy(pSMB->Data,buf,bytes_sent);
 901        else if(ubuf)
 902                copy_from_user(pSMB->Data,ubuf,bytes_sent);
 903    else {
 904                /* No buffer */
 905                if(pSMB)
 906                        cifs_buf_release(pSMB);
 907                return -EINVAL;
 908        }
 909
 910        byte_count = bytes_sent + 1 /* pad */ ;
 911        pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
 912        pSMB->DataLengthHigh = 0;
 913        pSMB->hdr.smb_buf_length += byte_count;
 914        pSMB->ByteCount = cpu_to_le16(byte_count);
 915
 916        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
 917                         (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
 918        if (rc) {
 919                cFYI(1, ("Send error in write = %d", rc));
 920                *nbytes = 0;
 921        } else
 922                *nbytes = le16_to_cpu(pSMBr->Count);
 923
 924        if (pSMB)
 925                cifs_buf_release(pSMB);
 926
 927        /* Note: On -EAGAIN error only caller can retry on handle based calls 
 928                since file handle passed in no longer valid */
 929
 930        return rc;
 931}
 932
 933#ifdef CONFIG_CIFS_EXPERIMENTAL
 934int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
 935             const int netfid, const unsigned int count,
 936             const __u64 offset, unsigned int *nbytes, const char __user *buf,
 937             const int long_op)
 938{
 939        int rc = -EACCES;
 940        WRITE_REQ *pSMB = NULL;
 941        WRITE_RSP *pSMBr = NULL;
 942        /*int bytes_returned;*/
 943        unsigned bytes_sent;
 944        __u16 byte_count;
 945
 946        rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
 947        pSMBr = (WRITE_RSP *)pSMB; /* BB removeme BB */
 948    
 949    if (rc)
 950                return rc;
 951        /* tcon and ses pointer are checked in smb_init */
 952        if (tcon->ses->server == NULL)
 953                return -ECONNABORTED;
 954
 955        pSMB->AndXCommand = 0xFF; /* none */
 956        pSMB->Fid = netfid;
 957        pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
 958        pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
 959        pSMB->Reserved = 0xFFFFFFFF;
 960        pSMB->WriteMode = 0;
 961        pSMB->Remaining = 0;
 962        bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & ~0xFF;
 963        if (bytes_sent > count)
 964                bytes_sent = count;
 965        pSMB->DataLengthHigh = 0;
 966        pSMB->DataOffset =
 967            cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
 968
 969        byte_count = bytes_sent + 1 /* pad */ ;
 970        pSMB->DataLengthLow = cpu_to_le16(bytes_sent);
 971        pSMB->DataLengthHigh = 0;
 972        pSMB->hdr.smb_buf_length += byte_count;
 973        pSMB->ByteCount = cpu_to_le16(byte_count);
 974
 975/*      rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB,
 976                         (struct smb_hdr *) pSMBr, buf, buflen, &bytes_returned, long_op); */  /* BB fixme BB */
 977        if (rc) {
 978                cFYI(1, ("Send error in write2 (large write) = %d", rc));
 979                *nbytes = 0;
 980        } else
 981                *nbytes = le16_to_cpu(pSMBr->Count);
 982
 983        if (pSMB)
 984                cifs_small_buf_release(pSMB);
 985
 986        /* Note: On -EAGAIN error only caller can retry on handle based calls 
 987                since file handle passed in no longer valid */
 988
 989        return rc;
 990}
 991#endif /* CIFS_EXPERIMENTAL */
 992
 993int
 994CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
 995            const __u16 smb_file_id, const __u64 len,
 996            const __u64 offset, const __u32 numUnlock,
 997            const __u32 numLock, const __u8 lockType, const int waitFlag)
 998{
 999        int rc = 0;
1000        LOCK_REQ *pSMB = NULL;
1001        LOCK_RSP *pSMBr = NULL;
1002        int bytes_returned;
1003        int timeout = 0;
1004        __u16 count;
1005
1006        cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1007        rc = smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB,
1008                      (void **) &pSMBr);
1009        if (rc)
1010                return rc;
1011
1012        if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1013                timeout = -1; /* no response expected */
1014                pSMB->Timeout = 0;
1015        } else if (waitFlag == TRUE) {
1016                timeout = 3;  /* blocking operation, no timeout */
1017                pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1018        } else {
1019                pSMB->Timeout = 0;
1020        }
1021
1022        pSMB->NumberOfLocks = cpu_to_le16(numLock);
1023        pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1024        pSMB->LockType = lockType;
1025        pSMB->AndXCommand = 0xFF;       /* none */
1026        pSMB->Fid = smb_file_id; /* netfid stays le */
1027
1028        if((numLock != 0) || (numUnlock != 0)) {
1029                pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1030                /* BB where to store pid high? */
1031                pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1032                pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1033                pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1034                pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1035                count = sizeof(LOCKING_ANDX_RANGE);
1036        } else {
1037                /* oplock break */
1038                count = 0;
1039        }
1040        pSMB->hdr.smb_buf_length += count;
1041        pSMB->ByteCount = cpu_to_le16(count);
1042
1043        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1044                         (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1045
1046        if (rc) {
1047                cFYI(1, ("Send error in Lock = %d", rc));
1048        }
1049        if (pSMB)
1050                cifs_buf_release(pSMB);
1051
1052        /* Note: On -EAGAIN error only caller can retry on handle based calls 
1053        since file handle passed in no longer valid */
1054        return rc;
1055}
1056
1057int
1058CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1059{
1060        int rc = 0;
1061        CLOSE_REQ *pSMB = NULL;
1062        CLOSE_RSP *pSMBr = NULL;
1063        int bytes_returned;
1064        cFYI(1, ("In CIFSSMBClose"));
1065
1066/* do not retry on dead session on close */
1067        rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1068        pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1069        if(rc == -EAGAIN)
1070                return 0;
1071        if (rc)
1072                return rc;
1073
1074        pSMB->FileID = (__u16) smb_file_id;
1075        pSMB->LastWriteTime = 0;
1076        pSMB->ByteCount = 0;
1077        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1078                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1079        if (rc) {
1080                if(rc!=-EINTR) {
1081                        /* EINTR is expected when user ctl-c to kill app */
1082                        cERROR(1, ("Send error in Close = %d", rc));
1083                }
1084        }
1085
1086        if (pSMB)
1087                cifs_small_buf_release(pSMB);
1088
1089        /* Since session is dead, file will be closed on server already */
1090        if(rc == -EAGAIN)
1091                rc = 0;
1092
1093        return rc;
1094}
1095
1096int
1097CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1098              const char *fromName, const char *toName,
1099              const struct nls_table *nls_codepage)
1100{
1101        int rc = 0;
1102        RENAME_REQ *pSMB = NULL;
1103        RENAME_RSP *pSMBr = NULL;
1104        int bytes_returned;
1105        int name_len, name_len2;
1106        __u16 count;
1107
1108        cFYI(1, ("In CIFSSMBRename"));
1109renameRetry:
1110        rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1111                      (void **) &pSMBr);
1112        if (rc)
1113                return rc;
1114
1115        pSMB->BufferFormat = 0x04;
1116        pSMB->SearchAttributes =
1117            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1118                        ATTR_DIRECTORY);
1119
1120        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1121                name_len =
1122                    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
1123                                  /* find define for this maxpathcomponent */
1124                                  , nls_codepage);
1125                name_len++;     /* trailing null */
1126                name_len *= 2;
1127                pSMB->OldFileName[name_len] = 0x04;     /* pad */
1128        /* protocol requires ASCII signature byte on Unicode string */
1129                pSMB->OldFileName[name_len + 1] = 0x00;
1130                name_len2 =
1131                    cifs_strtoUCS((wchar_t *) & pSMB->
1132                                  OldFileName[name_len + 2], toName, PATH_MAX,
1133                                  nls_codepage);
1134                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1135                name_len2 *= 2; /* convert to bytes */
1136        } else {                /* BB improve the check for buffer overruns BB */
1137                name_len = strnlen(fromName, PATH_MAX);
1138                name_len++;     /* trailing null */
1139                strncpy(pSMB->OldFileName, fromName, name_len);
1140                name_len2 = strnlen(toName, PATH_MAX);
1141                name_len2++;    /* trailing null */
1142                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1143                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1144                name_len2++;    /* trailing null */
1145                name_len2++;    /* signature byte */
1146        }
1147
1148        count = 1 /* 1st signature byte */  + name_len + name_len2;
1149        pSMB->hdr.smb_buf_length += count;
1150        pSMB->ByteCount = cpu_to_le16(count);
1151
1152        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1153                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1154        if (rc) {
1155                cFYI(1, ("Send error in rename = %d", rc));
1156        } 
1157
1158#ifdef CONFIG_CIFS_STATS
1159          else {
1160                atomic_inc(&tcon->num_renames);
1161        }
1162#endif
1163
1164        if (pSMB)
1165                cifs_buf_release(pSMB);
1166
1167        if (rc == -EAGAIN)
1168                goto renameRetry;
1169
1170        return rc;
1171}
1172
1173int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1174                int netfid, char * target_name, const struct nls_table * nls_codepage) 
1175{
1176        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1177        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1178        struct set_file_rename * rename_info;
1179        char *data_offset;
1180        char dummy_string[30];
1181        int rc = 0;
1182        int bytes_returned = 0;
1183        int len_of_str;
1184        __u16 params, param_offset, offset, count, byte_count;
1185
1186        cFYI(1, ("Rename to File by handle"));
1187        rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1188                        (void **) &pSMBr);
1189        if (rc)
1190                return rc;
1191
1192        params = 6;
1193        pSMB->MaxSetupCount = 0;
1194        pSMB->Reserved = 0;
1195        pSMB->Flags = 0;
1196        pSMB->Timeout = 0;
1197        pSMB->Reserved2 = 0;
1198        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1199        offset = param_offset + params;
1200
1201        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1202        rename_info = (struct set_file_rename *) data_offset;
1203        pSMB->MaxParameterCount = cpu_to_le16(2);
1204        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1205        pSMB->SetupCount = 1;
1206        pSMB->Reserved3 = 0;
1207        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1208        byte_count = 3 /* pad */  + params;
1209        pSMB->ParameterCount = cpu_to_le16(params);
1210        pSMB->TotalParameterCount = pSMB->ParameterCount;
1211        pSMB->ParameterOffset = cpu_to_le16(param_offset);
1212        pSMB->DataOffset = cpu_to_le16(offset);
1213        /* construct random name ".cifs_tmp<inodenum><mid>" */
1214        rename_info->overwrite = cpu_to_le32(1);
1215        rename_info->root_fid  = 0;
1216        /* unicode only call */
1217        if(target_name == NULL) {
1218                sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1219                len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, dummy_string, 24, nls_codepage);
1220        } else {
1221                len_of_str = cifs_strtoUCS((wchar_t *) rename_info->target_name, target_name, PATH_MAX, nls_codepage);
1222        }
1223        rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1224        count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1225        byte_count += count;
1226        pSMB->DataCount = cpu_to_le16(count);
1227        pSMB->TotalDataCount = pSMB->DataCount;
1228        pSMB->Fid = netfid;
1229        pSMB->InformationLevel =
1230                cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1231        pSMB->Reserved4 = 0;
1232        pSMB->hdr.smb_buf_length += byte_count;
1233        pSMB->ByteCount = cpu_to_le16(byte_count);
1234        rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1235                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1236        if (rc) {
1237                cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1238        }
1239#ifdef CONFIG_CIFS_STATS
1240          else {
1241                atomic_inc(&pTcon->num_t2renames);
1242        }
1243#endif
1244        if (pSMB)
1245                cifs_buf_release(pSMB);
1246
1247        /* Note: On -EAGAIN error only caller can retry on handle based calls
1248                since file handle passed in no longer valid */
1249
1250        return rc;
1251}
1252
1253int
1254CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1255            const __u16 target_tid, const char *toName, const int flags,
1256            const struct nls_table *nls_codepage)
1257{
1258        int rc = 0;
1259        COPY_REQ *pSMB = NULL;
1260        COPY_RSP *pSMBr = NULL;
1261        int bytes_returned;
1262        int name_len, name_len2;
1263        __u16 count;
1264
1265        cFYI(1, ("In CIFSSMBCopy"));
1266copyRetry:
1267        rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1268                        (void **) &pSMBr);
1269        if (rc)
1270                return rc;
1271
1272        pSMB->BufferFormat = 0x04;
1273        pSMB->Tid2 = target_tid;
1274
1275        pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1276
1277        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1278                name_len = cifs_strtoUCS((wchar_t *) pSMB->OldFileName, 
1279                                fromName, 
1280                                PATH_MAX /* find define for this maxpathcomponent */,
1281                                nls_codepage);
1282                name_len++;     /* trailing null */
1283                name_len *= 2;
1284                pSMB->OldFileName[name_len] = 0x04;     /* pad */
1285                /* protocol requires ASCII signature byte on Unicode string */
1286                pSMB->OldFileName[name_len + 1] = 0x00;
1287                name_len2 = cifs_strtoUCS((wchar_t *) & pSMB->
1288                                OldFileName[name_len + 2], toName, PATH_MAX,
1289                                nls_codepage);
1290                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1291                name_len2 *= 2; /* convert to bytes */
1292        } else {                /* BB improve the check for buffer overruns BB */
1293                name_len = strnlen(fromName, PATH_MAX);
1294                name_len++;     /* trailing null */
1295                strncpy(pSMB->OldFileName, fromName, name_len);
1296                name_len2 = strnlen(toName, PATH_MAX);
1297                name_len2++;    /* trailing null */
1298                pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1299                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1300                name_len2++;    /* trailing null */
1301                name_len2++;    /* signature byte */
1302        }
1303
1304        count = 1 /* 1st signature byte */  + name_len + name_len2;
1305        pSMB->hdr.smb_buf_length += count;
1306        pSMB->ByteCount = cpu_to_le16(count);
1307
1308        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1309                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1310        if (rc) {
1311                cFYI(1, ("Send error in copy = %d with %d files copied",
1312                        rc, le16_to_cpu(pSMBr->CopyCount)));
1313        }
1314        if (pSMB)
1315                cifs_buf_release(pSMB);
1316
1317        if (rc == -EAGAIN)
1318                goto copyRetry;
1319
1320        return rc;
1321}
1322
1323int
1324CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1325                      const char *fromName, const char *toName,
1326                      const struct nls_table *nls_codepage)
1327{
1328        TRANSACTION2_SPI_REQ *pSMB = NULL;
1329        TRANSACTION2_SPI_RSP *pSMBr = NULL;
1330        char *data_offset;
1331        int name_len;
1332        int name_len_target;
1333        int rc = 0;
1334        int bytes_returned = 0;
1335        __u16 params, param_offset, offset, byte_count;
1336
1337        cFYI(1, ("In Symlink Unix style"));
1338createSymLinkRetry:
1339        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1340                      (void **) &pSMBr);
1341        if (rc)
1342                return rc;
1343
1344        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1345                name_len =
1346                    cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1347                                  /* find define for this maxpathcomponent */
1348                                  , nls_codepage);
1349                name_len++;     /* trailing null */
1350                name_len *= 2;
1351
1352        } else {                /* BB improve the check for buffer overruns BB */
1353                name_len = strnlen(fromName, PATH_MAX);
1354                name_len++;     /* trailing null */
1355                strncpy(pSMB->FileName, fromName, name_len);
1356        }
1357        params = 6 + name_len;
1358        pSMB->MaxSetupCount = 0;
1359        pSMB->Reserved = 0;
1360        pSMB->Flags = 0;
1361        pSMB->Timeout = 0;
1362        pSMB->Reserved2 = 0;
1363        param_offset = offsetof(struct smb_com_transaction2_spi_req,
1364                                     InformationLevel) - 4;
1365        offset = param_offset + params;
1366
1367        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1368        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1369                name_len_target =
1370                    cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1371                                  /* find define for this maxpathcomponent */
1372                                  , nls_codepage);
1373                name_len_target++;      /* trailing null */
1374                name_len_target *= 2;
1375        } else {                /* BB improve the check for buffer overruns BB */
1376                name_len_target = strnlen(toName, PATH_MAX);
1377                name_len_target++;      /* trailing null */
1378                strncpy(data_offset, toName, name_len_target);
1379        }
1380
1381        pSMB->MaxParameterCount = cpu_to_le16(2);
1382        /* BB find exact max on data count below from sess */
1383        pSMB->MaxDataCount = cpu_to_le16(1000);
1384        pSMB->SetupCount = 1;
1385        pSMB->Reserved3 = 0;
1386        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1387        byte_count = 3 /* pad */  + params + name_len_target;
1388        pSMB->DataCount = cpu_to_le16(name_len_target);
1389        pSMB->ParameterCount = cpu_to_le16(params);
1390        pSMB->TotalDataCount = pSMB->DataCount;
1391        pSMB->TotalParameterCount = pSMB->ParameterCount;
1392        pSMB->ParameterOffset = cpu_to_le16(param_offset);
1393        pSMB->DataOffset = cpu_to_le16(offset);
1394        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1395        pSMB->Reserved4 = 0;
1396        pSMB->hdr.smb_buf_length += byte_count;
1397        pSMB->ByteCount = cpu_to_le16(byte_count);
1398        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1399                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1400        if (rc) {
1401                cFYI(1,
1402                     ("Send error in SetPathInfo (create symlink) = %d",
1403                      rc));
1404        }
1405
1406        if (pSMB)
1407                cifs_buf_release(pSMB);
1408
1409        if (rc == -EAGAIN)
1410                goto createSymLinkRetry;
1411
1412        return rc;
1413}
1414
1415int
1416CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1417                       const char *fromName, const char *toName,
1418                       const struct nls_table *nls_codepage)
1419{
1420        TRANSACTION2_SPI_REQ *pSMB = NULL;
1421        TRANSACTION2_SPI_RSP *pSMBr = NULL;
1422        char *data_offset;
1423        int name_len;
1424        int name_len_target;
1425        int rc = 0;
1426        int bytes_returned = 0;
1427        __u16 params, param_offset, offset, byte_count;
1428
1429        cFYI(1, ("In Create Hard link Unix style"));
1430createHardLinkRetry:
1431        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1432                      (void **) &pSMBr);
1433        if (rc)
1434                return rc;
1435
1436        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1437                name_len = cifs_strtoUCS((wchar_t *) pSMB->FileName, toName, PATH_MAX
1438                                         /* find define for this maxpathcomponent */
1439                                         , nls_codepage);
1440                name_len++;     /* trailing null */
1441                name_len *= 2;
1442
1443        } else {                /* BB improve the check for buffer overruns BB */
1444                name_len = strnlen(toName, PATH_MAX);
1445                name_len++;     /* trailing null */
1446                strncpy(pSMB->FileName, toName, name_len);
1447        }
1448        params = 6 + name_len;
1449        pSMB->MaxSetupCount = 0;
1450        pSMB->Reserved = 0;
1451        pSMB->Flags = 0;
1452        pSMB->Timeout = 0;
1453        pSMB->Reserved2 = 0;
1454        param_offset = offsetof(struct smb_com_transaction2_spi_req,
1455                                     InformationLevel) - 4;
1456        offset = param_offset + params;
1457
1458        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1459        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1460                name_len_target =
1461                    cifs_strtoUCS((wchar_t *) data_offset, fromName, PATH_MAX
1462                                  /* find define for this maxpathcomponent */
1463                                  , nls_codepage);
1464                name_len_target++;      /* trailing null */
1465                name_len_target *= 2;
1466        } else {                /* BB improve the check for buffer overruns BB */
1467                name_len_target = strnlen(fromName, PATH_MAX);
1468                name_len_target++;      /* trailing null */
1469                strncpy(data_offset, fromName, name_len_target);
1470        }
1471
1472        pSMB->MaxParameterCount = cpu_to_le16(2);
1473        /* BB find exact max on data count below from sess*/
1474        pSMB->MaxDataCount = cpu_to_le16(1000);
1475        pSMB->SetupCount = 1;
1476        pSMB->Reserved3 = 0;
1477        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1478        byte_count = 3 /* pad */  + params + name_len_target;
1479        pSMB->ParameterCount = cpu_to_le16(params);
1480        pSMB->TotalParameterCount = pSMB->ParameterCount;
1481        pSMB->DataCount = cpu_to_le16(name_len_target);
1482        pSMB->TotalDataCount = pSMB->DataCount;
1483        pSMB->ParameterOffset = cpu_to_le16(param_offset);
1484        pSMB->DataOffset = cpu_to_le16(offset);
1485        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1486        pSMB->Reserved4 = 0;
1487        pSMB->hdr.smb_buf_length += byte_count;
1488        pSMB->ByteCount = cpu_to_le16(byte_count);
1489        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1490                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1491        if (rc) {
1492                cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1493        }
1494
1495        if (pSMB)
1496                cifs_buf_release(pSMB);
1497        if (rc == -EAGAIN)
1498                goto createHardLinkRetry;
1499
1500        return rc;
1501}
1502
1503int
1504CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1505                   const char *fromName, const char *toName,
1506                   const struct nls_table *nls_codepage)
1507{
1508        int rc = 0;
1509        NT_RENAME_REQ *pSMB = NULL;
1510        RENAME_RSP *pSMBr = NULL;
1511        int bytes_returned;
1512        int name_len, name_len2;
1513        __u16 count;
1514
1515        cFYI(1, ("In CIFSCreateHardLink"));
1516winCreateHardLinkRetry:
1517
1518        rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1519                      (void **) &pSMBr);
1520        if (rc)
1521                return rc;
1522
1523        pSMB->SearchAttributes =
1524            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1525                        ATTR_DIRECTORY);
1526        pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1527        pSMB->ClusterCount = 0;
1528
1529        pSMB->BufferFormat = 0x04;
1530
1531        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1532                name_len =
1533                    cifs_strtoUCS((wchar_t *) pSMB->OldFileName, fromName, PATH_MAX
1534                                  /* find define for this maxpathcomponent */
1535                                  , nls_codepage);
1536                name_len++;     /* trailing null */
1537                name_len *= 2;
1538                pSMB->OldFileName[name_len] = 0;        /* pad */
1539                pSMB->OldFileName[name_len + 1] = 0x04; 
1540                name_len2 =
1541                    cifs_strtoUCS((wchar_t *) & pSMB->
1542                                  OldFileName[name_len + 2], toName, PATH_MAX,
1543                                  nls_codepage);
1544                name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1545                name_len2 *= 2; /* convert to bytes */
1546        } else {                /* BB improve the check for buffer overruns BB */
1547                name_len = strnlen(fromName, PATH_MAX);
1548                name_len++;     /* trailing null */
1549                strncpy(pSMB->OldFileName, fromName, name_len);
1550                name_len2 = strnlen(toName, PATH_MAX);
1551                name_len2++;    /* trailing null */
1552                pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1553                strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1554                name_len2++;    /* trailing null */
1555                name_len2++;    /* signature byte */
1556        }
1557
1558        count = 1 /* string type byte */  + name_len + name_len2;
1559        pSMB->hdr.smb_buf_length += count;
1560        pSMB->ByteCount = cpu_to_le16(count);
1561
1562        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1563                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1564        if (rc) {
1565                cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1566        }
1567        if (pSMB)
1568                cifs_buf_release(pSMB);
1569        if (rc == -EAGAIN)
1570                goto winCreateHardLinkRetry;
1571
1572        return rc;
1573}
1574
1575int
1576CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1577                        const unsigned char *searchName,
1578                        char *symlinkinfo, const int buflen,
1579                        const struct nls_table *nls_codepage)
1580{
1581/* SMB_QUERY_FILE_UNIX_LINK */
1582        TRANSACTION2_QPI_REQ *pSMB = NULL;
1583        TRANSACTION2_QPI_RSP *pSMBr = NULL;
1584        int rc = 0;
1585        int bytes_returned;
1586        int name_len;
1587        __u16 params, byte_count;
1588
1589        cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1590
1591querySymLinkRetry:
1592        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1593                      (void **) &pSMBr);
1594        if (rc)
1595                return rc;
1596
1597        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1598                name_len =
1599                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1600                                  /* find define for this maxpathcomponent */
1601                                  , nls_codepage);
1602                name_len++;     /* trailing null */
1603                name_len *= 2;
1604        } else {                /* BB improve the check for buffer overruns BB */
1605                name_len = strnlen(searchName, PATH_MAX);
1606                name_len++;     /* trailing null */
1607                strncpy(pSMB->FileName, searchName, name_len);
1608        }
1609
1610        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1611        pSMB->TotalDataCount = 0;
1612        pSMB->MaxParameterCount = cpu_to_le16(2);
1613        /* BB find exact max data count below from sess structure BB */
1614        pSMB->MaxDataCount = cpu_to_le16(4000);
1615        pSMB->MaxSetupCount = 0;
1616        pSMB->Reserved = 0;
1617        pSMB->Flags = 0;
1618        pSMB->Timeout = 0;
1619        pSMB->Reserved2 = 0;
1620        pSMB->ParameterOffset = cpu_to_le16(offsetof(
1621        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1622        pSMB->DataCount = 0;
1623        pSMB->DataOffset = 0;
1624        pSMB->SetupCount = 1;
1625        pSMB->Reserved3 = 0;
1626        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1627        byte_count = params + 1 /* pad */ ;
1628        pSMB->TotalParameterCount = cpu_to_le16(params);
1629        pSMB->ParameterCount = pSMB->TotalParameterCount;
1630        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1631        pSMB->Reserved4 = 0;
1632        pSMB->hdr.smb_buf_length += byte_count;
1633        pSMB->ByteCount = cpu_to_le16(byte_count);
1634
1635        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1636                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1637        if (rc) {
1638                cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1639        } else {
1640                /* decode response */
1641
1642                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1643                if (rc || (pSMBr->ByteCount < 2))
1644                /* BB also check enough total bytes returned */
1645                        rc = -EIO;      /* bad smb */
1646                else {
1647                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1648                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1649
1650                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1651                                name_len = UniStrnlen((wchar_t *) ((char *)
1652                                        &pSMBr->hdr.Protocol +data_offset),
1653                                        min_t(const int, buflen,count) / 2);
1654                                cifs_strfromUCS_le(symlinkinfo,
1655                                        (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1656                                                data_offset),
1657                                        name_len, nls_codepage);
1658                        } else {
1659                                strncpy(symlinkinfo,
1660                                        (char *) &pSMBr->hdr.Protocol + 
1661                                                data_offset,
1662                                        min_t(const int, buflen, count));
1663                        }
1664                        symlinkinfo[buflen] = 0;
1665        /* just in case so calling code does not go off the end of buffer */
1666                }
1667        }
1668        if (pSMB)
1669                cifs_buf_release(pSMB);
1670        if (rc == -EAGAIN)
1671                goto querySymLinkRetry;
1672        return rc;
1673}
1674
1675
1676
1677int
1678CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1679                        const unsigned char *searchName,
1680                        char *symlinkinfo, const int buflen,__u16 fid,
1681                        const struct nls_table *nls_codepage)
1682{
1683        int rc = 0;
1684        int bytes_returned;
1685        int name_len;
1686        struct smb_com_transaction_ioctl_req * pSMB;
1687        struct smb_com_transaction_ioctl_rsp * pSMBr;
1688
1689        cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1690        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1691                      (void **) &pSMBr);
1692        if (rc)
1693                return rc;
1694
1695        pSMB->TotalParameterCount = 0 ;
1696        pSMB->TotalDataCount = 0;
1697        pSMB->MaxParameterCount = cpu_to_le32(2);
1698        /* BB find exact data count max from sess structure BB */
1699        pSMB->MaxDataCount = cpu_to_le32(4000);
1700        pSMB->MaxSetupCount = 4;
1701        pSMB->Reserved = 0;
1702        pSMB->ParameterOffset = 0;
1703        pSMB->DataCount = 0;
1704        pSMB->DataOffset = 0;
1705        pSMB->SetupCount = 4;
1706        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1707        pSMB->ParameterCount = pSMB->TotalParameterCount;
1708        pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1709        pSMB->IsFsctl = 1; /* FSCTL */
1710        pSMB->IsRootFlag = 0;
1711        pSMB->Fid = fid; /* file handle always le */
1712        pSMB->ByteCount = 0;
1713
1714        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1715                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1716        if (rc) {
1717                cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1718        } else {                /* decode response */
1719                __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1720                __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1721                if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1722                /* BB also check enough total bytes returned */
1723                        rc = -EIO;      /* bad smb */
1724                else {
1725                        if(data_count && (data_count < 2048)) {
1726                /* could also validate reparse tag && better check name length */
1727                                struct reparse_data * reparse_buf = (struct reparse_data *)
1728                                        ((char *)&pSMBr->hdr.Protocol + data_offset);
1729                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1730                                        name_len = UniStrnlen((wchar_t *)
1731                                                        (reparse_buf->LinkNamesBuf + 
1732                                                        reparse_buf->TargetNameOffset),
1733                                                        min(buflen/2, reparse_buf->TargetNameLen / 2)); 
1734                                        cifs_strfromUCS_le(symlinkinfo,
1735                                                (wchar_t *) (reparse_buf->LinkNamesBuf + 
1736                                                reparse_buf->TargetNameOffset),
1737                                                name_len, nls_codepage);
1738                                } else { /* ASCII names */
1739                                        strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
1740                                                reparse_buf->TargetNameOffset, 
1741                                                min_t(const int, buflen, reparse_buf->TargetNameLen));
1742                                }
1743                        } else {
1744                                rc = -EIO;
1745                                cFYI(1,("Invalid return data count on get reparse info ioctl"));
1746                        }
1747                        symlinkinfo[buflen] = 0; /* just in case so the caller
1748                                        does not go off the end of the buffer */
1749                        cFYI(1,("readlink result - %s ",symlinkinfo));
1750                }
1751        }
1752        if (pSMB)
1753                cifs_buf_release(pSMB);
1754
1755        /* Note: On -EAGAIN error only caller can retry on handle based calls
1756                since file handle passed in no longer valid */
1757
1758        return rc;
1759}
1760
1761#ifdef CONFIG_CIFS_POSIX
1762
1763/*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1764static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1765{
1766        /* u8 cifs fields do not need le conversion */
1767        ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
1768        ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
1769        ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1770        /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1771
1772        return;
1773}
1774
1775/* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1776static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,const int acl_type,const int size_of_data_area)
1777{
1778        int size =  0;
1779        int i;
1780        __u16 count;
1781        struct cifs_posix_ace * pACE;
1782        struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1783        posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1784
1785        if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1786                return -EOPNOTSUPP;
1787
1788        if(acl_type & ACL_TYPE_ACCESS) {
1789                count = le16_to_cpu(cifs_acl->access_entry_count);
1790                pACE = &cifs_acl->ace_array[0];
1791                size = sizeof(struct cifs_posix_acl);
1792                size += sizeof(struct cifs_posix_ace) * count;
1793                /* check if we would go beyond end of SMB */
1794                if(size_of_data_area < size) {
1795                        cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
1796                        return -EINVAL;
1797                }
1798        } else if(acl_type & ACL_TYPE_DEFAULT) {
1799                count = le16_to_cpu(cifs_acl->access_entry_count);
1800                size = sizeof(struct cifs_posix_acl);
1801                size += sizeof(struct cifs_posix_ace) * count;
1802/* skip past access ACEs to get to default ACEs */
1803                pACE = &cifs_acl->ace_array[count];
1804                count = le16_to_cpu(cifs_acl->default_entry_count);
1805                size += sizeof(struct cifs_posix_ace) * count;
1806                /* check if we would go beyond end of SMB */
1807                if(size_of_data_area < size)
1808                        return -EINVAL;
1809        } else {
1810                /* illegal type */
1811                return -EINVAL;
1812        }
1813
1814        size = posix_acl_xattr_size(count);
1815        if((buflen == 0) || (local_acl == NULL)) {
1816                /* used to query ACL EA size */                         
1817        } else if(size > buflen) {
1818                return -ERANGE;
1819        } else /* buffer big enough */ {
1820                local_acl->a_version = POSIX_ACL_XATTR_VERSION;
1821                for(i = 0;i < count ;i++) {
1822                        cifs_convert_ace(&local_acl->a_entries[i],pACE);
1823                        pACE ++;
1824                }
1825        }
1826        return size;
1827}
1828
1829__u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
1830                        const posix_acl_xattr_entry * local_ace)
1831{
1832        __u16 rc = 0; /* 0 = ACL converted ok */
1833
1834        cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
1835        cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
1836        /* BB is there a better way to handle the large uid? */
1837        if(local_ace->e_id == -1) {
1838        /* Probably no need to le convert -1 on any arch but can not hurt */
1839                cifs_ace->cifs_uid = cpu_to_le64(-1);
1840        } else 
1841                cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
1842        /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
1843        return rc;
1844}
1845
1846/* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
1847__u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
1848                const int acl_type)
1849{
1850        __u16 rc = 0;
1851        struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
1852        posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
1853        int count;
1854        int i;
1855
1856        if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
1857                return 0;
1858
1859        count = posix_acl_xattr_count((size_t)buflen);
1860        cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
1861                count,buflen,local_acl->a_version));
1862        if(local_acl->a_version != 2) {
1863                cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
1864                return 0;
1865        }
1866        cifs_acl->version = cpu_to_le16(1);
1867        if(acl_type == ACL_TYPE_ACCESS) 
1868                cifs_acl->access_entry_count = count;
1869        else if(acl_type == ACL_TYPE_DEFAULT)
1870                cifs_acl->default_entry_count = count;
1871        else {
1872                cFYI(1,("unknown ACL type %d",acl_type));
1873                return 0;
1874        }
1875        for(i=0;i<count;i++) {
1876                rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
1877                                        &local_acl->a_entries[i]);
1878                if(rc != 0) {
1879                        /* ACE not converted */
1880                        break;
1881                }
1882        }
1883        if(rc == 0) {
1884                rc = (__u16)(count * sizeof(struct cifs_posix_ace));
1885                rc += sizeof(struct cifs_posix_acl);
1886                /* BB add check to make sure ACL does not overflow SMB */
1887        }
1888        return rc;
1889}
1890
1891int
1892CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
1893                        const unsigned char *searchName,
1894                        char *acl_inf, const int buflen, const int acl_type,
1895                        const struct nls_table *nls_codepage)
1896{
1897/* SMB_QUERY_POSIX_ACL */
1898        TRANSACTION2_QPI_REQ *pSMB = NULL;
1899        TRANSACTION2_QPI_RSP *pSMBr = NULL;
1900        int rc = 0;
1901        int bytes_returned;
1902        int name_len;
1903        __u16 params, byte_count;
1904                                                                                                                                             
1905        cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
1906
1907queryAclRetry:
1908        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1909                (void **) &pSMBr);
1910        if (rc)
1911                return rc;
1912                                                                                                                                             
1913        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1914                name_len =
1915                        cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1916                                /* BB fixme find define for this maxpathcomponent */
1917                                , nls_codepage);
1918                name_len++;     /* trailing null */
1919                name_len *= 2;
1920                pSMB->FileName[name_len] = 0;
1921                pSMB->FileName[name_len+1] = 0;
1922        } else {                /* BB improve the check for buffer overruns BB */
1923                name_len = strnlen(searchName, PATH_MAX /* BB fixme */);
1924                name_len++;     /* trailing null */
1925                strncpy(pSMB->FileName, searchName, name_len);
1926        }
1927
1928        params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1929        pSMB->TotalDataCount = 0;
1930        pSMB->MaxParameterCount = cpu_to_le16(2);
1931        /* BB find exact max data count below from sess structure BB */
1932        pSMB->MaxDataCount = cpu_to_le16(4000);
1933        pSMB->MaxSetupCount = 0;
1934        pSMB->Reserved = 0;
1935        pSMB->Flags = 0;
1936        pSMB->Timeout = 0;
1937        pSMB->Reserved2 = 0;
1938        pSMB->ParameterOffset = cpu_to_le16(
1939                offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1940        pSMB->DataCount = 0;
1941        pSMB->DataOffset = 0;
1942        pSMB->SetupCount = 1;
1943        pSMB->Reserved3 = 0;
1944        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1945        byte_count = params + 1 /* pad */ ;
1946        pSMB->TotalParameterCount = cpu_to_le16(params);
1947        pSMB->ParameterCount = pSMB->TotalParameterCount;
1948        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
1949        pSMB->Reserved4 = 0;
1950        pSMB->hdr.smb_buf_length += byte_count;
1951        pSMB->ByteCount = cpu_to_le16(byte_count);
1952
1953        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1954                (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1955        if (rc) {
1956                cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
1957        } else {
1958                /* decode response */
1959 
1960                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1961                if (rc || (pSMBr->ByteCount < 2))
1962                /* BB also check enough total bytes returned */
1963                        rc = -EIO;      /* bad smb */
1964                else {
1965                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1966                        __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1967                        rc = cifs_copy_posix_acl(acl_inf,
1968                                (char *)&pSMBr->hdr.Protocol+data_offset,
1969                                buflen,acl_type,count);
1970                }
1971        }
1972        if (pSMB)
1973                cifs_buf_release(pSMB);
1974        if (rc == -EAGAIN)
1975                goto queryAclRetry;
1976        return rc;
1977}
1978
1979int
1980CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
1981                        const unsigned char *fileName,
1982                        const char *local_acl, const int buflen, const int acl_type,
1983                        const struct nls_table *nls_codepage)
1984{
1985        struct smb_com_transaction2_spi_req *pSMB = NULL;
1986        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
1987        char *parm_data;
1988        int name_len;
1989        int rc = 0;
1990        int bytes_returned = 0;
1991        __u16 params, byte_count, data_count, param_offset, offset;
1992
1993        cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
1994setAclRetry:
1995        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1996                      (void **) &pSMBr);
1997        if (rc)
1998                return rc;
1999                                                                                                                if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2000                name_len =
2001                        cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
2002                                /* BB fixme find define for this maxpathcomponent */
2003                                , nls_codepage);
2004                name_len++;     /* trailing null */
2005                name_len *= 2;
2006        } else {                /* BB improve the check for buffer overruns BB */
2007                name_len = strnlen(fileName, PATH_MAX);
2008                name_len++;     /* trailing null */
2009                strncpy(pSMB->FileName, fileName, name_len);
2010        }
2011        params = 6 + name_len;
2012        pSMB->MaxParameterCount = cpu_to_le16(2);
2013        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2014        pSMB->MaxSetupCount = 0;
2015        pSMB->Reserved = 0;
2016        pSMB->Flags = 0;
2017        pSMB->Timeout = 0;
2018        pSMB->Reserved2 = 0;
2019        param_offset = offsetof(struct smb_com_transaction2_spi_req,
2020                                     InformationLevel) - 4;
2021        offset = param_offset + params;
2022        parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2023        pSMB->ParameterOffset = cpu_to_le16(param_offset);
2024
2025        /* convert to on the wire format for POSIX ACL */
2026        data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2027
2028        if(data_count == 0) {
2029                rc = -EOPNOTSUPP;
2030                goto setACLerrorExit;
2031        }
2032        pSMB->DataOffset = cpu_to_le16(offset);
2033        pSMB->SetupCount = 1;
2034        pSMB->Reserved3 = 0;
2035        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2036        pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2037        byte_count = 3 /* pad */  + params + data_count;
2038        pSMB->DataCount = cpu_to_le16(data_count);
2039        pSMB->TotalDataCount = pSMB->DataCount;
2040        pSMB->ParameterCount = cpu_to_le16(params);
2041        pSMB->TotalParameterCount = pSMB->ParameterCount;
2042        pSMB->Reserved4 = 0;
2043        pSMB->hdr.smb_buf_length += byte_count;
2044        pSMB->ByteCount = cpu_to_le16(byte_count);
2045        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2046                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2047        if (rc) {
2048                cFYI(1, ("Set POSIX ACL returned %d", rc));
2049        }
2050
2051setACLerrorExit:
2052        if (pSMB)
2053                cifs_buf_release(pSMB);
2054                                                                                                                if (rc == -EAGAIN)
2055                goto setAclRetry;
2056                                                                                                                return rc;
2057}
2058
2059#endif
2060
2061int
2062CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2063                 const unsigned char *searchName,
2064                 FILE_ALL_INFO * pFindData,
2065                 const struct nls_table *nls_codepage)
2066{
2067/* level 263 SMB_QUERY_FILE_ALL_INFO */
2068        TRANSACTION2_QPI_REQ *pSMB = NULL;
2069        TRANSACTION2_QPI_RSP *pSMBr = NULL;
2070        int rc = 0;
2071        int bytes_returned;
2072        int name_len;
2073        __u16 params, byte_count;
2074
2075/* cFYI(1, ("In QPathInfo path %s", searchName)); */ /* BB fixme BB */
2076QPathInfoRetry:
2077        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2078                      (void **) &pSMBr);
2079        if (rc)
2080                return rc;
2081
2082        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2083                name_len =
2084                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2085                                  /* find define for this maxpathcomponent */
2086                                  , nls_codepage);
2087                name_len++;     /* trailing null */
2088                name_len *= 2;
2089        } else {                /* BB improve the check for buffer overruns BB */
2090                name_len = strnlen(searchName, PATH_MAX);
2091                name_len++;     /* trailing null */
2092                strncpy(pSMB->FileName, searchName, name_len);
2093        }
2094
2095        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2096        pSMB->TotalDataCount = 0;
2097        pSMB->MaxParameterCount = cpu_to_le16(2);
2098        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2099        pSMB->MaxSetupCount = 0;
2100        pSMB->Reserved = 0;
2101        pSMB->Flags = 0;
2102        pSMB->Timeout = 0;
2103        pSMB->Reserved2 = 0;
2104        pSMB->ParameterOffset = cpu_to_le16(offsetof(
2105        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2106        pSMB->DataCount = 0;
2107        pSMB->DataOffset = 0;
2108        pSMB->SetupCount = 1;
2109        pSMB->Reserved3 = 0;
2110        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2111        byte_count = params + 1 /* pad */ ;
2112        pSMB->TotalParameterCount = cpu_to_le16(params);
2113        pSMB->ParameterCount = pSMB->TotalParameterCount;
2114        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2115        pSMB->Reserved4 = 0;
2116        pSMB->hdr.smb_buf_length += byte_count;
2117        pSMB->ByteCount = cpu_to_le16(byte_count);
2118
2119        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2120                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2121        if (rc) {
2122                cFYI(1, ("Send error in QPathInfo = %d", rc));
2123        } else {                /* decode response */
2124                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2125
2126                if (rc || (pSMBr->ByteCount < 40)) 
2127                        rc = -EIO;      /* bad smb */
2128                else if (pFindData){
2129                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2130                        memcpy((char *) pFindData,
2131                               (char *) &pSMBr->hdr.Protocol +
2132                               data_offset, sizeof (FILE_ALL_INFO));
2133                } else
2134                    rc = -ENOMEM;
2135        }
2136        if (pSMB)
2137                cifs_buf_release(pSMB);
2138        if (rc == -EAGAIN)
2139                goto QPathInfoRetry;
2140
2141        return rc;
2142}
2143
2144int
2145CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2146                     const unsigned char *searchName,
2147                     FILE_UNIX_BASIC_INFO * pFindData,
2148                     const struct nls_table *nls_codepage)
2149{
2150/* SMB_QUERY_FILE_UNIX_BASIC */
2151        TRANSACTION2_QPI_REQ *pSMB = NULL;
2152        TRANSACTION2_QPI_RSP *pSMBr = NULL;
2153        int rc = 0;
2154        int bytes_returned = 0;
2155        int name_len;
2156        __u16 params, byte_count;
2157
2158        cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2159UnixQPathInfoRetry:
2160        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2161                      (void **) &pSMBr);
2162        if (rc)
2163                return rc;
2164
2165        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2166                name_len =
2167                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2168                                  /* find define for this maxpathcomponent */
2169                                  , nls_codepage);
2170                name_len++;     /* trailing null */
2171                name_len *= 2;
2172        } else {                /* BB improve the check for buffer overruns BB */
2173                name_len = strnlen(searchName, PATH_MAX);
2174                name_len++;     /* trailing null */
2175                strncpy(pSMB->FileName, searchName, name_len);
2176        }
2177
2178        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2179        pSMB->TotalDataCount = 0;
2180        pSMB->MaxParameterCount = cpu_to_le16(2);
2181        /* BB find exact max SMB PDU from sess structure BB */
2182        pSMB->MaxDataCount = cpu_to_le16(4000); 
2183        pSMB->MaxSetupCount = 0;
2184        pSMB->Reserved = 0;
2185        pSMB->Flags = 0;
2186        pSMB->Timeout = 0;
2187        pSMB->Reserved2 = 0;
2188        pSMB->ParameterOffset = cpu_to_le16(offsetof(
2189        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2190        pSMB->DataCount = 0;
2191        pSMB->DataOffset = 0;
2192        pSMB->SetupCount = 1;
2193        pSMB->Reserved3 = 0;
2194        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2195        byte_count = params + 1 /* pad */ ;
2196        pSMB->TotalParameterCount = cpu_to_le16(params);
2197        pSMB->ParameterCount = pSMB->TotalParameterCount;
2198        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2199        pSMB->Reserved4 = 0;
2200        pSMB->hdr.smb_buf_length += byte_count;
2201        pSMB->ByteCount = cpu_to_le16(byte_count);
2202
2203        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2204                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2205        if (rc) {
2206                cFYI(1, ("Send error in QPathInfo = %d", rc));
2207        } else {                /* decode response */
2208                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2209
2210                if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2211                        rc = -EIO;      /* bad smb */
2212                } else {
2213                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2214                        memcpy((char *) pFindData,
2215                               (char *) &pSMBr->hdr.Protocol +
2216                               data_offset,
2217                               sizeof (FILE_UNIX_BASIC_INFO));
2218                }
2219        }
2220        if (pSMB)
2221                cifs_buf_release(pSMB);
2222        if (rc == -EAGAIN)
2223                goto UnixQPathInfoRetry;
2224
2225        return rc;
2226}
2227
2228#ifdef CONFIG_CIFS_EXPERIMENTAL  /* function unused at present */
2229int
2230CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2231               const char *searchName, FILE_ALL_INFO * findData,
2232               const struct nls_table *nls_codepage)
2233{
2234/* level 257 SMB_ */
2235        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2236        TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2237        int rc = 0;
2238        int bytes_returned;
2239        int name_len;
2240        __u16 params, byte_count;
2241
2242        cFYI(1, ("In FindUnique"));
2243findUniqueRetry:
2244        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2245                      (void **) &pSMBr);
2246        if (rc)
2247                return rc;
2248
2249        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2250                name_len =
2251                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2252                                  /* find define for this maxpathcomponent */
2253                                  , nls_codepage);
2254                name_len++;     /* trailing null */
2255                name_len *= 2;
2256        } else {                /* BB improve the check for buffer overruns BB */
2257                name_len = strnlen(searchName, PATH_MAX);
2258                name_len++;     /* trailing null */
2259                strncpy(pSMB->FileName, searchName, name_len);
2260        }
2261
2262        params = 12 + name_len /* includes null */ ;
2263        pSMB->TotalDataCount = 0;       /* no EAs */
2264        pSMB->MaxParameterCount = cpu_to_le16(2);
2265        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2266        pSMB->MaxSetupCount = 0;
2267        pSMB->Reserved = 0;
2268        pSMB->Flags = 0;
2269        pSMB->Timeout = 0;
2270        pSMB->Reserved2 = 0;
2271        pSMB->ParameterOffset = cpu_to_le16(
2272         offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2273        pSMB->DataCount = 0;
2274        pSMB->DataOffset = 0;
2275        pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2276        pSMB->Reserved3 = 0;
2277        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2278        byte_count = params + 1 /* pad */ ;
2279        pSMB->TotalParameterCount = cpu_to_le16(params);
2280        pSMB->ParameterCount = pSMB->TotalParameterCount;
2281        pSMB->SearchAttributes =
2282            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2283                        ATTR_DIRECTORY);
2284        pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2285        pSMB->SearchFlags = cpu_to_le16(1);
2286        pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2287        pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2288        pSMB->hdr.smb_buf_length += byte_count;
2289        pSMB->ByteCount = cpu_to_le16(byte_count);
2290
2291        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2292                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2293
2294        if (rc) {
2295                cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2296        } else {                /* decode response */
2297
2298                /* BB fill in */
2299        }
2300        if (pSMB)
2301                cifs_buf_release(pSMB);
2302        if (rc == -EAGAIN)
2303                goto findUniqueRetry;
2304
2305        return rc;
2306}
2307#endif /* CIFS_EXPERIMENTAL */
2308
2309int
2310CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2311              const char *searchName, FILE_DIRECTORY_INFO * findData,
2312              T2_FFIRST_RSP_PARMS * findParms,
2313              const struct nls_table *nls_codepage, int *pUnicodeFlag,
2314              int *pUnixFlag)
2315{
2316/* level 257 SMB_ */
2317        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2318        TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2319        char *response_data;
2320        int rc = 0;
2321        int bytes_returned;
2322        int name_len;
2323        __u16 params, byte_count;
2324
2325        cFYI(1, ("In FindFirst"));
2326findFirstRetry:
2327        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2328                      (void **) &pSMBr);
2329        if (rc)
2330                return rc;
2331
2332        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2333                name_len =
2334                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
2335                                  /* find define for this maxpathcomponent */
2336                                  , nls_codepage);
2337                name_len++;     /* trailing null */
2338                name_len *= 2;
2339        } else {                /* BB improve the check for buffer overruns BB */
2340                name_len = strnlen(searchName, PATH_MAX);
2341                name_len++;     /* trailing null */
2342                strncpy(pSMB->FileName, searchName, name_len);
2343        }
2344
2345        params = 12 + name_len /* includes null */ ;
2346        pSMB->TotalDataCount = 0;       /* no EAs */
2347        pSMB->MaxParameterCount = cpu_to_le16(10);
2348        pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2349                                          MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2350        pSMB->MaxSetupCount = 0;
2351        pSMB->Reserved = 0;
2352        pSMB->Flags = 0;
2353        pSMB->Timeout = 0;
2354        pSMB->Reserved2 = 0;
2355        byte_count = params + 1 /* pad */ ;
2356        pSMB->TotalParameterCount = cpu_to_le16(params);
2357        pSMB->ParameterCount = pSMB->TotalParameterCount;
2358        pSMB->ParameterOffset = cpu_to_le16(
2359                offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2360        pSMB->DataCount = 0;
2361        pSMB->DataOffset = 0;
2362        pSMB->SetupCount = 1;   /* one byte no need to make endian neutral */
2363        pSMB->Reserved3 = 0;
2364        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2365        pSMB->SearchAttributes =
2366            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2367                        ATTR_DIRECTORY);
2368        pSMB->SearchCount = cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_DIRECTORY_INFO)); /* should this be shrunk even more ? */
2369        pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2370
2371        /* test for Unix extensions */
2372        if (tcon->ses->capabilities & CAP_UNIX) {
2373                pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2374                *pUnixFlag = TRUE;
2375        } else {
2376                pSMB->InformationLevel =
2377                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2378                *pUnixFlag = FALSE;
2379        }
2380        pSMB->SearchStorageType = 0;    /* BB what should we set this to? It is not clear if it matters BB */
2381        pSMB->hdr.smb_buf_length += byte_count;
2382        pSMB->ByteCount = cpu_to_le16(byte_count);
2383
2384        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2385                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2386
2387        if (rc) {               /* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2388                cFYI(1, ("Error in FindFirst = %d", rc));
2389        } else {
2390                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2391                if(!rc) {
2392                /* decode response */
2393                /* BB add safety checks for these memcpys */
2394                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2395                                *pUnicodeFlag = TRUE;
2396                        else
2397                                *pUnicodeFlag = FALSE;
2398                        memcpy(findParms,
2399                               (char *) &pSMBr->hdr.Protocol +
2400                               le16_to_cpu(pSMBr->t2.ParameterOffset),
2401                               sizeof (T2_FFIRST_RSP_PARMS));
2402                        response_data =
2403                            (char *) &pSMBr->hdr.Protocol +
2404                            le16_to_cpu(pSMBr->t2.DataOffset);
2405                        memcpy(findData, response_data, 
2406                                le16_to_cpu(pSMBr->t2.DataCount));
2407                }
2408        }
2409        if (pSMB)
2410                cifs_buf_release(pSMB);
2411
2412        if (rc == -EAGAIN)
2413                goto findFirstRetry;
2414
2415        return rc;
2416}
2417
2418/* xid, tcon, searchName and codepage are input parms, rest are returned */
2419int
2420CIFSFindFirst2(const int xid, struct cifsTconInfo *tcon,
2421              const char *searchName, 
2422              const struct nls_table *nls_codepage,
2423              __u16 *   pnetfid,
2424              struct cifs_search_info * psrch_inf)
2425{
2426/* level 257 SMB_ */
2427        TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2428        TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2429        T2_FFIRST_RSP_PARMS * parms;
2430        int rc = 0;
2431        int bytes_returned = 0;
2432        int name_len;
2433        __u16 params, byte_count;
2434
2435        cFYI(1, ("In FindFirst2"));
2436
2437findFirst2Retry:
2438        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2439                      (void **) &pSMBr);
2440        if (rc)
2441                return rc;
2442
2443        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2444                name_len =
2445                    cifs_strtoUCS((wchar_t *) pSMB->FileName,searchName,
2446                                 PATH_MAX, nls_codepage);
2447                name_len++;     /* trailing null */
2448                name_len *= 2;
2449                pSMB->FileName[name_len] = 0; /* null terminate just in case */
2450                pSMB->FileName[name_len+1] = 0;
2451        } else {        /* BB add check for overrun of SMB buf BB */
2452                name_len = strnlen(searchName, PATH_MAX);
2453                name_len++;     /* trailing null */
2454/* BB fix here and in unicode clause above ie
2455                if(name_len > buffersize-header)
2456                        free buffer exit; BB */
2457                strncpy(pSMB->FileName, searchName, name_len);
2458                pSMB->FileName[name_len] = 0; /* just in case */
2459        }
2460
2461        params = 12 + name_len /* includes null */ ;
2462        pSMB->TotalDataCount = 0;       /* no EAs */
2463        pSMB->MaxParameterCount = cpu_to_le16(10);
2464        pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2465                                          MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2466        pSMB->MaxSetupCount = 0;
2467        pSMB->Reserved = 0;
2468        pSMB->Flags = 0;
2469        pSMB->Timeout = 0;
2470        pSMB->Reserved2 = 0;
2471        byte_count = params + 1 /* pad */ ;
2472        pSMB->TotalParameterCount = cpu_to_le16(params);
2473        pSMB->ParameterCount = pSMB->TotalParameterCount;
2474        pSMB->ParameterOffset = cpu_to_le16(
2475          offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2476        pSMB->DataCount = 0;
2477        pSMB->DataOffset = 0;
2478        pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2479        pSMB->Reserved3 = 0;
2480        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2481        pSMB->SearchAttributes =
2482            cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2483                        ATTR_DIRECTORY);
2484        pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2485        pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2486                CIFS_SEARCH_RETURN_RESUME);
2487        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2488
2489        /* BB what should we set StorageType to? Does it matter? BB */
2490        pSMB->SearchStorageType = 0;
2491        pSMB->hdr.smb_buf_length += byte_count;
2492        pSMB->ByteCount = cpu_to_le16(byte_count);
2493
2494        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2495                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2496
2497        if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2498                /* BB Add code to handle unsupported level rc */
2499                cFYI(1, ("Error in FindFirst = %d", rc));
2500
2501                if (pSMB)
2502                        cifs_buf_release(pSMB);
2503
2504                /* BB eventually could optimize out free and realloc of buf */
2505                /*    for this case */
2506                if (rc == -EAGAIN)
2507                        goto findFirst2Retry;
2508        } else { /* decode response */
2509                /* BB remember to free buffer if error BB */
2510                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2511                if(rc == 0) {
2512                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2513                                psrch_inf->unicode = TRUE;
2514                        else
2515                                psrch_inf->unicode = FALSE;
2516
2517                        psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2518                        psrch_inf->srch_entries_start = 
2519                                (char *) &pSMBr->hdr.Protocol + 
2520                                        le16_to_cpu(pSMBr->t2.DataOffset);
2521
2522                        parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2523                               le16_to_cpu(pSMBr->t2.ParameterOffset));
2524
2525                        if(parms->EndofSearch)
2526                                psrch_inf->endOfSearch = TRUE;
2527                        else
2528                                psrch_inf->endOfSearch = FALSE;
2529
2530                        psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2531                        psrch_inf->index_of_last_entry = 
2532                                psrch_inf->entries_in_buffer;
2533/*cFYI(1,("entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry));  */
2534                        *pnetfid = parms->SearchHandle;
2535                } else {
2536                        if(pSMB)
2537                                cifs_buf_release(pSMB);
2538                }
2539        }
2540
2541        return rc;
2542}
2543
2544int CIFSFindNext2(const int xid, struct cifsTconInfo *tcon,
2545            __u16 searchHandle, struct cifs_search_info * psrch_inf)
2546{
2547        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2548        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2549        T2_FNEXT_RSP_PARMS * parms;
2550        char *response_data;
2551        int rc = 0;
2552        int bytes_returned, name_len;
2553        __u16 params, byte_count;
2554
2555        cFYI(1, ("In FindNext2"));
2556
2557        if(psrch_inf->endOfSearch == TRUE)
2558                return -ENOENT;
2559
2560        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2561                (void **) &pSMBr);
2562        if (rc)
2563                return rc;
2564
2565        params = 14;    /* includes 2 bytes of null string, converted to LE below */
2566        byte_count = 0;
2567        pSMB->TotalDataCount = 0;       /* no EAs */
2568        pSMB->MaxParameterCount = cpu_to_le16(8);
2569        pSMB->MaxDataCount =
2570            cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2571        pSMB->MaxSetupCount = 0;
2572        pSMB->Reserved = 0;
2573        pSMB->Flags = 0;
2574        pSMB->Timeout = 0;
2575        pSMB->Reserved2 = 0;
2576        pSMB->ParameterOffset =  cpu_to_le16(
2577              offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2578        pSMB->DataCount = 0;
2579        pSMB->DataOffset = 0;
2580        pSMB->SetupCount = 1;
2581        pSMB->Reserved3 = 0;
2582        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2583        pSMB->SearchHandle = searchHandle;      /* always kept as le */
2584        pSMB->SearchCount =
2585                cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2586        /* test for Unix extensions */
2587/*      if (tcon->ses->capabilities & CAP_UNIX) {
2588                pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2589                psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2590        } else {
2591                pSMB->InformationLevel =
2592                   cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2593                psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2594        } */
2595        pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2596        pSMB->ResumeKey = psrch_inf->resume_key;
2597        pSMB->SearchFlags =
2598              cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2599
2600        name_len = psrch_inf->resume_name_len;
2601        params += name_len;
2602        if(name_len < PATH_MAX) {
2603                memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2604                byte_count += name_len;
2605        } else {
2606                rc = -EINVAL;
2607                goto FNext2_err_exit;
2608        }
2609        byte_count = params + 1 /* pad */ ;
2610        pSMB->TotalParameterCount = cpu_to_le16(params);
2611        pSMB->ParameterCount = pSMB->TotalParameterCount;
2612        pSMB->hdr.smb_buf_length += byte_count;
2613        pSMB->ByteCount = cpu_to_le16(byte_count);
2614                                                                                              
2615        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2616                        (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2617                                                                                              
2618        if (rc) {
2619                if (rc == -EBADF) {
2620                        psrch_inf->endOfSearch = TRUE;
2621                        rc = 0; /* search probably was closed at end of search above */
2622                } else
2623                        cFYI(1, ("FindNext returned = %d", rc));
2624        } else {                /* decode response */
2625                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2626                
2627                if(rc == 0) {
2628                        /* BB fixme add lock for file (srch_info) struct here */
2629                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2630                                psrch_inf->unicode = TRUE;
2631                        else
2632                                psrch_inf->unicode = FALSE;
2633                        response_data = (char *) &pSMBr->hdr.Protocol +
2634                               le16_to_cpu(pSMBr->t2.ParameterOffset);
2635                        parms = (T2_FNEXT_RSP_PARMS *)response_data;
2636                        response_data = (char *)&pSMBr->hdr.Protocol +
2637                                le16_to_cpu(pSMBr->t2.DataOffset);
2638                        cifs_buf_release(psrch_inf->ntwrk_buf_start);
2639                        psrch_inf->srch_entries_start = response_data;
2640                        psrch_inf->ntwrk_buf_start = (char *)pSMB;
2641                        if(parms->EndofSearch)
2642                                psrch_inf->endOfSearch = TRUE;
2643                        else
2644                                psrch_inf->endOfSearch = FALSE;
2645                                                                                              
2646                        psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2647                        psrch_inf->index_of_last_entry +=
2648                                psrch_inf->entries_in_buffer;
2649/*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2650
2651                        /* BB fixme add unlock here */
2652                }
2653
2654        }
2655
2656        /* BB On error, should we leave previous search buf (and count and
2657        last entry fields) intact or free the previous one? */
2658
2659        /* Note: On -EAGAIN error only caller can retry on handle based calls
2660        since file handle passed in no longer valid */
2661FNext2_err_exit:
2662        if ((rc != 0) && pSMB)
2663                cifs_buf_release(pSMB);
2664                                                                                              
2665        return rc;
2666}
2667
2668int
2669CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2670                FILE_DIRECTORY_INFO * findData, T2_FNEXT_RSP_PARMS * findParms,
2671                const __u16 searchHandle, char * resume_file_name, int name_len,
2672                __u32 resume_key, int *pUnicodeFlag, int *pUnixFlag)
2673{
2674/* level 257 SMB_ */
2675        TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2676        TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2677        char *response_data;
2678        int rc = 0;
2679        int bytes_returned;
2680        __u16 params, byte_count;
2681
2682        cFYI(1, ("In FindNext"));
2683
2684        if(resume_file_name == NULL) {
2685                return -EIO;
2686        }
2687        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2688                      (void **) &pSMBr);
2689        if (rc)
2690                return rc;
2691
2692        params = 14;    /* includes 2 bytes of null string, converted to LE below */
2693        byte_count = 0;
2694        pSMB->TotalDataCount = 0;       /* no EAs */
2695        pSMB->MaxParameterCount = cpu_to_le16(8);
2696        pSMB->MaxDataCount =
2697            cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2698        pSMB->MaxSetupCount = 0;
2699        pSMB->Reserved = 0;
2700        pSMB->Flags = 0;
2701        pSMB->Timeout = 0;
2702        pSMB->Reserved2 = 0;
2703        pSMB->ParameterOffset =  cpu_to_le16(
2704           offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2705        pSMB->DataCount = 0;
2706        pSMB->DataOffset = 0;
2707        pSMB->SetupCount = 1;
2708        pSMB->Reserved3 = 0;
2709        pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2710        pSMB->SearchHandle = searchHandle;      /* always kept as le */
2711        findParms->SearchCount = 0;     /* set to zero in case of error */
2712        pSMB->SearchCount =
2713            cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2714        /* test for Unix extensions */
2715        if (tcon->ses->capabilities & CAP_UNIX) {
2716                pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2717                *pUnixFlag = TRUE;
2718        } else {
2719                pSMB->InformationLevel =
2720                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2721                *pUnixFlag = FALSE;
2722        }
2723        pSMB->ResumeKey = resume_key;
2724        pSMB->SearchFlags =
2725            cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2726        /* BB add check to make sure we do not cross end of smb */
2727        if(name_len < PATH_MAX) {
2728                memcpy(pSMB->ResumeFileName, resume_file_name, name_len);
2729                byte_count += name_len;
2730        }
2731        params += name_len;
2732        byte_count = params + 1 /* pad */ ;
2733        pSMB->TotalParameterCount = cpu_to_le16(params);
2734        pSMB->ParameterCount = pSMB->TotalParameterCount;
2735        /* BB improve error handling here */
2736        pSMB->hdr.smb_buf_length += byte_count;
2737        pSMB->ByteCount = cpu_to_le16(byte_count);
2738
2739        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2740                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2741
2742        if (rc) {
2743                if (rc == -EBADF)
2744                        rc = 0; /* search probably was closed at end of search above */
2745                else
2746                        cFYI(1, ("FindNext returned = %d", rc));
2747        } else {                /* decode response */
2748                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2749
2750                /* BB add safety checks for these memcpys */
2751                if(rc == 0) {
2752                        if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2753                                *pUnicodeFlag = TRUE;
2754                        else
2755                                *pUnicodeFlag = FALSE;
2756                        memcpy(findParms,
2757                               (char *) &pSMBr->hdr.Protocol +
2758                               le16_to_cpu(pSMBr->t2.ParameterOffset),
2759                               sizeof (T2_FNEXT_RSP_PARMS));
2760                        response_data =
2761                            (char *) &pSMBr->hdr.Protocol +
2762                            le16_to_cpu(pSMBr->t2.DataOffset);
2763                        memcpy(findData,response_data,le16_to_cpu(pSMBr->t2.DataCount));
2764                }
2765        }
2766        if (pSMB)
2767                cifs_buf_release(pSMB);
2768
2769        /* Note: On -EAGAIN error only caller can retry on handle based calls
2770                since file handle passed in no longer valid */
2771
2772        return rc;
2773}
2774
2775int
2776CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2777{
2778        int rc = 0;
2779        FINDCLOSE_REQ *pSMB = NULL;
2780        CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2781        int bytes_returned;
2782
2783        cFYI(1, ("In CIFSSMBFindClose"));
2784        rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2785        pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2786        /* no sense returning error if session restarted
2787                file handle has been closed */
2788        if(rc == -EAGAIN)
2789                return 0;
2790        if (rc)
2791                return rc;
2792
2793        pSMB->FileID = searchHandle;
2794        pSMB->ByteCount = 0;
2795        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2796                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2797        if (rc) {
2798                cERROR(1, ("Send error in FindClose = %d", rc));
2799        }
2800        if (pSMB)
2801                cifs_small_buf_release(pSMB);
2802
2803        /* Since session is dead, search handle closed on server already */
2804        if (rc == -EAGAIN)
2805                rc = 0;
2806
2807        return rc;
2808}
2809
2810#ifdef CONFIG_CIFS_EXPERIMENTAL
2811int
2812CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2813                const unsigned char *searchName,
2814                __u64 * inode_number,
2815                const struct nls_table *nls_codepage)
2816{
2817        int rc = 0;
2818        TRANSACTION2_QPI_REQ *pSMB = NULL;
2819        TRANSACTION2_QPI_RSP *pSMBr = NULL;
2820
2821        cFYI(1,("In GetSrvInodeNumber for %s",searchName));
2822        if(tcon == NULL)
2823                return -ENODEV; 
2824
2825        cFYI(1, ("In QPathInfo path %s", searchName));
2826GetInodeNumberRetry:
2827        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2828                      (void **) &pSMBr);
2829        if (rc)
2830                return rc;
2831
2832/* BB add missing code here */
2833
2834        if (pSMB)
2835                cifs_buf_release(pSMB);
2836                                                                                                                         
2837        if (rc == -EAGAIN)
2838                goto GetInodeNumberRetry;
2839        return rc;
2840}
2841#endif /* CIFS_EXPERIMENTAL */
2842
2843int
2844CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
2845                const unsigned char *searchName,
2846                unsigned char **targetUNCs,
2847                unsigned int *number_of_UNC_in_array,
2848                const struct nls_table *nls_codepage)
2849{
2850/* TRANS2_GET_DFS_REFERRAL */
2851        TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
2852        TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
2853        struct dfs_referral_level_3 * referrals = NULL;
2854        int rc = 0;
2855        int bytes_returned;
2856        int name_len;
2857        unsigned int i;
2858        char * temp;
2859        __u16 params, byte_count;
2860        *number_of_UNC_in_array = 0;
2861        *targetUNCs = NULL;
2862
2863        cFYI(1, ("In GetDFSRefer the path %s", searchName));
2864        if (ses == NULL)
2865                return -ENODEV;
2866getDFSRetry:
2867        rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
2868                      (void **) &pSMBr);
2869        if (rc)
2870                return rc;
2871
2872        pSMB->hdr.Tid = ses->ipc_tid;
2873        pSMB->hdr.Uid = ses->Suid;
2874        if (ses->capabilities & CAP_STATUS32) {
2875                pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
2876        }
2877        if (ses->capabilities & CAP_DFS) {
2878                pSMB->hdr.Flags2 |= SMBFLG2_DFS;
2879        }
2880
2881        if (ses->capabilities & CAP_UNICODE) {
2882                pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
2883                name_len =
2884                    cifs_strtoUCS((wchar_t *) pSMB->RequestFileName,
2885                                  searchName, PATH_MAX
2886                                  /* find define for this maxpathcomponent */
2887                                  , nls_codepage);
2888                name_len++;     /* trailing null */
2889                name_len *= 2;
2890        } else {                /* BB improve the check for buffer overruns BB */
2891                name_len = strnlen(searchName, PATH_MAX);
2892                name_len++;     /* trailing null */
2893                strncpy(pSMB->RequestFileName, searchName, name_len);
2894        }
2895
2896        params = 2 /* level */  + name_len /*includes null */ ;
2897        pSMB->TotalDataCount = 0;
2898        pSMB->DataCount = 0;
2899        pSMB->DataOffset = 0;
2900        pSMB->MaxParameterCount = 0;
2901        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2902        pSMB->MaxSetupCount = 0;
2903        pSMB->Reserved = 0;
2904        pSMB->Flags = 0;
2905        pSMB->Timeout = 0;
2906        pSMB->Reserved2 = 0;
2907        pSMB->ParameterOffset = cpu_to_le16(offsetof(
2908        struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
2909        pSMB->SetupCount = 1;
2910        pSMB->Reserved3 = 0;
2911        pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
2912        byte_count = params + 3 /* pad */ ;
2913        pSMB->ParameterCount = cpu_to_le16(params);
2914        pSMB->TotalParameterCount = pSMB->ParameterCount;
2915        pSMB->MaxReferralLevel = cpu_to_le16(3);
2916        pSMB->hdr.smb_buf_length += byte_count;
2917        pSMB->ByteCount = cpu_to_le16(byte_count);
2918
2919        rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
2920                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2921        if (rc) {
2922                cFYI(1, ("Send error in GetDFSRefer = %d", rc));
2923        } else {                /* decode response */
2924/* BB Add logic to parse referrals here */
2925                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2926
2927                if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
2928                        rc = -EIO;      /* bad smb */
2929                else {
2930                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
2931                        __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
2932
2933                        cFYI(1,
2934                             ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
2935                              pSMBr->ByteCount, data_offset));
2936                        referrals = 
2937                            (struct dfs_referral_level_3 *) 
2938                                        (8 /* sizeof start of data block */ +
2939                                        data_offset +
2940                                        (char *) &pSMBr->hdr.Protocol); 
2941                        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",
2942                                le16_to_cpu(pSMBr->NumberOfReferrals),le16_to_cpu(pSMBr->DFSFlags), le16_to_cpu(referrals->ReferralSize),le16_to_cpu(referrals->ServerType),le16_to_cpu(referrals->ReferralFlags),le16_to_cpu(referrals->TimeToLive)));
2943                        /* BB This field is actually two bytes in from start of
2944                           data block so we could do safety check that DataBlock
2945                           begins at address of pSMBr->NumberOfReferrals */
2946                        *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
2947
2948                        /* BB Fix below so can return more than one referral */
2949                        if(*number_of_UNC_in_array > 1)
2950                                *number_of_UNC_in_array = 1;
2951
2952                        /* get the length of the strings describing refs */
2953                        name_len = 0;
2954                        for(i=0;i<*number_of_UNC_in_array;i++) {
2955                                /* make sure that DfsPathOffset not past end */
2956                                __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
2957                                if (offset > data_count) {
2958                                        /* if invalid referral, stop here and do 
2959                                        not try to copy any more */
2960                                        *number_of_UNC_in_array = i;
2961                                        break;
2962                                } 
2963                                temp = ((char *)referrals) + offset;
2964
2965                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2966                                        name_len += UniStrnlen((wchar_t *)temp,data_count);
2967                                } else {
2968                                        name_len += strnlen(temp,data_count);
2969                                }
2970                                referrals++;
2971                                /* BB add check that referral pointer does not fall off end PDU */
2972                                
2973                        }
2974                        /* BB add check for name_len bigger than bcc */
2975                        *targetUNCs = 
2976                                kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
2977                        if(*targetUNCs == NULL) {
2978                                rc = -ENOMEM;
2979                                goto GetDFSRefExit;
2980                        }
2981                        /* copy the ref strings */
2982                        referrals =  
2983                            (struct dfs_referral_level_3 *) 
2984                                        (8 /* sizeof data hdr */ +
2985                                        data_offset + 
2986                                        (char *) &pSMBr->hdr.Protocol);
2987
2988                        for(i=0;i<*number_of_UNC_in_array;i++) {
2989                                temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
2990                                if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
2991                                        cifs_strfromUCS_le(*targetUNCs,
2992                                                (wchar_t *) temp, name_len, nls_codepage);
2993                                } else {
2994                                        strncpy(*targetUNCs,temp,name_len);
2995                                }
2996                                /*  BB update target_uncs pointers */
2997                                referrals++;
2998                        }
2999                        temp = *targetUNCs;
3000                        temp[name_len] = 0;
3001                }
3002
3003        }
3004GetDFSRefExit:
3005        if (pSMB)
3006                cifs_buf_release(pSMB);
3007
3008        if (rc == -EAGAIN)
3009                goto getDFSRetry;
3010
3011        return rc;
3012}
3013
3014int
3015CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
3016               struct kstatfs *FSData, const struct nls_table *nls_codepage)
3017{
3018/* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3019        TRANSACTION2_QFSI_REQ *pSMB = NULL;
3020        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3021        FILE_SYSTEM_INFO *response_data;
3022        int rc = 0;
3023        int bytes_returned = 0;
3024        __u16 params, byte_count;
3025
3026        cFYI(1, ("In QFSInfo"));
3027QFSInfoRetry:
3028        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3029                      (void **) &pSMBr);
3030        if (rc)
3031                return rc;
3032
3033        params = 2;     /* level */
3034        pSMB->TotalDataCount = 0;
3035        pSMB->MaxParameterCount = cpu_to_le16(2);
3036        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3037        pSMB->MaxSetupCount = 0;
3038        pSMB->Reserved = 0;
3039        pSMB->Flags = 0;
3040        pSMB->Timeout = 0;
3041        pSMB->Reserved2 = 0;
3042        byte_count = params + 1 /* pad */ ;
3043        pSMB->TotalParameterCount = cpu_to_le16(params);
3044        pSMB->ParameterCount = pSMB->TotalParameterCount;
3045        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3046        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3047        pSMB->DataCount = 0;
3048        pSMB->DataOffset = 0;
3049        pSMB->SetupCount = 1;
3050        pSMB->Reserved3 = 0;
3051        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3052        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3053        pSMB->hdr.smb_buf_length += byte_count;
3054        pSMB->ByteCount = cpu_to_le16(byte_count);
3055
3056        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3057                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3058        if (rc) {
3059                cERROR(1, ("Send error in QFSInfo = %d", rc));
3060        } else {                /* decode response */
3061                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3062
3063                if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3064                        rc = -EIO;      /* bad smb */
3065                else {
3066                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3067                        cFYI(1,
3068                                ("Decoding qfsinfo response.  BCC: %d  Offset %d",
3069                                pSMBr->ByteCount, data_offset));
3070
3071                        response_data =
3072                            (FILE_SYSTEM_INFO
3073                             *) (((char *) &pSMBr->hdr.Protocol) +
3074                                 data_offset);
3075                        FSData->f_bsize =
3076                            le32_to_cpu(response_data->BytesPerSector) *
3077                            le32_to_cpu(response_data->
3078                                        SectorsPerAllocationUnit);
3079                        FSData->f_blocks =
3080                            le64_to_cpu(response_data->TotalAllocationUnits);
3081                        FSData->f_bfree = FSData->f_bavail =
3082                            le64_to_cpu(response_data->FreeAllocationUnits);
3083                        cFYI(1,
3084                             ("Blocks: %lld  Free: %lld Block size %ld",
3085                              (unsigned long long)FSData->f_blocks,
3086                              (unsigned long long)FSData->f_bfree,
3087                              FSData->f_bsize));
3088                }
3089        }
3090        if (pSMB)
3091                cifs_buf_release(pSMB);
3092
3093        if (rc == -EAGAIN)
3094                goto QFSInfoRetry;
3095
3096        return rc;
3097}
3098
3099int
3100CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon,
3101                        const struct nls_table *nls_codepage)
3102{
3103/* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3104        TRANSACTION2_QFSI_REQ *pSMB = NULL;
3105        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3106        FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3107        int rc = 0;
3108        int bytes_returned = 0;
3109        __u16 params, byte_count;
3110
3111        cFYI(1, ("In QFSAttributeInfo"));
3112QFSAttributeRetry:
3113        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3114                      (void **) &pSMBr);
3115        if (rc)
3116                return rc;
3117
3118        params = 2;     /* level */
3119        pSMB->TotalDataCount = 0;
3120        pSMB->MaxParameterCount = cpu_to_le16(2);
3121        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3122        pSMB->MaxSetupCount = 0;
3123        pSMB->Reserved = 0;
3124        pSMB->Flags = 0;
3125        pSMB->Timeout = 0;
3126        pSMB->Reserved2 = 0;
3127        byte_count = params + 1 /* pad */ ;
3128        pSMB->TotalParameterCount = cpu_to_le16(params);
3129        pSMB->ParameterCount = pSMB->TotalParameterCount;
3130        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3131        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3132        pSMB->DataCount = 0;
3133        pSMB->DataOffset = 0;
3134        pSMB->SetupCount = 1;
3135        pSMB->Reserved3 = 0;
3136        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3137        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3138        pSMB->hdr.smb_buf_length += byte_count;
3139        pSMB->ByteCount = cpu_to_le16(byte_count);
3140
3141        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3142                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3143        if (rc) {
3144                cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3145        } else {                /* decode response */
3146                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3147
3148                if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3149                        rc = -EIO;      /* bad smb */
3150                } else {
3151                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3152                        response_data =
3153                            (FILE_SYSTEM_ATTRIBUTE_INFO
3154                             *) (((char *) &pSMBr->hdr.Protocol) +
3155                                 data_offset);
3156                        memcpy(&tcon->fsAttrInfo, response_data,
3157                               sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3158                }
3159        }
3160        if (pSMB)
3161                cifs_buf_release(pSMB);
3162
3163        if (rc == -EAGAIN)
3164                goto QFSAttributeRetry;
3165
3166        return rc;
3167}
3168
3169int
3170CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon,
3171                     const struct nls_table *nls_codepage)
3172{
3173/* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3174        TRANSACTION2_QFSI_REQ *pSMB = NULL;
3175        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3176        FILE_SYSTEM_DEVICE_INFO *response_data;
3177        int rc = 0;
3178        int bytes_returned = 0;
3179        __u16 params, byte_count;
3180
3181        cFYI(1, ("In QFSDeviceInfo"));
3182QFSDeviceRetry:
3183        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3184                      (void **) &pSMBr);
3185        if (rc)
3186                return rc;
3187
3188        params = 2;     /* level */
3189        pSMB->TotalDataCount = 0;
3190        pSMB->MaxParameterCount = cpu_to_le16(2);
3191        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3192        pSMB->MaxSetupCount = 0;
3193        pSMB->Reserved = 0;
3194        pSMB->Flags = 0;
3195        pSMB->Timeout = 0;
3196        pSMB->Reserved2 = 0;
3197        byte_count = params + 1 /* pad */ ;
3198        pSMB->TotalParameterCount = cpu_to_le16(params);
3199        pSMB->ParameterCount = pSMB->TotalParameterCount;
3200        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3201        struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3202
3203        pSMB->DataCount = 0;
3204        pSMB->DataOffset = 0;
3205        pSMB->SetupCount = 1;
3206        pSMB->Reserved3 = 0;
3207        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3208        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3209        pSMB->hdr.smb_buf_length += byte_count;
3210        pSMB->ByteCount = cpu_to_le16(byte_count);
3211
3212        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3213                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3214        if (rc) {
3215                cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3216        } else {                /* decode response */
3217                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3218
3219                if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3220                        rc = -EIO;      /* bad smb */
3221                else {
3222                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3223                        response_data =
3224                            (FILE_SYSTEM_DEVICE_INFO
3225                             *) (((char *) &pSMBr->hdr.Protocol) +
3226                                 data_offset);
3227                        memcpy(&tcon->fsDevInfo, response_data,
3228                               sizeof (FILE_SYSTEM_DEVICE_INFO));
3229                }
3230        }
3231        if (pSMB)
3232                cifs_buf_release(pSMB);
3233
3234        if (rc == -EAGAIN)
3235                goto QFSDeviceRetry;
3236
3237        return rc;
3238}
3239
3240int
3241CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon,
3242                   const struct nls_table *nls_codepage)
3243{
3244/* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3245        TRANSACTION2_QFSI_REQ *pSMB = NULL;
3246        TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3247        FILE_SYSTEM_UNIX_INFO *response_data;
3248        int rc = 0;
3249        int bytes_returned = 0;
3250        __u16 params, byte_count;
3251
3252        cFYI(1, ("In QFSUnixInfo"));
3253QFSUnixRetry:
3254        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3255                      (void **) &pSMBr);
3256        if (rc)
3257                return rc;
3258
3259        params = 2;     /* level */
3260        pSMB->TotalDataCount = 0;
3261        pSMB->DataCount = 0;
3262        pSMB->DataOffset = 0;
3263        pSMB->MaxParameterCount = cpu_to_le16(2);
3264        pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3265        pSMB->MaxSetupCount = 0;
3266        pSMB->Reserved = 0;
3267        pSMB->Flags = 0;
3268        pSMB->Timeout = 0;
3269        pSMB->Reserved2 = 0;
3270        byte_count = params + 1 /* pad */ ;
3271        pSMB->ParameterCount = cpu_to_le16(params);
3272        pSMB->TotalParameterCount = pSMB->ParameterCount;
3273        pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3274        smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3275        pSMB->SetupCount = 1;
3276        pSMB->Reserved3 = 0;
3277        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3278        pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3279        pSMB->hdr.smb_buf_length += byte_count;
3280        pSMB->ByteCount = cpu_to_le16(byte_count);
3281
3282        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3283                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3284        if (rc) {
3285                cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3286        } else {                /* decode response */
3287                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3288
3289                if (rc || (pSMBr->ByteCount < 13)) {
3290                        rc = -EIO;      /* bad smb */
3291                } else {
3292                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3293                        response_data =
3294                            (FILE_SYSTEM_UNIX_INFO
3295                             *) (((char *) &pSMBr->hdr.Protocol) +
3296                                 data_offset);
3297                        memcpy(&tcon->fsUnixInfo, response_data,
3298                               sizeof (FILE_SYSTEM_UNIX_INFO));
3299                }
3300        }
3301        if (pSMB)
3302                cifs_buf_release(pSMB);
3303
3304        if (rc == -EAGAIN)
3305                goto QFSUnixRetry;
3306
3307
3308        return rc;
3309}
3310
3311/* We can not use write of zero bytes trick to 
3312   set file size due to need for large file support.  Also note that 
3313   this SetPathInfo is preferred to SetFileInfo based method in next 
3314   routine which is only needed to work around a sharing violation bug
3315   in Samba which this routine can run into */
3316
3317int
3318CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3319              __u64 size, int SetAllocation, const struct nls_table *nls_codepage)
3320{
3321        struct smb_com_transaction2_spi_req *pSMB = NULL;
3322        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3323        struct file_end_of_file_info *parm_data;
3324        int name_len;
3325        int rc = 0;
3326        int bytes_returned = 0;
3327        __u16 params, byte_count, data_count, param_offset, offset;
3328
3329        cFYI(1, ("In SetEOF"));
3330SetEOFRetry:
3331        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3332                      (void **) &pSMBr);
3333        if (rc)
3334                return rc;
3335
3336        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3337                name_len =
3338                    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3339                                  /* find define for this maxpathcomponent */
3340                                  , nls_codepage);
3341                name_len++;     /* trailing null */
3342                name_len *= 2;
3343        } else {                /* BB improve the check for buffer overruns BB */
3344                name_len = strnlen(fileName, PATH_MAX);
3345                name_len++;     /* trailing null */
3346                strncpy(pSMB->FileName, fileName, name_len);
3347        }
3348        params = 6 + name_len;
3349        data_count = sizeof (struct file_end_of_file_info);
3350        pSMB->MaxParameterCount = cpu_to_le16(2);
3351        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3352        pSMB->MaxSetupCount = 0;
3353        pSMB->Reserved = 0;
3354        pSMB->Flags = 0;
3355        pSMB->Timeout = 0;
3356        pSMB->Reserved2 = 0;
3357        param_offset = offsetof(struct smb_com_transaction2_spi_req,
3358                                     InformationLevel) - 4;
3359        offset = param_offset + params;
3360        if(SetAllocation) {
3361                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3362                    pSMB->InformationLevel =
3363                        cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3364                else
3365                    pSMB->InformationLevel =
3366                        cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3367        } else /* Set File Size */  {    
3368            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3369                    pSMB->InformationLevel =
3370                        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3371            else
3372                    pSMB->InformationLevel =
3373                        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3374        }
3375
3376        parm_data =
3377            (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3378                                       offset);
3379        pSMB->ParameterOffset = cpu_to_le16(param_offset);
3380        pSMB->DataOffset = cpu_to_le16(offset);
3381        pSMB->SetupCount = 1;
3382        pSMB->Reserved3 = 0;
3383        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3384        byte_count = 3 /* pad */  + params + data_count;
3385        pSMB->DataCount = cpu_to_le16(data_count);
3386        pSMB->TotalDataCount = pSMB->DataCount;
3387        pSMB->ParameterCount = cpu_to_le16(params);
3388        pSMB->TotalParameterCount = pSMB->ParameterCount;
3389        pSMB->Reserved4 = 0;
3390        pSMB->hdr.smb_buf_length += byte_count;
3391        parm_data->FileSize = cpu_to_le64(size);
3392        pSMB->ByteCount = cpu_to_le16(byte_count);
3393        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3394                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3395        if (rc) {
3396                cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3397        }
3398
3399        if (pSMB)
3400                cifs_buf_release(pSMB);
3401
3402        if (rc == -EAGAIN)
3403                goto SetEOFRetry;
3404
3405        return rc;
3406}
3407
3408int
3409CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3410                   __u16 fid, __u32 pid_of_opener, int SetAllocation)
3411{
3412        struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3413        struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3414        char *data_offset;
3415        struct file_end_of_file_info *parm_data;
3416        int rc = 0;
3417        int bytes_returned = 0;
3418        __u16 params, param_offset, offset, byte_count, count;
3419
3420        cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3421                        (long long)size));
3422        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3423                      (void **) &pSMBr);
3424        if (rc)
3425                return rc;
3426
3427        pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3428        pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3429    
3430        params = 6;
3431        pSMB->MaxSetupCount = 0;
3432        pSMB->Reserved = 0;
3433        pSMB->Flags = 0;
3434        pSMB->Timeout = 0;
3435        pSMB->Reserved2 = 0;
3436        param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3437        offset = param_offset + params;
3438
3439        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3440
3441        count = sizeof(struct file_end_of_file_info);
3442        pSMB->MaxParameterCount = cpu_to_le16(2);
3443        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3444        pSMB->SetupCount = 1;
3445        pSMB->Reserved3 = 0;
3446        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3447        byte_count = 3 /* pad */  + params + count;
3448        pSMB->DataCount = cpu_to_le16(count);
3449        pSMB->ParameterCount = cpu_to_le16(params);
3450        pSMB->TotalDataCount = pSMB->DataCount;
3451        pSMB->TotalParameterCount = pSMB->ParameterCount;
3452        pSMB->ParameterOffset = cpu_to_le16(param_offset);
3453        parm_data =
3454                (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3455                        offset);
3456        pSMB->DataOffset = cpu_to_le16(offset);
3457        parm_data->FileSize = cpu_to_le64(size);
3458        pSMB->Fid = fid;
3459        if(SetAllocation) {
3460                if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3461                        pSMB->InformationLevel =
3462                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3463                else
3464                        pSMB->InformationLevel =
3465                                cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3466        } else /* Set File Size */  {    
3467            if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3468                    pSMB->InformationLevel =
3469                        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3470            else
3471                    pSMB->InformationLevel =
3472                        cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3473        }
3474        pSMB->Reserved4 = 0;
3475        pSMB->hdr.smb_buf_length += byte_count;
3476        pSMB->ByteCount = cpu_to_le16(byte_count);
3477        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3478                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3479        if (rc) {
3480                cFYI(1,
3481                     ("Send error in SetFileInfo (SetFileSize) = %d",
3482                      rc));
3483        }
3484
3485        if (pSMB)
3486                cifs_buf_release(pSMB);
3487
3488        /* Note: On -EAGAIN error only caller can retry on handle based calls 
3489                since file handle passed in no longer valid */
3490
3491        return rc;
3492}
3493
3494int
3495CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3496                const FILE_BASIC_INFO * data, 
3497                const struct nls_table *nls_codepage)
3498{
3499        TRANSACTION2_SPI_REQ *pSMB = NULL;
3500        TRANSACTION2_SPI_RSP *pSMBr = NULL;
3501        int name_len;
3502        int rc = 0;
3503        int bytes_returned = 0;
3504        char *data_offset;
3505        __u16 params, param_offset, offset, byte_count, count;
3506
3507        cFYI(1, ("In SetTimes"));
3508
3509SetTimesRetry:
3510        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3511                      (void **) &pSMBr);
3512        if (rc)
3513                return rc;
3514
3515        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3516                name_len =
3517                    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3518                                  /* find define for this maxpathcomponent */
3519                                  , nls_codepage);
3520                name_len++;     /* trailing null */
3521                name_len *= 2;
3522        } else {                /* BB improve the check for buffer overruns BB */
3523                name_len = strnlen(fileName, PATH_MAX);
3524                name_len++;     /* trailing null */
3525                strncpy(pSMB->FileName, fileName, name_len);
3526        }
3527
3528        params = 6 + name_len;
3529        count = sizeof (FILE_BASIC_INFO);
3530        pSMB->MaxParameterCount = cpu_to_le16(2);
3531        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3532        pSMB->MaxSetupCount = 0;
3533        pSMB->Reserved = 0;
3534        pSMB->Flags = 0;
3535        pSMB->Timeout = 0;
3536        pSMB->Reserved2 = 0;
3537        param_offset = offsetof(struct smb_com_transaction2_spi_req,
3538                                     InformationLevel) - 4;
3539        offset = param_offset + params;
3540        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3541        pSMB->ParameterOffset = cpu_to_le16(param_offset);
3542        pSMB->DataOffset = cpu_to_le16(offset);
3543        pSMB->SetupCount = 1;
3544        pSMB->Reserved3 = 0;
3545        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3546        byte_count = 3 /* pad */  + params + count;
3547
3548        pSMB->DataCount = cpu_to_le16(count);
3549        pSMB->ParameterCount = cpu_to_le16(params);
3550        pSMB->TotalDataCount = pSMB->DataCount;
3551        pSMB->TotalParameterCount = pSMB->ParameterCount;
3552        if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3553                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3554        else
3555                pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3556        pSMB->Reserved4 = 0;
3557        pSMB->hdr.smb_buf_length += byte_count;
3558        memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3559        pSMB->ByteCount = cpu_to_le16(byte_count);
3560        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3561                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3562        if (rc) {
3563                cFYI(1, ("SetPathInfo (times) returned %d", rc));
3564        }
3565
3566        if (pSMB)
3567                cifs_buf_release(pSMB);
3568
3569        if (rc == -EAGAIN)
3570                goto SetTimesRetry;
3571
3572        return rc;
3573}
3574
3575int
3576CIFSSMBSetTimesLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
3577                FILE_INFO_STANDARD * data, const struct nls_table *nls_codepage)
3578{
3579        TRANSACTION2_SPI_REQ *pSMB = NULL;
3580        TRANSACTION2_SPI_RSP *pSMBr = NULL;
3581        int name_len;
3582        int rc = 0;
3583        int bytes_returned = 0;
3584        char *data_offset;
3585        __u16 params, param_offset, count, offset, byte_count;
3586
3587        cFYI(1, ("In SetTimesLegacy"));
3588
3589SetTimesRetryLegacy:
3590        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3591                      (void **) &pSMBr);
3592        if (rc)
3593                return rc;
3594
3595        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3596                name_len =
3597                    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3598                                  /* find define for this maxpathcomponent */
3599                                  , nls_codepage);
3600                name_len++;     /* trailing null */
3601                name_len *= 2;
3602        } else {                /* BB improve the check for buffer overruns BB */
3603                name_len = strnlen(fileName, PATH_MAX);
3604                name_len++;     /* trailing null */
3605                strncpy(pSMB->FileName, fileName, name_len);
3606        }
3607/* BB fixme - we have to map to FILE_STANDARD_INFO (level 1 info
3608        in parent function, from the better and ususal FILE_BASIC_INFO */
3609        params = 6 + name_len;
3610        count = sizeof (FILE_INFO_STANDARD);
3611        pSMB->MaxParameterCount = cpu_to_le16(2);
3612        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3613        pSMB->MaxSetupCount = 0;
3614        pSMB->Reserved = 0;
3615        pSMB->Flags = 0;
3616        pSMB->Timeout = 0;
3617        pSMB->Reserved2 = 0;
3618        param_offset = offsetof(struct smb_com_transaction2_spi_req,
3619                                     InformationLevel) - 4;
3620        offset = param_offset + params;
3621        data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3622        pSMB->ParameterOffset = cpu_to_le16(param_offset);
3623        pSMB->DataOffset = cpu_to_le16(offset);
3624        pSMB->SetupCount = 1;
3625        pSMB->Reserved3 = 0;
3626        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3627        byte_count = 3 /* pad */  + params + count;
3628
3629        pSMB->DataCount = cpu_to_le16(count);
3630        pSMB->ParameterCount = cpu_to_le16(params);
3631        pSMB->TotalDataCount = pSMB->DataCount;
3632        pSMB->TotalParameterCount = pSMB->ParameterCount;
3633        pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
3634        pSMB->Reserved4 = 0;
3635        pSMB->hdr.smb_buf_length += byte_count;
3636        memcpy(data_offset, data, sizeof (FILE_INFO_STANDARD));
3637        pSMB->ByteCount = cpu_to_le16(byte_count);
3638        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3639                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3640        if (rc) {
3641                cFYI(1, ("SetPathInfo (times legacy) returned %d", rc));
3642        }
3643
3644        if (pSMB)
3645                cifs_buf_release(pSMB);
3646
3647        if (rc == -EAGAIN)
3648                goto SetTimesRetryLegacy;
3649
3650        return rc;
3651}
3652
3653int
3654CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
3655                    char *fileName, __u64 mode, __u64 uid, __u64 gid,
3656                    dev_t device, const struct nls_table *nls_codepage)
3657{
3658        TRANSACTION2_SPI_REQ *pSMB = NULL;
3659        TRANSACTION2_SPI_RSP *pSMBr = NULL;
3660        int name_len;
3661        int rc = 0;
3662        int bytes_returned = 0;
3663        FILE_UNIX_BASIC_INFO *data_offset;
3664        __u16 params, param_offset, offset, count, byte_count;
3665
3666        cFYI(1, ("In SetUID/GID/Mode"));
3667setPermsRetry:
3668        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3669                      (void **) &pSMBr);
3670        if (rc)
3671                return rc;
3672
3673        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3674                name_len =
3675                    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
3676                                  /* find define for this maxpathcomponent */
3677                                  , nls_codepage);
3678                name_len++;     /* trailing null */
3679                name_len *= 2;
3680        } else {                /* BB improve the check for buffer overruns BB */
3681                name_len = strnlen(fileName, PATH_MAX);
3682                name_len++;     /* trailing null */
3683                strncpy(pSMB->FileName, fileName, name_len);
3684        }
3685
3686        params = 6 + name_len;
3687        count = sizeof (FILE_UNIX_BASIC_INFO);
3688        pSMB->MaxParameterCount = cpu_to_le16(2);
3689        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3690        pSMB->MaxSetupCount = 0;
3691        pSMB->Reserved = 0;
3692        pSMB->Flags = 0;
3693        pSMB->Timeout = 0;
3694        pSMB->Reserved2 = 0;
3695        param_offset = offsetof(struct smb_com_transaction2_spi_req,
3696                                     InformationLevel) - 4;
3697        offset = param_offset + params;
3698        data_offset =
3699            (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
3700                                      offset);
3701        memset(data_offset, 0, count);
3702        pSMB->DataOffset = cpu_to_le16(offset);
3703        pSMB->ParameterOffset = cpu_to_le16(param_offset);
3704        pSMB->SetupCount = 1;
3705        pSMB->Reserved3 = 0;
3706        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3707        byte_count = 3 /* pad */  + params + count;
3708        pSMB->ParameterCount = cpu_to_le16(params);
3709        pSMB->DataCount = cpu_to_le16(count);
3710        pSMB->TotalParameterCount = pSMB->ParameterCount;
3711        pSMB->TotalDataCount = pSMB->DataCount;
3712        pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
3713        pSMB->Reserved4 = 0;
3714        pSMB->hdr.smb_buf_length += byte_count;
3715        data_offset->Uid = cpu_to_le64(uid);
3716        data_offset->Gid = cpu_to_le64(gid);
3717        /* better to leave device as zero when it is  */
3718        data_offset->DevMajor = cpu_to_le64(MAJOR(device));
3719        data_offset->DevMinor = cpu_to_le64(MINOR(device));
3720        data_offset->Permissions = cpu_to_le64(mode);
3721    
3722        if(S_ISREG(mode))
3723                data_offset->Type = cpu_to_le32(UNIX_FILE);
3724        else if(S_ISDIR(mode))
3725                data_offset->Type = cpu_to_le32(UNIX_DIR);
3726        else if(S_ISLNK(mode))
3727                data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
3728        else if(S_ISCHR(mode))
3729                data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
3730        else if(S_ISBLK(mode))
3731                data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
3732        else if(S_ISFIFO(mode))
3733                data_offset->Type = cpu_to_le32(UNIX_FIFO);
3734        else if(S_ISSOCK(mode))
3735                data_offset->Type = cpu_to_le32(UNIX_SOCKET);
3736
3737
3738        pSMB->ByteCount = cpu_to_le16(byte_count);
3739        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3740                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3741        if (rc) {
3742                cFYI(1, ("SetPathInfo (perms) returned %d", rc));
3743        }
3744
3745        if (pSMB)
3746                cifs_buf_release(pSMB);
3747        if (rc == -EAGAIN)
3748                goto setPermsRetry;
3749        return rc;
3750}
3751
3752int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
3753                        const int notify_subdirs, const __u16 netfid,
3754                        __u32 filter, const struct nls_table *nls_codepage)
3755{
3756        int rc = 0;
3757        struct smb_com_transaction_change_notify_req * pSMB = NULL;
3758        struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
3759        int bytes_returned;
3760
3761        cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
3762        rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
3763                      (void **) &pSMBr);
3764        if (rc)
3765                return rc;
3766
3767        pSMB->TotalParameterCount = 0 ;
3768        pSMB->TotalDataCount = 0;
3769        pSMB->MaxParameterCount = cpu_to_le32(2);
3770        /* BB find exact data count max from sess structure BB */
3771        pSMB->MaxDataCount = 0; /* same in little endian or be */
3772        pSMB->MaxSetupCount = 4;
3773        pSMB->Reserved = 0;
3774        pSMB->ParameterOffset = 0;
3775        pSMB->DataCount = 0;
3776        pSMB->DataOffset = 0;
3777        pSMB->SetupCount = 4; /* single byte does not need le conversion */
3778        pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
3779        pSMB->ParameterCount = pSMB->TotalParameterCount;
3780        if(notify_subdirs)
3781                pSMB->WatchTree = 1; /* one byte - no le conversion needed */
3782        pSMB->Reserved2 = 0;
3783        pSMB->CompletionFilter = cpu_to_le32(filter);
3784        pSMB->Fid = netfid; /* file handle always le */
3785        pSMB->ByteCount = 0;
3786
3787        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3788                        (struct smb_hdr *) pSMBr, &bytes_returned, -1);
3789        if (rc) {
3790                cFYI(1, ("Error in Notify = %d", rc));
3791        }
3792        if (pSMB)
3793                cifs_buf_release(pSMB);
3794/*              if (rc == -EAGAIN)
3795                        goto NotifyRetry; */
3796        return rc;      
3797}
3798#ifdef CONFIG_CIFS_XATTR
3799ssize_t
3800CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
3801                 const unsigned char *searchName,
3802                 char * EAData, size_t buf_size,
3803                 const struct nls_table *nls_codepage)
3804{
3805                /* BB assumes one setup word */
3806        TRANSACTION2_QPI_REQ *pSMB = NULL;
3807        TRANSACTION2_QPI_RSP *pSMBr = NULL;
3808        int rc = 0;
3809        int bytes_returned;
3810        int name_len;
3811        struct fea * temp_fea;
3812        char * temp_ptr;
3813        __u16 params, byte_count;
3814
3815        cFYI(1, ("In Query All EAs path %s", searchName));
3816QAllEAsRetry:
3817        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3818                      (void **) &pSMBr);
3819        if (rc)
3820                return rc;
3821
3822        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3823                name_len =
3824                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
3825                                  /* find define for this maxpathcomponent */
3826                                  , nls_codepage);
3827                name_len++;     /* trailing null */
3828                name_len *= 2;
3829        } else {        /* BB improve the check for buffer overruns BB */
3830                name_len = strnlen(searchName, PATH_MAX);
3831                name_len++;     /* trailing null */
3832                strncpy(pSMB->FileName, searchName, name_len);
3833        }
3834
3835        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3836        pSMB->TotalDataCount = 0;
3837        pSMB->MaxParameterCount = cpu_to_le16(2);
3838        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3839        pSMB->MaxSetupCount = 0;
3840        pSMB->Reserved = 0;
3841        pSMB->Flags = 0;
3842        pSMB->Timeout = 0;
3843        pSMB->Reserved2 = 0;
3844        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3845        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3846        pSMB->DataCount = 0;
3847        pSMB->DataOffset = 0;
3848        pSMB->SetupCount = 1;
3849        pSMB->Reserved3 = 0;
3850        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3851        byte_count = params + 1 /* pad */ ;
3852        pSMB->TotalParameterCount = cpu_to_le16(params);
3853        pSMB->ParameterCount = pSMB->TotalParameterCount;
3854        pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3855        pSMB->Reserved4 = 0;
3856        pSMB->hdr.smb_buf_length += byte_count;
3857        pSMB->ByteCount = cpu_to_le16(byte_count);
3858
3859        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3860                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3861        if (rc) {
3862                cFYI(1, ("Send error in QueryAllEAs = %d", rc));
3863        } else {                /* decode response */
3864                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3865
3866                /* BB also check enough total bytes returned */
3867                /* BB we need to improve the validity checking
3868                of these trans2 responses */
3869                if (rc || (pSMBr->ByteCount < 4)) 
3870                        rc = -EIO;      /* bad smb */
3871           /* else if (pFindData){
3872                        memcpy((char *) pFindData,
3873                               (char *) &pSMBr->hdr.Protocol +
3874                               data_offset, kl);
3875                }*/ else {
3876                        /* check that length of list is not more than bcc */
3877                        /* check that each entry does not go beyond length
3878                           of list */
3879                        /* check that each element of each entry does not
3880                           go beyond end of list */
3881                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3882                        struct fealist * ea_response_data;
3883                        rc = 0;
3884                        /* validate_trans2_offsets() */
3885                        /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
3886                        ea_response_data = (struct fealist *)
3887                                (((char *) &pSMBr->hdr.Protocol) +
3888                                data_offset);
3889                        name_len = le32_to_cpu(ea_response_data->list_len);
3890                        cFYI(1,("ea length %d", name_len));
3891                        if(name_len <= 8) {
3892                        /* returned EA size zeroed at top of function */
3893                                cFYI(1,("empty EA list returned from server"));
3894                        } else {
3895                                /* account for ea list len */
3896                                name_len -= 4;
3897                                temp_fea = ea_response_data->list;
3898                                temp_ptr = (char *)temp_fea;
3899                                while(name_len > 0) {
3900                                        __u16 value_len;
3901                                        name_len -= 4;
3902                                        temp_ptr += 4;
3903                                        rc += temp_fea->name_len;
3904                                /* account for prefix user. and trailing null */
3905                                        rc = rc + 5 + 1; 
3906                                        if(rc<(int)buf_size) {
3907                                                memcpy(EAData,"user.",5);
3908                                                EAData+=5;
3909                                                memcpy(EAData,temp_ptr,temp_fea->name_len);
3910                                                EAData+=temp_fea->name_len;
3911                                                /* null terminate name */
3912                                                *EAData = 0;
3913                                                EAData = EAData + 1;
3914                                        } else if(buf_size == 0) {
3915                                                /* skip copy - calc size only */
3916                                        } else {
3917                                                /* stop before overrun buffer */
3918                                                rc = -ERANGE;
3919                                                break;
3920                                        }
3921                                        name_len -= temp_fea->name_len;
3922                                        temp_ptr += temp_fea->name_len;
3923                                        /* account for trailing null */
3924                                        name_len--;
3925                                        temp_ptr++;
3926                                        value_len = le16_to_cpu(temp_fea->value_len);
3927                                        name_len -= value_len;
3928                                        temp_ptr += value_len;
3929                                        /* BB check that temp_ptr is still within smb BB*/
3930                                /* no trailing null to account for in value len */
3931                                        /* go on to next EA */
3932                                        temp_fea = (struct fea *)temp_ptr;
3933                                }
3934                        }
3935                }
3936        }
3937        if (pSMB)
3938                cifs_buf_release(pSMB);
3939        if (rc == -EAGAIN)
3940                goto QAllEAsRetry;
3941
3942        return (ssize_t)rc;
3943}
3944
3945ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
3946                const unsigned char * searchName,const unsigned char * ea_name,
3947                unsigned char * ea_value, size_t buf_size, 
3948                const struct nls_table *nls_codepage)
3949{
3950        TRANSACTION2_QPI_REQ *pSMB = NULL;
3951        TRANSACTION2_QPI_RSP *pSMBr = NULL;
3952        int rc = 0;
3953        int bytes_returned;
3954        int name_len;
3955        struct fea * temp_fea;
3956        char * temp_ptr;
3957        __u16 params, byte_count;
3958
3959        cFYI(1, ("In Query EA path %s", searchName));
3960QEARetry:
3961        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3962                      (void **) &pSMBr);
3963        if (rc)
3964                return rc;
3965
3966        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3967                name_len =
3968                    cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
3969                                  /* find define for this maxpathcomponent */
3970                                  , nls_codepage);
3971                name_len++;     /* trailing null */
3972                name_len *= 2;
3973        } else {        /* BB improve the check for buffer overruns BB */
3974                name_len = strnlen(searchName, PATH_MAX);
3975                name_len++;     /* trailing null */
3976                strncpy(pSMB->FileName, searchName, name_len);
3977        }
3978
3979        params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
3980        pSMB->TotalDataCount = 0;
3981        pSMB->MaxParameterCount = cpu_to_le16(2);
3982        pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3983        pSMB->MaxSetupCount = 0;
3984        pSMB->Reserved = 0;
3985        pSMB->Flags = 0;
3986        pSMB->Timeout = 0;
3987        pSMB->Reserved2 = 0;
3988        pSMB->ParameterOffset = cpu_to_le16(offsetof(
3989        struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3990        pSMB->DataCount = 0;
3991        pSMB->DataOffset = 0;
3992        pSMB->SetupCount = 1;
3993        pSMB->Reserved3 = 0;
3994        pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3995        byte_count = params + 1 /* pad */ ;
3996        pSMB->TotalParameterCount = cpu_to_le16(params);
3997        pSMB->ParameterCount = pSMB->TotalParameterCount;
3998        pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
3999        pSMB->Reserved4 = 0;
4000        pSMB->hdr.smb_buf_length += byte_count;
4001        pSMB->ByteCount = cpu_to_le16(byte_count);
4002
4003        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4004                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4005        if (rc) {
4006                cFYI(1, ("Send error in Query EA = %d", rc));
4007        } else {                /* decode response */
4008                rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4009
4010                /* BB also check enough total bytes returned */
4011                /* BB we need to improve the validity checking
4012                of these trans2 responses */
4013                if (rc || (pSMBr->ByteCount < 4)) 
4014                        rc = -EIO;      /* bad smb */
4015           /* else if (pFindData){
4016                        memcpy((char *) pFindData,
4017                               (char *) &pSMBr->hdr.Protocol +
4018                               data_offset, kl);
4019                }*/ else {
4020                        /* check that length of list is not more than bcc */
4021                        /* check that each entry does not go beyond length
4022                           of list */
4023                        /* check that each element of each entry does not
4024                           go beyond end of list */
4025                        __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4026                        struct fealist * ea_response_data;
4027                        rc = -ENODATA;
4028                        /* validate_trans2_offsets() */
4029                        /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4030                        ea_response_data = (struct fealist *)
4031                                (((char *) &pSMBr->hdr.Protocol) +
4032                                data_offset);
4033                        name_len = le32_to_cpu(ea_response_data->list_len);
4034                        cFYI(1,("ea length %d", name_len));
4035                        if(name_len <= 8) {
4036                        /* returned EA size zeroed at top of function */
4037                                cFYI(1,("empty EA list returned from server"));
4038                        } else {
4039                                /* account for ea list len */
4040                                name_len -= 4;
4041                                temp_fea = ea_response_data->list;
4042                                temp_ptr = (char *)temp_fea;
4043                                /* loop through checking if we have a matching
4044                                name and then return the associated value */
4045                                while(name_len > 0) {
4046                                        __u16 value_len;
4047                                        name_len -= 4;
4048                                        temp_ptr += 4;
4049                                        value_len = le16_to_cpu(temp_fea->value_len);
4050                                /* BB validate that value_len falls within SMB, 
4051                                even though maximum for name_len is 255 */ 
4052                                        if(memcmp(temp_fea->name,ea_name,
4053                                                  temp_fea->name_len) == 0) {
4054                                                /* found a match */
4055                                                rc = value_len;
4056                                /* account for prefix user. and trailing null */
4057                                                if(rc<=(int)buf_size) {
4058                                                        memcpy(ea_value,
4059                                                                temp_fea->name+temp_fea->name_len+1,
4060                                                                rc);
4061                                                        /* ea values, unlike ea names,
4062                                                        are not null terminated */
4063                                                } else if(buf_size == 0) {
4064                                                /* skip copy - calc size only */
4065                                                } else {
4066                                                        /* stop before overrun buffer */
4067                                                        rc = -ERANGE;
4068                                                }
4069                                                break;
4070                                        }
4071                                        name_len -= temp_fea->name_len;
4072                                        temp_ptr += temp_fea->name_len;
4073                                        /* account for trailing null */
4074                                        name_len--;
4075                                        temp_ptr++;
4076                                        name_len -= value_len;
4077                                        temp_ptr += value_len;
4078                                /* no trailing null to account for in value len */
4079                                        /* go on to next EA */
4080                                        temp_fea = (struct fea *)temp_ptr;
4081                                }
4082                        } 
4083                }
4084        }
4085        if (pSMB)
4086                cifs_buf_release(pSMB);
4087        if (rc == -EAGAIN)
4088                goto QEARetry;
4089
4090        return (ssize_t)rc;
4091}
4092
4093int
4094CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4095                const char * ea_name, const void * ea_value, 
4096                const __u16 ea_value_len, const struct nls_table *nls_codepage)
4097{
4098        struct smb_com_transaction2_spi_req *pSMB = NULL;
4099        struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4100        struct fealist *parm_data;
4101        int name_len;
4102        int rc = 0;
4103        int bytes_returned = 0;
4104        __u16 params, param_offset, byte_count, offset, count;
4105
4106        cFYI(1, ("In SetEA"));
4107SetEARetry:
4108        rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4109                      (void **) &pSMBr);
4110        if (rc)
4111                return rc;
4112
4113        if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4114                name_len =
4115                    cifs_strtoUCS((wchar_t *) pSMB->FileName, fileName, PATH_MAX
4116                                  /* find define for this maxpathcomponent */
4117                                  , nls_codepage);
4118                name_len++;     /* trailing null */
4119                name_len *= 2;
4120        } else {                /* BB improve the check for buffer overruns BB */
4121                name_len = strnlen(fileName, PATH_MAX);
4122                name_len++;     /* trailing null */
4123                strncpy(pSMB->FileName, fileName, name_len);
4124        }
4125
4126        params = 6 + name_len;
4127
4128        /* done calculating parms using name_len of file name,
4129        now use name_len to calculate length of ea name
4130        we are going to create in the inode xattrs */
4131        if(ea_name == NULL)
4132                name_len = 0;
4133        else
4134                name_len = strnlen(ea_name,255);
4135
4136        count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4137        pSMB->MaxParameterCount = cpu_to_le16(2);
4138        pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4139        pSMB->MaxSetupCount = 0;
4140        pSMB->Reserved = 0;
4141        pSMB->Flags = 0;
4142        pSMB->Timeout = 0;
4143        pSMB->Reserved2 = 0;
4144        param_offset = offsetof(struct smb_com_transaction2_spi_req,
4145                                     InformationLevel) - 4;
4146        offset = param_offset + params;
4147        pSMB->InformationLevel =
4148                cpu_to_le16(SMB_SET_FILE_EA);
4149
4150        parm_data =
4151                (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4152                                       offset);
4153        pSMB->ParameterOffset = cpu_to_le16(param_offset);
4154        pSMB->DataOffset = cpu_to_le16(offset);
4155        pSMB->SetupCount = 1;
4156        pSMB->Reserved3 = 0;
4157        pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4158        byte_count = 3 /* pad */  + params + count;
4159        pSMB->DataCount = cpu_to_le16(count);
4160        parm_data->list_len = cpu_to_le32(count);
4161        parm_data->list[0].EA_flags = 0;
4162        /* we checked above that name len is less than 255 */
4163        parm_data->list[0].name_len = (__u8)name_len;;
4164        /* EA names are always ASCII */
4165        strncpy(parm_data->list[0].name,ea_name,name_len);
4166        parm_data->list[0].name[name_len] = 0;
4167        parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4168        /* caller ensures that ea_value_len is less than 64K but
4169        we need to ensure that it fits within the smb */
4170
4171        /*BB add length check that it would fit in negotiated SMB buffer size BB */
4172        /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4173        if(ea_value_len)
4174                memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4175
4176        pSMB->TotalDataCount = pSMB->DataCount;
4177        pSMB->ParameterCount = cpu_to_le16(params);
4178        pSMB->TotalParameterCount = pSMB->ParameterCount;
4179        pSMB->Reserved4 = 0;
4180        pSMB->hdr.smb_buf_length += byte_count;
4181        pSMB->ByteCount = cpu_to_le16(byte_count);
4182        rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4183                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4184        if (rc) {
4185                cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4186        }
4187
4188        if (pSMB)
4189                cifs_buf_release(pSMB);
4190
4191        if (rc == -EAGAIN)
4192                goto SetEARetry;
4193
4194        return rc;
4195}
4196
4197#endif
4198
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.