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