local.h: Fix spelling mistake :-).
[kai/samba.git] / source3 / smbd / reply.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    Main SMB reply routines
5    Copyright (C) Andrew Tridgell 1992-1997
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
30 /* look in server.c for some explanation of these variables */
31 extern int Protocol;
32 extern int DEBUGLEVEL;
33 extern int max_send;
34 extern int max_recv;
35 extern int chain_fnum;
36 extern char magic_char;
37 extern connection_struct Connections[];
38 extern files_struct Files[];
39 extern BOOL case_sensitive;
40 extern BOOL case_preserve;
41 extern BOOL short_case_preserve;
42 extern pstring sesssetup_user;
43 extern fstring myworkgroup;
44 extern int Client;
45 extern int global_oplock_break;
46
47 /* this macro should always be used to extract an fnum (smb_fid) from
48 a packet to ensure chaining works correctly */
49 #define GETFNUM(buf,where) (chain_fnum!= -1?chain_fnum:SVAL(buf,where))
50
51
52 /****************************************************************************
53 report a possible attack via the password buffer overflow bug
54 ****************************************************************************/
55 static void overflow_attack(int len)
56 {
57         DEBUG(0,("ERROR: Invalid password length %d\n", len));
58         DEBUG(0,("your machine may be under attack by a user exploiting an old bug\n"));
59         DEBUG(0,("Attack was from IP=%s\n", client_addr()));
60         exit_server("possible attack");
61 }
62
63
64 /****************************************************************************
65   reply to an special message 
66 ****************************************************************************/
67 int reply_special(char *inbuf,char *outbuf)
68 {
69         int outsize = 4;
70         int msg_type = CVAL(inbuf,0);
71         int msg_flags = CVAL(inbuf,1);
72         pstring name1,name2;
73         extern fstring remote_machine;
74         extern fstring local_machine;
75         char *p;
76         
77         *name1 = *name2 = 0;
78         
79         smb_setlen(outbuf,0);
80         
81         switch (msg_type) {
82     case 0x81: /* session request */
83       CVAL(outbuf,0) = 0x82;
84       CVAL(outbuf,3) = 0;
85       if (name_len(inbuf+4) > 50 || name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
86               DEBUG(0,("Invalid name length in session request\n"));
87               return(0);
88       }
89       name_extract(inbuf,4,name1);
90       name_extract(inbuf,4 + name_len(inbuf + 4),name2);
91                 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
92                          name1,name2));      
93
94       fstrcpy(remote_machine,name2);
95       trim_string(remote_machine," "," ");
96       p = strchr(remote_machine,' ');
97       strlower(remote_machine);
98       if (p) *p = 0;
99
100       fstrcpy(local_machine,name1);
101       trim_string(local_machine," "," ");
102       p = strchr(local_machine,' ');
103       strlower(local_machine);
104       if (p) *p = 0;
105
106       add_session_user(remote_machine);
107
108       reload_services(True);
109       reopen_logs();
110
111       break;
112                 
113         case 0x89: /* session keepalive request 
114                       (some old clients produce this?) */
115                 CVAL(outbuf,0) = 0x85;
116                 CVAL(outbuf,3) = 0;
117                 break;
118                 
119         case 0x82: /* positive session response */
120         case 0x83: /* negative session response */
121         case 0x84: /* retarget session response */
122                 DEBUG(0,("Unexpected session response\n"));
123                 break;
124                 
125         case 0x85: /* session keepalive */
126         default:
127                 return(0);
128         }
129         
130         DEBUG(5,("%s init msg_type=0x%x msg_flags=0x%x\n",
131                  timestring(),msg_type,msg_flags));
132         
133         return(outsize);
134 }
135
136
137 /*******************************************************************
138 work out what error to give to a failed connection
139 ********************************************************************/
140 static int connection_error(char *inbuf,char *outbuf,int connection_num)
141 {
142   switch (connection_num)
143     {
144     case -8:
145       return(ERROR(ERRSRV,ERRnoresource));
146     case -7:
147       return(ERROR(ERRSRV,ERRbaduid));
148     case -6:
149       return(ERROR(ERRSRV,ERRinvdevice));
150     case -5:
151       return(ERROR(ERRSRV,ERRinvnetname));
152     case -4:
153       return(ERROR(ERRSRV,ERRaccess));
154     case -3:
155       return(ERROR(ERRDOS,ERRnoipc));
156     case -2:
157       return(ERROR(ERRSRV,ERRinvnetname));
158     }
159   return(ERROR(ERRSRV,ERRbadpw));
160 }
161
162
163
164 /****************************************************************************
165   parse a share descriptor string
166 ****************************************************************************/
167 static void parse_connect(char *p,char *service,char *user,
168                           char *password,int *pwlen,char *dev)
169 {
170   char *p2;
171
172   DEBUG(4,("parsing connect string %s\n",p));
173     
174   p2 = strrchr(p,'\\');
175   if (p2 == NULL)
176     fstrcpy(service,p);
177   else
178     fstrcpy(service,p2+1);
179   
180   p += strlen(p) + 2;
181   
182   fstrcpy(password,p);
183   *pwlen = strlen(password);
184
185   p += strlen(p) + 2;
186
187   fstrcpy(dev,p);
188   
189   *user = 0;
190   p = strchr(service,'%');
191   if (p != NULL)
192     {
193       *p = 0;
194       fstrcpy(user,p+1);
195     }
196 }
197
198
199
200
201 /****************************************************************************
202   reply to a tcon
203 ****************************************************************************/
204 int reply_tcon(char *inbuf,char *outbuf)
205 {
206   pstring service;
207   pstring user;
208   pstring password;
209   pstring dev;
210   int connection_num;
211   int outsize = 0;
212   uint16 vuid = SVAL(inbuf,smb_uid);
213   int pwlen=0;
214
215   *service = *user = *password = *dev = 0;
216
217   parse_connect(smb_buf(inbuf)+1,service,user,password,&pwlen,dev);
218
219   connection_num = make_connection(service,user,password,pwlen,dev,vuid);
220   
221   if (connection_num < 0)
222     return(connection_error(inbuf,outbuf,connection_num));
223   
224   outsize = set_message(outbuf,2,0,True);
225   SSVAL(outbuf,smb_vwv0,max_recv);
226   SSVAL(outbuf,smb_vwv1,connection_num);
227   SSVAL(outbuf,smb_tid,connection_num);
228   
229   DEBUG(3,("%s tcon service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
230   
231   return(outsize);
232 }
233
234
235 /****************************************************************************
236   reply to a tcon and X
237 ****************************************************************************/
238 int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize)
239 {
240   pstring service;
241   pstring user;
242   pstring password;
243   pstring devicename;
244   int connection_num;
245   uint16 vuid = SVAL(inbuf,smb_uid);
246   int passlen = SVAL(inbuf,smb_vwv3);
247   BOOL doencrypt = SMBENCRYPT();
248
249   *service = *user = *password = *devicename = 0;
250
251   /* we might have to close an old one */
252   if ((SVAL(inbuf,smb_vwv2) & 0x1) != 0)
253     close_cnum(SVAL(inbuf,smb_tid),vuid);
254
255   if (passlen > MAX_PASS_LEN) {
256           overflow_attack(passlen);
257   }
258   
259   {
260     char *path;
261     char *p;
262     memcpy(password,smb_buf(inbuf),passlen);
263     password[passlen]=0;    
264     path = smb_buf(inbuf) + passlen;
265
266     if (!doencrypt || passlen != 24) {
267       if (strequal(password," "))
268         *password = 0;
269       passlen = strlen(password);
270     }
271     
272     fstrcpy(service,path+2);
273     p = strchr(service,'\\');
274     if (!p)
275       return(ERROR(ERRSRV,ERRinvnetname));
276     *p = 0;
277     fstrcpy(service,p+1);
278     p = strchr(service,'%');
279     if (p)
280       {
281         *p++ = 0;
282         fstrcpy(user,p);
283       }
284     StrnCpy(devicename,path + strlen(path) + 1,6);
285     DEBUG(4,("Got device type %s\n",devicename));
286   }
287
288   connection_num = make_connection(service,user,password,passlen,devicename,vuid);
289   
290   if (connection_num < 0)
291     return(connection_error(inbuf,outbuf,connection_num));
292
293   if (Protocol < PROTOCOL_NT1)
294   {
295     set_message(outbuf,2,strlen(devicename)+1,True);
296     strcpy(smb_buf(outbuf),devicename);
297   }
298   else
299   {
300     char *fsname = "SAMBA";
301     char *p;
302
303     set_message(outbuf,3,3,True);
304
305     p = smb_buf(outbuf);
306     strcpy(p,devicename); p = skip_string(p,1); /* device name */
307     strcpy(p,fsname); p = skip_string(p,1); /* filesystem type e.g NTFS */
308
309     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
310
311     SSVAL(outbuf, smb_vwv2, 0x0); /* optional support */
312   }
313   
314   DEBUG(3,("%s tconX service=%s user=%s cnum=%d\n",timestring(),service,user,connection_num));
315   
316   /* set the incoming and outgoing tid to the just created one */
317   SSVAL(inbuf,smb_tid,connection_num);
318   SSVAL(outbuf,smb_tid,connection_num);
319
320   return chain_reply(inbuf,outbuf,length,bufsize);
321 }
322
323
324 /****************************************************************************
325   reply to an unknown type
326 ****************************************************************************/
327 int reply_unknown(char *inbuf,char *outbuf)
328 {
329   int cnum;
330   int type;
331   cnum = SVAL(inbuf,smb_tid);
332   type = CVAL(inbuf,smb_com);
333   
334   DEBUG(0,("%s unknown command type (%s): cnum=%d type=%d (0x%X)\n",
335         timestring(),
336         smb_fn_name(type),
337         cnum,type,type));
338   
339   return(ERROR(ERRSRV,ERRunknownsmb));
340 }
341
342
343 /****************************************************************************
344   reply to an ioctl
345 ****************************************************************************/
346 int reply_ioctl(char *inbuf,char *outbuf)
347 {
348   DEBUG(3,("ignoring ioctl\n"));
349 #if 0
350   /* we just say it succeeds and hope its all OK. 
351      some day it would be nice to interpret them individually */
352   return set_message(outbuf,1,0,True); 
353 #else
354   return(ERROR(ERRSRV,ERRnosupport));
355 #endif
356 }
357
358
359 /****************************************************************************
360 reply to a session setup command
361 ****************************************************************************/
362 int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
363 {
364   uint16 sess_vuid;
365   int gid;
366   int uid;
367   int   smb_bufsize;    
368   int   smb_mpxmax;     
369   int   smb_vc_num;     
370   uint32   smb_sesskey;    
371   int   smb_apasslen = 0;   
372   pstring smb_apasswd;
373   int   smb_ntpasslen = 0;   
374   pstring smb_ntpasswd;
375   BOOL valid_nt_password = False;
376   pstring user;
377   BOOL guest=False;
378   BOOL computer_id=False;
379   static BOOL done_sesssetup = False;
380   BOOL doencrypt = SMBENCRYPT();
381
382   *smb_apasswd = 0;
383   
384   smb_bufsize = SVAL(inbuf,smb_vwv2);
385   smb_mpxmax = SVAL(inbuf,smb_vwv3);
386   smb_vc_num = SVAL(inbuf,smb_vwv4);
387   smb_sesskey = IVAL(inbuf,smb_vwv5);
388
389   if (Protocol < PROTOCOL_NT1) {
390     smb_apasslen = SVAL(inbuf,smb_vwv7);
391     if (smb_apasslen > MAX_PASS_LEN)
392     {
393             overflow_attack(smb_apasslen);
394     }
395
396     memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
397     pstrcpy(user,smb_buf(inbuf)+smb_apasslen);
398
399     if (lp_security() != SEC_SERVER && !doencrypt) {
400             smb_apasslen = strlen(smb_apasswd);
401     }
402   } else {
403     uint16 passlen1 = SVAL(inbuf,smb_vwv7);
404     uint16 passlen2 = SVAL(inbuf,smb_vwv8);
405     uint32 client_caps = IVAL(inbuf,smb_vwv11);
406     enum remote_arch_types ra_type = get_remote_arch();
407
408     char *p = smb_buf(inbuf);    
409
410     /* client_caps is used as final determination if client is NT or Win95. 
411        This is needed to return the correct error codes in some
412        circumstances.
413      */
414     
415     if(ra_type == RA_WINNT || ra_type == RA_WIN95)
416     {
417       if(client_caps & (CAP_NT_SMBS | CAP_STATUS32))
418         set_remote_arch( RA_WINNT);
419       else
420         set_remote_arch( RA_WIN95);
421     }
422
423     if (passlen1 != 24 && passlen2 != 24)
424       doencrypt = False;
425
426     if (passlen1 > MAX_PASS_LEN) {
427             overflow_attack(passlen1);
428     }
429
430     passlen1 = MIN(passlen1, MAX_PASS_LEN);
431     passlen2 = MIN(passlen2, MAX_PASS_LEN);
432
433     if(doencrypt) {
434       /* Save the lanman2 password and the NT md4 password. */
435       smb_apasslen = passlen1;
436       memcpy(smb_apasswd,p,smb_apasslen);
437       smb_ntpasslen = passlen2;
438       memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
439     } else {
440       /* both Win95 and WinNT stuff up the password lengths for
441          non-encrypting systems. Uggh. 
442       
443          if passlen1==24 its a win95 system, and its setting the
444          password length incorrectly. Luckily it still works with the
445          default code because Win95 will null terminate the password
446          anyway 
447
448          if passlen1>0 and passlen2>0 then maybe its a NT box and its
449          setting passlen2 to some random value which really stuffs
450          things up. we need to fix that one.  */
451       if (passlen1 > 0 && passlen2 > 0 && passlen2 != 24 &&
452           passlen2 != 1) {
453         passlen2 = 0;
454       }
455       /* we use the first password that they gave */
456       smb_apasslen = passlen1;
457       StrnCpy(smb_apasswd,p,smb_apasslen);      
458       
459       /* trim the password */
460       smb_apasslen = strlen(smb_apasswd);
461
462       /* wfwg sometimes uses a space instead of a null */
463       if (strequal(smb_apasswd," ")) {
464         smb_apasslen = 0;
465         *smb_apasswd = 0;
466       }
467     }
468     
469     p += passlen1 + passlen2;
470     fstrcpy(user,p); p = skip_string(p,1);
471     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
472              p,skip_string(p,1),skip_string(p,2)));
473   }
474
475
476   DEBUG(3,("sesssetupX:name=[%s]\n",user));
477
478   /* If name ends in $ then I think it's asking about whether a */
479   /* computer with that name (minus the $) has access. For now */
480   /* say yes to everything ending in $. */
481   if (user[strlen(user) - 1] == '$') {
482     computer_id = True;
483     user[strlen(user) - 1] = '\0';
484   }
485
486
487   /* If no username is sent use the guest account */
488   if (!*user)
489     {
490       strcpy(user,lp_guestaccount(-1));
491       /* If no user and no password then set guest flag. */
492       if( *smb_apasswd == 0)
493         guest = True;
494     }
495
496   strlower(user);
497
498   strcpy(sesssetup_user,user);
499
500   reload_services(True);
501
502   add_session_user(user);
503
504   /* Check if the given username was the guest user with no password.
505      We need to do this check after add_session_user() as that
506      call can potentially change the username (via map_user).
507    */
508
509   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
510     guest = True;
511
512   if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
513       !check_hosts_equiv(user))
514     {
515
516       /* now check if it's a valid username/password */
517       /* If an NT password was supplied try and validate with that
518          first. This is superior as the passwords are mixed case 
519          128 length unicode */
520       if(smb_ntpasslen)
521         {
522           if(!password_ok(user,smb_ntpasswd,smb_ntpasslen,NULL))
523             DEBUG(0,("NT Password did not match ! Defaulting to Lanman\n"));
524           else
525             valid_nt_password = True;
526         } 
527       if (!valid_nt_password && !password_ok(user,smb_apasswd,smb_apasslen,NULL))
528         {
529           if (!computer_id && lp_security() >= SEC_USER) {
530 #if (GUEST_SESSSETUP == 0)
531             return(ERROR(ERRSRV,ERRbadpw));
532 #endif
533 #if (GUEST_SESSSETUP == 1)
534             if (Get_Pwnam(user,True))
535               return(ERROR(ERRSRV,ERRbadpw));
536 #endif
537           }
538           if (*smb_apasswd || !Get_Pwnam(user,True))
539             strcpy(user,lp_guestaccount(-1));
540           DEBUG(3,("Registered username %s for guest access\n",user));
541           guest = True;
542         }
543     }
544
545   if (!Get_Pwnam(user,True)) {
546     DEBUG(3,("No such user %s - using guest account\n",user));
547     strcpy(user,lp_guestaccount(-1));
548     guest = True;
549   }
550
551   if (!strequal(user,lp_guestaccount(-1)) &&
552       lp_servicenumber(user) < 0)      
553     {
554       int homes = lp_servicenumber(HOMES_NAME);
555       char *home = get_home_dir(user);
556       if (homes >= 0 && home)
557         lp_add_home(user,homes,home);
558     }
559
560
561   /* it's ok - setup a reply */
562   if (Protocol < PROTOCOL_NT1) {
563     set_message(outbuf,3,0,True);
564   } else {
565     char *p;
566     set_message(outbuf,3,3,True);
567     p = smb_buf(outbuf);
568     strcpy(p,"Unix"); p = skip_string(p,1);
569     strcpy(p,"Samba "); strcat(p,VERSION); p = skip_string(p,1);
570     strcpy(p,myworkgroup); p = skip_string(p,1);
571     set_message(outbuf,3,PTR_DIFF(p,smb_buf(outbuf)),False);
572     /* perhaps grab OS version here?? */
573   }
574
575   /* Set the correct uid in the outgoing and incoming packets
576      We will use this on future requests to determine which
577      user we should become.
578      */
579   {
580     struct passwd *pw = Get_Pwnam(user,False);
581     if (!pw) {
582       DEBUG(1,("Username %s is invalid on this system\n",user));
583       return(ERROR(ERRSRV,ERRbadpw));
584     }
585     gid = pw->pw_gid;
586     uid = pw->pw_uid;
587   }
588
589   if (guest && !computer_id)
590     SSVAL(outbuf,smb_vwv2,1);
591
592   /* register the name and uid as being validated, so further connections
593      to a uid can get through without a password, on the same VC */
594   sess_vuid = register_vuid(uid,gid,user,guest);
595  
596   SSVAL(outbuf,smb_uid,sess_vuid);
597   SSVAL(inbuf,smb_uid,sess_vuid);
598
599   if (!done_sesssetup)
600     max_send = MIN(max_send,smb_bufsize);
601
602   DEBUG(6,("Client requested max send size of %d\n", max_send));
603
604   done_sesssetup = True;
605
606   return chain_reply(inbuf,outbuf,length,bufsize);
607 }
608
609
610 /****************************************************************************
611   reply to a chkpth
612 ****************************************************************************/
613 int reply_chkpth(char *inbuf,char *outbuf)
614 {
615   int outsize = 0;
616   int cnum,mode;
617   pstring name;
618   BOOL ok = False;
619   BOOL bad_path = False;
620  
621   cnum = SVAL(inbuf,smb_tid);
622   
623   pstrcpy(name,smb_buf(inbuf) + 1);
624   unix_convert(name,cnum,0,&bad_path);
625
626   mode = SVAL(inbuf,smb_vwv0);
627
628   if (check_name(name,cnum))
629     ok = directory_exist(name,NULL);
630
631   if (!ok)
632   {
633     /* We special case this - as when a Windows machine
634        is parsing a path is steps through the components
635        one at a time - if a component fails it expects
636        ERRbadpath, not ERRbadfile.
637      */
638     if(errno == ENOENT)
639     {
640       unix_ERR_class = ERRDOS;
641       unix_ERR_code = ERRbadpath;
642     }
643
644 #if 0
645     /* Ugly - NT specific hack - maybe not needed ? (JRA) */
646     if((errno == ENOTDIR) && (Protocol >= PROTOCOL_NT1) &&
647        (get_remote_arch() == RA_WINNT))
648     {
649       unix_ERR_class = ERRDOS;
650       unix_ERR_code = ERRbaddirectory;
651     }
652 #endif
653
654     return(UNIXERROR(ERRDOS,ERRbadpath));
655   }
656  
657   outsize = set_message(outbuf,0,0,True);
658   
659   DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
660   
661   return(outsize);
662 }
663
664
665 /****************************************************************************
666   reply to a getatr
667 ****************************************************************************/
668 int reply_getatr(char *inbuf,char *outbuf)
669 {
670   pstring fname;
671   int cnum;
672   int outsize = 0;
673   struct stat sbuf;
674   BOOL ok = False;
675   int mode=0;
676   uint32 size=0;
677   time_t mtime=0;
678   BOOL bad_path = False;
679  
680   cnum = SVAL(inbuf,smb_tid);
681
682   pstrcpy(fname,smb_buf(inbuf) + 1);
683   unix_convert(fname,cnum,0,&bad_path);
684
685   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
686      under WfWg - weird! */
687   if (! (*fname))
688     {
689       mode = aHIDDEN | aDIR;
690       if (!CAN_WRITE(cnum)) mode |= aRONLY;
691       size = 0;
692       mtime = 0;
693       ok = True;
694     }
695   else
696     if (check_name(fname,cnum))
697     {
698       if (sys_stat(fname,&sbuf) == 0)
699       {
700         mode = dos_mode(cnum,fname,&sbuf);
701         size = sbuf.st_size;
702         mtime = sbuf.st_mtime;
703         if (mode & aDIR)
704           size = 0;
705         ok = True;
706       }
707       else
708         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
709     }
710   
711   if (!ok)
712   {
713     if((errno == ENOENT) && bad_path)
714     {
715       unix_ERR_class = ERRDOS;
716       unix_ERR_code = ERRbadpath;
717     }
718
719     return(UNIXERROR(ERRDOS,ERRbadfile));
720   }
721  
722   outsize = set_message(outbuf,10,0,True);
723
724   SSVAL(outbuf,smb_vwv0,mode);
725   put_dos_date3(outbuf,smb_vwv1,mtime);
726   SIVAL(outbuf,smb_vwv3,size);
727
728   if (Protocol >= PROTOCOL_NT1) {
729     char *p = strrchr(fname,'/');
730     uint16 flg2 = SVAL(outbuf,smb_flg2);
731     if (!p) p = fname;
732     if (!is_8_3(fname, True))
733       SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
734   }
735   
736   DEBUG(3,("%s getatr name=%s mode=%d size=%d\n",timestring(),fname,mode,size));
737   
738   return(outsize);
739 }
740
741
742 /****************************************************************************
743   reply to a setatr
744 ****************************************************************************/
745 int reply_setatr(char *inbuf,char *outbuf)
746 {
747   pstring fname;
748   int cnum;
749   int outsize = 0;
750   BOOL ok=False;
751   int mode;
752   time_t mtime;
753   BOOL bad_path = False;
754  
755   cnum = SVAL(inbuf,smb_tid);
756   
757   pstrcpy(fname,smb_buf(inbuf) + 1);
758   unix_convert(fname,cnum,0,&bad_path);
759
760   mode = SVAL(inbuf,smb_vwv0);
761   mtime = make_unix_date3(inbuf+smb_vwv1);
762   
763   if (directory_exist(fname,NULL))
764     mode |= aDIR;
765   if (check_name(fname,cnum))
766     ok =  (dos_chmod(cnum,fname,mode,NULL) == 0);
767   if (ok)
768     ok = set_filetime(fname,mtime);
769   
770   if (!ok)
771   {
772     if((errno == ENOENT) && bad_path)
773     {
774       unix_ERR_class = ERRDOS;
775       unix_ERR_code = ERRbadpath;
776     }
777
778     return(UNIXERROR(ERRDOS,ERRnoaccess));
779   }
780  
781   outsize = set_message(outbuf,0,0,True);
782   
783   DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
784   
785   return(outsize);
786 }
787
788
789 /****************************************************************************
790   reply to a dskattr
791 ****************************************************************************/
792 int reply_dskattr(char *inbuf,char *outbuf)
793 {
794   int cnum;
795   int outsize = 0;
796   int dfree,dsize,bsize;
797   
798   cnum = SVAL(inbuf,smb_tid);
799   
800   sys_disk_free(".",&bsize,&dfree,&dsize);
801   
802   outsize = set_message(outbuf,5,0,True);
803   
804   SSVAL(outbuf,smb_vwv0,dsize);
805   SSVAL(outbuf,smb_vwv1,bsize/512);
806   SSVAL(outbuf,smb_vwv2,512);
807   SSVAL(outbuf,smb_vwv3,dfree);
808   
809   DEBUG(3,("%s dskattr cnum=%d dfree=%d\n",timestring(),cnum,dfree));
810   
811   return(outsize);
812 }
813
814
815 /****************************************************************************
816   reply to a search
817   Can be called from SMBsearch, SMBffirst or SMBfunique.
818 ****************************************************************************/
819 int reply_search(char *inbuf,char *outbuf)
820 {
821   pstring mask;
822   pstring directory;
823   pstring fname;
824   int size,mode;
825   time_t date;
826   int dirtype;
827   int cnum;
828   int outsize = 0;
829   int numentries = 0;
830   BOOL finished = False;
831   int maxentries;
832   int i;
833   char *p;
834   BOOL ok = False;
835   int status_len;
836   char *path;
837   char status[21];
838   int dptr_num= -1;
839   BOOL check_descend = False;
840   BOOL expect_close = False;
841   BOOL can_open = True;
842   BOOL bad_path = False;
843
844   *mask = *directory = *fname = 0;
845
846   /* If we were called as SMBffirst then we must expect close. */
847   if(CVAL(inbuf,smb_com) == SMBffirst)
848     expect_close = True;
849   
850   cnum = SVAL(inbuf,smb_tid);
851
852   outsize = set_message(outbuf,1,3,True);
853   maxentries = SVAL(inbuf,smb_vwv0); 
854   dirtype = SVAL(inbuf,smb_vwv1);
855   path = smb_buf(inbuf) + 1;
856   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
857
858   
859   /* dirtype &= ~aDIR; */
860   
861   DEBUG(5,("path=%s status_len=%d\n",path,status_len));
862
863   
864   if (status_len == 0)
865     {
866       pstring dir2;
867
868       pstrcpy(directory,smb_buf(inbuf)+1);
869       pstrcpy(dir2,smb_buf(inbuf)+1);
870       unix_convert(directory,cnum,0,&bad_path);
871       unix_format(dir2);
872
873       if (!check_name(directory,cnum))
874         can_open = False;
875
876       p = strrchr(dir2,'/');
877       if (p == NULL) 
878       {
879         strcpy(mask,dir2);
880         *dir2 = 0;
881       }
882       else
883       {
884         *p = 0;
885         pstrcpy(mask,p+1);
886       }
887
888       p = strrchr(directory,'/');
889       if (!p) 
890         *directory = 0;
891       else
892         *p = 0;
893
894       if (strlen(directory) == 0)
895         strcpy(directory,"./");
896       bzero(status,21);
897       CVAL(status,0) = dirtype;
898     }
899   else
900     {
901       memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
902       memcpy(mask,status+1,11);
903       mask[11] = 0;
904       dirtype = CVAL(status,0) & 0x1F;
905       Connections[cnum].dirptr = dptr_fetch(status+12,&dptr_num);      
906       if (!Connections[cnum].dirptr)
907         goto SearchEmpty;
908       string_set(&Connections[cnum].dirpath,dptr_path(dptr_num));
909       if (!case_sensitive)
910         strnorm(mask);
911     }
912
913   /* turn strings of spaces into a . */  
914   {
915     trim_string(mask,NULL," ");
916     if ((p = strrchr(mask,' ')))
917       {
918         fstring ext;
919         fstrcpy(ext,p+1);
920         *p = 0;
921         trim_string(mask,NULL," ");
922         strcat(mask,".");
923         strcat(mask,ext);
924       }
925   }
926
927   {
928     for (p=mask; *p; p++)
929       {
930         if (*p != '?' && *p != '*' && !isdoschar(*p))
931           {
932             DEBUG(5,("Invalid char [%c] in search mask?\n",*p));
933             *p = '?';
934           }
935       }
936   }
937
938   if (!strchr(mask,'.') && strlen(mask)>8)
939     {
940       fstring tmp;
941       fstrcpy(tmp,&mask[8]);
942       mask[8] = '.';
943       mask[9] = 0;
944       strcat(mask,tmp);
945     }
946
947   DEBUG(5,("mask=%s directory=%s\n",mask,directory));
948   
949   if (can_open)
950     {
951       p = smb_buf(outbuf) + 3;
952       
953       ok = True;
954       
955       if (status_len == 0)
956         {
957           dptr_num = dptr_create(cnum,directory,expect_close,SVAL(inbuf,smb_pid));
958           if (dptr_num < 0)
959         {
960           if(dptr_num == -2)
961           {
962             if((errno == ENOENT) && bad_path)
963             {
964               unix_ERR_class = ERRDOS;
965               unix_ERR_code = ERRbadpath;
966             }
967             return (UNIXERROR(ERRDOS,ERRnofids));
968           }
969           return(ERROR(ERRDOS,ERRnofids));
970         }
971         }
972
973       DEBUG(4,("dptr_num is %d\n",dptr_num));
974
975       if (ok)
976         {
977           if ((dirtype&0x1F) == aVOLID)
978             {     
979               memcpy(p,status,21);
980               make_dir_struct(p,"???????????",volume_label(SNUM(cnum)),0,aVOLID,0);
981               dptr_fill(p+12,dptr_num);
982               if (dptr_zero(p+12) && (status_len==0))
983                 numentries = 1;
984               else
985                 numentries = 0;
986               p += DIR_STRUCT_SIZE;
987             }
988           else 
989             {
990               DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",Connections[cnum].dirpath,lp_dontdescend(SNUM(cnum))));
991               if (in_list(Connections[cnum].dirpath,
992                           lp_dontdescend(SNUM(cnum)),True))
993                 check_descend = True;
994
995               for (i=numentries;(i<maxentries) && !finished;i++)
996                 {
997                   finished = 
998                     !get_dir_entry(cnum,mask,dirtype,fname,&size,&mode,&date,check_descend);
999                   if (!finished)
1000                     {
1001                       memcpy(p,status,21);
1002                       make_dir_struct(p,mask,fname,size,mode,date);
1003                       dptr_fill(p+12,dptr_num);
1004                       numentries++;
1005                     }
1006                   p += DIR_STRUCT_SIZE;
1007                 }
1008             }
1009         }
1010     }
1011
1012
1013  SearchEmpty:
1014
1015   if (numentries == 0 || !ok)
1016     {
1017       CVAL(outbuf,smb_rcls) = ERRDOS;
1018       SSVAL(outbuf,smb_err,ERRnofiles);
1019     }
1020
1021   /* If we were called as SMBffirst with smb_search_id == NULL
1022      and no entries were found then return error and close dirptr 
1023      (X/Open spec) */
1024
1025   if(ok && expect_close && numentries == 0 && status_len == 0)
1026     {
1027       CVAL(outbuf,smb_rcls) = ERRDOS;
1028       SSVAL(outbuf,smb_err,ERRnofiles);
1029       /* Also close the dptr - we know it's gone */
1030       dptr_close(dptr_num);
1031     }
1032
1033   /* If we were called as SMBfunique, then we can close the dirptr now ! */
1034   if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
1035     dptr_close(dptr_num);
1036
1037   SSVAL(outbuf,smb_vwv0,numentries);
1038   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1039   CVAL(smb_buf(outbuf),0) = 5;
1040   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
1041
1042   if (Protocol >= PROTOCOL_NT1) {
1043     uint16 flg2 = SVAL(outbuf,smb_flg2);
1044     SSVAL(outbuf,smb_flg2,flg2 | 0x40); /* IS_LONG_NAME */
1045   }
1046   
1047   outsize += DIR_STRUCT_SIZE*numentries;
1048   smb_setlen(outbuf,outsize - 4);
1049   
1050   if ((! *directory) && dptr_path(dptr_num))
1051     sprintf(directory,"(%s)",dptr_path(dptr_num));
1052
1053   DEBUG(4,("%s %s mask=%s path=%s cnum=%d dtype=%d nument=%d of %d\n",
1054         timestring(),
1055         smb_fn_name(CVAL(inbuf,smb_com)), 
1056         mask,directory,cnum,dirtype,numentries,maxentries));
1057
1058   return(outsize);
1059 }
1060
1061
1062 /****************************************************************************
1063   reply to a fclose (stop directory search)
1064 ****************************************************************************/
1065 int reply_fclose(char *inbuf,char *outbuf)
1066 {
1067   int cnum;
1068   int outsize = 0;
1069   int status_len;
1070   char *path;
1071   char status[21];
1072   int dptr_num= -1;
1073
1074   cnum = SVAL(inbuf,smb_tid);
1075
1076   outsize = set_message(outbuf,1,0,True);
1077   path = smb_buf(inbuf) + 1;
1078   status_len = SVAL(smb_buf(inbuf),3 + strlen(path));
1079
1080   
1081   if (status_len == 0)
1082     return(ERROR(ERRSRV,ERRsrverror));
1083
1084   memcpy(status,smb_buf(inbuf) + 1 + strlen(path) + 4,21);
1085
1086   if(dptr_fetch(status+12,&dptr_num)) {
1087     /*  Close the dptr - we know it's gone */
1088     dptr_close(dptr_num);
1089   }
1090
1091   SSVAL(outbuf,smb_vwv0,0);
1092
1093   DEBUG(3,("%s search close cnum=%d\n",timestring(),cnum));
1094
1095   return(outsize);
1096 }
1097
1098
1099 /****************************************************************************
1100   reply to an open
1101 ****************************************************************************/
1102 int reply_open(char *inbuf,char *outbuf)
1103 {
1104   pstring fname;
1105   int cnum;
1106   int fnum = -1;
1107   int outsize = 0;
1108   int fmode=0;
1109   int share_mode;
1110   int size = 0;
1111   time_t mtime=0;
1112   int unixmode;
1113   int rmode=0;
1114   struct stat sbuf;
1115   BOOL bad_path = False;
1116   files_struct *fsp;
1117   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1118  
1119   cnum = SVAL(inbuf,smb_tid);
1120
1121   share_mode = SVAL(inbuf,smb_vwv0);
1122
1123   pstrcpy(fname,smb_buf(inbuf)+1);
1124   unix_convert(fname,cnum,0,&bad_path);
1125     
1126   fnum = find_free_file();
1127   if (fnum < 0)
1128     return(ERROR(ERRSRV,ERRnofids));
1129
1130   if (!check_name(fname,cnum))
1131   {
1132     if((errno == ENOENT) && bad_path)
1133     {
1134       unix_ERR_class = ERRDOS;
1135       unix_ERR_code = ERRbadpath;
1136     }
1137     return(UNIXERROR(ERRDOS,ERRnoaccess));
1138   }
1139  
1140   unixmode = unix_mode(cnum,aARCH);
1141       
1142   open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,
1143                    oplock_request,&rmode,NULL);
1144
1145   fsp = &Files[fnum];
1146
1147   if (!fsp->open)
1148   {
1149     if((errno == ENOENT) && bad_path)
1150     {
1151       unix_ERR_class = ERRDOS;
1152       unix_ERR_code = ERRbadpath;
1153     }
1154     return(UNIXERROR(ERRDOS,ERRnoaccess));
1155   }
1156
1157   if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
1158     close_file(fnum);
1159     return(ERROR(ERRDOS,ERRnoaccess));
1160   }
1161     
1162   size = sbuf.st_size;
1163   fmode = dos_mode(cnum,fname,&sbuf);
1164   mtime = sbuf.st_mtime;
1165
1166   if (fmode & aDIR) {
1167     DEBUG(3,("attempt to open a directory %s\n",fname));
1168     close_file(fnum);
1169     return(ERROR(ERRDOS,ERRnoaccess));
1170   }
1171   
1172   outsize = set_message(outbuf,7,0,True);
1173   SSVAL(outbuf,smb_vwv0,fnum);
1174   SSVAL(outbuf,smb_vwv1,fmode);
1175   put_dos_date3(outbuf,smb_vwv2,mtime);
1176   SIVAL(outbuf,smb_vwv4,size);
1177   SSVAL(outbuf,smb_vwv6,rmode);
1178
1179   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1180     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1181   }
1182     
1183   if(fsp->granted_oplock)
1184     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1185   return(outsize);
1186 }
1187
1188
1189 /****************************************************************************
1190   reply to an open and X
1191 ****************************************************************************/
1192 int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
1193 {
1194   pstring fname;
1195   int cnum = SVAL(inbuf,smb_tid);
1196   int fnum = -1;
1197   int smb_mode = SVAL(inbuf,smb_vwv3);
1198   int smb_attr = SVAL(inbuf,smb_vwv5);
1199   BOOL oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
1200 #if 0
1201   int open_flags = SVAL(inbuf,smb_vwv2);
1202   int smb_sattr = SVAL(inbuf,smb_vwv4); 
1203   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
1204 #endif
1205   int smb_ofun = SVAL(inbuf,smb_vwv8);
1206   int unixmode;
1207   int size=0,fmode=0,mtime=0,rmode=0;
1208   struct stat sbuf;
1209   int smb_action = 0;
1210   BOOL bad_path = False;
1211   files_struct *fsp;
1212
1213   /* If it's an IPC, pass off the pipe handler. */
1214   if (IS_IPC(cnum))
1215     return reply_open_pipe_and_X(inbuf,outbuf,length,bufsize);
1216
1217   /* XXXX we need to handle passed times, sattr and flags */
1218
1219   pstrcpy(fname,smb_buf(inbuf));
1220   unix_convert(fname,cnum,0,&bad_path);
1221     
1222   fnum = find_free_file();
1223   if (fnum < 0)
1224     return(ERROR(ERRSRV,ERRnofids));
1225
1226   if (!check_name(fname,cnum))
1227   {
1228     if((errno == ENOENT) && bad_path)
1229     {
1230       unix_ERR_class = ERRDOS;
1231       unix_ERR_code = ERRbadpath;
1232     }
1233     return(UNIXERROR(ERRDOS,ERRnoaccess));
1234   }
1235
1236   unixmode = unix_mode(cnum,smb_attr | aARCH);
1237       
1238   open_file_shared(fnum,cnum,fname,smb_mode,smb_ofun,unixmode,
1239                    oplock_request, &rmode,&smb_action);
1240       
1241   fsp = &Files[fnum];
1242
1243   if (!fsp->open)
1244   {
1245     if((errno == ENOENT) && bad_path)
1246     {
1247       unix_ERR_class = ERRDOS;
1248       unix_ERR_code = ERRbadpath;
1249     }
1250     return(UNIXERROR(ERRDOS,ERRnoaccess));
1251   }
1252
1253   if (fstat(fsp->fd_ptr->fd,&sbuf) != 0) {
1254     close_file(fnum);
1255     return(ERROR(ERRDOS,ERRnoaccess));
1256   }
1257
1258   size = sbuf.st_size;
1259   fmode = dos_mode(cnum,fname,&sbuf);
1260   mtime = sbuf.st_mtime;
1261   if (fmode & aDIR) {
1262     close_file(fnum);
1263     return(ERROR(ERRDOS,ERRnoaccess));
1264   }
1265
1266   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1267     smb_action |= EXTENDED_OPLOCK_GRANTED;
1268     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1269   }
1270
1271   if(fsp->granted_oplock) {
1272     smb_action |= EXTENDED_OPLOCK_GRANTED;
1273     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1274   }
1275
1276   set_message(outbuf,15,0,True);
1277   SSVAL(outbuf,smb_vwv2,fnum);
1278   SSVAL(outbuf,smb_vwv3,fmode);
1279   put_dos_date3(outbuf,smb_vwv4,mtime);
1280   SIVAL(outbuf,smb_vwv6,size);
1281   SSVAL(outbuf,smb_vwv8,rmode);
1282   SSVAL(outbuf,smb_vwv11,smb_action);
1283
1284   chain_fnum = fnum;
1285
1286   return chain_reply(inbuf,outbuf,length,bufsize);
1287 }
1288
1289
1290 /****************************************************************************
1291   reply to a SMBulogoffX
1292 ****************************************************************************/
1293 int reply_ulogoffX(char *inbuf,char *outbuf,int length,int bufsize)
1294 {
1295   uint16 vuid = SVAL(inbuf,smb_uid);
1296   user_struct *vuser = get_valid_user_struct(vuid);
1297
1298   if(vuser == 0) {
1299     DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
1300   }
1301
1302   /* in user level security we are supposed to close any files
1303      open by this user */
1304   if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
1305     int i;
1306     for (i=0;i<MAX_OPEN_FILES;i++)
1307       if (Files[i].uid == vuser->uid && Files[i].open) {
1308         close_file(i);
1309       }
1310   }
1311
1312   invalidate_vuid(vuid);
1313
1314   set_message(outbuf,2,0,True);
1315
1316   DEBUG(3,("%s ulogoffX vuid=%d\n",timestring(),vuid));
1317
1318   return chain_reply(inbuf,outbuf,length,bufsize);
1319 }
1320
1321
1322 /****************************************************************************
1323   reply to a mknew or a create
1324 ****************************************************************************/
1325 int reply_mknew(char *inbuf,char *outbuf)
1326 {
1327   pstring fname;
1328   int cnum,com;
1329   int fnum = -1;
1330   int outsize = 0;
1331   int createmode;
1332   mode_t unixmode;
1333   int ofun = 0;
1334   BOOL bad_path = False;
1335   files_struct *fsp;
1336   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1337  
1338   com = SVAL(inbuf,smb_com);
1339   cnum = SVAL(inbuf,smb_tid);
1340
1341   createmode = SVAL(inbuf,smb_vwv0);
1342   pstrcpy(fname,smb_buf(inbuf)+1);
1343   unix_convert(fname,cnum,0,&bad_path);
1344
1345   if (createmode & aVOLID)
1346     {
1347       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1348     }
1349   
1350   unixmode = unix_mode(cnum,createmode);
1351   
1352   fnum = find_free_file();
1353   if (fnum < 0)
1354     return(ERROR(ERRSRV,ERRnofids));
1355
1356   if (!check_name(fname,cnum))
1357   {
1358     if((errno == ENOENT) && bad_path)
1359     {
1360       unix_ERR_class = ERRDOS;
1361       unix_ERR_code = ERRbadpath;
1362     }
1363     return(UNIXERROR(ERRDOS,ERRnoaccess));
1364   }
1365
1366   if(com == SMBmknew)
1367   {
1368     /* We should fail if file exists. */
1369     ofun = 0x10;
1370   }
1371   else
1372   {
1373     /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1374     ofun = 0x12;
1375   }
1376
1377   /* Open file in dos compatibility share mode. */
1378   open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, 
1379                    oplock_request, NULL, NULL);
1380   
1381   fsp = &Files[fnum];
1382
1383   if (!fsp->open)
1384   {
1385     if((errno == ENOENT) && bad_path) 
1386     {
1387       unix_ERR_class = ERRDOS;
1388       unix_ERR_code = ERRbadpath;
1389     }
1390     return(UNIXERROR(ERRDOS,ERRnoaccess));
1391   }
1392  
1393   outsize = set_message(outbuf,1,0,True);
1394   SSVAL(outbuf,smb_vwv0,fnum);
1395
1396   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1397     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1398   }
1399  
1400   if(fsp->granted_oplock)
1401     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1402  
1403   DEBUG(2,("new file %s\n",fname));
1404   DEBUG(3,("%s mknew %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode));
1405   
1406   return(outsize);
1407 }
1408
1409
1410 /****************************************************************************
1411   reply to a create temporary file
1412 ****************************************************************************/
1413 int reply_ctemp(char *inbuf,char *outbuf)
1414 {
1415   pstring fname;
1416   pstring fname2;
1417   int cnum;
1418   int fnum = -1;
1419   int outsize = 0;
1420   int createmode;
1421   mode_t unixmode;
1422   BOOL bad_path = False;
1423   files_struct *fsp;
1424   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1425  
1426   cnum = SVAL(inbuf,smb_tid);
1427   createmode = SVAL(inbuf,smb_vwv0);
1428   pstrcpy(fname,smb_buf(inbuf)+1);
1429   strcat(fname,"/TMXXXXXX");
1430   unix_convert(fname,cnum,0,&bad_path);
1431   
1432   unixmode = unix_mode(cnum,createmode);
1433   
1434   fnum = find_free_file();
1435   if (fnum < 0)
1436     return(ERROR(ERRSRV,ERRnofids));
1437
1438   if (!check_name(fname,cnum))
1439   {
1440     if((errno == ENOENT) && bad_path)
1441     {
1442       unix_ERR_class = ERRDOS;
1443       unix_ERR_code = ERRbadpath;
1444     }
1445     return(UNIXERROR(ERRDOS,ERRnoaccess));
1446   }
1447
1448   strcpy(fname2,(char *)mktemp(fname));
1449
1450   /* Open file in dos compatibility share mode. */
1451   /* We should fail if file exists. */
1452   open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, 
1453                    oplock_request, NULL, NULL);
1454
1455   fsp = &Files[fnum];
1456
1457   if (!fsp->open)
1458   {
1459     if((errno == ENOENT) && bad_path)
1460     {
1461       unix_ERR_class = ERRDOS;
1462       unix_ERR_code = ERRbadpath;
1463     }
1464     return(UNIXERROR(ERRDOS,ERRnoaccess));
1465   }
1466
1467   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
1468   SSVAL(outbuf,smb_vwv0,fnum);
1469   CVAL(smb_buf(outbuf),0) = 4;
1470   strcpy(smb_buf(outbuf) + 1,fname2);
1471
1472   if (oplock_request && lp_fake_oplocks(SNUM(cnum))) {
1473     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1474   }
1475   
1476   if(fsp->granted_oplock)
1477     CVAL(outbuf,smb_flg) |= CORE_OPLOCK_GRANTED;
1478
1479   DEBUG(2,("created temp file %s\n",fname2));
1480   DEBUG(3,("%s ctemp %s fd=%d fnum=%d cnum=%d dmode=%d umode=%o\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum,createmode,unixmode));
1481   
1482   return(outsize);
1483 }
1484
1485
1486 /*******************************************************************
1487 check if a user is allowed to delete a file
1488 ********************************************************************/
1489 static BOOL can_delete(char *fname,int cnum,int dirtype)
1490 {
1491   struct stat sbuf;
1492   int fmode;
1493
1494   if (!CAN_WRITE(cnum)) return(False);
1495
1496   if (sys_lstat(fname,&sbuf) != 0) return(False);
1497   fmode = dos_mode(cnum,fname,&sbuf);
1498   if (fmode & aDIR) return(False);
1499   if (!lp_delete_readonly(SNUM(cnum))) {
1500     if (fmode & aRONLY) return(False);
1501   }
1502   if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1503     return(False);
1504   if (!check_file_sharing(cnum,fname)) return(False);
1505   return(True);
1506 }
1507
1508 /****************************************************************************
1509   reply to a unlink
1510 ****************************************************************************/
1511 int reply_unlink(char *inbuf,char *outbuf)
1512 {
1513   int outsize = 0;
1514   pstring name;
1515   int cnum;
1516   int dirtype;
1517   pstring directory;
1518   pstring mask;
1519   char *p;
1520   int count=0;
1521   int error = ERRnoaccess;
1522   BOOL has_wild;
1523   BOOL exists=False;
1524   BOOL bad_path = False;
1525
1526   *directory = *mask = 0;
1527
1528   cnum = SVAL(inbuf,smb_tid);
1529   dirtype = SVAL(inbuf,smb_vwv0);
1530   
1531   pstrcpy(name,smb_buf(inbuf) + 1);
1532    
1533   DEBUG(3,("reply_unlink : %s\n",name));
1534    
1535   unix_convert(name,cnum,0,&bad_path);
1536
1537   p = strrchr(name,'/');
1538   if (!p) {
1539     strcpy(directory,"./");
1540     strcpy(mask,name);
1541   } else {
1542     *p = 0;
1543     strcpy(directory,name);
1544     strcpy(mask,p+1);
1545   }
1546
1547   if (is_mangled(mask))
1548     check_mangled_stack(mask);
1549
1550   has_wild = strchr(mask,'*') || strchr(mask,'?');
1551
1552   if (!has_wild) {
1553     strcat(directory,"/");
1554     strcat(directory,mask);
1555     if (can_delete(directory,cnum,dirtype) && !sys_unlink(directory)) count++;
1556     if (!count) exists = file_exist(directory,NULL);    
1557   } else {
1558     void *dirptr = NULL;
1559     char *dname;
1560
1561     if (check_name(directory,cnum))
1562       dirptr = OpenDir(cnum, directory, True);
1563
1564     /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
1565        the pattern matches against the long name, otherwise the short name 
1566        We don't implement this yet XXXX
1567        */
1568
1569     if (dirptr)
1570       {
1571         error = ERRbadfile;
1572
1573         if (strequal(mask,"????????.???"))
1574           strcpy(mask,"*");
1575
1576         while ((dname = ReadDirName(dirptr)))
1577           {
1578             pstring fname;
1579             pstrcpy(fname,dname);
1580             
1581             if(!mask_match(fname, mask, case_sensitive, False)) continue;
1582
1583             error = ERRnoaccess;
1584             sprintf(fname,"%s/%s",directory,dname);
1585             if (!can_delete(fname,cnum,dirtype)) continue;
1586             if (!sys_unlink(fname)) count++;
1587             DEBUG(3,("reply_unlink : doing unlink on %s\n",fname));
1588           }
1589         CloseDir(dirptr);
1590       }
1591   }
1592   
1593   if (count == 0) {
1594     if (exists)
1595       return(ERROR(ERRDOS,error));
1596     else
1597     {
1598       if((errno == ENOENT) && bad_path)
1599       {
1600         unix_ERR_class = ERRDOS;
1601         unix_ERR_code = ERRbadpath;
1602       }
1603       return(UNIXERROR(ERRDOS,error));
1604     }
1605   }
1606   
1607   outsize = set_message(outbuf,0,0,True);
1608   
1609   return(outsize);
1610 }
1611
1612
1613 /****************************************************************************
1614    reply to a readbraw (core+ protocol)
1615 ****************************************************************************/
1616 int reply_readbraw(char *inbuf, char *outbuf)
1617 {
1618   int cnum,maxcount,mincount,fnum;
1619   int nread = 0;
1620   uint32 startpos;
1621   char *header = outbuf;
1622   int ret=0;
1623   int fd;
1624   char *fname;
1625
1626   /*
1627    * Special check if an oplock break has been issued
1628    * and the readraw request croses on the wire, we must
1629    * return a zero length response here.
1630    */
1631
1632   if(global_oplock_break)
1633   {
1634     _smb_setlen(header,0);
1635     transfer_file(0,Client,0,header,4,0);
1636     DEBUG(5,("readbraw - oplock break finished\n"));
1637     return -1;
1638   }
1639
1640   cnum = SVAL(inbuf,smb_tid);
1641   fnum = GETFNUM(inbuf,smb_vwv0);
1642
1643   startpos = IVAL(inbuf,smb_vwv1);
1644   maxcount = SVAL(inbuf,smb_vwv3);
1645   mincount = SVAL(inbuf,smb_vwv4);
1646
1647   /* ensure we don't overrun the packet size */
1648   maxcount = MIN(65535,maxcount);
1649   maxcount = MAX(mincount,maxcount);
1650
1651   if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read)
1652     {
1653       DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum));
1654       _smb_setlen(header,0);
1655       transfer_file(0,Client,0,header,4,0);
1656       return(-1);
1657     }
1658   else
1659     {
1660       fd = Files[fnum].fd_ptr->fd;
1661       fname = Files[fnum].name;
1662     }
1663
1664
1665   if (!is_locked(fnum,cnum,maxcount,startpos))
1666     {
1667       int size = Files[fnum].size;
1668       int sizeneeded = startpos + maxcount;
1669             
1670       if (size < sizeneeded) {
1671         struct stat st;
1672         if (fstat(Files[fnum].fd_ptr->fd,&st) == 0)
1673           size = st.st_size;
1674         if (!Files[fnum].can_write) 
1675           Files[fnum].size = size;
1676       }
1677
1678       nread = MIN(maxcount,(int)(size - startpos));       
1679     }
1680
1681   if (nread < mincount)
1682     nread = 0;
1683   
1684   DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n",
1685            timestring(),
1686            fnum,cnum,startpos,
1687            maxcount,mincount,nread));
1688   
1689 #if UNSAFE_READRAW
1690   {
1691     int predict=0;
1692     _smb_setlen(header,nread);
1693
1694     if (!Files[fnum].can_write)
1695       predict = read_predict(fd,startpos,header+4,NULL,nread);
1696
1697     if ((nread-predict) > 0)
1698       seek_file(fnum,startpos + predict);
1699     
1700     ret = transfer_file(fd,Client,nread-predict,header,4+predict,
1701                         startpos+predict);
1702   }
1703
1704   if (ret != nread+4)
1705     DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
1706              fname,startpos,nread,ret));
1707
1708 #else
1709   ret = read_file(fnum,header+4,startpos,nread);
1710   if (ret < mincount) ret = 0;
1711
1712   _smb_setlen(header,ret);
1713   transfer_file(0,Client,0,header,4+ret,0);
1714 #endif
1715
1716   DEBUG(5,("readbraw finished\n"));
1717   return -1;
1718 }
1719
1720
1721 /****************************************************************************
1722   reply to a lockread (core+ protocol)
1723 ****************************************************************************/
1724 int reply_lockread(char *inbuf,char *outbuf)
1725 {
1726   int cnum,fnum;
1727   int nread = -1;
1728   char *data;
1729   int outsize = 0;
1730   uint32 startpos, numtoread;
1731   int eclass;
1732   uint32 ecode;
1733   
1734   cnum = SVAL(inbuf,smb_tid);
1735   fnum = GETFNUM(inbuf,smb_vwv0);
1736
1737   CHECK_FNUM(fnum,cnum);
1738   CHECK_READ(fnum);
1739   CHECK_ERROR(fnum);
1740
1741   numtoread = SVAL(inbuf,smb_vwv1);
1742   startpos = IVAL(inbuf,smb_vwv2);
1743   
1744   outsize = set_message(outbuf,5,3,True);
1745   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1746   data = smb_buf(outbuf) + 3;
1747   
1748   if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
1749     return (ERROR(eclass,ecode));
1750
1751   nread = read_file(fnum,data,startpos,numtoread);
1752   
1753   if (nread < 0)
1754     return(UNIXERROR(ERRDOS,ERRnoaccess));
1755   
1756   outsize += nread;
1757   SSVAL(outbuf,smb_vwv0,nread);
1758   SSVAL(outbuf,smb_vwv5,nread+3);
1759   SSVAL(smb_buf(outbuf),1,nread);
1760   
1761   DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1762   
1763   return(outsize);
1764 }
1765
1766
1767 /****************************************************************************
1768   reply to a read
1769 ****************************************************************************/
1770 int reply_read(char *inbuf,char *outbuf)
1771 {
1772   int cnum,numtoread,fnum;
1773   int nread = 0;
1774   char *data;
1775   uint32 startpos;
1776   int outsize = 0;
1777   
1778   cnum = SVAL(inbuf,smb_tid);
1779   fnum = GETFNUM(inbuf,smb_vwv0);
1780
1781   CHECK_FNUM(fnum,cnum);
1782   CHECK_READ(fnum);
1783   CHECK_ERROR(fnum);
1784
1785   numtoread = SVAL(inbuf,smb_vwv1);
1786   startpos = IVAL(inbuf,smb_vwv2);
1787   
1788   outsize = set_message(outbuf,5,3,True);
1789   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1790   data = smb_buf(outbuf) + 3;
1791   
1792   if (is_locked(fnum,cnum,numtoread,startpos))
1793     return(ERROR(ERRDOS,ERRlock));      
1794
1795   if (numtoread > 0)
1796     nread = read_file(fnum,data,startpos,numtoread);
1797   
1798   if (nread < 0)
1799     return(UNIXERROR(ERRDOS,ERRnoaccess));
1800   
1801   outsize += nread;
1802   SSVAL(outbuf,smb_vwv0,nread);
1803   SSVAL(outbuf,smb_vwv5,nread+3);
1804   CVAL(smb_buf(outbuf),0) = 1;
1805   SSVAL(smb_buf(outbuf),1,nread);
1806   
1807   DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1808   
1809   return(outsize);
1810 }
1811
1812
1813 /****************************************************************************
1814   reply to a read and X
1815 ****************************************************************************/
1816 int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
1817 {
1818   int fnum = GETFNUM(inbuf,smb_vwv2);
1819   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
1820   int smb_maxcnt = SVAL(inbuf,smb_vwv5);
1821   int smb_mincnt = SVAL(inbuf,smb_vwv6);
1822   int cnum;
1823   int nread = -1;
1824   char *data;
1825   BOOL ok = False;
1826
1827   cnum = SVAL(inbuf,smb_tid);
1828
1829   CHECK_FNUM(fnum,cnum);
1830   CHECK_READ(fnum);
1831   CHECK_ERROR(fnum);
1832
1833   set_message(outbuf,12,0,True);
1834   data = smb_buf(outbuf);
1835
1836   if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
1837     return(ERROR(ERRDOS,ERRlock));
1838   nread = read_file(fnum,data,smb_offs,smb_maxcnt);
1839   ok = True;
1840   
1841   if (nread < 0)
1842     return(UNIXERROR(ERRDOS,ERRnoaccess));
1843   
1844   SSVAL(outbuf,smb_vwv5,nread);
1845   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
1846   SSVAL(smb_buf(outbuf),-2,nread);
1847   
1848   DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d\n",
1849         timestring(),fnum,cnum,
1850         smb_mincnt,smb_maxcnt,nread));
1851
1852   chain_fnum = fnum;
1853
1854   return chain_reply(inbuf,outbuf,length,bufsize);
1855 }
1856
1857
1858 /****************************************************************************
1859   reply to a writebraw (core+ or LANMAN1.0 protocol)
1860 ****************************************************************************/
1861 int reply_writebraw(char *inbuf,char *outbuf)
1862 {
1863   int nwritten=0;
1864   int total_written=0;
1865   int numtowrite=0;
1866   int cnum,fnum;
1867   int outsize = 0;
1868   long startpos;
1869   char *data=NULL;
1870   BOOL write_through;
1871   int tcount;
1872
1873   cnum = SVAL(inbuf,smb_tid);
1874   fnum = GETFNUM(inbuf,smb_vwv0);
1875
1876   CHECK_FNUM(fnum,cnum);
1877   CHECK_WRITE(fnum);
1878   CHECK_ERROR(fnum);
1879   
1880   tcount = IVAL(inbuf,smb_vwv1);
1881   startpos = IVAL(inbuf,smb_vwv3);
1882   write_through = BITSETW(inbuf+smb_vwv7,0);
1883
1884   /* We have to deal with slightly different formats depending
1885      on whether we are using the core+ or lanman1.0 protocol */
1886   if(Protocol <= PROTOCOL_COREPLUS) {
1887     numtowrite = SVAL(smb_buf(inbuf),-2);
1888     data = smb_buf(inbuf);
1889   } else {
1890     numtowrite = SVAL(inbuf,smb_vwv10);
1891     data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
1892   }
1893
1894   /* force the error type */
1895   CVAL(inbuf,smb_com) = SMBwritec;
1896   CVAL(outbuf,smb_com) = SMBwritec;
1897
1898   if (is_locked(fnum,cnum,tcount,startpos))
1899     return(ERROR(ERRDOS,ERRlock));
1900
1901   if (seek_file(fnum,startpos) != startpos)
1902     DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
1903
1904   if (numtowrite>0)
1905     nwritten = write_file(fnum,data,numtowrite);
1906   
1907   DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n",
1908            timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through));
1909
1910   if (nwritten < numtowrite) 
1911     return(UNIXERROR(ERRHRD,ERRdiskfull));
1912
1913   total_written = nwritten;
1914
1915   /* Return a message to the redirector to tell it
1916      to send more bytes */
1917   CVAL(outbuf,smb_com) = SMBwritebraw;
1918   SSVALS(outbuf,smb_vwv0,-1);
1919   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
1920   send_smb(Client,outbuf);
1921   
1922   /* Now read the raw data into the buffer and write it */
1923   if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
1924     exit_server("secondary writebraw failed");
1925   }
1926   
1927   /* Even though this is not an smb message, smb_len
1928      returns the generic length of an smb message */
1929   numtowrite = smb_len(inbuf);
1930
1931   if (tcount > nwritten+numtowrite) {
1932     DEBUG(3,("Client overestimated the write %d %d %d\n",
1933              tcount,nwritten,numtowrite));
1934   }
1935
1936   nwritten = transfer_file(Client,Files[fnum].fd_ptr->fd,numtowrite,NULL,0,
1937                            startpos+nwritten);
1938   total_written += nwritten;
1939   
1940   /* Set up outbuf to return the correct return */
1941   outsize = set_message(outbuf,1,0,True);
1942   CVAL(outbuf,smb_com) = SMBwritec;
1943   SSVAL(outbuf,smb_vwv0,total_written);
1944
1945   if (nwritten < numtowrite) {
1946     CVAL(outbuf,smb_rcls) = ERRHRD;
1947     SSVAL(outbuf,smb_err,ERRdiskfull);      
1948   }
1949
1950   if (lp_syncalways(SNUM(cnum)) || write_through)
1951     sync_file(fnum);
1952
1953   DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
1954            timestring(),fnum,cnum,startpos,numtowrite,total_written));
1955
1956   /* we won't return a status if write through is not selected - this 
1957      follows what WfWg does */
1958   if (!write_through && total_written==tcount)
1959     return(-1);
1960
1961   return(outsize);
1962 }
1963
1964
1965 /****************************************************************************
1966   reply to a writeunlock (core+)
1967 ****************************************************************************/
1968 int reply_writeunlock(char *inbuf,char *outbuf)
1969 {
1970   int cnum,fnum;
1971   int nwritten = -1;
1972   int outsize = 0;
1973   char *data;
1974   uint32 numtowrite,startpos;
1975   int eclass;
1976   uint32 ecode;
1977   
1978   cnum = SVAL(inbuf,smb_tid);
1979   fnum = GETFNUM(inbuf,smb_vwv0);
1980
1981   CHECK_FNUM(fnum,cnum);
1982   CHECK_WRITE(fnum);
1983   CHECK_ERROR(fnum);
1984
1985   numtowrite = SVAL(inbuf,smb_vwv1);
1986   startpos = IVAL(inbuf,smb_vwv2);
1987   data = smb_buf(inbuf) + 3;
1988   
1989   if (is_locked(fnum,cnum,numtowrite,startpos))
1990     return(ERROR(ERRDOS,ERRlock));
1991
1992   seek_file(fnum,startpos);
1993
1994   /* The special X/Open SMB protocol handling of
1995      zero length writes is *NOT* done for
1996      this call */
1997   if(numtowrite == 0)
1998     nwritten = 0;
1999   else
2000     nwritten = write_file(fnum,data,numtowrite);
2001   
2002   if (lp_syncalways(SNUM(cnum)))
2003     sync_file(fnum);
2004
2005   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2006     return(UNIXERROR(ERRDOS,ERRnoaccess));
2007
2008   if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode))
2009     return(ERROR(eclass,ecode));
2010
2011   outsize = set_message(outbuf,1,0,True);
2012   
2013   SSVAL(outbuf,smb_vwv0,nwritten);
2014   
2015   DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n",
2016            timestring(),fnum,cnum,numtowrite,nwritten));
2017   
2018   return(outsize);
2019 }
2020
2021
2022 /****************************************************************************
2023   reply to a write
2024 ****************************************************************************/
2025 int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
2026 {
2027   int cnum,numtowrite,fnum;
2028   int nwritten = -1;
2029   int outsize = 0;
2030   int startpos;
2031   char *data;
2032
2033   dum1 = dum2 = 0;
2034
2035   
2036   cnum = SVAL(inbuf,smb_tid);
2037   fnum = GETFNUM(inbuf,smb_vwv0);
2038
2039   CHECK_FNUM(fnum,cnum);
2040   CHECK_WRITE(fnum);
2041   CHECK_ERROR(fnum);
2042
2043   numtowrite = SVAL(inbuf,smb_vwv1);
2044   startpos = IVAL(inbuf,smb_vwv2);
2045   data = smb_buf(inbuf) + 3;
2046   
2047   if (is_locked(fnum,cnum,numtowrite,startpos))
2048     return(ERROR(ERRDOS,ERRlock));
2049
2050   seek_file(fnum,startpos);
2051
2052   /* X/Open SMB protocol says that if smb_vwv1 is
2053      zero then the file size should be extended or
2054      truncated to the size given in smb_vwv[2-3] */
2055   if(numtowrite == 0)
2056     nwritten = set_filelen(Files[fnum].fd_ptr->fd, startpos);
2057   else
2058     nwritten = write_file(fnum,data,numtowrite);
2059   
2060   if (lp_syncalways(SNUM(cnum)))
2061     sync_file(fnum);
2062
2063   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2064     return(UNIXERROR(ERRDOS,ERRnoaccess));
2065
2066   outsize = set_message(outbuf,1,0,True);
2067   
2068   SSVAL(outbuf,smb_vwv0,nwritten);
2069
2070   if (nwritten < numtowrite) {
2071     CVAL(outbuf,smb_rcls) = ERRHRD;
2072     SSVAL(outbuf,smb_err,ERRdiskfull);      
2073   }
2074   
2075   DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten));
2076   
2077   return(outsize);
2078 }
2079
2080
2081 /****************************************************************************
2082   reply to a write and X
2083 ****************************************************************************/
2084 int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
2085 {
2086   int fnum = GETFNUM(inbuf,smb_vwv2);
2087   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
2088   int smb_dsize = SVAL(inbuf,smb_vwv10);
2089   int smb_doff = SVAL(inbuf,smb_vwv11);
2090   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2091   int cnum;
2092   int nwritten = -1;
2093   char *data;
2094
2095   cnum = SVAL(inbuf,smb_tid);
2096
2097   CHECK_FNUM(fnum,cnum);
2098   CHECK_WRITE(fnum);
2099   CHECK_ERROR(fnum);
2100
2101   data = smb_base(inbuf) + smb_doff;
2102
2103   if (is_locked(fnum,cnum,smb_dsize,smb_offs))
2104     return(ERROR(ERRDOS,ERRlock));
2105
2106   seek_file(fnum,smb_offs);
2107   
2108   /* X/Open SMB protocol says that, unlike SMBwrite
2109      if the length is zero then NO truncation is
2110      done, just a write of zero. To truncate a file,
2111      use SMBwrite. */
2112   if(smb_dsize == 0)
2113     nwritten = 0;
2114   else
2115     nwritten = write_file(fnum,data,smb_dsize);
2116   
2117   if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
2118     return(UNIXERROR(ERRDOS,ERRnoaccess));
2119
2120   set_message(outbuf,6,0,True);
2121   
2122   SSVAL(outbuf,smb_vwv2,nwritten);
2123   
2124   if (nwritten < smb_dsize) {
2125     CVAL(outbuf,smb_rcls) = ERRHRD;
2126     SSVAL(outbuf,smb_err,ERRdiskfull);      
2127   }
2128
2129   DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten));
2130
2131   chain_fnum = fnum;
2132
2133   if (lp_syncalways(SNUM(cnum)) || write_through)
2134     sync_file(fnum);
2135
2136   return chain_reply(inbuf,outbuf,length,bufsize);
2137 }
2138
2139
2140 /****************************************************************************
2141   reply to a lseek
2142 ****************************************************************************/
2143 int reply_lseek(char *inbuf,char *outbuf)
2144 {
2145   int cnum,fnum;
2146   uint32 startpos;
2147   int32 res= -1;
2148   int mode,umode;
2149   int outsize = 0;
2150   
2151   cnum = SVAL(inbuf,smb_tid);
2152   fnum = GETFNUM(inbuf,smb_vwv0);
2153
2154   CHECK_FNUM(fnum,cnum);
2155   CHECK_ERROR(fnum);
2156
2157   mode = SVAL(inbuf,smb_vwv1) & 3;
2158   startpos = IVAL(inbuf,smb_vwv2);
2159
2160   switch (mode & 3) 
2161     {
2162     case 0: umode = SEEK_SET; break;
2163     case 1: umode = SEEK_CUR; break;
2164     case 2: umode = SEEK_END; break;
2165     default:
2166       umode = SEEK_SET; break;
2167     }
2168   
2169   res = lseek(Files[fnum].fd_ptr->fd,startpos,umode);
2170   Files[fnum].pos = res;
2171   
2172   outsize = set_message(outbuf,2,0,True);
2173   SIVALS(outbuf,smb_vwv0,res);
2174   
2175   DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode));
2176   
2177   return(outsize);
2178 }
2179
2180
2181 /****************************************************************************
2182   reply to a flush
2183 ****************************************************************************/
2184 int reply_flush(char *inbuf,char *outbuf)
2185 {
2186   int cnum, fnum;
2187   int outsize = set_message(outbuf,0,0,True);
2188
2189   cnum = SVAL(inbuf,smb_tid);
2190   fnum = GETFNUM(inbuf,smb_vwv0);
2191
2192   if (fnum != 0xFFFF) {
2193     CHECK_FNUM(fnum,cnum);
2194     CHECK_ERROR(fnum);
2195   }
2196
2197   if (fnum == 0xFFFF)
2198     {
2199       int i;
2200       for (i=0;i<MAX_OPEN_FILES;i++)
2201         if (OPEN_FNUM(i))
2202           sync_file(i);
2203     }
2204   else
2205     sync_file(fnum);
2206
2207   DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
2208   return(outsize);
2209 }
2210
2211
2212 /****************************************************************************
2213   reply to a exit
2214 ****************************************************************************/
2215 int reply_exit(char *inbuf,char *outbuf)
2216 {
2217   int outsize = set_message(outbuf,0,0,True);
2218   DEBUG(3,("%s exit\n",timestring()));
2219   
2220   return(outsize);
2221 }
2222
2223
2224 /****************************************************************************
2225   reply to a close
2226 ****************************************************************************/
2227 int reply_close(char *inbuf,char *outbuf)
2228 {
2229   int fnum,cnum;
2230   int outsize = 0;
2231   time_t mtime;
2232   int32 eclass = 0, err = 0;
2233
2234   outsize = set_message(outbuf,0,0,True);
2235
2236   cnum = SVAL(inbuf,smb_tid);
2237
2238   fnum = GETFNUM(inbuf,smb_vwv0);
2239   CHECK_FNUM(fnum,cnum);
2240
2241   if(HAS_CACHED_ERROR(fnum)) {
2242     eclass = Files[fnum].wbmpx_ptr->wr_errclass;
2243     err = Files[fnum].wbmpx_ptr->wr_error;
2244   }
2245
2246   mtime = make_unix_date3(inbuf+smb_vwv1);
2247
2248   /* try and set the date */
2249   set_filetime(Files[fnum].name,mtime);
2250
2251   close_file(fnum);
2252
2253   /* We have a cached error */
2254   if(eclass || err)
2255     return(ERROR(eclass,err));
2256
2257   DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
2258            timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,
2259            Connections[cnum].num_files_open));
2260   
2261   return(outsize);
2262 }
2263
2264
2265 /****************************************************************************
2266   reply to a writeclose (Core+ protocol)
2267 ****************************************************************************/
2268 int reply_writeclose(char *inbuf,char *outbuf)
2269 {
2270   int cnum,numtowrite,fnum;
2271   int nwritten = -1;
2272   int outsize = 0;
2273   int startpos;
2274   char *data;
2275   time_t mtime;
2276   
2277   cnum = SVAL(inbuf,smb_tid);
2278   fnum = GETFNUM(inbuf,smb_vwv0);
2279
2280   CHECK_FNUM(fnum,cnum);
2281   CHECK_WRITE(fnum);
2282   CHECK_ERROR(fnum);
2283
2284   numtowrite = SVAL(inbuf,smb_vwv1);
2285   startpos = IVAL(inbuf,smb_vwv2);
2286   mtime = make_unix_date3(inbuf+smb_vwv4);
2287   data = smb_buf(inbuf) + 1;
2288   
2289   if (is_locked(fnum,cnum,numtowrite,startpos))
2290     return(ERROR(ERRDOS,ERRlock));
2291       
2292   seek_file(fnum,startpos);
2293       
2294   nwritten = write_file(fnum,data,numtowrite);
2295
2296   set_filetime(Files[fnum].name,mtime);
2297   
2298   close_file(fnum);
2299
2300   DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
2301            timestring(),fnum,cnum,numtowrite,nwritten,
2302            Connections[cnum].num_files_open));
2303   
2304   if (nwritten <= 0)
2305     return(UNIXERROR(ERRDOS,ERRnoaccess));
2306   
2307   outsize = set_message(outbuf,1,0,True);
2308   
2309   SSVAL(outbuf,smb_vwv0,nwritten);
2310   return(outsize);
2311 }
2312
2313
2314 /****************************************************************************
2315   reply to a lock
2316 ****************************************************************************/
2317 int reply_lock(char *inbuf,char *outbuf)
2318 {
2319   int fnum,cnum;
2320   int outsize = set_message(outbuf,0,0,True);
2321   uint32 count,offset;
2322   int eclass;
2323   uint32 ecode;
2324
2325   cnum = SVAL(inbuf,smb_tid);
2326   fnum = GETFNUM(inbuf,smb_vwv0);
2327
2328   CHECK_FNUM(fnum,cnum);
2329   CHECK_ERROR(fnum);
2330
2331   count = IVAL(inbuf,smb_vwv1);
2332   offset = IVAL(inbuf,smb_vwv3);
2333
2334   DEBUG(3,("%s lock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count));
2335
2336   if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
2337     return (ERROR(eclass,ecode));
2338   
2339   return(outsize);
2340 }
2341
2342
2343 /****************************************************************************
2344   reply to a unlock
2345 ****************************************************************************/
2346 int reply_unlock(char *inbuf,char *outbuf)
2347 {
2348   int fnum,cnum;
2349   int outsize = set_message(outbuf,0,0,True);
2350   uint32 count,offset;
2351   int eclass;
2352   uint32 ecode;
2353   
2354   cnum = SVAL(inbuf,smb_tid);
2355   fnum = GETFNUM(inbuf,smb_vwv0);
2356
2357   CHECK_FNUM(fnum,cnum);
2358   CHECK_ERROR(fnum);
2359
2360   count = IVAL(inbuf,smb_vwv1);
2361   offset = IVAL(inbuf,smb_vwv3);
2362
2363   if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
2364     return (ERROR(eclass,ecode));
2365
2366   DEBUG(3,("%s unlock fd=%d fnum=%d cnum=%d ofs=%d cnt=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,offset,count));
2367   
2368   return(outsize);
2369 }
2370
2371
2372 /****************************************************************************
2373   reply to a tdis
2374 ****************************************************************************/
2375 int reply_tdis(char *inbuf,char *outbuf)
2376 {
2377   int cnum;
2378   int outsize = set_message(outbuf,0,0,True);
2379   uint16 vuid;
2380
2381   cnum = SVAL(inbuf,smb_tid);
2382   vuid = SVAL(inbuf,smb_uid);
2383
2384   if (!OPEN_CNUM(cnum)) {
2385     DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
2386     return(ERROR(ERRSRV,ERRinvnid));
2387   }
2388
2389   Connections[cnum].used = False;
2390
2391   close_cnum(cnum,vuid);
2392   
2393   DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
2394
2395   return outsize;
2396 }
2397
2398
2399
2400 /****************************************************************************
2401   reply to a echo
2402 ****************************************************************************/
2403 int reply_echo(char *inbuf,char *outbuf)
2404 {
2405   int cnum;
2406   int smb_reverb = SVAL(inbuf,smb_vwv0);
2407   int seq_num;
2408   int data_len = smb_buflen(inbuf);
2409   int outsize = set_message(outbuf,1,data_len,True);
2410
2411   cnum = SVAL(inbuf,smb_tid);
2412
2413   /* According to the latest CIFS spec we shouldn't
2414      care what the TID is.
2415    */
2416
2417 #if 0
2418   if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
2419     {
2420       DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
2421       return(ERROR(ERRSRV,ERRinvnid));
2422     }
2423 #endif
2424
2425   /* copy any incoming data back out */
2426   if (data_len > 0)
2427     memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2428
2429   if (smb_reverb > 100)
2430     {
2431       DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2432       smb_reverb = 100;
2433     }
2434
2435   for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++)
2436     {
2437       SSVAL(outbuf,smb_vwv0,seq_num);
2438
2439       smb_setlen(outbuf,outsize - 4);
2440
2441       send_smb(Client,outbuf);
2442     }
2443
2444   DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
2445
2446   return -1;
2447 }
2448
2449
2450 /****************************************************************************
2451   reply to a printopen
2452 ****************************************************************************/
2453 int reply_printopen(char *inbuf,char *outbuf)
2454 {
2455   pstring fname;
2456   pstring fname2;
2457   int cnum;
2458   int fnum = -1;
2459   int outsize = 0;
2460
2461   *fname = *fname2 = 0;
2462
2463   cnum = SVAL(inbuf,smb_tid);
2464
2465   if (!CAN_PRINT(cnum))
2466     return(ERROR(ERRDOS,ERRnoaccess));
2467
2468   {
2469     pstring s;
2470     char *p;
2471     pstrcpy(s,smb_buf(inbuf)+1);
2472     p = s;
2473     while (*p)
2474       {
2475         if (!(isalnum(*p) || strchr("._-",*p)))
2476           *p = 'X';
2477         p++;
2478       }
2479
2480     if (strlen(s) > 10) s[10] = 0;
2481
2482     sprintf(fname,"%s.XXXXXX",s);  
2483   }
2484
2485   fnum = find_free_file();
2486   if (fnum < 0)
2487     return(ERROR(ERRSRV,ERRnofids));
2488
2489   strcpy(fname2,(char *)mktemp(fname));
2490
2491   if (!check_name(fname2,cnum))
2492     return(ERROR(ERRDOS,ERRnoaccess));
2493
2494   /* Open for exclusive use, write only. */
2495   open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), 
2496                    0, NULL, NULL);
2497
2498   if (!Files[fnum].open)
2499     return(UNIXERROR(ERRDOS,ERRnoaccess));
2500
2501   /* force it to be a print file */
2502   Files[fnum].print_file = True;
2503   
2504   outsize = set_message(outbuf,1,0,True);
2505   SSVAL(outbuf,smb_vwv0,fnum);
2506   
2507   DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum));
2508   
2509   return(outsize);
2510 }
2511
2512
2513 /****************************************************************************
2514   reply to a printclose
2515 ****************************************************************************/
2516 int reply_printclose(char *inbuf,char *outbuf)
2517 {
2518   int fnum,cnum;
2519   int outsize = set_message(outbuf,0,0,True);
2520   
2521   cnum = SVAL(inbuf,smb_tid);
2522   fnum = GETFNUM(inbuf,smb_vwv0);
2523
2524   CHECK_FNUM(fnum,cnum);
2525   CHECK_ERROR(fnum);
2526
2527   if (!CAN_PRINT(cnum))
2528     return(ERROR(ERRDOS,ERRnoaccess));
2529   
2530   close_file(fnum);
2531   
2532   DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum));
2533   
2534   return(outsize);
2535 }
2536
2537
2538 /****************************************************************************
2539   reply to a printqueue
2540 ****************************************************************************/
2541 int reply_printqueue(char *inbuf,char *outbuf)
2542 {
2543   int cnum;
2544   int outsize = set_message(outbuf,2,3,True);
2545   int max_count = SVAL(inbuf,smb_vwv0);
2546   int start_index = SVAL(inbuf,smb_vwv1);
2547   uint16 vuid;
2548
2549   cnum = SVAL(inbuf,smb_tid);
2550   vuid = SVAL(inbuf,smb_uid);
2551
2552 /* allow checking the queue for anyone */
2553 #if 0
2554   if (!CAN_PRINT(cnum))
2555     return(ERROR(ERRDOS,ERRnoaccess));
2556 #endif
2557
2558   SSVAL(outbuf,smb_vwv0,0);
2559   SSVAL(outbuf,smb_vwv1,0);
2560   CVAL(smb_buf(outbuf),0) = 1;
2561   SSVAL(smb_buf(outbuf),1,0);
2562   
2563   DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n",
2564         timestring(),cnum,start_index,max_count));
2565
2566   if (!OPEN_CNUM(cnum) || !Connections[cnum].printer)
2567     {
2568       int i;
2569       cnum = -1;
2570
2571       for (i=0;i<MAX_CONNECTIONS;i++)
2572         if (CAN_PRINT(i) && Connections[i].printer)
2573           cnum = i;
2574
2575       if (cnum == -1)
2576         for (i=0;i<MAX_CONNECTIONS;i++)
2577           if (OPEN_CNUM(i))
2578             cnum = i;
2579
2580       if (!OPEN_CNUM(cnum))
2581         return(ERROR(ERRSRV,ERRinvnid));
2582
2583       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
2584     }
2585
2586   if (!become_user(cnum,vuid))
2587     return(ERROR(ERRSRV,ERRinvnid));
2588
2589   {
2590     print_queue_struct *queue = NULL;
2591     char *p = smb_buf(outbuf) + 3;
2592     int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL);
2593     int num_to_get = ABS(max_count);
2594     int first = (max_count>0?start_index:start_index+max_count+1);
2595     int i;
2596
2597     if (first >= count)
2598       num_to_get = 0;
2599     else
2600       num_to_get = MIN(num_to_get,count-first);
2601     
2602
2603     for (i=first;i<first+num_to_get;i++)
2604       {
2605         put_dos_date2(p,0,queue[i].time);
2606         CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
2607         SSVAL(p,5,printjob_encode(SNUM(cnum), queue[i].job));
2608         SIVAL(p,7,queue[i].size);
2609         CVAL(p,11) = 0;
2610         StrnCpy(p+12,queue[i].user,16);
2611         p += 28;
2612       }
2613
2614     if (count > 0)
2615       {
2616         outsize = set_message(outbuf,2,28*count+3,False);         
2617         SSVAL(outbuf,smb_vwv0,count);
2618         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
2619         CVAL(smb_buf(outbuf),0) = 1;
2620         SSVAL(smb_buf(outbuf),1,28*count);
2621       }
2622
2623     if (queue) free(queue);
2624           
2625     DEBUG(3,("%d entries returned in queue\n",count));
2626   }
2627   
2628   return(outsize);
2629 }
2630
2631
2632 /****************************************************************************
2633   reply to a printwrite
2634 ****************************************************************************/
2635 int reply_printwrite(char *inbuf,char *outbuf)
2636 {
2637   int cnum,numtowrite,fnum;
2638   int outsize = set_message(outbuf,0,0,True);
2639   char *data;
2640   
2641   cnum = SVAL(inbuf,smb_tid);
2642
2643   if (!CAN_PRINT(cnum))
2644     return(ERROR(ERRDOS,ERRnoaccess));
2645
2646   fnum = GETFNUM(inbuf,smb_vwv0);
2647
2648   CHECK_FNUM(fnum,cnum);
2649   CHECK_WRITE(fnum);
2650   CHECK_ERROR(fnum);
2651
2652   numtowrite = SVAL(smb_buf(inbuf),1);
2653   data = smb_buf(inbuf) + 3;
2654   
2655   if (write_file(fnum,data,numtowrite) != numtowrite)
2656     return(UNIXERROR(ERRDOS,ERRnoaccess));
2657   
2658   DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
2659   
2660   return(outsize);
2661 }
2662
2663
2664 /****************************************************************************
2665   reply to a mkdir
2666 ****************************************************************************/
2667 int reply_mkdir(char *inbuf,char *outbuf)
2668 {
2669   pstring directory;
2670   int cnum;
2671   int outsize,ret= -1;
2672   BOOL bad_path = False;
2673  
2674   pstrcpy(directory,smb_buf(inbuf) + 1);
2675   cnum = SVAL(inbuf,smb_tid);
2676   unix_convert(directory,cnum,0,&bad_path);
2677   
2678   if (check_name(directory,cnum))
2679     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
2680   
2681   if (ret < 0)
2682   {
2683     if((errno == ENOENT) && bad_path)
2684     {
2685       unix_ERR_class = ERRDOS;
2686       unix_ERR_code = ERRbadpath;
2687     }
2688     return(UNIXERROR(ERRDOS,ERRnoaccess));
2689   }
2690  
2691   outsize = set_message(outbuf,0,0,True);
2692   
2693   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
2694   
2695   return(outsize);
2696 }
2697
2698 /****************************************************************************
2699 Static function used by reply_rmdir to delete an entire directory
2700 tree recursively.
2701 ****************************************************************************/
2702 static BOOL recursive_rmdir(char *directory)
2703 {
2704   char *dname = NULL;
2705   BOOL ret = False;
2706   void *dirptr = OpenDir(-1, directory, False);
2707
2708   if(dirptr == NULL)
2709     return True;
2710
2711   while((dname = ReadDirName(dirptr)))
2712   {
2713     pstring fullname;
2714     struct stat st;
2715
2716     if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2717       continue;
2718
2719     /* Construct the full name. */
2720     if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
2721     {
2722       errno = ENOMEM;
2723       ret = True;
2724       break;
2725     }
2726     strcpy(fullname, directory);
2727     strcat(fullname, "/");
2728     strcat(fullname, dname);
2729
2730     if(sys_lstat(fullname, &st) != 0)
2731     {
2732       ret = True;
2733       break;
2734     }
2735
2736     if(st.st_mode & S_IFDIR)
2737     {
2738       if(recursive_rmdir(fullname)!=0)
2739       {
2740         ret = True;
2741         break;
2742       }
2743       if(sys_rmdir(fullname) != 0)
2744       {
2745         ret = True;
2746         break;
2747       }
2748     }
2749     else if(sys_unlink(fullname) != 0)
2750     {
2751       ret = True;
2752       break;
2753     }
2754   }
2755   CloseDir(dirptr);
2756   return ret;
2757 }
2758
2759 /****************************************************************************
2760   reply to a rmdir
2761 ****************************************************************************/
2762 int reply_rmdir(char *inbuf,char *outbuf)
2763 {
2764   pstring directory;
2765   int cnum;
2766   int outsize = 0;
2767   BOOL ok = False;
2768   BOOL bad_path = False;
2769
2770   cnum = SVAL(inbuf,smb_tid);
2771   pstrcpy(directory,smb_buf(inbuf) + 1);
2772   unix_convert(directory,cnum,0,&bad_path);
2773   
2774   if (check_name(directory,cnum))
2775     {
2776
2777       dptr_closepath(directory,SVAL(inbuf,smb_pid));
2778       ok = (sys_rmdir(directory) == 0);
2779       if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(cnum)))
2780         {
2781           /* Check to see if the only thing in this directory are
2782              vetoed files/directories. If so then delete them and
2783              retry. If we fail to delete any of them (and we *don't*
2784              do a recursive delete) then fail the rmdir. */
2785           BOOL all_veto_files = True;
2786           char *dname;
2787           void *dirptr = OpenDir(cnum, directory, False);
2788
2789           if(dirptr != NULL)
2790             {
2791               int dirpos = TellDir(dirptr);
2792                   while ((dname = ReadDirName(dirptr)))
2793                     {
2794                   if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2795                     continue;
2796                   if(!IS_VETO_PATH(cnum, dname))
2797                     {
2798                       all_veto_files = False;
2799                       break;
2800                     }
2801                 }
2802               if(all_veto_files)
2803                 {
2804                   SeekDir(dirptr,dirpos);
2805                   while ((dname = ReadDirName(dirptr)))
2806                     {
2807                       pstring fullname;
2808                       struct stat st;
2809
2810                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2811                         continue;
2812
2813                       /* Construct the full name. */
2814                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
2815                         {
2816                           errno = ENOMEM;
2817                           break;
2818                         }
2819                       pstrcpy(fullname, directory);
2820                       strcat(fullname, "/");
2821                       strcat(fullname, dname);
2822                       
2823                       if(sys_lstat(fullname, &st) != 0)
2824                         break;
2825                       if(st.st_mode & S_IFDIR)
2826                       {
2827                         if(lp_recursive_veto_delete(SNUM(cnum)))
2828                         {
2829                           if(recursive_rmdir(fullname) != 0)
2830                             break;
2831                         }
2832                         if(sys_rmdir(fullname) != 0)
2833                           break;
2834                       }
2835                       else if(sys_unlink(fullname) != 0)
2836                         break;
2837                     }
2838                   CloseDir(dirptr);
2839                   /* Retry the rmdir */
2840                   ok = (sys_rmdir(directory) == 0);
2841                 }
2842               else
2843                 CloseDir(dirptr);
2844             }
2845           else
2846             errno = ENOTEMPTY;
2847          }
2848           
2849       if (!ok)
2850         DEBUG(3,("couldn't remove directory %s : %s\n",
2851                  directory,strerror(errno)));
2852     }
2853   
2854   if (!ok)
2855   {
2856     if((errno == ENOENT) && bad_path)
2857     {
2858       unix_ERR_class = ERRDOS;
2859       unix_ERR_code = ERRbadpath;
2860     }
2861     return(UNIXERROR(ERRDOS,ERRbadpath));
2862   }
2863  
2864   outsize = set_message(outbuf,0,0,True);
2865   
2866   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
2867   
2868   return(outsize);
2869 }
2870
2871
2872 /*******************************************************************
2873 resolve wildcards in a filename rename
2874 ********************************************************************/
2875 static BOOL resolve_wildcards(char *name1,char *name2)
2876 {
2877   fstring root1,root2;
2878   fstring ext1,ext2;
2879   char *p,*p2;
2880
2881   name1 = strrchr(name1,'/');
2882   name2 = strrchr(name2,'/');
2883
2884   if (!name1 || !name2) return(False);
2885   
2886   fstrcpy(root1,name1);
2887   fstrcpy(root2,name2);
2888   p = strrchr(root1,'.');
2889   if (p) {
2890     *p = 0;
2891     fstrcpy(ext1,p+1);
2892   } else {
2893     fstrcpy(ext1,"");    
2894   }
2895   p = strrchr(root2,'.');
2896   if (p) {
2897     *p = 0;
2898     fstrcpy(ext2,p+1);
2899   } else {
2900     fstrcpy(ext2,"");    
2901   }
2902
2903   p = root1;
2904   p2 = root2;
2905   while (*p2) {
2906     if (*p2 == '?') {
2907       *p2 = *p;
2908       p2++;
2909     } else {
2910       p2++;
2911     }
2912     if (*p) p++;
2913   }
2914
2915   p = ext1;
2916   p2 = ext2;
2917   while (*p2) {
2918     if (*p2 == '?') {
2919       *p2 = *p;
2920       p2++;
2921     } else {
2922       p2++;
2923     }
2924     if (*p) p++;
2925   }
2926
2927   strcpy(name2,root2);
2928   if (ext2[0]) {
2929     strcat(name2,".");
2930     strcat(name2,ext2);
2931   }
2932
2933   return(True);
2934 }
2935
2936 /*******************************************************************
2937 check if a user is allowed to rename a file
2938 ********************************************************************/
2939 static BOOL can_rename(char *fname,int cnum)
2940 {
2941   struct stat sbuf;
2942
2943   if (!CAN_WRITE(cnum)) return(False);
2944
2945   if (sys_lstat(fname,&sbuf) != 0) return(False);
2946   if (!check_file_sharing(cnum,fname)) return(False);
2947
2948   return(True);
2949 }
2950
2951 /****************************************************************************
2952   reply to a mv
2953 ****************************************************************************/
2954 int reply_mv(char *inbuf,char *outbuf)
2955 {
2956   int outsize = 0;
2957   pstring name;
2958   int cnum;
2959   pstring directory;
2960   pstring mask,newname;
2961   pstring newname_last_component;
2962   char *p;
2963   int count=0;
2964   int error = ERRnoaccess;
2965   BOOL has_wild;
2966   BOOL exists=False;
2967   BOOL bad_path1 = False;
2968   BOOL bad_path2 = False;
2969
2970   *directory = *mask = 0;
2971
2972   cnum = SVAL(inbuf,smb_tid);
2973   
2974   pstrcpy(name,smb_buf(inbuf) + 1);
2975   pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
2976    
2977   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
2978    
2979   unix_convert(name,cnum,0,&bad_path1);
2980   unix_convert(newname,cnum,newname_last_component,&bad_path2);
2981
2982   /*
2983    * Split the old name into directory and last component
2984    * strings. Note that unix_convert may have stripped off a 
2985    * leading ./ from both name and newname if the rename is 
2986    * at the root of the share. We need to make sure either both
2987    * name and newname contain a / character or neither of them do
2988    * as this is checked in resolve_wildcards().
2989    */
2990
2991   p = strrchr(name,'/');
2992   if (!p) {
2993     strcpy(directory,".");
2994     strcpy(mask,name);
2995   } else {
2996     *p = 0;
2997     strcpy(directory,name);
2998     strcpy(mask,p+1);
2999     *p = '/'; /* Replace needed for exceptional test below. */
3000   }
3001
3002   if (is_mangled(mask))
3003     check_mangled_stack(mask);
3004
3005   has_wild = strchr(mask,'*') || strchr(mask,'?');
3006
3007   if (!has_wild) {
3008     BOOL is_short_name = is_8_3(name, True);
3009
3010     /* Add a terminating '/' to the directory name. */
3011     strcat(directory,"/");
3012     strcat(directory,mask);
3013
3014     /* Ensure newname contains a '/' also */
3015     if(strrchr(newname,'/') == 0) {
3016       pstring tmpstr;
3017
3018       strcpy(tmpstr, "./");
3019       strcat(tmpstr, newname);
3020       strcpy(newname, tmpstr);
3021     }
3022   
3023     DEBUG(3,("reply_mv : case_sensitive = %d, case_preserve = %d, short case preserve = %d, directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
3024             case_sensitive, case_preserve, short_case_preserve, directory, 
3025             newname, newname_last_component, is_short_name));
3026
3027     /*
3028      * Check for special case with case preserving and not
3029      * case sensitive, if directory and newname are identical,
3030      * and the old last component differs from the original
3031      * last component only by case, then we should allow
3032      * the rename (user is trying to change the case of the
3033      * filename).
3034      */
3035     if((case_sensitive == False) && ( ((case_preserve == True) && (is_short_name == False)) || 
3036             ((short_case_preserve == True) && (is_short_name == True))) &&
3037        strcsequal(directory, newname)) {
3038       pstring newname_modified_last_component;
3039
3040       /*
3041        * Get the last component of the modified name.
3042        * Note that we guarantee that newname contains a '/'
3043        * character above.
3044        */
3045       p = strrchr(newname,'/');
3046       strcpy(newname_modified_last_component,p+1);
3047
3048       if(strcsequal(newname_modified_last_component, 
3049                     newname_last_component) == False) {
3050         /*
3051          * Replace the modified last component with
3052          * the original.
3053          */
3054         strcpy(p+1, newname_last_component);
3055       }
3056     }
3057
3058     if (resolve_wildcards(directory,newname) && 
3059         can_rename(directory,cnum) && 
3060         !file_exist(newname,NULL) &&
3061         !sys_rename(directory,newname)) count++;
3062
3063     DEBUG(3,("reply_mv : %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
3064                          directory,newname));
3065
3066     if (!count) exists = file_exist(directory,NULL);
3067     if (!count && exists && file_exist(newname,NULL)) {
3068       exists = True;
3069       error = 183;
3070     }
3071   } else {
3072     void *dirptr = NULL;
3073     char *dname;
3074     pstring destname;
3075
3076     if (check_name(directory,cnum))
3077       dirptr = OpenDir(cnum, directory, True);
3078
3079     if (dirptr)
3080       {
3081         error = ERRbadfile;
3082
3083         if (strequal(mask,"????????.???"))
3084           strcpy(mask,"*");
3085
3086         while ((dname = ReadDirName(dirptr)))
3087           {
3088             pstring fname;
3089             pstrcpy(fname,dname);
3090             
3091             if(!mask_match(fname, mask, case_sensitive, False)) continue;
3092
3093             error = ERRnoaccess;
3094             sprintf(fname,"%s/%s",directory,dname);
3095             if (!can_rename(fname,cnum)) continue;
3096             pstrcpy(destname,newname);
3097
3098             if (!resolve_wildcards(fname,destname)) continue;
3099
3100             if (file_exist(destname,NULL)) {
3101               error = 183;
3102               continue;
3103             }
3104             if (!sys_rename(fname,destname)) count++;
3105             DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
3106           }
3107         CloseDir(dirptr);
3108       }
3109   }
3110   
3111   if (count == 0) {
3112     if (exists)
3113       return(ERROR(ERRDOS,error));
3114     else
3115     {
3116       if((errno == ENOENT) && (bad_path1 || bad_path2))
3117       {
3118         unix_ERR_class = ERRDOS;
3119         unix_ERR_code = ERRbadpath;
3120       }
3121       return(UNIXERROR(ERRDOS,error));
3122     }
3123   }
3124   
3125   outsize = set_message(outbuf,0,0,True);
3126   
3127   return(outsize);
3128 }
3129
3130 /*******************************************************************
3131   copy a file as part of a reply_copy
3132   ******************************************************************/
3133 static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
3134                       int count,BOOL target_is_directory)
3135 {
3136   int Access,action;
3137   struct stat st;
3138   int ret=0;
3139   int fnum1,fnum2;
3140   pstring dest;
3141   
3142   pstrcpy(dest,dest1);
3143   if (target_is_directory) {
3144     char *p = strrchr(src,'/');
3145     if (p) 
3146       p++;
3147     else
3148       p = src;
3149     strcat(dest,"/");
3150     strcat(dest,p);
3151   }
3152
3153   if (!file_exist(src,&st)) return(False);
3154
3155   fnum1 = find_free_file();
3156   if (fnum1<0) return(False);
3157   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
3158                    1,0,0,&Access,&action);
3159
3160   if (!Files[fnum1].open) return(False);
3161
3162   if (!target_is_directory && count)
3163     ofun = 1;
3164
3165   fnum2 = find_free_file();
3166   if (fnum2<0) {
3167     close_file(fnum1);
3168     return(False);
3169   }
3170   open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
3171                    ofun,st.st_mode,0,&Access,&action);
3172
3173   if (!Files[fnum2].open) {
3174     close_file(fnum1);
3175     return(False);
3176   }
3177
3178   if ((ofun&3) == 1) {
3179     lseek(Files[fnum2].fd_ptr->fd,0,SEEK_END);
3180   }
3181   
3182   if (st.st_size)
3183     ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0);
3184
3185   close_file(fnum1);
3186   close_file(fnum2);
3187
3188   return(ret == st.st_size);
3189 }
3190
3191
3192
3193 /****************************************************************************
3194   reply to a file copy.
3195   ****************************************************************************/
3196 int reply_copy(char *inbuf,char *outbuf)
3197 {
3198   int outsize = 0;
3199   pstring name;
3200   int cnum;
3201   pstring directory;
3202   pstring mask,newname;
3203   char *p;
3204   int count=0;
3205   int error = ERRnoaccess;
3206   BOOL has_wild;
3207   BOOL exists=False;
3208   int tid2 = SVAL(inbuf,smb_vwv0);
3209   int ofun = SVAL(inbuf,smb_vwv1);
3210   int flags = SVAL(inbuf,smb_vwv2);
3211   BOOL target_is_directory=False;
3212   BOOL bad_path1 = False;
3213   BOOL bad_path2 = False;
3214
3215   *directory = *mask = 0;
3216
3217   cnum = SVAL(inbuf,smb_tid);
3218   
3219   pstrcpy(name,smb_buf(inbuf));
3220   pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
3221    
3222   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
3223    
3224   if (tid2 != cnum) {
3225     /* can't currently handle inter share copies XXXX */
3226     DEBUG(3,("Rejecting inter-share copy\n"));
3227     return(ERROR(ERRSRV,ERRinvdevice));
3228   }
3229
3230   unix_convert(name,cnum,0,&bad_path1);
3231   unix_convert(newname,cnum,0,&bad_path2);
3232
3233   target_is_directory = directory_exist(newname,NULL);
3234
3235   if ((flags&1) && target_is_directory) {
3236     return(ERROR(ERRDOS,ERRbadfile));
3237   }
3238
3239   if ((flags&2) && !target_is_directory) {
3240     return(ERROR(ERRDOS,ERRbadpath));
3241   }
3242
3243   if ((flags&(1<<5)) && directory_exist(name,NULL)) {
3244     /* wants a tree copy! XXXX */
3245     DEBUG(3,("Rejecting tree copy\n"));
3246     return(ERROR(ERRSRV,ERRerror));    
3247   }
3248
3249   p = strrchr(name,'/');
3250   if (!p) {
3251     strcpy(directory,"./");
3252     strcpy(mask,name);
3253   } else {
3254     *p = 0;
3255     strcpy(directory,name);
3256     strcpy(mask,p+1);
3257   }
3258
3259   if (is_mangled(mask))
3260     check_mangled_stack(mask);
3261
3262   has_wild = strchr(mask,'*') || strchr(mask,'?');
3263
3264   if (!has_wild) {
3265     strcat(directory,"/");
3266     strcat(directory,mask);
3267     if (resolve_wildcards(directory,newname) && 
3268         copy_file(directory,newname,cnum,ofun,
3269                   count,target_is_directory)) count++;
3270     if (!count) exists = file_exist(directory,NULL);
3271   } else {
3272     void *dirptr = NULL;
3273     char *dname;
3274     pstring destname;
3275
3276     if (check_name(directory,cnum))
3277       dirptr = OpenDir(cnum, directory, True);
3278
3279     if (dirptr)
3280       {
3281         error = ERRbadfile;
3282
3283         if (strequal(mask,"????????.???"))
3284           strcpy(mask,"*");
3285
3286         while ((dname = ReadDirName(dirptr)))
3287           {
3288             pstring fname;
3289             pstrcpy(fname,dname);
3290             
3291             if(!mask_match(fname, mask, case_sensitive, False)) continue;
3292
3293             error = ERRnoaccess;
3294             sprintf(fname,"%s/%s",directory,dname);
3295             strcpy(destname,newname);
3296             if (resolve_wildcards(fname,destname) && 
3297                 copy_file(directory,newname,cnum,ofun,
3298                           count,target_is_directory)) count++;
3299             DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
3300           }
3301         CloseDir(dirptr);
3302       }
3303   }
3304   
3305   if (count == 0) {
3306     if (exists)
3307       return(ERROR(ERRDOS,error));
3308     else
3309     {
3310       if((errno == ENOENT) && (bad_path1 || bad_path2))
3311       {
3312         unix_ERR_class = ERRDOS;
3313         unix_ERR_code = ERRbadpath;
3314       }
3315       return(UNIXERROR(ERRDOS,error));
3316     }
3317   }
3318   
3319   outsize = set_message(outbuf,1,0,True);
3320   SSVAL(outbuf,smb_vwv0,count);
3321
3322   return(outsize);
3323 }
3324
3325
3326
3327 /****************************************************************************
3328   reply to a setdir
3329 ****************************************************************************/
3330 int reply_setdir(char *inbuf,char *outbuf)
3331 {
3332   int cnum,snum;
3333   int outsize = 0;
3334   BOOL ok = False;
3335   pstring newdir;
3336   
3337   cnum = SVAL(inbuf,smb_tid);
3338   
3339   snum = Connections[cnum].service;
3340   if (!CAN_SETDIR(snum))
3341     return(ERROR(ERRDOS,ERRnoaccess));
3342   
3343   pstrcpy(newdir,smb_buf(inbuf) + 1);
3344   strlower(newdir);
3345   
3346   if (strlen(newdir) == 0)
3347     ok = True;
3348   else
3349     {
3350       ok = directory_exist(newdir,NULL);
3351       if (ok)
3352         string_set(&Connections[cnum].connectpath,newdir);
3353     }
3354   
3355   if (!ok)
3356     return(ERROR(ERRDOS,ERRbadpath));
3357   
3358   outsize = set_message(outbuf,0,0,True);
3359   CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
3360   
3361   DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum));
3362   
3363   return(outsize);
3364 }
3365
3366
3367 /****************************************************************************
3368   reply to a lockingX request
3369 ****************************************************************************/
3370 int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
3371 {
3372   int fnum = GETFNUM(inbuf,smb_vwv2);
3373   unsigned char locktype = CVAL(inbuf,smb_vwv3);
3374 #if 0
3375   unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
3376 #endif
3377   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
3378   uint16 num_locks = SVAL(inbuf,smb_vwv7);
3379   uint32 count, offset;
3380
3381   int cnum;
3382   int i;
3383   char *data;
3384   uint32 ecode=0, dummy2;
3385   int eclass=0, dummy1;
3386
3387   cnum = SVAL(inbuf,smb_tid);
3388
3389   CHECK_FNUM(fnum,cnum);
3390   CHECK_ERROR(fnum);
3391
3392   data = smb_buf(inbuf);
3393
3394   /* Check if this is an oplock break on a file
3395      we have granted an oplock on.
3396    */
3397   if((locktype == LOCKING_ANDX_OPLOCK_RELEASE) && 
3398      (num_ulocks == 0) && (num_locks == 0) &&
3399      (CVAL(inbuf,smb_vwv0) == 0xFF))
3400   {
3401     share_lock_token token;
3402     files_struct *fsp = &Files[fnum];
3403     uint32 dev = fsp->fd_ptr->dev;
3404     uint32 inode = fsp->fd_ptr->inode;
3405
3406     DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
3407               fnum));
3408     /*
3409      * Make sure we have granted an oplock on this file.
3410      */
3411     if(!fsp->granted_oplock)
3412     {
3413       DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
3414 no oplock granted on this file.\n", fnum));
3415       return ERROR(ERRDOS,ERRlock);
3416     }
3417
3418     /* Remove the oplock flag from the sharemode. */
3419     lock_share_entry(fsp->cnum, dev, inode, &token);
3420     if(remove_share_oplock( fnum, token)==False)
3421     {
3422       DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
3423 dev = %x, inode = %x\n", fnum, dev, inode));
3424       unlock_share_entry(fsp->cnum, dev, inode, token);
3425       return -1;
3426     }
3427     unlock_share_entry(fsp->cnum, dev, inode, token);
3428
3429     /* Clear the granted flag and return. */
3430
3431     fsp->granted_oplock = False;
3432     return -1;
3433   }
3434
3435   /* Data now points at the beginning of the list
3436      of smb_unlkrng structs */
3437   for(i = 0; i < (int)num_ulocks; i++) {
3438     count = IVAL(data,SMB_LKLEN_OFFSET(i));
3439     offset = IVAL(data,SMB_LKOFF_OFFSET(i));
3440     if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode))
3441       return ERROR(eclass,ecode);
3442   }
3443
3444   /* Now do any requested locks */
3445   data += 10*num_ulocks;
3446   /* Data now points at the beginning of the list
3447      of smb_lkrng structs */
3448   for(i = 0; i < (int)num_locks; i++) {
3449     count = IVAL(data,SMB_LKLEN_OFFSET(i)); 
3450     offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
3451     if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
3452       break;
3453   }
3454
3455   /* If any of the above locks failed, then we must unlock
3456      all of the previous locks (X/Open spec). */
3457   if(i != num_locks && num_locks != 0) {
3458     for(; i >= 0; i--) {
3459       count = IVAL(data,SMB_LKLEN_OFFSET(i));  
3460       offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
3461       do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2);
3462     }
3463     return ERROR(eclass,ecode);
3464   }
3465
3466   set_message(outbuf,2,0,True);
3467   
3468   DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
3469         timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
3470
3471   chain_fnum = fnum;
3472
3473   return chain_reply(inbuf,outbuf,length,bufsize);
3474 }
3475
3476
3477 /****************************************************************************
3478   reply to a SMBreadbmpx (read block multiplex) request
3479 ****************************************************************************/
3480 int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
3481 {
3482   int cnum,fnum;
3483   int nread = -1;
3484   int total_read;
3485   char *data;
3486   uint32 startpos;
3487   int outsize, mincount, maxcount;
3488   int max_per_packet;
3489   int tcount;
3490   int pad;
3491
3492   /* this function doesn't seem to work - disable by default */
3493   if (!lp_readbmpx())
3494     return(ERROR(ERRSRV,ERRuseSTD));
3495
3496   outsize = set_message(outbuf,8,0,True);
3497
3498   cnum = SVAL(inbuf,smb_tid);
3499   fnum = GETFNUM(inbuf,smb_vwv0);
3500
3501   CHECK_FNUM(fnum,cnum);
3502   CHECK_READ(fnum);
3503   CHECK_ERROR(fnum);
3504
3505   startpos = IVAL(inbuf,smb_vwv1);
3506   maxcount = SVAL(inbuf,smb_vwv3);
3507   mincount = SVAL(inbuf,smb_vwv4);
3508
3509   data = smb_buf(outbuf);
3510   pad = ((long)data)%4;
3511   if (pad) pad = 4 - pad;
3512   data += pad;
3513
3514   max_per_packet = bufsize-(outsize+pad);
3515   tcount = maxcount;
3516   total_read = 0;
3517
3518   if (is_locked(fnum,cnum,maxcount,startpos))
3519     return(ERROR(ERRDOS,ERRlock));
3520         
3521   do
3522     {
3523       int N = MIN(max_per_packet,tcount-total_read);
3524   
3525       nread = read_file(fnum,data,startpos,N);
3526
3527       if (nread <= 0) nread = 0;
3528
3529       if (nread < N)
3530         tcount = total_read + nread;
3531
3532       set_message(outbuf,8,nread,False);
3533       SIVAL(outbuf,smb_vwv0,startpos);
3534       SSVAL(outbuf,smb_vwv2,tcount);
3535       SSVAL(outbuf,smb_vwv6,nread);
3536       SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
3537
3538       send_smb(Client,outbuf);
3539
3540       total_read += nread;
3541       startpos += nread;
3542     }
3543   while (total_read < tcount);
3544
3545   return(-1);
3546 }
3547
3548
3549 /****************************************************************************
3550   reply to a SMBwritebmpx (write block multiplex primary) request
3551 ****************************************************************************/
3552 int reply_writebmpx(char *inbuf,char *outbuf)
3553 {
3554   int cnum,numtowrite,fnum;
3555   int nwritten = -1;
3556   int outsize = 0;
3557   uint32 startpos;
3558   int tcount, write_through, smb_doff;
3559   char *data;
3560   
3561   cnum = SVAL(inbuf,smb_tid);
3562   fnum = GETFNUM(inbuf,smb_vwv0);
3563
3564   CHECK_FNUM(fnum,cnum);
3565   CHECK_WRITE(fnum);
3566   CHECK_ERROR(fnum);
3567
3568   tcount = SVAL(inbuf,smb_vwv1);
3569   startpos = IVAL(inbuf,smb_vwv3);
3570   write_through = BITSETW(inbuf+smb_vwv7,0);
3571   numtowrite = SVAL(inbuf,smb_vwv10);
3572   smb_doff = SVAL(inbuf,smb_vwv11);
3573
3574   data = smb_base(inbuf) + smb_doff;
3575
3576   /* If this fails we need to send an SMBwriteC response,
3577      not an SMBwritebmpx - set this up now so we don't forget */
3578   CVAL(outbuf,smb_com) = SMBwritec;
3579
3580   if (is_locked(fnum,cnum,tcount,startpos))
3581     return(ERROR(ERRDOS,ERRlock));
3582
3583   seek_file(fnum,startpos);
3584   nwritten = write_file(fnum,data,numtowrite);
3585
3586   if(lp_syncalways(SNUM(cnum)) || write_through)
3587     sync_file(fnum);
3588   
3589   if(nwritten < numtowrite)
3590     return(UNIXERROR(ERRHRD,ERRdiskfull));
3591
3592   /* If the maximum to be written to this file
3593      is greater than what we just wrote then set
3594      up a secondary struct to be attached to this
3595      fd, we will use this to cache error messages etc. */
3596   if(tcount > nwritten) 
3597     {
3598       write_bmpx_struct *wbms;
3599       if(Files[fnum].wbmpx_ptr != NULL)
3600         wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */
3601       else
3602         wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
3603       if(!wbms)
3604         {
3605           DEBUG(0,("Out of memory in reply_readmpx\n"));
3606           return(ERROR(ERRSRV,ERRnoresource));
3607         }
3608       wbms->wr_mode = write_through;
3609       wbms->wr_discard = False; /* No errors yet */
3610       wbms->wr_total_written = nwritten;
3611       wbms->wr_errclass = 0;
3612       wbms->wr_error = 0;
3613       Files[fnum].wbmpx_ptr = wbms;
3614     }
3615
3616   /* We are returning successfully, set the message type back to
3617      SMBwritebmpx */
3618   CVAL(outbuf,smb_com) = SMBwriteBmpx;
3619   
3620   outsize = set_message(outbuf,1,0,True);
3621   
3622   SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
3623   
3624   DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n",
3625         timestring(),fnum,cnum,numtowrite,nwritten));
3626   
3627   if (write_through && tcount==nwritten) {
3628     /* we need to send both a primary and a secondary response */
3629     smb_setlen(outbuf,outsize - 4);
3630     send_smb(Client,outbuf);
3631
3632     /* now the secondary */
3633     outsize = set_message(outbuf,1,0,True);
3634     CVAL(outbuf,smb_com) = SMBwritec;
3635     SSVAL(outbuf,smb_vwv0,nwritten);
3636   }
3637
3638   return(outsize);
3639 }
3640
3641
3642 /****************************************************************************
3643   reply to a SMBwritebs (write block multiplex secondary) request
3644 ****************************************************************************/
3645 int reply_writebs(char *inbuf,char *outbuf)
3646 {
3647   int cnum,numtowrite,fnum;
3648   int nwritten = -1;
3649   int outsize = 0;
3650   int32 startpos;
3651   int tcount, write_through, smb_doff;
3652   char *data;
3653   write_bmpx_struct *wbms;
3654   BOOL send_response = False;
3655   
3656   cnum = SVAL(inbuf,smb_tid);
3657   fnum = GETFNUM(inbuf,smb_vwv0);
3658   CHECK_FNUM(fnum,cnum);
3659   CHECK_WRITE(fnum);
3660
3661   tcount = SVAL(inbuf,smb_vwv1);
3662   startpos = IVAL(inbuf,smb_vwv2);
3663   numtowrite = SVAL(inbuf,smb_vwv6);
3664   smb_doff = SVAL(inbuf,smb_vwv7);
3665
3666   data = smb_base(inbuf) + smb_doff;
3667
3668   /* We need to send an SMBwriteC response, not an SMBwritebs */
3669   CVAL(outbuf,smb_com) = SMBwritec;
3670
3671   /* This fd should have an auxiliary struct attached,
3672      check that it does */
3673   wbms = Files[fnum].wbmpx_ptr;
3674   if(!wbms) return(-1);
3675
3676   /* If write through is set we can return errors, else we must
3677      cache them */
3678   write_through = wbms->wr_mode;
3679
3680   /* Check for an earlier error */
3681   if(wbms->wr_discard)
3682     return -1; /* Just discard the packet */
3683
3684   seek_file(fnum,startpos);
3685   nwritten = write_file(fnum,data,numtowrite);
3686
3687   if(lp_syncalways(SNUM(cnum)) || write_through)
3688     sync_file(fnum);
3689   
3690   if (nwritten < numtowrite)
3691     {
3692       if(write_through) {
3693         /* We are returning an error - we can delete the aux struct */
3694         if (wbms) free((char *)wbms);
3695         Files[fnum].wbmpx_ptr = NULL;
3696         return(ERROR(ERRHRD,ERRdiskfull));
3697       }
3698       return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
3699     }
3700
3701   /* Increment the total written, if this matches tcount
3702      we can discard the auxiliary struct (hurrah !) and return a writeC */
3703   wbms->wr_total_written += nwritten;
3704   if(wbms->wr_total_written >= tcount)
3705     {
3706       if (write_through) {
3707         outsize = set_message(outbuf,1,0,True);
3708         SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
3709         send_response = True;
3710       }
3711
3712       free((char *)wbms);
3713       Files[fnum].wbmpx_ptr = NULL;
3714     }
3715
3716   if(send_response)
3717     return(outsize);
3718
3719   return(-1);
3720 }
3721
3722
3723 /****************************************************************************
3724   reply to a SMBsetattrE
3725 ****************************************************************************/
3726 int reply_setattrE(char *inbuf,char *outbuf)
3727 {
3728   int cnum,fnum;
3729   struct utimbuf unix_times;
3730   int outsize = 0;
3731
3732   outsize = set_message(outbuf,0,0,True);
3733
3734   cnum = SVAL(inbuf,smb_tid);
3735   fnum = GETFNUM(inbuf,smb_vwv0);
3736
3737   CHECK_FNUM(fnum,cnum);
3738   CHECK_ERROR(fnum);
3739
3740   /* Convert the DOS times into unix times. Ignore create
3741      time as UNIX can't set this.
3742      */
3743   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
3744   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
3745   
3746   /* 
3747    * Patch from Ray Frush <frush@engr.colostate.edu>
3748    * Sometimes times are sent as zero - ignore them.
3749    */
3750
3751   if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
3752   {
3753     /* Ignore request */
3754     DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d ignoring zero request - \
3755 not setting timestamps of 0\n",
3756           timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
3757     return(outsize);
3758   }
3759   else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
3760   {
3761     /* set modify time = to access time if modify time was 0 */
3762     unix_times.modtime = unix_times.actime;
3763   }
3764
3765   /* Set the date on this file */
3766   if(sys_utime(Files[fnum].name, &unix_times))
3767     return(ERROR(ERRDOS,ERRnoaccess));
3768   
3769   DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n",
3770     timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
3771
3772   return(outsize);
3773 }
3774
3775
3776 /****************************************************************************
3777   reply to a SMBgetattrE
3778 ****************************************************************************/
3779 int reply_getattrE(char *inbuf,char *outbuf)
3780 {
3781   int cnum,fnum;
3782   struct stat sbuf;
3783   int outsize = 0;
3784   int mode;
3785
3786   outsize = set_message(outbuf,11,0,True);
3787
3788   cnum = SVAL(inbuf,smb_tid);
3789   fnum = GETFNUM(inbuf,smb_vwv0);
3790
3791   CHECK_FNUM(fnum,cnum);
3792   CHECK_ERROR(fnum);
3793
3794   /* Do an fstat on this file */
3795   if(fstat(Files[fnum].fd_ptr->fd, &sbuf))
3796     return(UNIXERROR(ERRDOS,ERRnoaccess));
3797   
3798   mode = dos_mode(cnum,Files[fnum].name,&sbuf);
3799   
3800   /* Convert the times into dos times. Set create
3801      date to be last modify date as UNIX doesn't save
3802      this */
3803   put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime);
3804   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
3805   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
3806   if (mode & aDIR)
3807     {
3808       SIVAL(outbuf,smb_vwv6,0);
3809       SIVAL(outbuf,smb_vwv8,0);
3810     }
3811   else
3812     {
3813       SIVAL(outbuf,smb_vwv6,sbuf.st_size);
3814       SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
3815     }
3816   SSVAL(outbuf,smb_vwv10, mode);
3817   
3818   DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
3819   
3820   return(outsize);
3821 }