Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[pandora-kernel.git] / fs / cifs / cifssmb.c
1 /*
2  *   fs/cifs/cifssmb.c
3  *
4  *   Copyright (C) International Business Machines  Corp., 2002,2005
5  *   Author(s): Steve French (sfrench@us.ibm.com)
6  *
7  *   Contains the routines for constructing the SMB PDUs themselves
8  *
9  *   This library is free software; you can redistribute it and/or modify
10  *   it under the terms of the GNU Lesser General Public License as published
11  *   by the Free Software Foundation; either version 2.1 of the License, or
12  *   (at your option) any later version.
13  *
14  *   This library is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
17  *   the GNU Lesser General Public License for more details.
18  *
19  *   You should have received a copy of the GNU Lesser General Public License
20  *   along with this library; if not, write to the Free Software
21  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  */
23
24  /* SMB/CIFS PDU handling routines here - except for leftovers in connect.c   */
25  /* These are mostly routines that operate on a pathname, or on a tree id     */
26  /* (mounted volume), but there are eight handle based routines which must be */
27  /* treated slightly different for reconnection purposes since we never want  */
28  /* to reuse a stale file handle and the caller knows the file handle */
29
30 #include <linux/fs.h>
31 #include <linux/kernel.h>
32 #include <linux/vfs.h>
33 #include <linux/posix_acl_xattr.h>
34 #include <asm/uaccess.h>
35 #include "cifspdu.h"
36 #include "cifsglob.h"
37 #include "cifsproto.h"
38 #include "cifs_unicode.h"
39 #include "cifs_debug.h"
40
41 #ifdef CONFIG_CIFS_POSIX
42 static struct {
43         int index;
44         char *name;
45 } protocols[] = {
46         {CIFS_PROT, "\2NT LM 0.12"}, 
47         {CIFS_PROT, "\2POSIX 2"},
48         {BAD_PROT, "\2"}
49 };
50 #else
51 static struct {
52         int index;
53         char *name;
54 } protocols[] = {
55         {CIFS_PROT, "\2NT LM 0.12"}, 
56         {BAD_PROT, "\2"}
57 };
58 #endif
59
60
61 /* Mark as invalid, all open files on tree connections since they
62    were closed when session to server was lost */
63 static void mark_open_files_invalid(struct cifsTconInfo * pTcon)
64 {
65         struct cifsFileInfo *open_file = NULL;
66         struct list_head * tmp;
67         struct list_head * tmp1;
68
69 /* list all files open on tree connection and mark them invalid */
70         write_lock(&GlobalSMBSeslock);
71         list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {
72                 open_file = list_entry(tmp,struct cifsFileInfo, tlist);
73                 if(open_file) {
74                         open_file->invalidHandle = TRUE;
75                 }
76         }
77         write_unlock(&GlobalSMBSeslock);
78         /* BB Add call to invalidate_inodes(sb) for all superblocks mounted
79            to this tcon */
80 }
81
82 /* If the return code is zero, this function must fill in request_buf pointer */
83 static int
84 small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon,
85          void **request_buf /* returned */)
86 {
87         int rc = 0;
88
89         /* SMBs NegProt, SessSetup, uLogoff do not have tcon yet so
90            check for tcp and smb session status done differently
91            for those three - in the calling routine */
92         if(tcon) {
93                 if(tcon->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 int
1930 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1931                         const unsigned char *searchName,
1932                         char *symlinkinfo, const int buflen,__u16 fid,
1933                         const struct nls_table *nls_codepage)
1934 {
1935         int rc = 0;
1936         int bytes_returned;
1937         int name_len;
1938         struct smb_com_transaction_ioctl_req * pSMB;
1939         struct smb_com_transaction_ioctl_rsp * pSMBr;
1940
1941         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1942         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1943                       (void **) &pSMBr);
1944         if (rc)
1945                 return rc;
1946
1947         pSMB->TotalParameterCount = 0 ;
1948         pSMB->TotalDataCount = 0;
1949         pSMB->MaxParameterCount = cpu_to_le32(2);
1950         /* BB find exact data count max from sess structure BB */
1951         pSMB->MaxDataCount = cpu_to_le32(4000);
1952         pSMB->MaxSetupCount = 4;
1953         pSMB->Reserved = 0;
1954         pSMB->ParameterOffset = 0;
1955         pSMB->DataCount = 0;
1956         pSMB->DataOffset = 0;
1957         pSMB->SetupCount = 4;
1958         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1959         pSMB->ParameterCount = pSMB->TotalParameterCount;
1960         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1961         pSMB->IsFsctl = 1; /* FSCTL */
1962         pSMB->IsRootFlag = 0;
1963         pSMB->Fid = fid; /* file handle always le */
1964         pSMB->ByteCount = 0;
1965
1966         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1967                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1968         if (rc) {
1969                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1970         } else {                /* decode response */
1971                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1972                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1973                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1974                 /* BB also check enough total bytes returned */
1975                         rc = -EIO;      /* bad smb */
1976                 else {
1977                         if(data_count && (data_count < 2048)) {
1978                                 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1979
1980                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1981                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1982                                 if((char*)reparse_buf >= end_of_smb) {
1983                                         rc = -EIO;
1984                                         goto qreparse_out;
1985                                 }
1986                                 if((reparse_buf->LinkNamesBuf + 
1987                                         reparse_buf->TargetNameOffset +
1988                                         reparse_buf->TargetNameLen) >
1989                                                 end_of_smb) {
1990                                         cFYI(1,("reparse buf extended beyond SMB"));
1991                                         rc = -EIO;
1992                                         goto qreparse_out;
1993                                 }
1994                                 
1995                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1996                                         name_len = UniStrnlen((wchar_t *)
1997                                                         (reparse_buf->LinkNamesBuf + 
1998                                                         reparse_buf->TargetNameOffset),
1999                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
2000                                         cifs_strfromUCS_le(symlinkinfo,
2001                                                 (__le16 *) (reparse_buf->LinkNamesBuf + 
2002                                                 reparse_buf->TargetNameOffset),
2003                                                 name_len, nls_codepage);
2004                                 } else { /* ASCII names */
2005                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
2006                                                 reparse_buf->TargetNameOffset, 
2007                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
2008                                 }
2009                         } else {
2010                                 rc = -EIO;
2011                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
2012                         }
2013                         symlinkinfo[buflen] = 0; /* just in case so the caller
2014                                         does not go off the end of the buffer */
2015                         cFYI(1,("readlink result - %s ",symlinkinfo));
2016                 }
2017         }
2018 qreparse_out:
2019         cifs_buf_release(pSMB);
2020
2021         /* Note: On -EAGAIN error only caller can retry on handle based calls
2022                 since file handle passed in no longer valid */
2023
2024         return rc;
2025 }
2026
2027 #ifdef CONFIG_CIFS_POSIX
2028
2029 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
2030 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
2031 {
2032         /* u8 cifs fields do not need le conversion */
2033         ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm);
2034         ace->e_tag  = cpu_to_le16(cifs_ace->cifs_e_tag);
2035         ace->e_id   = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid));
2036         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
2037
2038         return;
2039 }
2040
2041 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
2042 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
2043                                 const int acl_type,const int size_of_data_area)
2044 {
2045         int size =  0;
2046         int i;
2047         __u16 count;
2048         struct cifs_posix_ace * pACE;
2049         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
2050         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
2051
2052         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
2053                 return -EOPNOTSUPP;
2054
2055         if(acl_type & ACL_TYPE_ACCESS) {
2056                 count = le16_to_cpu(cifs_acl->access_entry_count);
2057                 pACE = &cifs_acl->ace_array[0];
2058                 size = sizeof(struct cifs_posix_acl);
2059                 size += sizeof(struct cifs_posix_ace) * count;
2060                 /* check if we would go beyond end of SMB */
2061                 if(size_of_data_area < size) {
2062                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2063                         return -EINVAL;
2064                 }
2065         } else if(acl_type & ACL_TYPE_DEFAULT) {
2066                 count = le16_to_cpu(cifs_acl->access_entry_count);
2067                 size = sizeof(struct cifs_posix_acl);
2068                 size += sizeof(struct cifs_posix_ace) * count;
2069 /* skip past access ACEs to get to default ACEs */
2070                 pACE = &cifs_acl->ace_array[count];
2071                 count = le16_to_cpu(cifs_acl->default_entry_count);
2072                 size += sizeof(struct cifs_posix_ace) * count;
2073                 /* check if we would go beyond end of SMB */
2074                 if(size_of_data_area < size)
2075                         return -EINVAL;
2076         } else {
2077                 /* illegal type */
2078                 return -EINVAL;
2079         }
2080
2081         size = posix_acl_xattr_size(count);
2082         if((buflen == 0) || (local_acl == NULL)) {
2083                 /* used to query ACL EA size */                         
2084         } else if(size > buflen) {
2085                 return -ERANGE;
2086         } else /* buffer big enough */ {
2087                 local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
2088                 for(i = 0;i < count ;i++) {
2089                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2090                         pACE ++;
2091                 }
2092         }
2093         return size;
2094 }
2095
2096 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2097                         const posix_acl_xattr_entry * local_ace)
2098 {
2099         __u16 rc = 0; /* 0 = ACL converted ok */
2100
2101         cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm);
2102         cifs_ace->cifs_e_tag =  le16_to_cpu(local_ace->e_tag);
2103         /* BB is there a better way to handle the large uid? */
2104         if(local_ace->e_id == cpu_to_le32(-1)) {
2105         /* Probably no need to le convert -1 on any arch but can not hurt */
2106                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2107         } else 
2108                 cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id));
2109         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2110         return rc;
2111 }
2112
2113 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2114 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2115                 const int acl_type)
2116 {
2117         __u16 rc = 0;
2118         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2119         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2120         int count;
2121         int i;
2122
2123         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2124                 return 0;
2125
2126         count = posix_acl_xattr_count((size_t)buflen);
2127         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2128                 count, buflen, le32_to_cpu(local_acl->a_version)));
2129         if(le32_to_cpu(local_acl->a_version) != 2) {
2130                 cFYI(1,("unknown POSIX ACL version %d",
2131                      le32_to_cpu(local_acl->a_version)));
2132                 return 0;
2133         }
2134         cifs_acl->version = cpu_to_le16(1);
2135         if(acl_type == ACL_TYPE_ACCESS) 
2136                 cifs_acl->access_entry_count = cpu_to_le16(count);
2137         else if(acl_type == ACL_TYPE_DEFAULT)
2138                 cifs_acl->default_entry_count = cpu_to_le16(count);
2139         else {
2140                 cFYI(1,("unknown ACL type %d",acl_type));
2141                 return 0;
2142         }
2143         for(i=0;i<count;i++) {
2144                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2145                                         &local_acl->a_entries[i]);
2146                 if(rc != 0) {
2147                         /* ACE not converted */
2148                         break;
2149                 }
2150         }
2151         if(rc == 0) {
2152                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2153                 rc += sizeof(struct cifs_posix_acl);
2154                 /* BB add check to make sure ACL does not overflow SMB */
2155         }
2156         return rc;
2157 }
2158
2159 int
2160 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2161                         const unsigned char *searchName,
2162                         char *acl_inf, const int buflen, const int acl_type,
2163                         const struct nls_table *nls_codepage, int remap)
2164 {
2165 /* SMB_QUERY_POSIX_ACL */
2166         TRANSACTION2_QPI_REQ *pSMB = NULL;
2167         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2168         int rc = 0;
2169         int bytes_returned;
2170         int name_len;
2171         __u16 params, byte_count;
2172                                                                                                                                              
2173         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2174
2175 queryAclRetry:
2176         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2177                 (void **) &pSMBr);
2178         if (rc)
2179                 return rc;
2180                                                                                                                                              
2181         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2182                 name_len =
2183                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2184                                          PATH_MAX, nls_codepage, remap);
2185                 name_len++;     /* trailing null */
2186                 name_len *= 2;
2187                 pSMB->FileName[name_len] = 0;
2188                 pSMB->FileName[name_len+1] = 0;
2189         } else {                /* BB improve the check for buffer overruns BB */
2190                 name_len = strnlen(searchName, PATH_MAX);
2191                 name_len++;     /* trailing null */
2192                 strncpy(pSMB->FileName, searchName, name_len);
2193         }
2194
2195         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2196         pSMB->TotalDataCount = 0;
2197         pSMB->MaxParameterCount = cpu_to_le16(2);
2198         /* BB find exact max data count below from sess structure BB */
2199         pSMB->MaxDataCount = cpu_to_le16(4000);
2200         pSMB->MaxSetupCount = 0;
2201         pSMB->Reserved = 0;
2202         pSMB->Flags = 0;
2203         pSMB->Timeout = 0;
2204         pSMB->Reserved2 = 0;
2205         pSMB->ParameterOffset = cpu_to_le16(
2206                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2207         pSMB->DataCount = 0;
2208         pSMB->DataOffset = 0;
2209         pSMB->SetupCount = 1;
2210         pSMB->Reserved3 = 0;
2211         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2212         byte_count = params + 1 /* pad */ ;
2213         pSMB->TotalParameterCount = cpu_to_le16(params);
2214         pSMB->ParameterCount = pSMB->TotalParameterCount;
2215         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2216         pSMB->Reserved4 = 0;
2217         pSMB->hdr.smb_buf_length += byte_count;
2218         pSMB->ByteCount = cpu_to_le16(byte_count);
2219
2220         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2221                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2222         if (rc) {
2223                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2224         } else {
2225                 /* decode response */
2226  
2227                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2228                 if (rc || (pSMBr->ByteCount < 2))
2229                 /* BB also check enough total bytes returned */
2230                         rc = -EIO;      /* bad smb */
2231                 else {
2232                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2233                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2234                         rc = cifs_copy_posix_acl(acl_inf,
2235                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2236                                 buflen,acl_type,count);
2237                 }
2238         }
2239         cifs_buf_release(pSMB);
2240         if (rc == -EAGAIN)
2241                 goto queryAclRetry;
2242         return rc;
2243 }
2244
2245 int
2246 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2247                         const unsigned char *fileName,
2248                         const char *local_acl, const int buflen, 
2249                         const int acl_type,
2250                         const struct nls_table *nls_codepage, int remap)
2251 {
2252         struct smb_com_transaction2_spi_req *pSMB = NULL;
2253         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2254         char *parm_data;
2255         int name_len;
2256         int rc = 0;
2257         int bytes_returned = 0;
2258         __u16 params, byte_count, data_count, param_offset, offset;
2259
2260         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2261 setAclRetry:
2262         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2263                       (void **) &pSMBr);
2264         if (rc)
2265                 return rc;
2266         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2267                 name_len =
2268                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2269                                       PATH_MAX, nls_codepage, remap);
2270                 name_len++;     /* trailing null */
2271                 name_len *= 2;
2272         } else {                /* BB improve the check for buffer overruns BB */
2273                 name_len = strnlen(fileName, PATH_MAX);
2274                 name_len++;     /* trailing null */
2275                 strncpy(pSMB->FileName, fileName, name_len);
2276         }
2277         params = 6 + name_len;
2278         pSMB->MaxParameterCount = cpu_to_le16(2);
2279         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2280         pSMB->MaxSetupCount = 0;
2281         pSMB->Reserved = 0;
2282         pSMB->Flags = 0;
2283         pSMB->Timeout = 0;
2284         pSMB->Reserved2 = 0;
2285         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2286                                      InformationLevel) - 4;
2287         offset = param_offset + params;
2288         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2289         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2290
2291         /* convert to on the wire format for POSIX ACL */
2292         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2293
2294         if(data_count == 0) {
2295                 rc = -EOPNOTSUPP;
2296                 goto setACLerrorExit;
2297         }
2298         pSMB->DataOffset = cpu_to_le16(offset);
2299         pSMB->SetupCount = 1;
2300         pSMB->Reserved3 = 0;
2301         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2302         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2303         byte_count = 3 /* pad */  + params + data_count;
2304         pSMB->DataCount = cpu_to_le16(data_count);
2305         pSMB->TotalDataCount = pSMB->DataCount;
2306         pSMB->ParameterCount = cpu_to_le16(params);
2307         pSMB->TotalParameterCount = pSMB->ParameterCount;
2308         pSMB->Reserved4 = 0;
2309         pSMB->hdr.smb_buf_length += byte_count;
2310         pSMB->ByteCount = cpu_to_le16(byte_count);
2311         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2312                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2313         if (rc) {
2314                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2315         }
2316
2317 setACLerrorExit:
2318         cifs_buf_release(pSMB);
2319         if (rc == -EAGAIN)
2320                 goto setAclRetry;
2321         return rc;
2322 }
2323
2324 /* BB fix tabs in this function FIXME BB */
2325 int
2326 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2327                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2328 {
2329         int rc = 0;
2330         struct smb_t2_qfi_req *pSMB = NULL;
2331         struct smb_t2_qfi_rsp *pSMBr = NULL;
2332         int bytes_returned;
2333         __u16 params, byte_count;
2334
2335         cFYI(1,("In GetExtAttr"));
2336         if(tcon == NULL)
2337                 return -ENODEV;
2338
2339 GetExtAttrRetry:
2340         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2341                       (void **) &pSMBr);
2342         if (rc)
2343                 return rc;
2344
2345         params = 2 /* level */ +2 /* fid */;
2346         pSMB->t2.TotalDataCount = 0;
2347         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2348         /* BB find exact max data count below from sess structure BB */
2349         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2350         pSMB->t2.MaxSetupCount = 0;
2351         pSMB->t2.Reserved = 0;
2352         pSMB->t2.Flags = 0;
2353         pSMB->t2.Timeout = 0;
2354         pSMB->t2.Reserved2 = 0;
2355         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2356                         Fid) - 4);
2357         pSMB->t2.DataCount = 0;
2358         pSMB->t2.DataOffset = 0;
2359         pSMB->t2.SetupCount = 1;
2360         pSMB->t2.Reserved3 = 0;
2361         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2362         byte_count = params + 1 /* pad */ ;
2363         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2364         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2365         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2366         pSMB->Pad = 0;
2367         pSMB->Fid = netfid;
2368         pSMB->hdr.smb_buf_length += byte_count;
2369         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2370
2371         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2372                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2373         if (rc) {
2374                 cFYI(1, ("error %d in GetExtAttr", rc));
2375         } else {
2376                 /* decode response */
2377                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2378                 if (rc || (pSMBr->ByteCount < 2))
2379                 /* BB also check enough total bytes returned */
2380                         /* If rc should we check for EOPNOSUPP and
2381                         disable the srvino flag? or in caller? */
2382                         rc = -EIO;      /* bad smb */
2383                 else {
2384                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2385                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2386                         struct file_chattr_info * pfinfo;
2387                         /* BB Do we need a cast or hash here ? */
2388                         if(count != 16) {
2389                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2390                                 rc = -EIO;
2391                                 goto GetExtAttrOut;
2392                         }
2393                         pfinfo = (struct file_chattr_info *)
2394                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2395                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2396                         *pMask = le64_to_cpu(pfinfo->mask);
2397                 }
2398         }
2399 GetExtAttrOut:
2400         cifs_buf_release(pSMB);
2401         if (rc == -EAGAIN)
2402                 goto GetExtAttrRetry;
2403         return rc;
2404 }
2405
2406
2407 #endif /* CONFIG_POSIX */
2408
2409 /* Legacy Query Path Information call for lookup to old servers such
2410    as Win9x/WinME */
2411 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2412                  const unsigned char *searchName,
2413                  FILE_ALL_INFO * pFinfo,
2414                  const struct nls_table *nls_codepage, int remap)
2415 {
2416         QUERY_INFORMATION_REQ * pSMB;
2417         QUERY_INFORMATION_RSP * pSMBr;
2418         int rc = 0;
2419         int bytes_returned;
2420         int name_len;
2421
2422         cFYI(1, ("In SMBQPath path %s", searchName)); 
2423 QInfRetry:
2424         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2425                       (void **) &pSMBr);
2426         if (rc)
2427                 return rc;
2428
2429         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2430                 name_len =
2431                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2432                                      PATH_MAX, nls_codepage, remap);
2433                 name_len++;     /* trailing null */
2434                 name_len *= 2;
2435         } else {               
2436                 name_len = strnlen(searchName, PATH_MAX);
2437                 name_len++;     /* trailing null */
2438                 strncpy(pSMB->FileName, searchName, name_len);
2439         }
2440         pSMB->BufferFormat = 0x04;
2441         name_len++; /* account for buffer type byte */  
2442         pSMB->hdr.smb_buf_length += (__u16) name_len;
2443         pSMB->ByteCount = cpu_to_le16(name_len);
2444
2445         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2446                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2447         if (rc) {
2448                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2449         } else if (pFinfo) {            /* decode response */
2450                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2451                 pFinfo->AllocationSize =
2452                         cpu_to_le64(le32_to_cpu(pSMBr->size));
2453                 pFinfo->EndOfFile = pFinfo->AllocationSize;
2454                 pFinfo->Attributes =
2455                         cpu_to_le32(le16_to_cpu(pSMBr->attr));
2456         } else
2457                 rc = -EIO; /* bad buffer passed in */
2458
2459         cifs_buf_release(pSMB);
2460
2461         if (rc == -EAGAIN)
2462                 goto QInfRetry;
2463
2464         return rc;
2465 }
2466
2467
2468
2469
2470 int
2471 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2472                  const unsigned char *searchName,
2473                  FILE_ALL_INFO * pFindData,
2474                  const struct nls_table *nls_codepage, int remap)
2475 {
2476 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2477         TRANSACTION2_QPI_REQ *pSMB = NULL;
2478         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2479         int rc = 0;
2480         int bytes_returned;
2481         int name_len;
2482         __u16 params, byte_count;
2483
2484 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2485 QPathInfoRetry:
2486         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2487                       (void **) &pSMBr);
2488         if (rc)
2489                 return rc;
2490
2491         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2492                 name_len =
2493                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2494                                      PATH_MAX, nls_codepage, remap);
2495                 name_len++;     /* trailing null */
2496                 name_len *= 2;
2497         } else {                /* BB improve the check for buffer overruns BB */
2498                 name_len = strnlen(searchName, PATH_MAX);
2499                 name_len++;     /* trailing null */
2500                 strncpy(pSMB->FileName, searchName, name_len);
2501         }
2502
2503         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2504         pSMB->TotalDataCount = 0;
2505         pSMB->MaxParameterCount = cpu_to_le16(2);
2506         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2507         pSMB->MaxSetupCount = 0;
2508         pSMB->Reserved = 0;
2509         pSMB->Flags = 0;
2510         pSMB->Timeout = 0;
2511         pSMB->Reserved2 = 0;
2512         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2513         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2514         pSMB->DataCount = 0;
2515         pSMB->DataOffset = 0;
2516         pSMB->SetupCount = 1;
2517         pSMB->Reserved3 = 0;
2518         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2519         byte_count = params + 1 /* pad */ ;
2520         pSMB->TotalParameterCount = cpu_to_le16(params);
2521         pSMB->ParameterCount = pSMB->TotalParameterCount;
2522         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2523         pSMB->Reserved4 = 0;
2524         pSMB->hdr.smb_buf_length += byte_count;
2525         pSMB->ByteCount = cpu_to_le16(byte_count);
2526
2527         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2528                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2529         if (rc) {
2530                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2531         } else {                /* decode response */
2532                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2533
2534                 if (rc || (pSMBr->ByteCount < 40)) 
2535                         rc = -EIO;      /* bad smb */
2536                 else if (pFindData){
2537                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2538                         memcpy((char *) pFindData,
2539                                (char *) &pSMBr->hdr.Protocol +
2540                                data_offset, sizeof (FILE_ALL_INFO));
2541                 } else
2542                     rc = -ENOMEM;
2543         }
2544         cifs_buf_release(pSMB);
2545         if (rc == -EAGAIN)
2546                 goto QPathInfoRetry;
2547
2548         return rc;
2549 }
2550
2551 int
2552 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2553                      const unsigned char *searchName,
2554                      FILE_UNIX_BASIC_INFO * pFindData,
2555                      const struct nls_table *nls_codepage, int remap)
2556 {
2557 /* SMB_QUERY_FILE_UNIX_BASIC */
2558         TRANSACTION2_QPI_REQ *pSMB = NULL;
2559         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2560         int rc = 0;
2561         int bytes_returned = 0;
2562         int name_len;
2563         __u16 params, byte_count;
2564
2565         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2566 UnixQPathInfoRetry:
2567         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2568                       (void **) &pSMBr);
2569         if (rc)
2570                 return rc;
2571
2572         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2573                 name_len =
2574                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2575                                   PATH_MAX, nls_codepage, remap);
2576                 name_len++;     /* trailing null */
2577                 name_len *= 2;
2578         } else {                /* BB improve the check for buffer overruns BB */
2579                 name_len = strnlen(searchName, PATH_MAX);
2580                 name_len++;     /* trailing null */
2581                 strncpy(pSMB->FileName, searchName, name_len);
2582         }
2583
2584         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2585         pSMB->TotalDataCount = 0;
2586         pSMB->MaxParameterCount = cpu_to_le16(2);
2587         /* BB find exact max SMB PDU from sess structure BB */
2588         pSMB->MaxDataCount = cpu_to_le16(4000); 
2589         pSMB->MaxSetupCount = 0;
2590         pSMB->Reserved = 0;
2591         pSMB->Flags = 0;
2592         pSMB->Timeout = 0;
2593         pSMB->Reserved2 = 0;
2594         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2595         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2596         pSMB->DataCount = 0;
2597         pSMB->DataOffset = 0;
2598         pSMB->SetupCount = 1;
2599         pSMB->Reserved3 = 0;
2600         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2601         byte_count = params + 1 /* pad */ ;
2602         pSMB->TotalParameterCount = cpu_to_le16(params);
2603         pSMB->ParameterCount = pSMB->TotalParameterCount;
2604         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2605         pSMB->Reserved4 = 0;
2606         pSMB->hdr.smb_buf_length += byte_count;
2607         pSMB->ByteCount = cpu_to_le16(byte_count);
2608
2609         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2610                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2611         if (rc) {
2612                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2613         } else {                /* decode response */
2614                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2615
2616                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2617                         rc = -EIO;      /* bad smb */
2618                 } else {
2619                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2620                         memcpy((char *) pFindData,
2621                                (char *) &pSMBr->hdr.Protocol +
2622                                data_offset,
2623                                sizeof (FILE_UNIX_BASIC_INFO));
2624                 }
2625         }
2626         cifs_buf_release(pSMB);
2627         if (rc == -EAGAIN)
2628                 goto UnixQPathInfoRetry;
2629
2630         return rc;
2631 }
2632
2633 #if 0  /* function unused at present */
2634 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2635                const char *searchName, FILE_ALL_INFO * findData,
2636                const struct nls_table *nls_codepage)
2637 {
2638 /* level 257 SMB_ */
2639         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2640         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2641         int rc = 0;
2642         int bytes_returned;
2643         int name_len;
2644         __u16 params, byte_count;
2645
2646         cFYI(1, ("In FindUnique"));
2647 findUniqueRetry:
2648         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2649                       (void **) &pSMBr);
2650         if (rc)
2651                 return rc;
2652
2653         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2654                 name_len =
2655                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2656                                   /* find define for this maxpathcomponent */
2657                                   , nls_codepage);
2658                 name_len++;     /* trailing null */
2659                 name_len *= 2;
2660         } else {                /* BB improve the check for buffer overruns BB */
2661                 name_len = strnlen(searchName, PATH_MAX);
2662                 name_len++;     /* trailing null */
2663                 strncpy(pSMB->FileName, searchName, name_len);
2664         }
2665
2666         params = 12 + name_len /* includes null */ ;
2667         pSMB->TotalDataCount = 0;       /* no EAs */
2668         pSMB->MaxParameterCount = cpu_to_le16(2);
2669         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2670         pSMB->MaxSetupCount = 0;
2671         pSMB->Reserved = 0;
2672         pSMB->Flags = 0;
2673         pSMB->Timeout = 0;
2674         pSMB->Reserved2 = 0;
2675         pSMB->ParameterOffset = cpu_to_le16(
2676          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2677         pSMB->DataCount = 0;
2678         pSMB->DataOffset = 0;
2679         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2680         pSMB->Reserved3 = 0;
2681         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2682         byte_count = params + 1 /* pad */ ;
2683         pSMB->TotalParameterCount = cpu_to_le16(params);
2684         pSMB->ParameterCount = pSMB->TotalParameterCount;
2685         pSMB->SearchAttributes =
2686             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2687                         ATTR_DIRECTORY);
2688         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2689         pSMB->SearchFlags = cpu_to_le16(1);
2690         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2691         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2692         pSMB->hdr.smb_buf_length += byte_count;
2693         pSMB->ByteCount = cpu_to_le16(byte_count);
2694
2695         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2696                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2697
2698         if (rc) {
2699                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2700         } else {                /* decode response */
2701                 cifs_stats_inc(&tcon->num_ffirst);
2702                 /* BB fill in */
2703         }
2704
2705         cifs_buf_release(pSMB);
2706         if (rc == -EAGAIN)
2707                 goto findUniqueRetry;
2708
2709         return rc;
2710 }
2711 #endif /* end unused (temporarily) function */
2712
2713 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2714 int
2715 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2716               const char *searchName, 
2717               const struct nls_table *nls_codepage,
2718               __u16 *   pnetfid,
2719               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2720 {
2721 /* level 257 SMB_ */
2722         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2723         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2724         T2_FFIRST_RSP_PARMS * parms;
2725         int rc = 0;
2726         int bytes_returned = 0;
2727         int name_len;
2728         __u16 params, byte_count;
2729
2730         cFYI(1, ("In FindFirst for %s",searchName));
2731
2732 findFirstRetry:
2733         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2734                       (void **) &pSMBr);
2735         if (rc)
2736                 return rc;
2737
2738         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2739                 name_len =
2740                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2741                                  PATH_MAX, nls_codepage, remap);
2742                 /* We can not add the asterik earlier in case
2743                 it got remapped to 0xF03A as if it were part of the
2744                 directory name instead of a wildcard */
2745                 name_len *= 2;
2746                 pSMB->FileName[name_len] = dirsep;
2747                 pSMB->FileName[name_len+1] = 0;
2748                 pSMB->FileName[name_len+2] = '*';
2749                 pSMB->FileName[name_len+3] = 0;
2750                 name_len += 4; /* now the trailing null */
2751                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2752                 pSMB->FileName[name_len+1] = 0;
2753                 name_len += 2;
2754         } else {        /* BB add check for overrun of SMB buf BB */
2755                 name_len = strnlen(searchName, PATH_MAX);
2756 /* BB fix here and in unicode clause above ie
2757                 if(name_len > buffersize-header)
2758                         free buffer exit; BB */
2759                 strncpy(pSMB->FileName, searchName, name_len);
2760                 pSMB->FileName[name_len] = dirsep;
2761                 pSMB->FileName[name_len+1] = '*';
2762                 pSMB->FileName[name_len+2] = 0;
2763                 name_len += 3;
2764         }
2765
2766         params = 12 + name_len /* includes null */ ;
2767         pSMB->TotalDataCount = 0;       /* no EAs */
2768         pSMB->MaxParameterCount = cpu_to_le16(10);
2769         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2770                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2771         pSMB->MaxSetupCount = 0;
2772         pSMB->Reserved = 0;
2773         pSMB->Flags = 0;
2774         pSMB->Timeout = 0;
2775         pSMB->Reserved2 = 0;
2776         byte_count = params + 1 /* pad */ ;
2777         pSMB->TotalParameterCount = cpu_to_le16(params);
2778         pSMB->ParameterCount = pSMB->TotalParameterCount;
2779         pSMB->ParameterOffset = cpu_to_le16(
2780           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2781         pSMB->DataCount = 0;
2782         pSMB->DataOffset = 0;
2783         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2784         pSMB->Reserved3 = 0;
2785         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2786         pSMB->SearchAttributes =
2787             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2788                         ATTR_DIRECTORY);
2789         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2790         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2791                 CIFS_SEARCH_RETURN_RESUME);
2792         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2793
2794         /* BB what should we set StorageType to? Does it matter? BB */
2795         pSMB->SearchStorageType = 0;
2796         pSMB->hdr.smb_buf_length += byte_count;
2797         pSMB->ByteCount = cpu_to_le16(byte_count);
2798
2799         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2800                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2801         cifs_stats_inc(&tcon->num_ffirst);
2802
2803         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2804                 /* BB Add code to handle unsupported level rc */
2805                 cFYI(1, ("Error in FindFirst = %d", rc));
2806
2807                 if (pSMB)
2808                         cifs_buf_release(pSMB);
2809
2810                 /* BB eventually could optimize out free and realloc of buf */
2811                 /*    for this case */
2812                 if (rc == -EAGAIN)
2813                         goto findFirstRetry;
2814         } else { /* decode response */
2815                 /* BB remember to free buffer if error BB */
2816                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2817                 if(rc == 0) {
2818                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2819                                 psrch_inf->unicode = TRUE;
2820                         else
2821                                 psrch_inf->unicode = FALSE;
2822
2823                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2824                         psrch_inf->srch_entries_start = 
2825                                 (char *) &pSMBr->hdr.Protocol + 
2826                                         le16_to_cpu(pSMBr->t2.DataOffset);
2827                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2828                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2829
2830                         if(parms->EndofSearch)
2831                                 psrch_inf->endOfSearch = TRUE;
2832                         else
2833                                 psrch_inf->endOfSearch = FALSE;
2834
2835                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2836                         psrch_inf->index_of_last_entry = 
2837                                 psrch_inf->entries_in_buffer;
2838                         *pnetfid = parms->SearchHandle;
2839                 } else {
2840                         cifs_buf_release(pSMB);
2841                 }
2842         }
2843
2844         return rc;
2845 }
2846
2847 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2848             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2849 {
2850         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2851         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2852         T2_FNEXT_RSP_PARMS * parms;
2853         char *response_data;
2854         int rc = 0;
2855         int bytes_returned, name_len;
2856         __u16 params, byte_count;
2857
2858         cFYI(1, ("In FindNext"));
2859
2860         if(psrch_inf->endOfSearch == TRUE)
2861                 return -ENOENT;
2862
2863         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2864                 (void **) &pSMBr);
2865         if (rc)
2866                 return rc;
2867
2868         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2869         byte_count = 0;
2870         pSMB->TotalDataCount = 0;       /* no EAs */
2871         pSMB->MaxParameterCount = cpu_to_le16(8);
2872         pSMB->MaxDataCount =
2873             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2874         pSMB->MaxSetupCount = 0;
2875         pSMB->Reserved = 0;
2876         pSMB->Flags = 0;
2877         pSMB->Timeout = 0;
2878         pSMB->Reserved2 = 0;
2879         pSMB->ParameterOffset =  cpu_to_le16(
2880               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2881         pSMB->DataCount = 0;
2882         pSMB->DataOffset = 0;
2883         pSMB->SetupCount = 1;
2884         pSMB->Reserved3 = 0;
2885         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2886         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2887         pSMB->SearchCount =
2888                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2889         /* test for Unix extensions */
2890 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2891                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2892                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2893         } else {
2894                 pSMB->InformationLevel =
2895                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2896                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2897         } */
2898         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2899         pSMB->ResumeKey = psrch_inf->resume_key;
2900         pSMB->SearchFlags =
2901               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2902
2903         name_len = psrch_inf->resume_name_len;
2904         params += name_len;
2905         if(name_len < PATH_MAX) {
2906                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2907                 byte_count += name_len;
2908                 /* 14 byte parm len above enough for 2 byte null terminator */
2909                 pSMB->ResumeFileName[name_len] = 0;
2910                 pSMB->ResumeFileName[name_len+1] = 0;
2911         } else {
2912                 rc = -EINVAL;
2913                 goto FNext2_err_exit;
2914         }
2915         byte_count = params + 1 /* pad */ ;
2916         pSMB->TotalParameterCount = cpu_to_le16(params);
2917         pSMB->ParameterCount = pSMB->TotalParameterCount;
2918         pSMB->hdr.smb_buf_length += byte_count;
2919         pSMB->ByteCount = cpu_to_le16(byte_count);
2920                                                                                               
2921         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2922                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2923         cifs_stats_inc(&tcon->num_fnext);
2924         if (rc) {
2925                 if (rc == -EBADF) {
2926                         psrch_inf->endOfSearch = TRUE;
2927                         rc = 0; /* search probably was closed at end of search above */
2928                 } else
2929                         cFYI(1, ("FindNext returned = %d", rc));
2930         } else {                /* decode response */
2931                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2932                 
2933                 if(rc == 0) {
2934                         /* BB fixme add lock for file (srch_info) struct here */
2935                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2936                                 psrch_inf->unicode = TRUE;
2937                         else
2938                                 psrch_inf->unicode = FALSE;
2939                         response_data = (char *) &pSMBr->hdr.Protocol +
2940                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2941                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2942                         response_data = (char *)&pSMBr->hdr.Protocol +
2943                                 le16_to_cpu(pSMBr->t2.DataOffset);
2944                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2945                         psrch_inf->srch_entries_start = response_data;
2946                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2947                         if(parms->EndofSearch)
2948                                 psrch_inf->endOfSearch = TRUE;
2949                         else
2950                                 psrch_inf->endOfSearch = FALSE;
2951                                                                                               
2952                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2953                         psrch_inf->index_of_last_entry +=
2954                                 psrch_inf->entries_in_buffer;
2955 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2956
2957                         /* BB fixme add unlock here */
2958                 }
2959
2960         }
2961
2962         /* BB On error, should we leave previous search buf (and count and
2963         last entry fields) intact or free the previous one? */
2964
2965         /* Note: On -EAGAIN error only caller can retry on handle based calls
2966         since file handle passed in no longer valid */
2967 FNext2_err_exit:
2968         if (rc != 0)
2969                 cifs_buf_release(pSMB);
2970                                                                                               
2971         return rc;
2972 }
2973
2974 int
2975 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2976 {
2977         int rc = 0;
2978         FINDCLOSE_REQ *pSMB = NULL;
2979         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2980         int bytes_returned;
2981
2982         cFYI(1, ("In CIFSSMBFindClose"));
2983         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2984
2985         /* no sense returning error if session restarted
2986                 as file handle has been closed */
2987         if(rc == -EAGAIN)
2988                 return 0;
2989         if (rc)
2990                 return rc;
2991
2992         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2993         pSMB->FileID = searchHandle;
2994         pSMB->ByteCount = 0;
2995         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2996                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2997         if (rc) {
2998                 cERROR(1, ("Send error in FindClose = %d", rc));
2999         }
3000         cifs_stats_inc(&tcon->num_fclose);
3001         cifs_small_buf_release(pSMB);
3002
3003         /* Since session is dead, search handle closed on server already */
3004         if (rc == -EAGAIN)
3005                 rc = 0;
3006
3007         return rc;
3008 }
3009
3010 int
3011 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
3012                 const unsigned char *searchName,
3013                 __u64 * inode_number,
3014                 const struct nls_table *nls_codepage, int remap)
3015 {
3016         int rc = 0;
3017         TRANSACTION2_QPI_REQ *pSMB = NULL;
3018         TRANSACTION2_QPI_RSP *pSMBr = NULL;
3019         int name_len, bytes_returned;
3020         __u16 params, byte_count;
3021
3022         cFYI(1,("In GetSrvInodeNum for %s",searchName));
3023         if(tcon == NULL)
3024                 return -ENODEV; 
3025
3026 GetInodeNumberRetry:
3027         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3028                       (void **) &pSMBr);
3029         if (rc)
3030                 return rc;
3031
3032
3033         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3034                 name_len =
3035                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
3036                                 PATH_MAX,nls_codepage, remap);
3037                 name_len++;     /* trailing null */
3038                 name_len *= 2;
3039         } else {                /* BB improve the check for buffer overruns BB */
3040                 name_len = strnlen(searchName, PATH_MAX);
3041                 name_len++;     /* trailing null */
3042                 strncpy(pSMB->FileName, searchName, name_len);
3043         }
3044
3045         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
3046         pSMB->TotalDataCount = 0;
3047         pSMB->MaxParameterCount = cpu_to_le16(2);
3048         /* BB find exact max data count below from sess structure BB */
3049         pSMB->MaxDataCount = cpu_to_le16(4000);
3050         pSMB->MaxSetupCount = 0;
3051         pSMB->Reserved = 0;
3052         pSMB->Flags = 0;
3053         pSMB->Timeout = 0;
3054         pSMB->Reserved2 = 0;
3055         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3056                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
3057         pSMB->DataCount = 0;
3058         pSMB->DataOffset = 0;
3059         pSMB->SetupCount = 1;
3060         pSMB->Reserved3 = 0;
3061         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
3062         byte_count = params + 1 /* pad */ ;
3063         pSMB->TotalParameterCount = cpu_to_le16(params);
3064         pSMB->ParameterCount = pSMB->TotalParameterCount;
3065         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3066         pSMB->Reserved4 = 0;
3067         pSMB->hdr.smb_buf_length += byte_count;
3068         pSMB->ByteCount = cpu_to_le16(byte_count);
3069
3070         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3071                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3072         if (rc) {
3073                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3074         } else {
3075                 /* decode response */
3076                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3077                 if (rc || (pSMBr->ByteCount < 2))
3078                 /* BB also check enough total bytes returned */
3079                         /* If rc should we check for EOPNOSUPP and
3080                         disable the srvino flag? or in caller? */
3081                         rc = -EIO;      /* bad smb */
3082                 else {
3083                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3084                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3085                         struct file_internal_info * pfinfo;
3086                         /* BB Do we need a cast or hash here ? */
3087                         if(count < 8) {
3088                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3089                                 rc = -EIO;
3090                                 goto GetInodeNumOut;
3091                         }
3092                         pfinfo = (struct file_internal_info *)
3093                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3094                         *inode_number = pfinfo->UniqueId;
3095                 }
3096         }
3097 GetInodeNumOut:
3098         cifs_buf_release(pSMB);
3099         if (rc == -EAGAIN)
3100                 goto GetInodeNumberRetry;
3101         return rc;
3102 }
3103
3104 int
3105 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3106                 const unsigned char *searchName,
3107                 unsigned char **targetUNCs,
3108                 unsigned int *number_of_UNC_in_array,
3109                 const struct nls_table *nls_codepage, int remap)
3110 {
3111 /* TRANS2_GET_DFS_REFERRAL */
3112         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3113         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3114         struct dfs_referral_level_3 * referrals = NULL;
3115         int rc = 0;
3116         int bytes_returned;
3117         int name_len;
3118         unsigned int i;
3119         char * temp;
3120         __u16 params, byte_count;
3121         *number_of_UNC_in_array = 0;
3122         *targetUNCs = NULL;
3123
3124         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3125         if (ses == NULL)
3126                 return -ENODEV;
3127 getDFSRetry:
3128         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3129                       (void **) &pSMBr);
3130         if (rc)
3131                 return rc;
3132         
3133         /* server pointer checked in called function, 
3134         but should never be null here anyway */
3135         pSMB->hdr.Mid = GetNextMid(ses->server);
3136         pSMB->hdr.Tid = ses->ipc_tid;
3137         pSMB->hdr.Uid = ses->Suid;
3138         if (ses->capabilities & CAP_STATUS32) {
3139                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3140         }
3141         if (ses->capabilities & CAP_DFS) {
3142                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3143         }
3144
3145         if (ses->capabilities & CAP_UNICODE) {
3146                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3147                 name_len =
3148                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3149                                      searchName, PATH_MAX, nls_codepage, remap);
3150                 name_len++;     /* trailing null */
3151                 name_len *= 2;
3152         } else {                /* BB improve the check for buffer overruns BB */
3153                 name_len = strnlen(searchName, PATH_MAX);
3154                 name_len++;     /* trailing null */
3155                 strncpy(pSMB->RequestFileName, searchName, name_len);
3156         }
3157
3158         params = 2 /* level */  + name_len /*includes null */ ;
3159         pSMB->TotalDataCount = 0;
3160         pSMB->DataCount = 0;
3161         pSMB->DataOffset = 0;
3162         pSMB->MaxParameterCount = 0;
3163         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3164         pSMB->MaxSetupCount = 0;
3165         pSMB->Reserved = 0;
3166         pSMB->Flags = 0;
3167         pSMB->Timeout = 0;
3168         pSMB->Reserved2 = 0;
3169         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3170         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3171         pSMB->SetupCount = 1;
3172         pSMB->Reserved3 = 0;
3173         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3174         byte_count = params + 3 /* pad */ ;
3175         pSMB->ParameterCount = cpu_to_le16(params);
3176         pSMB->TotalParameterCount = pSMB->ParameterCount;
3177         pSMB->MaxReferralLevel = cpu_to_le16(3);
3178         pSMB->hdr.smb_buf_length += byte_count;
3179         pSMB->ByteCount = cpu_to_le16(byte_count);
3180
3181         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3182                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3183         if (rc) {
3184                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3185         } else {                /* decode response */
3186 /* BB Add logic to parse referrals here */
3187                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3188
3189                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3190                         rc = -EIO;      /* bad smb */
3191                 else {
3192                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3193                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3194
3195                         cFYI(1,
3196                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3197                               pSMBr->ByteCount, data_offset));
3198                         referrals = 
3199                             (struct dfs_referral_level_3 *) 
3200                                         (8 /* sizeof start of data block */ +
3201                                         data_offset +
3202                                         (char *) &pSMBr->hdr.Protocol); 
3203                         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",
3204                                 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)));
3205                         /* BB This field is actually two bytes in from start of
3206                            data block so we could do safety check that DataBlock
3207                            begins at address of pSMBr->NumberOfReferrals */
3208                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3209
3210                         /* BB Fix below so can return more than one referral */
3211                         if(*number_of_UNC_in_array > 1)
3212                                 *number_of_UNC_in_array = 1;
3213
3214                         /* get the length of the strings describing refs */
3215                         name_len = 0;
3216                         for(i=0;i<*number_of_UNC_in_array;i++) {
3217                                 /* make sure that DfsPathOffset not past end */
3218                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3219                                 if (offset > data_count) {
3220                                         /* if invalid referral, stop here and do 
3221                                         not try to copy any more */
3222                                         *number_of_UNC_in_array = i;
3223                                         break;
3224                                 } 
3225                                 temp = ((char *)referrals) + offset;
3226
3227                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3228                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3229                                 } else {
3230                                         name_len += strnlen(temp,data_count);
3231                                 }
3232                                 referrals++;
3233                                 /* BB add check that referral pointer does not fall off end PDU */
3234                                 
3235                         }
3236                         /* BB add check for name_len bigger than bcc */
3237                         *targetUNCs = 
3238                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3239                         if(*targetUNCs == NULL) {
3240                                 rc = -ENOMEM;
3241                                 goto GetDFSRefExit;
3242                         }
3243                         /* copy the ref strings */
3244                         referrals =  
3245                             (struct dfs_referral_level_3 *) 
3246                                         (8 /* sizeof data hdr */ +
3247                                         data_offset + 
3248                                         (char *) &pSMBr->hdr.Protocol);
3249
3250                         for(i=0;i<*number_of_UNC_in_array;i++) {
3251                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3252                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3253                                         cifs_strfromUCS_le(*targetUNCs,
3254                                                 (__le16 *) temp, name_len, nls_codepage);
3255                                 } else {
3256                                         strncpy(*targetUNCs,temp,name_len);
3257                                 }
3258                                 /*  BB update target_uncs pointers */
3259                                 referrals++;
3260                         }
3261                         temp = *targetUNCs;
3262                         temp[name_len] = 0;
3263                 }
3264
3265         }
3266 GetDFSRefExit:
3267         if (pSMB)
3268                 cifs_buf_release(pSMB);
3269
3270         if (rc == -EAGAIN)
3271                 goto getDFSRetry;
3272
3273         return rc;
3274 }
3275
3276 /* Query File System Info such as free space to old servers such as Win 9x */
3277 int
3278 SMBOldQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3279 {
3280 /* level 0x01 SMB_QUERY_FILE_SYSTEM_INFO */
3281         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3282         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3283         FILE_SYSTEM_ALLOC_INFO *response_data;
3284         int rc = 0;
3285         int bytes_returned = 0;
3286         __u16 params, byte_count;
3287
3288         cFYI(1, ("OldQFSInfo"));
3289 oldQFSInfoRetry:
3290         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3291                 (void **) &pSMBr);
3292         if (rc)
3293                 return rc;
3294         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3295                       (void **) &pSMBr);
3296         if (rc)
3297                 return rc;
3298
3299         params = 2;     /* level */
3300         pSMB->TotalDataCount = 0;
3301         pSMB->MaxParameterCount = cpu_to_le16(2);
3302         pSMB->MaxDataCount = cpu_to_le16(1000);
3303         pSMB->MaxSetupCount = 0;
3304         pSMB->Reserved = 0;
3305         pSMB->Flags = 0;
3306         pSMB->Timeout = 0;
3307         pSMB->Reserved2 = 0;
3308         byte_count = params + 1 /* pad */ ;
3309         pSMB->TotalParameterCount = cpu_to_le16(params);
3310         pSMB->ParameterCount = pSMB->TotalParameterCount;
3311         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3312         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3313         pSMB->DataCount = 0;
3314         pSMB->DataOffset = 0;
3315         pSMB->SetupCount = 1;
3316         pSMB->Reserved3 = 0;
3317         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3318         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_ALLOCATION);
3319         pSMB->hdr.smb_buf_length += byte_count;
3320         pSMB->ByteCount = cpu_to_le16(byte_count);
3321
3322         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3323                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3324         if (rc) {
3325                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3326         } else {                /* decode response */
3327                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3328
3329                 if (rc || (pSMBr->ByteCount < 18))
3330                         rc = -EIO;      /* bad smb */
3331                 else {
3332                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3333                         cFYI(1,("qfsinf resp BCC: %d  Offset %d",
3334                                  pSMBr->ByteCount, data_offset));
3335
3336                         response_data =
3337                                 (FILE_SYSTEM_ALLOC_INFO *) 
3338                                 (((char *) &pSMBr->hdr.Protocol) + data_offset);
3339                         FSData->f_bsize =
3340                                 le16_to_cpu(response_data->BytesPerSector) *
3341                                 le32_to_cpu(response_data->
3342                                         SectorsPerAllocationUnit);
3343                         FSData->f_blocks =
3344                                 le32_to_cpu(response_data->TotalAllocationUnits);
3345                         FSData->f_bfree = FSData->f_bavail =
3346                                 le32_to_cpu(response_data->FreeAllocationUnits);
3347                         cFYI(1,
3348                              ("Blocks: %lld  Free: %lld Block size %ld",
3349                               (unsigned long long)FSData->f_blocks,
3350                               (unsigned long long)FSData->f_bfree,
3351                               FSData->f_bsize));
3352                 }
3353         }
3354         cifs_buf_release(pSMB);
3355
3356         if (rc == -EAGAIN)
3357                 goto oldQFSInfoRetry;
3358
3359         return rc;
3360 }
3361
3362 int
3363 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3364 {
3365 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3366         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3367         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3368         FILE_SYSTEM_INFO *response_data;
3369         int rc = 0;
3370         int bytes_returned = 0;
3371         __u16 params, byte_count;
3372
3373         cFYI(1, ("In QFSInfo"));
3374 QFSInfoRetry:
3375         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3376                       (void **) &pSMBr);
3377         if (rc)
3378                 return rc;
3379
3380         params = 2;     /* level */
3381         pSMB->TotalDataCount = 0;
3382         pSMB->MaxParameterCount = cpu_to_le16(2);
3383         pSMB->MaxDataCount = cpu_to_le16(1000);
3384         pSMB->MaxSetupCount = 0;
3385         pSMB->Reserved = 0;
3386         pSMB->Flags = 0;
3387         pSMB->Timeout = 0;
3388         pSMB->Reserved2 = 0;
3389         byte_count = params + 1 /* pad */ ;
3390         pSMB->TotalParameterCount = cpu_to_le16(params);
3391         pSMB->ParameterCount = pSMB->TotalParameterCount;
3392         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3393         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3394         pSMB->DataCount = 0;
3395         pSMB->DataOffset = 0;
3396         pSMB->SetupCount = 1;
3397         pSMB->Reserved3 = 0;
3398         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3399         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3400         pSMB->hdr.smb_buf_length += byte_count;
3401         pSMB->ByteCount = cpu_to_le16(byte_count);
3402
3403         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3404                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3405         if (rc) {
3406                 cFYI(1, ("Send error in QFSInfo = %d", rc));
3407         } else {                /* decode response */
3408                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3409
3410                 if (rc || (pSMBr->ByteCount < 24))
3411                         rc = -EIO;      /* bad smb */
3412                 else {
3413                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3414
3415                         response_data =
3416                             (FILE_SYSTEM_INFO
3417                              *) (((char *) &pSMBr->hdr.Protocol) +
3418                                  data_offset);
3419                         FSData->f_bsize =
3420                             le32_to_cpu(response_data->BytesPerSector) *
3421                             le32_to_cpu(response_data->
3422                                         SectorsPerAllocationUnit);
3423                         FSData->f_blocks =
3424                             le64_to_cpu(response_data->TotalAllocationUnits);
3425                         FSData->f_bfree = FSData->f_bavail =
3426                             le64_to_cpu(response_data->FreeAllocationUnits);
3427                         cFYI(1,
3428                              ("Blocks: %lld  Free: %lld Block size %ld",
3429                               (unsigned long long)FSData->f_blocks,
3430                               (unsigned long long)FSData->f_bfree,
3431                               FSData->f_bsize));
3432                 }
3433         }
3434         cifs_buf_release(pSMB);
3435
3436         if (rc == -EAGAIN)
3437                 goto QFSInfoRetry;
3438
3439         return rc;
3440 }
3441
3442 int
3443 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3444 {
3445 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3446         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3447         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3448         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3449         int rc = 0;
3450         int bytes_returned = 0;
3451         __u16 params, byte_count;
3452
3453         cFYI(1, ("In QFSAttributeInfo"));
3454 QFSAttributeRetry:
3455         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3456                       (void **) &pSMBr);
3457         if (rc)
3458                 return rc;
3459
3460         params = 2;     /* level */
3461         pSMB->TotalDataCount = 0;
3462         pSMB->MaxParameterCount = cpu_to_le16(2);
3463         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3464         pSMB->MaxSetupCount = 0;
3465         pSMB->Reserved = 0;
3466         pSMB->Flags = 0;
3467         pSMB->Timeout = 0;
3468         pSMB->Reserved2 = 0;
3469         byte_count = params + 1 /* pad */ ;
3470         pSMB->TotalParameterCount = cpu_to_le16(params);
3471         pSMB->ParameterCount = pSMB->TotalParameterCount;
3472         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3473         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3474         pSMB->DataCount = 0;
3475         pSMB->DataOffset = 0;
3476         pSMB->SetupCount = 1;
3477         pSMB->Reserved3 = 0;
3478         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3479         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3480         pSMB->hdr.smb_buf_length += byte_count;
3481         pSMB->ByteCount = cpu_to_le16(byte_count);
3482
3483         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3484                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3485         if (rc) {
3486                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3487         } else {                /* decode response */
3488                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3489
3490                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3491                         rc = -EIO;      /* bad smb */
3492                 } else {
3493                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3494                         response_data =
3495                             (FILE_SYSTEM_ATTRIBUTE_INFO
3496                              *) (((char *) &pSMBr->hdr.Protocol) +
3497                                  data_offset);
3498                         memcpy(&tcon->fsAttrInfo, response_data,
3499                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3500                 }
3501         }
3502         cifs_buf_release(pSMB);
3503
3504         if (rc == -EAGAIN)
3505                 goto QFSAttributeRetry;
3506
3507         return rc;
3508 }
3509
3510 int
3511 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3512 {
3513 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3514         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3515         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3516         FILE_SYSTEM_DEVICE_INFO *response_data;
3517         int rc = 0;
3518         int bytes_returned = 0;
3519         __u16 params, byte_count;
3520
3521         cFYI(1, ("In QFSDeviceInfo"));
3522 QFSDeviceRetry:
3523         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3524                       (void **) &pSMBr);
3525         if (rc)
3526                 return rc;
3527
3528         params = 2;     /* level */
3529         pSMB->TotalDataCount = 0;
3530         pSMB->MaxParameterCount = cpu_to_le16(2);
3531         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3532         pSMB->MaxSetupCount = 0;
3533         pSMB->Reserved = 0;
3534         pSMB->Flags = 0;
3535         pSMB->Timeout = 0;
3536         pSMB->Reserved2 = 0;
3537         byte_count = params + 1 /* pad */ ;
3538         pSMB->TotalParameterCount = cpu_to_le16(params);
3539         pSMB->ParameterCount = pSMB->TotalParameterCount;
3540         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3541         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3542
3543         pSMB->DataCount = 0;
3544         pSMB->DataOffset = 0;
3545         pSMB->SetupCount = 1;
3546         pSMB->Reserved3 = 0;
3547         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3548         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3549         pSMB->hdr.smb_buf_length += byte_count;
3550         pSMB->ByteCount = cpu_to_le16(byte_count);
3551
3552         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3553                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3554         if (rc) {
3555                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3556         } else {                /* decode response */
3557                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3558
3559                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3560                         rc = -EIO;      /* bad smb */
3561                 else {
3562                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3563                         response_data =
3564                             (FILE_SYSTEM_DEVICE_INFO *)
3565                                 (((char *) &pSMBr->hdr.Protocol) +
3566                                  data_offset);
3567                         memcpy(&tcon->fsDevInfo, response_data,
3568                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3569                 }
3570         }
3571         cifs_buf_release(pSMB);
3572
3573         if (rc == -EAGAIN)
3574                 goto QFSDeviceRetry;
3575
3576         return rc;
3577 }
3578
3579 int
3580 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3581 {
3582 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3583         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3584         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3585         FILE_SYSTEM_UNIX_INFO *response_data;
3586         int rc = 0;
3587         int bytes_returned = 0;
3588         __u16 params, byte_count;
3589
3590         cFYI(1, ("In QFSUnixInfo"));
3591 QFSUnixRetry:
3592         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3593                       (void **) &pSMBr);
3594         if (rc)
3595                 return rc;
3596
3597         params = 2;     /* level */
3598         pSMB->TotalDataCount = 0;
3599         pSMB->DataCount = 0;
3600         pSMB->DataOffset = 0;
3601         pSMB->MaxParameterCount = cpu_to_le16(2);
3602         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3603         pSMB->MaxSetupCount = 0;
3604         pSMB->Reserved = 0;
3605         pSMB->Flags = 0;
3606         pSMB->Timeout = 0;
3607         pSMB->Reserved2 = 0;
3608         byte_count = params + 1 /* pad */ ;
3609         pSMB->ParameterCount = cpu_to_le16(params);
3610         pSMB->TotalParameterCount = pSMB->ParameterCount;
3611         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3612         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3613         pSMB->SetupCount = 1;
3614         pSMB->Reserved3 = 0;
3615         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3616         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3617         pSMB->hdr.smb_buf_length += byte_count;
3618         pSMB->ByteCount = cpu_to_le16(byte_count);
3619
3620         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3621                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3622         if (rc) {
3623                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3624         } else {                /* decode response */
3625                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3626
3627                 if (rc || (pSMBr->ByteCount < 13)) {
3628                         rc = -EIO;      /* bad smb */
3629                 } else {
3630                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3631                         response_data =
3632                             (FILE_SYSTEM_UNIX_INFO
3633                              *) (((char *) &pSMBr->hdr.Protocol) +
3634                                  data_offset);
3635                         memcpy(&tcon->fsUnixInfo, response_data,
3636                                sizeof (FILE_SYSTEM_UNIX_INFO));
3637                 }
3638         }
3639         cifs_buf_release(pSMB);
3640
3641         if (rc == -EAGAIN)
3642                 goto QFSUnixRetry;
3643
3644
3645         return rc;
3646 }
3647
3648 int
3649 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3650 {
3651 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
3652         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3653         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3654         int rc = 0;
3655         int bytes_returned = 0;
3656         __u16 params, param_offset, offset, byte_count;
3657
3658         cFYI(1, ("In SETFSUnixInfo"));
3659 SETFSUnixRetry:
3660         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3661                       (void **) &pSMBr);
3662         if (rc)
3663                 return rc;
3664
3665         params = 4;     /* 2 bytes zero followed by info level. */
3666         pSMB->MaxSetupCount = 0;
3667         pSMB->Reserved = 0;
3668         pSMB->Flags = 0;
3669         pSMB->Timeout = 0;
3670         pSMB->Reserved2 = 0;
3671         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3672         offset = param_offset + params;
3673
3674         pSMB->MaxParameterCount = cpu_to_le16(4);
3675         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3676         pSMB->SetupCount = 1;
3677         pSMB->Reserved3 = 0;
3678         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3679         byte_count = 1 /* pad */ + params + 12;
3680
3681         pSMB->DataCount = cpu_to_le16(12);
3682         pSMB->ParameterCount = cpu_to_le16(params);
3683         pSMB->TotalDataCount = pSMB->DataCount;
3684         pSMB->TotalParameterCount = pSMB->ParameterCount;
3685         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3686         pSMB->DataOffset = cpu_to_le16(offset);
3687
3688         /* Params. */
3689         pSMB->FileNum = 0;
3690         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3691
3692         /* Data. */
3693         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3694         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3695         pSMB->ClientUnixCap = cpu_to_le64(cap);
3696
3697         pSMB->hdr.smb_buf_length += byte_count;
3698         pSMB->ByteCount = cpu_to_le16(byte_count);
3699
3700         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3701                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3702         if (rc) {
3703                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3704         } else {                /* decode response */
3705                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3706                 if (rc) {
3707                         rc = -EIO;      /* bad smb */
3708                 }
3709         }
3710         cifs_buf_release(pSMB);
3711
3712         if (rc == -EAGAIN)
3713                 goto SETFSUnixRetry;
3714
3715         return rc;
3716 }
3717
3718
3719
3720 int
3721 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3722                    struct kstatfs *FSData)
3723 {
3724 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3725         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3726         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3727         FILE_SYSTEM_POSIX_INFO *response_data;
3728         int rc = 0;
3729         int bytes_returned = 0;
3730         __u16 params, byte_count;
3731
3732         cFYI(1, ("In QFSPosixInfo"));
3733 QFSPosixRetry:
3734         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3735                       (void **) &pSMBr);
3736         if (rc)
3737                 return rc;
3738
3739         params = 2;     /* level */
3740         pSMB->TotalDataCount = 0;
3741         pSMB->DataCount = 0;
3742         pSMB->DataOffset = 0;
3743         pSMB->MaxParameterCount = cpu_to_le16(2);
3744         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3745         pSMB->MaxSetupCount = 0;
3746         pSMB->Reserved = 0;
3747         pSMB->Flags = 0;
3748         pSMB->Timeout = 0;
3749         pSMB->Reserved2 = 0;
3750         byte_count = params + 1 /* pad */ ;
3751         pSMB->ParameterCount = cpu_to_le16(params);
3752         pSMB->TotalParameterCount = pSMB->ParameterCount;
3753         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3754         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3755         pSMB->SetupCount = 1;
3756         pSMB->Reserved3 = 0;
3757         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3758         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3759         pSMB->hdr.smb_buf_length += byte_count;
3760         pSMB->ByteCount = cpu_to_le16(byte_count);
3761
3762         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3763                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3764         if (rc) {
3765                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3766         } else {                /* decode response */
3767                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3768
3769                 if (rc || (pSMBr->ByteCount < 13)) {
3770                         rc = -EIO;      /* bad smb */
3771                 } else {
3772                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3773                         response_data =
3774                             (FILE_SYSTEM_POSIX_INFO
3775                              *) (((char *) &pSMBr->hdr.Protocol) +
3776                                  data_offset);
3777                         FSData->f_bsize =
3778                                         le32_to_cpu(response_data->BlockSize);
3779                         FSData->f_blocks =
3780                                         le64_to_cpu(response_data->TotalBlocks);
3781                         FSData->f_bfree =
3782                             le64_to_cpu(response_data->BlocksAvail);
3783                         if(response_data->UserBlocksAvail == cpu_to_le64(-1)) {
3784                                 FSData->f_bavail = FSData->f_bfree;
3785                         } else {
3786                                 FSData->f_bavail =
3787                                         le64_to_cpu(response_data->UserBlocksAvail);
3788                         }
3789                         if(response_data->TotalFileNodes != cpu_to_le64(-1))
3790                                 FSData->f_files =
3791                                         le64_to_cpu(response_data->TotalFileNodes);
3792                         if(response_data->FreeFileNodes != cpu_to_le64(-1))
3793                                 FSData->f_ffree =
3794                                         le64_to_cpu(response_data->FreeFileNodes);
3795                 }
3796         }
3797         cifs_buf_release(pSMB);
3798
3799         if (rc == -EAGAIN)
3800                 goto QFSPosixRetry;
3801
3802         return rc;
3803 }
3804
3805
3806 /* We can not use write of zero bytes trick to 
3807    set file size due to need for large file support.  Also note that 
3808    this SetPathInfo is preferred to SetFileInfo based method in next 
3809    routine which is only needed to work around a sharing violation bug
3810    in Samba which this routine can run into */
3811
3812 int
3813 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3814               __u64 size, int SetAllocation, 
3815               const struct nls_table *nls_codepage, int remap)
3816 {
3817         struct smb_com_transaction2_spi_req *pSMB = NULL;
3818         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3819         struct file_end_of_file_info *parm_data;
3820         int name_len;
3821         int rc = 0;
3822         int bytes_returned = 0;
3823         __u16 params, byte_count, data_count, param_offset, offset;
3824
3825         cFYI(1, ("In SetEOF"));
3826 SetEOFRetry:
3827         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3828                       (void **) &pSMBr);
3829         if (rc)
3830                 return rc;
3831
3832         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3833                 name_len =
3834                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3835                                      PATH_MAX, nls_codepage, remap);
3836                 name_len++;     /* trailing null */
3837                 name_len *= 2;
3838         } else {        /* BB improve the check for buffer overruns BB */
3839                 name_len = strnlen(fileName, PATH_MAX);
3840                 name_len++;     /* trailing null */
3841                 strncpy(pSMB->FileName, fileName, name_len);
3842         }
3843         params = 6 + name_len;
3844         data_count = sizeof (struct file_end_of_file_info);
3845         pSMB->MaxParameterCount = cpu_to_le16(2);
3846         pSMB->MaxDataCount = cpu_to_le16(4100);
3847         pSMB->MaxSetupCount = 0;
3848         pSMB->Reserved = 0;
3849         pSMB->Flags = 0;
3850         pSMB->Timeout = 0;
3851         pSMB->Reserved2 = 0;
3852         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3853                                      InformationLevel) - 4;
3854         offset = param_offset + params;
3855         if(SetAllocation) {
3856                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3857                     pSMB->InformationLevel =
3858                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3859                 else
3860                     pSMB->InformationLevel =
3861                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3862         } else /* Set File Size */  {    
3863             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3864                     pSMB->InformationLevel =
3865                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3866             else
3867                     pSMB->InformationLevel =
3868                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3869         }
3870
3871         parm_data =
3872             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3873                                        offset);
3874         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3875         pSMB->DataOffset = cpu_to_le16(offset);
3876         pSMB->SetupCount = 1;
3877         pSMB->Reserved3 = 0;
3878         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3879         byte_count = 3 /* pad */  + params + data_count;
3880         pSMB->DataCount = cpu_to_le16(data_count);
3881         pSMB->TotalDataCount = pSMB->DataCount;
3882         pSMB->ParameterCount = cpu_to_le16(params);
3883         pSMB->TotalParameterCount = pSMB->ParameterCount;
3884         pSMB->Reserved4 = 0;
3885         pSMB->hdr.smb_buf_length += byte_count;
3886         parm_data->FileSize = cpu_to_le64(size);
3887         pSMB->ByteCount = cpu_to_le16(byte_count);
3888         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3889                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3890         if (rc) {
3891                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3892         }
3893
3894         cifs_buf_release(pSMB);
3895
3896         if (rc == -EAGAIN)
3897                 goto SetEOFRetry;
3898
3899         return rc;
3900 }
3901
3902 int
3903 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3904                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
3905 {
3906         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3907         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3908         char *data_offset;
3909         struct file_end_of_file_info *parm_data;
3910         int rc = 0;
3911         int bytes_returned = 0;
3912         __u16 params, param_offset, offset, byte_count, count;
3913
3914         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3915                         (long long)size));
3916         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3917
3918         if (rc)
3919                 return rc;
3920
3921         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3922
3923         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3924         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3925     
3926         params = 6;
3927         pSMB->MaxSetupCount = 0;
3928         pSMB->Reserved = 0;
3929         pSMB->Flags = 0;
3930         pSMB->Timeout = 0;
3931         pSMB->Reserved2 = 0;
3932         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3933         offset = param_offset + params;
3934
3935         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3936
3937         count = sizeof(struct file_end_of_file_info);
3938         pSMB->MaxParameterCount = cpu_to_le16(2);
3939         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3940         pSMB->SetupCount = 1;
3941         pSMB->Reserved3 = 0;
3942         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3943         byte_count = 3 /* pad */  + params + count;
3944         pSMB->DataCount = cpu_to_le16(count);
3945         pSMB->ParameterCount = cpu_to_le16(params);
3946         pSMB->TotalDataCount = pSMB->DataCount;
3947         pSMB->TotalParameterCount = pSMB->ParameterCount;
3948         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3949         parm_data =
3950                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3951                         offset);
3952         pSMB->DataOffset = cpu_to_le16(offset);
3953         parm_data->FileSize = cpu_to_le64(size);
3954         pSMB->Fid = fid;
3955         if(SetAllocation) {
3956                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3957                         pSMB->InformationLevel =
3958                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3959                 else
3960                         pSMB->InformationLevel =
3961                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3962         } else /* Set File Size */  {    
3963             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3964                     pSMB->InformationLevel =
3965                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3966             else
3967                     pSMB->InformationLevel =
3968                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3969         }
3970         pSMB->Reserved4 = 0;
3971         pSMB->hdr.smb_buf_length += byte_count;
3972         pSMB->ByteCount = cpu_to_le16(byte_count);
3973         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3974                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3975         if (rc) {
3976                 cFYI(1,
3977                      ("Send error in SetFileInfo (SetFileSize) = %d",
3978                       rc));
3979         }
3980
3981         if (pSMB)
3982                 cifs_small_buf_release(pSMB);
3983
3984         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3985                 since file handle passed in no longer valid */
3986
3987         return rc;
3988 }
3989
3990 /* Some legacy servers such as NT4 require that the file times be set on 
3991    an open handle, rather than by pathname - this is awkward due to
3992    potential access conflicts on the open, but it is unavoidable for these
3993    old servers since the only other choice is to go from 100 nanosecond DCE
3994    time and resort to the original setpathinfo level which takes the ancient
3995    DOS time format with 2 second granularity */
3996 int
3997 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
3998                    __u16 fid)
3999 {
4000         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
4001         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
4002         char *data_offset;
4003         int rc = 0;
4004         int bytes_returned = 0;
4005         __u16 params, param_offset, offset, byte_count, count;
4006
4007         cFYI(1, ("Set Times (via SetFileInfo)"));
4008         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
4009
4010         if (rc)
4011                 return rc;
4012
4013         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
4014
4015         /* At this point there is no need to override the current pid
4016         with the pid of the opener, but that could change if we someday
4017         use an existing handle (rather than opening one on the fly) */
4018         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
4019         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
4020     
4021         params = 6;
4022         pSMB->MaxSetupCount = 0;
4023         pSMB->Reserved = 0;
4024         pSMB->Flags = 0;
4025         pSMB->Timeout = 0;
4026         pSMB->Reserved2 = 0;
4027         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
4028         offset = param_offset + params;
4029
4030         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
4031
4032         count = sizeof (FILE_BASIC_INFO);
4033         pSMB->MaxParameterCount = cpu_to_le16(2);
4034         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
4035         pSMB->SetupCount = 1;
4036         pSMB->Reserved3 = 0;
4037         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
4038         byte_count = 3 /* pad */  + params + count;
4039         pSMB->DataCount = cpu_to_le16(count);
4040         pSMB->ParameterCount = cpu_to_le16(params);
4041         pSMB->TotalDataCount = pSMB->DataCount;
4042         pSMB->TotalParameterCount = pSMB->ParameterCount;
4043         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4044         pSMB->DataOffset = cpu_to_le16(offset);
4045         pSMB->Fid = fid;
4046         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4047                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4048         else
4049                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4050         pSMB->Reserved4 = 0;
4051         pSMB->hdr.smb_buf_length += byte_count;
4052         pSMB->ByteCount = cpu_to_le16(byte_count);
4053         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
4054         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4055                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4056         if (rc) {
4057                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
4058         }
4059
4060         cifs_small_buf_release(pSMB);
4061
4062         /* Note: On -EAGAIN error only caller can retry on handle based calls 
4063                 since file handle passed in no longer valid */
4064
4065         return rc;
4066 }
4067
4068
4069 int
4070 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4071                 const FILE_BASIC_INFO * data, 
4072                 const struct nls_table *nls_codepage, int remap)
4073 {
4074         TRANSACTION2_SPI_REQ *pSMB = NULL;
4075         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4076         int name_len;
4077         int rc = 0;
4078         int bytes_returned = 0;
4079         char *data_offset;
4080         __u16 params, param_offset, offset, byte_count, count;
4081
4082         cFYI(1, ("In SetTimes"));
4083
4084 SetTimesRetry:
4085         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4086                       (void **) &pSMBr);
4087         if (rc)
4088                 return rc;
4089
4090         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4091                 name_len =
4092                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
4093                                      PATH_MAX, nls_codepage, remap);
4094                 name_len++;     /* trailing null */
4095                 name_len *= 2;
4096         } else {                /* BB improve the check for buffer overruns BB */
4097                 name_len = strnlen(fileName, PATH_MAX);
4098                 name_len++;     /* trailing null */
4099                 strncpy(pSMB->FileName, fileName, name_len);
4100         }
4101
4102         params = 6 + name_len;
4103         count = sizeof (FILE_BASIC_INFO);
4104         pSMB->MaxParameterCount = cpu_to_le16(2);
4105         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4106         pSMB->MaxSetupCount = 0;
4107         pSMB->Reserved = 0;
4108         pSMB->Flags = 0;
4109         pSMB->Timeout = 0;
4110         pSMB->Reserved2 = 0;
4111         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4112                                      InformationLevel) - 4;
4113         offset = param_offset + params;
4114         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
4115         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4116         pSMB->DataOffset = cpu_to_le16(offset);
4117         pSMB->SetupCount = 1;
4118         pSMB->Reserved3 = 0;
4119         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4120         byte_count = 3 /* pad */  + params + count;
4121
4122         pSMB->DataCount = cpu_to_le16(count);
4123         pSMB->ParameterCount = cpu_to_le16(params);
4124         pSMB->TotalDataCount = pSMB->DataCount;
4125         pSMB->TotalParameterCount = pSMB->ParameterCount;
4126         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
4127                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
4128         else
4129                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
4130         pSMB->Reserved4 = 0;
4131         pSMB->hdr.smb_buf_length += byte_count;
4132         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
4133         pSMB->ByteCount = cpu_to_le16(byte_count);
4134         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4135                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4136         if (rc) {
4137                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
4138         }
4139
4140         cifs_buf_release(pSMB);
4141
4142         if (rc == -EAGAIN)
4143                 goto SetTimesRetry;
4144
4145         return rc;
4146 }
4147
4148 /* Can not be used to set time stamps yet (due to old DOS time format) */
4149 /* Can be used to set attributes */
4150 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4151           handling it anyway and NT4 was what we thought it would be needed for
4152           Do not delete it until we prove whether needed for Win9x though */
4153 int
4154 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4155                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4156 {
4157         SETATTR_REQ *pSMB = NULL;
4158         SETATTR_RSP *pSMBr = NULL;
4159         int rc = 0;
4160         int bytes_returned;
4161         int name_len;
4162
4163         cFYI(1, ("In SetAttrLegacy"));
4164
4165 SetAttrLgcyRetry:
4166         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4167                       (void **) &pSMBr);
4168         if (rc)
4169                 return rc;
4170
4171         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4172                 name_len =
4173                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4174                                 PATH_MAX, nls_codepage);
4175                 name_len++;     /* trailing null */
4176                 name_len *= 2;
4177         } else {                /* BB improve the check for buffer overruns BB */
4178                 name_len = strnlen(fileName, PATH_MAX);
4179                 name_len++;     /* trailing null */
4180                 strncpy(pSMB->fileName, fileName, name_len);
4181         }
4182         pSMB->attr = cpu_to_le16(dos_attrs);
4183         pSMB->BufferFormat = 0x04;
4184         pSMB->hdr.smb_buf_length += name_len + 1;
4185         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4186         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4187                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4188         if (rc) {
4189                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4190         }
4191
4192         cifs_buf_release(pSMB);
4193
4194         if (rc == -EAGAIN)
4195                 goto SetAttrLgcyRetry;
4196
4197         return rc;
4198 }
4199 #endif /* temporarily unneeded SetAttr legacy function */
4200
4201 int
4202 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4203                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4204                     dev_t device, const struct nls_table *nls_codepage, 
4205                     int remap)
4206 {
4207         TRANSACTION2_SPI_REQ *pSMB = NULL;
4208         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4209         int name_len;
4210         int rc = 0;
4211         int bytes_returned = 0;
4212         FILE_UNIX_BASIC_INFO *data_offset;
4213         __u16 params, param_offset, offset, count, byte_count;
4214
4215         cFYI(1, ("In SetUID/GID/Mode"));
4216 setPermsRetry:
4217         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4218                       (void **) &pSMBr);
4219         if (rc)
4220                 return rc;
4221
4222         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4223                 name_len =
4224                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4225                                      PATH_MAX, nls_codepage, remap);
4226                 name_len++;     /* trailing null */
4227                 name_len *= 2;
4228         } else {        /* BB improve the check for buffer overruns BB */
4229                 name_len = strnlen(fileName, PATH_MAX);
4230                 name_len++;     /* trailing null */
4231                 strncpy(pSMB->FileName, fileName, name_len);
4232         }
4233
4234         params = 6 + name_len;
4235         count = sizeof (FILE_UNIX_BASIC_INFO);
4236         pSMB->MaxParameterCount = cpu_to_le16(2);
4237         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4238         pSMB->MaxSetupCount = 0;
4239         pSMB->Reserved = 0;
4240         pSMB->Flags = 0;
4241         pSMB->Timeout = 0;
4242         pSMB->Reserved2 = 0;
4243         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4244                                      InformationLevel) - 4;
4245         offset = param_offset + params;
4246         data_offset =
4247             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4248                                       offset);
4249         memset(data_offset, 0, count);
4250         pSMB->DataOffset = cpu_to_le16(offset);
4251         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4252         pSMB->SetupCount = 1;
4253         pSMB->Reserved3 = 0;
4254         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4255         byte_count = 3 /* pad */  + params + count;
4256         pSMB->ParameterCount = cpu_to_le16(params);
4257         pSMB->DataCount = cpu_to_le16(count);
4258         pSMB->TotalParameterCount = pSMB->ParameterCount;
4259         pSMB->TotalDataCount = pSMB->DataCount;
4260         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4261         pSMB->Reserved4 = 0;
4262         pSMB->hdr.smb_buf_length += byte_count;
4263         data_offset->Uid = cpu_to_le64(uid);
4264         data_offset->Gid = cpu_to_le64(gid);
4265         /* better to leave device as zero when it is  */
4266         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4267         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4268         data_offset->Permissions = cpu_to_le64(mode);
4269     
4270         if(S_ISREG(mode))
4271                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4272         else if(S_ISDIR(mode))
4273                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4274         else if(S_ISLNK(mode))
4275                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4276         else if(S_ISCHR(mode))
4277                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4278         else if(S_ISBLK(mode))
4279                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4280         else if(S_ISFIFO(mode))
4281                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4282         else if(S_ISSOCK(mode))
4283                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4284
4285
4286         pSMB->ByteCount = cpu_to_le16(byte_count);
4287         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4288                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4289         if (rc) {
4290                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4291         }
4292
4293         if (pSMB)
4294                 cifs_buf_release(pSMB);
4295         if (rc == -EAGAIN)
4296                 goto setPermsRetry;
4297         return rc;
4298 }
4299
4300 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4301                   const int notify_subdirs, const __u16 netfid,
4302                   __u32 filter, struct file * pfile, int multishot, 
4303                   const struct nls_table *nls_codepage)
4304 {
4305         int rc = 0;
4306         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4307         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
4308         struct dir_notify_req *dnotify_req;
4309         int bytes_returned;
4310
4311         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4312         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4313                       (void **) &pSMBr);
4314         if (rc)
4315                 return rc;
4316
4317         pSMB->TotalParameterCount = 0 ;
4318         pSMB->TotalDataCount = 0;
4319         pSMB->MaxParameterCount = cpu_to_le32(2);
4320         /* BB find exact data count max from sess structure BB */
4321         pSMB->MaxDataCount = 0; /* same in little endian or be */
4322         pSMB->MaxSetupCount = 4;
4323         pSMB->Reserved = 0;
4324         pSMB->ParameterOffset = 0;
4325         pSMB->DataCount = 0;
4326         pSMB->DataOffset = 0;
4327         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4328         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4329         pSMB->ParameterCount = pSMB->TotalParameterCount;
4330         if(notify_subdirs)
4331                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4332         pSMB->Reserved2 = 0;
4333         pSMB->CompletionFilter = cpu_to_le32(filter);
4334         pSMB->Fid = netfid; /* file handle always le */
4335         pSMB->ByteCount = 0;
4336
4337         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4338                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4339         if (rc) {
4340                 cFYI(1, ("Error in Notify = %d", rc));
4341         } else {
4342                 /* Add file to outstanding requests */
4343                 /* BB change to kmem cache alloc */     
4344                 dnotify_req = (struct dir_notify_req *) kmalloc(
4345                                                 sizeof(struct dir_notify_req),
4346                                                  GFP_KERNEL);
4347                 if(dnotify_req) {
4348                         dnotify_req->Pid = pSMB->hdr.Pid;
4349                         dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4350                         dnotify_req->Mid = pSMB->hdr.Mid;
4351                         dnotify_req->Tid = pSMB->hdr.Tid;
4352                         dnotify_req->Uid = pSMB->hdr.Uid;
4353                         dnotify_req->netfid = netfid;
4354                         dnotify_req->pfile = pfile;
4355                         dnotify_req->filter = filter;
4356                         dnotify_req->multishot = multishot;
4357                         spin_lock(&GlobalMid_Lock);
4358                         list_add_tail(&dnotify_req->lhead, 
4359                                         &GlobalDnotifyReqList);
4360                         spin_unlock(&GlobalMid_Lock);
4361                 } else 
4362                         rc = -ENOMEM;
4363         }
4364         cifs_buf_release(pSMB);
4365         return rc;      
4366 }
4367 #ifdef CONFIG_CIFS_XATTR
4368 ssize_t
4369 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4370                  const unsigned char *searchName,
4371                  char * EAData, size_t buf_size,
4372                  const struct nls_table *nls_codepage, int remap)
4373 {
4374                 /* BB assumes one setup word */
4375         TRANSACTION2_QPI_REQ *pSMB = NULL;
4376         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4377         int rc = 0;
4378         int bytes_returned;
4379         int name_len;
4380         struct fea * temp_fea;
4381         char * temp_ptr;
4382         __u16 params, byte_count;
4383
4384         cFYI(1, ("In Query All EAs path %s", searchName));
4385 QAllEAsRetry:
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, searchName, 
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(searchName, PATH_MAX);
4399                 name_len++;     /* trailing null */
4400                 strncpy(pSMB->FileName, searchName, name_len);
4401         }
4402
4403         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4404         pSMB->TotalDataCount = 0;
4405         pSMB->MaxParameterCount = cpu_to_le16(2);
4406         pSMB->MaxDataCount = cpu_to_le16(4000); /* 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         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4413         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4414         pSMB->DataCount = 0;
4415         pSMB->DataOffset = 0;
4416         pSMB->SetupCount = 1;
4417         pSMB->Reserved3 = 0;
4418         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4419         byte_count = params + 1 /* pad */ ;
4420         pSMB->TotalParameterCount = cpu_to_le16(params);
4421         pSMB->ParameterCount = pSMB->TotalParameterCount;
4422         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4423         pSMB->Reserved4 = 0;
4424         pSMB->hdr.smb_buf_length += byte_count;
4425         pSMB->ByteCount = cpu_to_le16(byte_count);
4426
4427         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4428                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4429         if (rc) {
4430                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4431         } else {                /* decode response */
4432                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4433
4434                 /* BB also check enough total bytes returned */
4435                 /* BB we need to improve the validity checking
4436                 of these trans2 responses */
4437                 if (rc || (pSMBr->ByteCount < 4)) 
4438                         rc = -EIO;      /* bad smb */
4439            /* else if (pFindData){
4440                         memcpy((char *) pFindData,
4441                                (char *) &pSMBr->hdr.Protocol +
4442                                data_offset, kl);
4443                 }*/ else {
4444                         /* check that length of list is not more than bcc */
4445                         /* check that each entry does not go beyond length
4446                            of list */
4447                         /* check that each element of each entry does not
4448                            go beyond end of list */
4449                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4450                         struct fealist * ea_response_data;
4451                         rc = 0;
4452                         /* validate_trans2_offsets() */
4453                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4454                         ea_response_data = (struct fealist *)
4455                                 (((char *) &pSMBr->hdr.Protocol) +
4456                                 data_offset);
4457                         name_len = le32_to_cpu(ea_response_data->list_len);
4458                         cFYI(1,("ea length %d", name_len));
4459                         if(name_len <= 8) {
4460                         /* returned EA size zeroed at top of function */
4461                                 cFYI(1,("empty EA list returned from server"));
4462                         } else {
4463                                 /* account for ea list len */
4464                                 name_len -= 4;
4465                                 temp_fea = ea_response_data->list;
4466                                 temp_ptr = (char *)temp_fea;
4467                                 while(name_len > 0) {
4468                                         __u16 value_len;
4469                                         name_len -= 4;
4470                                         temp_ptr += 4;
4471                                         rc += temp_fea->name_len;
4472                                 /* account for prefix user. and trailing null */
4473                                         rc = rc + 5 + 1; 
4474                                         if(rc<(int)buf_size) {
4475                                                 memcpy(EAData,"user.",5);
4476                                                 EAData+=5;
4477                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4478                                                 EAData+=temp_fea->name_len;
4479                                                 /* null terminate name */
4480                                                 *EAData = 0;
4481                                                 EAData = EAData + 1;
4482                                         } else if(buf_size == 0) {
4483                                                 /* skip copy - calc size only */
4484                                         } else {
4485                                                 /* stop before overrun buffer */
4486                                                 rc = -ERANGE;
4487                                                 break;
4488                                         }
4489                                         name_len -= temp_fea->name_len;
4490                                         temp_ptr += temp_fea->name_len;
4491                                         /* account for trailing null */
4492                                         name_len--;
4493                                         temp_ptr++;
4494                                         value_len = le16_to_cpu(temp_fea->value_len);
4495                                         name_len -= value_len;
4496                                         temp_ptr += value_len;
4497                                         /* BB check that temp_ptr is still within smb BB*/
4498                                 /* no trailing null to account for in value len */
4499                                         /* go on to next EA */
4500                                         temp_fea = (struct fea *)temp_ptr;
4501                                 }
4502                         }
4503                 }
4504         }
4505         if (pSMB)
4506                 cifs_buf_release(pSMB);
4507         if (rc == -EAGAIN)
4508                 goto QAllEAsRetry;
4509
4510         return (ssize_t)rc;
4511 }
4512
4513 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4514                 const unsigned char * searchName,const unsigned char * ea_name,
4515                 unsigned char * ea_value, size_t buf_size, 
4516                 const struct nls_table *nls_codepage, int remap)
4517 {
4518         TRANSACTION2_QPI_REQ *pSMB = NULL;
4519         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4520         int rc = 0;
4521         int bytes_returned;
4522         int name_len;
4523         struct fea * temp_fea;
4524         char * temp_ptr;
4525         __u16 params, byte_count;
4526
4527         cFYI(1, ("In Query EA path %s", searchName));
4528 QEARetry:
4529         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4530                       (void **) &pSMBr);
4531         if (rc)
4532                 return rc;
4533
4534         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4535                 name_len =
4536                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4537                                      PATH_MAX, nls_codepage, remap);
4538                 name_len++;     /* trailing null */
4539                 name_len *= 2;
4540         } else {        /* BB improve the check for buffer overruns BB */
4541                 name_len = strnlen(searchName, PATH_MAX);
4542                 name_len++;     /* trailing null */
4543                 strncpy(pSMB->FileName, searchName, name_len);
4544         }
4545
4546         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4547         pSMB->TotalDataCount = 0;
4548         pSMB->MaxParameterCount = cpu_to_le16(2);
4549         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4550         pSMB->MaxSetupCount = 0;
4551         pSMB->Reserved = 0;
4552         pSMB->Flags = 0;
4553         pSMB->Timeout = 0;
4554         pSMB->Reserved2 = 0;
4555         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4556         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4557         pSMB->DataCount = 0;
4558         pSMB->DataOffset = 0;
4559         pSMB->SetupCount = 1;
4560         pSMB->Reserved3 = 0;
4561         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4562         byte_count = params + 1 /* pad */ ;
4563         pSMB->TotalParameterCount = cpu_to_le16(params);
4564         pSMB->ParameterCount = pSMB->TotalParameterCount;
4565         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4566         pSMB->Reserved4 = 0;
4567         pSMB->hdr.smb_buf_length += byte_count;
4568         pSMB->ByteCount = cpu_to_le16(byte_count);
4569
4570         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4571                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4572         if (rc) {
4573                 cFYI(1, ("Send error in Query EA = %d", rc));
4574         } else {                /* decode response */
4575                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4576
4577                 /* BB also check enough total bytes returned */
4578                 /* BB we need to improve the validity checking
4579                 of these trans2 responses */
4580                 if (rc || (pSMBr->ByteCount < 4)) 
4581                         rc = -EIO;      /* bad smb */
4582            /* else if (pFindData){
4583                         memcpy((char *) pFindData,
4584                                (char *) &pSMBr->hdr.Protocol +
4585                                data_offset, kl);
4586                 }*/ else {
4587                         /* check that length of list is not more than bcc */
4588                         /* check that each entry does not go beyond length
4589                            of list */
4590                         /* check that each element of each entry does not
4591                            go beyond end of list */
4592                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4593                         struct fealist * ea_response_data;
4594                         rc = -ENODATA;
4595                         /* validate_trans2_offsets() */
4596                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4597                         ea_response_data = (struct fealist *)
4598                                 (((char *) &pSMBr->hdr.Protocol) +
4599                                 data_offset);
4600                         name_len = le32_to_cpu(ea_response_data->list_len);
4601                         cFYI(1,("ea length %d", name_len));
4602                         if(name_len <= 8) {
4603                         /* returned EA size zeroed at top of function */
4604                                 cFYI(1,("empty EA list returned from server"));
4605                         } else {
4606                                 /* account for ea list len */
4607                                 name_len -= 4;
4608                                 temp_fea = ea_response_data->list;
4609                                 temp_ptr = (char *)temp_fea;
4610                                 /* loop through checking if we have a matching
4611                                 name and then return the associated value */
4612                                 while(name_len > 0) {
4613                                         __u16 value_len;
4614                                         name_len -= 4;
4615                                         temp_ptr += 4;
4616                                         value_len = le16_to_cpu(temp_fea->value_len);
4617                                 /* BB validate that value_len falls within SMB, 
4618                                 even though maximum for name_len is 255 */ 
4619                                         if(memcmp(temp_fea->name,ea_name,
4620                                                   temp_fea->name_len) == 0) {
4621                                                 /* found a match */
4622                                                 rc = value_len;
4623                                 /* account for prefix user. and trailing null */
4624                                                 if(rc<=(int)buf_size) {
4625                                                         memcpy(ea_value,
4626                                                                 temp_fea->name+temp_fea->name_len+1,
4627                                                                 rc);
4628                                                         /* ea values, unlike ea names,
4629                                                         are not null terminated */
4630                                                 } else if(buf_size == 0) {
4631                                                 /* skip copy - calc size only */
4632                                                 } else {
4633                                                         /* stop before overrun buffer */
4634                                                         rc = -ERANGE;
4635                                                 }
4636                                                 break;
4637                                         }
4638                                         name_len -= temp_fea->name_len;
4639                                         temp_ptr += temp_fea->name_len;
4640                                         /* account for trailing null */
4641                                         name_len--;
4642                                         temp_ptr++;
4643                                         name_len -= value_len;
4644                                         temp_ptr += value_len;
4645                                 /* no trailing null to account for in value len */
4646                                         /* go on to next EA */
4647                                         temp_fea = (struct fea *)temp_ptr;
4648                                 }
4649                         } 
4650                 }
4651         }
4652         if (pSMB)
4653                 cifs_buf_release(pSMB);
4654         if (rc == -EAGAIN)
4655                 goto QEARetry;
4656
4657         return (ssize_t)rc;
4658 }
4659
4660 int
4661 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4662                 const char * ea_name, const void * ea_value, 
4663                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4664                 int remap)
4665 {
4666         struct smb_com_transaction2_spi_req *pSMB = NULL;
4667         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4668         struct fealist *parm_data;
4669         int name_len;
4670         int rc = 0;
4671         int bytes_returned = 0;
4672         __u16 params, param_offset, byte_count, offset, count;
4673
4674         cFYI(1, ("In SetEA"));
4675 SetEARetry:
4676         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4677                       (void **) &pSMBr);
4678         if (rc)
4679                 return rc;
4680
4681         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4682                 name_len =
4683                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4684                                      PATH_MAX, nls_codepage, remap);
4685                 name_len++;     /* trailing null */
4686                 name_len *= 2;
4687         } else {                /* BB improve the check for buffer overruns BB */
4688                 name_len = strnlen(fileName, PATH_MAX);
4689                 name_len++;     /* trailing null */
4690                 strncpy(pSMB->FileName, fileName, name_len);
4691         }
4692
4693         params = 6 + name_len;
4694
4695         /* done calculating parms using name_len of file name,
4696         now use name_len to calculate length of ea name
4697         we are going to create in the inode xattrs */
4698         if(ea_name == NULL)
4699                 name_len = 0;
4700         else
4701                 name_len = strnlen(ea_name,255);
4702
4703         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4704         pSMB->MaxParameterCount = cpu_to_le16(2);
4705         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4706         pSMB->MaxSetupCount = 0;
4707         pSMB->Reserved = 0;
4708         pSMB->Flags = 0;
4709         pSMB->Timeout = 0;
4710         pSMB->Reserved2 = 0;
4711         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4712                                      InformationLevel) - 4;
4713         offset = param_offset + params;
4714         pSMB->InformationLevel =
4715                 cpu_to_le16(SMB_SET_FILE_EA);
4716
4717         parm_data =
4718                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4719                                        offset);
4720         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4721         pSMB->DataOffset = cpu_to_le16(offset);
4722         pSMB->SetupCount = 1;
4723         pSMB->Reserved3 = 0;
4724         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4725         byte_count = 3 /* pad */  + params + count;
4726         pSMB->DataCount = cpu_to_le16(count);
4727         parm_data->list_len = cpu_to_le32(count);
4728         parm_data->list[0].EA_flags = 0;
4729         /* we checked above that name len is less than 255 */
4730         parm_data->list[0].name_len = (__u8)name_len;;
4731         /* EA names are always ASCII */
4732         if(ea_name)
4733                 strncpy(parm_data->list[0].name,ea_name,name_len);
4734         parm_data->list[0].name[name_len] = 0;
4735         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4736         /* caller ensures that ea_value_len is less than 64K but
4737         we need to ensure that it fits within the smb */
4738
4739         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4740         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4741         if(ea_value_len)
4742                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4743
4744         pSMB->TotalDataCount = pSMB->DataCount;
4745         pSMB->ParameterCount = cpu_to_le16(params);
4746         pSMB->TotalParameterCount = pSMB->ParameterCount;
4747         pSMB->Reserved4 = 0;
4748         pSMB->hdr.smb_buf_length += byte_count;
4749         pSMB->ByteCount = cpu_to_le16(byte_count);
4750         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4751                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4752         if (rc) {
4753                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4754         }
4755
4756         cifs_buf_release(pSMB);
4757
4758         if (rc == -EAGAIN)
4759                 goto SetEARetry;
4760
4761         return rc;
4762 }
4763
4764 #endif