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