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