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