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