[CIFS] Add support for legacy servers part 5
[linux-2.6] / 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 /* If no buffer passed in, then caller wants to do the copy
927         as in the case of readpages so the SMB buffer must be
928         freed by the caller */
929
930 int
931 CIFSSMBRead(const int xid, struct cifsTconInfo *tcon,
932             const int netfid, const unsigned int count,
933             const __u64 lseek, unsigned int *nbytes, char **buf)
934 {
935         int rc = -EACCES;
936         READ_REQ *pSMB = NULL;
937         READ_RSP *pSMBr = NULL;
938         char *pReadData = NULL;
939         int bytes_returned;
940         int wct;
941
942         cFYI(1,("Reading %d bytes on fid %d",count,netfid));
943         if(tcon->ses->capabilities & CAP_LARGE_FILES)
944                 wct = 12;
945         else
946                 wct = 10; /* old style read */
947
948         *nbytes = 0;
949         rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB,
950                       (void **) &pSMBr);
951         if (rc)
952                 return rc;
953
954         /* tcon and ses pointer are checked in smb_init */
955         if (tcon->ses->server == NULL)
956                 return -ECONNABORTED;
957
958         pSMB->AndXCommand = 0xFF;       /* none */
959         pSMB->Fid = netfid;
960         pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF);
961         if(wct == 12)
962                 pSMB->OffsetHigh = cpu_to_le32(lseek >> 32);
963         else if((lseek >> 32) > 0) /* can not handle this big offset for old */
964                 return -EIO;
965
966         pSMB->Remaining = 0;
967         pSMB->MaxCount = cpu_to_le16(count & 0xFFFF);
968         pSMB->MaxCountHigh = cpu_to_le32(count >> 16);
969         if(wct == 12)
970                 pSMB->ByteCount = 0;  /* no need to do le conversion since 0 */
971         else {
972                 /* old style read */
973                 struct smb_com_readx_req * pSMBW = 
974                         (struct smb_com_readx_req *)pSMB;
975                 pSMBW->ByteCount = 0;   
976         }
977         
978         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
979                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
980         cifs_stats_inc(&tcon->num_reads);
981         if (rc) {
982                 cERROR(1, ("Send error in read = %d", rc));
983         } else {
984                 int data_length = le16_to_cpu(pSMBr->DataLengthHigh);
985                 data_length = data_length << 16;
986                 data_length += le16_to_cpu(pSMBr->DataLength);
987                 *nbytes = data_length;
988
989                 /*check that DataLength would not go beyond end of SMB */
990                 if ((data_length > CIFSMaxBufSize) 
991                                 || (data_length > count)) {
992                         cFYI(1,("bad length %d for count %d",data_length,count));
993                         rc = -EIO;
994                         *nbytes = 0;
995                 } else {
996                         pReadData =
997                             (char *) (&pSMBr->hdr.Protocol) +
998                             le16_to_cpu(pSMBr->DataOffset);
999 /*                      if(rc = copy_to_user(buf, pReadData, data_length)) {
1000                                 cERROR(1,("Faulting on read rc = %d",rc));
1001                                 rc = -EFAULT;
1002                         }*/ /* can not use copy_to_user when using page cache*/
1003                         if(*buf)
1004                             memcpy(*buf,pReadData,data_length);
1005                 }
1006         }
1007         if(*buf)
1008                 cifs_buf_release(pSMB);
1009         else
1010                 *buf = (char *)pSMB;
1011
1012         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1013                 since file handle passed in no longer valid */
1014         return rc;
1015 }
1016
1017 int
1018 CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon,
1019              const int netfid, const unsigned int count,
1020              const __u64 offset, unsigned int *nbytes, const char *buf,
1021              const char __user * ubuf, const int long_op)
1022 {
1023         int rc = -EACCES;
1024         WRITE_REQ *pSMB = NULL;
1025         WRITE_RSP *pSMBr = NULL;
1026         int bytes_returned, wct;
1027         __u32 bytes_sent;
1028         __u16 byte_count;
1029
1030         /* cFYI(1,("write at %lld %d bytes",offset,count));*/
1031         if(tcon->ses == NULL)
1032                 return -ECONNABORTED;
1033
1034         if(tcon->ses->capabilities & CAP_LARGE_FILES)
1035                 wct = 14;
1036         else
1037                 wct = 12;
1038
1039         rc = smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **) &pSMB,
1040                       (void **) &pSMBr);
1041         if (rc)
1042                 return rc;
1043         /* tcon and ses pointer are checked in smb_init */
1044         if (tcon->ses->server == NULL)
1045                 return -ECONNABORTED;
1046
1047         pSMB->AndXCommand = 0xFF;       /* none */
1048         pSMB->Fid = netfid;
1049         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1050         if(wct == 14) 
1051                 pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1052         else if((offset >> 32) > 0) /* can not handle this big offset for old */
1053                 return -EIO;
1054         
1055         pSMB->Reserved = 0xFFFFFFFF;
1056         pSMB->WriteMode = 0;
1057         pSMB->Remaining = 0;
1058
1059         /* Can increase buffer size if buffer is big enough in some cases - ie we 
1060         can send more if LARGE_WRITE_X capability returned by the server and if
1061         our buffer is big enough or if we convert to iovecs on socket writes
1062         and eliminate the copy to the CIFS buffer */
1063         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1064                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1065         } else {
1066                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1067                          & ~0xFF;
1068         }
1069
1070         if (bytes_sent > count)
1071                 bytes_sent = count;
1072         pSMB->DataOffset =
1073             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1074         if(buf)
1075             memcpy(pSMB->Data,buf,bytes_sent);
1076         else if(ubuf) {
1077                 if(copy_from_user(pSMB->Data,ubuf,bytes_sent)) {
1078                         cifs_buf_release(pSMB);
1079                         return -EFAULT;
1080                 }
1081         } else {
1082                 /* No buffer */
1083                 cifs_buf_release(pSMB);
1084                 return -EINVAL;
1085         }
1086
1087         byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1088         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1089         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1090         pSMB->hdr.smb_buf_length += bytes_sent+1;
1091
1092         if(wct == 14)
1093                 pSMB->ByteCount = cpu_to_le16(byte_count);
1094         else { /* old style write has byte count 4 bytes earlier */
1095                 struct smb_com_writex_req * pSMBW = 
1096                         (struct smb_com_writex_req *)pSMB;
1097                 pSMBW->ByteCount = cpu_to_le16(byte_count);
1098         }
1099
1100         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1101                          (struct smb_hdr *) pSMBr, &bytes_returned, long_op);
1102         cifs_stats_inc(&tcon->num_writes);
1103         if (rc) {
1104                 cFYI(1, ("Send error in write = %d", rc));
1105                 *nbytes = 0;
1106         } else {
1107                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1108                 *nbytes = (*nbytes) << 16;
1109                 *nbytes += le16_to_cpu(pSMBr->Count);
1110         }
1111
1112         cifs_buf_release(pSMB);
1113
1114         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1115                 since file handle passed in no longer valid */
1116
1117         return rc;
1118 }
1119
1120 #ifdef CONFIG_CIFS_EXPERIMENTAL
1121 int
1122 CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon,
1123              const int netfid, const unsigned int count,
1124              const __u64 offset, unsigned int *nbytes, const char *buf,
1125              const int long_op)
1126 {
1127         int rc = -EACCES;
1128         WRITE_REQ *pSMB = NULL;
1129         int bytes_returned;
1130         int smb_hdr_len;
1131         __u32 bytes_sent;
1132         __u16 byte_count;
1133
1134         cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */
1135         rc = small_smb_init(SMB_COM_WRITE_ANDX, 14, tcon, (void **) &pSMB);
1136         if (rc)
1137                 return rc;
1138         /* tcon and ses pointer are checked in smb_init */
1139         if (tcon->ses->server == NULL)
1140                 return -ECONNABORTED;
1141
1142         pSMB->AndXCommand = 0xFF;       /* none */
1143         pSMB->Fid = netfid;
1144         pSMB->OffsetLow = cpu_to_le32(offset & 0xFFFFFFFF);
1145         pSMB->OffsetHigh = cpu_to_le32(offset >> 32);
1146         pSMB->Reserved = 0xFFFFFFFF;
1147         pSMB->WriteMode = 0;
1148         pSMB->Remaining = 0;
1149
1150         /* Can increase buffer size if buffer is big enough in some cases - ie 
1151         can send more if LARGE_WRITE_X capability returned by the server and if
1152         our buffer is big enough or if we convert to iovecs on socket writes
1153         and eliminate the copy to the CIFS buffer */
1154         if(tcon->ses->capabilities & CAP_LARGE_WRITE_X) {
1155                 bytes_sent = min_t(const unsigned int, CIFSMaxBufSize, count);
1156         } else {
1157                 bytes_sent = (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)
1158                          & ~0xFF;
1159         }
1160
1161         if (bytes_sent > count)
1162                 bytes_sent = count;
1163         pSMB->DataOffset =
1164             cpu_to_le16(offsetof(struct smb_com_write_req,Data) - 4);
1165
1166         byte_count = bytes_sent + 1 /* pad */ ; /* BB fix this for sends > 64K */
1167         pSMB->DataLengthLow = cpu_to_le16(bytes_sent & 0xFFFF);
1168         pSMB->DataLengthHigh = cpu_to_le16(bytes_sent >> 16);
1169         smb_hdr_len = pSMB->hdr.smb_buf_length + 1; /* hdr + 1 byte pad */
1170         pSMB->hdr.smb_buf_length += bytes_sent+1;
1171         pSMB->ByteCount = cpu_to_le16(byte_count);
1172
1173         rc = SendReceive2(xid, tcon->ses, (struct smb_hdr *) pSMB, smb_hdr_len,
1174                           buf, bytes_sent, &bytes_returned, long_op);
1175         cifs_stats_inc(&tcon->num_writes);
1176         if (rc) {
1177                 cFYI(1, ("Send error in write = %d", rc));
1178                 *nbytes = 0;
1179         } else {
1180                 WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB;
1181                 *nbytes = le16_to_cpu(pSMBr->CountHigh);
1182                 *nbytes = (*nbytes) << 16;
1183                 *nbytes += le16_to_cpu(pSMBr->Count);
1184         }
1185
1186         cifs_small_buf_release(pSMB);
1187
1188         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1189                 since file handle passed in no longer valid */
1190
1191         return rc;
1192 }
1193
1194
1195 #endif /* CIFS_EXPERIMENTAL */
1196
1197 int
1198 CIFSSMBLock(const int xid, struct cifsTconInfo *tcon,
1199             const __u16 smb_file_id, const __u64 len,
1200             const __u64 offset, const __u32 numUnlock,
1201             const __u32 numLock, const __u8 lockType, const int waitFlag)
1202 {
1203         int rc = 0;
1204         LOCK_REQ *pSMB = NULL;
1205         LOCK_RSP *pSMBr = NULL;
1206         int bytes_returned;
1207         int timeout = 0;
1208         __u16 count;
1209
1210         cFYI(1, ("In CIFSSMBLock - timeout %d numLock %d",waitFlag,numLock));
1211         rc = small_smb_init(SMB_COM_LOCKING_ANDX, 8, tcon, (void **) &pSMB);
1212
1213         if (rc)
1214                 return rc;
1215
1216         pSMBr = (LOCK_RSP *)pSMB; /* BB removeme BB */
1217
1218         if(lockType == LOCKING_ANDX_OPLOCK_RELEASE) {
1219                 timeout = -1; /* no response expected */
1220                 pSMB->Timeout = 0;
1221         } else if (waitFlag == TRUE) {
1222                 timeout = 3;  /* blocking operation, no timeout */
1223                 pSMB->Timeout = cpu_to_le32(-1);/* blocking - do not time out */
1224         } else {
1225                 pSMB->Timeout = 0;
1226         }
1227
1228         pSMB->NumberOfLocks = cpu_to_le16(numLock);
1229         pSMB->NumberOfUnlocks = cpu_to_le16(numUnlock);
1230         pSMB->LockType = lockType;
1231         pSMB->AndXCommand = 0xFF;       /* none */
1232         pSMB->Fid = smb_file_id; /* netfid stays le */
1233
1234         if((numLock != 0) || (numUnlock != 0)) {
1235                 pSMB->Locks[0].Pid = cpu_to_le16(current->tgid);
1236                 /* BB where to store pid high? */
1237                 pSMB->Locks[0].LengthLow = cpu_to_le32((u32)len);
1238                 pSMB->Locks[0].LengthHigh = cpu_to_le32((u32)(len>>32));
1239                 pSMB->Locks[0].OffsetLow = cpu_to_le32((u32)offset);
1240                 pSMB->Locks[0].OffsetHigh = cpu_to_le32((u32)(offset>>32));
1241                 count = sizeof(LOCKING_ANDX_RANGE);
1242         } else {
1243                 /* oplock break */
1244                 count = 0;
1245         }
1246         pSMB->hdr.smb_buf_length += count;
1247         pSMB->ByteCount = cpu_to_le16(count);
1248
1249         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1250                          (struct smb_hdr *) pSMBr, &bytes_returned, timeout);
1251         cifs_stats_inc(&tcon->num_locks);
1252         if (rc) {
1253                 cFYI(1, ("Send error in Lock = %d", rc));
1254         }
1255         cifs_small_buf_release(pSMB);
1256
1257         /* Note: On -EAGAIN error only caller can retry on handle based calls 
1258         since file handle passed in no longer valid */
1259         return rc;
1260 }
1261
1262 int
1263 CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
1264 {
1265         int rc = 0;
1266         CLOSE_REQ *pSMB = NULL;
1267         CLOSE_RSP *pSMBr = NULL;
1268         int bytes_returned;
1269         cFYI(1, ("In CIFSSMBClose"));
1270
1271 /* do not retry on dead session on close */
1272         rc = small_smb_init(SMB_COM_CLOSE, 3, tcon, (void **) &pSMB);
1273         if(rc == -EAGAIN)
1274                 return 0;
1275         if (rc)
1276                 return rc;
1277
1278         pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
1279
1280         pSMB->FileID = (__u16) smb_file_id;
1281         pSMB->LastWriteTime = 0;
1282         pSMB->ByteCount = 0;
1283         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1284                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1285         cifs_stats_inc(&tcon->num_closes);
1286         if (rc) {
1287                 if(rc!=-EINTR) {
1288                         /* EINTR is expected when user ctl-c to kill app */
1289                         cERROR(1, ("Send error in Close = %d", rc));
1290                 }
1291         }
1292
1293         cifs_small_buf_release(pSMB);
1294
1295         /* Since session is dead, file will be closed on server already */
1296         if(rc == -EAGAIN)
1297                 rc = 0;
1298
1299         return rc;
1300 }
1301
1302 int
1303 CIFSSMBRename(const int xid, struct cifsTconInfo *tcon,
1304               const char *fromName, const char *toName,
1305               const struct nls_table *nls_codepage, int remap)
1306 {
1307         int rc = 0;
1308         RENAME_REQ *pSMB = NULL;
1309         RENAME_RSP *pSMBr = NULL;
1310         int bytes_returned;
1311         int name_len, name_len2;
1312         __u16 count;
1313
1314         cFYI(1, ("In CIFSSMBRename"));
1315 renameRetry:
1316         rc = smb_init(SMB_COM_RENAME, 1, tcon, (void **) &pSMB,
1317                       (void **) &pSMBr);
1318         if (rc)
1319                 return rc;
1320
1321         pSMB->BufferFormat = 0x04;
1322         pSMB->SearchAttributes =
1323             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1324                         ATTR_DIRECTORY);
1325
1326         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1327                 name_len =
1328                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName, 
1329                                      PATH_MAX, nls_codepage, remap);
1330                 name_len++;     /* trailing null */
1331                 name_len *= 2;
1332                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1333         /* protocol requires ASCII signature byte on Unicode string */
1334                 pSMB->OldFileName[name_len + 1] = 0x00;
1335                 name_len2 =
1336                     cifsConvertToUCS((__le16 *) &pSMB->OldFileName[name_len + 2],
1337                                      toName, PATH_MAX, nls_codepage, remap);
1338                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1339                 name_len2 *= 2; /* convert to bytes */
1340         } else {                /* BB improve the check for buffer overruns BB */
1341                 name_len = strnlen(fromName, PATH_MAX);
1342                 name_len++;     /* trailing null */
1343                 strncpy(pSMB->OldFileName, fromName, name_len);
1344                 name_len2 = strnlen(toName, PATH_MAX);
1345                 name_len2++;    /* trailing null */
1346                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1347                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1348                 name_len2++;    /* trailing null */
1349                 name_len2++;    /* signature byte */
1350         }
1351
1352         count = 1 /* 1st signature byte */  + name_len + name_len2;
1353         pSMB->hdr.smb_buf_length += count;
1354         pSMB->ByteCount = cpu_to_le16(count);
1355
1356         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1357                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1358         cifs_stats_inc(&tcon->num_renames);
1359         if (rc) {
1360                 cFYI(1, ("Send error in rename = %d", rc));
1361         } 
1362
1363         cifs_buf_release(pSMB);
1364
1365         if (rc == -EAGAIN)
1366                 goto renameRetry;
1367
1368         return rc;
1369 }
1370
1371 int CIFSSMBRenameOpenFile(const int xid,struct cifsTconInfo *pTcon, 
1372                 int netfid, char * target_name, 
1373                 const struct nls_table * nls_codepage, int remap)
1374 {
1375         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
1376         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
1377         struct set_file_rename * rename_info;
1378         char *data_offset;
1379         char dummy_string[30];
1380         int rc = 0;
1381         int bytes_returned = 0;
1382         int len_of_str;
1383         __u16 params, param_offset, offset, count, byte_count;
1384
1385         cFYI(1, ("Rename to File by handle"));
1386         rc = smb_init(SMB_COM_TRANSACTION2, 15, pTcon, (void **) &pSMB,
1387                         (void **) &pSMBr);
1388         if (rc)
1389                 return rc;
1390
1391         params = 6;
1392         pSMB->MaxSetupCount = 0;
1393         pSMB->Reserved = 0;
1394         pSMB->Flags = 0;
1395         pSMB->Timeout = 0;
1396         pSMB->Reserved2 = 0;
1397         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
1398         offset = param_offset + params;
1399
1400         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1401         rename_info = (struct set_file_rename *) data_offset;
1402         pSMB->MaxParameterCount = cpu_to_le16(2);
1403         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
1404         pSMB->SetupCount = 1;
1405         pSMB->Reserved3 = 0;
1406         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
1407         byte_count = 3 /* pad */  + params;
1408         pSMB->ParameterCount = cpu_to_le16(params);
1409         pSMB->TotalParameterCount = pSMB->ParameterCount;
1410         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1411         pSMB->DataOffset = cpu_to_le16(offset);
1412         /* construct random name ".cifs_tmp<inodenum><mid>" */
1413         rename_info->overwrite = cpu_to_le32(1);
1414         rename_info->root_fid  = 0;
1415         /* unicode only call */
1416         if(target_name == NULL) {
1417                 sprintf(dummy_string,"cifs%x",pSMB->hdr.Mid);
1418                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1419                                         dummy_string, 24, nls_codepage, remap);
1420         } else {
1421                 len_of_str = cifsConvertToUCS((__le16 *)rename_info->target_name,
1422                                         target_name, PATH_MAX, nls_codepage, remap);
1423         }
1424         rename_info->target_name_len = cpu_to_le32(2 * len_of_str);
1425         count = 12 /* sizeof(struct set_file_rename) */ + (2 * len_of_str) + 2;
1426         byte_count += count;
1427         pSMB->DataCount = cpu_to_le16(count);
1428         pSMB->TotalDataCount = pSMB->DataCount;
1429         pSMB->Fid = netfid;
1430         pSMB->InformationLevel =
1431                 cpu_to_le16(SMB_SET_FILE_RENAME_INFORMATION);
1432         pSMB->Reserved4 = 0;
1433         pSMB->hdr.smb_buf_length += byte_count;
1434         pSMB->ByteCount = cpu_to_le16(byte_count);
1435         rc = SendReceive(xid, pTcon->ses, (struct smb_hdr *) pSMB,
1436                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1437         cifs_stats_inc(&pTcon->num_t2renames);
1438         if (rc) {
1439                 cFYI(1,("Send error in Rename (by file handle) = %d", rc));
1440         }
1441
1442         cifs_buf_release(pSMB);
1443
1444         /* Note: On -EAGAIN error only caller can retry on handle based calls
1445                 since file handle passed in no longer valid */
1446
1447         return rc;
1448 }
1449
1450 int
1451 CIFSSMBCopy(const int xid, struct cifsTconInfo *tcon, const char * fromName, 
1452             const __u16 target_tid, const char *toName, const int flags,
1453             const struct nls_table *nls_codepage, int remap)
1454 {
1455         int rc = 0;
1456         COPY_REQ *pSMB = NULL;
1457         COPY_RSP *pSMBr = NULL;
1458         int bytes_returned;
1459         int name_len, name_len2;
1460         __u16 count;
1461
1462         cFYI(1, ("In CIFSSMBCopy"));
1463 copyRetry:
1464         rc = smb_init(SMB_COM_COPY, 1, tcon, (void **) &pSMB,
1465                         (void **) &pSMBr);
1466         if (rc)
1467                 return rc;
1468
1469         pSMB->BufferFormat = 0x04;
1470         pSMB->Tid2 = target_tid;
1471
1472         pSMB->Flags = cpu_to_le16(flags & COPY_TREE);
1473
1474         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1475                 name_len = cifsConvertToUCS((__le16 *) pSMB->OldFileName, 
1476                                             fromName, PATH_MAX, nls_codepage,
1477                                             remap);
1478                 name_len++;     /* trailing null */
1479                 name_len *= 2;
1480                 pSMB->OldFileName[name_len] = 0x04;     /* pad */
1481                 /* protocol requires ASCII signature byte on Unicode string */
1482                 pSMB->OldFileName[name_len + 1] = 0x00;
1483                 name_len2 = cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1484                                 toName, PATH_MAX, nls_codepage, remap);
1485                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1486                 name_len2 *= 2; /* convert to bytes */
1487         } else {                /* BB improve the check for buffer overruns BB */
1488                 name_len = strnlen(fromName, PATH_MAX);
1489                 name_len++;     /* trailing null */
1490                 strncpy(pSMB->OldFileName, fromName, name_len);
1491                 name_len2 = strnlen(toName, PATH_MAX);
1492                 name_len2++;    /* trailing null */
1493                 pSMB->OldFileName[name_len] = 0x04;  /* 2nd buffer format */
1494                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1495                 name_len2++;    /* trailing null */
1496                 name_len2++;    /* signature byte */
1497         }
1498
1499         count = 1 /* 1st signature byte */  + name_len + name_len2;
1500         pSMB->hdr.smb_buf_length += count;
1501         pSMB->ByteCount = cpu_to_le16(count);
1502
1503         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1504                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1505         if (rc) {
1506                 cFYI(1, ("Send error in copy = %d with %d files copied",
1507                         rc, le16_to_cpu(pSMBr->CopyCount)));
1508         }
1509         if (pSMB)
1510                 cifs_buf_release(pSMB);
1511
1512         if (rc == -EAGAIN)
1513                 goto copyRetry;
1514
1515         return rc;
1516 }
1517
1518 int
1519 CIFSUnixCreateSymLink(const int xid, struct cifsTconInfo *tcon,
1520                       const char *fromName, const char *toName,
1521                       const struct nls_table *nls_codepage)
1522 {
1523         TRANSACTION2_SPI_REQ *pSMB = NULL;
1524         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1525         char *data_offset;
1526         int name_len;
1527         int name_len_target;
1528         int rc = 0;
1529         int bytes_returned = 0;
1530         __u16 params, param_offset, offset, byte_count;
1531
1532         cFYI(1, ("In Symlink Unix style"));
1533 createSymLinkRetry:
1534         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1535                       (void **) &pSMBr);
1536         if (rc)
1537                 return rc;
1538
1539         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1540                 name_len =
1541                     cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX
1542                                   /* find define for this maxpathcomponent */
1543                                   , nls_codepage);
1544                 name_len++;     /* trailing null */
1545                 name_len *= 2;
1546
1547         } else {                /* BB improve the check for buffer overruns BB */
1548                 name_len = strnlen(fromName, PATH_MAX);
1549                 name_len++;     /* trailing null */
1550                 strncpy(pSMB->FileName, fromName, name_len);
1551         }
1552         params = 6 + name_len;
1553         pSMB->MaxSetupCount = 0;
1554         pSMB->Reserved = 0;
1555         pSMB->Flags = 0;
1556         pSMB->Timeout = 0;
1557         pSMB->Reserved2 = 0;
1558         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1559                                      InformationLevel) - 4;
1560         offset = param_offset + params;
1561
1562         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1563         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1564                 name_len_target =
1565                     cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX
1566                                   /* find define for this maxpathcomponent */
1567                                   , nls_codepage);
1568                 name_len_target++;      /* trailing null */
1569                 name_len_target *= 2;
1570         } else {                /* BB improve the check for buffer overruns BB */
1571                 name_len_target = strnlen(toName, PATH_MAX);
1572                 name_len_target++;      /* trailing null */
1573                 strncpy(data_offset, toName, name_len_target);
1574         }
1575
1576         pSMB->MaxParameterCount = cpu_to_le16(2);
1577         /* BB find exact max on data count below from sess */
1578         pSMB->MaxDataCount = cpu_to_le16(1000);
1579         pSMB->SetupCount = 1;
1580         pSMB->Reserved3 = 0;
1581         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1582         byte_count = 3 /* pad */  + params + name_len_target;
1583         pSMB->DataCount = cpu_to_le16(name_len_target);
1584         pSMB->ParameterCount = cpu_to_le16(params);
1585         pSMB->TotalDataCount = pSMB->DataCount;
1586         pSMB->TotalParameterCount = pSMB->ParameterCount;
1587         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1588         pSMB->DataOffset = cpu_to_le16(offset);
1589         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_LINK);
1590         pSMB->Reserved4 = 0;
1591         pSMB->hdr.smb_buf_length += byte_count;
1592         pSMB->ByteCount = cpu_to_le16(byte_count);
1593         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1594                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1595         cifs_stats_inc(&tcon->num_symlinks);
1596         if (rc) {
1597                 cFYI(1,
1598                      ("Send error in SetPathInfo (create symlink) = %d",
1599                       rc));
1600         }
1601
1602         if (pSMB)
1603                 cifs_buf_release(pSMB);
1604
1605         if (rc == -EAGAIN)
1606                 goto createSymLinkRetry;
1607
1608         return rc;
1609 }
1610
1611 int
1612 CIFSUnixCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1613                        const char *fromName, const char *toName,
1614                        const struct nls_table *nls_codepage, int remap)
1615 {
1616         TRANSACTION2_SPI_REQ *pSMB = NULL;
1617         TRANSACTION2_SPI_RSP *pSMBr = NULL;
1618         char *data_offset;
1619         int name_len;
1620         int name_len_target;
1621         int rc = 0;
1622         int bytes_returned = 0;
1623         __u16 params, param_offset, offset, byte_count;
1624
1625         cFYI(1, ("In Create Hard link Unix style"));
1626 createHardLinkRetry:
1627         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1628                       (void **) &pSMBr);
1629         if (rc)
1630                 return rc;
1631
1632         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1633                 name_len = cifsConvertToUCS((__le16 *) pSMB->FileName, toName,
1634                                             PATH_MAX, nls_codepage, remap);
1635                 name_len++;     /* trailing null */
1636                 name_len *= 2;
1637
1638         } else {                /* BB improve the check for buffer overruns BB */
1639                 name_len = strnlen(toName, PATH_MAX);
1640                 name_len++;     /* trailing null */
1641                 strncpy(pSMB->FileName, toName, name_len);
1642         }
1643         params = 6 + name_len;
1644         pSMB->MaxSetupCount = 0;
1645         pSMB->Reserved = 0;
1646         pSMB->Flags = 0;
1647         pSMB->Timeout = 0;
1648         pSMB->Reserved2 = 0;
1649         param_offset = offsetof(struct smb_com_transaction2_spi_req,
1650                                      InformationLevel) - 4;
1651         offset = param_offset + params;
1652
1653         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
1654         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1655                 name_len_target =
1656                     cifsConvertToUCS((__le16 *) data_offset, fromName, PATH_MAX,
1657                                      nls_codepage, remap);
1658                 name_len_target++;      /* trailing null */
1659                 name_len_target *= 2;
1660         } else {                /* BB improve the check for buffer overruns BB */
1661                 name_len_target = strnlen(fromName, PATH_MAX);
1662                 name_len_target++;      /* trailing null */
1663                 strncpy(data_offset, fromName, name_len_target);
1664         }
1665
1666         pSMB->MaxParameterCount = cpu_to_le16(2);
1667         /* BB find exact max on data count below from sess*/
1668         pSMB->MaxDataCount = cpu_to_le16(1000);
1669         pSMB->SetupCount = 1;
1670         pSMB->Reserved3 = 0;
1671         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
1672         byte_count = 3 /* pad */  + params + name_len_target;
1673         pSMB->ParameterCount = cpu_to_le16(params);
1674         pSMB->TotalParameterCount = pSMB->ParameterCount;
1675         pSMB->DataCount = cpu_to_le16(name_len_target);
1676         pSMB->TotalDataCount = pSMB->DataCount;
1677         pSMB->ParameterOffset = cpu_to_le16(param_offset);
1678         pSMB->DataOffset = cpu_to_le16(offset);
1679         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_HLINK);
1680         pSMB->Reserved4 = 0;
1681         pSMB->hdr.smb_buf_length += byte_count;
1682         pSMB->ByteCount = cpu_to_le16(byte_count);
1683         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1684                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1685         cifs_stats_inc(&tcon->num_hardlinks);
1686         if (rc) {
1687                 cFYI(1, ("Send error in SetPathInfo (hard link) = %d", rc));
1688         }
1689
1690         cifs_buf_release(pSMB);
1691         if (rc == -EAGAIN)
1692                 goto createHardLinkRetry;
1693
1694         return rc;
1695 }
1696
1697 int
1698 CIFSCreateHardLink(const int xid, struct cifsTconInfo *tcon,
1699                    const char *fromName, const char *toName,
1700                    const struct nls_table *nls_codepage, int remap)
1701 {
1702         int rc = 0;
1703         NT_RENAME_REQ *pSMB = NULL;
1704         RENAME_RSP *pSMBr = NULL;
1705         int bytes_returned;
1706         int name_len, name_len2;
1707         __u16 count;
1708
1709         cFYI(1, ("In CIFSCreateHardLink"));
1710 winCreateHardLinkRetry:
1711
1712         rc = smb_init(SMB_COM_NT_RENAME, 4, tcon, (void **) &pSMB,
1713                       (void **) &pSMBr);
1714         if (rc)
1715                 return rc;
1716
1717         pSMB->SearchAttributes =
1718             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
1719                         ATTR_DIRECTORY);
1720         pSMB->Flags = cpu_to_le16(CREATE_HARD_LINK);
1721         pSMB->ClusterCount = 0;
1722
1723         pSMB->BufferFormat = 0x04;
1724
1725         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1726                 name_len =
1727                     cifsConvertToUCS((__le16 *) pSMB->OldFileName, fromName,
1728                                      PATH_MAX, nls_codepage, remap);
1729                 name_len++;     /* trailing null */
1730                 name_len *= 2;
1731                 pSMB->OldFileName[name_len] = 0;        /* pad */
1732                 pSMB->OldFileName[name_len + 1] = 0x04; 
1733                 name_len2 =
1734                     cifsConvertToUCS((__le16 *)&pSMB->OldFileName[name_len + 2], 
1735                                      toName, PATH_MAX, nls_codepage, remap);
1736                 name_len2 += 1 /* trailing null */  + 1 /* Signature word */ ;
1737                 name_len2 *= 2; /* convert to bytes */
1738         } else {                /* BB improve the check for buffer overruns BB */
1739                 name_len = strnlen(fromName, PATH_MAX);
1740                 name_len++;     /* trailing null */
1741                 strncpy(pSMB->OldFileName, fromName, name_len);
1742                 name_len2 = strnlen(toName, PATH_MAX);
1743                 name_len2++;    /* trailing null */
1744                 pSMB->OldFileName[name_len] = 0x04;     /* 2nd buffer format */
1745                 strncpy(&pSMB->OldFileName[name_len + 1], toName, name_len2);
1746                 name_len2++;    /* trailing null */
1747                 name_len2++;    /* signature byte */
1748         }
1749
1750         count = 1 /* string type byte */  + name_len + name_len2;
1751         pSMB->hdr.smb_buf_length += count;
1752         pSMB->ByteCount = cpu_to_le16(count);
1753
1754         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1755                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1756         cifs_stats_inc(&tcon->num_hardlinks);
1757         if (rc) {
1758                 cFYI(1, ("Send error in hard link (NT rename) = %d", rc));
1759         }
1760         cifs_buf_release(pSMB);
1761         if (rc == -EAGAIN)
1762                 goto winCreateHardLinkRetry;
1763
1764         return rc;
1765 }
1766
1767 int
1768 CIFSSMBUnixQuerySymLink(const int xid, struct cifsTconInfo *tcon,
1769                         const unsigned char *searchName,
1770                         char *symlinkinfo, const int buflen,
1771                         const struct nls_table *nls_codepage)
1772 {
1773 /* SMB_QUERY_FILE_UNIX_LINK */
1774         TRANSACTION2_QPI_REQ *pSMB = NULL;
1775         TRANSACTION2_QPI_RSP *pSMBr = NULL;
1776         int rc = 0;
1777         int bytes_returned;
1778         int name_len;
1779         __u16 params, byte_count;
1780
1781         cFYI(1, ("In QPathSymLinkInfo (Unix) for path %s", searchName));
1782
1783 querySymLinkRetry:
1784         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
1785                       (void **) &pSMBr);
1786         if (rc)
1787                 return rc;
1788
1789         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
1790                 name_len =
1791                     cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX
1792                                   /* find define for this maxpathcomponent */
1793                                   , nls_codepage);
1794                 name_len++;     /* trailing null */
1795                 name_len *= 2;
1796         } else {                /* BB improve the check for buffer overruns BB */
1797                 name_len = strnlen(searchName, PATH_MAX);
1798                 name_len++;     /* trailing null */
1799                 strncpy(pSMB->FileName, searchName, name_len);
1800         }
1801
1802         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
1803         pSMB->TotalDataCount = 0;
1804         pSMB->MaxParameterCount = cpu_to_le16(2);
1805         /* BB find exact max data count below from sess structure BB */
1806         pSMB->MaxDataCount = cpu_to_le16(4000);
1807         pSMB->MaxSetupCount = 0;
1808         pSMB->Reserved = 0;
1809         pSMB->Flags = 0;
1810         pSMB->Timeout = 0;
1811         pSMB->Reserved2 = 0;
1812         pSMB->ParameterOffset = cpu_to_le16(offsetof(
1813         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
1814         pSMB->DataCount = 0;
1815         pSMB->DataOffset = 0;
1816         pSMB->SetupCount = 1;
1817         pSMB->Reserved3 = 0;
1818         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
1819         byte_count = params + 1 /* pad */ ;
1820         pSMB->TotalParameterCount = cpu_to_le16(params);
1821         pSMB->ParameterCount = pSMB->TotalParameterCount;
1822         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_LINK);
1823         pSMB->Reserved4 = 0;
1824         pSMB->hdr.smb_buf_length += byte_count;
1825         pSMB->ByteCount = cpu_to_le16(byte_count);
1826
1827         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1828                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1829         if (rc) {
1830                 cFYI(1, ("Send error in QuerySymLinkInfo = %d", rc));
1831         } else {
1832                 /* decode response */
1833
1834                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
1835                 if (rc || (pSMBr->ByteCount < 2))
1836                 /* BB also check enough total bytes returned */
1837                         rc = -EIO;      /* bad smb */
1838                 else {
1839                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
1840                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
1841
1842                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1843                                 name_len = UniStrnlen((wchar_t *) ((char *)
1844                                         &pSMBr->hdr.Protocol +data_offset),
1845                                         min_t(const int, buflen,count) / 2);
1846                         /* BB FIXME investigate remapping reserved chars here */
1847                                 cifs_strfromUCS_le(symlinkinfo,
1848                                         (wchar_t *) ((char *)&pSMBr->hdr.Protocol +
1849                                                 data_offset),
1850                                         name_len, nls_codepage);
1851                         } else {
1852                                 strncpy(symlinkinfo,
1853                                         (char *) &pSMBr->hdr.Protocol + 
1854                                                 data_offset,
1855                                         min_t(const int, buflen, count));
1856                         }
1857                         symlinkinfo[buflen] = 0;
1858         /* just in case so calling code does not go off the end of buffer */
1859                 }
1860         }
1861         cifs_buf_release(pSMB);
1862         if (rc == -EAGAIN)
1863                 goto querySymLinkRetry;
1864         return rc;
1865 }
1866
1867 int
1868 CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon,
1869                         const unsigned char *searchName,
1870                         char *symlinkinfo, const int buflen,__u16 fid,
1871                         const struct nls_table *nls_codepage)
1872 {
1873         int rc = 0;
1874         int bytes_returned;
1875         int name_len;
1876         struct smb_com_transaction_ioctl_req * pSMB;
1877         struct smb_com_transaction_ioctl_rsp * pSMBr;
1878
1879         cFYI(1, ("In Windows reparse style QueryLink for path %s", searchName));
1880         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
1881                       (void **) &pSMBr);
1882         if (rc)
1883                 return rc;
1884
1885         pSMB->TotalParameterCount = 0 ;
1886         pSMB->TotalDataCount = 0;
1887         pSMB->MaxParameterCount = cpu_to_le32(2);
1888         /* BB find exact data count max from sess structure BB */
1889         pSMB->MaxDataCount = cpu_to_le32(4000);
1890         pSMB->MaxSetupCount = 4;
1891         pSMB->Reserved = 0;
1892         pSMB->ParameterOffset = 0;
1893         pSMB->DataCount = 0;
1894         pSMB->DataOffset = 0;
1895         pSMB->SetupCount = 4;
1896         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
1897         pSMB->ParameterCount = pSMB->TotalParameterCount;
1898         pSMB->FunctionCode = cpu_to_le32(FSCTL_GET_REPARSE_POINT);
1899         pSMB->IsFsctl = 1; /* FSCTL */
1900         pSMB->IsRootFlag = 0;
1901         pSMB->Fid = fid; /* file handle always le */
1902         pSMB->ByteCount = 0;
1903
1904         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
1905                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
1906         if (rc) {
1907                 cFYI(1, ("Send error in QueryReparseLinkInfo = %d", rc));
1908         } else {                /* decode response */
1909                 __u32 data_offset = le32_to_cpu(pSMBr->DataOffset);
1910                 __u32 data_count = le32_to_cpu(pSMBr->DataCount);
1911                 if ((pSMBr->ByteCount < 2) || (data_offset > 512))
1912                 /* BB also check enough total bytes returned */
1913                         rc = -EIO;      /* bad smb */
1914                 else {
1915                         if(data_count && (data_count < 2048)) {
1916                                 char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount;
1917
1918                                 struct reparse_data * reparse_buf = (struct reparse_data *)
1919                                         ((char *)&pSMBr->hdr.Protocol + data_offset);
1920                                 if((char*)reparse_buf >= end_of_smb) {
1921                                         rc = -EIO;
1922                                         goto qreparse_out;
1923                                 }
1924                                 if((reparse_buf->LinkNamesBuf + 
1925                                         reparse_buf->TargetNameOffset +
1926                                         reparse_buf->TargetNameLen) >
1927                                                 end_of_smb) {
1928                                         cFYI(1,("reparse buf extended beyond SMB"));
1929                                         rc = -EIO;
1930                                         goto qreparse_out;
1931                                 }
1932                                 
1933                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
1934                                         name_len = UniStrnlen((wchar_t *)
1935                                                         (reparse_buf->LinkNamesBuf + 
1936                                                         reparse_buf->TargetNameOffset),
1937                                                         min(buflen/2, reparse_buf->TargetNameLen / 2)); 
1938                                         cifs_strfromUCS_le(symlinkinfo,
1939                                                 (wchar_t *) (reparse_buf->LinkNamesBuf + 
1940                                                 reparse_buf->TargetNameOffset),
1941                                                 name_len, nls_codepage);
1942                                 } else { /* ASCII names */
1943                                         strncpy(symlinkinfo,reparse_buf->LinkNamesBuf + 
1944                                                 reparse_buf->TargetNameOffset, 
1945                                                 min_t(const int, buflen, reparse_buf->TargetNameLen));
1946                                 }
1947                         } else {
1948                                 rc = -EIO;
1949                                 cFYI(1,("Invalid return data count on get reparse info ioctl"));
1950                         }
1951                         symlinkinfo[buflen] = 0; /* just in case so the caller
1952                                         does not go off the end of the buffer */
1953                         cFYI(1,("readlink result - %s ",symlinkinfo));
1954                 }
1955         }
1956 qreparse_out:
1957         cifs_buf_release(pSMB);
1958
1959         /* Note: On -EAGAIN error only caller can retry on handle based calls
1960                 since file handle passed in no longer valid */
1961
1962         return rc;
1963 }
1964
1965 #ifdef CONFIG_CIFS_POSIX
1966
1967 /*Convert an Access Control Entry from wire format to local POSIX xattr format*/
1968 static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace)
1969 {
1970         /* u8 cifs fields do not need le conversion */
1971         ace->e_perm = (__u16)cifs_ace->cifs_e_perm; 
1972         ace->e_tag  = (__u16)cifs_ace->cifs_e_tag;
1973         ace->e_id   = (__u32)le64_to_cpu(cifs_ace->cifs_uid);
1974         /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */
1975
1976         return;
1977 }
1978
1979 /* Convert ACL from CIFS POSIX wire format to local Linux POSIX ACL xattr */
1980 static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen,
1981                                 const int acl_type,const int size_of_data_area)
1982 {
1983         int size =  0;
1984         int i;
1985         __u16 count;
1986         struct cifs_posix_ace * pACE;
1987         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)src;
1988         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)trgt;
1989
1990         if (le16_to_cpu(cifs_acl->version) != CIFS_ACL_VERSION)
1991                 return -EOPNOTSUPP;
1992
1993         if(acl_type & ACL_TYPE_ACCESS) {
1994                 count = le16_to_cpu(cifs_acl->access_entry_count);
1995                 pACE = &cifs_acl->ace_array[0];
1996                 size = sizeof(struct cifs_posix_acl);
1997                 size += sizeof(struct cifs_posix_ace) * count;
1998                 /* check if we would go beyond end of SMB */
1999                 if(size_of_data_area < size) {
2000                         cFYI(1,("bad CIFS POSIX ACL size %d vs. %d",size_of_data_area,size));
2001                         return -EINVAL;
2002                 }
2003         } else if(acl_type & ACL_TYPE_DEFAULT) {
2004                 count = le16_to_cpu(cifs_acl->access_entry_count);
2005                 size = sizeof(struct cifs_posix_acl);
2006                 size += sizeof(struct cifs_posix_ace) * count;
2007 /* skip past access ACEs to get to default ACEs */
2008                 pACE = &cifs_acl->ace_array[count];
2009                 count = le16_to_cpu(cifs_acl->default_entry_count);
2010                 size += sizeof(struct cifs_posix_ace) * count;
2011                 /* check if we would go beyond end of SMB */
2012                 if(size_of_data_area < size)
2013                         return -EINVAL;
2014         } else {
2015                 /* illegal type */
2016                 return -EINVAL;
2017         }
2018
2019         size = posix_acl_xattr_size(count);
2020         if((buflen == 0) || (local_acl == NULL)) {
2021                 /* used to query ACL EA size */                         
2022         } else if(size > buflen) {
2023                 return -ERANGE;
2024         } else /* buffer big enough */ {
2025                 local_acl->a_version = POSIX_ACL_XATTR_VERSION;
2026                 for(i = 0;i < count ;i++) {
2027                         cifs_convert_ace(&local_acl->a_entries[i],pACE);
2028                         pACE ++;
2029                 }
2030         }
2031         return size;
2032 }
2033
2034 static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace,
2035                         const posix_acl_xattr_entry * local_ace)
2036 {
2037         __u16 rc = 0; /* 0 = ACL converted ok */
2038
2039         cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm);
2040         cifs_ace->cifs_e_tag =  (__u8)cpu_to_le16(local_ace->e_tag);
2041         /* BB is there a better way to handle the large uid? */
2042         if(local_ace->e_id == -1) {
2043         /* Probably no need to le convert -1 on any arch but can not hurt */
2044                 cifs_ace->cifs_uid = cpu_to_le64(-1);
2045         } else 
2046                 cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id);
2047         /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/
2048         return rc;
2049 }
2050
2051 /* Convert ACL from local Linux POSIX xattr to CIFS POSIX ACL wire format */
2052 static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int buflen,
2053                 const int acl_type)
2054 {
2055         __u16 rc = 0;
2056         struct cifs_posix_acl * cifs_acl = (struct cifs_posix_acl *)parm_data;
2057         posix_acl_xattr_header * local_acl = (posix_acl_xattr_header *)pACL;
2058         int count;
2059         int i;
2060
2061         if((buflen == 0) || (pACL == NULL) || (cifs_acl == NULL))
2062                 return 0;
2063
2064         count = posix_acl_xattr_count((size_t)buflen);
2065         cFYI(1,("setting acl with %d entries from buf of length %d and version of %d",
2066                 count,buflen,local_acl->a_version));
2067         if(local_acl->a_version != 2) {
2068                 cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version));
2069                 return 0;
2070         }
2071         cifs_acl->version = cpu_to_le16(1);
2072         if(acl_type == ACL_TYPE_ACCESS) 
2073                 cifs_acl->access_entry_count = count;
2074         else if(acl_type == ACL_TYPE_DEFAULT)
2075                 cifs_acl->default_entry_count = count;
2076         else {
2077                 cFYI(1,("unknown ACL type %d",acl_type));
2078                 return 0;
2079         }
2080         for(i=0;i<count;i++) {
2081                 rc = convert_ace_to_cifs_ace(&cifs_acl->ace_array[i],
2082                                         &local_acl->a_entries[i]);
2083                 if(rc != 0) {
2084                         /* ACE not converted */
2085                         break;
2086                 }
2087         }
2088         if(rc == 0) {
2089                 rc = (__u16)(count * sizeof(struct cifs_posix_ace));
2090                 rc += sizeof(struct cifs_posix_acl);
2091                 /* BB add check to make sure ACL does not overflow SMB */
2092         }
2093         return rc;
2094 }
2095
2096 int
2097 CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon,
2098                         const unsigned char *searchName,
2099                         char *acl_inf, const int buflen, const int acl_type,
2100                         const struct nls_table *nls_codepage, int remap)
2101 {
2102 /* SMB_QUERY_POSIX_ACL */
2103         TRANSACTION2_QPI_REQ *pSMB = NULL;
2104         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2105         int rc = 0;
2106         int bytes_returned;
2107         int name_len;
2108         __u16 params, byte_count;
2109                                                                                                                                              
2110         cFYI(1, ("In GetPosixACL (Unix) for path %s", searchName));
2111
2112 queryAclRetry:
2113         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2114                 (void **) &pSMBr);
2115         if (rc)
2116                 return rc;
2117                                                                                                                                              
2118         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2119                 name_len =
2120                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2121                                          PATH_MAX, nls_codepage, remap);
2122                 name_len++;     /* trailing null */
2123                 name_len *= 2;
2124                 pSMB->FileName[name_len] = 0;
2125                 pSMB->FileName[name_len+1] = 0;
2126         } else {                /* BB improve the check for buffer overruns BB */
2127                 name_len = strnlen(searchName, PATH_MAX);
2128                 name_len++;     /* trailing null */
2129                 strncpy(pSMB->FileName, searchName, name_len);
2130         }
2131
2132         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2133         pSMB->TotalDataCount = 0;
2134         pSMB->MaxParameterCount = cpu_to_le16(2);
2135         /* BB find exact max data count below from sess structure BB */
2136         pSMB->MaxDataCount = cpu_to_le16(4000);
2137         pSMB->MaxSetupCount = 0;
2138         pSMB->Reserved = 0;
2139         pSMB->Flags = 0;
2140         pSMB->Timeout = 0;
2141         pSMB->Reserved2 = 0;
2142         pSMB->ParameterOffset = cpu_to_le16(
2143                 offsetof(struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2144         pSMB->DataCount = 0;
2145         pSMB->DataOffset = 0;
2146         pSMB->SetupCount = 1;
2147         pSMB->Reserved3 = 0;
2148         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2149         byte_count = params + 1 /* pad */ ;
2150         pSMB->TotalParameterCount = cpu_to_le16(params);
2151         pSMB->ParameterCount = pSMB->TotalParameterCount;
2152         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_ACL);
2153         pSMB->Reserved4 = 0;
2154         pSMB->hdr.smb_buf_length += byte_count;
2155         pSMB->ByteCount = cpu_to_le16(byte_count);
2156
2157         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2158                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2159         if (rc) {
2160                 cFYI(1, ("Send error in Query POSIX ACL = %d", rc));
2161         } else {
2162                 /* decode response */
2163  
2164                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2165                 if (rc || (pSMBr->ByteCount < 2))
2166                 /* BB also check enough total bytes returned */
2167                         rc = -EIO;      /* bad smb */
2168                 else {
2169                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2170                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2171                         rc = cifs_copy_posix_acl(acl_inf,
2172                                 (char *)&pSMBr->hdr.Protocol+data_offset,
2173                                 buflen,acl_type,count);
2174                 }
2175         }
2176         cifs_buf_release(pSMB);
2177         if (rc == -EAGAIN)
2178                 goto queryAclRetry;
2179         return rc;
2180 }
2181
2182 int
2183 CIFSSMBSetPosixACL(const int xid, struct cifsTconInfo *tcon,
2184                         const unsigned char *fileName,
2185                         const char *local_acl, const int buflen, 
2186                         const int acl_type,
2187                         const struct nls_table *nls_codepage, int remap)
2188 {
2189         struct smb_com_transaction2_spi_req *pSMB = NULL;
2190         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
2191         char *parm_data;
2192         int name_len;
2193         int rc = 0;
2194         int bytes_returned = 0;
2195         __u16 params, byte_count, data_count, param_offset, offset;
2196
2197         cFYI(1, ("In SetPosixACL (Unix) for path %s", fileName));
2198 setAclRetry:
2199         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2200                       (void **) &pSMBr);
2201         if (rc)
2202                 return rc;
2203         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2204                 name_len =
2205                         cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
2206                                       PATH_MAX, nls_codepage, remap);
2207                 name_len++;     /* trailing null */
2208                 name_len *= 2;
2209         } else {                /* BB improve the check for buffer overruns BB */
2210                 name_len = strnlen(fileName, PATH_MAX);
2211                 name_len++;     /* trailing null */
2212                 strncpy(pSMB->FileName, fileName, name_len);
2213         }
2214         params = 6 + name_len;
2215         pSMB->MaxParameterCount = cpu_to_le16(2);
2216         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
2217         pSMB->MaxSetupCount = 0;
2218         pSMB->Reserved = 0;
2219         pSMB->Flags = 0;
2220         pSMB->Timeout = 0;
2221         pSMB->Reserved2 = 0;
2222         param_offset = offsetof(struct smb_com_transaction2_spi_req,
2223                                      InformationLevel) - 4;
2224         offset = param_offset + params;
2225         parm_data = ((char *) &pSMB->hdr.Protocol) + offset;
2226         pSMB->ParameterOffset = cpu_to_le16(param_offset);
2227
2228         /* convert to on the wire format for POSIX ACL */
2229         data_count = ACL_to_cifs_posix(parm_data,local_acl,buflen,acl_type);
2230
2231         if(data_count == 0) {
2232                 rc = -EOPNOTSUPP;
2233                 goto setACLerrorExit;
2234         }
2235         pSMB->DataOffset = cpu_to_le16(offset);
2236         pSMB->SetupCount = 1;
2237         pSMB->Reserved3 = 0;
2238         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
2239         pSMB->InformationLevel = cpu_to_le16(SMB_SET_POSIX_ACL);
2240         byte_count = 3 /* pad */  + params + data_count;
2241         pSMB->DataCount = cpu_to_le16(data_count);
2242         pSMB->TotalDataCount = pSMB->DataCount;
2243         pSMB->ParameterCount = cpu_to_le16(params);
2244         pSMB->TotalParameterCount = pSMB->ParameterCount;
2245         pSMB->Reserved4 = 0;
2246         pSMB->hdr.smb_buf_length += byte_count;
2247         pSMB->ByteCount = cpu_to_le16(byte_count);
2248         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2249                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2250         if (rc) {
2251                 cFYI(1, ("Set POSIX ACL returned %d", rc));
2252         }
2253
2254 setACLerrorExit:
2255         cifs_buf_release(pSMB);
2256         if (rc == -EAGAIN)
2257                 goto setAclRetry;
2258         return rc;
2259 }
2260
2261 /* BB fix tabs in this function FIXME BB */
2262 int
2263 CIFSGetExtAttr(const int xid, struct cifsTconInfo *tcon,
2264                 const int netfid, __u64 * pExtAttrBits, __u64 *pMask)
2265 {
2266         int rc = 0;
2267         struct smb_t2_qfi_req *pSMB = NULL;
2268         struct smb_t2_qfi_rsp *pSMBr = NULL;
2269         int bytes_returned;
2270         __u16 params, byte_count;
2271
2272         cFYI(1,("In GetExtAttr"));
2273         if(tcon == NULL)
2274                 return -ENODEV;
2275
2276 GetExtAttrRetry:
2277         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2278                       (void **) &pSMBr);
2279         if (rc)
2280                 return rc;
2281
2282         params = 2 /* level */ +2 /* fid */;
2283         pSMB->t2.TotalDataCount = 0;
2284         pSMB->t2.MaxParameterCount = cpu_to_le16(4);
2285         /* BB find exact max data count below from sess structure BB */
2286         pSMB->t2.MaxDataCount = cpu_to_le16(4000);
2287         pSMB->t2.MaxSetupCount = 0;
2288         pSMB->t2.Reserved = 0;
2289         pSMB->t2.Flags = 0;
2290         pSMB->t2.Timeout = 0;
2291         pSMB->t2.Reserved2 = 0;
2292         pSMB->t2.ParameterOffset = cpu_to_le16(offsetof(struct smb_t2_qfi_req,
2293                         Fid) - 4);
2294         pSMB->t2.DataCount = 0;
2295         pSMB->t2.DataOffset = 0;
2296         pSMB->t2.SetupCount = 1;
2297         pSMB->t2.Reserved3 = 0;
2298         pSMB->t2.SubCommand = cpu_to_le16(TRANS2_QUERY_FILE_INFORMATION);
2299         byte_count = params + 1 /* pad */ ;
2300         pSMB->t2.TotalParameterCount = cpu_to_le16(params);
2301         pSMB->t2.ParameterCount = pSMB->t2.TotalParameterCount;
2302         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_ATTR_FLAGS);
2303         pSMB->Pad = 0;
2304         pSMB->Fid = netfid;
2305         pSMB->hdr.smb_buf_length += byte_count;
2306         pSMB->t2.ByteCount = cpu_to_le16(byte_count);
2307
2308         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2309                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2310         if (rc) {
2311                 cFYI(1, ("error %d in GetExtAttr", rc));
2312         } else {
2313                 /* decode response */
2314                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2315                 if (rc || (pSMBr->ByteCount < 2))
2316                 /* BB also check enough total bytes returned */
2317                         /* If rc should we check for EOPNOSUPP and
2318                         disable the srvino flag? or in caller? */
2319                         rc = -EIO;      /* bad smb */
2320                 else {
2321                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2322                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
2323                         struct file_chattr_info * pfinfo;
2324                         /* BB Do we need a cast or hash here ? */
2325                         if(count != 16) {
2326                                 cFYI(1, ("Illegal size ret in GetExtAttr"));
2327                                 rc = -EIO;
2328                                 goto GetExtAttrOut;
2329                         }
2330                         pfinfo = (struct file_chattr_info *)
2331                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
2332                         *pExtAttrBits = le64_to_cpu(pfinfo->mode);
2333                         *pMask = le64_to_cpu(pfinfo->mask);
2334                 }
2335         }
2336 GetExtAttrOut:
2337         cifs_buf_release(pSMB);
2338         if (rc == -EAGAIN)
2339                 goto GetExtAttrRetry;
2340         return rc;
2341 }
2342
2343
2344 #endif /* CONFIG_POSIX */
2345
2346 /* Legacy Query Path Information call for lookup to old servers such
2347    as Win9x/WinME */
2348 int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
2349                  const unsigned char *searchName,
2350                  FILE_ALL_INFO * pFinfo,
2351                  const struct nls_table *nls_codepage, int remap)
2352 {
2353         QUERY_INFORMATION_REQ * pSMB;
2354         QUERY_INFORMATION_RSP * pSMBr;
2355         int rc = 0;
2356         int bytes_returned;
2357         int name_len;
2358
2359         cFYI(1, ("In SMBQPath path %s", searchName)); 
2360 QInfRetry:
2361         rc = smb_init(SMB_COM_QUERY_INFORMATION, 0, tcon, (void **) &pSMB,
2362                       (void **) &pSMBr);
2363         if (rc)
2364                 return rc;
2365
2366         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2367                 name_len =
2368                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2369                                      PATH_MAX, nls_codepage, remap);
2370                 name_len++;     /* trailing null */
2371                 name_len *= 2;
2372         } else {               
2373                 name_len = strnlen(searchName, PATH_MAX);
2374                 name_len++;     /* trailing null */
2375                 strncpy(pSMB->FileName, searchName, name_len);
2376         }
2377         pSMB->BufferFormat = 0x04;
2378         name_len++; /* account for buffer type byte */  
2379         pSMB->hdr.smb_buf_length += (__u16) name_len;
2380         pSMB->ByteCount = cpu_to_le16(name_len);
2381
2382         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2383                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2384         if (rc) {
2385                 cFYI(1, ("Send error in QueryInfo = %d", rc));
2386         } else if (pFinfo) {            /* decode response */
2387                 memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
2388                 pFinfo->AllocationSize = (__le64) pSMBr->size;
2389                 pFinfo->EndOfFile = (__le64) pSMBr->size;
2390                 pFinfo->Attributes = (__le32) pSMBr->attr;
2391         } else
2392                 rc = -EIO; /* bad buffer passed in */
2393
2394         cifs_buf_release(pSMB);
2395
2396         if (rc == -EAGAIN)
2397                 goto QInfRetry;
2398
2399         return rc;
2400 }
2401
2402
2403
2404
2405 int
2406 CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
2407                  const unsigned char *searchName,
2408                  FILE_ALL_INFO * pFindData,
2409                  const struct nls_table *nls_codepage, int remap)
2410 {
2411 /* level 263 SMB_QUERY_FILE_ALL_INFO */
2412         TRANSACTION2_QPI_REQ *pSMB = NULL;
2413         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2414         int rc = 0;
2415         int bytes_returned;
2416         int name_len;
2417         __u16 params, byte_count;
2418
2419 /* cFYI(1, ("In QPathInfo path %s", searchName)); */
2420 QPathInfoRetry:
2421         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2422                       (void **) &pSMBr);
2423         if (rc)
2424                 return rc;
2425
2426         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2427                 name_len =
2428                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
2429                                      PATH_MAX, nls_codepage, remap);
2430                 name_len++;     /* trailing null */
2431                 name_len *= 2;
2432         } else {                /* BB improve the check for buffer overruns BB */
2433                 name_len = strnlen(searchName, PATH_MAX);
2434                 name_len++;     /* trailing null */
2435                 strncpy(pSMB->FileName, searchName, name_len);
2436         }
2437
2438         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2439         pSMB->TotalDataCount = 0;
2440         pSMB->MaxParameterCount = cpu_to_le16(2);
2441         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2442         pSMB->MaxSetupCount = 0;
2443         pSMB->Reserved = 0;
2444         pSMB->Flags = 0;
2445         pSMB->Timeout = 0;
2446         pSMB->Reserved2 = 0;
2447         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2448         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2449         pSMB->DataCount = 0;
2450         pSMB->DataOffset = 0;
2451         pSMB->SetupCount = 1;
2452         pSMB->Reserved3 = 0;
2453         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2454         byte_count = params + 1 /* pad */ ;
2455         pSMB->TotalParameterCount = cpu_to_le16(params);
2456         pSMB->ParameterCount = pSMB->TotalParameterCount;
2457         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
2458         pSMB->Reserved4 = 0;
2459         pSMB->hdr.smb_buf_length += byte_count;
2460         pSMB->ByteCount = cpu_to_le16(byte_count);
2461
2462         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2463                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2464         if (rc) {
2465                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2466         } else {                /* decode response */
2467                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2468
2469                 if (rc || (pSMBr->ByteCount < 40)) 
2470                         rc = -EIO;      /* bad smb */
2471                 else if (pFindData){
2472                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2473                         memcpy((char *) pFindData,
2474                                (char *) &pSMBr->hdr.Protocol +
2475                                data_offset, sizeof (FILE_ALL_INFO));
2476                 } else
2477                     rc = -ENOMEM;
2478         }
2479         cifs_buf_release(pSMB);
2480         if (rc == -EAGAIN)
2481                 goto QPathInfoRetry;
2482
2483         return rc;
2484 }
2485
2486 int
2487 CIFSSMBUnixQPathInfo(const int xid, struct cifsTconInfo *tcon,
2488                      const unsigned char *searchName,
2489                      FILE_UNIX_BASIC_INFO * pFindData,
2490                      const struct nls_table *nls_codepage, int remap)
2491 {
2492 /* SMB_QUERY_FILE_UNIX_BASIC */
2493         TRANSACTION2_QPI_REQ *pSMB = NULL;
2494         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2495         int rc = 0;
2496         int bytes_returned = 0;
2497         int name_len;
2498         __u16 params, byte_count;
2499
2500         cFYI(1, ("In QPathInfo (Unix) the path %s", searchName));
2501 UnixQPathInfoRetry:
2502         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2503                       (void **) &pSMBr);
2504         if (rc)
2505                 return rc;
2506
2507         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2508                 name_len =
2509                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2510                                   PATH_MAX, nls_codepage, remap);
2511                 name_len++;     /* trailing null */
2512                 name_len *= 2;
2513         } else {                /* BB improve the check for buffer overruns BB */
2514                 name_len = strnlen(searchName, PATH_MAX);
2515                 name_len++;     /* trailing null */
2516                 strncpy(pSMB->FileName, searchName, name_len);
2517         }
2518
2519         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
2520         pSMB->TotalDataCount = 0;
2521         pSMB->MaxParameterCount = cpu_to_le16(2);
2522         /* BB find exact max SMB PDU from sess structure BB */
2523         pSMB->MaxDataCount = cpu_to_le16(4000); 
2524         pSMB->MaxSetupCount = 0;
2525         pSMB->Reserved = 0;
2526         pSMB->Flags = 0;
2527         pSMB->Timeout = 0;
2528         pSMB->Reserved2 = 0;
2529         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2530         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2531         pSMB->DataCount = 0;
2532         pSMB->DataOffset = 0;
2533         pSMB->SetupCount = 1;
2534         pSMB->Reserved3 = 0;
2535         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2536         byte_count = params + 1 /* pad */ ;
2537         pSMB->TotalParameterCount = cpu_to_le16(params);
2538         pSMB->ParameterCount = pSMB->TotalParameterCount;
2539         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC);
2540         pSMB->Reserved4 = 0;
2541         pSMB->hdr.smb_buf_length += byte_count;
2542         pSMB->ByteCount = cpu_to_le16(byte_count);
2543
2544         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2545                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2546         if (rc) {
2547                 cFYI(1, ("Send error in QPathInfo = %d", rc));
2548         } else {                /* decode response */
2549                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2550
2551                 if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) {
2552                         rc = -EIO;      /* bad smb */
2553                 } else {
2554                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
2555                         memcpy((char *) pFindData,
2556                                (char *) &pSMBr->hdr.Protocol +
2557                                data_offset,
2558                                sizeof (FILE_UNIX_BASIC_INFO));
2559                 }
2560         }
2561         cifs_buf_release(pSMB);
2562         if (rc == -EAGAIN)
2563                 goto UnixQPathInfoRetry;
2564
2565         return rc;
2566 }
2567
2568 #if 0  /* function unused at present */
2569 int CIFSFindSingle(const int xid, struct cifsTconInfo *tcon,
2570                const char *searchName, FILE_ALL_INFO * findData,
2571                const struct nls_table *nls_codepage)
2572 {
2573 /* level 257 SMB_ */
2574         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2575         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2576         int rc = 0;
2577         int bytes_returned;
2578         int name_len;
2579         __u16 params, byte_count;
2580
2581         cFYI(1, ("In FindUnique"));
2582 findUniqueRetry:
2583         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2584                       (void **) &pSMBr);
2585         if (rc)
2586                 return rc;
2587
2588         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2589                 name_len =
2590                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX
2591                                   /* find define for this maxpathcomponent */
2592                                   , nls_codepage);
2593                 name_len++;     /* trailing null */
2594                 name_len *= 2;
2595         } else {                /* BB improve the check for buffer overruns BB */
2596                 name_len = strnlen(searchName, PATH_MAX);
2597                 name_len++;     /* trailing null */
2598                 strncpy(pSMB->FileName, searchName, name_len);
2599         }
2600
2601         params = 12 + name_len /* includes null */ ;
2602         pSMB->TotalDataCount = 0;       /* no EAs */
2603         pSMB->MaxParameterCount = cpu_to_le16(2);
2604         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
2605         pSMB->MaxSetupCount = 0;
2606         pSMB->Reserved = 0;
2607         pSMB->Flags = 0;
2608         pSMB->Timeout = 0;
2609         pSMB->Reserved2 = 0;
2610         pSMB->ParameterOffset = cpu_to_le16(
2611          offsetof(struct smb_com_transaction2_ffirst_req,InformationLevel) - 4);
2612         pSMB->DataCount = 0;
2613         pSMB->DataOffset = 0;
2614         pSMB->SetupCount = 1;   /* one byte, no need to le convert */
2615         pSMB->Reserved3 = 0;
2616         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2617         byte_count = params + 1 /* pad */ ;
2618         pSMB->TotalParameterCount = cpu_to_le16(params);
2619         pSMB->ParameterCount = pSMB->TotalParameterCount;
2620         pSMB->SearchAttributes =
2621             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2622                         ATTR_DIRECTORY);
2623         pSMB->SearchCount = cpu_to_le16(16);    /* BB increase */
2624         pSMB->SearchFlags = cpu_to_le16(1);
2625         pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2626         pSMB->SearchStorageType = 0;    /* BB what should we set this to? BB */
2627         pSMB->hdr.smb_buf_length += byte_count;
2628         pSMB->ByteCount = cpu_to_le16(byte_count);
2629
2630         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2631                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2632
2633         if (rc) {
2634                 cFYI(1, ("Send error in FindFileDirInfo = %d", rc));
2635         } else {                /* decode response */
2636                 cifs_stats_inc(&tcon->num_ffirst);
2637                 /* BB fill in */
2638         }
2639
2640         cifs_buf_release(pSMB);
2641         if (rc == -EAGAIN)
2642                 goto findUniqueRetry;
2643
2644         return rc;
2645 }
2646 #endif /* end unused (temporarily) function */
2647
2648 /* xid, tcon, searchName and codepage are input parms, rest are returned */
2649 int
2650 CIFSFindFirst(const int xid, struct cifsTconInfo *tcon,
2651               const char *searchName, 
2652               const struct nls_table *nls_codepage,
2653               __u16 *   pnetfid,
2654               struct cifs_search_info * psrch_inf, int remap, const char dirsep)
2655 {
2656 /* level 257 SMB_ */
2657         TRANSACTION2_FFIRST_REQ *pSMB = NULL;
2658         TRANSACTION2_FFIRST_RSP *pSMBr = NULL;
2659         T2_FFIRST_RSP_PARMS * parms;
2660         int rc = 0;
2661         int bytes_returned = 0;
2662         int name_len;
2663         __u16 params, byte_count;
2664
2665         cFYI(1, ("In FindFirst for %s",searchName));
2666
2667 findFirstRetry:
2668         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2669                       (void **) &pSMBr);
2670         if (rc)
2671                 return rc;
2672
2673         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2674                 name_len =
2675                     cifsConvertToUCS((__le16 *) pSMB->FileName,searchName,
2676                                  PATH_MAX, nls_codepage, remap);
2677                 /* We can not add the asterik earlier in case
2678                 it got remapped to 0xF03A as if it were part of the
2679                 directory name instead of a wildcard */
2680                 name_len *= 2;
2681                 pSMB->FileName[name_len] = dirsep;
2682                 pSMB->FileName[name_len+1] = 0;
2683                 pSMB->FileName[name_len+2] = '*';
2684                 pSMB->FileName[name_len+3] = 0;
2685                 name_len += 4; /* now the trailing null */
2686                 pSMB->FileName[name_len] = 0; /* null terminate just in case */
2687                 pSMB->FileName[name_len+1] = 0;
2688                 name_len += 2;
2689         } else {        /* BB add check for overrun of SMB buf BB */
2690                 name_len = strnlen(searchName, PATH_MAX);
2691 /* BB fix here and in unicode clause above ie
2692                 if(name_len > buffersize-header)
2693                         free buffer exit; BB */
2694                 strncpy(pSMB->FileName, searchName, name_len);
2695                 pSMB->FileName[name_len] = dirsep;
2696                 pSMB->FileName[name_len+1] = '*';
2697                 pSMB->FileName[name_len+2] = 0;
2698                 name_len += 3;
2699         }
2700
2701         params = 12 + name_len /* includes null */ ;
2702         pSMB->TotalDataCount = 0;       /* no EAs */
2703         pSMB->MaxParameterCount = cpu_to_le16(10);
2704         pSMB->MaxDataCount = cpu_to_le16((tcon->ses->server->maxBuf -
2705                                           MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2706         pSMB->MaxSetupCount = 0;
2707         pSMB->Reserved = 0;
2708         pSMB->Flags = 0;
2709         pSMB->Timeout = 0;
2710         pSMB->Reserved2 = 0;
2711         byte_count = params + 1 /* pad */ ;
2712         pSMB->TotalParameterCount = cpu_to_le16(params);
2713         pSMB->ParameterCount = pSMB->TotalParameterCount;
2714         pSMB->ParameterOffset = cpu_to_le16(
2715           offsetof(struct smb_com_transaction2_ffirst_req, SearchAttributes) - 4);
2716         pSMB->DataCount = 0;
2717         pSMB->DataOffset = 0;
2718         pSMB->SetupCount = 1;   /* one byte, no need to make endian neutral */
2719         pSMB->Reserved3 = 0;
2720         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_FIRST);
2721         pSMB->SearchAttributes =
2722             cpu_to_le16(ATTR_READONLY | ATTR_HIDDEN | ATTR_SYSTEM |
2723                         ATTR_DIRECTORY);
2724         pSMB->SearchCount= cpu_to_le16(CIFSMaxBufSize/sizeof(FILE_UNIX_INFO));
2725         pSMB->SearchFlags = cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | 
2726                 CIFS_SEARCH_RETURN_RESUME);
2727         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2728
2729         /* BB what should we set StorageType to? Does it matter? BB */
2730         pSMB->SearchStorageType = 0;
2731         pSMB->hdr.smb_buf_length += byte_count;
2732         pSMB->ByteCount = cpu_to_le16(byte_count);
2733
2734         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2735                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2736         cifs_stats_inc(&tcon->num_ffirst);
2737
2738         if (rc) {/* BB add logic to retry regular search if Unix search rejected unexpectedly by server */
2739                 /* BB Add code to handle unsupported level rc */
2740                 cFYI(1, ("Error in FindFirst = %d", rc));
2741
2742                 if (pSMB)
2743                         cifs_buf_release(pSMB);
2744
2745                 /* BB eventually could optimize out free and realloc of buf */
2746                 /*    for this case */
2747                 if (rc == -EAGAIN)
2748                         goto findFirstRetry;
2749         } else { /* decode response */
2750                 /* BB remember to free buffer if error BB */
2751                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2752                 if(rc == 0) {
2753                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2754                                 psrch_inf->unicode = TRUE;
2755                         else
2756                                 psrch_inf->unicode = FALSE;
2757
2758                         psrch_inf->ntwrk_buf_start = (char *)pSMBr;
2759                         psrch_inf->srch_entries_start = 
2760                                 (char *) &pSMBr->hdr.Protocol + 
2761                                         le16_to_cpu(pSMBr->t2.DataOffset);
2762                         parms = (T2_FFIRST_RSP_PARMS *)((char *) &pSMBr->hdr.Protocol +
2763                                le16_to_cpu(pSMBr->t2.ParameterOffset));
2764
2765                         if(parms->EndofSearch)
2766                                 psrch_inf->endOfSearch = TRUE;
2767                         else
2768                                 psrch_inf->endOfSearch = FALSE;
2769
2770                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2771                         psrch_inf->index_of_last_entry = 
2772                                 psrch_inf->entries_in_buffer;
2773                         *pnetfid = parms->SearchHandle;
2774                 } else {
2775                         cifs_buf_release(pSMB);
2776                 }
2777         }
2778
2779         return rc;
2780 }
2781
2782 int CIFSFindNext(const int xid, struct cifsTconInfo *tcon,
2783             __u16 searchHandle, struct cifs_search_info * psrch_inf)
2784 {
2785         TRANSACTION2_FNEXT_REQ *pSMB = NULL;
2786         TRANSACTION2_FNEXT_RSP *pSMBr = NULL;
2787         T2_FNEXT_RSP_PARMS * parms;
2788         char *response_data;
2789         int rc = 0;
2790         int bytes_returned, name_len;
2791         __u16 params, byte_count;
2792
2793         cFYI(1, ("In FindNext"));
2794
2795         if(psrch_inf->endOfSearch == TRUE)
2796                 return -ENOENT;
2797
2798         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2799                 (void **) &pSMBr);
2800         if (rc)
2801                 return rc;
2802
2803         params = 14;    /* includes 2 bytes of null string, converted to LE below */
2804         byte_count = 0;
2805         pSMB->TotalDataCount = 0;       /* no EAs */
2806         pSMB->MaxParameterCount = cpu_to_le16(8);
2807         pSMB->MaxDataCount =
2808             cpu_to_le16((tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFF00);
2809         pSMB->MaxSetupCount = 0;
2810         pSMB->Reserved = 0;
2811         pSMB->Flags = 0;
2812         pSMB->Timeout = 0;
2813         pSMB->Reserved2 = 0;
2814         pSMB->ParameterOffset =  cpu_to_le16(
2815               offsetof(struct smb_com_transaction2_fnext_req,SearchHandle) - 4);
2816         pSMB->DataCount = 0;
2817         pSMB->DataOffset = 0;
2818         pSMB->SetupCount = 1;
2819         pSMB->Reserved3 = 0;
2820         pSMB->SubCommand = cpu_to_le16(TRANS2_FIND_NEXT);
2821         pSMB->SearchHandle = searchHandle;      /* always kept as le */
2822         pSMB->SearchCount =
2823                 cpu_to_le16(CIFSMaxBufSize / sizeof (FILE_UNIX_INFO));
2824         /* test for Unix extensions */
2825 /*      if (tcon->ses->capabilities & CAP_UNIX) {
2826                 pSMB->InformationLevel = cpu_to_le16(SMB_FIND_FILE_UNIX);
2827                 psrch_inf->info_level = SMB_FIND_FILE_UNIX;
2828         } else {
2829                 pSMB->InformationLevel =
2830                    cpu_to_le16(SMB_FIND_FILE_DIRECTORY_INFO);
2831                 psrch_inf->info_level = SMB_FIND_FILE_DIRECTORY_INFO;
2832         } */
2833         pSMB->InformationLevel = cpu_to_le16(psrch_inf->info_level);
2834         pSMB->ResumeKey = psrch_inf->resume_key;
2835         pSMB->SearchFlags =
2836               cpu_to_le16(CIFS_SEARCH_CLOSE_AT_END | CIFS_SEARCH_RETURN_RESUME);
2837
2838         name_len = psrch_inf->resume_name_len;
2839         params += name_len;
2840         if(name_len < PATH_MAX) {
2841                 memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len);
2842                 byte_count += name_len;
2843                 /* 14 byte parm len above enough for 2 byte null terminator */
2844                 pSMB->ResumeFileName[name_len] = 0;
2845                 pSMB->ResumeFileName[name_len+1] = 0;
2846         } else {
2847                 rc = -EINVAL;
2848                 goto FNext2_err_exit;
2849         }
2850         byte_count = params + 1 /* pad */ ;
2851         pSMB->TotalParameterCount = cpu_to_le16(params);
2852         pSMB->ParameterCount = pSMB->TotalParameterCount;
2853         pSMB->hdr.smb_buf_length += byte_count;
2854         pSMB->ByteCount = cpu_to_le16(byte_count);
2855                                                                                               
2856         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2857                         (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2858         cifs_stats_inc(&tcon->num_fnext);
2859         if (rc) {
2860                 if (rc == -EBADF) {
2861                         psrch_inf->endOfSearch = TRUE;
2862                         rc = 0; /* search probably was closed at end of search above */
2863                 } else
2864                         cFYI(1, ("FindNext returned = %d", rc));
2865         } else {                /* decode response */
2866                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
2867                 
2868                 if(rc == 0) {
2869                         /* BB fixme add lock for file (srch_info) struct here */
2870                         if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE)
2871                                 psrch_inf->unicode = TRUE;
2872                         else
2873                                 psrch_inf->unicode = FALSE;
2874                         response_data = (char *) &pSMBr->hdr.Protocol +
2875                                le16_to_cpu(pSMBr->t2.ParameterOffset);
2876                         parms = (T2_FNEXT_RSP_PARMS *)response_data;
2877                         response_data = (char *)&pSMBr->hdr.Protocol +
2878                                 le16_to_cpu(pSMBr->t2.DataOffset);
2879                         cifs_buf_release(psrch_inf->ntwrk_buf_start);
2880                         psrch_inf->srch_entries_start = response_data;
2881                         psrch_inf->ntwrk_buf_start = (char *)pSMB;
2882                         if(parms->EndofSearch)
2883                                 psrch_inf->endOfSearch = TRUE;
2884                         else
2885                                 psrch_inf->endOfSearch = FALSE;
2886                                                                                               
2887                         psrch_inf->entries_in_buffer  = le16_to_cpu(parms->SearchCount);
2888                         psrch_inf->index_of_last_entry +=
2889                                 psrch_inf->entries_in_buffer;
2890 /*  cFYI(1,("fnxt2 entries in buf %d index_of_last %d",psrch_inf->entries_in_buffer,psrch_inf->index_of_last_entry)); */
2891
2892                         /* BB fixme add unlock here */
2893                 }
2894
2895         }
2896
2897         /* BB On error, should we leave previous search buf (and count and
2898         last entry fields) intact or free the previous one? */
2899
2900         /* Note: On -EAGAIN error only caller can retry on handle based calls
2901         since file handle passed in no longer valid */
2902 FNext2_err_exit:
2903         if (rc != 0)
2904                 cifs_buf_release(pSMB);
2905                                                                                               
2906         return rc;
2907 }
2908
2909 int
2910 CIFSFindClose(const int xid, struct cifsTconInfo *tcon, const __u16 searchHandle)
2911 {
2912         int rc = 0;
2913         FINDCLOSE_REQ *pSMB = NULL;
2914         CLOSE_RSP *pSMBr = NULL; /* BB removeme BB */
2915         int bytes_returned;
2916
2917         cFYI(1, ("In CIFSSMBFindClose"));
2918         rc = small_smb_init(SMB_COM_FIND_CLOSE2, 1, tcon, (void **)&pSMB);
2919
2920         /* no sense returning error if session restarted
2921                 as file handle has been closed */
2922         if(rc == -EAGAIN)
2923                 return 0;
2924         if (rc)
2925                 return rc;
2926
2927         pSMBr = (CLOSE_RSP *)pSMB;  /* BB removeme BB */
2928         pSMB->FileID = searchHandle;
2929         pSMB->ByteCount = 0;
2930         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
2931                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
2932         if (rc) {
2933                 cERROR(1, ("Send error in FindClose = %d", rc));
2934         }
2935         cifs_stats_inc(&tcon->num_fclose);
2936         cifs_small_buf_release(pSMB);
2937
2938         /* Since session is dead, search handle closed on server already */
2939         if (rc == -EAGAIN)
2940                 rc = 0;
2941
2942         return rc;
2943 }
2944
2945 #ifdef CONFIG_CIFS_EXPERIMENTAL
2946 int
2947 CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon,
2948                 const unsigned char *searchName,
2949                 __u64 * inode_number,
2950                 const struct nls_table *nls_codepage, int remap)
2951 {
2952         int rc = 0;
2953         TRANSACTION2_QPI_REQ *pSMB = NULL;
2954         TRANSACTION2_QPI_RSP *pSMBr = NULL;
2955         int name_len, bytes_returned;
2956         __u16 params, byte_count;
2957
2958         cFYI(1,("In GetSrvInodeNum for %s",searchName));
2959         if(tcon == NULL)
2960                 return -ENODEV; 
2961
2962 GetInodeNumberRetry:
2963         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
2964                       (void **) &pSMBr);
2965         if (rc)
2966                 return rc;
2967
2968
2969         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
2970                 name_len =
2971                         cifsConvertToUCS((__le16 *) pSMB->FileName, searchName,
2972                                 PATH_MAX,nls_codepage, remap);
2973                 name_len++;     /* trailing null */
2974                 name_len *= 2;
2975         } else {                /* BB improve the check for buffer overruns BB */
2976                 name_len = strnlen(searchName, PATH_MAX);
2977                 name_len++;     /* trailing null */
2978                 strncpy(pSMB->FileName, searchName, name_len);
2979         }
2980
2981         params = 2 /* level */  + 4 /* rsrvd */  + name_len /* incl null */ ;
2982         pSMB->TotalDataCount = 0;
2983         pSMB->MaxParameterCount = cpu_to_le16(2);
2984         /* BB find exact max data count below from sess structure BB */
2985         pSMB->MaxDataCount = cpu_to_le16(4000);
2986         pSMB->MaxSetupCount = 0;
2987         pSMB->Reserved = 0;
2988         pSMB->Flags = 0;
2989         pSMB->Timeout = 0;
2990         pSMB->Reserved2 = 0;
2991         pSMB->ParameterOffset = cpu_to_le16(offsetof(
2992                 struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
2993         pSMB->DataCount = 0;
2994         pSMB->DataOffset = 0;
2995         pSMB->SetupCount = 1;
2996         pSMB->Reserved3 = 0;
2997         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
2998         byte_count = params + 1 /* pad */ ;
2999         pSMB->TotalParameterCount = cpu_to_le16(params);
3000         pSMB->ParameterCount = pSMB->TotalParameterCount;
3001         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_INTERNAL_INFO);
3002         pSMB->Reserved4 = 0;
3003         pSMB->hdr.smb_buf_length += byte_count;
3004         pSMB->ByteCount = cpu_to_le16(byte_count);
3005
3006         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3007                 (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3008         if (rc) {
3009                 cFYI(1, ("error %d in QueryInternalInfo", rc));
3010         } else {
3011                 /* decode response */
3012                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3013                 if (rc || (pSMBr->ByteCount < 2))
3014                 /* BB also check enough total bytes returned */
3015                         /* If rc should we check for EOPNOSUPP and
3016                         disable the srvino flag? or in caller? */
3017                         rc = -EIO;      /* bad smb */
3018                 else {
3019                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3020                         __u16 count = le16_to_cpu(pSMBr->t2.DataCount);
3021                         struct file_internal_info * pfinfo;
3022                         /* BB Do we need a cast or hash here ? */
3023                         if(count < 8) {
3024                                 cFYI(1, ("Illegal size ret in QryIntrnlInf"));
3025                                 rc = -EIO;
3026                                 goto GetInodeNumOut;
3027                         }
3028                         pfinfo = (struct file_internal_info *)
3029                                 (data_offset + (char *) &pSMBr->hdr.Protocol);
3030                         *inode_number = pfinfo->UniqueId;
3031                 }
3032         }
3033 GetInodeNumOut:
3034         cifs_buf_release(pSMB);
3035         if (rc == -EAGAIN)
3036                 goto GetInodeNumberRetry;
3037         return rc;
3038 }
3039 #endif /* CIFS_EXPERIMENTAL */
3040
3041 int
3042 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
3043                 const unsigned char *searchName,
3044                 unsigned char **targetUNCs,
3045                 unsigned int *number_of_UNC_in_array,
3046                 const struct nls_table *nls_codepage, int remap)
3047 {
3048 /* TRANS2_GET_DFS_REFERRAL */
3049         TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
3050         TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
3051         struct dfs_referral_level_3 * referrals = NULL;
3052         int rc = 0;
3053         int bytes_returned;
3054         int name_len;
3055         unsigned int i;
3056         char * temp;
3057         __u16 params, byte_count;
3058         *number_of_UNC_in_array = 0;
3059         *targetUNCs = NULL;
3060
3061         cFYI(1, ("In GetDFSRefer the path %s", searchName));
3062         if (ses == NULL)
3063                 return -ENODEV;
3064 getDFSRetry:
3065         rc = smb_init(SMB_COM_TRANSACTION2, 15, NULL, (void **) &pSMB,
3066                       (void **) &pSMBr);
3067         if (rc)
3068                 return rc;
3069         
3070         /* server pointer checked in called function, 
3071         but should never be null here anyway */
3072         pSMB->hdr.Mid = GetNextMid(ses->server);
3073         pSMB->hdr.Tid = ses->ipc_tid;
3074         pSMB->hdr.Uid = ses->Suid;
3075         if (ses->capabilities & CAP_STATUS32) {
3076                 pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS;
3077         }
3078         if (ses->capabilities & CAP_DFS) {
3079                 pSMB->hdr.Flags2 |= SMBFLG2_DFS;
3080         }
3081
3082         if (ses->capabilities & CAP_UNICODE) {
3083                 pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
3084                 name_len =
3085                     cifsConvertToUCS((__le16 *) pSMB->RequestFileName,
3086                                      searchName, PATH_MAX, nls_codepage, remap);
3087                 name_len++;     /* trailing null */
3088                 name_len *= 2;
3089         } else {                /* BB improve the check for buffer overruns BB */
3090                 name_len = strnlen(searchName, PATH_MAX);
3091                 name_len++;     /* trailing null */
3092                 strncpy(pSMB->RequestFileName, searchName, name_len);
3093         }
3094
3095         params = 2 /* level */  + name_len /*includes null */ ;
3096         pSMB->TotalDataCount = 0;
3097         pSMB->DataCount = 0;
3098         pSMB->DataOffset = 0;
3099         pSMB->MaxParameterCount = 0;
3100         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
3101         pSMB->MaxSetupCount = 0;
3102         pSMB->Reserved = 0;
3103         pSMB->Flags = 0;
3104         pSMB->Timeout = 0;
3105         pSMB->Reserved2 = 0;
3106         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3107         struct smb_com_transaction2_get_dfs_refer_req, MaxReferralLevel) - 4);
3108         pSMB->SetupCount = 1;
3109         pSMB->Reserved3 = 0;
3110         pSMB->SubCommand = cpu_to_le16(TRANS2_GET_DFS_REFERRAL);
3111         byte_count = params + 3 /* pad */ ;
3112         pSMB->ParameterCount = cpu_to_le16(params);
3113         pSMB->TotalParameterCount = pSMB->ParameterCount;
3114         pSMB->MaxReferralLevel = cpu_to_le16(3);
3115         pSMB->hdr.smb_buf_length += byte_count;
3116         pSMB->ByteCount = cpu_to_le16(byte_count);
3117
3118         rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB,
3119                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3120         if (rc) {
3121                 cFYI(1, ("Send error in GetDFSRefer = %d", rc));
3122         } else {                /* decode response */
3123 /* BB Add logic to parse referrals here */
3124                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3125
3126                 if (rc || (pSMBr->ByteCount < 17))      /* BB also check enough total bytes returned */
3127                         rc = -EIO;      /* bad smb */
3128                 else {
3129                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); 
3130                         __u16 data_count = le16_to_cpu(pSMBr->t2.DataCount);
3131
3132                         cFYI(1,
3133                              ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
3134                               pSMBr->ByteCount, data_offset));
3135                         referrals = 
3136                             (struct dfs_referral_level_3 *) 
3137                                         (8 /* sizeof start of data block */ +
3138                                         data_offset +
3139                                         (char *) &pSMBr->hdr.Protocol); 
3140                         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",
3141                                 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)));
3142                         /* BB This field is actually two bytes in from start of
3143                            data block so we could do safety check that DataBlock
3144                            begins at address of pSMBr->NumberOfReferrals */
3145                         *number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
3146
3147                         /* BB Fix below so can return more than one referral */
3148                         if(*number_of_UNC_in_array > 1)
3149                                 *number_of_UNC_in_array = 1;
3150
3151                         /* get the length of the strings describing refs */
3152                         name_len = 0;
3153                         for(i=0;i<*number_of_UNC_in_array;i++) {
3154                                 /* make sure that DfsPathOffset not past end */
3155                                 __u16 offset = le16_to_cpu(referrals->DfsPathOffset);
3156                                 if (offset > data_count) {
3157                                         /* if invalid referral, stop here and do 
3158                                         not try to copy any more */
3159                                         *number_of_UNC_in_array = i;
3160                                         break;
3161                                 } 
3162                                 temp = ((char *)referrals) + offset;
3163
3164                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3165                                         name_len += UniStrnlen((wchar_t *)temp,data_count);
3166                                 } else {
3167                                         name_len += strnlen(temp,data_count);
3168                                 }
3169                                 referrals++;
3170                                 /* BB add check that referral pointer does not fall off end PDU */
3171                                 
3172                         }
3173                         /* BB add check for name_len bigger than bcc */
3174                         *targetUNCs = 
3175                                 kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
3176                         if(*targetUNCs == NULL) {
3177                                 rc = -ENOMEM;
3178                                 goto GetDFSRefExit;
3179                         }
3180                         /* copy the ref strings */
3181                         referrals =  
3182                             (struct dfs_referral_level_3 *) 
3183                                         (8 /* sizeof data hdr */ +
3184                                         data_offset + 
3185                                         (char *) &pSMBr->hdr.Protocol);
3186
3187                         for(i=0;i<*number_of_UNC_in_array;i++) {
3188                                 temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset);
3189                                 if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
3190                                         cifs_strfromUCS_le(*targetUNCs,
3191                                                 (wchar_t *) temp, name_len, nls_codepage);
3192                                 } else {
3193                                         strncpy(*targetUNCs,temp,name_len);
3194                                 }
3195                                 /*  BB update target_uncs pointers */
3196                                 referrals++;
3197                         }
3198                         temp = *targetUNCs;
3199                         temp[name_len] = 0;
3200                 }
3201
3202         }
3203 GetDFSRefExit:
3204         if (pSMB)
3205                 cifs_buf_release(pSMB);
3206
3207         if (rc == -EAGAIN)
3208                 goto getDFSRetry;
3209
3210         return rc;
3211 }
3212
3213 int
3214 CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon, struct kstatfs *FSData)
3215 {
3216 /* level 0x103 SMB_QUERY_FILE_SYSTEM_INFO */
3217         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3218         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3219         FILE_SYSTEM_INFO *response_data;
3220         int rc = 0;
3221         int bytes_returned = 0;
3222         __u16 params, byte_count;
3223
3224         cFYI(1, ("In QFSInfo"));
3225 QFSInfoRetry:
3226         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3227                       (void **) &pSMBr);
3228         if (rc)
3229                 return rc;
3230
3231         params = 2;     /* level */
3232         pSMB->TotalDataCount = 0;
3233         pSMB->MaxParameterCount = cpu_to_le16(2);
3234         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3235         pSMB->MaxSetupCount = 0;
3236         pSMB->Reserved = 0;
3237         pSMB->Flags = 0;
3238         pSMB->Timeout = 0;
3239         pSMB->Reserved2 = 0;
3240         byte_count = params + 1 /* pad */ ;
3241         pSMB->TotalParameterCount = cpu_to_le16(params);
3242         pSMB->ParameterCount = pSMB->TotalParameterCount;
3243         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3244         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3245         pSMB->DataCount = 0;
3246         pSMB->DataOffset = 0;
3247         pSMB->SetupCount = 1;
3248         pSMB->Reserved3 = 0;
3249         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3250         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_SIZE_INFO);
3251         pSMB->hdr.smb_buf_length += byte_count;
3252         pSMB->ByteCount = cpu_to_le16(byte_count);
3253
3254         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3255                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3256         if (rc) {
3257                 cERROR(1, ("Send error in QFSInfo = %d", rc));
3258         } else {                /* decode response */
3259                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3260
3261                 if (rc || (pSMBr->ByteCount < 24)) /* BB alsO CHEck enough total bytes returned */
3262                         rc = -EIO;      /* bad smb */
3263                 else {
3264                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3265                         cFYI(1,
3266                                 ("Decoding qfsinfo response.  BCC: %d  Offset %d",
3267                                 pSMBr->ByteCount, data_offset));
3268
3269                         response_data =
3270                             (FILE_SYSTEM_INFO
3271                              *) (((char *) &pSMBr->hdr.Protocol) +
3272                                  data_offset);
3273                         FSData->f_bsize =
3274                             le32_to_cpu(response_data->BytesPerSector) *
3275                             le32_to_cpu(response_data->
3276                                         SectorsPerAllocationUnit);
3277                         FSData->f_blocks =
3278                             le64_to_cpu(response_data->TotalAllocationUnits);
3279                         FSData->f_bfree = FSData->f_bavail =
3280                             le64_to_cpu(response_data->FreeAllocationUnits);
3281                         cFYI(1,
3282                              ("Blocks: %lld  Free: %lld Block size %ld",
3283                               (unsigned long long)FSData->f_blocks,
3284                               (unsigned long long)FSData->f_bfree,
3285                               FSData->f_bsize));
3286                 }
3287         }
3288         cifs_buf_release(pSMB);
3289
3290         if (rc == -EAGAIN)
3291                 goto QFSInfoRetry;
3292
3293         return rc;
3294 }
3295
3296 int
3297 CIFSSMBQFSAttributeInfo(const int xid, struct cifsTconInfo *tcon)
3298 {
3299 /* level 0x105  SMB_QUERY_FILE_SYSTEM_INFO */
3300         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3301         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3302         FILE_SYSTEM_ATTRIBUTE_INFO *response_data;
3303         int rc = 0;
3304         int bytes_returned = 0;
3305         __u16 params, byte_count;
3306
3307         cFYI(1, ("In QFSAttributeInfo"));
3308 QFSAttributeRetry:
3309         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3310                       (void **) &pSMBr);
3311         if (rc)
3312                 return rc;
3313
3314         params = 2;     /* level */
3315         pSMB->TotalDataCount = 0;
3316         pSMB->MaxParameterCount = cpu_to_le16(2);
3317         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3318         pSMB->MaxSetupCount = 0;
3319         pSMB->Reserved = 0;
3320         pSMB->Flags = 0;
3321         pSMB->Timeout = 0;
3322         pSMB->Reserved2 = 0;
3323         byte_count = params + 1 /* pad */ ;
3324         pSMB->TotalParameterCount = cpu_to_le16(params);
3325         pSMB->ParameterCount = pSMB->TotalParameterCount;
3326         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3327         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3328         pSMB->DataCount = 0;
3329         pSMB->DataOffset = 0;
3330         pSMB->SetupCount = 1;
3331         pSMB->Reserved3 = 0;
3332         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3333         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_ATTRIBUTE_INFO);
3334         pSMB->hdr.smb_buf_length += byte_count;
3335         pSMB->ByteCount = cpu_to_le16(byte_count);
3336
3337         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3338                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3339         if (rc) {
3340                 cERROR(1, ("Send error in QFSAttributeInfo = %d", rc));
3341         } else {                /* decode response */
3342                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3343
3344                 if (rc || (pSMBr->ByteCount < 13)) {    /* BB also check enough bytes returned */
3345                         rc = -EIO;      /* bad smb */
3346                 } else {
3347                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3348                         response_data =
3349                             (FILE_SYSTEM_ATTRIBUTE_INFO
3350                              *) (((char *) &pSMBr->hdr.Protocol) +
3351                                  data_offset);
3352                         memcpy(&tcon->fsAttrInfo, response_data,
3353                                sizeof (FILE_SYSTEM_ATTRIBUTE_INFO));
3354                 }
3355         }
3356         cifs_buf_release(pSMB);
3357
3358         if (rc == -EAGAIN)
3359                 goto QFSAttributeRetry;
3360
3361         return rc;
3362 }
3363
3364 int
3365 CIFSSMBQFSDeviceInfo(const int xid, struct cifsTconInfo *tcon)
3366 {
3367 /* level 0x104 SMB_QUERY_FILE_SYSTEM_INFO */
3368         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3369         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3370         FILE_SYSTEM_DEVICE_INFO *response_data;
3371         int rc = 0;
3372         int bytes_returned = 0;
3373         __u16 params, byte_count;
3374
3375         cFYI(1, ("In QFSDeviceInfo"));
3376 QFSDeviceRetry:
3377         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3378                       (void **) &pSMBr);
3379         if (rc)
3380                 return rc;
3381
3382         params = 2;     /* level */
3383         pSMB->TotalDataCount = 0;
3384         pSMB->MaxParameterCount = cpu_to_le16(2);
3385         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3386         pSMB->MaxSetupCount = 0;
3387         pSMB->Reserved = 0;
3388         pSMB->Flags = 0;
3389         pSMB->Timeout = 0;
3390         pSMB->Reserved2 = 0;
3391         byte_count = params + 1 /* pad */ ;
3392         pSMB->TotalParameterCount = cpu_to_le16(params);
3393         pSMB->ParameterCount = pSMB->TotalParameterCount;
3394         pSMB->ParameterOffset = cpu_to_le16(offsetof(
3395         struct smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3396
3397         pSMB->DataCount = 0;
3398         pSMB->DataOffset = 0;
3399         pSMB->SetupCount = 1;
3400         pSMB->Reserved3 = 0;
3401         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3402         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FS_DEVICE_INFO);
3403         pSMB->hdr.smb_buf_length += byte_count;
3404         pSMB->ByteCount = cpu_to_le16(byte_count);
3405
3406         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3407                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3408         if (rc) {
3409                 cFYI(1, ("Send error in QFSDeviceInfo = %d", rc));
3410         } else {                /* decode response */
3411                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3412
3413                 if (rc || (pSMBr->ByteCount < sizeof (FILE_SYSTEM_DEVICE_INFO)))
3414                         rc = -EIO;      /* bad smb */
3415                 else {
3416                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3417                         response_data =
3418                             (FILE_SYSTEM_DEVICE_INFO *)
3419                                 (((char *) &pSMBr->hdr.Protocol) +
3420                                  data_offset);
3421                         memcpy(&tcon->fsDevInfo, response_data,
3422                                sizeof (FILE_SYSTEM_DEVICE_INFO));
3423                 }
3424         }
3425         cifs_buf_release(pSMB);
3426
3427         if (rc == -EAGAIN)
3428                 goto QFSDeviceRetry;
3429
3430         return rc;
3431 }
3432
3433 int
3434 CIFSSMBQFSUnixInfo(const int xid, struct cifsTconInfo *tcon)
3435 {
3436 /* level 0x200  SMB_QUERY_CIFS_UNIX_INFO */
3437         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3438         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3439         FILE_SYSTEM_UNIX_INFO *response_data;
3440         int rc = 0;
3441         int bytes_returned = 0;
3442         __u16 params, byte_count;
3443
3444         cFYI(1, ("In QFSUnixInfo"));
3445 QFSUnixRetry:
3446         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3447                       (void **) &pSMBr);
3448         if (rc)
3449                 return rc;
3450
3451         params = 2;     /* level */
3452         pSMB->TotalDataCount = 0;
3453         pSMB->DataCount = 0;
3454         pSMB->DataOffset = 0;
3455         pSMB->MaxParameterCount = cpu_to_le16(2);
3456         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3457         pSMB->MaxSetupCount = 0;
3458         pSMB->Reserved = 0;
3459         pSMB->Flags = 0;
3460         pSMB->Timeout = 0;
3461         pSMB->Reserved2 = 0;
3462         byte_count = params + 1 /* pad */ ;
3463         pSMB->ParameterCount = cpu_to_le16(params);
3464         pSMB->TotalParameterCount = pSMB->ParameterCount;
3465         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3466         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3467         pSMB->SetupCount = 1;
3468         pSMB->Reserved3 = 0;
3469         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3470         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_CIFS_UNIX_INFO);
3471         pSMB->hdr.smb_buf_length += byte_count;
3472         pSMB->ByteCount = cpu_to_le16(byte_count);
3473
3474         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3475                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3476         if (rc) {
3477                 cERROR(1, ("Send error in QFSUnixInfo = %d", rc));
3478         } else {                /* decode response */
3479                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3480
3481                 if (rc || (pSMBr->ByteCount < 13)) {
3482                         rc = -EIO;      /* bad smb */
3483                 } else {
3484                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3485                         response_data =
3486                             (FILE_SYSTEM_UNIX_INFO
3487                              *) (((char *) &pSMBr->hdr.Protocol) +
3488                                  data_offset);
3489                         memcpy(&tcon->fsUnixInfo, response_data,
3490                                sizeof (FILE_SYSTEM_UNIX_INFO));
3491                 }
3492         }
3493         cifs_buf_release(pSMB);
3494
3495         if (rc == -EAGAIN)
3496                 goto QFSUnixRetry;
3497
3498
3499         return rc;
3500 }
3501
3502 int
3503 CIFSSMBSetFSUnixInfo(const int xid, struct cifsTconInfo *tcon, __u64 cap)
3504 {
3505 /* level 0x200  SMB_SET_CIFS_UNIX_INFO */
3506         TRANSACTION2_SETFSI_REQ *pSMB = NULL;
3507         TRANSACTION2_SETFSI_RSP *pSMBr = NULL;
3508         int rc = 0;
3509         int bytes_returned = 0;
3510         __u16 params, param_offset, offset, byte_count;
3511
3512         cFYI(1, ("In SETFSUnixInfo"));
3513 SETFSUnixRetry:
3514         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3515                       (void **) &pSMBr);
3516         if (rc)
3517                 return rc;
3518
3519         params = 4;     /* 2 bytes zero followed by info level. */
3520         pSMB->MaxSetupCount = 0;
3521         pSMB->Reserved = 0;
3522         pSMB->Flags = 0;
3523         pSMB->Timeout = 0;
3524         pSMB->Reserved2 = 0;
3525         param_offset = offsetof(struct smb_com_transaction2_setfsi_req, FileNum) - 4;
3526         offset = param_offset + params;
3527
3528         pSMB->MaxParameterCount = cpu_to_le16(4);
3529         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3530         pSMB->SetupCount = 1;
3531         pSMB->Reserved3 = 0;
3532         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FS_INFORMATION);
3533         byte_count = 1 /* pad */ + params + 12;
3534
3535         pSMB->DataCount = cpu_to_le16(12);
3536         pSMB->ParameterCount = cpu_to_le16(params);
3537         pSMB->TotalDataCount = pSMB->DataCount;
3538         pSMB->TotalParameterCount = pSMB->ParameterCount;
3539         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3540         pSMB->DataOffset = cpu_to_le16(offset);
3541
3542         /* Params. */
3543         pSMB->FileNum = 0;
3544         pSMB->InformationLevel = cpu_to_le16(SMB_SET_CIFS_UNIX_INFO);
3545
3546         /* Data. */
3547         pSMB->ClientUnixMajor = cpu_to_le16(CIFS_UNIX_MAJOR_VERSION);
3548         pSMB->ClientUnixMinor = cpu_to_le16(CIFS_UNIX_MINOR_VERSION);
3549         pSMB->ClientUnixCap = cpu_to_le64(cap);
3550
3551         pSMB->hdr.smb_buf_length += byte_count;
3552         pSMB->ByteCount = cpu_to_le16(byte_count);
3553
3554         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3555                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3556         if (rc) {
3557                 cERROR(1, ("Send error in SETFSUnixInfo = %d", rc));
3558         } else {                /* decode response */
3559                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3560                 if (rc) {
3561                         rc = -EIO;      /* bad smb */
3562                 }
3563         }
3564         cifs_buf_release(pSMB);
3565
3566         if (rc == -EAGAIN)
3567                 goto SETFSUnixRetry;
3568
3569         return rc;
3570 }
3571
3572
3573
3574 int
3575 CIFSSMBQFSPosixInfo(const int xid, struct cifsTconInfo *tcon,
3576                    struct kstatfs *FSData)
3577 {
3578 /* level 0x201  SMB_QUERY_CIFS_POSIX_INFO */
3579         TRANSACTION2_QFSI_REQ *pSMB = NULL;
3580         TRANSACTION2_QFSI_RSP *pSMBr = NULL;
3581         FILE_SYSTEM_POSIX_INFO *response_data;
3582         int rc = 0;
3583         int bytes_returned = 0;
3584         __u16 params, byte_count;
3585
3586         cFYI(1, ("In QFSPosixInfo"));
3587 QFSPosixRetry:
3588         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3589                       (void **) &pSMBr);
3590         if (rc)
3591                 return rc;
3592
3593         params = 2;     /* level */
3594         pSMB->TotalDataCount = 0;
3595         pSMB->DataCount = 0;
3596         pSMB->DataOffset = 0;
3597         pSMB->MaxParameterCount = cpu_to_le16(2);
3598         pSMB->MaxDataCount = cpu_to_le16(100);  /* BB find exact max SMB PDU from sess structure BB */
3599         pSMB->MaxSetupCount = 0;
3600         pSMB->Reserved = 0;
3601         pSMB->Flags = 0;
3602         pSMB->Timeout = 0;
3603         pSMB->Reserved2 = 0;
3604         byte_count = params + 1 /* pad */ ;
3605         pSMB->ParameterCount = cpu_to_le16(params);
3606         pSMB->TotalParameterCount = pSMB->ParameterCount;
3607         pSMB->ParameterOffset = cpu_to_le16(offsetof(struct 
3608         smb_com_transaction2_qfsi_req, InformationLevel) - 4);
3609         pSMB->SetupCount = 1;
3610         pSMB->Reserved3 = 0;
3611         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_FS_INFORMATION);
3612         pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_POSIX_FS_INFO);
3613         pSMB->hdr.smb_buf_length += byte_count;
3614         pSMB->ByteCount = cpu_to_le16(byte_count);
3615
3616         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3617                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3618         if (rc) {
3619                 cFYI(1, ("Send error in QFSUnixInfo = %d", rc));
3620         } else {                /* decode response */
3621                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
3622
3623                 if (rc || (pSMBr->ByteCount < 13)) {
3624                         rc = -EIO;      /* bad smb */
3625                 } else {
3626                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
3627                         response_data =
3628                             (FILE_SYSTEM_POSIX_INFO
3629                              *) (((char *) &pSMBr->hdr.Protocol) +
3630                                  data_offset);
3631                         FSData->f_bsize =
3632                                         le32_to_cpu(response_data->BlockSize);
3633                         FSData->f_blocks =
3634                                         le64_to_cpu(response_data->TotalBlocks);
3635                         FSData->f_bfree =
3636                             le64_to_cpu(response_data->BlocksAvail);
3637                         if(response_data->UserBlocksAvail == -1) {
3638                                 FSData->f_bavail = FSData->f_bfree;
3639                         } else {
3640                                 FSData->f_bavail =
3641                                         le64_to_cpu(response_data->UserBlocksAvail);
3642                         }
3643                         if(response_data->TotalFileNodes != -1)
3644                                 FSData->f_files =
3645                                         le64_to_cpu(response_data->TotalFileNodes);
3646                         if(response_data->FreeFileNodes != -1)
3647                                 FSData->f_ffree =
3648                                         le64_to_cpu(response_data->FreeFileNodes);
3649                 }
3650         }
3651         cifs_buf_release(pSMB);
3652
3653         if (rc == -EAGAIN)
3654                 goto QFSPosixRetry;
3655
3656         return rc;
3657 }
3658
3659
3660 /* We can not use write of zero bytes trick to 
3661    set file size due to need for large file support.  Also note that 
3662    this SetPathInfo is preferred to SetFileInfo based method in next 
3663    routine which is only needed to work around a sharing violation bug
3664    in Samba which this routine can run into */
3665
3666 int
3667 CIFSSMBSetEOF(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3668               __u64 size, int SetAllocation, 
3669               const struct nls_table *nls_codepage, int remap)
3670 {
3671         struct smb_com_transaction2_spi_req *pSMB = NULL;
3672         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
3673         struct file_end_of_file_info *parm_data;
3674         int name_len;
3675         int rc = 0;
3676         int bytes_returned = 0;
3677         __u16 params, byte_count, data_count, param_offset, offset;
3678
3679         cFYI(1, ("In SetEOF"));
3680 SetEOFRetry:
3681         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3682                       (void **) &pSMBr);
3683         if (rc)
3684                 return rc;
3685
3686         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3687                 name_len =
3688                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3689                                      PATH_MAX, nls_codepage, remap);
3690                 name_len++;     /* trailing null */
3691                 name_len *= 2;
3692         } else {                /* BB improve the check for buffer overruns BB */
3693                 name_len = strnlen(fileName, PATH_MAX);
3694                 name_len++;     /* trailing null */
3695                 strncpy(pSMB->FileName, fileName, name_len);
3696         }
3697         params = 6 + name_len;
3698         data_count = sizeof (struct file_end_of_file_info);
3699         pSMB->MaxParameterCount = cpu_to_le16(2);
3700         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
3701         pSMB->MaxSetupCount = 0;
3702         pSMB->Reserved = 0;
3703         pSMB->Flags = 0;
3704         pSMB->Timeout = 0;
3705         pSMB->Reserved2 = 0;
3706         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3707                                      InformationLevel) - 4;
3708         offset = param_offset + params;
3709         if(SetAllocation) {
3710                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3711                     pSMB->InformationLevel =
3712                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3713                 else
3714                     pSMB->InformationLevel =
3715                         cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3716         } else /* Set File Size */  {    
3717             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3718                     pSMB->InformationLevel =
3719                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3720             else
3721                     pSMB->InformationLevel =
3722                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3723         }
3724
3725         parm_data =
3726             (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3727                                        offset);
3728         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3729         pSMB->DataOffset = cpu_to_le16(offset);
3730         pSMB->SetupCount = 1;
3731         pSMB->Reserved3 = 0;
3732         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3733         byte_count = 3 /* pad */  + params + data_count;
3734         pSMB->DataCount = cpu_to_le16(data_count);
3735         pSMB->TotalDataCount = pSMB->DataCount;
3736         pSMB->ParameterCount = cpu_to_le16(params);
3737         pSMB->TotalParameterCount = pSMB->ParameterCount;
3738         pSMB->Reserved4 = 0;
3739         pSMB->hdr.smb_buf_length += byte_count;
3740         parm_data->FileSize = cpu_to_le64(size);
3741         pSMB->ByteCount = cpu_to_le16(byte_count);
3742         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3743                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3744         if (rc) {
3745                 cFYI(1, ("SetPathInfo (file size) returned %d", rc));
3746         }
3747
3748         cifs_buf_release(pSMB);
3749
3750         if (rc == -EAGAIN)
3751                 goto SetEOFRetry;
3752
3753         return rc;
3754 }
3755
3756 int
3757 CIFSSMBSetFileSize(const int xid, struct cifsTconInfo *tcon, __u64 size, 
3758                    __u16 fid, __u32 pid_of_opener, int SetAllocation)
3759 {
3760         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3761         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3762         char *data_offset;
3763         struct file_end_of_file_info *parm_data;
3764         int rc = 0;
3765         int bytes_returned = 0;
3766         __u16 params, param_offset, offset, byte_count, count;
3767
3768         cFYI(1, ("SetFileSize (via SetFileInfo) %lld",
3769                         (long long)size));
3770         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3771
3772         if (rc)
3773                 return rc;
3774
3775         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3776
3777         pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3778         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));
3779     
3780         params = 6;
3781         pSMB->MaxSetupCount = 0;
3782         pSMB->Reserved = 0;
3783         pSMB->Flags = 0;
3784         pSMB->Timeout = 0;
3785         pSMB->Reserved2 = 0;
3786         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3787         offset = param_offset + params;
3788
3789         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;  
3790
3791         count = sizeof(struct file_end_of_file_info);
3792         pSMB->MaxParameterCount = cpu_to_le16(2);
3793         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3794         pSMB->SetupCount = 1;
3795         pSMB->Reserved3 = 0;
3796         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3797         byte_count = 3 /* pad */  + params + count;
3798         pSMB->DataCount = cpu_to_le16(count);
3799         pSMB->ParameterCount = cpu_to_le16(params);
3800         pSMB->TotalDataCount = pSMB->DataCount;
3801         pSMB->TotalParameterCount = pSMB->ParameterCount;
3802         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3803         parm_data =
3804                 (struct file_end_of_file_info *) (((char *) &pSMB->hdr.Protocol) +
3805                         offset);
3806         pSMB->DataOffset = cpu_to_le16(offset);
3807         parm_data->FileSize = cpu_to_le64(size);
3808         pSMB->Fid = fid;
3809         if(SetAllocation) {
3810                 if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3811                         pSMB->InformationLevel =
3812                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO2);
3813                 else
3814                         pSMB->InformationLevel =
3815                                 cpu_to_le16(SMB_SET_FILE_ALLOCATION_INFO);
3816         } else /* Set File Size */  {    
3817             if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3818                     pSMB->InformationLevel =
3819                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO2);
3820             else
3821                     pSMB->InformationLevel =
3822                         cpu_to_le16(SMB_SET_FILE_END_OF_FILE_INFO);
3823         }
3824         pSMB->Reserved4 = 0;
3825         pSMB->hdr.smb_buf_length += byte_count;
3826         pSMB->ByteCount = cpu_to_le16(byte_count);
3827         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3828                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3829         if (rc) {
3830                 cFYI(1,
3831                      ("Send error in SetFileInfo (SetFileSize) = %d",
3832                       rc));
3833         }
3834
3835         if (pSMB)
3836                 cifs_small_buf_release(pSMB);
3837
3838         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3839                 since file handle passed in no longer valid */
3840
3841         return rc;
3842 }
3843
3844 /* Some legacy servers such as NT4 require that the file times be set on 
3845    an open handle, rather than by pathname - this is awkward due to
3846    potential access conflicts on the open, but it is unavoidable for these
3847    old servers since the only other choice is to go from 100 nanosecond DCE
3848    time and resort to the original setpathinfo level which takes the ancient
3849    DOS time format with 2 second granularity */
3850 int
3851 CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, const FILE_BASIC_INFO * data, 
3852                    __u16 fid)
3853 {
3854         struct smb_com_transaction2_sfi_req *pSMB  = NULL;
3855         struct smb_com_transaction2_sfi_rsp *pSMBr = NULL;
3856         char *data_offset;
3857         int rc = 0;
3858         int bytes_returned = 0;
3859         __u16 params, param_offset, offset, byte_count, count;
3860
3861         cFYI(1, ("Set Times (via SetFileInfo)"));
3862         rc = small_smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB);
3863
3864         if (rc)
3865                 return rc;
3866
3867         pSMBr = (struct smb_com_transaction2_sfi_rsp *)pSMB;
3868
3869         /* At this point there is no need to override the current pid
3870         with the pid of the opener, but that could change if we someday
3871         use an existing handle (rather than opening one on the fly) */
3872         /* pSMB->hdr.Pid = cpu_to_le16((__u16)pid_of_opener);
3873         pSMB->hdr.PidHigh = cpu_to_le16((__u16)(pid_of_opener >> 16));*/
3874     
3875         params = 6;
3876         pSMB->MaxSetupCount = 0;
3877         pSMB->Reserved = 0;
3878         pSMB->Flags = 0;
3879         pSMB->Timeout = 0;
3880         pSMB->Reserved2 = 0;
3881         param_offset = offsetof(struct smb_com_transaction2_sfi_req, Fid) - 4;
3882         offset = param_offset + params;
3883
3884         data_offset = (char *) (&pSMB->hdr.Protocol) + offset; 
3885
3886         count = sizeof (FILE_BASIC_INFO);
3887         pSMB->MaxParameterCount = cpu_to_le16(2);
3888         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */
3889         pSMB->SetupCount = 1;
3890         pSMB->Reserved3 = 0;
3891         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_FILE_INFORMATION);
3892         byte_count = 3 /* pad */  + params + count;
3893         pSMB->DataCount = cpu_to_le16(count);
3894         pSMB->ParameterCount = cpu_to_le16(params);
3895         pSMB->TotalDataCount = pSMB->DataCount;
3896         pSMB->TotalParameterCount = pSMB->ParameterCount;
3897         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3898         pSMB->DataOffset = cpu_to_le16(offset);
3899         pSMB->Fid = fid;
3900         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3901                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3902         else
3903                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3904         pSMB->Reserved4 = 0;
3905         pSMB->hdr.smb_buf_length += byte_count;
3906         pSMB->ByteCount = cpu_to_le16(byte_count);
3907         memcpy(data_offset,data,sizeof(FILE_BASIC_INFO));
3908         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3909                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3910         if (rc) {
3911                 cFYI(1,("Send error in Set Time (SetFileInfo) = %d",rc));
3912         }
3913
3914         cifs_small_buf_release(pSMB);
3915
3916         /* Note: On -EAGAIN error only caller can retry on handle based calls 
3917                 since file handle passed in no longer valid */
3918
3919         return rc;
3920 }
3921
3922
3923 int
3924 CIFSSMBSetTimes(const int xid, struct cifsTconInfo *tcon, const char *fileName,
3925                 const FILE_BASIC_INFO * data, 
3926                 const struct nls_table *nls_codepage, int remap)
3927 {
3928         TRANSACTION2_SPI_REQ *pSMB = NULL;
3929         TRANSACTION2_SPI_RSP *pSMBr = NULL;
3930         int name_len;
3931         int rc = 0;
3932         int bytes_returned = 0;
3933         char *data_offset;
3934         __u16 params, param_offset, offset, byte_count, count;
3935
3936         cFYI(1, ("In SetTimes"));
3937
3938 SetTimesRetry:
3939         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
3940                       (void **) &pSMBr);
3941         if (rc)
3942                 return rc;
3943
3944         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
3945                 name_len =
3946                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName,
3947                                      PATH_MAX, nls_codepage, remap);
3948                 name_len++;     /* trailing null */
3949                 name_len *= 2;
3950         } else {                /* BB improve the check for buffer overruns BB */
3951                 name_len = strnlen(fileName, PATH_MAX);
3952                 name_len++;     /* trailing null */
3953                 strncpy(pSMB->FileName, fileName, name_len);
3954         }
3955
3956         params = 6 + name_len;
3957         count = sizeof (FILE_BASIC_INFO);
3958         pSMB->MaxParameterCount = cpu_to_le16(2);
3959         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
3960         pSMB->MaxSetupCount = 0;
3961         pSMB->Reserved = 0;
3962         pSMB->Flags = 0;
3963         pSMB->Timeout = 0;
3964         pSMB->Reserved2 = 0;
3965         param_offset = offsetof(struct smb_com_transaction2_spi_req,
3966                                      InformationLevel) - 4;
3967         offset = param_offset + params;
3968         data_offset = (char *) (&pSMB->hdr.Protocol) + offset;
3969         pSMB->ParameterOffset = cpu_to_le16(param_offset);
3970         pSMB->DataOffset = cpu_to_le16(offset);
3971         pSMB->SetupCount = 1;
3972         pSMB->Reserved3 = 0;
3973         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
3974         byte_count = 3 /* pad */  + params + count;
3975
3976         pSMB->DataCount = cpu_to_le16(count);
3977         pSMB->ParameterCount = cpu_to_le16(params);
3978         pSMB->TotalDataCount = pSMB->DataCount;
3979         pSMB->TotalParameterCount = pSMB->ParameterCount;
3980         if (tcon->ses->capabilities & CAP_INFOLEVEL_PASSTHRU)
3981                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO2);
3982         else
3983                 pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO);
3984         pSMB->Reserved4 = 0;
3985         pSMB->hdr.smb_buf_length += byte_count;
3986         memcpy(data_offset, data, sizeof (FILE_BASIC_INFO));
3987         pSMB->ByteCount = cpu_to_le16(byte_count);
3988         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
3989                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
3990         if (rc) {
3991                 cFYI(1, ("SetPathInfo (times) returned %d", rc));
3992         }
3993
3994         cifs_buf_release(pSMB);
3995
3996         if (rc == -EAGAIN)
3997                 goto SetTimesRetry;
3998
3999         return rc;
4000 }
4001
4002 /* Can not be used to set time stamps yet (due to old DOS time format) */
4003 /* Can be used to set attributes */
4004 #if 0  /* Possibly not needed - since it turns out that strangely NT4 has a bug
4005           handling it anyway and NT4 was what we thought it would be needed for
4006           Do not delete it until we prove whether needed for Win9x though */
4007 int
4008 CIFSSMBSetAttrLegacy(int xid, struct cifsTconInfo *tcon, char *fileName,
4009                 __u16 dos_attrs, const struct nls_table *nls_codepage)
4010 {
4011         SETATTR_REQ *pSMB = NULL;
4012         SETATTR_RSP *pSMBr = NULL;
4013         int rc = 0;
4014         int bytes_returned;
4015         int name_len;
4016
4017         cFYI(1, ("In SetAttrLegacy"));
4018
4019 SetAttrLgcyRetry:
4020         rc = smb_init(SMB_COM_SETATTR, 8, tcon, (void **) &pSMB,
4021                       (void **) &pSMBr);
4022         if (rc)
4023                 return rc;
4024
4025         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4026                 name_len =
4027                         ConvertToUCS((__le16 *) pSMB->fileName, fileName, 
4028                                 PATH_MAX, nls_codepage);
4029                 name_len++;     /* trailing null */
4030                 name_len *= 2;
4031         } else {                /* BB improve the check for buffer overruns BB */
4032                 name_len = strnlen(fileName, PATH_MAX);
4033                 name_len++;     /* trailing null */
4034                 strncpy(pSMB->fileName, fileName, name_len);
4035         }
4036         pSMB->attr = cpu_to_le16(dos_attrs);
4037         pSMB->BufferFormat = 0x04;
4038         pSMB->hdr.smb_buf_length += name_len + 1;
4039         pSMB->ByteCount = cpu_to_le16(name_len + 1);
4040         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4041                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4042         if (rc) {
4043                 cFYI(1, ("Error in LegacySetAttr = %d", rc));
4044         }
4045
4046         cifs_buf_release(pSMB);
4047
4048         if (rc == -EAGAIN)
4049                 goto SetAttrLgcyRetry;
4050
4051         return rc;
4052 }
4053 #endif /* temporarily unneeded SetAttr legacy function */
4054
4055 int
4056 CIFSSMBUnixSetPerms(const int xid, struct cifsTconInfo *tcon,
4057                     char *fileName, __u64 mode, __u64 uid, __u64 gid, 
4058                     dev_t device, const struct nls_table *nls_codepage, 
4059                     int remap)
4060 {
4061         TRANSACTION2_SPI_REQ *pSMB = NULL;
4062         TRANSACTION2_SPI_RSP *pSMBr = NULL;
4063         int name_len;
4064         int rc = 0;
4065         int bytes_returned = 0;
4066         FILE_UNIX_BASIC_INFO *data_offset;
4067         __u16 params, param_offset, offset, count, byte_count;
4068
4069         cFYI(1, ("In SetUID/GID/Mode"));
4070 setPermsRetry:
4071         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4072                       (void **) &pSMBr);
4073         if (rc)
4074                 return rc;
4075
4076         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4077                 name_len =
4078                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4079                                      PATH_MAX, nls_codepage, remap);
4080                 name_len++;     /* trailing null */
4081                 name_len *= 2;
4082         } else {                /* BB improve the check for buffer overruns BB */
4083                 name_len = strnlen(fileName, PATH_MAX);
4084                 name_len++;     /* trailing null */
4085                 strncpy(pSMB->FileName, fileName, name_len);
4086         }
4087
4088         params = 6 + name_len;
4089         count = sizeof (FILE_UNIX_BASIC_INFO);
4090         pSMB->MaxParameterCount = cpu_to_le16(2);
4091         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */
4092         pSMB->MaxSetupCount = 0;
4093         pSMB->Reserved = 0;
4094         pSMB->Flags = 0;
4095         pSMB->Timeout = 0;
4096         pSMB->Reserved2 = 0;
4097         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4098                                      InformationLevel) - 4;
4099         offset = param_offset + params;
4100         data_offset =
4101             (FILE_UNIX_BASIC_INFO *) ((char *) &pSMB->hdr.Protocol +
4102                                       offset);
4103         memset(data_offset, 0, count);
4104         pSMB->DataOffset = cpu_to_le16(offset);
4105         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4106         pSMB->SetupCount = 1;
4107         pSMB->Reserved3 = 0;
4108         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4109         byte_count = 3 /* pad */  + params + count;
4110         pSMB->ParameterCount = cpu_to_le16(params);
4111         pSMB->DataCount = cpu_to_le16(count);
4112         pSMB->TotalParameterCount = pSMB->ParameterCount;
4113         pSMB->TotalDataCount = pSMB->DataCount;
4114         pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_UNIX_BASIC);
4115         pSMB->Reserved4 = 0;
4116         pSMB->hdr.smb_buf_length += byte_count;
4117         data_offset->Uid = cpu_to_le64(uid);
4118         data_offset->Gid = cpu_to_le64(gid);
4119         /* better to leave device as zero when it is  */
4120         data_offset->DevMajor = cpu_to_le64(MAJOR(device));
4121         data_offset->DevMinor = cpu_to_le64(MINOR(device));
4122         data_offset->Permissions = cpu_to_le64(mode);
4123     
4124         if(S_ISREG(mode))
4125                 data_offset->Type = cpu_to_le32(UNIX_FILE);
4126         else if(S_ISDIR(mode))
4127                 data_offset->Type = cpu_to_le32(UNIX_DIR);
4128         else if(S_ISLNK(mode))
4129                 data_offset->Type = cpu_to_le32(UNIX_SYMLINK);
4130         else if(S_ISCHR(mode))
4131                 data_offset->Type = cpu_to_le32(UNIX_CHARDEV);
4132         else if(S_ISBLK(mode))
4133                 data_offset->Type = cpu_to_le32(UNIX_BLOCKDEV);
4134         else if(S_ISFIFO(mode))
4135                 data_offset->Type = cpu_to_le32(UNIX_FIFO);
4136         else if(S_ISSOCK(mode))
4137                 data_offset->Type = cpu_to_le32(UNIX_SOCKET);
4138
4139
4140         pSMB->ByteCount = cpu_to_le16(byte_count);
4141         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4142                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4143         if (rc) {
4144                 cFYI(1, ("SetPathInfo (perms) returned %d", rc));
4145         }
4146
4147         if (pSMB)
4148                 cifs_buf_release(pSMB);
4149         if (rc == -EAGAIN)
4150                 goto setPermsRetry;
4151         return rc;
4152 }
4153
4154 int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, 
4155                   const int notify_subdirs, const __u16 netfid,
4156                   __u32 filter, struct file * pfile, int multishot, 
4157                   const struct nls_table *nls_codepage)
4158 {
4159         int rc = 0;
4160         struct smb_com_transaction_change_notify_req * pSMB = NULL;
4161         struct smb_com_transaction_change_notify_rsp * pSMBr = NULL;
4162         struct dir_notify_req *dnotify_req;
4163         int bytes_returned;
4164
4165         cFYI(1, ("In CIFSSMBNotify for file handle %d",(int)netfid));
4166         rc = smb_init(SMB_COM_NT_TRANSACT, 23, tcon, (void **) &pSMB,
4167                       (void **) &pSMBr);
4168         if (rc)
4169                 return rc;
4170
4171         pSMB->TotalParameterCount = 0 ;
4172         pSMB->TotalDataCount = 0;
4173         pSMB->MaxParameterCount = cpu_to_le32(2);
4174         /* BB find exact data count max from sess structure BB */
4175         pSMB->MaxDataCount = 0; /* same in little endian or be */
4176         pSMB->MaxSetupCount = 4;
4177         pSMB->Reserved = 0;
4178         pSMB->ParameterOffset = 0;
4179         pSMB->DataCount = 0;
4180         pSMB->DataOffset = 0;
4181         pSMB->SetupCount = 4; /* single byte does not need le conversion */
4182         pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_NOTIFY_CHANGE);
4183         pSMB->ParameterCount = pSMB->TotalParameterCount;
4184         if(notify_subdirs)
4185                 pSMB->WatchTree = 1; /* one byte - no le conversion needed */
4186         pSMB->Reserved2 = 0;
4187         pSMB->CompletionFilter = cpu_to_le32(filter);
4188         pSMB->Fid = netfid; /* file handle always le */
4189         pSMB->ByteCount = 0;
4190
4191         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4192                         (struct smb_hdr *) pSMBr, &bytes_returned, -1);
4193         if (rc) {
4194                 cFYI(1, ("Error in Notify = %d", rc));
4195         } else {
4196                 /* Add file to outstanding requests */
4197                 dnotify_req = (struct dir_notify_req *) kmalloc(
4198                                                 sizeof(struct dir_notify_req), GFP_KERNEL);
4199                 dnotify_req->Pid = pSMB->hdr.Pid;
4200                 dnotify_req->PidHigh = pSMB->hdr.PidHigh;
4201                 dnotify_req->Mid = pSMB->hdr.Mid;
4202                 dnotify_req->Tid = pSMB->hdr.Tid;
4203                 dnotify_req->Uid = pSMB->hdr.Uid;
4204                 dnotify_req->netfid = netfid;
4205                 dnotify_req->pfile = pfile;
4206                 dnotify_req->filter = filter;
4207                 dnotify_req->multishot = multishot;
4208                 spin_lock(&GlobalMid_Lock);
4209                 list_add_tail(&dnotify_req->lhead, &GlobalDnotifyReqList);
4210                 spin_unlock(&GlobalMid_Lock);
4211         }
4212         cifs_buf_release(pSMB);
4213         return rc;      
4214 }
4215 #ifdef CONFIG_CIFS_XATTR
4216 ssize_t
4217 CIFSSMBQAllEAs(const int xid, struct cifsTconInfo *tcon,
4218                  const unsigned char *searchName,
4219                  char * EAData, size_t buf_size,
4220                  const struct nls_table *nls_codepage, int remap)
4221 {
4222                 /* BB assumes one setup word */
4223         TRANSACTION2_QPI_REQ *pSMB = NULL;
4224         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4225         int rc = 0;
4226         int bytes_returned;
4227         int name_len;
4228         struct fea * temp_fea;
4229         char * temp_ptr;
4230         __u16 params, byte_count;
4231
4232         cFYI(1, ("In Query All EAs path %s", searchName));
4233 QAllEAsRetry:
4234         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4235                       (void **) &pSMBr);
4236         if (rc)
4237                 return rc;
4238
4239         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4240                 name_len =
4241                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4242                                      PATH_MAX, nls_codepage, remap);
4243                 name_len++;     /* trailing null */
4244                 name_len *= 2;
4245         } else {        /* BB improve the check for buffer overruns BB */
4246                 name_len = strnlen(searchName, PATH_MAX);
4247                 name_len++;     /* trailing null */
4248                 strncpy(pSMB->FileName, searchName, name_len);
4249         }
4250
4251         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4252         pSMB->TotalDataCount = 0;
4253         pSMB->MaxParameterCount = cpu_to_le16(2);
4254         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4255         pSMB->MaxSetupCount = 0;
4256         pSMB->Reserved = 0;
4257         pSMB->Flags = 0;
4258         pSMB->Timeout = 0;
4259         pSMB->Reserved2 = 0;
4260         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4261         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4262         pSMB->DataCount = 0;
4263         pSMB->DataOffset = 0;
4264         pSMB->SetupCount = 1;
4265         pSMB->Reserved3 = 0;
4266         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4267         byte_count = params + 1 /* pad */ ;
4268         pSMB->TotalParameterCount = cpu_to_le16(params);
4269         pSMB->ParameterCount = pSMB->TotalParameterCount;
4270         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4271         pSMB->Reserved4 = 0;
4272         pSMB->hdr.smb_buf_length += byte_count;
4273         pSMB->ByteCount = cpu_to_le16(byte_count);
4274
4275         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4276                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4277         if (rc) {
4278                 cFYI(1, ("Send error in QueryAllEAs = %d", rc));
4279         } else {                /* decode response */
4280                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4281
4282                 /* BB also check enough total bytes returned */
4283                 /* BB we need to improve the validity checking
4284                 of these trans2 responses */
4285                 if (rc || (pSMBr->ByteCount < 4)) 
4286                         rc = -EIO;      /* bad smb */
4287            /* else if (pFindData){
4288                         memcpy((char *) pFindData,
4289                                (char *) &pSMBr->hdr.Protocol +
4290                                data_offset, kl);
4291                 }*/ else {
4292                         /* check that length of list is not more than bcc */
4293                         /* check that each entry does not go beyond length
4294                            of list */
4295                         /* check that each element of each entry does not
4296                            go beyond end of list */
4297                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4298                         struct fealist * ea_response_data;
4299                         rc = 0;
4300                         /* validate_trans2_offsets() */
4301                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4302                         ea_response_data = (struct fealist *)
4303                                 (((char *) &pSMBr->hdr.Protocol) +
4304                                 data_offset);
4305                         name_len = le32_to_cpu(ea_response_data->list_len);
4306                         cFYI(1,("ea length %d", name_len));
4307                         if(name_len <= 8) {
4308                         /* returned EA size zeroed at top of function */
4309                                 cFYI(1,("empty EA list returned from server"));
4310                         } else {
4311                                 /* account for ea list len */
4312                                 name_len -= 4;
4313                                 temp_fea = ea_response_data->list;
4314                                 temp_ptr = (char *)temp_fea;
4315                                 while(name_len > 0) {
4316                                         __u16 value_len;
4317                                         name_len -= 4;
4318                                         temp_ptr += 4;
4319                                         rc += temp_fea->name_len;
4320                                 /* account for prefix user. and trailing null */
4321                                         rc = rc + 5 + 1; 
4322                                         if(rc<(int)buf_size) {
4323                                                 memcpy(EAData,"user.",5);
4324                                                 EAData+=5;
4325                                                 memcpy(EAData,temp_ptr,temp_fea->name_len);
4326                                                 EAData+=temp_fea->name_len;
4327                                                 /* null terminate name */
4328                                                 *EAData = 0;
4329                                                 EAData = EAData + 1;
4330                                         } else if(buf_size == 0) {
4331                                                 /* skip copy - calc size only */
4332                                         } else {
4333                                                 /* stop before overrun buffer */
4334                                                 rc = -ERANGE;
4335                                                 break;
4336                                         }
4337                                         name_len -= temp_fea->name_len;
4338                                         temp_ptr += temp_fea->name_len;
4339                                         /* account for trailing null */
4340                                         name_len--;
4341                                         temp_ptr++;
4342                                         value_len = le16_to_cpu(temp_fea->value_len);
4343                                         name_len -= value_len;
4344                                         temp_ptr += value_len;
4345                                         /* BB check that temp_ptr is still within smb BB*/
4346                                 /* no trailing null to account for in value len */
4347                                         /* go on to next EA */
4348                                         temp_fea = (struct fea *)temp_ptr;
4349                                 }
4350                         }
4351                 }
4352         }
4353         if (pSMB)
4354                 cifs_buf_release(pSMB);
4355         if (rc == -EAGAIN)
4356                 goto QAllEAsRetry;
4357
4358         return (ssize_t)rc;
4359 }
4360
4361 ssize_t CIFSSMBQueryEA(const int xid,struct cifsTconInfo * tcon,
4362                 const unsigned char * searchName,const unsigned char * ea_name,
4363                 unsigned char * ea_value, size_t buf_size, 
4364                 const struct nls_table *nls_codepage, int remap)
4365 {
4366         TRANSACTION2_QPI_REQ *pSMB = NULL;
4367         TRANSACTION2_QPI_RSP *pSMBr = NULL;
4368         int rc = 0;
4369         int bytes_returned;
4370         int name_len;
4371         struct fea * temp_fea;
4372         char * temp_ptr;
4373         __u16 params, byte_count;
4374
4375         cFYI(1, ("In Query EA path %s", searchName));
4376 QEARetry:
4377         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4378                       (void **) &pSMBr);
4379         if (rc)
4380                 return rc;
4381
4382         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4383                 name_len =
4384                     cifsConvertToUCS((__le16 *) pSMB->FileName, searchName, 
4385                                      PATH_MAX, nls_codepage, remap);
4386                 name_len++;     /* trailing null */
4387                 name_len *= 2;
4388         } else {        /* BB improve the check for buffer overruns BB */
4389                 name_len = strnlen(searchName, PATH_MAX);
4390                 name_len++;     /* trailing null */
4391                 strncpy(pSMB->FileName, searchName, name_len);
4392         }
4393
4394         params = 2 /* level */ + 4 /* reserved */ + name_len /* includes NUL */ ;
4395         pSMB->TotalDataCount = 0;
4396         pSMB->MaxParameterCount = cpu_to_le16(2);
4397         pSMB->MaxDataCount = cpu_to_le16(4000); /* BB find exact max SMB PDU from sess structure BB */
4398         pSMB->MaxSetupCount = 0;
4399         pSMB->Reserved = 0;
4400         pSMB->Flags = 0;
4401         pSMB->Timeout = 0;
4402         pSMB->Reserved2 = 0;
4403         pSMB->ParameterOffset = cpu_to_le16(offsetof(
4404         struct smb_com_transaction2_qpi_req ,InformationLevel) - 4);
4405         pSMB->DataCount = 0;
4406         pSMB->DataOffset = 0;
4407         pSMB->SetupCount = 1;
4408         pSMB->Reserved3 = 0;
4409         pSMB->SubCommand = cpu_to_le16(TRANS2_QUERY_PATH_INFORMATION);
4410         byte_count = params + 1 /* pad */ ;
4411         pSMB->TotalParameterCount = cpu_to_le16(params);
4412         pSMB->ParameterCount = pSMB->TotalParameterCount;
4413         pSMB->InformationLevel = cpu_to_le16(SMB_INFO_QUERY_ALL_EAS);
4414         pSMB->Reserved4 = 0;
4415         pSMB->hdr.smb_buf_length += byte_count;
4416         pSMB->ByteCount = cpu_to_le16(byte_count);
4417
4418         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4419                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4420         if (rc) {
4421                 cFYI(1, ("Send error in Query EA = %d", rc));
4422         } else {                /* decode response */
4423                 rc = validate_t2((struct smb_t2_rsp *)pSMBr);
4424
4425                 /* BB also check enough total bytes returned */
4426                 /* BB we need to improve the validity checking
4427                 of these trans2 responses */
4428                 if (rc || (pSMBr->ByteCount < 4)) 
4429                         rc = -EIO;      /* bad smb */
4430            /* else if (pFindData){
4431                         memcpy((char *) pFindData,
4432                                (char *) &pSMBr->hdr.Protocol +
4433                                data_offset, kl);
4434                 }*/ else {
4435                         /* check that length of list is not more than bcc */
4436                         /* check that each entry does not go beyond length
4437                            of list */
4438                         /* check that each element of each entry does not
4439                            go beyond end of list */
4440                         __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
4441                         struct fealist * ea_response_data;
4442                         rc = -ENODATA;
4443                         /* validate_trans2_offsets() */
4444                         /* BB to check if(start of smb + data_offset > &bcc+ bcc)*/
4445                         ea_response_data = (struct fealist *)
4446                                 (((char *) &pSMBr->hdr.Protocol) +
4447                                 data_offset);
4448                         name_len = le32_to_cpu(ea_response_data->list_len);
4449                         cFYI(1,("ea length %d", name_len));
4450                         if(name_len <= 8) {
4451                         /* returned EA size zeroed at top of function */
4452                                 cFYI(1,("empty EA list returned from server"));
4453                         } else {
4454                                 /* account for ea list len */
4455                                 name_len -= 4;
4456                                 temp_fea = ea_response_data->list;
4457                                 temp_ptr = (char *)temp_fea;
4458                                 /* loop through checking if we have a matching
4459                                 name and then return the associated value */
4460                                 while(name_len > 0) {
4461                                         __u16 value_len;
4462                                         name_len -= 4;
4463                                         temp_ptr += 4;
4464                                         value_len = le16_to_cpu(temp_fea->value_len);
4465                                 /* BB validate that value_len falls within SMB, 
4466                                 even though maximum for name_len is 255 */ 
4467                                         if(memcmp(temp_fea->name,ea_name,
4468                                                   temp_fea->name_len) == 0) {
4469                                                 /* found a match */
4470                                                 rc = value_len;
4471                                 /* account for prefix user. and trailing null */
4472                                                 if(rc<=(int)buf_size) {
4473                                                         memcpy(ea_value,
4474                                                                 temp_fea->name+temp_fea->name_len+1,
4475                                                                 rc);
4476                                                         /* ea values, unlike ea names,
4477                                                         are not null terminated */
4478                                                 } else if(buf_size == 0) {
4479                                                 /* skip copy - calc size only */
4480                                                 } else {
4481                                                         /* stop before overrun buffer */
4482                                                         rc = -ERANGE;
4483                                                 }
4484                                                 break;
4485                                         }
4486                                         name_len -= temp_fea->name_len;
4487                                         temp_ptr += temp_fea->name_len;
4488                                         /* account for trailing null */
4489                                         name_len--;
4490                                         temp_ptr++;
4491                                         name_len -= value_len;
4492                                         temp_ptr += value_len;
4493                                 /* no trailing null to account for in value len */
4494                                         /* go on to next EA */
4495                                         temp_fea = (struct fea *)temp_ptr;
4496                                 }
4497                         } 
4498                 }
4499         }
4500         if (pSMB)
4501                 cifs_buf_release(pSMB);
4502         if (rc == -EAGAIN)
4503                 goto QEARetry;
4504
4505         return (ssize_t)rc;
4506 }
4507
4508 int
4509 CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName,
4510                 const char * ea_name, const void * ea_value, 
4511                 const __u16 ea_value_len, const struct nls_table *nls_codepage,
4512                 int remap)
4513 {
4514         struct smb_com_transaction2_spi_req *pSMB = NULL;
4515         struct smb_com_transaction2_spi_rsp *pSMBr = NULL;
4516         struct fealist *parm_data;
4517         int name_len;
4518         int rc = 0;
4519         int bytes_returned = 0;
4520         __u16 params, param_offset, byte_count, offset, count;
4521
4522         cFYI(1, ("In SetEA"));
4523 SetEARetry:
4524         rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB,
4525                       (void **) &pSMBr);
4526         if (rc)
4527                 return rc;
4528
4529         if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) {
4530                 name_len =
4531                     cifsConvertToUCS((__le16 *) pSMB->FileName, fileName, 
4532                                      PATH_MAX, nls_codepage, remap);
4533                 name_len++;     /* trailing null */
4534                 name_len *= 2;
4535         } else {                /* BB improve the check for buffer overruns BB */
4536                 name_len = strnlen(fileName, PATH_MAX);
4537                 name_len++;     /* trailing null */
4538                 strncpy(pSMB->FileName, fileName, name_len);
4539         }
4540
4541         params = 6 + name_len;
4542
4543         /* done calculating parms using name_len of file name,
4544         now use name_len to calculate length of ea name
4545         we are going to create in the inode xattrs */
4546         if(ea_name == NULL)
4547                 name_len = 0;
4548         else
4549                 name_len = strnlen(ea_name,255);
4550
4551         count = sizeof(*parm_data) + ea_value_len + name_len + 1;
4552         pSMB->MaxParameterCount = cpu_to_le16(2);
4553         pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB size from sess */
4554         pSMB->MaxSetupCount = 0;
4555         pSMB->Reserved = 0;
4556         pSMB->Flags = 0;
4557         pSMB->Timeout = 0;
4558         pSMB->Reserved2 = 0;
4559         param_offset = offsetof(struct smb_com_transaction2_spi_req,
4560                                      InformationLevel) - 4;
4561         offset = param_offset + params;
4562         pSMB->InformationLevel =
4563                 cpu_to_le16(SMB_SET_FILE_EA);
4564
4565         parm_data =
4566                 (struct fealist *) (((char *) &pSMB->hdr.Protocol) +
4567                                        offset);
4568         pSMB->ParameterOffset = cpu_to_le16(param_offset);
4569         pSMB->DataOffset = cpu_to_le16(offset);
4570         pSMB->SetupCount = 1;
4571         pSMB->Reserved3 = 0;
4572         pSMB->SubCommand = cpu_to_le16(TRANS2_SET_PATH_INFORMATION);
4573         byte_count = 3 /* pad */  + params + count;
4574         pSMB->DataCount = cpu_to_le16(count);
4575         parm_data->list_len = cpu_to_le32(count);
4576         parm_data->list[0].EA_flags = 0;
4577         /* we checked above that name len is less than 255 */
4578         parm_data->list[0].name_len = (__u8)name_len;;
4579         /* EA names are always ASCII */
4580         if(ea_name)
4581                 strncpy(parm_data->list[0].name,ea_name,name_len);
4582         parm_data->list[0].name[name_len] = 0;
4583         parm_data->list[0].value_len = cpu_to_le16(ea_value_len);
4584         /* caller ensures that ea_value_len is less than 64K but
4585         we need to ensure that it fits within the smb */
4586
4587         /*BB add length check that it would fit in negotiated SMB buffer size BB */
4588         /* if(ea_value_len > buffer_size - 512 (enough for header)) */
4589         if(ea_value_len)
4590                 memcpy(parm_data->list[0].name+name_len+1,ea_value,ea_value_len);
4591
4592         pSMB->TotalDataCount = pSMB->DataCount;
4593         pSMB->ParameterCount = cpu_to_le16(params);
4594         pSMB->TotalParameterCount = pSMB->ParameterCount;
4595         pSMB->Reserved4 = 0;
4596         pSMB->hdr.smb_buf_length += byte_count;
4597         pSMB->ByteCount = cpu_to_le16(byte_count);
4598         rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
4599                          (struct smb_hdr *) pSMBr, &bytes_returned, 0);
4600         if (rc) {
4601                 cFYI(1, ("SetPathInfo (EA) returned %d", rc));
4602         }
4603
4604         cifs_buf_release(pSMB);
4605
4606         if (rc == -EAGAIN)
4607                 goto SetEARetry;
4608
4609         return rc;
4610 }
4611
4612 #endif