[CIFS] Add worker function for Get ACL cifs style
[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         CHECK ON OTHER COMPUTER TO SEE IF FORMAT ENCODED IN CIFSPDU.H ALREADY
2501         return 0;
2502 }
2503
2504 /* Get Security Descriptor (by handle) from remote server for a file or dir */
2505 int
2506 CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid,
2507          /*  BB fix up return info */ char *acl_inf, const int buflen, 
2508                   const int acl_type /* ACCESS/DEFAULT not sure implication */)
2509 {
2510         int rc = 0;
2511         int buf_type = 0;
2512         QUERY_SEC_DESC_REQ * pSMB;
2513         struct kvec iov[1];
2514
2515         cFYI(1, ("GetCifsACL"));
2516
2517         rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, 
2518                         8 /* parm len */, tcon, (void **) &pSMB);
2519         if (rc)
2520                 return rc;
2521
2522         pSMB->MaxParameterCount = cpu_to_le32(4);
2523         /* BB TEST with big acls that might need to be e.g. larger than 16K */
2524         pSMB->MaxSetupCount = 0;
2525         pSMB->Fid = fid; /* file handle always le */
2526         pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP |
2527                                      CIFS_ACL_DACL);
2528         pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */
2529         pSMB->hdr.smb_buf_length += 11;
2530         iov[0].iov_base = (char *)pSMB;
2531         iov[0].iov_len = pSMB->hdr.smb_buf_length + 4;
2532
2533         rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0);
2534         cifs_stats_inc(&tcon->num_acl_get);
2535         if (rc) {
2536                 cFYI(1, ("Send error in QuerySecDesc = %d", rc));
2537         } else {                /* decode response */
2538                 struct sec_desc * psec_desc;
2539                 __le32 * parm;
2540                 int parm_len;
2541                 int data_len;
2542                 int acl_len;
2543                 struct smb_com_ntransact_rsp * pSMBr;
2544
2545 /* validate_nttransact */
2546                 rc = validate_ntransact(iov[0].iov_base, (char **)&parm, 
2547                                         (char **)&psec_desc,
2548                                         &parm_len, &data_len);
2549                 
2550                 if(rc)
2551                         goto qsec_out;
2552                 pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base;
2553
2554                 cERROR(1,("smb %p parm %p data %p",pSMBr,parm,psec_desc));  /* BB removeme BB */
2555
2556                 if (le32_to_cpu(pSMBr->ParameterCount) != 4) {
2557                         rc = -EIO;      /* bad smb */
2558                         goto qsec_out;
2559                 }
2560
2561 /* BB check that data area is minimum length and as big as acl_len */
2562
2563                 acl_len = le32_to_cpu(*(__le32 *)parm);
2564                 /* BB check if(acl_len > bufsize) */
2565
2566                 parse_sec_desc(psec_desc, acl_len);
2567         }
2568 qsec_out:
2569         if(buf_type == CIFS_SMALL_BUFFER)
2570                 cifs_small_buf_release(iov[0].iov_base);
2571         else if(buf_type == CIFS_LARGE_BUFFER)
2572                 cifs_buf_release(iov[0].iov_base);
2573         cifs_small_buf_release(pSMB);
2574         return rc;
2575 }
2576
2577
2578 /* Legacy Query Path Information call for lookup to old servers such
2579    as Win9x/WinME */
2580 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2581                  const unsigned char *searchName,
2582                  FILE_ALL_INFO * pFinfo,
2583                  const struct nls_table *nls_codepage, int remap)
2584 {
2585         QUERY_INFORMATION_REQ * pSMB;
2586         QUERY_INFORMATION_RSP * pSMBr;
2587         int rc = 0;
2588         int bytes_returned;
2589         int name_len;
2590
2591         cFYI(1, ("In SMBQPath path %s", searchName)); 
2592 QInfRetry:
2593         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2594                       (void **) &pSMBr);
2595         if (rc)
2596                 return rc;
2597
2598         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2599                 name_len =
2600                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2601                                      PATH_MAX, nls_codepage, remap);
2602                 name_len++;     /* trailing null */
2603                 name_len *= 2;
2604         } else {               
2605                 name_len = strnlen(searchName, PATH_MAX);
2606                 name_len++;     /* trailing null */
2607                 strncpy(pSMB->FileName, searchName, name_len);
2608         }
2609         pSMB->BufferFormat = 0x04;
2610         name_len++; /* account for buffer type byte */  
2611         pSMB->hdr.smb_buf_length += (__u16) name_len;
2612         pSMB->ByteCount = cpu_to_le16(name_len);
2613
2614         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2615                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2616         if (rc) {
2617                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2618         } else if (pFinfo) {            /* decode response */
2619                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2620                 pFinfo->AllocationSize =
2621                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2622                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2623                 pFinfo->Attributes =
2624                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2625         } else
2626                 rc = -EIO; /* bad buffer passed in */
2627
2628         cifs_buf_release(pSMB);
2629
2630         if (rc == -EAGAIN)
2631                 goto QInfRetry;
2632
2633         return rc;
2634 }
2635
2636
2637
2638
2639 int
2640 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2641                  const unsigned char *searchName,
2642                  FILE_ALL_INFO * pFindData,
2643                  const struct nls_table *nls_codepage, int remap)
2644 {
2645 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2646         TRANSACTION2_QPI_REQ *pSMB = NULL;
2647         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2648         int rc = 0;
2649         int bytes_returned;
2650         int name_len;
2651         __u16 params, byte_count;
2652
2653 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2654 QPathInfoRetry:
2655         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2656                       (void **) &pSMBr);
2657         if (rc)
2658                 return rc;
2659
2660         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2661                 name_len =
2662                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2663                                      PATH_MAX, nls_codepage, remap);
2664                 name_len++;     /* trailing null */
2665                 name_len *= 2;
2666         } else {                /* BB improve the check for buffer overruns BB */
2667                 name_len = strnlen(searchName, PATH_MAX);
2668                 name_len++;     /* trailing null */
2669                 strncpy(pSMB->FileName, searchName, name_len);
2670         }
2671
2672         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2673         pSMB->TotalDataCount = 0;
2674         pSMB->MaxParameterCount = cpu_to_le16(2);
2675         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2676         pSMB->MaxSetupCount = 0;
2677         pSMB->Reserved = 0;
2678         pSMB->Flags = 0;
2679         pSMB->Timeout = 0;
2680         pSMB->Reserved2 = 0;
2681         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2682         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2683         pSMB->DataCount = 0;
2684         pSMB->DataOffset = 0;
2685         pSMB->SetupCount = 1;
2686         pSMB->Reserved3 = 0;
2687         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2688         byte_count = params + 1 /* pad */ ;
2689         pSMB->TotalParameterCount = cpu_to_le16(params);
2690         pSMB->ParameterCount = pSMB->TotalParameterCount;
2691         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2692         pSMB->Reserved4 = 0;
2693         pSMB->hdr.smb_buf_length += byte_count;
2694         pSMB->ByteCount = cpu_to_le16(byte_count);
2695
2696         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2697                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2698         if (rc) {
2699                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2700         } else {                /* decode response */
2701                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2702
2703                 if (rc || (pSMBr->ByteCount < 40)) 
2704                         rc = -EIO;      /* bad smb */
2705                 else if (pFindData){
2706                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2707                         memcpy((char *) pFindData,
2708                                (char *) &pSMBr->hdr.Protocol +
2709                                data_offset, sizeof (FILE_ALL_INFO));
2710                 } else
2711                     rc = -ENOMEM;
2712         }
2713         cifs_buf_release(pSMB);
2714         if (rc == -EAGAIN)
2715                 goto QPathInfoRetry;
2716
2717         return rc;
2718 }
2719
2720 int
2721 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2722                      const unsigned char *searchName,
2723                      FILE_UNIX_BASIC_INFO * pFindData,
2724                      const struct nls_table *nls_codepage, int remap)
2725 {
2726 /* SMB_QUERY_FILE_UNIX_BASIC */
2727         TRANSACTION2_QPI_REQ *pSMB = NULL;
2728         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2729         int rc = 0;
2730         int bytes_returned = 0;
2731         int name_len;
2732         __u16 params, byte_count;
2733
2734         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2735 UnixQPathInfoRetry:
2736         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2737                       (void **) &pSMBr);
2738         if (rc)
2739                 return rc;
2740
2741         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2742                 name_len =
2743                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2744                                   PATH_MAX, nls_codepage, remap);
2745                 name_len++;     /* trailing null */
2746                 name_len *= 2;
2747         } else {                /* BB improve the check for buffer overruns BB */
2748                 name_len = strnlen(searchName, PATH_MAX);
2749                 name_len++;     /* trailing null */
2750                 strncpy(pSMB->FileName, searchName, name_len);
2751         }
2752
2753         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2754         pSMB->TotalDataCount = 0;
2755         pSMB->MaxParameterCount = cpu_to_le16(2);
2756         /* BB find exact max SMB PDU from sess structure BB */
2757         pSMB->MaxDataCount = cpu_to_le16(4000); 
2758         pSMB->MaxSetupCount = 0;
2759         pSMB->Reserved = 0;
2760         pSMB->Flags = 0;
2761         pSMB->Timeout = 0;
2762         pSMB->Reserved2 = 0;
2763         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2764         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2765         pSMB->DataCount = 0;
2766         pSMB->DataOffset = 0;
2767         pSMB->SetupCount = 1;
2768         pSMB->Reserved3 = 0;
2769         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2770         byte_count = params + 1 /* pad */ ;
2771         pSMB->TotalParameterCount = cpu_to_le16(params);
2772         pSMB->ParameterCount = pSMB->TotalParameterCount;
2773         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2774         pSMB->Reserved4 = 0;
2775         pSMB->hdr.smb_buf_length += byte_count;
2776         pSMB->ByteCount = cpu_to_le16(byte_count);
2777
2778         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2779                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2780         if (rc) {
2781                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2782         } else {                /* decode response */
2783                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2784
2785                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2786                         rc = -EIO;      /* bad smb */
2787                 } else {
2788                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2789                         memcpy((char *) pFindData,
2790                                (char *) &pSMBr->hdr.Protocol +
2791                                data_offset,
2792                                sizeof (FILE_UNIX_BASIC_INFO));
2793                 }
2794         }
2795         cifs_buf_release(pSMB);
2796         if (rc == -EAGAIN)
2797                 goto UnixQPathInfoRetry;
2798
2799         return rc;
2800 }
2801
2802 #if 0  /* function unused at present */
2803 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2804                const char *searchName, FILE_ALL_INFO * findData,
2805                const struct nls_table *nls_codepage)
2806 {
2807 /* level 257 SMB_ */
2808         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2809         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2810         int rc = 0;
2811         int bytes_returned;
2812         int name_len;
2813         __u16 params, byte_count;
2814
2815         cFYI(1, ("In FindUnique"));
2816 findUniqueRetry:
2817         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2818                       (void **) &pSMBr);
2819         if (rc)
2820                 return rc;
2821
2822         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2823                 name_len =
2824                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2825                                   /* find define for this maxpathcomponent */
2826                                   , nls_codepage);
2827                 name_len++;     /* trailing null */
2828                 name_len *= 2;
2829         } else {                /* BB improve the check for buffer overruns BB */
2830                 name_len = strnlen(searchName, PATH_MAX);
2831                 name_len++;     /* trailing null */
2832                 strncpy(pSMB->FileName, searchName, name_len);
2833         }
2834
2835         params = 12 + name_len /* includes null */ ;
2836         pSMB->TotalDataCount = 0;       /* no EAs */
2837         pSMB->MaxParameterCount = cpu_to_le16(2);
2838         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2839         pSMB->MaxSetupCount = 0;
2840         pSMB->Reserved = 0;
2841         pSMB->Flags = 0;
2842         pSMB->Timeout = 0;
2843         pSMB->Reserved2 = 0;
2844         pSMB->ParameterOffset = cpu_to_le16(
2845          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2846         pSMB->DataCount = 0;
2847         pSMB->DataOffset = 0;
2848         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2849         pSMB->Reserved3 = 0;
2850         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2851         byte_count = params + 1 /* pad */ ;
2852         pSMB->TotalParameterCount = cpu_to_le16(params);
2853         pSMB->ParameterCount = pSMB->TotalParameterCount;
2854         pSMB->SearchAttributes =
2855             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2856                         ATTR_DIRECTORY);
2857         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2858         pSMB->SearchFlags = cpu_to_le16(1);
2859         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2860         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2861         pSMB->hdr.smb_buf_length += byte_count;
2862         pSMB->ByteCount = cpu_to_le16(byte_count);
2863
2864         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2865                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2866
2867         if (rc) {
2868                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2869         } else {                /* decode response */
2870                 cifs_stats_inc(&tcon->num_ffirst);
2871                 /* BB fill in */
2872         }
2873
2874         cifs_buf_release(pSMB);
2875         if (rc == -EAGAIN)
2876                 goto findUniqueRetry;
2877
2878         return rc;
2879 }
2880 #endif /* end unused (temporarily) function */
2881
2882 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2883 int
2884 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2885               const char *searchName, 
2886               const struct nls_table *nls_codepage,
2887               __u16 *   pnetfid,
2888               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2889 {
2890 /* level 257 SMB_ */
2891         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2892         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2893         T2_FFIRST_RSP_PARMS * parms;
2894         int rc = 0;
2895         int bytes_returned = 0;
2896         int name_len;
2897         __u16 params, byte_count;
2898
2899         cFYI(1, ("In FindFirst for %s",searchName));
2900
2901 findFirstRetry:
2902         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2903                       (void **) &pSMBr);
2904         if (rc)
2905                 return rc;
2906
2907         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2908                 name_len =
2909                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2910                                  PATH_MAX, nls_codepage, remap);
2911                 /* We can not add the asterik earlier in case
2912                 it got remapped to 0xF03A as if it were part of the
2913                 directory name instead of a wildcard */
2914                 name_len *= 2;
2915                 pSMB->FileName[name_len] = dirsep;
2916                 pSMB->FileName[name_len+1] = 0;
2917                 pSMB->FileName[name_len+2] = '*';
2918                 pSMB->FileName[name_len+3] = 0;
2919                 name_len += 4; /* now the trailing null */
2920                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2921                 pSMB->FileName[name_len+1] = 0;
2922                 name_len += 2;
2923         } else {        /* BB add check for overrun of SMB buf BB */
2924                 name_len = strnlen(searchName, PATH_MAX);
2925 /* BB fix here and in unicode clause above ie
2926                 if(name_len > buffersize-header)
2927                         free buffer exit; BB */
2928                 strncpy(pSMB->FileName, searchName, name_len);
2929                 pSMB->FileName[name_len] = dirsep;
2930                 pSMB->FileName[name_len+1] = '*';
2931                 pSMB->FileName[name_len+2] = 0;
2932                 name_len += 3;
2933         }
2934
2935         params = 12 + name_len /* includes null */ ;
2936         pSMB->TotalDataCount = 0;       /* no EAs */
2937         pSMB->MaxParameterCount = cpu_to_le16(10);
2938         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2939                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2940         pSMB->MaxSetupCount = 0;
2941         pSMB->Reserved = 0;
2942         pSMB->Flags = 0;
2943         pSMB->Timeout = 0;
2944         pSMB->Reserved2 = 0;
2945         byte_count = params + 1 /* pad */ ;
2946         pSMB->TotalParameterCount = cpu_to_le16(params);
2947         pSMB->ParameterCount = pSMB->TotalParameterCount;
2948         pSMB->ParameterOffset = cpu_to_le16(
2949           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2950         pSMB->DataCount = 0;
2951         pSMB->DataOffset = 0;
2952         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2953         pSMB->Reserved3 = 0;
2954         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2955         pSMB->SearchAttributes =
2956             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2957                         ATTR_DIRECTORY);
2958         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2959         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2960                 CIFS_SEARCH_RETURN_RESUME);
2961         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2962
2963         /* BB what should we set StorageType to? Does it matter? BB */
2964         pSMB->SearchStorageType = 0;
2965         pSMB->hdr.smb_buf_length += byte_count;
2966         pSMB->ByteCount = cpu_to_le16(byte_count);
2967
2968         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2969                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2970         cifs_stats_inc(&tcon->num_ffirst);
2971
2972         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2973                 /* BB Add code to handle unsupported level rc */
2974                 cFYI(1, ("Error in FindFirst = %d", rc));
2975
2976                 if (pSMB)
2977                         cifs_buf_release(pSMB);
2978
2979                 /* BB eventually could optimize out free and realloc of buf */
2980                 /*    for this case */
2981                 if (rc == -EAGAIN)
2982                         goto findFirstRetry;
2983         } else { /* decode response */
2984                 /* BB remember to free buffer if error BB */
2985                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2986                 if(rc == 0) {
2987                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2988                                 psrch_inf->unicode = TRUE;
2989                         else
2990                                 psrch_inf->unicode = FALSE;
2991
2992                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2993                         psrch_inf->srch_entries_start = 
2994                                 (char *) &pSMBr->hdr.Protocol + 
2995                                         le16_to_cpu(pSMBr->t2.DataOffset);
2996                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2997                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2998
2999                         if(parms->EndofSearch)
3000                                 psrch_inf->endOfSearch = TRUE;
3001                         else
3002                                 psrch_inf->endOfSearch = FALSE;
3003
3004                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3005                         psrch_inf->index_of_last_entry = 
3006                                 psrch_inf->entries_in_buffer;
3007                         *pnetfid = parms->SearchHandle;
3008                 } else {
3009                         cifs_buf_release(pSMB);
3010                 }
3011         }
3012
3013         return rc;
3014 }
3015
3016 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
3017             __u16 searchHandle, struct cifs_search_info * psrch_inf)
3018 {
3019         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
3020         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
3021         T2_FNEXT_RSP_PARMS * parms;
3022         char *response_data;
3023         int rc = 0;
3024         int bytes_returned, name_len;
3025         __u16 params, byte_count;
3026
3027         cFYI(1, ("In FindNext"));
3028
3029         if(psrch_inf->endOfSearch == TRUE)
3030                 return -ENOENT;
3031
3032         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3033                 (void **) &pSMBr);
3034         if (rc)
3035                 return rc;
3036
3037         params = 14;    /* includes 2 bytes of null string, converted to LE below */
3038         byte_count = 0;
3039         pSMB->TotalDataCount = 0;       /* no EAs */
3040         pSMB->MaxParameterCount = cpu_to_le16(8);
3041         pSMB->MaxDataCount =
3042             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
3043         pSMB->MaxSetupCount = 0;
3044         pSMB->Reserved = 0;
3045         pSMB->Flags = 0;
3046         pSMB->Timeout = 0;
3047         pSMB->Reserved2 = 0;
3048         pSMB->ParameterOffset =  cpu_to_le16(
3049               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
3050         pSMB->DataCount = 0;
3051         pSMB->DataOffset = 0;
3052         pSMB->SetupCount = 1;
3053         pSMB->Reserved3 = 0;
3054         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
3055         pSMB->SearchHandle = searchHandle;      /* always kept as le */
3056         pSMB->SearchCount =
3057                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
3058         /* test for Unix extensions */
3059 /*      if (tcon->ses->capabilities & CAP_UNIX) {
3060                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
3061                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
3062         } else {
3063                 pSMB->InformationLevel =
3064                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
3065                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
3066         } */
3067         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
3068         pSMB->ResumeKey = psrch_inf->resume_key;
3069         pSMB->SearchFlags =
3070               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
3071
3072         name_len = psrch_inf->resume_name_len;
3073         params += name_len;
3074         if(name_len < PATH_MAX) {
3075                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
3076                 byte_count += name_len;
3077                 /* 14 byte parm len above enough for 2 byte null terminator */
3078                 pSMB->ResumeFileName[name_len] = 0;
3079                 pSMB->ResumeFileName[name_len+1] = 0;
3080         } else {
3081                 rc = -EINVAL;
3082                 goto FNext2_err_exit;
3083         }
3084         byte_count = params + 1 /* pad */ ;
3085         pSMB->TotalParameterCount = cpu_to_le16(params);
3086         pSMB->ParameterCount = pSMB->TotalParameterCount;
3087         pSMB->hdr.smb_buf_length += byte_count;
3088         pSMB->ByteCount = cpu_to_le16(byte_count);
3089                                                                                               
3090         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3091                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3092         cifs_stats_inc(&tcon->num_fnext);
3093         if (rc) {
3094                 if (rc == -EBADF) {
3095                         psrch_inf->endOfSearch = TRUE;
3096                         rc = 0; /* search probably was closed at end of search above */
3097                 } else
3098                         cFYI(1, ("FindNext returned = %d", rc));
3099         } else {                /* decode response */
3100                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3101                 
3102                 if(rc == 0) {
3103                         /* BB fixme add lock for file (srch_info) struct here */
3104                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
3105                                 psrch_inf->unicode = TRUE;
3106                         else
3107                                 psrch_inf->unicode = FALSE;
3108                         response_data = (char *) &pSMBr->hdr.Protocol +
3109                                le16_to_cpu(pSMBr->t2.ParameterOffset);
3110                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
3111                         response_data = (char *)&pSMBr->hdr.Protocol +
3112                                 le16_to_cpu(pSMBr->t2.DataOffset);
3113                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
3114                         psrch_inf->srch_entries_start = response_data;
3115                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
3116                         if(parms->EndofSearch)
3117                                 psrch_inf->endOfSearch = TRUE;
3118                         else
3119                                 psrch_inf->endOfSearch = FALSE;
3120                                                                                               
3121                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
3122                         psrch_inf->index_of_last_entry +=
3123                                 psrch_inf->entries_in_buffer;
3124 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
3125
3126                         /* BB fixme add unlock here */
3127                 }
3128
3129         }
3130
3131         /* BB On error, should we leave previous search buf (and count and
3132         last entry fields) intact or free the previous one? */
3133
3134         /* Note: On -EAGAIN error only caller can retry on handle based calls
3135         since file handle passed in no longer valid */
3136 FNext2_err_exit:
3137         if (rc != 0)
3138                 cifs_buf_release(pSMB);
3139                                                                                               
3140         return rc;
3141 }
3142
3143 int
3144 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
3145 {
3146         int rc = 0;
3147         FINDCLOSE_REQ *pSMB = NULL;
3148         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
3149         int bytes_returned;
3150
3151         cFYI(1, ("In CIFSSMBFindClose"));
3152         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
3153
3154         /* no sense returning error if session restarted
3155                 as file handle has been closed */
3156         if(rc == -EAGAIN)
3157                 return 0;
3158         if (rc)
3159                 return rc;
3160
3161         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
3162         pSMB->FileID = searchHandle;
3163         pSMB->ByteCount = 0;
3164         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3165                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3166         if (rc) {
3167                 cERROR(1, ("Send error in FindClose = %d", rc));
3168         }
3169         cifs_stats_inc(&tcon->num_fclose);
3170         cifs_small_buf_release(pSMB);
3171
3172         /* Since session is dead, search handle closed on server already */
3173         if (rc == -EAGAIN)
3174                 rc = 0;
3175
3176         return rc;
3177 }
3178
3179 int
3180 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3181                 const unsigned char *searchName,
3182                 __u64 * inode_number,
3183                 const struct nls_table *nls_codepage, int remap)
3184 {
3185         int rc = 0;
3186         TRANSACTION2_QPI_REQ *pSMB = NULL;
3187         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3188         int name_len, bytes_returned;
3189         __u16 params, byte_count;
3190
3191         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3192         if(tcon == NULL)
3193                 return -ENODEV; 
3194
3195 GetInodeNumberRetry:
3196         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3197                       (void **) &pSMBr);
3198         if (rc)
3199                 return rc;
3200
3201
3202         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3203                 name_len =
3204                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3205                                 PATH_MAX,nls_codepage, remap);
3206                 name_len++;     /* trailing null */
3207                 name_len *= 2;
3208         } else {                /* BB improve the check for buffer overruns BB */
3209                 name_len = strnlen(searchName, PATH_MAX);
3210                 name_len++;     /* trailing null */
3211                 strncpy(pSMB->FileName, searchName, name_len);
3212         }
3213
3214         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3215         pSMB->TotalDataCount = 0;
3216         pSMB->MaxParameterCount = cpu_to_le16(2);
3217         /* BB find exact max data count below from sess structure BB */
3218         pSMB->MaxDataCount = cpu_to_le16(4000);
3219         pSMB->MaxSetupCount = 0;
3220         pSMB->Reserved = 0;
3221         pSMB->Flags = 0;
3222         pSMB->Timeout = 0;
3223         pSMB->Reserved2 = 0;
3224         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3225                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3226         pSMB->DataCount = 0;
3227         pSMB->DataOffset = 0;
3228         pSMB->SetupCount = 1;
3229         pSMB->Reserved3 = 0;
3230         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3231         byte_count = params + 1 /* pad */ ;
3232         pSMB->TotalParameterCount = cpu_to_le16(params);
3233         pSMB->ParameterCount = pSMB->TotalParameterCount;
3234         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3235         pSMB->Reserved4 = 0;
3236         pSMB->hdr.smb_buf_length += byte_count;
3237         pSMB->ByteCount = cpu_to_le16(byte_count);
3238
3239         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3240                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3241         if (rc) {
3242                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3243         } else {
3244                 /* decode response */
3245                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3246                 if (rc || (pSMBr->ByteCount < 2))
3247                 /* BB also check enough total bytes returned */
3248                         /* If rc should we check for EOPNOSUPP and
3249                         disable the srvino flag? or in caller? */
3250                         rc = -EIO;      /* bad smb */
3251                 else {
3252                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3253                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3254                         struct file_internal_info * pfinfo;
3255                         /* BB Do we need a cast or hash here ? */
3256                         if(count < 8) {
3257                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3258                                 rc = -EIO;
3259                                 goto GetInodeNumOut;
3260                         }
3261                         pfinfo = (struct file_internal_info *)
3262                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3263                         *inode_number = pfinfo->UniqueId;
3264                 }
3265         }
3266 GetInodeNumOut:
3267         cifs_buf_release(pSMB);
3268         if (rc == -EAGAIN)
3269                 goto GetInodeNumberRetry;
3270         return rc;
3271 }
3272
3273 int
3274 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3275                 const unsigned char *searchName,
3276                 unsigned char **targetUNCs,
3277                 unsigned int *number_of_UNC_in_array,
3278                 const struct nls_table *nls_codepage, int remap)
3279 {
3280 /* TRANS2_GET_DFS_REFERRAL */
3281         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3282         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3283         struct dfs_referral_level_3 * referrals = NULL;
3284         int rc = 0;
3285         int bytes_returned;
3286         int name_len;
3287         unsigned int i;
3288         char * temp;
3289         __u16 params, byte_count;
3290         *number_of_UNC_in_array = 0;
3291         *targetUNCs = NULL;
3292
3293         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3294         if (ses == NULL)
3295                 return -ENODEV;
3296 getDFSRetry:
3297         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3298                       (void **) &pSMBr);
3299         if (rc)
3300                 return rc;
3301         
3302         /* server pointer checked in called function, 
3303         but should never be null here anyway */
3304         pSMB->hdr.Mid = GetNextMid(ses->server);
3305         pSMB->hdr.Tid = ses->ipc_tid;
3306         pSMB->hdr.Uid = ses->Suid;
3307         if (ses->capabilities & CAP_STATUS32) {
3308                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3309         }
3310         if (ses->capabilities & CAP_DFS) {
3311                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3312         }
3313
3314         if (ses->capabilities & CAP_UNICODE) {
3315                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3316                 name_len =
3317                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3318                                      searchName, PATH_MAX, nls_codepage, remap);
3319                 name_len++;     /* trailing null */
3320                 name_len *= 2;
3321         } else {                /* BB improve the check for buffer overruns BB */
3322                 name_len = strnlen(searchName, PATH_MAX);
3323                 name_len++;     /* trailing null */
3324                 strncpy(pSMB->RequestFileName, searchName, name_len);
3325         }
3326
3327         params = 2 /* level */  + name_len /*includes null */ ;
3328         pSMB->TotalDataCount = 0;
3329         pSMB->DataCount = 0;
3330         pSMB->DataOffset = 0;
3331         pSMB->MaxParameterCount = 0;
3332         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3333         pSMB->MaxSetupCount = 0;
3334         pSMB->Reserved = 0;
3335         pSMB->Flags = 0;
3336         pSMB->Timeout = 0;
3337         pSMB->Reserved2 = 0;
3338         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3339         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3340         pSMB->SetupCount = 1;
3341         pSMB->Reserved3 = 0;
3342         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3343         byte_count = params + 3 /* pad */ ;
3344         pSMB->ParameterCount = cpu_to_le16(params);
3345         pSMB->TotalParameterCount = pSMB->ParameterCount;
3346         pSMB->MaxReferralLevel = cpu_to_le16(3);
3347         pSMB->hdr.smb_buf_length += byte_count;
3348         pSMB->ByteCount = cpu_to_le16(byte_count);
3349
3350         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3351                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3352         if (rc) {
3353                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3354         } else {                /* decode response */
3355 /* BB Add logic to parse referrals here */
3356                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3357
3358                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3359                         rc = -EIO;      /* bad smb */
3360                 else {
3361                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3362                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3363
3364                         cFYI(1,
3365                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3366                               pSMBr->ByteCount, data_offset));
3367                         referrals = 
3368                             (struct dfs_referral_level_3 *) 
3369                                         (8 /* sizeof start of data block */ +
3370                                         data_offset +
3371                                         (char *) &pSMBr->hdr.Protocol); 
3372                         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",
3373                                 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)));
3374                         /* BB This field is actually two bytes in from start of
3375                            data block so we could do safety check that DataBlock
3376                            begins at address of pSMBr->NumberOfReferrals */
3377                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3378
3379                         /* BB Fix below so can return more than one referral */
3380                         if(*number_of_UNC_in_array > 1)
3381                                 *number_of_UNC_in_array = 1;
3382
3383                         /* get the length of the strings describing refs */
3384                         name_len = 0;
3385                         for(i=0;i<*number_of_UNC_in_array;i++) {
3386                                 /* make sure that DfsPathOffset not past end */
3387                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3388                                 if (offset > data_count) {
3389                                         /* if invalid referral, stop here and do 
3390                                         not try to copy any more */
3391                                         *number_of_UNC_in_array = i;
3392                                         break;
3393                                 } 
3394                                 temp = ((char *)referrals) + offset;
3395
3396                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3397                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3398                                 } else {
3399                                         name_len += strnlen(temp,data_count);
3400                                 }
3401                                 referrals++;
3402                                 /* BB add check that referral pointer does not fall off end PDU */
3403                                 
3404                         }
3405                         /* BB add check for name_len bigger than bcc */
3406                         *targetUNCs = 
3407                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3408                         if(*targetUNCs == NULL) {
3409                                 rc = -ENOMEM;
3410                                 goto GetDFSRefExit;
3411                         }
3412                         /* copy the ref strings */
3413                         referrals =  
3414                             (struct dfs_referral_level_3 *) 
3415                                         (8 /* sizeof data hdr */ +
3416                                         data_offset + 
3417                                         (char *) &pSMBr->hdr.Protocol);
3418
3419                         for(i=0;i<*number_of_UNC_in_array;i++) {
3420                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3421                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3422                                         cifs_strfromUCS_le(*targetUNCs,
3423                                                 (__le16 *) temp, name_len, nls_codepage);
3424                                 } else {
3425                                         strncpy(*targetUNCs,temp,name_len);
3426                                 }
3427                                 /*  BB update target_uncs pointers */
3428                                 referrals++;
3429                         }
3430                         temp = *targetUNCs;
3431                         temp[name_len] = 0;
3432                 }
3433
3434         }
3435 GetDFSRefExit:
3436         if (pSMB)
3437                 cifs_buf_release(pSMB);
3438
3439         if (rc == -EAGAIN)
3440                 goto getDFSRetry;
3441
3442         return rc;
3443 }
3444
3445 /* Query File System Info such as free space to old servers such as Win 9x */
3446 int
3447 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3448 {
3449 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3450         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3451         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3452         FILE_SYSTEM_ALLOC_INFO *response_data;
3453         int rc = 0;
3454         int bytes_returned = 0;
3455         __u16 params, byte_count;
3456
3457         cFYI(1, ("OldQFSInfo"));
3458 oldQFSInfoRetry:
3459         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3460                 (void **) &pSMBr);
3461         if (rc)
3462                 return rc;
3463         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3464                       (void **) &pSMBr);
3465         if (rc)
3466                 return rc;
3467
3468         params = 2;     /* level */
3469         pSMB->TotalDataCount = 0;
3470         pSMB->MaxParameterCount = cpu_to_le16(2);
3471         pSMB->MaxDataCount = cpu_to_le16(1000);
3472         pSMB->MaxSetupCount = 0;
3473         pSMB->Reserved = 0;
3474         pSMB->Flags = 0;
3475         pSMB->Timeout = 0;
3476         pSMB->Reserved2 = 0;
3477         byte_count = params + 1 /* pad */ ;
3478         pSMB->TotalParameterCount = cpu_to_le16(params);
3479         pSMB->ParameterCount = pSMB->TotalParameterCount;
3480         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3481         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3482         pSMB->DataCount = 0;
3483         pSMB->DataOffset = 0;
3484         pSMB->SetupCount = 1;
3485         pSMB->Reserved3 = 0;
3486         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3487         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3488         pSMB->hdr.smb_buf_length += byte_count;
3489         pSMB->ByteCount = cpu_to_le16(byte_count);
3490
3491         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3492                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3493         if (rc) {
3494                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3495         } else {                /* decode response */
3496                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3497
3498                 if (rc || (pSMBr->ByteCount < 18))
3499                         rc = -EIO;      /* bad smb */
3500                 else {
3501                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3502                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3503                                  pSMBr->ByteCount, data_offset));
3504
3505                         response_data =
3506                                 (FILE_SYSTEM_ALLOC_INFO *) 
3507                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3508                         FSData->f_bsize =
3509                                 le16_to_cpu(response_data->BytesPerSector) *
3510                                 le32_to_cpu(response_data->
3511                                         SectorsPerAllocationUnit);
3512                         FSData->f_blocks =
3513                                 le32_to_cpu(response_data->TotalAllocationUnits);
3514                         FSData->f_bfree = FSData->f_bavail =
3515                                 le32_to_cpu(response_data->FreeAllocationUnits);
3516                         cFYI(1,
3517                              ("Blocks: %lld  Free: %lld Block size %ld",
3518                               (unsigned long long)FSData->f_blocks,
3519                               (unsigned long long)FSData->f_bfree,
3520                               FSData->f_bsize));
3521                 }
3522         }
3523         cifs_buf_release(pSMB);
3524
3525         if (rc == -EAGAIN)
3526                 goto oldQFSInfoRetry;
3527
3528         return rc;
3529 }
3530
3531 int
3532 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3533 {
3534 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3535         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3536         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3537         FILE_SYSTEM_INFO *response_data;
3538         int rc = 0;
3539         int bytes_returned = 0;
3540         __u16 params, byte_count;
3541
3542         cFYI(1, ("In QFSInfo"));
3543 QFSInfoRetry:
3544         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3545                       (void **) &pSMBr);
3546         if (rc)
3547                 return rc;
3548
3549         params = 2;     /* level */
3550         pSMB->TotalDataCount = 0;
3551         pSMB->MaxParameterCount = cpu_to_le16(2);
3552         pSMB->MaxDataCount = cpu_to_le16(1000);
3553         pSMB->MaxSetupCount = 0;
3554         pSMB->Reserved = 0;
3555         pSMB->Flags = 0;
3556         pSMB->Timeout = 0;
3557         pSMB->Reserved2 = 0;
3558         byte_count = params + 1 /* pad */ ;
3559         pSMB->TotalParameterCount = cpu_to_le16(params);
3560         pSMB->ParameterCount = pSMB->TotalParameterCount;
3561         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3562         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3563         pSMB->DataCount = 0;
3564         pSMB->DataOffset = 0;
3565         pSMB->SetupCount = 1;
3566         pSMB->Reserved3 = 0;
3567         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3568         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3569         pSMB->hdr.smb_buf_length += byte_count;
3570         pSMB->ByteCount = cpu_to_le16(byte_count);
3571
3572         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3573                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3574         if (rc) {
3575                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3576         } else {                /* decode response */
3577                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3578
3579                 if (rc || (pSMBr->ByteCount < 24))
3580                         rc = -EIO;      /* bad smb */
3581                 else {
3582                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3583
3584                         response_data =
3585                             (FILE_SYSTEM_INFO
3586                              *) (((char *) &pSMBr->hdr.Protocol) +
3587                                  data_offset);
3588                         FSData->f_bsize =
3589                             le32_to_cpu(response_data->BytesPerSector) *
3590                             le32_to_cpu(response_data->
3591                                         SectorsPerAllocationUnit);
3592                         FSData->f_blocks =
3593                             le64_to_cpu(response_data->TotalAllocationUnits);
3594                         FSData->f_bfree = FSData->f_bavail =
3595                             le64_to_cpu(response_data->FreeAllocationUnits);
3596                         cFYI(1,
3597                              ("Blocks: %lld  Free: %lld Block size %ld",
3598                               (unsigned long long)FSData->f_blocks,
3599                               (unsigned long long)FSData->f_bfree,
3600                               FSData->f_bsize));
3601                 }
3602         }
3603         cifs_buf_release(pSMB);
3604
3605         if (rc == -EAGAIN)
3606                 goto QFSInfoRetry;
3607
3608         return rc;
3609 }
3610
3611 int
3612 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3613 {
3614 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3615         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3616         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3617         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3618         int rc = 0;
3619         int bytes_returned = 0;
3620         __u16 params, byte_count;
3621
3622         cFYI(1, ("In QFSAttributeInfo"));
3623 QFSAttributeRetry:
3624         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3625                       (void **) &pSMBr);
3626         if (rc)
3627                 return rc;
3628
3629         params = 2;     /* level */
3630         pSMB->TotalDataCount = 0;
3631         pSMB->MaxParameterCount = cpu_to_le16(2);
3632         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3633         pSMB->MaxSetupCount = 0;
3634         pSMB->Reserved = 0;
3635         pSMB->Flags = 0;
3636         pSMB->Timeout = 0;
3637         pSMB->Reserved2 = 0;
3638         byte_count = params + 1 /* pad */ ;
3639         pSMB->TotalParameterCount = cpu_to_le16(params);
3640         pSMB->ParameterCount = pSMB->TotalParameterCount;
3641         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3642         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3643         pSMB->DataCount = 0;
3644         pSMB->DataOffset = 0;
3645         pSMB->SetupCount = 1;
3646         pSMB->Reserved3 = 0;
3647         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3648         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3649         pSMB->hdr.smb_buf_length += byte_count;
3650         pSMB->ByteCount = cpu_to_le16(byte_count);
3651
3652         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3653                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3654         if (rc) {
3655                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3656         } else {                /* decode response */
3657                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3658
3659                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3660                         rc = -EIO;      /* bad smb */
3661                 } else {
3662                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3663                         response_data =
3664                             (FILE_SYSTEM_ATTRIBUTE_INFO
3665                              *) (((char *) &pSMBr->hdr.Protocol) +
3666                                  data_offset);
3667                         memcpy(&tcon->fsAttrInfo, response_data,
3668                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3669                 }
3670         }
3671         cifs_buf_release(pSMB);
3672
3673         if (rc == -EAGAIN)
3674                 goto QFSAttributeRetry;
3675
3676         return rc;
3677 }
3678
3679 int
3680 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3681 {
3682 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3683         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3684         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3685         FILE_SYSTEM_DEVICE_INFO *response_data;
3686         int rc = 0;
3687         int bytes_returned = 0;
3688         __u16 params, byte_count;
3689
3690         cFYI(1, ("In QFSDeviceInfo"));
3691 QFSDeviceRetry:
3692         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3693                       (void **) &pSMBr);
3694         if (rc)
3695                 return rc;
3696
3697         params = 2;     /* level */
3698         pSMB->TotalDataCount = 0;
3699         pSMB->MaxParameterCount = cpu_to_le16(2);
3700         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3701         pSMB->MaxSetupCount = 0;
3702         pSMB->Reserved = 0;
3703         pSMB->Flags = 0;
3704         pSMB->Timeout = 0;
3705         pSMB->Reserved2 = 0;
3706         byte_count = params + 1 /* pad */ ;
3707         pSMB->TotalParameterCount = cpu_to_le16(params);
3708         pSMB->ParameterCount = pSMB->TotalParameterCount;
3709         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3710         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3711
3712         pSMB->DataCount = 0;
3713         pSMB->DataOffset = 0;
3714         pSMB->SetupCount = 1;
3715         pSMB->Reserved3 = 0;
3716         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3717         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3718         pSMB->hdr.smb_buf_length += byte_count;
3719         pSMB->ByteCount = cpu_to_le16(byte_count);
3720
3721         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3722                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3723         if (rc) {
3724                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3725         } else {                /* decode response */
3726                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3727
3728                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3729                         rc = -EIO;      /* bad smb */
3730                 else {
3731                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3732                         response_data =
3733                             (FILE_SYSTEM_DEVICE_INFO *)
3734                                 (((char *) &pSMBr->hdr.Protocol) +
3735                                  data_offset);
3736                         memcpy(&tcon->fsDevInfo, response_data,
3737                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3738                 }
3739         }
3740         cifs_buf_release(pSMB);
3741
3742         if (rc == -EAGAIN)
3743                 goto QFSDeviceRetry;
3744
3745         return rc;
3746 }
3747
3748 int
3749 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3750 {
3751 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3752         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3753         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3754         FILE_SYSTEM_UNIX_INFO *response_data;
3755         int rc = 0;
3756         int bytes_returned = 0;
3757         __u16 params, byte_count;
3758
3759         cFYI(1, ("In QFSUnixInfo"));
3760 QFSUnixRetry:
3761         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3762                       (void **) &pSMBr);
3763         if (rc)
3764                 return rc;
3765
3766         params = 2;     /* level */
3767         pSMB->TotalDataCount = 0;
3768         pSMB->DataCount = 0;
3769         pSMB->DataOffset = 0;
3770         pSMB->MaxParameterCount = cpu_to_le16(2);
3771         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3772         pSMB->MaxSetupCount = 0;
3773         pSMB->Reserved = 0;
3774         pSMB->Flags = 0;
3775         pSMB->Timeout = 0;
3776         pSMB->Reserved2 = 0;
3777         byte_count = params + 1 /* pad */ ;
3778         pSMB->ParameterCount = cpu_to_le16(params);
3779         pSMB->TotalParameterCount = pSMB->ParameterCount;
3780         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3781         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3782         pSMB->SetupCount = 1;
3783         pSMB->Reserved3 = 0;
3784         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3785         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3786         pSMB->hdr.smb_buf_length += byte_count;
3787         pSMB->ByteCount = cpu_to_le16(byte_count);
3788
3789         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3790                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3791         if (rc) {
3792                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3793         } else {                /* decode response */
3794                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3795
3796                 if (rc || (pSMBr->ByteCount < 13)) {
3797                         rc = -EIO;      /* bad smb */
3798                 } else {
3799                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3800                         response_data =
3801                             (FILE_SYSTEM_UNIX_INFO
3802                              *) (((char *) &pSMBr->hdr.Protocol) +
3803                                  data_offset);
3804                         memcpy(&tcon->fsUnixInfo, response_data,
3805                                sizeof (FILE_SYSTEM_UNIX_INFO));
3806                 }
3807         }
3808         cifs_buf_release(pSMB);
3809
3810         if (rc == -EAGAIN)
3811                 goto QFSUnixRetry;
3812
3813
3814         return rc;
3815 }
3816
3817 int
3818 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3819 {
3820 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
3821         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3822         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3823         int rc = 0;
3824         int bytes_returned = 0;
3825         __u16 params, param_offset, offset, byte_count;
3826
3827         cFYI(1, ("In SETFSUnixInfo"));
3828 SETFSUnixRetry:
3829         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3830                       (void **) &pSMBr);
3831         if (rc)
3832                 return rc;
3833
3834         params = 4;     /* 2 bytes zero followed by info level. */
3835         pSMB->MaxSetupCount = 0;
3836         pSMB->Reserved = 0;
3837         pSMB->Flags = 0;
3838         pSMB->Timeout = 0;
3839         pSMB->Reserved2 = 0;
3840         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3841         offset = param_offset + params;
3842
3843         pSMB->MaxParameterCount = cpu_to_le16(4);
3844         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3845         pSMB->SetupCount = 1;
3846         pSMB->Reserved3 = 0;
3847         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3848         byte_count = 1 /* pad */ + params + 12;
3849
3850         pSMB->DataCount = cpu_to_le16(12);
3851         pSMB->ParameterCount = cpu_to_le16(params);
3852         pSMB->TotalDataCount = pSMB->DataCount;
3853         pSMB->TotalParameterCount = pSMB->ParameterCount;
3854         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3855         pSMB->DataOffset = cpu_to_le16(offset);
3856
3857         /* Params. */
3858         pSMB->FileNum = 0;
3859         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3860
3861         /* Data. */
3862         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3863         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3864         pSMB->ClientUnixCap = cpu_to_le64(cap);
3865
3866         pSMB->hdr.smb_buf_length += byte_count;
3867         pSMB->ByteCount = cpu_to_le16(byte_count);
3868
3869         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3870                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3871         if (rc) {
3872                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3873         } else {                /* decode response */
3874                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3875                 if (rc) {
3876                         rc = -EIO;      /* bad smb */
3877                 }
3878         }
3879         cifs_buf_release(pSMB);
3880
3881         if (rc == -EAGAIN)
3882                 goto SETFSUnixRetry;
3883
3884         return rc;
3885 }
3886
3887
3888
3889 int
3890 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3891                    struct kstatfs *FSData)
3892 {
3893 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3894         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3895         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3896         FILE_SYSTEM_POSIX_INFO *response_data;
3897         int rc = 0;
3898         int bytes_returned = 0;
3899         __u16 params, byte_count;
3900
3901         cFYI(1, ("In QFSPosixInfo"));
3902 QFSPosixRetry:
3903         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3904                       (void **) &pSMBr);
3905         if (rc)
3906                 return rc;
3907
3908         params = 2;     /* level */
3909         pSMB->TotalDataCount = 0;
3910         pSMB->DataCount = 0;
3911         pSMB->DataOffset = 0;
3912         pSMB->MaxParameterCount = cpu_to_le16(2);
3913         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3914         pSMB->MaxSetupCount = 0;
3915         pSMB->Reserved = 0;
3916         pSMB->Flags = 0;
3917         pSMB->Timeout = 0;
3918         pSMB->Reserved2 = 0;
3919         byte_count = params + 1 /* pad */ ;
3920         pSMB->ParameterCount = cpu_to_le16(params);
3921         pSMB->TotalParameterCount = pSMB->ParameterCount;
3922         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3923         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3924         pSMB->SetupCount = 1;
3925         pSMB->Reserved3 = 0;
3926         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3927         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3928         pSMB->hdr.smb_buf_length += byte_count;
3929         pSMB->ByteCount = cpu_to_le16(byte_count);
3930
3931         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3932                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3933         if (rc) {
3934                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3935         } else {                /* decode response */
3936                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3937
3938                 if (rc || (pSMBr->ByteCount < 13)) {
3939                         rc = -EIO;      /* bad smb */
3940                 } else {
3941                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3942                         response_data =
3943                             (FILE_SYSTEM_POSIX_INFO
3944                              *) (((char *) &pSMBr->hdr.Protocol) +
3945                                  data_offset);
3946                         FSData->f_bsize =
3947                                         le32_to_cpu(response_data->BlockSize);
3948                         FSData->f_blocks =
3949                                         le64_to_cpu(response_data->TotalBlocks);
3950                         FSData->f_bfree =
3951                             le64_to_cpu(response_data->BlocksAvail);
3952                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3953                                 FSData->f_bavail = FSData->f_bfree;
3954                         } else {
3955                                 FSData->f_bavail =
3956                                         le64_to_cpu(response_data->UserBlocksAvail);
3957                         }
3958                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
3959                                 FSData->f_files =
3960                                         le64_to_cpu(response_data->TotalFileNodes);
3961                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
3962                                 FSData->f_ffree =
3963                                         le64_to_cpu(response_data->FreeFileNodes);
3964                 }
3965         }
3966         cifs_buf_release(pSMB);
3967
3968         if (rc == -EAGAIN)
3969                 goto QFSPosixRetry;
3970
3971         return rc;
3972 }
3973
3974
3975 /* We can not use write of zero bytes trick to 
3976    set file size due to need for large file support.  Also note that 
3977    this SetPathInfo is preferred to SetFileInfo based method in next 
3978    routine which is only needed to work around a sharing violation bug
3979    in Samba which this routine can run into */
3980
3981 int
3982 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3983               __u64 size, int SetAllocation, 
3984               const struct nls_table *nls_codepage, int remap)
3985 {
3986         struct smb_com_transaction2_spi_req *pSMB = NULL;
3987         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3988         struct file_end_of_file_info *parm_data;
3989         int name_len;
3990         int rc = 0;
3991         int bytes_returned = 0;
3992         __u16 params, byte_count, data_count, param_offset, offset;
3993
3994         cFYI(1, ("In SetEOF"));
3995 SetEOFRetry:
3996         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3997                       (void **) &pSMBr);
3998         if (rc)
3999                 return rc;
4000
4001         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4002                 name_len =
4003                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4004                                      PATH_MAX, nls_codepage, remap);
4005                 name_len++;     /* trailing null */
4006                 name_len *= 2;
4007         } else {        /* BB improve the check for buffer overruns BB */
4008                 name_len = strnlen(fileName, PATH_MAX);
4009                 name_len++;     /* trailing null */
4010                 strncpy(pSMB->FileName, fileName, name_len);
4011         }
4012         params = 6 + name_len;
4013         data_count = sizeof (struct file_end_of_file_info);
4014         pSMB->MaxParameterCount = cpu_to_le16(2);
4015         pSMB->MaxDataCount = cpu_to_le16(4100);
4016         pSMB->MaxSetupCount = 0;
4017         pSMB->Reserved = 0;
4018         pSMB->Flags = 0;
4019         pSMB->Timeout = 0;
4020         pSMB->Reserved2 = 0;
4021         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4022                                      InformationLevel) - 4;
4023         offset = param_offset + params;
4024         if(SetAllocation) {
4025                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4026                     pSMB->InformationLevel =
4027                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4028                 else
4029                     pSMB->InformationLevel =
4030                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4031         } else /* Set File Size */  {    
4032             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4033                     pSMB->InformationLevel =
4034                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4035             else
4036                     pSMB->InformationLevel =
4037                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4038         }
4039
4040         parm_data =
4041             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4042                                        offset);
4043         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4044         pSMB->DataOffset = cpu_to_le16(offset);
4045         pSMB->SetupCount = 1;
4046         pSMB->Reserved3 = 0;
4047         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4048         byte_count = 3 /* pad */  + params + data_count;
4049         pSMB->DataCount = cpu_to_le16(data_count);
4050         pSMB->TotalDataCount = pSMB->DataCount;
4051         pSMB->ParameterCount = cpu_to_le16(params);
4052         pSMB->TotalParameterCount = pSMB->ParameterCount;
4053         pSMB->Reserved4 = 0;
4054         pSMB->hdr.smb_buf_length += byte_count;
4055         parm_data->FileSize = cpu_to_le64(size);
4056         pSMB->ByteCount = cpu_to_le16(byte_count);
4057         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4058                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4059         if (rc) {
4060                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
4061         }
4062
4063         cifs_buf_release(pSMB);
4064
4065         if (rc == -EAGAIN)
4066                 goto SetEOFRetry;
4067
4068         return rc;
4069 }
4070
4071 int
4072 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
4073                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
4074 {
4075         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4076         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4077         char *data_offset;
4078         struct file_end_of_file_info *parm_data;
4079         int rc = 0;
4080         int bytes_returned = 0;
4081         __u16 params, param_offset, offset, byte_count, count;
4082
4083         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
4084                         (long long)size));
4085         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4086
4087         if (rc)
4088                 return rc;
4089
4090         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4091
4092         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4093         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
4094     
4095         params = 6;
4096         pSMB->MaxSetupCount = 0;
4097         pSMB->Reserved = 0;
4098         pSMB->Flags = 0;
4099         pSMB->Timeout = 0;
4100         pSMB->Reserved2 = 0;
4101         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4102         offset = param_offset + params;
4103
4104         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
4105
4106         count = sizeof(struct file_end_of_file_info);
4107         pSMB->MaxParameterCount = cpu_to_le16(2);
4108         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4109         pSMB->SetupCount = 1;
4110         pSMB->Reserved3 = 0;
4111         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4112         byte_count = 3 /* pad */  + params + count;
4113         pSMB->DataCount = cpu_to_le16(count);
4114         pSMB->ParameterCount = cpu_to_le16(params);
4115         pSMB->TotalDataCount = pSMB->DataCount;
4116         pSMB->TotalParameterCount = pSMB->ParameterCount;
4117         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4118         parm_data =
4119                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
4120                         offset);
4121         pSMB->DataOffset = cpu_to_le16(offset);
4122         parm_data->FileSize = cpu_to_le64(size);
4123         pSMB->Fid = fid;
4124         if(SetAllocation) {
4125                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4126                         pSMB->InformationLevel =
4127                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
4128                 else
4129                         pSMB->InformationLevel =
4130                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
4131         } else /* Set File Size */  {    
4132             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4133                     pSMB->InformationLevel =
4134                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
4135             else
4136                     pSMB->InformationLevel =
4137                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
4138         }
4139         pSMB->Reserved4 = 0;
4140         pSMB->hdr.smb_buf_length += byte_count;
4141         pSMB->ByteCount = cpu_to_le16(byte_count);
4142         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4143                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4144         if (rc) {
4145                 cFYI(1,
4146                      ("Send error in SetFileInfo (SetFileSize) = %d",
4147                       rc));
4148         }
4149
4150         if (pSMB)
4151                 cifs_small_buf_release(pSMB);
4152
4153         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4154                 since file handle passed in no longer valid */
4155
4156         return rc;
4157 }
4158
4159 /* Some legacy servers such as NT4 require that the file times be set on 
4160    an open handle, rather than by pathname - this is awkward due to
4161    potential access conflicts on the open, but it is unavoidable for these
4162    old servers since the only other choice is to go from 100 nanosecond DCE
4163    time and resort to the original setpathinfo level which takes the ancient
4164    DOS time format with 2 second granularity */
4165 int
4166 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
4167                    __u16 fid)
4168 {
4169         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4170         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4171         char *data_offset;
4172         int rc = 0;
4173         int bytes_returned = 0;
4174         __u16 params, param_offset, offset, byte_count, count;
4175
4176         cFYI(1, ("Set Times (via SetFileInfo)"));
4177         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4178
4179         if (rc)
4180                 return rc;
4181
4182         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4183
4184         /* At this point there is no need to override the current pid
4185         with the pid of the opener, but that could change if we someday
4186         use an existing handle (rather than opening one on the fly) */
4187         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4188         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4189     
4190         params = 6;
4191         pSMB->MaxSetupCount = 0;
4192         pSMB->Reserved = 0;
4193         pSMB->Flags = 0;
4194         pSMB->Timeout = 0;
4195         pSMB->Reserved2 = 0;
4196         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4197         offset = param_offset + params;
4198
4199         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4200
4201         count = sizeof (FILE_BASIC_INFO);
4202         pSMB->MaxParameterCount = cpu_to_le16(2);
4203         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4204         pSMB->SetupCount = 1;
4205         pSMB->Reserved3 = 0;
4206         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4207         byte_count = 3 /* pad */  + params + count;
4208         pSMB->DataCount = cpu_to_le16(count);
4209         pSMB->ParameterCount = cpu_to_le16(params);
4210         pSMB->TotalDataCount = pSMB->DataCount;
4211         pSMB->TotalParameterCount = pSMB->ParameterCount;
4212         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4213         pSMB->DataOffset = cpu_to_le16(offset);
4214         pSMB->Fid = fid;
4215         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4216                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4217         else
4218                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4219         pSMB->Reserved4 = 0;
4220         pSMB->hdr.smb_buf_length += byte_count;
4221         pSMB->ByteCount = cpu_to_le16(byte_count);
4222         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4223         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4224                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4225         if (rc) {
4226                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4227         }
4228
4229         cifs_small_buf_release(pSMB);
4230
4231         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4232                 since file handle passed in no longer valid */
4233
4234         return rc;
4235 }
4236
4237
4238 int
4239 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4240                 const FILE_BASIC_INFO * data, 
4241                 const struct nls_table *nls_codepage, int remap)
4242 {
4243         TRANSACTION2_SPI_REQ *pSMB = NULL;
4244         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4245         int name_len;
4246         int rc = 0;
4247         int bytes_returned = 0;
4248         char *data_offset;
4249         __u16 params, param_offset, offset, byte_count, count;
4250
4251         cFYI(1, ("In SetTimes"));
4252
4253 SetTimesRetry:
4254         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4255                       (void **) &pSMBr);
4256         if (rc)
4257                 return rc;
4258
4259         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4260                 name_len =
4261                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4262                                      PATH_MAX, nls_codepage, remap);
4263                 name_len++;     /* trailing null */
4264                 name_len *= 2;
4265         } else {                /* BB improve the check for buffer overruns BB */
4266                 name_len = strnlen(fileName, PATH_MAX);
4267                 name_len++;     /* trailing null */
4268                 strncpy(pSMB->FileName, fileName, name_len);
4269         }
4270
4271         params = 6 + name_len;
4272         count = sizeof (FILE_BASIC_INFO);
4273         pSMB->MaxParameterCount = cpu_to_le16(2);
4274         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4275         pSMB->MaxSetupCount = 0;
4276         pSMB->Reserved = 0;
4277         pSMB->Flags = 0;
4278         pSMB->Timeout = 0;
4279         pSMB->Reserved2 = 0;
4280         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4281                                      InformationLevel) - 4;
4282         offset = param_offset + params;
4283         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4284         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4285         pSMB->DataOffset = cpu_to_le16(offset);
4286         pSMB->SetupCount = 1;
4287         pSMB->Reserved3 = 0;
4288         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4289         byte_count = 3 /* pad */  + params + count;
4290
4291         pSMB->DataCount = cpu_to_le16(count);
4292         pSMB->ParameterCount = cpu_to_le16(params);
4293         pSMB->TotalDataCount = pSMB->DataCount;
4294         pSMB->TotalParameterCount = pSMB->ParameterCount;
4295         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4296                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4297         else
4298                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4299         pSMB->Reserved4 = 0;
4300         pSMB->hdr.smb_buf_length += byte_count;
4301         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4302         pSMB->ByteCount = cpu_to_le16(byte_count);
4303         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4304                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4305         if (rc) {
4306                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4307         }
4308
4309         cifs_buf_release(pSMB);
4310
4311         if (rc == -EAGAIN)
4312                 goto SetTimesRetry;
4313
4314         return rc;
4315 }
4316
4317 /* Can not be used to set time stamps yet (due to old DOS time format) */
4318 /* Can be used to set attributes */
4319 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4320           handling it anyway and NT4 was what we thought it would be needed for
4321           Do not delete it until we prove whether needed for Win9x though */
4322 int
4323 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4324                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4325 {
4326         SETATTR_REQ *pSMB = NULL;
4327         SETATTR_RSP *pSMBr = NULL;
4328         int rc = 0;
4329         int bytes_returned;
4330         int name_len;
4331
4332         cFYI(1, ("In SetAttrLegacy"));
4333
4334 SetAttrLgcyRetry:
4335         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4336                       (void **) &pSMBr);
4337         if (rc)
4338                 return rc;
4339
4340         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4341                 name_len =
4342                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4343                                 PATH_MAX, nls_codepage);
4344                 name_len++;     /* trailing null */
4345                 name_len *= 2;
4346         } else {                /* BB improve the check for buffer overruns BB */
4347                 name_len = strnlen(fileName, PATH_MAX);
4348                 name_len++;     /* trailing null */
4349                 strncpy(pSMB->fileName, fileName, name_len);
4350         }
4351         pSMB->attr = cpu_to_le16(dos_attrs);
4352         pSMB->BufferFormat = 0x04;
4353         pSMB->hdr.smb_buf_length += name_len + 1;
4354         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4355         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4356                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4357         if (rc) {
4358                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4359         }
4360
4361         cifs_buf_release(pSMB);
4362
4363         if (rc == -EAGAIN)
4364                 goto SetAttrLgcyRetry;
4365
4366         return rc;
4367 }
4368 #endif /* temporarily unneeded SetAttr legacy function */
4369
4370 int
4371 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4372                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4373                     dev_t device, const struct nls_table *nls_codepage, 
4374                     int remap)
4375 {
4376         TRANSACTION2_SPI_REQ *pSMB = NULL;
4377         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4378         int name_len;
4379         int rc = 0;
4380         int bytes_returned = 0;
4381         FILE_UNIX_BASIC_INFO *data_offset;
4382         __u16 params, param_offset, offset, count, byte_count;
4383
4384         cFYI(1, ("In SetUID/GID/Mode"));
4385 setPermsRetry:
4386         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4387                       (void **) &pSMBr);
4388         if (rc)
4389                 return rc;
4390
4391         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4392                 name_len =
4393                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4394                                      PATH_MAX, nls_codepage, remap);
4395                 name_len++;     /* trailing null */
4396                 name_len *= 2;
4397         } else {        /* BB improve the check for buffer overruns BB */
4398                 name_len = strnlen(fileName, PATH_MAX);
4399                 name_len++;     /* trailing null */
4400                 strncpy(pSMB->FileName, fileName, name_len);
4401         }
4402
4403         params = 6 + name_len;
4404         count = sizeof (FILE_UNIX_BASIC_INFO);
4405         pSMB->MaxParameterCount = cpu_to_le16(2);
4406         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4407         pSMB->MaxSetupCount = 0;
4408         pSMB->Reserved = 0;
4409         pSMB->Flags = 0;
4410         pSMB->Timeout = 0;
4411         pSMB->Reserved2 = 0;
4412         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4413                                      InformationLevel) - 4;
4414         offset = param_offset + params;
4415         data_offset =
4416             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4417                                       offset);
4418         memset(data_offset, 0, count);
4419         pSMB->DataOffset = cpu_to_le16(offset);
4420         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4421         pSMB->SetupCount = 1;
4422         pSMB->Reserved3 = 0;
4423         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4424         byte_count = 3 /* pad */  + params + count;
4425         pSMB->ParameterCount = cpu_to_le16(params);
4426         pSMB->DataCount = cpu_to_le16(count);
4427         pSMB->TotalParameterCount = pSMB->ParameterCount;
4428         pSMB->TotalDataCount = pSMB->DataCount;
4429         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4430         pSMB->Reserved4 = 0;
4431         pSMB->hdr.smb_buf_length += byte_count;
4432         data_offset->Uid = cpu_to_le64(uid);
4433         data_offset->Gid = cpu_to_le64(gid);
4434         /* better to leave device as zero when it is  */
4435         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4436         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4437         data_offset->Permissions = cpu_to_le64(mode);
4438     
4439         if(S_ISREG(mode))
4440                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4441         else if(S_ISDIR(mode))
4442                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4443         else if(S_ISLNK(mode))
4444                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4445         else if(S_ISCHR(mode))
4446                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4447         else if(S_ISBLK(mode))
4448                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4449         else if(S_ISFIFO(mode))
4450                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4451         else if(S_ISSOCK(mode))
4452                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4453
4454
4455         pSMB->ByteCount = cpu_to_le16(byte_count);
4456         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4457                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4458         if (rc) {
4459                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4460         }
4461
4462         if (pSMB)
4463                 cifs_buf_release(pSMB);
4464         if (rc == -EAGAIN)
4465                 goto setPermsRetry;
4466         return rc;
4467 }
4468
4469 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4470                   const int notify_subdirs, const __u16 netfid,
4471                   __u32 filter, struct file * pfile, int multishot, 
4472                   const struct nls_table *nls_codepage)
4473 {
4474         int rc = 0;
4475         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4476         struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL;
4477         struct dir_notify_req *dnotify_req;
4478         int bytes_returned;
4479
4480         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4481         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4482                       (void **) &pSMBr);
4483         if (rc)
4484                 return rc;
4485
4486         pSMB->TotalParameterCount = 0 ;
4487         pSMB->TotalDataCount = 0;
4488         pSMB->MaxParameterCount = cpu_to_le32(2);
4489         /* BB find exact data count max from sess structure BB */
4490         pSMB->MaxDataCount = 0; /* same in little endian or be */
4491 /* BB VERIFY verify which is correct for above BB */
4492         pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf -
4493                                              MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
4494
4495         pSMB->MaxSetupCount = 4;
4496         pSMB->Reserved = 0;
4497         pSMB->ParameterOffset = 0;
4498         pSMB->DataCount = 0;
4499         pSMB->DataOffset = 0;
4500         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4501         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4502         pSMB->ParameterCount = pSMB->TotalParameterCount;
4503         if(notify_subdirs)
4504                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4505         pSMB->Reserved2 = 0;
4506         pSMB->CompletionFilter = cpu_to_le32(filter);
4507         pSMB->Fid = netfid; /* file handle always le */
4508         pSMB->ByteCount = 0;
4509
4510         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4511                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4512         if (rc) {
4513                 cFYI(1, ("Error in Notify = %d", rc));
4514         } else {
4515                 /* Add file to outstanding requests */
4516                 /* BB change to kmem cache alloc */     
4517                 dnotify_req = (struct dir_notify_req *) kmalloc(
4518                                                 sizeof(struct dir_notify_req),
4519                                                  GFP_KERNEL);
4520                 if(dnotify_req) {
4521                         dnotify_req->Pid = pSMB->hdr.Pid;
4522                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4523                         dnotify_req->Mid = pSMB->hdr.Mid;
4524                         dnotify_req->Tid = pSMB->hdr.Tid;
4525                         dnotify_req->Uid = pSMB->hdr.Uid;
4526                         dnotify_req->netfid = netfid;
4527                         dnotify_req->pfile = pfile;
4528                         dnotify_req->filter = filter;
4529                         dnotify_req->multishot = multishot;
4530                         spin_lock(&GlobalMid_Lock);
4531                         list_add_tail(&dnotify_req->lhead, 
4532                                         &GlobalDnotifyReqList);
4533                         spin_unlock(&GlobalMid_Lock);
4534                 } else 
4535                         rc = -ENOMEM;
4536         }
4537         cifs_buf_release(pSMB);
4538         return rc;      
4539 }
4540 #ifdef CONFIG_CIFS_XATTR
4541 ssize_t
4542 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4543                  const unsigned char *searchName,
4544                  char * EAData, size_t buf_size,
4545                  const struct nls_table *nls_codepage, int remap)
4546 {
4547                 /* BB assumes one setup word */
4548         TRANSACTION2_QPI_REQ *pSMB = NULL;
4549         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4550         int rc = 0;
4551         int bytes_returned;
4552         int name_len;
4553         struct fea * temp_fea;
4554         char * temp_ptr;
4555         __u16 params, byte_count;
4556
4557         cFYI(1, ("In Query All EAs path %s", searchName));
4558 QAllEAsRetry:
4559         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4560                       (void **) &pSMBr);
4561         if (rc)
4562                 return rc;
4563
4564         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4565                 name_len =
4566                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4567                                      PATH_MAX, nls_codepage, remap);
4568                 name_len++;     /* trailing null */
4569                 name_len *= 2;
4570         } else {        /* BB improve the check for buffer overruns BB */
4571                 name_len = strnlen(searchName, PATH_MAX);
4572                 name_len++;     /* trailing null */
4573                 strncpy(pSMB->FileName, searchName, name_len);
4574         }
4575
4576         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4577         pSMB->TotalDataCount = 0;
4578         pSMB->MaxParameterCount = cpu_to_le16(2);
4579         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4580         pSMB->MaxSetupCount = 0;
4581         pSMB->Reserved = 0;
4582         pSMB->Flags = 0;
4583         pSMB->Timeout = 0;
4584         pSMB->Reserved2 = 0;
4585         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4586         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4587         pSMB->DataCount = 0;
4588         pSMB->DataOffset = 0;
4589         pSMB->SetupCount = 1;
4590         pSMB->Reserved3 = 0;
4591         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4592         byte_count = params + 1 /* pad */ ;
4593         pSMB->TotalParameterCount = cpu_to_le16(params);
4594         pSMB->ParameterCount = pSMB->TotalParameterCount;
4595         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4596         pSMB->Reserved4 = 0;
4597         pSMB->hdr.smb_buf_length += byte_count;
4598         pSMB->ByteCount = cpu_to_le16(byte_count);
4599
4600         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4601                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4602         if (rc) {
4603                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4604         } else {                /* decode response */
4605                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4606
4607                 /* BB also check enough total bytes returned */
4608                 /* BB we need to improve the validity checking
4609                 of these trans2 responses */
4610                 if (rc || (pSMBr->ByteCount < 4)) 
4611                         rc = -EIO;      /* bad smb */
4612            /* else if (pFindData){
4613                         memcpy((char *) pFindData,
4614                                (char *) &pSMBr->hdr.Protocol +
4615                                data_offset, kl);
4616                 }*/ else {
4617                         /* check that length of list is not more than bcc */
4618                         /* check that each entry does not go beyond length
4619                            of list */
4620                         /* check that each element of each entry does not
4621                            go beyond end of list */
4622                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4623                         struct fealist * ea_response_data;
4624                         rc = 0;
4625                         /* validate_trans2_offsets() */
4626                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4627                         ea_response_data = (struct fealist *)
4628                                 (((char *) &pSMBr->hdr.Protocol) +
4629                                 data_offset);
4630                         name_len = le32_to_cpu(ea_response_data->list_len);
4631                         cFYI(1,("ea length %d", name_len));
4632                         if(name_len <= 8) {
4633                         /* returned EA size zeroed at top of function */
4634                                 cFYI(1,("empty EA list returned from server"));
4635                         } else {
4636                                 /* account for ea list len */
4637                                 name_len -= 4;
4638                                 temp_fea = ea_response_data->list;
4639                                 temp_ptr = (char *)temp_fea;
4640                                 while(name_len > 0) {
4641                                         __u16 value_len;
4642                                         name_len -= 4;
4643                                         temp_ptr += 4;
4644                                         rc += temp_fea->name_len;
4645                                 /* account for prefix user. and trailing null */
4646                                         rc = rc + 5 + 1; 
4647                                         if(rc<(int)buf_size) {
4648                                                 memcpy(EAData,"user.",5);
4649                                                 EAData+=5;
4650                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4651                                                 EAData+=temp_fea->name_len;
4652                                                 /* null terminate name */
4653                                                 *EAData = 0;
4654                                                 EAData = EAData + 1;
4655                                         } else if(buf_size == 0) {
4656                                                 /* skip copy - calc size only */
4657                                         } else {
4658                                                 /* stop before overrun buffer */
4659                                                 rc = -ERANGE;
4660                                                 break;
4661                                         }
4662                                         name_len -= temp_fea->name_len;
4663                                         temp_ptr += temp_fea->name_len;
4664                                         /* account for trailing null */
4665                                         name_len--;
4666                                         temp_ptr++;
4667                                         value_len = le16_to_cpu(temp_fea->value_len);
4668                                         name_len -= value_len;
4669                                         temp_ptr += value_len;
4670                                         /* BB check that temp_ptr is still within smb BB*/
4671                                 /* no trailing null to account for in value len */
4672                                         /* go on to next EA */
4673                                         temp_fea = (struct fea *)temp_ptr;
4674                                 }
4675                         }
4676                 }
4677         }
4678         if (pSMB)
4679                 cifs_buf_release(pSMB);
4680         if (rc == -EAGAIN)
4681                 goto QAllEAsRetry;
4682
4683         return (ssize_t)rc;
4684 }
4685
4686 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4687                 const unsigned char * searchName,const unsigned char * ea_name,
4688                 unsigned char * ea_value, size_t buf_size, 
4689                 const struct nls_table *nls_codepage, int remap)
4690 {
4691         TRANSACTION2_QPI_REQ *pSMB = NULL;
4692         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4693         int rc = 0;
4694         int bytes_returned;
4695         int name_len;
4696         struct fea * temp_fea;
4697         char * temp_ptr;
4698         __u16 params, byte_count;
4699
4700         cFYI(1, ("In Query EA path %s", searchName));
4701 QEARetry:
4702         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4703                       (void **) &pSMBr);
4704         if (rc)
4705                 return rc;
4706
4707         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4708                 name_len =
4709                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4710                                      PATH_MAX, nls_codepage, remap);
4711                 name_len++;     /* trailing null */
4712                 name_len *= 2;
4713         } else {        /* BB improve the check for buffer overruns BB */
4714                 name_len = strnlen(searchName, PATH_MAX);
4715                 name_len++;     /* trailing null */
4716                 strncpy(pSMB->FileName, searchName, name_len);
4717         }
4718
4719         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4720         pSMB->TotalDataCount = 0;
4721         pSMB->MaxParameterCount = cpu_to_le16(2);
4722         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4723         pSMB->MaxSetupCount = 0;
4724         pSMB->Reserved = 0;
4725         pSMB->Flags = 0;
4726         pSMB->Timeout = 0;
4727         pSMB->Reserved2 = 0;
4728         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4729         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4730         pSMB->DataCount = 0;
4731         pSMB->DataOffset = 0;
4732         pSMB->SetupCount = 1;
4733         pSMB->Reserved3 = 0;
4734         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4735         byte_count = params + 1 /* pad */ ;
4736         pSMB->TotalParameterCount = cpu_to_le16(params);
4737         pSMB->ParameterCount = pSMB->TotalParameterCount;
4738         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4739         pSMB->Reserved4 = 0;
4740         pSMB->hdr.smb_buf_length += byte_count;
4741         pSMB->ByteCount = cpu_to_le16(byte_count);
4742
4743         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4744                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4745         if (rc) {
4746                 cFYI(1, ("Send error in Query EA = %d", rc));
4747         } else {                /* decode response */
4748                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4749
4750                 /* BB also check enough total bytes returned */
4751                 /* BB we need to improve the validity checking
4752                 of these trans2 responses */
4753                 if (rc || (pSMBr->ByteCount < 4)) 
4754                         rc = -EIO;      /* bad smb */
4755            /* else if (pFindData){
4756                         memcpy((char *) pFindData,
4757                                (char *) &pSMBr->hdr.Protocol +
4758                                data_offset, kl);
4759                 }*/ else {
4760                         /* check that length of list is not more than bcc */
4761                         /* check that each entry does not go beyond length
4762                            of list */
4763                         /* check that each element of each entry does not
4764                            go beyond end of list */
4765                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4766                         struct fealist * ea_response_data;
4767                         rc = -ENODATA;
4768                         /* validate_trans2_offsets() */
4769                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4770                         ea_response_data = (struct fealist *)
4771                                 (((char *) &pSMBr->hdr.Protocol) +
4772                                 data_offset);
4773                         name_len = le32_to_cpu(ea_response_data->list_len);
4774                         cFYI(1,("ea length %d", name_len));
4775                         if(name_len <= 8) {
4776                         /* returned EA size zeroed at top of function */
4777                                 cFYI(1,("empty EA list returned from server"));
4778                         } else {
4779                                 /* account for ea list len */
4780                                 name_len -= 4;
4781                                 temp_fea = ea_response_data->list;
4782                                 temp_ptr = (char *)temp_fea;
4783                                 /* loop through checking if we have a matching
4784                                 name and then return the associated value */
4785                                 while(name_len > 0) {
4786                                         __u16 value_len;
4787                                         name_len -= 4;
4788                                         temp_ptr += 4;
4789                                         value_len = le16_to_cpu(temp_fea->value_len);
4790                                 /* BB validate that value_len falls within SMB, 
4791                                 even though maximum for name_len is 255 */ 
4792                                         if(memcmp(temp_fea->name,ea_name,
4793                                                   temp_fea->name_len) == 0) {
4794                                                 /* found a match */
4795                                                 rc = value_len;
4796                                 /* account for prefix user. and trailing null */
4797                                                 if(rc<=(int)buf_size) {
4798                                                         memcpy(ea_value,
4799                                                                 temp_fea->name+temp_fea->name_len+1,
4800                                                                 rc);
4801                                                         /* ea values, unlike ea names,
4802                                                         are not null terminated */
4803                                                 } else if(buf_size == 0) {
4804                                                 /* skip copy - calc size only */
4805                                                 } else {
4806                                                         /* stop before overrun buffer */
4807                                                         rc = -ERANGE;
4808                                                 }
4809                                                 break;
4810                                         }
4811                                         name_len -= temp_fea->name_len;
4812                                         temp_ptr += temp_fea->name_len;
4813                                         /* account for trailing null */
4814                                         name_len--;
4815                                         temp_ptr++;
4816                                         name_len -= value_len;
4817                                         temp_ptr += value_len;
4818                                 /* no trailing null to account for in value len */
4819                                         /* go on to next EA */
4820                                         temp_fea = (struct fea *)temp_ptr;
4821                                 }
4822                         } 
4823                 }
4824         }
4825         if (pSMB)
4826                 cifs_buf_release(pSMB);
4827         if (rc == -EAGAIN)
4828                 goto QEARetry;
4829
4830         return (ssize_t)rc;
4831 }
4832
4833 int
4834 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4835                 const char * ea_name, const void * ea_value, 
4836                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4837                 int remap)
4838 {
4839         struct smb_com_transaction2_spi_req *pSMB = NULL;
4840         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4841         struct fealist *parm_data;
4842         int name_len;
4843         int rc = 0;
4844         int bytes_returned = 0;
4845         __u16 params, param_offset, byte_count, offset, count;
4846
4847         cFYI(1, ("In SetEA"));
4848 SetEARetry:
4849         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4850                       (void **) &pSMBr);
4851         if (rc)
4852                 return rc;
4853
4854         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4855                 name_len =
4856                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4857                                      PATH_MAX, nls_codepage, remap);
4858                 name_len++;     /* trailing null */
4859                 name_len *= 2;
4860         } else {                /* BB improve the check for buffer overruns BB */
4861                 name_len = strnlen(fileName, PATH_MAX);
4862                 name_len++;     /* trailing null */
4863                 strncpy(pSMB->FileName, fileName, name_len);
4864         }
4865
4866         params = 6 + name_len;
4867
4868         /* done calculating parms using name_len of file name,
4869         now use name_len to calculate length of ea name
4870         we are going to create in the inode xattrs */
4871         if(ea_name == NULL)
4872                 name_len = 0;
4873         else
4874                 name_len = strnlen(ea_name,255);
4875
4876         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4877         pSMB->MaxParameterCount = cpu_to_le16(2);
4878         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4879         pSMB->MaxSetupCount = 0;
4880         pSMB->Reserved = 0;
4881         pSMB->Flags = 0;
4882         pSMB->Timeout = 0;
4883         pSMB->Reserved2 = 0;
4884         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4885                                      InformationLevel) - 4;
4886         offset = param_offset + params;
4887         pSMB->InformationLevel =
4888                 cpu_to_le16(SMB_SET_FILE_EA);
4889
4890         parm_data =
4891                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4892                                        offset);
4893         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4894         pSMB->DataOffset = cpu_to_le16(offset);
4895         pSMB->SetupCount = 1;
4896         pSMB->Reserved3 = 0;
4897         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4898         byte_count = 3 /* pad */  + params + count;
4899         pSMB->DataCount = cpu_to_le16(count);
4900         parm_data->list_len = cpu_to_le32(count);
4901         parm_data->list[0].EA_flags = 0;
4902         /* we checked above that name len is less than 255 */
4903         parm_data->list[0].name_len = (__u8)name_len;;
4904         /* EA names are always ASCII */
4905         if(ea_name)
4906                 strncpy(parm_data->list[0].name,ea_name,name_len);
4907         parm_data->list[0].name[name_len] = 0;
4908         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4909         /* caller ensures that ea_value_len is less than 64K but
4910         we need to ensure that it fits within the smb */
4911
4912         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4913         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4914         if(ea_value_len)
4915                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4916
4917         pSMB->TotalDataCount = pSMB->DataCount;
4918         pSMB->ParameterCount = cpu_to_le16(params);
4919         pSMB->TotalParameterCount = pSMB->ParameterCount;
4920         pSMB->Reserved4 = 0;
4921         pSMB->hdr.smb_buf_length += byte_count;
4922         pSMB->ByteCount = cpu_to_le16(byte_count);
4923         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4924                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4925         if (rc) {
4926                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4927         }
4928
4929         cifs_buf_release(pSMB);
4930
4931         if (rc == -EAGAIN)
4932                 goto SetEARetry;
4933
4934         return rc;
4935 }
4936
4937 #endif