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