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