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