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