More Japanese filename fixes wrt VFS code from
[kai/samba.git] / source / smbd / reply.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Main SMB reply routines
5    Copyright (C) Andrew Tridgell 1992-1998
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 /*
22    This file handles most of the reply_ calls that the server
23    makes to handle specific protocols
24 */
25
26
27 #include "includes.h"
28 #include "trans2.h"
29 #include "nterr.h"
30
31 /* look in server.c for some explanation of these variables */
32 extern int Protocol;
33 extern int DEBUGLEVEL;
34 extern int max_send;
35 extern int max_recv;
36 extern char magic_char;
37 extern BOOL case_sensitive;
38 extern BOOL case_preserve;
39 extern BOOL short_case_preserve;
40 extern pstring sesssetup_user;
41 extern pstring global_myname;
42 extern fstring global_myworkgroup;
43 extern int Client;
44 extern int global_oplock_break;
45 uint32 global_client_caps = 0;
46 unsigned int smb_echo_count = 0;
47
48 /****************************************************************************
49 report a possible attack via the password buffer overflow bug
50 ****************************************************************************/
51
52 static void overflow_attack(int len)
53 {
54         if( DEBUGLVL( 0 ) ) {
55                 dbgtext( "ERROR: Invalid password length %d.\n", len );
56                 dbgtext( "Your machine may be under attack by someone " );
57                 dbgtext( "attempting to exploit an old bug.\n" );
58                 dbgtext( "Attack was from IP = %s.\n", client_addr(Client) );
59         }
60         exit_server("possible attack");
61 }
62
63
64 /****************************************************************************
65   reply to an special message 
66 ****************************************************************************/
67
68 int reply_special(char *inbuf,char *outbuf)
69 {
70         int outsize = 4;
71         int msg_type = CVAL(inbuf,0);
72         int msg_flags = CVAL(inbuf,1);
73         pstring name1,name2;
74         extern fstring remote_machine;
75         extern fstring local_machine;
76         int len;
77         char name_type = 0;
78         
79         *name1 = *name2 = 0;
80         
81         memset(outbuf,'\0',smb_size);
82
83         smb_setlen(outbuf,0);
84         
85         switch (msg_type) {
86         case 0x81: /* session request */
87                 CVAL(outbuf,0) = 0x82;
88                 CVAL(outbuf,3) = 0;
89                 if (name_len(inbuf+4) > 50 || 
90                     name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
91                         DEBUG(0,("Invalid name length in session request\n"));
92                         return(0);
93                 }
94                 name_extract(inbuf,4,name1);
95                 name_extract(inbuf,4 + name_len(inbuf + 4),name2);
96                 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
97                          name1,name2));      
98
99                 fstrcpy(remote_machine,name2);
100                 remote_machine[15] = 0;
101                 trim_string(remote_machine," "," ");
102                 strlower(remote_machine);
103
104                 fstrcpy(local_machine,name1);
105                 len = strlen(local_machine);
106                 if (len == 16) {
107                         name_type = local_machine[15];
108                         local_machine[15] = 0;
109                 }
110                 trim_string(local_machine," "," ");
111                 strlower(local_machine);
112
113                 if (name_type == 'R') {
114                         /* We are being asked for a pathworks session --- 
115                            no thanks! */
116                         CVAL(outbuf, 0) = 0x83;
117                         break;
118                 }
119
120                 add_session_user(remote_machine);
121
122                 reload_services(True);
123                 reopen_logs();
124
125                 if (lp_status(-1)) {
126                         claim_connection(NULL,"",MAXSTATUS,True);
127                 }
128
129                 break;
130                 
131         case 0x89: /* session keepalive request 
132                       (some old clients produce this?) */
133                 CVAL(outbuf,0) = 0x85;
134                 CVAL(outbuf,3) = 0;
135                 break;
136                 
137         case 0x82: /* positive session response */
138         case 0x83: /* negative session response */
139         case 0x84: /* retarget session response */
140                 DEBUG(0,("Unexpected session response\n"));
141                 break;
142                 
143         case 0x85: /* session keepalive */
144         default:
145                 return(0);
146         }
147         
148         DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
149                     msg_type, msg_flags));
150         
151         return(outsize);
152 }
153
154
155 /*******************************************************************
156 work out what error to give to a failed connection
157 ********************************************************************/
158
159 static int connection_error(char *inbuf,char *outbuf,int ecode)
160 {
161         if (ecode == ERRnoipc)
162                 return(ERROR(ERRDOS,ERRnoipc));
163
164         return(ERROR(ERRSRV,ecode));
165 }
166
167
168
169 /****************************************************************************
170   parse a share descriptor string
171 ****************************************************************************/
172 static void parse_connect(char *p,char *service,char *user,
173                           char *password,int *pwlen,char *dev)
174 {
175   char *p2;
176
177   DEBUG(4,("parsing connect string %s\n",p));
178     
179   p2 = strrchr(p,'\\');
180   if (p2 == NULL)
181     fstrcpy(service,p);
182   else
183     fstrcpy(service,p2+1);
184   
185   p += strlen(p) + 2;
186   
187   fstrcpy(password,p);
188   *pwlen = strlen(password);
189
190   p += strlen(p) + 2;
191
192   fstrcpy(dev,p);
193   
194   *user = 0;
195   p = strchr(service,'%');
196   if (p != NULL)
197     {
198       *p = 0;
199       fstrcpy(user,p+1);
200     }
201 }
202
203 /****************************************************************************
204  Reply to a tcon.
205 ****************************************************************************/
206
207 int reply_tcon(connection_struct *conn,
208                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
209 {
210         BOOL doencrypt = SMBENCRYPT();
211         pstring service;
212         pstring user;
213         pstring password;
214         pstring dev;
215         int outsize = 0;
216         uint16 vuid = SVAL(inbuf,smb_uid);
217         int pwlen=0;
218         int ecode = -1;
219
220         *service = *user = *password = *dev = 0;
221
222         parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
223
224     /*
225      * Ensure the user and password names are in UNIX codepage format.
226      */
227
228     dos_to_unix(user,True);
229         if (!doencrypt)
230         dos_to_unix(password,True);
231
232         /*
233          * Pass the user through the NT -> unix user mapping
234          * function.
235          */
236    
237         (void)map_username(user);
238
239         /*
240          * Do any UNIX username case mangling.
241          */
242         (void)Get_Pwnam( user, True);
243
244         conn = make_connection(service,user,password,pwlen,dev,vuid,&ecode);
245   
246         if (!conn) {
247                 return(connection_error(inbuf,outbuf,ecode));
248         }
249   
250         outsize = set_message(outbuf,2,0,True);
251         SSVAL(outbuf,smb_vwv0,max_recv);
252         SSVAL(outbuf,smb_vwv1,conn->cnum);
253         SSVAL(outbuf,smb_tid,conn->cnum);
254   
255         DEBUG(3,("tcon service=%s user=%s cnum=%d\n", 
256                  service, user, conn->cnum));
257   
258         return(outsize);
259 }
260
261 /****************************************************************************
262  Reply to a tcon and X.
263 ****************************************************************************/
264
265 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
266 {
267         pstring service;
268         pstring user;
269         pstring password;
270         pstring devicename;
271         BOOL doencrypt = SMBENCRYPT();
272         int ecode = -1;
273         uint16 vuid = SVAL(inbuf,smb_uid);
274         int passlen = SVAL(inbuf,smb_vwv3);
275         char *path;
276         char *p;
277         
278         *service = *user = *password = *devicename = 0;
279
280         /* we might have to close an old one */
281         if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
282                 close_cnum(conn,vuid);
283         }
284
285         if (passlen > MAX_PASS_LEN) {
286                 overflow_attack(passlen);
287         }
288  
289         memcpy(password,smb_buf(inbuf),passlen);
290         password[passlen]=0;    
291         path = smb_buf(inbuf) + passlen;
292
293         if (passlen != 24) {
294                 if (strequal(password," "))
295                         *password = 0;
296                 passlen = strlen(password);
297         }
298         
299         fstrcpy(service,path+2);
300         p = strchr(service,'\\');
301         if (!p)
302                 return(ERROR(ERRSRV,ERRinvnetname));
303         *p = 0;
304         fstrcpy(service,p+1);
305         p = strchr(service,'%');
306         if (p) {
307                 *p++ = 0;
308                 fstrcpy(user,p);
309         }
310         StrnCpy(devicename,path + strlen(path) + 1,6);
311         DEBUG(4,("Got device type %s\n",devicename));
312
313     /*
314      * Ensure the user and password names are in UNIX codepage format.
315      */
316
317     dos_to_unix(user,True);
318         if (!doencrypt)
319                 dos_to_unix(password,True);
320
321         /*
322          * Pass the user through the NT -> unix user mapping
323          * function.
324          */
325         
326         (void)map_username(user);
327         
328         /*
329          * Do any UNIX username case mangling.
330          */
331         (void)Get_Pwnam(user, True);
332         
333         conn = make_connection(service,user,password,passlen,devicename,vuid,&ecode);
334         
335         if (!conn)
336                 return(connection_error(inbuf,outbuf,ecode));
337
338         if (Protocol < PROTOCOL_NT1) {
339                 set_message(outbuf,2,strlen(devicename)+1,True);
340                 pstrcpy(smb_buf(outbuf),devicename);
341         } else {
342                 char *fsname = lp_fstype(SNUM(conn));
343
344                 set_message(outbuf,3,3,True);
345
346                 p = smb_buf(outbuf);
347                 pstrcpy(p,devicename); p = skip_string(p,1); /* device name */
348                 pstrcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
349                 
350                 set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
351                 
352                 /* what does setting this bit do? It is set by NT4 and
353                    may affect the ability to autorun mounted cdroms */
354                 SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS); 
355                 
356                 init_dfsroot(conn, inbuf, outbuf);
357         }
358
359   
360         DEBUG(3,("tconX service=%s user=%s\n",
361                  service, user));
362   
363         /* set the incoming and outgoing tid to the just created one */
364         SSVAL(inbuf,smb_tid,conn->cnum);
365         SSVAL(outbuf,smb_tid,conn->cnum);
366
367         return chain_reply(inbuf,outbuf,length,bufsize);
368 }
369
370
371 /****************************************************************************
372   reply to an unknown type
373 ****************************************************************************/
374 int reply_unknown(char *inbuf,char *outbuf)
375 {
376         int type;
377         type = CVAL(inbuf,smb_com);
378   
379         DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
380                  smb_fn_name(type), type, type));
381   
382         return(ERROR(ERRSRV,ERRunknownsmb));
383 }
384
385
386 /****************************************************************************
387   reply to an ioctl
388 ****************************************************************************/
389 int reply_ioctl(connection_struct *conn,
390                 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
391 {
392         uint16 device     = SVAL(inbuf,smb_vwv1);
393         uint16 function   = SVAL(inbuf,smb_vwv2);
394         uint32 ioctl_code = (device << 16) + function;
395         int replysize, outsize;
396         char *p;
397
398         DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
399
400         switch (ioctl_code)
401         {
402             case IOCTL_QUERY_JOB_INFO:
403                 replysize = 32;
404                 break;
405             default:
406                 return(ERROR(ERRSRV,ERRnosupport));
407         }
408
409         outsize = set_message(outbuf,8,replysize+1,True);
410         SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
411         SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
412         SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
413         p = smb_buf(outbuf) + 1;          /* Allow for alignment */
414
415         switch (ioctl_code)
416         {
417             case IOCTL_QUERY_JOB_INFO:
418                 SSVAL(p,0,1);                            /* Job number */
419                 StrnCpy(p+2, global_myname, 15);         /* Our NetBIOS name */
420                 StrnCpy(p+18, lp_servicename(SNUM(conn)), 13); /* Service name */
421                 break;
422         }
423
424         return outsize;
425 }
426
427 /****************************************************************************
428  always return an error: it's just a matter of which one...
429  ****************************************************************************/
430 static int session_trust_account(connection_struct *conn, char *inbuf, char *outbuf, char *user,
431                                 char *smb_passwd, int smb_passlen,
432                                 char *smb_nt_passwd, int smb_nt_passlen)
433 {
434   struct smb_passwd *smb_trust_acct = NULL; /* check if trust account exists */
435   if (lp_security() == SEC_USER)
436   {
437     smb_trust_acct = getsmbpwnam(user);
438   }
439   else
440   {
441     DEBUG(0,("session_trust_account: Trust account %s only supported with security = user\n", user));
442     SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
443     return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
444   }
445
446   if (smb_trust_acct == NULL)
447   {
448     /* lkclXXXX: workstation entry doesn't exist */
449     DEBUG(0,("session_trust_account: Trust account %s user doesn't exist\n",user));
450     SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
451     return(ERROR(0, 0xc0000000|NT_STATUS_NO_SUCH_USER));
452   }
453   else
454   {
455     if ((smb_passlen != 24) || (smb_nt_passlen != 24))
456     {
457       DEBUG(0,("session_trust_account: Trust account %s - password length wrong.\n", user));
458       SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
459       return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
460     }
461
462     if (!smb_password_ok(smb_trust_acct, NULL, (unsigned char *)smb_passwd, (unsigned char *)smb_nt_passwd))
463     {
464       DEBUG(0,("session_trust_account: Trust Account %s - password failed\n", user));
465       SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
466       return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
467     }
468
469     if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_DOMTRUST))
470     {
471       DEBUG(0,("session_trust_account: Domain trust account %s denied by server\n",user));
472       SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
473       return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT));
474     }
475
476     if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_SVRTRUST))
477     {
478       DEBUG(0,("session_trust_account: Server trust account %s denied by server\n",user));
479       SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
480       return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT));
481     }
482
483     if (IS_BITS_SET_ALL(smb_trust_acct->acct_ctrl, ACB_WSTRUST))
484     {
485       DEBUG(4,("session_trust_account: Wksta trust account %s denied by server\n", user));
486       SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
487       return(ERROR(0, 0xc0000000|NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT));
488     }
489   }
490
491   /* don't know what to do: indicate logon failure */
492   SSVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
493   return(ERROR(0, 0xc0000000|NT_STATUS_LOGON_FAILURE));
494 }
495
496 /****************************************************************************
497  Create a UNIX user on demand.
498 ****************************************************************************/
499
500 static int smb_create_user(char *unix_user)
501 {
502   pstring add_script;
503   int ret;
504
505   pstrcpy(add_script, lp_adduser_script());
506   pstring_sub(add_script, "%u", unix_user);
507   ret = smbrun(add_script,NULL,False);
508   DEBUG(3,("smb_create_user: Running the command `%s' gave %d\n",add_script,ret));
509   return ret;
510 }
511
512 /****************************************************************************
513  Delete a UNIX user on demand.
514 ****************************************************************************/
515
516 static int smb_delete_user(char *unix_user)
517 {
518   pstring del_script;
519   int ret;
520
521   pstrcpy(del_script, lp_deluser_script());
522   pstring_sub(del_script, "%u", unix_user);
523   ret = smbrun(del_script,NULL,False);
524   DEBUG(3,("smb_delete_user: Running the command `%s' gave %d\n",del_script,ret));
525   return ret;
526 }
527
528 /****************************************************************************
529  Check user is in correct domain if required
530 ****************************************************************************/
531
532 static BOOL check_domain_match(char *user, char *domain) 
533 {
534   /*
535    * If we aren't serving to trusted domains, we must make sure that
536    * the validation request comes from an account in the same domain
537    * as the Samba server
538    */
539
540   if (!lp_allow_trusted_domains() &&
541       !strequal(lp_workgroup(), domain) ) {
542       DEBUG(1, ("check_domain_match: Attempt to connect as user %s from domain %s denied.\n", user, domain));
543       return False;
544   } else {
545       return True;
546   }
547 }
548
549 /****************************************************************************
550  Check for a valid username and password in security=server mode.
551 ****************************************************************************/
552
553 static BOOL check_server_security(char *orig_user, char *domain, char *unix_user,
554                                   char *smb_apasswd, int smb_apasslen,
555                                   char *smb_ntpasswd, int smb_ntpasslen)
556 {
557   BOOL ret = False;
558
559   if(lp_security() != SEC_SERVER)
560     return False;
561
562   if (!check_domain_match(orig_user, domain))
563      return False;
564
565   ret = server_validate(orig_user, domain, 
566                             smb_apasswd, smb_apasslen, 
567                             smb_ntpasswd, smb_ntpasslen);
568   if(ret) {
569     /*
570      * User validated ok against Domain controller.
571      * If the admin wants us to try and create a UNIX
572      * user on the fly, do so.
573      * Note that we can never delete users when in server
574      * level security as we never know if it was a failure
575      * due to a bad password, or the user really doesn't exist.
576      */
577     if(lp_adduser_script() && !Get_Pwnam(unix_user,True)) {
578       smb_create_user(unix_user);
579     }
580   }
581
582   return ret;
583 }
584
585 /****************************************************************************
586  Check for a valid username and password in security=domain mode.
587 ****************************************************************************/
588
589 static BOOL check_domain_security(char *orig_user, char *domain, char *unix_user, 
590                                   char *smb_apasswd, int smb_apasslen,
591                                   char *smb_ntpasswd, int smb_ntpasslen)
592 {
593   BOOL ret = False;
594   BOOL user_exists = True;
595
596   if(lp_security() != SEC_DOMAIN)
597     return False;
598
599   if (!check_domain_match(orig_user, domain))
600      return False;
601
602   ret = domain_client_validate(orig_user, domain,
603                                 smb_apasswd, smb_apasslen,
604                                 smb_ntpasswd, smb_ntpasslen,
605                                 &user_exists);
606
607   if(ret) {
608     /*
609      * User validated ok against Domain controller.
610      * If the admin wants us to try and create a UNIX
611      * user on the fly, do so.
612      */
613     if(user_exists && lp_adduser_script() && !Get_Pwnam(unix_user,True)) {
614       smb_create_user(unix_user);
615     }
616   } else {
617     /*
618      * User failed to validate ok against Domain controller.
619      * If the failure was "user doesn't exist" and admin 
620      * wants us to try and delete that UNIX user on the fly,
621      * do so.
622      */
623     if(!user_exists && lp_deluser_script() && Get_Pwnam(unix_user,True)) {
624       smb_delete_user(unix_user);
625     }
626   }
627
628   return ret;
629 }
630
631 /****************************************************************************
632  Return a bad password error configured for the correct client type.
633 ****************************************************************************/       
634
635 static int bad_password_error(char *inbuf,char *outbuf)
636 {
637   enum remote_arch_types ra_type = get_remote_arch();
638
639   if(((ra_type == RA_WINNT) || (ra_type == RA_WIN2K)) &&
640       (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32 ))) {
641     SSVAL(outbuf,smb_flg2,FLAGS2_32_BIT_ERROR_CODES);
642     return(ERROR(0,0xc0000000|NT_STATUS_LOGON_FAILURE));
643   }
644
645   return(ERROR(ERRSRV,ERRbadpw));
646 }
647
648 /****************************************************************************
649 reply to a session setup command
650 ****************************************************************************/
651
652 int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
653 {
654   uint16 sess_vuid;
655   gid_t gid;
656   uid_t uid;
657   int   smb_bufsize;    
658   int   smb_apasslen = 0;   
659   pstring smb_apasswd;
660   int   smb_ntpasslen = 0;   
661   pstring smb_ntpasswd;
662   BOOL valid_nt_password = False;
663   pstring user;
664   pstring orig_user;
665   BOOL guest=False;
666   static BOOL done_sesssetup = False;
667   BOOL doencrypt = SMBENCRYPT();
668   char *domain = "";
669
670   *smb_apasswd = 0;
671   *smb_ntpasswd = 0;
672   
673   smb_bufsize = SVAL(inbuf,smb_vwv2);
674
675   if (Protocol < PROTOCOL_NT1) {
676     smb_apasslen = SVAL(inbuf,smb_vwv7);
677     if (smb_apasslen > MAX_PASS_LEN)
678       overflow_attack(smb_apasslen);
679
680     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
681     smb_apasswd[smb_apasslen] = 0;
682     pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
683     /*
684      * Incoming user is in DOS codepage format. Convert
685      * to UNIX.
686      */
687     dos_to_unix(user,True);
688   
689     if (!doencrypt && (lp_security() != SEC_SERVER)) {
690       smb_apasslen = strlen(smb_apasswd);
691     }
692   } else {
693     uint16 passlen1 = SVAL(inbuf,smb_vwv7);
694     uint16 passlen2 = SVAL(inbuf,smb_vwv8);
695     enum remote_arch_types ra_type = get_remote_arch();
696     char *p = smb_buf(inbuf);    
697
698     if(global_client_caps == 0)
699       global_client_caps = IVAL(inbuf,smb_vwv11);
700
701     /* client_caps is used as final determination if client is NT or Win95. 
702        This is needed to return the correct error codes in some
703        circumstances.
704      */
705     
706     if(ra_type == RA_WINNT || ra_type == RA_WIN2K || ra_type == RA_WIN95) {
707       if(!(global_client_caps & (CAP_NT_SMBS | CAP_STATUS32))) {
708         set_remote_arch( RA_WIN95);
709       }
710     }
711
712     if (passlen1 != 24 && passlen2 != 24)
713       doencrypt = False;
714
715     if (passlen1 > MAX_PASS_LEN) {
716       overflow_attack(passlen1);
717     }
718
719     passlen1 = MIN(passlen1, MAX_PASS_LEN);
720     passlen2 = MIN(passlen2, MAX_PASS_LEN);
721
722     if(!doencrypt) {
723        /* both Win95 and WinNT stuff up the password lengths for
724           non-encrypting systems. Uggh. 
725       
726           if passlen1==24 its a win95 system, and its setting the
727           password length incorrectly. Luckily it still works with the
728           default code because Win95 will null terminate the password
729           anyway 
730
731           if passlen1>0 and passlen2>0 then maybe its a NT box and its
732           setting passlen2 to some random value which really stuffs
733           things up. we need to fix that one.  */
734
735       if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 && passlen2 != 1)
736         passlen2 = 0;
737     }
738
739     if (lp_restrict_anonymous()) {
740       /* there seems to be no reason behind the differences in MS clients formatting
741        * various info like the domain, NativeOS, and NativeLanMan fields. Win95
742        * in particular seems to have an extra null byte between the username and the
743        * domain, or the password length calculation is wrong, which throws off the
744        * string extraction routines below.  This makes the value of domain be the
745        * empty string, which fails the restrict anonymous check further down.
746        * This compensates for that, and allows browsing to work in mixed NT and
747        * win95 environments even when restrict anonymous is true. AAB
748        */
749       dump_data(100, p, 0x70);
750       DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
751       if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
752         DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
753         DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
754         DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
755         passlen1 = 1;
756       }
757     }
758
759     if(doencrypt || ((lp_security() == SEC_SERVER) || (lp_security() == SEC_DOMAIN))) {
760       /* Save the lanman2 password and the NT md4 password. */
761       smb_apasslen = passlen1;
762       memcpy(smb_apasswd,p,smb_apasslen);
763       smb_apasswd[smb_apasslen] = 0;
764       smb_ntpasslen = passlen2;
765       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
766       smb_ntpasswd[smb_ntpasslen] = 0;
767
768       /*
769        * Ensure the plaintext passwords are in UNIX format.
770        */
771       if(!doencrypt) {
772         dos_to_unix(smb_apasswd,True);
773         dos_to_unix(smb_ntpasswd,True);
774       }
775
776     } else {
777       /* we use the first password that they gave */
778       smb_apasslen = passlen1;
779       StrnCpy(smb_apasswd,p,smb_apasslen);      
780       /*
781        * Ensure the plaintext password is in UNIX format.
782        */
783       dos_to_unix(smb_apasswd,True);
784       
785       /* trim the password */
786       smb_apasslen = strlen(smb_apasswd);
787
788       /* wfwg sometimes uses a space instead of a null */
789       if (strequal(smb_apasswd," ")) {
790         smb_apasslen = 0;
791         *smb_apasswd = 0;
792       }
793     }
794     
795     p += passlen1 + passlen2;
796     fstrcpy(user,p);
797     p = skip_string(p,1);
798     /*
799      * Incoming user is in DOS codepage format. Convert
800      * to UNIX.
801      */
802     dos_to_unix(user,True);
803     domain = p;
804
805     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
806              domain,skip_string(p,1),skip_string(p,2)));
807   }
808
809
810   DEBUG(3,("sesssetupX:name=[%s]\n",user));
811
812   /* If name ends in $ then I think it's asking about whether a */
813   /* computer with that name (minus the $) has access. For now */
814   /* say yes to everything ending in $. */
815
816   if (*user && (user[strlen(user) - 1] == '$') && (smb_apasslen == 24) && (smb_ntpasslen == 24)) {
817     return session_trust_account(conn, inbuf, outbuf, user, 
818                                  smb_apasswd, smb_apasslen,
819                                  smb_ntpasswd, smb_ntpasslen);
820   }
821
822   if (done_sesssetup && lp_restrict_anonymous()) {
823     /* tests show that even if browsing is done over already validated connections
824      * without a username and password the domain is still provided, which it
825      * wouldn't be if it was a purely anonymous connection.  So, in order to
826      * restrict anonymous, we only deny connections that have no session
827      * information.  If a domain has been provided, then it's not a purely
828      * anonymous connection. AAB
829      */
830     if (!*user && !*smb_apasswd && !*domain) {
831       DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
832       return(ERROR(ERRDOS,ERRnoaccess));
833     }
834   }
835
836   /* If no username is sent use the guest account */
837   if (!*user) {
838     pstrcpy(user,lp_guestaccount(-1));
839     /* If no user and no password then set guest flag. */
840     if( *smb_apasswd == 0)
841       guest = True;
842   }
843
844   strlower(user);
845
846   /*
847    * In share level security, only overwrite sesssetup_use if
848    * it's a non null-session share. Helps keep %U and %G
849    * working.
850    */
851
852   if((lp_security() != SEC_SHARE) || (*user && !guest))
853     pstrcpy(sesssetup_user,user);
854
855   reload_services(True);
856
857   /*
858    * Save the username before mapping. We will use
859    * the original username sent to us for security=server
860    * and security=domain checking.
861    */
862
863   pstrcpy( orig_user, user);
864
865   /*
866    * Pass the user through the NT -> unix user mapping
867    * function.
868    */
869    
870   (void)map_username(user);
871
872   /*
873    * Do any UNIX username case mangling.
874    */
875   (void)Get_Pwnam( user, True);
876
877   add_session_user(user);
878
879   /*
880    * Check if the given username was the guest user with no password.
881    */
882
883   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
884     guest = True;
885
886   /* 
887    * Check with orig_user for security=server and
888    * security=domain.
889    */
890
891   if (!guest && 
892                           !check_server_security(orig_user, domain, user,
893                                                                          smb_apasswd, smb_apasslen,
894                                                                          smb_ntpasswd, smb_ntpasslen) &&
895                           !check_domain_security(orig_user, domain, user,
896                              smb_apasswd, smb_apasslen,
897                              smb_ntpasswd, smb_ntpasslen) &&
898       !check_hosts_equiv(user)
899      )
900   {
901
902     /* 
903      * If we get here then the user wasn't guest and the remote
904      * authentication methods failed. Check the authentication
905      * methods on this local server.
906      *
907      * If an NT password was supplied try and validate with that
908      * first. This is superior as the passwords are mixed case 
909      * 128 length unicode.
910       */
911
912     if(smb_ntpasslen)
913     {
914       if(!password_ok(user, smb_ntpasswd,smb_ntpasslen,NULL))
915         DEBUG(2,("NT Password did not match for user '%s' ! Defaulting to Lanman\n", user));
916       else
917         valid_nt_password = True;
918     } 
919
920     if (!valid_nt_password && !password_ok(user, smb_apasswd,smb_apasslen,NULL))
921     {
922       if (lp_security() >= SEC_USER) 
923       {
924         if (lp_map_to_guest() == NEVER_MAP_TO_GUEST)
925         {
926           DEBUG(1,("Rejecting user '%s': authentication failed\n", user));
927           return bad_password_error(inbuf,outbuf);
928         }
929
930         if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER)
931         {
932           if (Get_Pwnam(user,True))
933           {
934             DEBUG(1,("Rejecting user '%s': bad password\n", user));
935             return bad_password_error(inbuf,outbuf);
936           }
937         }
938
939         /*
940          * ..else if lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD
941          * Then always map to guest account - as done below.
942          */
943       }
944
945       if (*smb_apasswd || !Get_Pwnam(user,True))
946          pstrcpy(user,lp_guestaccount(-1));
947       DEBUG(3,("Registered username %s for guest access\n",user));
948       guest = True;
949     }
950   }
951
952   if (!Get_Pwnam(user,True)) {
953     DEBUG(3,("No such user %s - using guest account\n",user));
954     pstrcpy(user,lp_guestaccount(-1));
955     guest = True;
956   }
957
958   if (!strequal(user,lp_guestaccount(-1)) &&
959       lp_servicenumber(user) < 0)      
960   {
961     int homes = lp_servicenumber(HOMES_NAME);
962     char *home = get_user_home_dir(user);
963     if (homes >= 0 && home)
964       lp_add_home(user,homes,home);
965   }
966
967
968   /* it's ok - setup a reply */
969   if (Protocol < PROTOCOL_NT1) {
970     set_message(outbuf,3,0,True);
971   } else {
972     char *p;
973     set_message(outbuf,3,3,True);
974     p = smb_buf(outbuf);
975     pstrcpy(p,"Unix"); p = skip_string(p,1);
976     pstrcpy(p,"Samba "); pstrcat(p,VERSION); p = skip_string(p,1);
977     pstrcpy(p,global_myworkgroup); p = skip_string(p,1);
978     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
979     /* perhaps grab OS version here?? */
980   }
981
982   /* Set the correct uid in the outgoing and incoming packets
983      We will use this on future requests to determine which
984      user we should become.
985      */
986   {
987     const struct passwd *pw = Get_Pwnam(user,False);
988     if (!pw) {
989       DEBUG(1,("Username %s is invalid on this system\n",user));
990       return bad_password_error(inbuf,outbuf);
991     }
992     gid = pw->pw_gid;
993     uid = pw->pw_uid;
994   }
995
996   if (guest)
997     SSVAL(outbuf,smb_vwv2,1);
998
999   /* register the name and uid as being validated, so further connections
1000      to a uid can get through without a password, on the same VC */
1001   sess_vuid = register_vuid(uid,gid,user,sesssetup_user,guest);
1002  
1003   SSVAL(outbuf,smb_uid,sess_vuid);
1004   SSVAL(inbuf,smb_uid,sess_vuid);
1005
1006   if (!done_sesssetup)
1007     max_send = MIN(max_send,smb_bufsize);
1008
1009   DEBUG(6,("Client requested max send size of %d\n", max_send));
1010
1011   done_sesssetup = True;
1012
1013   return chain_reply(inbuf,outbuf,length,bufsize);
1014 }
1015
1016
1017 /****************************************************************************
1018   reply to a chkpth
1019 ****************************************************************************/
1020 int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1021 {
1022   int outsize = 0;
1023   int mode;
1024   pstring name;
1025   BOOL ok = False;
1026   BOOL bad_path = False;
1027   SMB_STRUCT_STAT st;
1028  
1029   pstrcpy(name,smb_buf(inbuf) + 1);
1030
1031   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1032
1033   unix_convert(name,conn,0,&bad_path,&st);
1034
1035   mode = SVAL(inbuf,smb_vwv0);
1036
1037   if (check_name(name,conn)) {
1038     if(VALID_STAT(st))
1039       ok = S_ISDIR(st.st_mode);
1040     else
1041       ok = vfs_directory_exist(conn,name,NULL);
1042   }
1043
1044   if (!ok)
1045   {
1046     /* We special case this - as when a Windows machine
1047        is parsing a path is steps through the components
1048        one at a time - if a component fails it expects
1049        ERRbadpath, not ERRbadfile.
1050      */
1051     if(errno == ENOENT)
1052     {
1053       unix_ERR_class = ERRDOS;
1054       unix_ERR_code = ERRbadpath;
1055     }
1056
1057 #if 0
1058     /* Ugly - NT specific hack - maybe not needed ? (JRA) */
1059     if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
1060        (get_remote_arch() == RA_WINNT))
1061     {
1062       unix_ERR_class = ERRDOS;
1063       unix_ERR_code = ERRbaddirectory;
1064     }
1065 #endif
1066
1067     return(UNIXERROR(ERRDOS,ERRbadpath));
1068   }
1069
1070   outsize = set_message(outbuf,0,0,True);
1071
1072   DEBUG(3,("chkpth %s mode=%d\n", name, mode));
1073
1074   return(outsize);
1075 }
1076
1077
1078 /****************************************************************************
1079   reply to a getatr
1080 ****************************************************************************/
1081 int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1082 {
1083   pstring fname;
1084   int outsize = 0;
1085   SMB_STRUCT_STAT sbuf;
1086   BOOL ok = False;
1087   int mode=0;
1088   SMB_OFF_T size=0;
1089   time_t mtime=0;
1090   BOOL bad_path = False;
1091  
1092   pstrcpy(fname,smb_buf(inbuf) + 1);
1093
1094   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1095   
1096   /* if((SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) && dfs_redirect(fname,conn)) return(dfs_path_error(inbuf,outbuf)); 
1097    */
1098   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
1099      under WfWg - weird! */
1100   if (! (*fname))
1101   {
1102     mode = aHIDDEN | aDIR;
1103     if (!CAN_WRITE(conn)) mode |= aRONLY;
1104     size = 0;
1105     mtime = 0;
1106     ok = True;
1107   }
1108   else
1109   {
1110     unix_convert(fname,conn,0,&bad_path,&sbuf);
1111     if (check_name(fname,conn))
1112     {
1113       if (VALID_STAT(sbuf) || dos_stat(fname,&sbuf) == 0)
1114       {
1115         mode = dos_mode(conn,fname,&sbuf);
1116         size = sbuf.st_size;
1117         mtime = sbuf.st_mtime;
1118         if (mode & aDIR)
1119           size = 0;
1120         ok = True;
1121       }
1122       else
1123         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
1124     }
1125   }
1126   
1127   if (!ok)
1128   {
1129     if((errno == ENOENT) && bad_path)
1130     {
1131       unix_ERR_class = ERRDOS;
1132       unix_ERR_code = ERRbadpath;
1133     }
1134
1135     return(UNIXERROR(ERRDOS,ERRbadfile));
1136   }
1137  
1138   outsize = set_message(outbuf,10,0,True);
1139
1140   SSVAL(outbuf,smb_vwv0,mode);
1141   if(lp_dos_filetime_resolution(SNUM(conn)) )
1142     put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
1143   else
1144     put_dos_date3(outbuf,smb_vwv1,mtime);
1145   SIVAL(outbuf,smb_vwv3,(uint32)size);
1146
1147   if (Protocol >= PROTOCOL_NT1) {
1148     char *p = strrchr(fname,'/');
1149     uint16 flg2 = SVAL(outbuf,smb_flg2);
1150     if (!p) p = fname;
1151     if (!is_8_3(fname, True))
1152       SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1153   }
1154   
1155   DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
1156   
1157   return(outsize);
1158 }
1159
1160
1161 /****************************************************************************
1162   reply to a setatr
1163 ****************************************************************************/
1164 int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1165 {
1166   pstring fname;
1167   int outsize = 0;
1168   BOOL ok=False;
1169   int mode;
1170   time_t mtime;
1171   SMB_STRUCT_STAT st;
1172   BOOL bad_path = False;
1173  
1174   pstrcpy(fname,smb_buf(inbuf) + 1);
1175   unix_convert(fname,conn,0,&bad_path,&st);
1176
1177   mode = SVAL(inbuf,smb_vwv0);
1178   mtime = make_unix_date3(inbuf+smb_vwv1);
1179   
1180   if (VALID_STAT_OF_DIR(st) || vfs_directory_exist(conn, fname, NULL))
1181     mode |= aDIR;
1182   if (check_name(fname,conn))
1183     ok =  (file_chmod(conn,fname,mode,NULL) == 0);
1184   if (ok)
1185     ok = set_filetime(conn,fname,mtime);
1186   
1187   if (!ok)
1188   {
1189     if((errno == ENOENT) && bad_path)
1190     {
1191       unix_ERR_class = ERRDOS;
1192       unix_ERR_code = ERRbadpath;
1193     }
1194
1195     return(UNIXERROR(ERRDOS,ERRnoaccess));
1196   }
1197  
1198   outsize = set_message(outbuf,0,0,True);
1199   
1200   DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
1201   
1202   return(outsize);
1203 }
1204
1205
1206 /****************************************************************************
1207   reply to a dskattr
1208 ****************************************************************************/
1209 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1210 {
1211   int outsize = 0;
1212   SMB_BIG_UINT dfree,dsize,bsize;
1213   
1214   conn->vfs_ops.disk_free(".",True,&bsize,&dfree,&dsize);
1215   
1216   outsize = set_message(outbuf,5,0,True);
1217   
1218   SSVAL(outbuf,smb_vwv0,dsize);
1219   SSVAL(outbuf,smb_vwv1,bsize/512);
1220   SSVAL(outbuf,smb_vwv2,512);
1221   SSVAL(outbuf,smb_vwv3,dfree);
1222
1223   DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1224
1225   return(outsize);
1226 }
1227
1228
1229 /****************************************************************************
1230   reply to a search
1231   Can be called from SMBsearch, SMBffirst or SMBfunique.
1232 ****************************************************************************/
1233 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1234 {
1235   pstring mask;
1236   pstring directory;
1237   pstring fname;
1238   SMB_OFF_T size;
1239   int mode;
1240   time_t date;
1241   int dirtype;
1242   int outsize = 0;
1243   int numentries = 0;
1244   BOOL finished = False;
1245   int maxentries;
1246   int i;
1247   char *p;
1248   BOOL ok = False;
1249   int status_len;
1250   char *path;
1251   char status[21];
1252   int dptr_num= -1;
1253   BOOL check_descend = False;
1254   BOOL expect_close = False;
1255   BOOL can_open = True;
1256   BOOL bad_path = False;
1257
1258   *mask = *directory = *fname = 0;
1259
1260   /* If we were called as SMBffirst then we must expect close. */
1261   if(CVAL(inbuf,smb_com) == SMBffirst)
1262     expect_close = True;
1263   
1264   outsize = set_message(outbuf,1,3,True);
1265   maxentries = SVAL(inbuf,smb_vwv0); 
1266   dirtype = SVAL(inbuf,smb_vwv1);
1267   path = smb_buf(inbuf) + 1;
1268   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1269
1270   
1271   /* dirtype &= ~aDIR; */
1272   
1273   DEBUG(5,("reply_search: path=%s status_len=%d\n",path,status_len));
1274
1275   
1276   if (status_len == 0)
1277   {
1278     pstring dir2;
1279
1280     pstrcpy(directory,smb_buf(inbuf)+1);
1281     pstrcpy(dir2,smb_buf(inbuf)+1);
1282     unix_convert(directory,conn,0,&bad_path,NULL);
1283     unix_format(dir2);
1284
1285     if (!check_name(directory,conn))
1286       can_open = False;
1287
1288     p = strrchr(dir2,'/');
1289     if (p == NULL) 
1290     {
1291       pstrcpy(mask,dir2);
1292       *dir2 = 0;
1293     }
1294     else
1295     {
1296       *p = 0;
1297       pstrcpy(mask,p+1);
1298     }
1299
1300     p = strrchr(directory,'/');
1301     if (!p) 
1302       *directory = 0;
1303     else
1304       *p = 0;
1305
1306     if (strlen(directory) == 0)
1307       pstrcpy(directory,"./");
1308     memset((char *)status,'\0',21);
1309     CVAL(status,0) = dirtype;
1310   }
1311   else
1312   {
1313     memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1314     memcpy(mask,status+1,11);
1315     mask[11] = 0;
1316     dirtype = CVAL(status,0) & 0x1F;
1317     conn->dirptr = dptr_fetch(status+12,&dptr_num);      
1318     if (!conn->dirptr)
1319       goto SearchEmpty;
1320     string_set(&conn->dirpath,dptr_path(dptr_num));
1321     if (!case_sensitive)
1322       strnorm(mask);
1323   }
1324
1325   /* turn strings of spaces into a . */  
1326   {
1327     trim_string(mask,NULL," ");
1328     if ((p = strrchr(mask,' ')))
1329     {
1330       fstring ext;
1331       fstrcpy(ext,p+1);
1332       *p = 0;
1333       trim_string(mask,NULL," ");
1334       pstrcat(mask,".");
1335       pstrcat(mask,ext);
1336     }
1337   }
1338
1339   /* Convert the formatted mask. (This code lives in trans2.c) */
1340   mask_convert(mask);
1341
1342   {
1343     int skip;
1344     p = mask;
1345     while(*p)
1346     {
1347       if((skip = get_character_len( *p )) != 0 )
1348       {
1349         p += skip;
1350       }
1351       else
1352       {
1353         if (*p != '?' && *p != '*' && !isdoschar(*p))
1354         {
1355           DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
1356           *p = '?';
1357         }
1358         p++;
1359       }
1360     }
1361   }
1362
1363   if (!strchr(mask,'.') && strlen(mask)>8)
1364   {
1365     fstring tmp;
1366     fstrcpy(tmp,&mask[8]);
1367     mask[8] = '.';
1368     mask[9] = 0;
1369     pstrcat(mask,tmp);
1370   }
1371
1372   DEBUG(5,("mask=%s directory=%s\n",mask,directory));
1373   
1374   if (can_open)
1375   {
1376     p = smb_buf(outbuf) + 3;
1377       
1378     ok = True;
1379      
1380     if (status_len == 0)
1381     {
1382       dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
1383       if (dptr_num < 0)
1384       {
1385         if(dptr_num == -2)
1386         {
1387           if((errno == ENOENT) && bad_path)
1388           {
1389             unix_ERR_class = ERRDOS;
1390             unix_ERR_code = ERRbadpath;
1391           }
1392           return (UNIXERROR(ERRDOS,ERRnofids));
1393         }
1394         return(ERROR(ERRDOS,ERRnofids));
1395       }
1396     }
1397
1398     DEBUG(4,("dptr_num is %d\n",dptr_num));
1399
1400     if (ok)
1401     {
1402       if ((dirtype&0x1F) == aVOLID)
1403       {   
1404         memcpy(p,status,21);
1405         make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
1406         dptr_fill(p+12,dptr_num);
1407         if (dptr_zero(p+12) && (status_len==0))
1408           numentries = 1;
1409         else
1410           numentries = 0;
1411         p += DIR_STRUCT_SIZE;
1412       }
1413       else 
1414       {
1415         DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1416               conn->dirpath,lp_dontdescend(SNUM(conn))));
1417         if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
1418           check_descend = True;
1419
1420         for (i=numentries;(i<maxentries) && !finished;i++)
1421         {
1422           finished = 
1423             !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
1424           if (!finished)
1425           {
1426             memcpy(p,status,21);
1427             make_dir_struct(p,mask,fname,size,mode,date);
1428             dptr_fill(p+12,dptr_num);
1429             numentries++;
1430           }
1431           p += DIR_STRUCT_SIZE;
1432         }
1433       }
1434         } /* if (ok ) */
1435   }
1436
1437
1438   SearchEmpty:
1439
1440   if (numentries == 0 || !ok)
1441   {
1442     CVAL(outbuf,smb_rcls) = ERRDOS;
1443     SSVAL(outbuf,smb_err,ERRnofiles);
1444     dptr_close(&dptr_num);
1445   }
1446
1447   /* If we were called as SMBffirst with smb_search_id == NULL
1448      and no entries were found then return error and close dirptr 
1449      (X/Open spec) */
1450
1451   if(ok && expect_close && numentries == 0 && status_len == 0)
1452   {
1453     CVAL(outbuf,smb_rcls) = ERRDOS;
1454     SSVAL(outbuf,smb_err,ERRnofiles);
1455     /* Also close the dptr - we know it's gone */
1456     dptr_close(&dptr_num);
1457   }
1458
1459   /* If we were called as SMBfunique, then we can close the dirptr now ! */
1460   if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
1461     dptr_close(&dptr_num);
1462
1463   SSVAL(outbuf,smb_vwv0,numentries);
1464   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1465   CVAL(smb_buf(outbuf),0) = 5;
1466   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
1467
1468   if (Protocol >= PROTOCOL_NT1) {
1469     uint16 flg2 = SVAL(outbuf,smb_flg2);
1470     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1471   }
1472   
1473   outsize += DIR_STRUCT_SIZE*numentries;
1474   smb_setlen(outbuf,outsize - 4);
1475   
1476   if ((! *directory) && dptr_path(dptr_num))
1477     slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
1478
1479   DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
1480         smb_fn_name(CVAL(inbuf,smb_com)), 
1481         mask, directory, dirtype, numentries, maxentries ) );
1482
1483   return(outsize);
1484 }
1485
1486
1487 /****************************************************************************
1488   reply to a fclose (stop directory search)
1489 ****************************************************************************/
1490 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1491 {
1492   int outsize = 0;
1493   int status_len;
1494   char *path;
1495   char status[21];
1496   int dptr_num= -2;
1497
1498   outsize = set_message(outbuf,1,0,True);
1499   path = smb_buf(inbuf) + 1;
1500   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1501
1502   
1503   if (status_len == 0)
1504     return(ERROR(ERRSRV,ERRsrverror));
1505
1506   memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1507
1508   if(dptr_fetch(status+12,&dptr_num)) {
1509     /*  Close the dptr - we know it's gone */
1510     dptr_close(&dptr_num);
1511   }
1512
1513   SSVAL(outbuf,smb_vwv0,0);
1514
1515   DEBUG(3,("search close\n"));
1516
1517   return(outsize);
1518 }
1519
1520
1521 /****************************************************************************
1522   reply to an open
1523 ****************************************************************************/
1524
1525 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1526 {
1527   pstring fname;
1528   int outsize = 0;
1529   int fmode=0;
1530   int share_mode;
1531   SMB_OFF_T size = 0;
1532   time_t mtime=0;
1533   mode_t unixmode;
1534   int rmode=0;
1535   SMB_STRUCT_STAT sbuf;
1536   BOOL bad_path = False;
1537   files_struct *fsp;
1538   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1539  
1540   share_mode = SVAL(inbuf,smb_vwv0);
1541
1542   pstrcpy(fname,smb_buf(inbuf)+1);
1543
1544   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1545
1546   unix_convert(fname,conn,0,&bad_path,NULL);
1547     
1548   fsp = file_new();
1549   if (!fsp)
1550     return(ERROR(ERRSRV,ERRnofids));
1551
1552   if (!check_name(fname,conn))
1553   {
1554     if((errno == ENOENT) && bad_path)
1555     {
1556       unix_ERR_class = ERRDOS;
1557       unix_ERR_code = ERRbadpath;
1558     }
1559     file_free(fsp);
1560     return(UNIXERROR(ERRDOS,ERRnoaccess));
1561   }
1562  
1563   unixmode = unix_mode(conn,aARCH,fname);
1564       
1565   open_file_shared(fsp,conn,fname,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1566                    unixmode, oplock_request,&rmode,NULL);
1567
1568   if (!fsp->open)
1569   {
1570     if((errno == ENOENT) && bad_path)
1571     {
1572       unix_ERR_class = ERRDOS;
1573       unix_ERR_code = ERRbadpath;
1574     }
1575     file_free(fsp);
1576     return(UNIXERROR(ERRDOS,ERRnoaccess));
1577   }
1578
1579   if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
1580     close_file(fsp,False);
1581     return(ERROR(ERRDOS,ERRnoaccess));
1582   }
1583     
1584   size = sbuf.st_size;
1585   fmode = dos_mode(conn,fname,&sbuf);
1586   mtime = sbuf.st_mtime;
1587
1588   if (fmode & aDIR) {
1589     DEBUG(3,("attempt to open a directory %s\n",fname));
1590     close_file(fsp,False);
1591     return(ERROR(ERRDOS,ERRnoaccess));
1592   }
1593   
1594   outsize = set_message(outbuf,7,0,True);
1595   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1596   SSVAL(outbuf,smb_vwv1,fmode);
1597   if(lp_dos_filetime_resolution(SNUM(conn)) )
1598     put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
1599   else
1600     put_dos_date3(outbuf,smb_vwv2,mtime);
1601   SIVAL(outbuf,smb_vwv4,(uint32)size);
1602   SSVAL(outbuf,smb_vwv6,rmode);
1603
1604   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1605     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1606   }
1607     
1608   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1609     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1610   return(outsize);
1611 }
1612
1613
1614 /****************************************************************************
1615   reply to an open and X
1616 ****************************************************************************/
1617 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1618 {
1619   pstring fname;
1620   int smb_mode = SVAL(inbuf,smb_vwv3);
1621   int smb_attr = SVAL(inbuf,smb_vwv5);
1622   /* Breakout the oplock request bits so we can set the
1623      reply bits separately. */
1624   BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
1625   BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1626   BOOL oplock_request = ex_oplock_request | core_oplock_request;
1627 #if 0
1628   int open_flags = SVAL(inbuf,smb_vwv2);
1629   int smb_sattr = SVAL(inbuf,smb_vwv4); 
1630   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
1631 #endif
1632   int smb_ofun = SVAL(inbuf,smb_vwv8);
1633   mode_t unixmode;
1634   SMB_OFF_T size=0;
1635   int fmode=0,mtime=0,rmode=0;
1636   SMB_STRUCT_STAT sbuf;
1637   int smb_action = 0;
1638   BOOL bad_path = False;
1639   files_struct *fsp;
1640
1641   /* If it's an IPC, pass off the pipe handler. */
1642   if (IS_IPC(conn) && lp_nt_pipe_support())
1643     return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
1644
1645   /* XXXX we need to handle passed times, sattr and flags */
1646
1647   pstrcpy(fname,smb_buf(inbuf));
1648
1649   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1650
1651   unix_convert(fname,conn,0,&bad_path,NULL);
1652     
1653   fsp = file_new();
1654   if (!fsp)
1655     return(ERROR(ERRSRV,ERRnofids));
1656
1657   if (!check_name(fname,conn))
1658   {
1659     if((errno == ENOENT) && bad_path)
1660     {
1661       unix_ERR_class = ERRDOS;
1662       unix_ERR_code = ERRbadpath;
1663     }
1664     file_free(fsp);
1665     return(UNIXERROR(ERRDOS,ERRnoaccess));
1666   }
1667
1668   unixmode = unix_mode(conn,smb_attr | aARCH, fname);
1669       
1670   open_file_shared(fsp,conn,fname,smb_mode,smb_ofun,unixmode,
1671                        oplock_request, &rmode,&smb_action);
1672       
1673   if (!fsp->open)
1674   {
1675     if((errno == ENOENT) && bad_path)
1676     {
1677       unix_ERR_class = ERRDOS;
1678       unix_ERR_code = ERRbadpath;
1679     }
1680     file_free(fsp);
1681     return(UNIXERROR(ERRDOS,ERRnoaccess));
1682   }
1683
1684   if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
1685     close_file(fsp,False);
1686     return(ERROR(ERRDOS,ERRnoaccess));
1687   }
1688
1689   size = sbuf.st_size;
1690   fmode = dos_mode(conn,fname,&sbuf);
1691   mtime = sbuf.st_mtime;
1692   if (fmode & aDIR) {
1693     close_file(fsp,False);
1694     return(ERROR(ERRDOS,ERRnoaccess));
1695   }
1696
1697   /* If the caller set the extended oplock request bit
1698      and we granted one (by whatever means) - set the
1699      correct bit for extended oplock reply.
1700    */
1701
1702   if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1703     smb_action |= EXTENDED_OPLOCK_GRANTED;
1704   }
1705
1706   if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1707     smb_action |= EXTENDED_OPLOCK_GRANTED;
1708   }
1709
1710   /* If the caller set the core oplock request bit
1711      and we granted one (by whatever means) - set the
1712      correct bit for core oplock reply.
1713    */
1714
1715   if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1716     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1717   }
1718
1719   if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1720     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1721   }
1722
1723   set_message(outbuf,15,0,True);
1724   SSVAL(outbuf,smb_vwv2,fsp->fnum);
1725   SSVAL(outbuf,smb_vwv3,fmode);
1726   if(lp_dos_filetime_resolution(SNUM(conn)) )
1727     put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
1728   else
1729     put_dos_date3(outbuf,smb_vwv4,mtime);
1730   SIVAL(outbuf,smb_vwv6,(uint32)size);
1731   SSVAL(outbuf,smb_vwv8,rmode);
1732   SSVAL(outbuf,smb_vwv11,smb_action);
1733
1734   return chain_reply(inbuf,outbuf,length,bufsize);
1735 }
1736
1737
1738 /****************************************************************************
1739   reply to a SMBulogoffX
1740 ****************************************************************************/
1741 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1742 {
1743   uint16 vuid = SVAL(inbuf,smb_uid);
1744   user_struct *vuser = get_valid_user_struct(vuid);
1745
1746   if(vuser == 0) {
1747     DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
1748   }
1749
1750   /* in user level security we are supposed to close any files
1751      open by this user */
1752   if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
1753           file_close_user(vuid);
1754   }
1755
1756   invalidate_vuid(vuid);
1757
1758   set_message(outbuf,2,0,True);
1759
1760   DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
1761
1762   return chain_reply(inbuf,outbuf,length,bufsize);
1763 }
1764
1765
1766 /****************************************************************************
1767   reply to a mknew or a create
1768 ****************************************************************************/
1769 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1770 {
1771   pstring fname;
1772   int com;
1773   int outsize = 0;
1774   int createmode;
1775   mode_t unixmode;
1776   int ofun = 0;
1777   BOOL bad_path = False;
1778   files_struct *fsp;
1779   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1780  
1781   com = SVAL(inbuf,smb_com);
1782
1783   createmode = SVAL(inbuf,smb_vwv0);
1784   pstrcpy(fname,smb_buf(inbuf)+1);
1785
1786   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1787
1788   unix_convert(fname,conn,0,&bad_path,NULL);
1789
1790   if (createmode & aVOLID)
1791     {
1792       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1793     }
1794   
1795   unixmode = unix_mode(conn,createmode,fname);
1796   
1797   fsp = file_new();
1798   if (!fsp)
1799     return(ERROR(ERRSRV,ERRnofids));
1800
1801   if (!check_name(fname,conn))
1802   {
1803     if((errno == ENOENT) && bad_path)
1804     {
1805       unix_ERR_class = ERRDOS;
1806       unix_ERR_code = ERRbadpath;
1807     }
1808     file_free(fsp);
1809     return(UNIXERROR(ERRDOS,ERRnoaccess));
1810   }
1811
1812   if(com == SMBmknew)
1813   {
1814     /* We should fail if file exists. */
1815     ofun = FILE_CREATE_IF_NOT_EXIST;
1816   }
1817   else
1818   {
1819     /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1820     ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
1821   }
1822
1823   /* Open file in dos compatibility share mode. */
1824   open_file_shared(fsp,conn,fname,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
1825                    ofun, unixmode, oplock_request, NULL, NULL);
1826   
1827   if (!fsp->open)
1828   {
1829     if((errno == ENOENT) && bad_path) 
1830     {
1831       unix_ERR_class = ERRDOS;
1832       unix_ERR_code = ERRbadpath;
1833     }
1834     file_free(fsp);
1835     return(UNIXERROR(ERRDOS,ERRnoaccess));
1836   }
1837  
1838   outsize = set_message(outbuf,1,0,True);
1839   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1840
1841   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1842     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1843   }
1844  
1845   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1846     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1847  
1848   DEBUG( 2, ( "new file %s\n", fname ) );
1849   DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
1850         fname, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
1851
1852   return(outsize);
1853 }
1854
1855
1856 /****************************************************************************
1857   reply to a create temporary file
1858 ****************************************************************************/
1859 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1860 {
1861   pstring fname;
1862   pstring fname2;
1863   int outsize = 0;
1864   int createmode;
1865   mode_t unixmode;
1866   BOOL bad_path = False;
1867   files_struct *fsp;
1868   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1869  
1870   createmode = SVAL(inbuf,smb_vwv0);
1871   pstrcpy(fname,smb_buf(inbuf)+1);
1872   pstrcat(fname,"/TMXXXXXX");
1873
1874   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1875
1876   unix_convert(fname,conn,0,&bad_path,NULL);
1877   
1878   unixmode = unix_mode(conn,createmode,fname);
1879   
1880   fsp = file_new();
1881   if (fsp)
1882     return(ERROR(ERRSRV,ERRnofids));
1883
1884   if (!check_name(fname,conn))
1885   {
1886     if((errno == ENOENT) && bad_path)
1887     {
1888       unix_ERR_class = ERRDOS;
1889       unix_ERR_code = ERRbadpath;
1890     }
1891     file_free(fsp);
1892     return(UNIXERROR(ERRDOS,ERRnoaccess));
1893   }
1894
1895   pstrcpy(fname2,(char *)smbd_mktemp(fname));
1896
1897   /* Open file in dos compatibility share mode. */
1898   /* We should fail if file exists. */
1899   open_file_shared(fsp,conn,fname2,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
1900                    (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unixmode, oplock_request, NULL, NULL);
1901
1902   if (!fsp->open)
1903   {
1904     if((errno == ENOENT) && bad_path)
1905     {
1906       unix_ERR_class = ERRDOS;
1907       unix_ERR_code = ERRbadpath;
1908     }
1909     file_free(fsp);
1910     return(UNIXERROR(ERRDOS,ERRnoaccess));
1911   }
1912
1913   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
1914   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1915   CVAL(smb_buf(outbuf),0) = 4;
1916   pstrcpy(smb_buf(outbuf) + 1,fname2);
1917
1918   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1919     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1920   }
1921   
1922   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1923     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1924
1925   DEBUG( 2, ( "created temp file %s\n", fname2 ) );
1926   DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
1927         fname2, fsp->fd_ptr->fd, createmode, (int)unixmode ) );
1928
1929   return(outsize);
1930 }
1931
1932
1933 /*******************************************************************
1934 check if a user is allowed to delete a file
1935 ********************************************************************/
1936 static BOOL can_delete(char *fname,connection_struct *conn, int dirtype)
1937 {
1938   SMB_STRUCT_STAT sbuf;
1939   int fmode;
1940
1941   if (!CAN_WRITE(conn)) return(False);
1942
1943   if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
1944   fmode = dos_mode(conn,fname,&sbuf);
1945   if (fmode & aDIR) return(False);
1946   if (!lp_delete_readonly(SNUM(conn))) {
1947     if (fmode & aRONLY) return(False);
1948   }
1949   if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1950     return(False);
1951   if (!check_file_sharing(conn,fname,False)) return(False);
1952   return(True);
1953 }
1954
1955 /****************************************************************************
1956  Reply to a unlink
1957 ****************************************************************************/
1958
1959 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1960 {
1961   int outsize = 0;
1962   pstring name;
1963   int dirtype;
1964   pstring directory;
1965   pstring mask;
1966   char *p;
1967   int count=0;
1968   int error = ERRnoaccess;
1969   BOOL has_wild;
1970   BOOL exists=False;
1971   BOOL bad_path = False;
1972   BOOL rc = True;
1973
1974   *directory = *mask = 0;
1975
1976   dirtype = SVAL(inbuf,smb_vwv0);
1977   
1978   pstrcpy(name,smb_buf(inbuf) + 1);
1979    
1980   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1981
1982   DEBUG(3,("reply_unlink : %s\n",name));
1983    
1984   rc = unix_convert(name,conn,0,&bad_path,NULL);
1985
1986   p = strrchr(name,'/');
1987   if (!p) {
1988     pstrcpy(directory,"./");
1989     pstrcpy(mask,name);
1990   } else {
1991     *p = 0;
1992     pstrcpy(directory,name);
1993     pstrcpy(mask,p+1);
1994   }
1995
1996   /*
1997    * We should only check the mangled cache
1998    * here if unix_convert failed. This means
1999    * that the path in 'mask' doesn't exist
2000    * on the file system and so we need to look
2001    * for a possible mangle. This patch from
2002    * Tine Smukavec <valentin.smukavec@hermes.si>.
2003    */
2004
2005   if (!rc && is_mangled(mask))
2006     check_mangled_cache( mask );
2007
2008   has_wild = strchr(mask,'*') || strchr(mask,'?');
2009
2010   if (!has_wild) {
2011     pstrcat(directory,"/");
2012     pstrcat(directory,mask);
2013     if (can_delete(directory,conn,dirtype) && !dos_unlink(directory))
2014       count++;
2015     if (!count)
2016       exists = vfs_file_exist(conn,directory,NULL);    
2017   } else {
2018     void *dirptr = NULL;
2019     char *dname;
2020
2021     if (check_name(directory,conn))
2022       dirptr = OpenDir(conn, directory, True);
2023
2024     /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2025        the pattern matches against the long name, otherwise the short name 
2026        We don't implement this yet XXXX
2027        */
2028
2029     if (dirptr)
2030       {
2031         error = ERRbadfile;
2032
2033         if (strequal(mask,"????????.???"))
2034           pstrcpy(mask,"*");
2035
2036         while ((dname = ReadDirName(dirptr)))
2037           {
2038             pstring fname;
2039             pstrcpy(fname,dname);
2040             
2041             if(!mask_match(fname, mask, case_sensitive, False)) continue;
2042
2043             error = ERRnoaccess;
2044             slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
2045             if (!can_delete(fname,conn,dirtype)) continue;
2046             if (!conn->vfs_ops.unlink(dos_to_unix(fname,False))) count++;
2047             DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
2048           }
2049         CloseDir(dirptr);
2050       }
2051   }
2052   
2053   if (count == 0) {
2054     if (exists)
2055       return(ERROR(ERRDOS,error));
2056     else
2057     {
2058       if((errno == ENOENT) && bad_path)
2059       {
2060         unix_ERR_class = ERRDOS;
2061         unix_ERR_code = ERRbadpath;
2062       }
2063       return(UNIXERROR(ERRDOS,error));
2064     }
2065   }
2066   
2067   outsize = set_message(outbuf,0,0,True);
2068   
2069   return(outsize);
2070 }
2071
2072
2073 /****************************************************************************
2074    reply to a readbraw (core+ protocol)
2075 ****************************************************************************/
2076
2077 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
2078 {
2079   size_t maxcount,mincount;
2080   size_t nread = 0;
2081   SMB_OFF_T startpos;
2082   char *header = outbuf;
2083   ssize_t ret=0;
2084   files_struct *fsp;
2085
2086   /*
2087    * Special check if an oplock break has been issued
2088    * and the readraw request croses on the wire, we must
2089    * return a zero length response here.
2090    */
2091
2092   if(global_oplock_break)
2093   {
2094     _smb_setlen(header,0);
2095     transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
2096     DEBUG(5,("readbraw - oplock break finished\n"));
2097     return -1;
2098   }
2099
2100   fsp = file_fsp(inbuf,smb_vwv0);
2101
2102   if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
2103           /*
2104            * fsp could be NULL here so use the value from the packet. JRA.
2105            */
2106           DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
2107           _smb_setlen(header,0);
2108           transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
2109           return(-1);
2110   }
2111
2112   CHECK_FSP(fsp,conn);
2113
2114   flush_write_cache(fsp, READRAW_FLUSH);
2115
2116   startpos = IVAL(inbuf,smb_vwv1);
2117   if(CVAL(inbuf,smb_wct) == 10) {
2118     /*
2119      * This is a large offset (64 bit) read.
2120      */
2121 #ifdef LARGE_SMB_OFF_T
2122
2123     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
2124
2125 #else /* !LARGE_SMB_OFF_T */
2126
2127     /*
2128      * Ensure we haven't been sent a >32 bit offset.
2129      */
2130
2131     if(IVAL(inbuf,smb_vwv8) != 0) {
2132       DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
2133 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
2134       _smb_setlen(header,0);
2135       transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
2136       return(-1);
2137     }
2138
2139 #endif /* LARGE_SMB_OFF_T */
2140
2141     if(startpos < 0) {
2142       DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n",
2143             (double)startpos ));
2144           _smb_setlen(header,0);
2145           transfer_file(0,Client,(SMB_OFF_T)0,header,4,0);
2146           return(-1);
2147     }      
2148   }
2149   maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
2150   mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
2151
2152   /* ensure we don't overrun the packet size */
2153   maxcount = MIN(65535,maxcount);
2154   maxcount = MAX(mincount,maxcount);
2155
2156   if (!is_locked(fsp,conn,maxcount,startpos, READ_LOCK))
2157   {
2158     SMB_OFF_T size = fsp->size;
2159     SMB_OFF_T sizeneeded = startpos + maxcount;
2160             
2161     if (size < sizeneeded)
2162     {
2163       SMB_STRUCT_STAT st;
2164       if (fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd,&st) == 0)
2165         size = st.st_size;
2166       if (!fsp->can_write) 
2167         fsp->size = size;
2168     }
2169
2170     nread = MIN(maxcount,(size - startpos));      
2171   }
2172
2173   if (nread < mincount)
2174     nread = 0;
2175   
2176   DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n",
2177               fsp->fnum, (double)startpos,
2178               (int)maxcount, (int)mincount, (int)nread ) );
2179   
2180 #if UNSAFE_READRAW
2181   {
2182     BOOL seek_fail = False;
2183     int predict=0;
2184     _smb_setlen(header,nread);
2185
2186 #if USE_READ_PREDICTION
2187     if (!fsp->can_write)
2188       predict = read_predict(fsp, fsp->fd_ptr->fd,startpos,header+4,NULL,nread);
2189 #endif /* USE_READ_PREDICTION */
2190
2191     if ((nread-predict) > 0) {
2192       if(conn->vfs_ops.seek(fsp,startpos + predict) == -1) {
2193         DEBUG(0,("reply_readbraw: ERROR: seek_file failed.\n"));
2194         ret = 0;
2195         seek_fail = True;
2196       } 
2197     }
2198
2199     if(!seek_fail)
2200       ret = (ssize_t)vfs_transfer_file(-1, fsp->fd_ptr->fd, Client, NULL,
2201                                    (SMB_OFF_T)(nread-predict),header,4+predict, 
2202                                    startpos+predict);
2203   }
2204
2205   if (ret != nread+4)
2206     DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
2207              fsp->fsp_name,startpos,nread,ret));
2208
2209 #else /* UNSAFE_READRAW */
2210   ret = read_file(fsp,header+4,startpos,nread);
2211   if (ret < mincount) ret = 0;
2212
2213   _smb_setlen(header,ret);
2214   transfer_file(0,Client,0,header,4+ret,0);
2215 #endif /* UNSAFE_READRAW */
2216
2217   DEBUG(5,("readbraw finished\n"));
2218   return -1;
2219 }
2220
2221
2222 /****************************************************************************
2223   reply to a lockread (core+ protocol)
2224 ****************************************************************************/
2225 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
2226 {
2227   ssize_t nread = -1;
2228   char *data;
2229   int outsize = 0;
2230   SMB_OFF_T startpos;
2231   size_t numtoread;
2232   int eclass;
2233   uint32 ecode;
2234   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2235
2236   CHECK_FSP(fsp,conn);
2237   CHECK_READ(fsp);
2238   CHECK_ERROR(fsp);
2239
2240   numtoread = SVAL(inbuf,smb_vwv1);
2241   startpos = IVAL(inbuf,smb_vwv2);
2242   
2243   outsize = set_message(outbuf,5,3,True);
2244   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
2245   data = smb_buf(outbuf) + 3;
2246  
2247   /*
2248    * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
2249    * protocol request that predates the read/write lock concept. 
2250    * Thus instead of asking for a read lock here we need to ask
2251    * for a write lock. JRA.
2252    */
2253
2254   if(!do_lock( fsp, conn, numtoread, startpos, WRITE_LOCK, &eclass, &ecode)) {
2255     if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
2256       /*
2257        * A blocking lock was requested. Package up
2258        * this smb into a queued request and push it
2259        * onto the blocking lock queue.
2260        */
2261       if(push_blocking_lock_request(inbuf, length, -1, 0))
2262         return -1;
2263     }
2264     return (ERROR(eclass,ecode));
2265   }
2266
2267   nread = read_file(fsp,data,startpos,numtoread);
2268
2269   if (nread < 0)
2270     return(UNIXERROR(ERRDOS,ERRnoaccess));
2271
2272   outsize += nread;
2273   SSVAL(outbuf,smb_vwv0,nread);
2274   SSVAL(outbuf,smb_vwv5,nread+3);
2275   SSVAL(smb_buf(outbuf),1,nread);
2276
2277   DEBUG( 3, ( "lockread fnum=%d num=%d nread=%d\n",
2278             fsp->fnum, (int)numtoread, (int)nread ) );
2279
2280   return(outsize);
2281 }
2282
2283
2284 /****************************************************************************
2285   reply to a read
2286 ****************************************************************************/
2287
2288 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2289 {
2290   size_t numtoread;
2291   ssize_t nread = 0;
2292   char *data;
2293   SMB_OFF_T startpos;
2294   int outsize = 0;
2295   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2296
2297   CHECK_FSP(fsp,conn);
2298   CHECK_READ(fsp);
2299   CHECK_ERROR(fsp);
2300
2301   numtoread = SVAL(inbuf,smb_vwv1);
2302   startpos = IVAL(inbuf,smb_vwv2);
2303   
2304   outsize = set_message(outbuf,5,3,True);
2305   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
2306   data = smb_buf(outbuf) + 3;
2307   
2308   if (is_locked(fsp,conn,numtoread,startpos, READ_LOCK))
2309     return(ERROR(ERRDOS,ERRlock));      
2310
2311   if (numtoread > 0)
2312     nread = read_file(fsp,data,startpos,numtoread);
2313   
2314   if (nread < 0)
2315     return(UNIXERROR(ERRDOS,ERRnoaccess));
2316   
2317   outsize += nread;
2318   SSVAL(outbuf,smb_vwv0,nread);
2319   SSVAL(outbuf,smb_vwv5,nread+3);
2320   CVAL(smb_buf(outbuf),0) = 1;
2321   SSVAL(smb_buf(outbuf),1,nread);
2322   
2323   DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
2324             fsp->fnum, (int)numtoread, (int)nread ) );
2325
2326   return(outsize);
2327 }
2328
2329
2330 /****************************************************************************
2331   reply to a read and X
2332 ****************************************************************************/
2333 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2334 {
2335   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2336   SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
2337   size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
2338   size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
2339   ssize_t nread = -1;
2340   char *data;
2341
2342   /* If it's an IPC, pass off the pipe handler. */
2343   if (IS_IPC(conn))
2344     return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
2345
2346   CHECK_FSP(fsp,conn);
2347   CHECK_READ(fsp);
2348   CHECK_ERROR(fsp);
2349
2350   set_message(outbuf,12,0,True);
2351   data = smb_buf(outbuf);
2352
2353   if(CVAL(inbuf,smb_wct) == 12) {
2354 #ifdef LARGE_SMB_OFF_T
2355     /*
2356      * This is a large offset (64 bit) read.
2357      */
2358     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
2359
2360 #else /* !LARGE_SMB_OFF_T */
2361
2362     /*
2363      * Ensure we haven't been sent a >32 bit offset.
2364      */
2365
2366     if(IVAL(inbuf,smb_vwv10) != 0) {
2367       DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
2368 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
2369       return(ERROR(ERRDOS,ERRbadaccess));
2370     }
2371
2372 #endif /* LARGE_SMB_OFF_T */
2373
2374   }
2375
2376   if (is_locked(fsp,conn,smb_maxcnt,startpos, READ_LOCK))
2377     return(ERROR(ERRDOS,ERRlock));
2378   nread = read_file(fsp,data,startpos,smb_maxcnt);
2379   
2380   if (nread < 0)
2381     return(UNIXERROR(ERRDOS,ERRnoaccess));
2382   
2383   SSVAL(outbuf,smb_vwv5,nread);
2384   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2385   SSVAL(smb_buf(outbuf),-2,nread);
2386   
2387   DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
2388               fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
2389
2390   return chain_reply(inbuf,outbuf,length,bufsize);
2391 }
2392
2393 /****************************************************************************
2394   reply to a writebraw (core+ or LANMAN1.0 protocol)
2395 ****************************************************************************/
2396
2397 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2398 {
2399   ssize_t nwritten=0;
2400   ssize_t total_written=0;
2401   size_t numtowrite=0;
2402   size_t tcount;
2403   SMB_OFF_T startpos;
2404   char *data=NULL;
2405   BOOL write_through;
2406   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2407   int outsize = 0;
2408
2409   CHECK_FSP(fsp,conn);
2410   CHECK_WRITE(fsp);
2411   CHECK_ERROR(fsp);
2412   
2413   tcount = IVAL(inbuf,smb_vwv1);
2414   startpos = IVAL(inbuf,smb_vwv3);
2415   write_through = BITSETW(inbuf+smb_vwv7,0);
2416
2417   /* We have to deal with slightly different formats depending
2418      on whether we are using the core+ or lanman1.0 protocol */
2419   if(Protocol <= PROTOCOL_COREPLUS) {
2420     numtowrite = SVAL(smb_buf(inbuf),-2);
2421     data = smb_buf(inbuf);
2422   } else {
2423     numtowrite = SVAL(inbuf,smb_vwv10);
2424     data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
2425   }
2426
2427   /* force the error type */
2428   CVAL(inbuf,smb_com) = SMBwritec;
2429   CVAL(outbuf,smb_com) = SMBwritec;
2430
2431   if (is_locked(fsp,conn,tcount,startpos, WRITE_LOCK))
2432     return(ERROR(ERRDOS,ERRlock));
2433
2434   if (numtowrite>0)
2435     nwritten = write_file(fsp,data,startpos,numtowrite);
2436   
2437   DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
2438            fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
2439
2440   if (nwritten < numtowrite) 
2441     return(UNIXERROR(ERRHRD,ERRdiskfull));
2442
2443   total_written = nwritten;
2444
2445   /* Return a message to the redirector to tell it
2446      to send more bytes */
2447   CVAL(outbuf,smb_com) = SMBwritebraw;
2448   SSVALS(outbuf,smb_vwv0,-1);
2449   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
2450   send_smb(Client,outbuf);
2451   
2452   /* Now read the raw data into the buffer and write it */
2453   if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
2454     exit_server("secondary writebraw failed");
2455   }
2456   
2457   /* Even though this is not an smb message, smb_len
2458      returns the generic length of an smb message */
2459   numtowrite = smb_len(inbuf);
2460
2461   if (tcount > nwritten+numtowrite) {
2462     DEBUG(3,("Client overestimated the write %d %d %d\n",
2463              (int)tcount,(int)nwritten,(int)numtowrite));
2464   }
2465
2466   nwritten = vfs_transfer_file(Client, NULL, -1, fsp,
2467                                (SMB_OFF_T)numtowrite,NULL,0, 
2468                                startpos+nwritten);
2469   total_written += nwritten;
2470   
2471   /* Set up outbuf to return the correct return */
2472   outsize = set_message(outbuf,1,0,True);
2473   CVAL(outbuf,smb_com) = SMBwritec;
2474   SSVAL(outbuf,smb_vwv0,total_written);
2475
2476   if (nwritten < (ssize_t)numtowrite) {
2477     CVAL(outbuf,smb_rcls) = ERRHRD;
2478     SSVAL(outbuf,smb_err,ERRdiskfull);      
2479   }
2480
2481   if ((lp_syncalways(SNUM(conn)) || write_through) && 
2482       lp_strict_sync(SNUM(conn)))
2483       conn->vfs_ops.fsync(fsp->fd_ptr->fd);
2484
2485   DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
2486            fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
2487
2488   /* we won't return a status if write through is not selected - this 
2489      follows what WfWg does */
2490   if (!write_through && total_written==tcount)
2491     return(-1);
2492
2493   return(outsize);
2494 }
2495
2496 /****************************************************************************
2497   reply to a writeunlock (core+)
2498 ****************************************************************************/
2499
2500 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2501 {
2502   ssize_t nwritten = -1;
2503   size_t numtowrite;
2504   SMB_OFF_T startpos;
2505   char *data;
2506   int eclass;
2507   uint32 ecode;
2508   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2509   int outsize = 0;
2510
2511   CHECK_FSP(fsp,conn);
2512   CHECK_WRITE(fsp);
2513   CHECK_ERROR(fsp);
2514
2515   numtowrite = SVAL(inbuf,smb_vwv1);
2516   startpos = IVAL(inbuf,smb_vwv2);
2517   data = smb_buf(inbuf) + 3;
2518   
2519   if (is_locked(fsp,conn,numtowrite,startpos, WRITE_LOCK))
2520     return(ERROR(ERRDOS,ERRlock));
2521
2522   /* The special X/Open SMB protocol handling of
2523      zero length writes is *NOT* done for
2524      this call */
2525   if(numtowrite == 0)
2526     nwritten = 0;
2527   else
2528     nwritten = write_file(fsp,data,startpos,numtowrite);
2529   
2530   if (lp_syncalways(SNUM(conn)))
2531       conn->vfs_ops.fsync(fsp->fd_ptr->fd);
2532
2533   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2534     return(UNIXERROR(ERRDOS,ERRnoaccess));
2535
2536   if(!do_unlock(fsp, conn, numtowrite, startpos, &eclass, &ecode))
2537     return(ERROR(eclass,ecode));
2538
2539   outsize = set_message(outbuf,1,0,True);
2540   
2541   SSVAL(outbuf,smb_vwv0,nwritten);
2542   
2543   DEBUG( 3, ( "writeunlock fnum=%d num=%d wrote=%d\n",
2544               fsp->fnum, (int)numtowrite, (int)nwritten ) );
2545
2546   return(outsize);
2547 }
2548
2549 /****************************************************************************
2550   reply to a write
2551 ****************************************************************************/
2552 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
2553 {
2554   size_t numtowrite;
2555   ssize_t nwritten = -1;
2556   SMB_OFF_T startpos;
2557   char *data;
2558   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2559   int outsize = 0;
2560
2561   /* If it's an IPC, pass off the pipe handler. */
2562   if (IS_IPC(conn))
2563     return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
2564
2565   CHECK_FSP(fsp,conn);
2566   CHECK_WRITE(fsp);
2567   CHECK_ERROR(fsp);
2568
2569   numtowrite = SVAL(inbuf,smb_vwv1);
2570   startpos = IVAL(inbuf,smb_vwv2);
2571   data = smb_buf(inbuf) + 3;
2572   
2573   if (is_locked(fsp,conn,numtowrite,startpos, WRITE_LOCK))
2574     return(ERROR(ERRDOS,ERRlock));
2575
2576   /* X/Open SMB protocol says that if smb_vwv1 is
2577      zero then the file size should be extended or
2578      truncated to the size given in smb_vwv[2-3] */
2579   if(numtowrite == 0) {
2580       if((nwritten = set_filelen(fsp->fd_ptr->fd, (SMB_OFF_T)startpos)) >= 0) /* tpot vfs */
2581       set_filelen_write_cache(fsp, startpos); 
2582   } else
2583     nwritten = write_file(fsp,data,startpos,numtowrite);
2584   
2585   if (lp_syncalways(SNUM(conn)))
2586     conn->vfs_ops.fsync(fsp->fd_ptr->fd);
2587
2588   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2589     return(UNIXERROR(ERRDOS,ERRnoaccess));
2590
2591   outsize = set_message(outbuf,1,0,True);
2592   
2593   SSVAL(outbuf,smb_vwv0,nwritten);
2594
2595   if (nwritten < (ssize_t)numtowrite) {
2596     CVAL(outbuf,smb_rcls) = ERRHRD;
2597     SSVAL(outbuf,smb_err,ERRdiskfull);      
2598   }
2599   
2600   DEBUG(3,("write fnum=%d num=%d wrote=%d\n",
2601            fsp->fnum, (int)numtowrite, (int)nwritten));
2602
2603   return(outsize);
2604 }
2605
2606
2607 /****************************************************************************
2608   reply to a write and X
2609 ****************************************************************************/
2610 int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2611 {
2612   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2613   SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
2614   size_t numtowrite = SVAL(inbuf,smb_vwv10);
2615   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2616   ssize_t nwritten = -1;
2617   int smb_doff = SVAL(inbuf,smb_vwv11);
2618   char *data;
2619
2620   /* If it's an IPC, pass off the pipe handler. */
2621   if (IS_IPC(conn))
2622     return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
2623
2624   CHECK_FSP(fsp,conn);
2625   CHECK_WRITE(fsp);
2626   CHECK_ERROR(fsp);
2627
2628   data = smb_base(inbuf) + smb_doff;
2629
2630   if(CVAL(inbuf,smb_wct) == 14) {
2631 #ifdef LARGE_SMB_OFF_T
2632     /*
2633      * This is a large offset (64 bit) write.
2634      */
2635     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
2636
2637 #else /* !LARGE_SMB_OFF_T */
2638
2639     /*
2640      * Ensure we haven't been sent a >32 bit offset.
2641      */
2642
2643     if(IVAL(inbuf,smb_vwv12) != 0) {
2644       DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
2645 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
2646       return(ERROR(ERRDOS,ERRbadaccess));
2647     }
2648
2649 #endif /* LARGE_SMB_OFF_T */
2650   }
2651
2652   if (is_locked(fsp,conn,numtowrite,startpos, WRITE_LOCK))
2653     return(ERROR(ERRDOS,ERRlock));
2654
2655   /* X/Open SMB protocol says that, unlike SMBwrite
2656      if the length is zero then NO truncation is
2657      done, just a write of zero. To truncate a file,
2658      use SMBwrite. */
2659   if(numtowrite == 0)
2660     nwritten = 0;
2661   else
2662     nwritten = write_file(fsp,data,startpos,numtowrite);
2663   
2664   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2665     return(UNIXERROR(ERRDOS,ERRnoaccess));
2666
2667   set_message(outbuf,6,0,True);
2668   
2669   SSVAL(outbuf,smb_vwv2,nwritten);
2670   
2671   if (nwritten < (ssize_t)numtowrite) {
2672     CVAL(outbuf,smb_rcls) = ERRHRD;
2673     SSVAL(outbuf,smb_err,ERRdiskfull);      
2674   }
2675
2676   DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
2677            fsp->fnum, (int)numtowrite, (int)nwritten));
2678
2679   if (lp_syncalways(SNUM(conn)) || write_through)
2680     conn->vfs_ops.fsync(fsp->fd_ptr->fd);
2681
2682   return chain_reply(inbuf,outbuf,length,bufsize);
2683 }
2684
2685
2686 /****************************************************************************
2687   reply to a lseek
2688 ****************************************************************************/
2689
2690 int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2691 {
2692   SMB_OFF_T startpos;
2693   SMB_OFF_T res= -1;
2694   int mode,umode;
2695   int outsize = 0;
2696   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2697
2698   CHECK_FSP(fsp,conn);
2699   CHECK_ERROR(fsp);
2700
2701   flush_write_cache(fsp, SEEK_FLUSH);
2702
2703   mode = SVAL(inbuf,smb_vwv1) & 3;
2704   startpos = IVALS(inbuf,smb_vwv2);
2705
2706   switch (mode) {
2707     case 0: umode = SEEK_SET; break;
2708     case 1: umode = SEEK_CUR; break;
2709     case 2: umode = SEEK_END; break;
2710     default:
2711       umode = SEEK_SET; break;
2712   }
2713
2714   if((res = conn->vfs_ops.lseek(fsp->fd_ptr->fd,startpos,umode)) == -1) {
2715     /*
2716      * Check for the special case where a seek before the start
2717      * of the file sets the offset to zero. Added in the CIFS spec,
2718      * section 4.2.7.
2719      */
2720
2721     if(errno == EINVAL) {
2722       SMB_OFF_T current_pos = startpos;
2723
2724       if(umode == SEEK_CUR) {
2725
2726         if((current_pos = conn->vfs_ops.lseek(fsp->fd_ptr->fd,0,SEEK_CUR)) == -1)
2727           return(UNIXERROR(ERRDOS,ERRnoaccess));
2728
2729         current_pos += startpos;
2730
2731       } else if (umode == SEEK_END) {
2732
2733         SMB_STRUCT_STAT sbuf;
2734
2735         if(conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf) == -1)
2736           return(UNIXERROR(ERRDOS,ERRnoaccess));
2737
2738         current_pos += sbuf.st_size;
2739       }
2740  
2741       if(current_pos < 0)
2742         res = conn->vfs_ops.lseek(fsp->fd_ptr->fd,0,SEEK_SET);
2743     }
2744
2745     if(res == -1)
2746       return(UNIXERROR(ERRDOS,ERRnoaccess));
2747   }
2748
2749   fsp->pos = res;
2750   
2751   outsize = set_message(outbuf,2,0,True);
2752   SIVAL(outbuf,smb_vwv0,res);
2753   
2754   DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
2755            fsp->fnum, (double)startpos, (double)res, mode));
2756
2757   return(outsize);
2758 }
2759
2760 /****************************************************************************
2761   reply to a flush
2762 ****************************************************************************/
2763
2764 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2765 {
2766   int outsize = set_message(outbuf,0,0,True);
2767   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2768
2769   if (fsp) {
2770           CHECK_FSP(fsp,conn);
2771           CHECK_ERROR(fsp);
2772   }
2773
2774   if (!fsp) {
2775           file_sync_all(conn);
2776   } else {
2777           conn->vfs_ops.fsync(fsp->fd_ptr->fd);
2778   }
2779
2780   DEBUG(3,("flush\n"));
2781   return(outsize);
2782 }
2783
2784
2785 /****************************************************************************
2786   reply to a exit
2787 ****************************************************************************/
2788 int reply_exit(connection_struct *conn, 
2789                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2790 {
2791         int outsize = set_message(outbuf,0,0,True);
2792         DEBUG(3,("exit\n"));
2793
2794         return(outsize);
2795 }
2796
2797
2798 /****************************************************************************
2799  Reply to a close - has to deal with closing a directory opened by NT SMB's.
2800 ****************************************************************************/
2801 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
2802                 int dum_buffsize)
2803 {
2804         int outsize = 0;
2805         time_t mtime;
2806         int32 eclass = 0, err = 0;
2807         files_struct *fsp = NULL;
2808
2809         outsize = set_message(outbuf,0,0,True);
2810
2811         /* If it's an IPC, pass off to the pipe handler. */
2812         if (IS_IPC(conn))
2813                 return reply_pipe_close(conn, inbuf,outbuf);
2814
2815         fsp = file_fsp(inbuf,smb_vwv0);
2816
2817         /*
2818          * We can only use CHECK_FSP if we know it's not a directory.
2819          */
2820
2821         if(!fsp || !fsp->open || (fsp->conn != conn))
2822                 return(ERROR(ERRDOS,ERRbadfid));
2823
2824         if(HAS_CACHED_ERROR(fsp)) {
2825                 eclass = fsp->wbmpx_ptr->wr_errclass;
2826                 err = fsp->wbmpx_ptr->wr_error;
2827         }
2828
2829         if(fsp->is_directory || fsp->stat_open) {
2830                 /*
2831                  * Special case - close NT SMB directory or stat file
2832                  * handle.
2833                  */
2834                 DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
2835                 close_file(fsp,True);
2836         } else {
2837                 /*
2838                  * Close ordinary file.
2839                  */
2840                 int close_err;
2841
2842                 /*
2843                  * If there was a modify time outstanding,
2844                  * try and set it here.
2845                  */
2846                 if(fsp->pending_modtime)
2847                         set_filetime(conn, fsp->fsp_name, fsp->pending_modtime);
2848
2849                 /*
2850                  * Now take care of any time sent in the close.
2851                  */
2852                 mtime = make_unix_date3(inbuf+smb_vwv1);
2853                 
2854                 /* try and set the date */
2855                 set_filetime(conn, fsp->fsp_name,mtime);
2856
2857                 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
2858                          fsp->fd_ptr ? fsp->fd_ptr->fd : -1, fsp->fnum,
2859                          conn->num_files_open));
2860  
2861                 /*
2862                  * close_file() returns the unix errno if an error
2863                  * was detected on close - normally this is due to
2864                  * a disk full error. If not then it was probably an I/O error.
2865                  */
2866  
2867                 if((close_err = close_file(fsp,True)) != 0) {
2868                         errno = close_err;
2869                         return (UNIXERROR(ERRHRD,ERRgeneral));
2870                 }
2871         }  
2872
2873         /* We have a cached error */
2874         if(eclass || err)
2875                 return(ERROR(eclass,err));
2876
2877         return(outsize);
2878 }
2879
2880
2881 /****************************************************************************
2882   reply to a writeclose (Core+ protocol)
2883 ****************************************************************************/
2884
2885 int reply_writeclose(connection_struct *conn,
2886                      char *inbuf,char *outbuf, int size, int dum_buffsize)
2887 {
2888         size_t numtowrite;
2889         ssize_t nwritten = -1;
2890         int outsize = 0;
2891         int close_err = 0;
2892         SMB_OFF_T startpos;
2893         char *data;
2894         time_t mtime;
2895         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2896
2897         CHECK_FSP(fsp,conn);
2898         CHECK_WRITE(fsp);
2899         CHECK_ERROR(fsp);
2900
2901         numtowrite = SVAL(inbuf,smb_vwv1);
2902         startpos = IVAL(inbuf,smb_vwv2);
2903         mtime = make_unix_date3(inbuf+smb_vwv4);
2904         data = smb_buf(inbuf) + 1;
2905   
2906         if (is_locked(fsp,conn,numtowrite,startpos, WRITE_LOCK))
2907                 return(ERROR(ERRDOS,ERRlock));
2908           
2909         nwritten = write_file(fsp,data,startpos,numtowrite);
2910
2911         set_filetime(conn, fsp->fsp_name,mtime);
2912   
2913         close_err = close_file(fsp,True);
2914
2915         DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
2916                  fsp->fnum, (int)numtowrite, (int)nwritten,
2917                  conn->num_files_open));
2918   
2919         if (nwritten <= 0)
2920                 return(UNIXERROR(ERRDOS,ERRnoaccess));
2921  
2922         if(close_err != 0) {
2923                 errno = close_err;
2924                 return(UNIXERROR(ERRHRD,ERRgeneral));
2925         }
2926  
2927         outsize = set_message(outbuf,1,0,True);
2928   
2929         SSVAL(outbuf,smb_vwv0,nwritten);
2930         return(outsize);
2931 }
2932
2933
2934 /****************************************************************************
2935   reply to a lock
2936 ****************************************************************************/
2937 int reply_lock(connection_struct *conn,
2938                char *inbuf,char *outbuf, int length, int dum_buffsize)
2939 {
2940         int outsize = set_message(outbuf,0,0,True);
2941         SMB_OFF_T count,offset;
2942         int eclass;
2943         uint32 ecode;
2944         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2945
2946         CHECK_FSP(fsp,conn);
2947         CHECK_ERROR(fsp);
2948
2949         count = IVAL(inbuf,smb_vwv1);
2950         offset = IVAL(inbuf,smb_vwv3);
2951
2952         DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2953                  fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count));
2954
2955         if (!do_lock(fsp, conn, count, offset, WRITE_LOCK, &eclass, &ecode)) {
2956       if((ecode == ERRlock) && lp_blocking_locks(SNUM(conn))) {
2957         /*
2958          * A blocking lock was requested. Package up
2959          * this smb into a queued request and push it
2960          * onto the blocking lock queue.
2961          */
2962         if(push_blocking_lock_request(inbuf, length, -1, 0))
2963           return -1;
2964       }
2965       return (ERROR(eclass,ecode));
2966     }
2967
2968         return(outsize);
2969 }
2970
2971
2972 /****************************************************************************
2973   reply to a unlock
2974 ****************************************************************************/
2975 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2976 {
2977   int outsize = set_message(outbuf,0,0,True);
2978   SMB_OFF_T count,offset;
2979   int eclass;
2980   uint32 ecode;
2981   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2982
2983   CHECK_FSP(fsp,conn);
2984   CHECK_ERROR(fsp);
2985
2986   count = IVAL(inbuf,smb_vwv1);
2987   offset = IVAL(inbuf,smb_vwv3);
2988
2989   if(!do_unlock(fsp, conn, count, offset, &eclass, &ecode))
2990     return (ERROR(eclass,ecode));
2991
2992   DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2993         fsp->fd_ptr->fd, fsp->fnum, (double)offset, (double)count ) );
2994   
2995   return(outsize);
2996 }
2997
2998
2999 /****************************************************************************
3000   reply to a tdis
3001 ****************************************************************************/
3002 int reply_tdis(connection_struct *conn, 
3003                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3004 {
3005         int outsize = set_message(outbuf,0,0,True);
3006         uint16 vuid;
3007
3008         vuid = SVAL(inbuf,smb_uid);
3009
3010         if (!conn) {
3011                 DEBUG(4,("Invalid connection in tdis\n"));
3012                 return(ERROR(ERRSRV,ERRinvnid));
3013         }
3014
3015         conn->used = False;
3016
3017         close_cnum(conn,vuid);
3018   
3019         return outsize;
3020 }
3021
3022
3023
3024 /****************************************************************************
3025   reply to a echo
3026 ****************************************************************************/
3027 int reply_echo(connection_struct *conn,
3028                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3029 {
3030         int smb_reverb = SVAL(inbuf,smb_vwv0);
3031         int seq_num;
3032         int data_len = smb_buflen(inbuf);
3033         int outsize = set_message(outbuf,1,data_len,True);
3034         
3035         /* copy any incoming data back out */
3036         if (data_len > 0)
3037                 memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
3038
3039         if (smb_reverb > 100) {
3040                 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
3041                 smb_reverb = 100;
3042         }
3043
3044         for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
3045                 SSVAL(outbuf,smb_vwv0,seq_num);
3046
3047                 smb_setlen(outbuf,outsize - 4);
3048
3049                 send_smb(Client,outbuf);
3050         }
3051
3052         DEBUG(3,("echo %d times\n", smb_reverb));
3053
3054         smb_echo_count++;
3055
3056         return -1;
3057 }
3058
3059
3060 /****************************************************************************
3061   reply to a printopen
3062 ****************************************************************************/
3063 int reply_printopen(connection_struct *conn, 
3064                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3065 {
3066         pstring fname;
3067         pstring fname2;
3068         int outsize = 0;
3069         files_struct *fsp;
3070         
3071         *fname = *fname2 = 0;
3072         
3073         if (!CAN_PRINT(conn))
3074                 return(ERROR(ERRDOS,ERRnoaccess));
3075
3076         {
3077                 pstring s;
3078                 char *p;
3079                 pstrcpy(s,smb_buf(inbuf)+1);
3080                 p = s;
3081                 while (*p) {
3082                         if (!(isalnum((int)*p) || strchr("._-",*p)))
3083                                 *p = 'X';
3084                         p++;
3085                 }
3086
3087                 if (strlen(s) > 10) s[10] = 0;
3088
3089                 slprintf(fname,sizeof(fname)-1, "%s.XXXXXX",s);  
3090         }
3091
3092         fsp = file_new();
3093         if (!fsp)
3094                 return(ERROR(ERRSRV,ERRnofids));
3095         
3096         pstrcpy(fname2,(char *)smbd_mktemp(fname));
3097
3098         if (!check_name(fname2,conn)) {
3099                 file_free(fsp);
3100                 return(ERROR(ERRDOS,ERRnoaccess));
3101         }
3102
3103         /* Open for exclusive use, write only. */
3104         open_file_shared(fsp,conn,fname2, SET_DENY_MODE(DENY_ALL)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
3105                      (FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_FAIL), unix_mode(conn,0,fname2), 0, NULL, NULL);
3106
3107         if (!fsp->open) {
3108                 file_free(fsp);
3109                 return(UNIXERROR(ERRDOS,ERRnoaccess));
3110         }
3111
3112         /* force it to be a print file */
3113         fsp->print_file = True;
3114   
3115         outsize = set_message(outbuf,1,0,True);
3116         SSVAL(outbuf,smb_vwv0,fsp->fnum);
3117   
3118         DEBUG(3,("openprint %s fd=%d fnum=%d\n",
3119                    fname2, fsp->fd_ptr->fd, fsp->fnum));
3120
3121         return(outsize);
3122 }
3123
3124
3125 /****************************************************************************
3126   reply to a printclose
3127 ****************************************************************************/
3128 int reply_printclose(connection_struct *conn,
3129                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3130 {
3131         int outsize = set_message(outbuf,0,0,True);
3132         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3133         int close_err = 0;
3134
3135         CHECK_FSP(fsp,conn);
3136         CHECK_ERROR(fsp);
3137
3138         if (!CAN_PRINT(conn))
3139                 return(ERROR(ERRDOS,ERRnoaccess));
3140   
3141         DEBUG(3,("printclose fd=%d fnum=%d\n",
3142                  fsp->fd_ptr->fd,fsp->fnum));
3143   
3144         close_err = close_file(fsp,True);
3145
3146         if(close_err != 0) {
3147                 errno = close_err;
3148                 return(UNIXERROR(ERRHRD,ERRgeneral));
3149         }
3150
3151         return(outsize);
3152 }
3153
3154
3155 /****************************************************************************
3156   reply to a printqueue
3157 ****************************************************************************/
3158 int reply_printqueue(connection_struct *conn,
3159                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3160 {
3161         int outsize = set_message(outbuf,2,3,True);
3162         int max_count = SVAL(inbuf,smb_vwv0);
3163         int start_index = SVAL(inbuf,smb_vwv1);
3164
3165         /* we used to allow the client to get the cnum wrong, but that
3166            is really quite gross and only worked when there was only
3167            one printer - I think we should now only accept it if they
3168            get it right (tridge) */
3169         if (!CAN_PRINT(conn))
3170                 return(ERROR(ERRDOS,ERRnoaccess));
3171
3172         SSVAL(outbuf,smb_vwv0,0);
3173         SSVAL(outbuf,smb_vwv1,0);
3174         CVAL(smb_buf(outbuf),0) = 1;
3175         SSVAL(smb_buf(outbuf),1,0);
3176   
3177         DEBUG(3,("printqueue start_index=%d max_count=%d\n",
3178                  start_index, max_count));
3179
3180         {
3181                 print_queue_struct *queue = NULL;
3182                 char *p = smb_buf(outbuf) + 3;
3183                 int count = get_printqueue(SNUM(conn), conn,&queue,NULL);
3184                 int num_to_get = ABS(max_count);
3185                 int first = (max_count>0?start_index:start_index+max_count+1);
3186                 int i;
3187
3188                 if (first >= count)
3189                         num_to_get = 0;
3190                 else
3191                         num_to_get = MIN(num_to_get,count-first);
3192     
3193
3194                 for (i=first;i<first+num_to_get;i++) {
3195                         put_dos_date2(p,0,queue[i].time);
3196                         CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
3197                         SSVAL(p,5,printjob_encode(SNUM(conn), 
3198                                                   queue[i].job));
3199                         SIVAL(p,7,queue[i].size);
3200                         CVAL(p,11) = 0;
3201                         StrnCpy(p+12,queue[i].user,16);
3202                         p += 28;
3203                 }
3204
3205                 if (count > 0) {
3206                         outsize = set_message(outbuf,2,28*count+3,False); 
3207                         SSVAL(outbuf,smb_vwv0,count);
3208                         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
3209                         CVAL(smb_buf(outbuf),0) = 1;
3210                         SSVAL(smb_buf(outbuf),1,28*count);
3211                 }
3212
3213                 if (queue) free(queue);
3214           
3215                 DEBUG(3,("%d entries returned in queue\n",count));
3216         }
3217   
3218         return(outsize);
3219 }
3220
3221
3222 /****************************************************************************
3223   reply to a printwrite
3224 ****************************************************************************/
3225 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3226 {
3227   int numtowrite;
3228   int outsize = set_message(outbuf,0,0,True);
3229   char *data;
3230   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3231   
3232   if (!CAN_PRINT(conn))
3233     return(ERROR(ERRDOS,ERRnoaccess));
3234
3235   CHECK_FSP(fsp,conn);
3236   CHECK_WRITE(fsp);
3237   CHECK_ERROR(fsp);
3238
3239   numtowrite = SVAL(smb_buf(inbuf),1);
3240   data = smb_buf(inbuf) + 3;
3241   
3242   if (write_file(fsp,data,-1,numtowrite) != numtowrite)
3243     return(UNIXERROR(ERRDOS,ERRnoaccess));
3244   
3245   DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
3246   
3247   return(outsize);
3248 }
3249
3250
3251 /****************************************************************************
3252   reply to a mkdir
3253 ****************************************************************************/
3254 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3255 {
3256   pstring directory;
3257   int outsize,ret= -1;
3258   BOOL bad_path = False;
3259  
3260   pstrcpy(directory,smb_buf(inbuf) + 1);
3261   unix_convert(directory,conn,0,&bad_path,NULL);
3262   
3263   if (check_name(directory, conn))
3264     ret = conn->vfs_ops.mkdir(dos_to_unix(directory,False),
3265                               unix_mode(conn,aDIR,directory));
3266   
3267   if (ret < 0)
3268   {
3269     if((errno == ENOENT) && bad_path)
3270     {
3271       unix_ERR_class = ERRDOS;
3272       unix_ERR_code = ERRbadpath;
3273     }
3274     return(UNIXERROR(ERRDOS,ERRnoaccess));
3275   }
3276
3277   outsize = set_message(outbuf,0,0,True);
3278
3279   DEBUG( 3, ( "mkdir %s ret=%d\n", directory, ret ) );
3280
3281   return(outsize);
3282 }
3283
3284 /****************************************************************************
3285 Static function used by reply_rmdir to delete an entire directory
3286 tree recursively.
3287 ****************************************************************************/
3288
3289 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
3290 {
3291   char *dname = NULL;
3292   BOOL ret = False;
3293   void *dirptr = OpenDir(NULL, directory, False);
3294
3295   if(dirptr == NULL)
3296     return True;
3297
3298   while((dname = ReadDirName(dirptr)))
3299   {
3300     pstring fullname;
3301     SMB_STRUCT_STAT st;
3302
3303     if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3304       continue;
3305
3306     /* Construct the full name. */
3307     if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
3308     {
3309       errno = ENOMEM;
3310       ret = True;
3311       break;
3312     }
3313     pstrcpy(fullname, directory);
3314     pstrcat(fullname, "/");
3315     pstrcat(fullname, dname);
3316
3317     if(conn->vfs_ops.lstat(dos_to_unix(fullname,False), &st) != 0)
3318     {
3319       ret = True;
3320       break;
3321     }
3322
3323     if(st.st_mode & S_IFDIR)
3324     {
3325       if(recursive_rmdir(conn, fullname)!=0)
3326       {
3327         ret = True;
3328         break;
3329       }
3330       if(conn->vfs_ops.rmdir(dos_to_unix(fullname,False)) != 0)
3331       {
3332         ret = True;
3333         break;
3334       }
3335     }
3336     else if(conn->vfs_ops.unlink(dos_to_unix(fullname,False)) != 0)
3337     {
3338       ret = True;
3339       break;
3340     }
3341   }
3342   CloseDir(dirptr);
3343   return ret;
3344 }
3345
3346 /****************************************************************************
3347  The internals of the rmdir code - called elsewhere.
3348 ****************************************************************************/
3349
3350 BOOL rmdir_internals(connection_struct *conn, char *directory)
3351 {
3352   BOOL ok;
3353
3354   ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
3355   if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn)))
3356   {
3357     /* 
3358      * Check to see if the only thing in this directory are
3359      * vetoed files/directories. If so then delete them and
3360      * retry. If we fail to delete any of them (and we *don't*
3361      * do a recursive delete) then fail the rmdir.
3362      */
3363     BOOL all_veto_files = True;
3364     char *dname;
3365     void *dirptr = OpenDir(conn, directory, False);
3366
3367     if(dirptr != NULL)
3368     {
3369       int dirpos = TellDir(dirptr);
3370       while ((dname = ReadDirName(dirptr)))
3371       {
3372         if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3373           continue;
3374         if(!IS_VETO_PATH(conn, dname))
3375         {
3376           all_veto_files = False;
3377           break;
3378         }
3379       }
3380       if(all_veto_files)
3381       {
3382         SeekDir(dirptr,dirpos);
3383         while ((dname = ReadDirName(dirptr)))
3384         {
3385           pstring fullname;
3386           SMB_STRUCT_STAT st;
3387
3388           if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3389             continue;
3390
3391           /* Construct the full name. */
3392           if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
3393           {
3394             errno = ENOMEM;
3395             break;
3396           }
3397           pstrcpy(fullname, directory);
3398           pstrcat(fullname, "/");
3399           pstrcat(fullname, dname);
3400                      
3401           if(conn->vfs_ops.lstat(dos_to_unix(fullname, False), &st) != 0)
3402             break;
3403           if(st.st_mode & S_IFDIR)
3404           {
3405             if(lp_recursive_veto_delete(SNUM(conn)))
3406             {
3407               if(recursive_rmdir(conn, fullname) != 0)
3408                 break;
3409             }
3410             if(conn->vfs_ops.rmdir(dos_to_unix(fullname, False)) != 0)
3411               break;
3412           }
3413           else if(conn->vfs_ops.unlink(dos_to_unix(fullname, False)) != 0)
3414             break;
3415         }
3416         CloseDir(dirptr);
3417         /* Retry the rmdir */
3418         ok = (conn->vfs_ops.rmdir(dos_to_unix(directory, False)) == 0);
3419       }
3420       else
3421         CloseDir(dirptr);
3422     }
3423     else
3424       errno = ENOTEMPTY;
3425   }
3426           
3427   if (!ok)
3428     DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n",
3429           directory,strerror(errno)));
3430
3431   return ok;
3432 }
3433
3434 /****************************************************************************
3435  Reply to a rmdir.
3436 ****************************************************************************/
3437
3438 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3439 {
3440   pstring directory;
3441   int outsize = 0;
3442   BOOL ok = False;
3443   BOOL bad_path = False;
3444
3445   pstrcpy(directory,smb_buf(inbuf) + 1);
3446
3447   RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
3448
3449   unix_convert(directory,conn, NULL,&bad_path,NULL);
3450   
3451   if (check_name(directory,conn))
3452   {
3453     dptr_closepath(directory,SVAL(inbuf,smb_pid));
3454     ok = rmdir_internals(conn, directory);
3455   }
3456   
3457   if (!ok)
3458   {
3459     if((errno == ENOENT) && bad_path)
3460     {
3461       unix_ERR_class = ERRDOS;
3462       unix_ERR_code = ERRbadpath;
3463     }
3464     return(UNIXERROR(ERRDOS,ERRbadpath));
3465   }
3466  
3467   outsize = set_message(outbuf,0,0,True);
3468   
3469   DEBUG( 3, ( "rmdir %s\n", directory ) );
3470   
3471   return(outsize);
3472 }
3473
3474
3475 /*******************************************************************
3476 resolve wildcards in a filename rename
3477 ********************************************************************/
3478 static BOOL resolve_wildcards(char *name1,char *name2)
3479 {
3480   fstring root1,root2;
3481   fstring ext1,ext2;
3482   char *p,*p2;
3483
3484   name1 = strrchr(name1,'/');
3485   name2 = strrchr(name2,'/');
3486
3487   if (!name1 || !name2) return(False);
3488   
3489   fstrcpy(root1,name1);
3490   fstrcpy(root2,name2);
3491   p = strrchr(root1,'.');
3492   if (p) {
3493     *p = 0;
3494     fstrcpy(ext1,p+1);
3495   } else {
3496     fstrcpy(ext1,"");    
3497   }
3498   p = strrchr(root2,'.');
3499   if (p) {
3500     *p = 0;
3501     fstrcpy(ext2,p+1);
3502   } else {
3503     fstrcpy(ext2,"");    
3504   }
3505
3506   p = root1;
3507   p2 = root2;
3508   while (*p2) {
3509     if (*p2 == '?') {
3510       *p2 = *p;
3511       p2++;
3512     } else {
3513       p2++;
3514     }
3515     if (*p) p++;
3516   }
3517
3518   p = ext1;
3519   p2 = ext2;
3520   while (*p2) {
3521     if (*p2 == '?') {
3522       *p2 = *p;
3523       p2++;
3524     } else {
3525       p2++;
3526     }
3527     if (*p) p++;
3528   }
3529
3530   pstrcpy(name2,root2);
3531   if (ext2[0]) {
3532     pstrcat(name2,".");
3533     pstrcat(name2,ext2);
3534   }
3535
3536   return(True);
3537 }
3538
3539 /*******************************************************************
3540 check if a user is allowed to rename a file
3541 ********************************************************************/
3542 static BOOL can_rename(char *fname,connection_struct *conn)
3543 {
3544   SMB_STRUCT_STAT sbuf;
3545
3546   if (!CAN_WRITE(conn)) return(False);
3547
3548   if (conn->vfs_ops.lstat(dos_to_unix(fname,False),&sbuf) != 0) return(False);
3549   if (!check_file_sharing(conn,fname,True)) return(False);
3550
3551   return(True);
3552 }
3553
3554 /****************************************************************************
3555  The guts of the rename command, split out so it may be called by the NT SMB
3556  code. 
3557 ****************************************************************************/
3558 int rename_internals(connection_struct *conn, 
3559                      char *inbuf, char *outbuf, char *name, 
3560                      char *newname, BOOL replace_if_exists)
3561 {
3562         pstring directory;
3563         pstring mask;
3564         pstring newname_last_component;
3565         char *p;
3566         BOOL has_wild;
3567         BOOL bad_path1 = False;
3568         BOOL bad_path2 = False;
3569         int count=0;
3570         int error = ERRnoaccess;
3571         BOOL exists=False;
3572         BOOL rc = True;
3573         pstring zdirectory;
3574
3575         *directory = *mask = 0;
3576
3577         rc = unix_convert(name,conn,0,&bad_path1,NULL);
3578         unix_convert(newname,conn,newname_last_component,&bad_path2,NULL);
3579
3580         /*
3581          * Split the old name into directory and last component
3582          * strings. Note that unix_convert may have stripped off a 
3583          * leading ./ from both name and newname if the rename is 
3584          * at the root of the share. We need to make sure either both
3585          * name and newname contain a / character or neither of them do
3586          * as this is checked in resolve_wildcards().
3587          */
3588         
3589         p = strrchr(name,'/');
3590         if (!p) {
3591                 pstrcpy(directory,".");
3592                 pstrcpy(mask,name);
3593         } else {
3594                 *p = 0;
3595                 pstrcpy(directory,name);
3596                 pstrcpy(mask,p+1);
3597                 *p = '/'; /* Replace needed for exceptional test below. */
3598         }
3599
3600         /*
3601          * We should only check the mangled cache
3602          * here if unix_convert failed. This means
3603          * that the path in 'mask' doesn't exist
3604          * on the file system and so we need to look
3605          * for a possible mangle. This patch from
3606          * Tine Smukavec <valentin.smukavec@hermes.si>.
3607          */
3608
3609         if (!rc && is_mangled(mask))
3610                 check_mangled_cache( mask );
3611
3612         has_wild = strchr(mask,'*') || strchr(mask,'?');
3613
3614         if (!has_wild) {
3615                 /*
3616                  * No wildcards - just process the one file.
3617                  */
3618                 BOOL is_short_name = is_8_3(name, True);
3619
3620                 /* Add a terminating '/' to the directory name. */
3621                 pstrcat(directory,"/");
3622                 pstrcat(directory,mask);
3623                 
3624                 /* Ensure newname contains a '/' also */
3625                 if(strrchr(newname,'/') == 0) {
3626                         pstring tmpstr;
3627                         
3628                         pstrcpy(tmpstr, "./");
3629                         pstrcat(tmpstr, newname);
3630                         pstrcpy(newname, tmpstr);
3631                 }
3632                 
3633                 DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
3634                          case_sensitive, case_preserve, short_case_preserve, directory, 
3635                          newname, newname_last_component, is_short_name));
3636
3637                 /*
3638                  * Check for special case with case preserving and not
3639                  * case sensitive, if directory and newname are identical,
3640                  * and the old last component differs from the original
3641                  * last component only by case, then we should allow
3642                  * the rename (user is trying to change the case of the
3643                  * filename).
3644                  */
3645                 if((case_sensitive == False) && 
3646                    (((case_preserve == True) && 
3647                      (is_short_name == False)) || 
3648                     ((short_case_preserve == True) && 
3649                      (is_short_name == True))) &&
3650                    strcsequal(directory, newname)) {
3651                         pstring newname_modified_last_component;
3652
3653                         /*
3654                          * Get the last component of the modified name.
3655                          * Note that we guarantee that newname contains a '/'
3656                          * character above.
3657                          */
3658                         p = strrchr(newname,'/');
3659                         pstrcpy(newname_modified_last_component,p+1);
3660                         
3661                         if(strcsequal(newname_modified_last_component, 
3662                                       newname_last_component) == False) {
3663                                 /*
3664                                  * Replace the modified last component with
3665                                  * the original.
3666                                  */
3667                                 pstrcpy(p+1, newname_last_component);
3668                         }
3669                 }
3670                 
3671                 pstrcpy(zdirectory, dos_to_unix(directory, False));
3672                 if(replace_if_exists) {
3673                         /*
3674                          * NT SMB specific flag - rename can overwrite
3675                          * file with the same name so don't check for
3676                          * vfs_file_exist().
3677                          */
3678                         if(resolve_wildcards(directory,newname) &&
3679                            can_rename(directory,conn) &&
3680                            !conn->vfs_ops.rename(zdirectory,
3681                                                  dos_to_unix(newname,False)))
3682                                 count++;
3683                 } else {
3684                         if (resolve_wildcards(directory,newname) && 
3685                             can_rename(directory,conn) && 
3686                             !vfs_file_exist(conn,newname,NULL) &&
3687                             !conn->vfs_ops.rename(zdirectory,
3688                                                   dos_to_unix(newname,False)))
3689                                 count++;
3690                 }
3691
3692                 DEBUG(3,("rename_internals: %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
3693                          directory,newname));
3694                 
3695                 if (!count) exists = vfs_file_exist(conn,directory,NULL);
3696                 if (!count && exists && vfs_file_exist(conn,newname,NULL)) {
3697                         exists = True;
3698                         error = ERRrename;
3699                 }
3700         } else {
3701                 /*
3702                  * Wildcards - process each file that matches.
3703                  */
3704                 void *dirptr = NULL;
3705                 char *dname;
3706                 pstring destname;
3707                 
3708                 if (check_name(directory,conn))
3709                         dirptr = OpenDir(conn, directory, True);
3710                 
3711                 if (dirptr) {
3712                         error = ERRbadfile;
3713                         
3714                         if (strequal(mask,"????????.???"))
3715                                 pstrcpy(mask,"*");
3716                         
3717                         while ((dname = ReadDirName(dirptr))) {
3718                                 pstring fname;
3719
3720                                 pstrcpy(fname,dname);
3721                                 
3722                                 if(!mask_match(fname, mask, case_sensitive, False))
3723                                         continue;
3724                                 
3725                                 error = ERRnoaccess;
3726                                 slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
3727                                 if (!can_rename(fname,conn)) {
3728                                         DEBUG(6,("rename %s refused\n", fname));
3729                                         continue;
3730                                 }
3731                                 pstrcpy(destname,newname);
3732                                 
3733                                 if (!resolve_wildcards(fname,destname)) {
3734                                         DEBUG(6,("resolve_wildcards %s %s failed\n", 
3735                                                  fname, destname));
3736                                         continue;
3737                                 }
3738                                 
3739                                 if (!replace_if_exists && 
3740                                     vfs_file_exist(conn,destname, NULL)) {
3741                                         DEBUG(6,("file_exist %s\n", destname));
3742                                         error = 183;
3743                                         continue;
3744                                 }
3745                                 
3746                                 if (!conn->vfs_ops.rename(dos_to_unix(fname,False),
3747                                                           dos_to_unix(destname,False)))
3748                                         count++;
3749                                 DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
3750                         }
3751                         CloseDir(dirptr);
3752                 }
3753         }
3754         
3755         if (count == 0) {
3756                 if (exists)
3757                         return(ERROR(ERRDOS,error));
3758                 else {
3759                         if((errno == ENOENT) && (bad_path1 || bad_path2)) {
3760                                 unix_ERR_class = ERRDOS;
3761                                 unix_ERR_code = ERRbadpath;
3762                         }
3763                         return(UNIXERROR(ERRDOS,error));
3764                 }
3765         }
3766         
3767         return 0;
3768 }
3769
3770 /****************************************************************************
3771  Reply to a mv.
3772 ****************************************************************************/
3773
3774 int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3775 {
3776   int outsize = 0;
3777   pstring name;
3778   pstring newname;
3779
3780   pstrcpy(name,smb_buf(inbuf) + 1);
3781   pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
3782
3783   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
3784   RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
3785
3786   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
3787
3788   outsize = rename_internals(conn, inbuf, outbuf, name, newname, False);
3789   if(outsize == 0) 
3790     outsize = set_message(outbuf,0,0,True);
3791   
3792   return(outsize);
3793 }
3794
3795 /*******************************************************************
3796   copy a file as part of a reply_copy
3797   ******************************************************************/
3798
3799 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
3800                       int count,BOOL target_is_directory, int *err_ret)
3801 {
3802   int Access,action;
3803   SMB_STRUCT_STAT st;
3804   SMB_OFF_T ret=-1;
3805   files_struct *fsp1,*fsp2;
3806   pstring dest;
3807   
3808   *err_ret = 0;
3809
3810   pstrcpy(dest,dest1);
3811   if (target_is_directory) {
3812     char *p = strrchr(src,'/');
3813     if (p) 
3814       p++;
3815     else
3816       p = src;
3817     pstrcat(dest,"/");
3818     pstrcat(dest,p);
3819   }
3820
3821   if (!vfs_file_exist(conn,src,&st))
3822     return(False);
3823
3824   fsp1 = file_new();
3825   if (!fsp1)
3826     return(False);
3827
3828   open_file_shared(fsp1,conn,src,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
3829                    (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
3830
3831   if (!fsp1->open) {
3832           file_free(fsp1);
3833           return(False);
3834   }
3835
3836   if (!target_is_directory && count)
3837     ofun = 1;
3838
3839   fsp2 = file_new();
3840   if (!fsp2) {
3841           close_file(fsp1,False);
3842           return(False);
3843   }
3844   open_file_shared(fsp2,conn,dest,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
3845                    ofun,st.st_mode,0,&Access,&action);
3846
3847   if (!fsp2->open) {
3848     close_file(fsp1,False);
3849     file_free(fsp2);
3850     return(False);
3851   }
3852
3853   if ((ofun&3) == 1) {
3854     if(conn->vfs_ops.lseek(fsp2->fd_ptr->fd,0,SEEK_END) == -1) {
3855       DEBUG(0,("copy_file: error - sys_lseek returned error %s\n",
3856                strerror(errno) ));
3857       /*
3858        * Stop the copy from occurring.
3859        */
3860       ret = -1;
3861       st.st_size = 0;
3862     }
3863   }
3864   
3865   if (st.st_size)
3866     ret = vfs_transfer_file(-1, fsp1, -1, fsp2, st.st_size, NULL, 0, 0);
3867
3868   close_file(fsp1,False);
3869   /*
3870    * As we are opening fsp1 read-only we only expect
3871    * an error on close on fsp2 if we are out of space.
3872    * Thus we don't look at the error return from the
3873    * close of fsp1.
3874    */
3875   *err_ret = close_file(fsp2,False);
3876
3877   return(ret == (SMB_OFF_T)st.st_size);
3878 }
3879
3880
3881
3882 /****************************************************************************
3883   reply to a file copy.
3884   ****************************************************************************/
3885 int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3886 {
3887   int outsize = 0;
3888   pstring name;
3889   pstring directory;
3890   pstring mask,newname;
3891   char *p;
3892   int count=0;
3893   int error = ERRnoaccess;
3894   int err = 0;
3895   BOOL has_wild;
3896   BOOL exists=False;
3897   int tid2 = SVAL(inbuf,smb_vwv0);
3898   int ofun = SVAL(inbuf,smb_vwv1);
3899   int flags = SVAL(inbuf,smb_vwv2);
3900   BOOL target_is_directory=False;
3901   BOOL bad_path1 = False;
3902   BOOL bad_path2 = False;
3903   BOOL rc = True;
3904
3905   *directory = *mask = 0;
3906
3907   pstrcpy(name,smb_buf(inbuf));
3908   pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
3909    
3910   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
3911    
3912   if (tid2 != conn->cnum) {
3913     /* can't currently handle inter share copies XXXX */
3914     DEBUG(3,("Rejecting inter-share copy\n"));
3915     return(ERROR(ERRSRV,ERRinvdevice));
3916   }
3917
3918   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
3919   RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
3920
3921   rc = unix_convert(name,conn,0,&bad_path1,NULL);
3922   unix_convert(newname,conn,0,&bad_path2,NULL);
3923
3924   target_is_directory = vfs_directory_exist(conn,False,NULL);
3925
3926   if ((flags&1) && target_is_directory) {
3927     return(ERROR(ERRDOS,ERRbadfile));
3928   }
3929
3930   if ((flags&2) && !target_is_directory) {
3931     return(ERROR(ERRDOS,ERRbadpath));
3932   }
3933
3934   if ((flags&(1<<5)) && vfs_directory_exist(conn,name,NULL)) {
3935     /* wants a tree copy! XXXX */
3936     DEBUG(3,("Rejecting tree copy\n"));
3937     return(ERROR(ERRSRV,ERRerror));    
3938   }
3939
3940   p = strrchr(name,'/');
3941   if (!p) {
3942     pstrcpy(directory,"./");
3943     pstrcpy(mask,name);
3944   } else {
3945     *p = 0;
3946     pstrcpy(directory,name);
3947     pstrcpy(mask,p+1);
3948   }
3949
3950   /*
3951    * We should only check the mangled cache
3952    * here if unix_convert failed. This means
3953    * that the path in 'mask' doesn't exist
3954    * on the file system and so we need to look
3955    * for a possible mangle. This patch from
3956    * Tine Smukavec <valentin.smukavec@hermes.si>.
3957    */
3958
3959   if (!rc && is_mangled(mask))
3960     check_mangled_cache( mask );
3961
3962   has_wild = strchr(mask,'*') || strchr(mask,'?');
3963
3964   if (!has_wild) {
3965     pstrcat(directory,"/");
3966     pstrcat(directory,mask);
3967     if (resolve_wildcards(directory,newname) && 
3968         copy_file(directory,newname,conn,ofun,
3969                   count,target_is_directory,&err)) count++;
3970     if(!count && err) {
3971                 errno = err;
3972                 return(UNIXERROR(ERRHRD,ERRgeneral));
3973         }
3974     if (!count) exists = vfs_file_exist(conn,directory,NULL);
3975   } else {
3976     void *dirptr = NULL;
3977     char *dname;
3978     pstring destname;
3979
3980     if (check_name(directory,conn))
3981       dirptr = OpenDir(conn, directory, True);
3982
3983     if (dirptr) {
3984         error = ERRbadfile;
3985
3986         if (strequal(mask,"????????.???"))
3987           pstrcpy(mask,"*");
3988
3989         while ((dname = ReadDirName(dirptr))) {
3990             pstring fname;
3991             pstrcpy(fname,dname);
3992             
3993             if(!mask_match(fname, mask, case_sensitive, False))
3994                         continue;
3995
3996             error = ERRnoaccess;
3997             slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
3998             pstrcpy(destname,newname);
3999             if (resolve_wildcards(fname,destname) && 
4000                 copy_file(fname,destname,conn,ofun,
4001                           count,target_is_directory,&err)) count++;
4002             DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
4003           }
4004         CloseDir(dirptr);
4005     }
4006   }
4007   
4008   if (count == 0) {
4009     if(err) {
4010       /* Error on close... */
4011       errno = err;
4012       return(UNIXERROR(ERRHRD,ERRgeneral));
4013     }
4014
4015     if (exists)
4016       return(ERROR(ERRDOS,error));
4017     else
4018     {
4019       if((errno == ENOENT) && (bad_path1 || bad_path2))
4020       {
4021         unix_ERR_class = ERRDOS;
4022         unix_ERR_code = ERRbadpath;
4023       }
4024       return(UNIXERROR(ERRDOS,error));
4025     }
4026   }
4027   
4028   outsize = set_message(outbuf,1,0,True);
4029   SSVAL(outbuf,smb_vwv0,count);
4030
4031   return(outsize);
4032 }
4033
4034 /****************************************************************************
4035   reply to a setdir
4036 ****************************************************************************/
4037 int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4038 {
4039   int snum;
4040   int outsize = 0;
4041   BOOL ok = False;
4042   pstring newdir;
4043   
4044   snum = SNUM(conn);
4045   if (!CAN_SETDIR(snum))
4046     return(ERROR(ERRDOS,ERRnoaccess));
4047   
4048   pstrcpy(newdir,smb_buf(inbuf) + 1);
4049   strlower(newdir);
4050   
4051   if (strlen(newdir) == 0) {
4052           ok = True;
4053   } else {
4054           ok = vfs_directory_exist(conn,newdir,NULL);
4055           if (ok) {
4056                   string_set(&conn->connectpath,newdir);
4057           }
4058   }
4059   
4060   if (!ok)
4061           return(ERROR(ERRDOS,ERRbadpath));
4062   
4063   outsize = set_message(outbuf,0,0,True);
4064   CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
4065   
4066   DEBUG(3,("setdir %s\n", newdir));
4067
4068   return(outsize);
4069 }
4070
4071 /****************************************************************************
4072  Get a lock count, dealing with large count requests.
4073 ****************************************************************************/
4074
4075 SMB_OFF_T get_lock_count( char *data, int data_offset, BOOL large_file_format, BOOL *err)
4076 {
4077   SMB_OFF_T count = 0;
4078
4079   *err = False;
4080
4081   if(!large_file_format) {
4082     count = (SMB_OFF_T)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
4083   } else {
4084
4085 #if defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
4086
4087     count = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
4088             ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
4089
4090 #else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
4091
4092     /*
4093      * NT4.x seems to be broken in that it sends large file
4094      * lockingX calls even if the CAP_LARGE_FILES was *not*
4095      * negotiated. For boxes without large file locks truncate the
4096      * lock count by dropping the top 32 bits.
4097      */
4098
4099     if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
4100       DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
4101             (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
4102             (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
4103       SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
4104     }
4105
4106     if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
4107       /*
4108        * Before we error out, see if we can sensibly map the top bits
4109        * down to the lower bits - or lose the top bits if they are all 1's.
4110        * It seems that NT has this horrible bug where it will send 64 bit
4111        * lock requests even if told not to. JRA.
4112        */
4113
4114       if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) == (uint32)0xFFFFFFFF)
4115         count = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset));
4116       else if (IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) == (uint32)0xFFFFFFFF)
4117         count = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
4118       else {
4119
4120         DEBUG(0,("get_lock_count: Error : a large file count (%x << 32 | %x) was sent and we don't \
4121 support large counts.\n", (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
4122             (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
4123
4124         *err = True;
4125         return (SMB_OFF_T)-1;
4126       }
4127     }
4128     else
4129       count = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
4130
4131 #endif /* LARGE_SMB_OFF_T */
4132   }
4133   return count;
4134 }
4135
4136 /****************************************************************************
4137  Get a lock offset, dealing with large offset requests.
4138 ****************************************************************************/
4139
4140 SMB_OFF_T get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
4141 {
4142   SMB_OFF_T offset = 0;
4143
4144   *err = False;
4145
4146   if(!large_file_format) {
4147     offset = (SMB_OFF_T)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
4148   } else {
4149
4150 #if defined(LARGE_SMB_OFF_T) && !defined(HAVE_BROKEN_FCNTL64_LOCKS)
4151
4152     offset = (((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
4153             ((SMB_OFF_T) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
4154
4155 #else /* !LARGE_SMB_OFF_T || HAVE_BROKEN_FCNTL64_LOCKS */
4156
4157     /*
4158      * NT4.x seems to be broken in that it sends large file
4159      * lockingX calls even if the CAP_LARGE_FILES was *not*
4160      * negotiated. For boxes without large file locks mangle the
4161      * lock offset by mapping the top 32 bits onto the lower 32.
4162      */
4163       
4164     if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
4165       uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4166       uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
4167       uint32 new_low = 0;
4168
4169       if((new_low = map_lock_offset(high, low)) == 0) {
4170         *err = True;
4171         return (SMB_OFF_T)-1;
4172       }
4173
4174       DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
4175             (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
4176       SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
4177       SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
4178     }
4179
4180     if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0){
4181       /*
4182        * Before we error out, see if we can sensibly map the top bits
4183        * down to the lower bits - or lose the top bits if they are all 1's.
4184        * It seems that NT has this horrible bug where it will send 64 bit
4185        * lock requests even if told not to. JRA.
4186        */
4187
4188       if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)) == (uint32)0xFFFFFFFF)
4189         offset = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
4190       else if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) == (uint32)0xFFFFFFFF)
4191         offset = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4192       else {
4193
4194         DEBUG(0,("get_lock_count: Error : a large file offset (%x << 32 | %x) was sent and we don't \
4195 support large offsets.\n", (unsigned int)IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)),
4196             (unsigned int)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)) ));
4197
4198         *err = True;
4199         return (SMB_OFF_T)-1;
4200       }
4201     }
4202     else
4203       offset = (SMB_OFF_T)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4204
4205 #endif /* LARGE_SMB_OFF_T */
4206   }
4207   return offset;
4208 }
4209
4210 /****************************************************************************
4211   reply to a lockingX request
4212 ****************************************************************************/
4213
4214 int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
4215 {
4216   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
4217   unsigned char locktype = CVAL(inbuf,smb_vwv3);
4218 #if 0
4219   unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
4220 #endif
4221   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
4222   uint16 num_locks = SVAL(inbuf,smb_vwv7);
4223   SMB_OFF_T count = 0, offset = 0;
4224   int32 lock_timeout = IVAL(inbuf,smb_vwv4);
4225   int i;
4226   char *data;
4227   uint32 ecode=0, dummy2;
4228   int eclass=0, dummy1;
4229   BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES);
4230   BOOL err1, err2;
4231
4232   CHECK_FSP(fsp,conn);
4233   CHECK_ERROR(fsp);
4234
4235   data = smb_buf(inbuf);
4236
4237   /* Check if this is an oplock break on a file
4238      we have granted an oplock on.
4239    */
4240   if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE))
4241   {
4242     DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
4243               fsp->fnum));
4244
4245     /*
4246      * Make sure we have granted an exclusive or batch oplock on this file.
4247      */
4248
4249     if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
4250     {
4251       DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
4252 no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
4253
4254       /* if this is a pure oplock break request then don't send a reply */
4255       if (num_locks == 0 && num_ulocks == 0)
4256         return -1;
4257       else
4258         return ERROR(ERRDOS,ERRlock);
4259     }
4260
4261     if (remove_oplock(fsp) == False) {
4262       DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
4263             fsp->fsp_name ));
4264     }
4265
4266     /* if this is a pure oplock break request then don't send a reply */
4267     if (num_locks == 0 && num_ulocks == 0)
4268     {
4269       /* Sanity check - ensure a pure oplock break is not a
4270          chained request. */
4271       if(CVAL(inbuf,smb_vwv0) != 0xff)
4272         DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
4273                  (unsigned int)CVAL(inbuf,smb_vwv0) ));
4274       return -1;
4275     }
4276   }
4277
4278   /* Data now points at the beginning of the list
4279      of smb_unlkrng structs */
4280   for(i = 0; i < (int)num_ulocks; i++) {
4281     count = get_lock_count( data, i, large_file_format, &err1);
4282     offset = get_lock_offset( data, i, large_file_format, &err2);
4283
4284     /*
4285      * There is no error code marked "stupid client bug".... :-).
4286      */
4287     if(err1 || err2)
4288       return ERROR(ERRDOS,ERRnoaccess);
4289
4290     DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for file %s\n",
4291           (double)offset, (double)count, fsp->fsp_name ));
4292
4293     if(!do_unlock(fsp,conn,count,offset, &eclass, &ecode))
4294       return ERROR(eclass,ecode);
4295   }
4296
4297   /* Setup the timeout in seconds. */
4298   lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
4299
4300   /* Now do any requested locks */
4301   data += ((large_file_format ? 20 : 10)*num_ulocks);
4302
4303   /* Data now points at the beginning of the list
4304      of smb_lkrng structs */
4305
4306   for(i = 0; i < (int)num_locks; i++) {
4307     count = get_lock_count( data, i, large_file_format, &err1);
4308     offset = get_lock_offset( data, i, large_file_format, &err2);
4309
4310     /*
4311      * There is no error code marked "stupid client bug".... :-).
4312      */
4313     if(err1 || err2)
4314       return ERROR(ERRDOS,ERRnoaccess);
4315  
4316     DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for file %s\n",
4317           (double)offset, (double)count, fsp->fsp_name ));
4318
4319     if(!do_lock(fsp,conn,count,offset, ((locktype & 1) ? READ_LOCK : WRITE_LOCK),
4320                 &eclass, &ecode)) {
4321       if((ecode == ERRlock) && (lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
4322         /*
4323          * A blocking lock was requested. Package up
4324          * this smb into a queued request and push it
4325          * onto the blocking lock queue.
4326          */
4327         if(push_blocking_lock_request(inbuf, length, lock_timeout, i))
4328           return -1;
4329       }
4330       break;
4331     }
4332   }
4333
4334   /* If any of the above locks failed, then we must unlock
4335      all of the previous locks (X/Open spec). */
4336   if(i != num_locks && num_locks != 0) {
4337     /*
4338      * Ensure we don't do a remove on the lock that just failed,
4339      * as under POSIX rules, if we have a lock already there, we
4340      * will delete it (and we shouldn't) .....
4341      */
4342     for(i--; i >= 0; i--) {
4343       count = get_lock_count( data, i, large_file_format, &err1);
4344       offset = get_lock_offset( data, i, large_file_format, &err2);
4345
4346       /*
4347        * There is no error code marked "stupid client bug".... :-).
4348        */
4349       if(err1 || err2)
4350         return ERROR(ERRDOS,ERRnoaccess);
4351  
4352       do_unlock(fsp,conn,count,offset,&dummy1,&dummy2);
4353     }
4354     return ERROR(eclass,ecode);
4355   }
4356
4357   set_message(outbuf,2,0,True);
4358   
4359   DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
4360         fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
4361
4362   return chain_reply(inbuf,outbuf,length,bufsize);
4363 }
4364
4365
4366 /****************************************************************************
4367   reply to a SMBreadbmpx (read block multiplex) request
4368 ****************************************************************************/
4369 int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
4370 {
4371   ssize_t nread = -1;
4372   ssize_t total_read;
4373   char *data;
4374   SMB_OFF_T startpos;
4375   int outsize;
4376   size_t maxcount;
4377   int max_per_packet;
4378   size_t tcount;
4379   int pad;
4380   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4381
4382   /* this function doesn't seem to work - disable by default */
4383   if (!lp_readbmpx())
4384     return(ERROR(ERRSRV,ERRuseSTD));
4385
4386   outsize = set_message(outbuf,8,0,True);
4387
4388   CHECK_FSP(fsp,conn);
4389   CHECK_READ(fsp);
4390   CHECK_ERROR(fsp);
4391
4392   startpos = IVAL(inbuf,smb_vwv1);
4393   maxcount = SVAL(inbuf,smb_vwv3);
4394
4395   data = smb_buf(outbuf);
4396   pad = ((long)data)%4;
4397   if (pad) pad = 4 - pad;
4398   data += pad;
4399
4400   max_per_packet = bufsize-(outsize+pad);
4401   tcount = maxcount;
4402   total_read = 0;
4403
4404   if (is_locked(fsp,conn,maxcount,startpos, READ_LOCK))
4405     return(ERROR(ERRDOS,ERRlock));
4406         
4407   do
4408     {
4409       size_t N = MIN(max_per_packet,tcount-total_read);
4410   
4411       nread = read_file(fsp,data,startpos,N);
4412
4413       if (nread <= 0) nread = 0;
4414
4415       if (nread < (ssize_t)N)
4416         tcount = total_read + nread;
4417
4418       set_message(outbuf,8,nread,False);
4419       SIVAL(outbuf,smb_vwv0,startpos);
4420       SSVAL(outbuf,smb_vwv2,tcount);
4421       SSVAL(outbuf,smb_vwv6,nread);
4422       SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
4423
4424       send_smb(Client,outbuf);
4425
4426       total_read += nread;
4427       startpos += nread;
4428     }
4429   while (total_read < (ssize_t)tcount);
4430
4431   return(-1);
4432 }
4433
4434 /****************************************************************************
4435   reply to a SMBwritebmpx (write block multiplex primary) request
4436 ****************************************************************************/
4437
4438 int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4439 {
4440   size_t numtowrite;
4441   ssize_t nwritten = -1;
4442   int outsize = 0;
4443   SMB_OFF_T startpos;
4444   size_t tcount;
4445   BOOL write_through;
4446   int smb_doff;
4447   char *data;
4448   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4449
4450   CHECK_FSP(fsp,conn);
4451   CHECK_WRITE(fsp);
4452   CHECK_ERROR(fsp);
4453
4454   tcount = SVAL(inbuf,smb_vwv1);
4455   startpos = IVAL(inbuf,smb_vwv3);
4456   write_through = BITSETW(inbuf+smb_vwv7,0);
4457   numtowrite = SVAL(inbuf,smb_vwv10);
4458   smb_doff = SVAL(inbuf,smb_vwv11);
4459
4460   data = smb_base(inbuf) + smb_doff;
4461
4462   /* If this fails we need to send an SMBwriteC response,
4463      not an SMBwritebmpx - set this up now so we don't forget */
4464   CVAL(outbuf,smb_com) = SMBwritec;
4465
4466   if (is_locked(fsp,conn,tcount,startpos,WRITE_LOCK))
4467     return(ERROR(ERRDOS,ERRlock));
4468
4469   nwritten = write_file(fsp,data,startpos,numtowrite);
4470
4471   if(lp_syncalways(SNUM(conn)) || write_through)
4472       conn->vfs_ops.fsync(fsp->fd_ptr->fd);
4473   
4474   if(nwritten < (ssize_t)numtowrite)
4475     return(UNIXERROR(ERRHRD,ERRdiskfull));
4476
4477   /* If the maximum to be written to this file
4478      is greater than what we just wrote then set
4479      up a secondary struct to be attached to this
4480      fd, we will use this to cache error messages etc. */
4481   if((ssize_t)tcount > nwritten) 
4482   {
4483     write_bmpx_struct *wbms;
4484     if(fsp->wbmpx_ptr != NULL)
4485       wbms = fsp->wbmpx_ptr; /* Use an existing struct */
4486     else
4487       wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
4488     if(!wbms)
4489     {
4490       DEBUG(0,("Out of memory in reply_readmpx\n"));
4491       return(ERROR(ERRSRV,ERRnoresource));
4492     }
4493     wbms->wr_mode = write_through;
4494     wbms->wr_discard = False; /* No errors yet */
4495     wbms->wr_total_written = nwritten;
4496     wbms->wr_errclass = 0;
4497     wbms->wr_error = 0;
4498     fsp->wbmpx_ptr = wbms;
4499   }
4500
4501   /* We are returning successfully, set the message type back to
4502      SMBwritebmpx */
4503   CVAL(outbuf,smb_com) = SMBwriteBmpx;
4504   
4505   outsize = set_message(outbuf,1,0,True);
4506   
4507   SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
4508   
4509   DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
4510             fsp->fnum, (int)numtowrite, (int)nwritten ) );
4511
4512   if (write_through && tcount==nwritten) {
4513     /* we need to send both a primary and a secondary response */
4514     smb_setlen(outbuf,outsize - 4);
4515     send_smb(Client,outbuf);
4516
4517     /* now the secondary */
4518     outsize = set_message(outbuf,1,0,True);
4519     CVAL(outbuf,smb_com) = SMBwritec;
4520     SSVAL(outbuf,smb_vwv0,nwritten);
4521   }
4522
4523   return(outsize);
4524 }
4525
4526
4527 /****************************************************************************
4528   reply to a SMBwritebs (write block multiplex secondary) request
4529 ****************************************************************************/
4530 int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4531 {
4532   size_t numtowrite;
4533   ssize_t nwritten = -1;
4534   int outsize = 0;
4535   SMB_OFF_T startpos;
4536   size_t tcount;
4537   BOOL write_through;
4538   int smb_doff;
4539   char *data;
4540   write_bmpx_struct *wbms;
4541   BOOL send_response = False; 
4542   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4543
4544   CHECK_FSP(fsp,conn);
4545   CHECK_WRITE(fsp);
4546
4547   tcount = SVAL(inbuf,smb_vwv1);
4548   startpos = IVAL(inbuf,smb_vwv2);
4549   numtowrite = SVAL(inbuf,smb_vwv6);
4550   smb_doff = SVAL(inbuf,smb_vwv7);
4551
4552   data = smb_base(inbuf) + smb_doff;
4553
4554   /* We need to send an SMBwriteC response, not an SMBwritebs */
4555   CVAL(outbuf,smb_com) = SMBwritec;
4556
4557   /* This fd should have an auxiliary struct attached,
4558      check that it does */
4559   wbms = fsp->wbmpx_ptr;
4560   if(!wbms) return(-1);
4561
4562   /* If write through is set we can return errors, else we must
4563      cache them */
4564   write_through = wbms->wr_mode;
4565
4566   /* Check for an earlier error */
4567   if(wbms->wr_discard)
4568     return -1; /* Just discard the packet */
4569
4570   nwritten = write_file(fsp,data,startpos,numtowrite);
4571
4572   if(lp_syncalways(SNUM(conn)) || write_through)
4573     conn->vfs_ops.fsync(fsp->fd_ptr->fd);
4574   
4575   if (nwritten < (ssize_t)numtowrite)
4576   {
4577     if(write_through)
4578     {
4579       /* We are returning an error - we can delete the aux struct */
4580       if (wbms) free((char *)wbms);
4581       fsp->wbmpx_ptr = NULL;
4582       return(ERROR(ERRHRD,ERRdiskfull));
4583     }
4584     return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
4585   }
4586
4587   /* Increment the total written, if this matches tcount
4588      we can discard the auxiliary struct (hurrah !) and return a writeC */
4589   wbms->wr_total_written += nwritten;
4590   if(wbms->wr_total_written >= tcount)
4591   {
4592     if (write_through)
4593     {
4594       outsize = set_message(outbuf,1,0,True);
4595       SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
4596       send_response = True;
4597     }
4598
4599     free((char *)wbms);
4600     fsp->wbmpx_ptr = NULL;
4601   }
4602
4603   if(send_response)
4604     return(outsize);
4605
4606   return(-1);
4607 }
4608
4609
4610 /****************************************************************************
4611   reply to a SMBsetattrE
4612 ****************************************************************************/
4613
4614 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4615 {
4616   struct utimbuf unix_times;
4617   int outsize = 0;
4618   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4619
4620   outsize = set_message(outbuf,0,0,True);
4621
4622   CHECK_FSP(fsp,conn);
4623   CHECK_ERROR(fsp);
4624
4625   /* Convert the DOS times into unix times. Ignore create
4626      time as UNIX can't set this.
4627      */
4628   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
4629   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
4630   
4631   /* 
4632    * Patch from Ray Frush <frush@engr.colostate.edu>
4633    * Sometimes times are sent as zero - ignore them.
4634    */
4635
4636   if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
4637   {
4638     /* Ignore request */
4639     if( DEBUGLVL( 3 ) )
4640       {
4641       dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
4642       dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
4643       }
4644     return(outsize);
4645   }
4646   else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
4647   {
4648     /* set modify time = to access time if modify time was 0 */
4649     unix_times.modtime = unix_times.actime;
4650   }
4651
4652   /* Set the date on this file */
4653   if(file_utime(conn, fsp->fsp_name, &unix_times))
4654     return(ERROR(ERRDOS,ERRnoaccess));
4655   
4656   DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
4657             fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
4658
4659   return(outsize);
4660 }
4661
4662
4663 /****************************************************************************
4664   reply to a SMBgetattrE
4665 ****************************************************************************/
4666
4667 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4668 {
4669   SMB_STRUCT_STAT sbuf;
4670   int outsize = 0;
4671   int mode;
4672   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4673
4674   outsize = set_message(outbuf,11,0,True);
4675
4676   CHECK_FSP(fsp,conn);
4677   CHECK_ERROR(fsp);
4678
4679   /* Do an fstat on this file */
4680   if(fsp->conn->vfs_ops.fstat(fsp->fd_ptr->fd, &sbuf))
4681     return(UNIXERROR(ERRDOS,ERRnoaccess));
4682   
4683   mode = dos_mode(conn,fsp->fsp_name,&sbuf);
4684   
4685   /* Convert the times into dos times. Set create
4686      date to be last modify date as UNIX doesn't save
4687      this */
4688   put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
4689   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
4690   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
4691   if (mode & aDIR)
4692     {
4693       SIVAL(outbuf,smb_vwv6,0);
4694       SIVAL(outbuf,smb_vwv8,0);
4695     }
4696   else
4697     {
4698       SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
4699       SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
4700     }
4701   SSVAL(outbuf,smb_vwv10, mode);
4702   
4703   DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
4704   
4705   return(outsize);
4706 }