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