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