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