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