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