client.c: Changed shadowed variable.
[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   /*
1625    * Special check if an oplock break has been issued
1626    * and the readraw request croses on the wire, we must
1627    * return a zero length response here.
1628    */
1629
1630   if(global_oplock_break)
1631   {
1632     _smb_setlen(header,0);
1633     transfer_file(0,Client,0,header,4,0);
1634     DEBUG(5,("readbraw - oplock break finished\n"));
1635     return -1;
1636   }
1637
1638   cnum = SVAL(inbuf,smb_tid);
1639   fnum = GETFNUM(inbuf,smb_vwv0);
1640
1641   startpos = IVAL(inbuf,smb_vwv1);
1642   maxcount = SVAL(inbuf,smb_vwv3);
1643   mincount = SVAL(inbuf,smb_vwv4);
1644
1645   /* ensure we don't overrun the packet size */
1646   maxcount = MIN(65535,maxcount);
1647   maxcount = MAX(mincount,maxcount);
1648
1649   if (!FNUM_OK(fnum,cnum) || !Files[fnum].can_read)
1650     {
1651       DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",fnum));
1652       _smb_setlen(header,0);
1653       transfer_file(0,Client,0,header,4,0);
1654       return(-1);
1655     }
1656   else
1657     {
1658       fd = Files[fnum].fd_ptr->fd;
1659       fname = Files[fnum].name;
1660     }
1661
1662
1663   if (!is_locked(fnum,cnum,maxcount,startpos))
1664     {
1665       int size = Files[fnum].size;
1666       int sizeneeded = startpos + maxcount;
1667             
1668       if (size < sizeneeded) {
1669         struct stat st;
1670         if (fstat(Files[fnum].fd_ptr->fd,&st) == 0)
1671           size = st.st_size;
1672         if (!Files[fnum].can_write) 
1673           Files[fnum].size = size;
1674       }
1675
1676       nread = MIN(maxcount,(int)(size - startpos));       
1677     }
1678
1679   if (nread < mincount)
1680     nread = 0;
1681   
1682   DEBUG(3,("%s readbraw fnum=%d cnum=%d start=%d max=%d min=%d nread=%d\n",
1683            timestring(),
1684            fnum,cnum,startpos,
1685            maxcount,mincount,nread));
1686   
1687 #if UNSAFE_READRAW
1688   {
1689     int predict=0;
1690     _smb_setlen(header,nread);
1691
1692     if (!Files[fnum].can_write)
1693       predict = read_predict(fd,startpos,header+4,NULL,nread);
1694
1695     if ((nread-predict) > 0)
1696       seek_file(fnum,startpos + predict);
1697     
1698     ret = transfer_file(fd,Client,nread-predict,header,4+predict,
1699                         startpos+predict);
1700   }
1701
1702   if (ret != nread+4)
1703     DEBUG(0,("ERROR: file read failure on %s at %d for %d bytes (%d)\n",
1704              fname,startpos,nread,ret));
1705
1706 #else
1707   ret = read_file(fnum,header+4,startpos,nread);
1708   if (ret < mincount) ret = 0;
1709
1710   _smb_setlen(header,ret);
1711   transfer_file(0,Client,0,header,4+ret,0);
1712 #endif
1713
1714   DEBUG(5,("readbraw finished\n"));
1715   return -1;
1716 }
1717
1718
1719 /****************************************************************************
1720   reply to a lockread (core+ protocol)
1721 ****************************************************************************/
1722 int reply_lockread(char *inbuf,char *outbuf)
1723 {
1724   int cnum,fnum;
1725   int nread = -1;
1726   char *data;
1727   int outsize = 0;
1728   uint32 startpos, numtoread;
1729   int eclass;
1730   uint32 ecode;
1731   
1732   cnum = SVAL(inbuf,smb_tid);
1733   fnum = GETFNUM(inbuf,smb_vwv0);
1734
1735   CHECK_FNUM(fnum,cnum);
1736   CHECK_READ(fnum);
1737   CHECK_ERROR(fnum);
1738
1739   numtoread = SVAL(inbuf,smb_vwv1);
1740   startpos = IVAL(inbuf,smb_vwv2);
1741   
1742   outsize = set_message(outbuf,5,3,True);
1743   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1744   data = smb_buf(outbuf) + 3;
1745   
1746   if(!do_lock( fnum, cnum, numtoread, startpos, &eclass, &ecode))
1747     return (ERROR(eclass,ecode));
1748
1749   nread = read_file(fnum,data,startpos,numtoread);
1750   
1751   if (nread < 0)
1752     return(UNIXERROR(ERRDOS,ERRnoaccess));
1753   
1754   outsize += nread;
1755   SSVAL(outbuf,smb_vwv0,nread);
1756   SSVAL(outbuf,smb_vwv5,nread+3);
1757   SSVAL(smb_buf(outbuf),1,nread);
1758   
1759   DEBUG(3,("%s lockread fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1760   
1761   return(outsize);
1762 }
1763
1764
1765 /****************************************************************************
1766   reply to a read
1767 ****************************************************************************/
1768 int reply_read(char *inbuf,char *outbuf)
1769 {
1770   int cnum,numtoread,fnum;
1771   int nread = 0;
1772   char *data;
1773   uint32 startpos;
1774   int outsize = 0;
1775   
1776   cnum = SVAL(inbuf,smb_tid);
1777   fnum = GETFNUM(inbuf,smb_vwv0);
1778
1779   CHECK_FNUM(fnum,cnum);
1780   CHECK_READ(fnum);
1781   CHECK_ERROR(fnum);
1782
1783   numtoread = SVAL(inbuf,smb_vwv1);
1784   startpos = IVAL(inbuf,smb_vwv2);
1785   
1786   outsize = set_message(outbuf,5,3,True);
1787   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1788   data = smb_buf(outbuf) + 3;
1789   
1790   if (is_locked(fnum,cnum,numtoread,startpos))
1791     return(ERROR(ERRDOS,ERRlock));      
1792
1793   if (numtoread > 0)
1794     nread = read_file(fnum,data,startpos,numtoread);
1795   
1796   if (nread < 0)
1797     return(UNIXERROR(ERRDOS,ERRnoaccess));
1798   
1799   outsize += nread;
1800   SSVAL(outbuf,smb_vwv0,nread);
1801   SSVAL(outbuf,smb_vwv5,nread+3);
1802   CVAL(smb_buf(outbuf),0) = 1;
1803   SSVAL(smb_buf(outbuf),1,nread);
1804   
1805   DEBUG(3,("%s read fnum=%d cnum=%d num=%d nread=%d\n",timestring(),fnum,cnum,numtoread,nread));
1806   
1807   return(outsize);
1808 }
1809
1810
1811 /****************************************************************************
1812   reply to a read and X
1813 ****************************************************************************/
1814 int reply_read_and_X(char *inbuf,char *outbuf,int length,int bufsize)
1815 {
1816   int fnum = GETFNUM(inbuf,smb_vwv2);
1817   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
1818   int smb_maxcnt = SVAL(inbuf,smb_vwv5);
1819   int smb_mincnt = SVAL(inbuf,smb_vwv6);
1820   int cnum;
1821   int nread = -1;
1822   char *data;
1823   BOOL ok = False;
1824
1825   cnum = SVAL(inbuf,smb_tid);
1826
1827   CHECK_FNUM(fnum,cnum);
1828   CHECK_READ(fnum);
1829   CHECK_ERROR(fnum);
1830
1831   set_message(outbuf,12,0,True);
1832   data = smb_buf(outbuf);
1833
1834   if (is_locked(fnum,cnum,smb_maxcnt,smb_offs))
1835     return(ERROR(ERRDOS,ERRlock));
1836   nread = read_file(fnum,data,smb_offs,smb_maxcnt);
1837   ok = True;
1838   
1839   if (nread < 0)
1840     return(UNIXERROR(ERRDOS,ERRnoaccess));
1841   
1842   SSVAL(outbuf,smb_vwv5,nread);
1843   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
1844   SSVAL(smb_buf(outbuf),-2,nread);
1845   
1846   DEBUG(3,("%s readX fnum=%d cnum=%d min=%d max=%d nread=%d\n",
1847         timestring(),fnum,cnum,
1848         smb_mincnt,smb_maxcnt,nread));
1849
1850   chain_fnum = fnum;
1851
1852   return chain_reply(inbuf,outbuf,length,bufsize);
1853 }
1854
1855
1856 /****************************************************************************
1857   reply to a writebraw (core+ or LANMAN1.0 protocol)
1858 ****************************************************************************/
1859 int reply_writebraw(char *inbuf,char *outbuf)
1860 {
1861   int nwritten=0;
1862   int total_written=0;
1863   int numtowrite=0;
1864   int cnum,fnum;
1865   int outsize = 0;
1866   long startpos;
1867   char *data=NULL;
1868   BOOL write_through;
1869   int tcount;
1870
1871   cnum = SVAL(inbuf,smb_tid);
1872   fnum = GETFNUM(inbuf,smb_vwv0);
1873
1874   CHECK_FNUM(fnum,cnum);
1875   CHECK_WRITE(fnum);
1876   CHECK_ERROR(fnum);
1877   
1878   tcount = IVAL(inbuf,smb_vwv1);
1879   startpos = IVAL(inbuf,smb_vwv3);
1880   write_through = BITSETW(inbuf+smb_vwv7,0);
1881
1882   /* We have to deal with slightly different formats depending
1883      on whether we are using the core+ or lanman1.0 protocol */
1884   if(Protocol <= PROTOCOL_COREPLUS) {
1885     numtowrite = SVAL(smb_buf(inbuf),-2);
1886     data = smb_buf(inbuf);
1887   } else {
1888     numtowrite = SVAL(inbuf,smb_vwv10);
1889     data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
1890   }
1891
1892   /* force the error type */
1893   CVAL(inbuf,smb_com) = SMBwritec;
1894   CVAL(outbuf,smb_com) = SMBwritec;
1895
1896   if (is_locked(fnum,cnum,tcount,startpos))
1897     return(ERROR(ERRDOS,ERRlock));
1898
1899   if (seek_file(fnum,startpos) != startpos)
1900     DEBUG(0,("couldn't seek to %d in writebraw\n",startpos));
1901
1902   if (numtowrite>0)
1903     nwritten = write_file(fnum,data,numtowrite);
1904   
1905   DEBUG(3,("%s writebraw1 fnum=%d cnum=%d start=%d num=%d wrote=%d sync=%d\n",
1906            timestring(),fnum,cnum,startpos,numtowrite,nwritten,write_through));
1907
1908   if (nwritten < numtowrite) 
1909     return(UNIXERROR(ERRHRD,ERRdiskfull));
1910
1911   total_written = nwritten;
1912
1913   /* Return a message to the redirector to tell it
1914      to send more bytes */
1915   CVAL(outbuf,smb_com) = SMBwritebraw;
1916   SSVALS(outbuf,smb_vwv0,-1);
1917   outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
1918   send_smb(Client,outbuf);
1919   
1920   /* Now read the raw data into the buffer and write it */
1921   if (read_smb_length(Client,inbuf,SMB_SECONDARY_WAIT) == -1) {
1922     exit_server("secondary writebraw failed");
1923   }
1924   
1925   /* Even though this is not an smb message, smb_len
1926      returns the generic length of an smb message */
1927   numtowrite = smb_len(inbuf);
1928
1929   if (tcount > nwritten+numtowrite) {
1930     DEBUG(3,("Client overestimated the write %d %d %d\n",
1931              tcount,nwritten,numtowrite));
1932   }
1933
1934   nwritten = transfer_file(Client,Files[fnum].fd_ptr->fd,numtowrite,NULL,0,
1935                            startpos+nwritten);
1936   total_written += nwritten;
1937   
1938   /* Set up outbuf to return the correct return */
1939   outsize = set_message(outbuf,1,0,True);
1940   CVAL(outbuf,smb_com) = SMBwritec;
1941   SSVAL(outbuf,smb_vwv0,total_written);
1942
1943   if (nwritten < numtowrite) {
1944     CVAL(outbuf,smb_rcls) = ERRHRD;
1945     SSVAL(outbuf,smb_err,ERRdiskfull);      
1946   }
1947
1948   if (lp_syncalways(SNUM(cnum)) || write_through)
1949     sync_file(fnum);
1950
1951   DEBUG(3,("%s writebraw2 fnum=%d cnum=%d start=%d num=%d wrote=%d\n",
1952            timestring(),fnum,cnum,startpos,numtowrite,total_written));
1953
1954   /* we won't return a status if write through is not selected - this 
1955      follows what WfWg does */
1956   if (!write_through && total_written==tcount)
1957     return(-1);
1958
1959   return(outsize);
1960 }
1961
1962
1963 /****************************************************************************
1964   reply to a writeunlock (core+)
1965 ****************************************************************************/
1966 int reply_writeunlock(char *inbuf,char *outbuf)
1967 {
1968   int cnum,fnum;
1969   int nwritten = -1;
1970   int outsize = 0;
1971   char *data;
1972   uint32 numtowrite,startpos;
1973   int eclass;
1974   uint32 ecode;
1975   
1976   cnum = SVAL(inbuf,smb_tid);
1977   fnum = GETFNUM(inbuf,smb_vwv0);
1978
1979   CHECK_FNUM(fnum,cnum);
1980   CHECK_WRITE(fnum);
1981   CHECK_ERROR(fnum);
1982
1983   numtowrite = SVAL(inbuf,smb_vwv1);
1984   startpos = IVAL(inbuf,smb_vwv2);
1985   data = smb_buf(inbuf) + 3;
1986   
1987   if (is_locked(fnum,cnum,numtowrite,startpos))
1988     return(ERROR(ERRDOS,ERRlock));
1989
1990   seek_file(fnum,startpos);
1991
1992   /* The special X/Open SMB protocol handling of
1993      zero length writes is *NOT* done for
1994      this call */
1995   if(numtowrite == 0)
1996     nwritten = 0;
1997   else
1998     nwritten = write_file(fnum,data,numtowrite);
1999   
2000   if (lp_syncalways(SNUM(cnum)))
2001     sync_file(fnum);
2002
2003   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2004     return(UNIXERROR(ERRDOS,ERRnoaccess));
2005
2006   if(!do_unlock(fnum, cnum, numtowrite, startpos, &eclass, &ecode))
2007     return(ERROR(eclass,ecode));
2008
2009   outsize = set_message(outbuf,1,0,True);
2010   
2011   SSVAL(outbuf,smb_vwv0,nwritten);
2012   
2013   DEBUG(3,("%s writeunlock fnum=%d cnum=%d num=%d wrote=%d\n",
2014            timestring(),fnum,cnum,numtowrite,nwritten));
2015   
2016   return(outsize);
2017 }
2018
2019
2020 /****************************************************************************
2021   reply to a write
2022 ****************************************************************************/
2023 int reply_write(char *inbuf,char *outbuf,int dum1,int dum2)
2024 {
2025   int cnum,numtowrite,fnum;
2026   int nwritten = -1;
2027   int outsize = 0;
2028   int startpos;
2029   char *data;
2030
2031   dum1 = dum2 = 0;
2032
2033   
2034   cnum = SVAL(inbuf,smb_tid);
2035   fnum = GETFNUM(inbuf,smb_vwv0);
2036
2037   CHECK_FNUM(fnum,cnum);
2038   CHECK_WRITE(fnum);
2039   CHECK_ERROR(fnum);
2040
2041   numtowrite = SVAL(inbuf,smb_vwv1);
2042   startpos = IVAL(inbuf,smb_vwv2);
2043   data = smb_buf(inbuf) + 3;
2044   
2045   if (is_locked(fnum,cnum,numtowrite,startpos))
2046     return(ERROR(ERRDOS,ERRlock));
2047
2048   seek_file(fnum,startpos);
2049
2050   /* X/Open SMB protocol says that if smb_vwv1 is
2051      zero then the file size should be extended or
2052      truncated to the size given in smb_vwv[2-3] */
2053   if(numtowrite == 0)
2054     nwritten = set_filelen(Files[fnum].fd_ptr->fd, startpos);
2055   else
2056     nwritten = write_file(fnum,data,numtowrite);
2057   
2058   if (lp_syncalways(SNUM(cnum)))
2059     sync_file(fnum);
2060
2061   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0))
2062     return(UNIXERROR(ERRDOS,ERRnoaccess));
2063
2064   outsize = set_message(outbuf,1,0,True);
2065   
2066   SSVAL(outbuf,smb_vwv0,nwritten);
2067
2068   if (nwritten < numtowrite) {
2069     CVAL(outbuf,smb_rcls) = ERRHRD;
2070     SSVAL(outbuf,smb_err,ERRdiskfull);      
2071   }
2072   
2073   DEBUG(3,("%s write fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,numtowrite,nwritten));
2074   
2075   return(outsize);
2076 }
2077
2078
2079 /****************************************************************************
2080   reply to a write and X
2081 ****************************************************************************/
2082 int reply_write_and_X(char *inbuf,char *outbuf,int length,int bufsize)
2083 {
2084   int fnum = GETFNUM(inbuf,smb_vwv2);
2085   uint32 smb_offs = IVAL(inbuf,smb_vwv3);
2086   int smb_dsize = SVAL(inbuf,smb_vwv10);
2087   int smb_doff = SVAL(inbuf,smb_vwv11);
2088   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2089   int cnum;
2090   int nwritten = -1;
2091   char *data;
2092
2093   cnum = SVAL(inbuf,smb_tid);
2094
2095   CHECK_FNUM(fnum,cnum);
2096   CHECK_WRITE(fnum);
2097   CHECK_ERROR(fnum);
2098
2099   data = smb_base(inbuf) + smb_doff;
2100
2101   if (is_locked(fnum,cnum,smb_dsize,smb_offs))
2102     return(ERROR(ERRDOS,ERRlock));
2103
2104   seek_file(fnum,smb_offs);
2105   
2106   /* X/Open SMB protocol says that, unlike SMBwrite
2107      if the length is zero then NO truncation is
2108      done, just a write of zero. To truncate a file,
2109      use SMBwrite. */
2110   if(smb_dsize == 0)
2111     nwritten = 0;
2112   else
2113     nwritten = write_file(fnum,data,smb_dsize);
2114   
2115   if(((nwritten == 0) && (smb_dsize != 0))||(nwritten < 0))
2116     return(UNIXERROR(ERRDOS,ERRnoaccess));
2117
2118   set_message(outbuf,6,0,True);
2119   
2120   SSVAL(outbuf,smb_vwv2,nwritten);
2121   
2122   if (nwritten < smb_dsize) {
2123     CVAL(outbuf,smb_rcls) = ERRHRD;
2124     SSVAL(outbuf,smb_err,ERRdiskfull);      
2125   }
2126
2127   DEBUG(3,("%s writeX fnum=%d cnum=%d num=%d wrote=%d\n",timestring(),fnum,cnum,smb_dsize,nwritten));
2128
2129   chain_fnum = fnum;
2130
2131   if (lp_syncalways(SNUM(cnum)) || write_through)
2132     sync_file(fnum);
2133
2134   return chain_reply(inbuf,outbuf,length,bufsize);
2135 }
2136
2137
2138 /****************************************************************************
2139   reply to a lseek
2140 ****************************************************************************/
2141 int reply_lseek(char *inbuf,char *outbuf)
2142 {
2143   int cnum,fnum;
2144   uint32 startpos;
2145   int32 res= -1;
2146   int mode,umode;
2147   int outsize = 0;
2148   
2149   cnum = SVAL(inbuf,smb_tid);
2150   fnum = GETFNUM(inbuf,smb_vwv0);
2151
2152   CHECK_FNUM(fnum,cnum);
2153   CHECK_ERROR(fnum);
2154
2155   mode = SVAL(inbuf,smb_vwv1) & 3;
2156   startpos = IVAL(inbuf,smb_vwv2);
2157
2158   switch (mode & 3) 
2159     {
2160     case 0: umode = SEEK_SET; break;
2161     case 1: umode = SEEK_CUR; break;
2162     case 2: umode = SEEK_END; break;
2163     default:
2164       umode = SEEK_SET; break;
2165     }
2166   
2167   res = lseek(Files[fnum].fd_ptr->fd,startpos,umode);
2168   Files[fnum].pos = res;
2169   
2170   outsize = set_message(outbuf,2,0,True);
2171   SIVALS(outbuf,smb_vwv0,res);
2172   
2173   DEBUG(3,("%s lseek fnum=%d cnum=%d ofs=%d mode=%d\n",timestring(),fnum,cnum,startpos,mode));
2174   
2175   return(outsize);
2176 }
2177
2178
2179 /****************************************************************************
2180   reply to a flush
2181 ****************************************************************************/
2182 int reply_flush(char *inbuf,char *outbuf)
2183 {
2184   int cnum, fnum;
2185   int outsize = set_message(outbuf,0,0,True);
2186
2187   cnum = SVAL(inbuf,smb_tid);
2188   fnum = GETFNUM(inbuf,smb_vwv0);
2189
2190   if (fnum != 0xFFFF) {
2191     CHECK_FNUM(fnum,cnum);
2192     CHECK_ERROR(fnum);
2193   }
2194
2195   if (fnum == 0xFFFF)
2196     {
2197       int i;
2198       for (i=0;i<MAX_OPEN_FILES;i++)
2199         if (OPEN_FNUM(i))
2200           sync_file(i);
2201     }
2202   else
2203     sync_file(fnum);
2204
2205   DEBUG(3,("%s flush fnum=%d\n",timestring(),fnum));
2206   return(outsize);
2207 }
2208
2209
2210 /****************************************************************************
2211   reply to a exit
2212 ****************************************************************************/
2213 int reply_exit(char *inbuf,char *outbuf)
2214 {
2215   int outsize = set_message(outbuf,0,0,True);
2216   DEBUG(3,("%s exit\n",timestring()));
2217   
2218   return(outsize);
2219 }
2220
2221
2222 /****************************************************************************
2223   reply to a close
2224 ****************************************************************************/
2225 int reply_close(char *inbuf,char *outbuf)
2226 {
2227   int fnum,cnum;
2228   int outsize = 0;
2229   time_t mtime;
2230   int32 eclass = 0, err = 0;
2231
2232   outsize = set_message(outbuf,0,0,True);
2233
2234   cnum = SVAL(inbuf,smb_tid);
2235
2236   fnum = GETFNUM(inbuf,smb_vwv0);
2237   CHECK_FNUM(fnum,cnum);
2238
2239   if(HAS_CACHED_ERROR(fnum)) {
2240     eclass = Files[fnum].wbmpx_ptr->wr_errclass;
2241     err = Files[fnum].wbmpx_ptr->wr_error;
2242   }
2243
2244   mtime = make_unix_date3(inbuf+smb_vwv1);
2245
2246   /* try and set the date */
2247   set_filetime(Files[fnum].name,mtime);
2248
2249   close_file(fnum);
2250
2251   /* We have a cached error */
2252   if(eclass || err)
2253     return(ERROR(eclass,err));
2254
2255   DEBUG(3,("%s close fd=%d fnum=%d cnum=%d (numopen=%d)\n",
2256            timestring(),Files[fnum].fd_ptr->fd,fnum,cnum,
2257            Connections[cnum].num_files_open));
2258   
2259   return(outsize);
2260 }
2261
2262
2263 /****************************************************************************
2264   reply to a writeclose (Core+ protocol)
2265 ****************************************************************************/
2266 int reply_writeclose(char *inbuf,char *outbuf)
2267 {
2268   int cnum,numtowrite,fnum;
2269   int nwritten = -1;
2270   int outsize = 0;
2271   int startpos;
2272   char *data;
2273   time_t mtime;
2274   
2275   cnum = SVAL(inbuf,smb_tid);
2276   fnum = GETFNUM(inbuf,smb_vwv0);
2277
2278   CHECK_FNUM(fnum,cnum);
2279   CHECK_WRITE(fnum);
2280   CHECK_ERROR(fnum);
2281
2282   numtowrite = SVAL(inbuf,smb_vwv1);
2283   startpos = IVAL(inbuf,smb_vwv2);
2284   mtime = make_unix_date3(inbuf+smb_vwv4);
2285   data = smb_buf(inbuf) + 1;
2286   
2287   if (is_locked(fnum,cnum,numtowrite,startpos))
2288     return(ERROR(ERRDOS,ERRlock));
2289       
2290   seek_file(fnum,startpos);
2291       
2292   nwritten = write_file(fnum,data,numtowrite);
2293
2294   set_filetime(Files[fnum].name,mtime);
2295   
2296   close_file(fnum);
2297
2298   DEBUG(3,("%s writeclose fnum=%d cnum=%d num=%d wrote=%d (numopen=%d)\n",
2299            timestring(),fnum,cnum,numtowrite,nwritten,
2300            Connections[cnum].num_files_open));
2301   
2302   if (nwritten <= 0)
2303     return(UNIXERROR(ERRDOS,ERRnoaccess));
2304   
2305   outsize = set_message(outbuf,1,0,True);
2306   
2307   SSVAL(outbuf,smb_vwv0,nwritten);
2308   return(outsize);
2309 }
2310
2311
2312 /****************************************************************************
2313   reply to a lock
2314 ****************************************************************************/
2315 int reply_lock(char *inbuf,char *outbuf)
2316 {
2317   int fnum,cnum;
2318   int outsize = set_message(outbuf,0,0,True);
2319   uint32 count,offset;
2320   int eclass;
2321   uint32 ecode;
2322
2323   cnum = SVAL(inbuf,smb_tid);
2324   fnum = GETFNUM(inbuf,smb_vwv0);
2325
2326   CHECK_FNUM(fnum,cnum);
2327   CHECK_ERROR(fnum);
2328
2329   count = IVAL(inbuf,smb_vwv1);
2330   offset = IVAL(inbuf,smb_vwv3);
2331
2332   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));
2333
2334   if(!do_lock( fnum, cnum, count, offset, &eclass, &ecode))
2335     return (ERROR(eclass,ecode));
2336   
2337   return(outsize);
2338 }
2339
2340
2341 /****************************************************************************
2342   reply to a unlock
2343 ****************************************************************************/
2344 int reply_unlock(char *inbuf,char *outbuf)
2345 {
2346   int fnum,cnum;
2347   int outsize = set_message(outbuf,0,0,True);
2348   uint32 count,offset;
2349   int eclass;
2350   uint32 ecode;
2351   
2352   cnum = SVAL(inbuf,smb_tid);
2353   fnum = GETFNUM(inbuf,smb_vwv0);
2354
2355   CHECK_FNUM(fnum,cnum);
2356   CHECK_ERROR(fnum);
2357
2358   count = IVAL(inbuf,smb_vwv1);
2359   offset = IVAL(inbuf,smb_vwv3);
2360
2361   if(!do_unlock(fnum, cnum, count, offset, &eclass, &ecode))
2362     return (ERROR(eclass,ecode));
2363
2364   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));
2365   
2366   return(outsize);
2367 }
2368
2369
2370 /****************************************************************************
2371   reply to a tdis
2372 ****************************************************************************/
2373 int reply_tdis(char *inbuf,char *outbuf)
2374 {
2375   int cnum;
2376   int outsize = set_message(outbuf,0,0,True);
2377   uint16 vuid;
2378
2379   cnum = SVAL(inbuf,smb_tid);
2380   vuid = SVAL(inbuf,smb_uid);
2381
2382   if (!OPEN_CNUM(cnum)) {
2383     DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
2384     return(ERROR(ERRSRV,ERRinvnid));
2385   }
2386
2387   Connections[cnum].used = False;
2388
2389   close_cnum(cnum,vuid);
2390   
2391   DEBUG(3,("%s tdis cnum=%d\n",timestring(),cnum));
2392
2393   return outsize;
2394 }
2395
2396
2397
2398 /****************************************************************************
2399   reply to a echo
2400 ****************************************************************************/
2401 int reply_echo(char *inbuf,char *outbuf)
2402 {
2403   int cnum;
2404   int smb_reverb = SVAL(inbuf,smb_vwv0);
2405   int seq_num;
2406   int data_len = smb_buflen(inbuf);
2407   int outsize = set_message(outbuf,1,data_len,True);
2408
2409   cnum = SVAL(inbuf,smb_tid);
2410
2411   /* According to the latest CIFS spec we shouldn't
2412      care what the TID is.
2413    */
2414
2415 #if 0
2416   if (cnum != 0xFFFF && !OPEN_CNUM(cnum))
2417     {
2418       DEBUG(4,("Invalid cnum in echo (%d)\n",cnum));
2419       return(ERROR(ERRSRV,ERRinvnid));
2420     }
2421 #endif
2422
2423   /* copy any incoming data back out */
2424   if (data_len > 0)
2425     memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2426
2427   if (smb_reverb > 100)
2428     {
2429       DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2430       smb_reverb = 100;
2431     }
2432
2433   for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++)
2434     {
2435       SSVAL(outbuf,smb_vwv0,seq_num);
2436
2437       smb_setlen(outbuf,outsize - 4);
2438
2439       send_smb(Client,outbuf);
2440     }
2441
2442   DEBUG(3,("%s echo %d times cnum=%d\n",timestring(),smb_reverb,cnum));
2443
2444   return -1;
2445 }
2446
2447
2448 /****************************************************************************
2449   reply to a printopen
2450 ****************************************************************************/
2451 int reply_printopen(char *inbuf,char *outbuf)
2452 {
2453   pstring fname;
2454   pstring fname2;
2455   int cnum;
2456   int fnum = -1;
2457   int outsize = 0;
2458
2459   *fname = *fname2 = 0;
2460
2461   cnum = SVAL(inbuf,smb_tid);
2462
2463   if (!CAN_PRINT(cnum))
2464     return(ERROR(ERRDOS,ERRnoaccess));
2465
2466   {
2467     pstring s;
2468     char *p;
2469     pstrcpy(s,smb_buf(inbuf)+1);
2470     p = s;
2471     while (*p)
2472       {
2473         if (!(isalnum(*p) || strchr("._-",*p)))
2474           *p = 'X';
2475         p++;
2476       }
2477
2478     if (strlen(s) > 10) s[10] = 0;
2479
2480     sprintf(fname,"%s.XXXXXX",s);  
2481   }
2482
2483   fnum = find_free_file();
2484   if (fnum < 0)
2485     return(ERROR(ERRSRV,ERRnofids));
2486
2487   strcpy(fname2,(char *)mktemp(fname));
2488
2489   if (!check_name(fname2,cnum))
2490     return(ERROR(ERRDOS,ERRnoaccess));
2491
2492   /* Open for exclusive use, write only. */
2493   open_file_shared(fnum,cnum,fname2,(DENY_ALL<<4)|1, 0x12, unix_mode(cnum,0), 
2494                    0, NULL, NULL);
2495
2496   if (!Files[fnum].open)
2497     return(UNIXERROR(ERRDOS,ERRnoaccess));
2498
2499   /* force it to be a print file */
2500   Files[fnum].print_file = True;
2501   
2502   outsize = set_message(outbuf,1,0,True);
2503   SSVAL(outbuf,smb_vwv0,fnum);
2504   
2505   DEBUG(3,("%s openprint %s fd=%d fnum=%d cnum=%d\n",timestring(),fname2,Files[fnum].fd_ptr->fd,fnum,cnum));
2506   
2507   return(outsize);
2508 }
2509
2510
2511 /****************************************************************************
2512   reply to a printclose
2513 ****************************************************************************/
2514 int reply_printclose(char *inbuf,char *outbuf)
2515 {
2516   int fnum,cnum;
2517   int outsize = set_message(outbuf,0,0,True);
2518   
2519   cnum = SVAL(inbuf,smb_tid);
2520   fnum = GETFNUM(inbuf,smb_vwv0);
2521
2522   CHECK_FNUM(fnum,cnum);
2523   CHECK_ERROR(fnum);
2524
2525   if (!CAN_PRINT(cnum))
2526     return(ERROR(ERRDOS,ERRnoaccess));
2527   
2528   close_file(fnum);
2529   
2530   DEBUG(3,("%s printclose fd=%d fnum=%d cnum=%d\n",timestring(),Files[fnum].fd_ptr->fd,fnum,cnum));
2531   
2532   return(outsize);
2533 }
2534
2535
2536 /****************************************************************************
2537   reply to a printqueue
2538 ****************************************************************************/
2539 int reply_printqueue(char *inbuf,char *outbuf)
2540 {
2541   int cnum;
2542   int outsize = set_message(outbuf,2,3,True);
2543   int max_count = SVAL(inbuf,smb_vwv0);
2544   int start_index = SVAL(inbuf,smb_vwv1);
2545   uint16 vuid;
2546
2547   cnum = SVAL(inbuf,smb_tid);
2548   vuid = SVAL(inbuf,smb_uid);
2549
2550 /* allow checking the queue for anyone */
2551 #if 0
2552   if (!CAN_PRINT(cnum))
2553     return(ERROR(ERRDOS,ERRnoaccess));
2554 #endif
2555
2556   SSVAL(outbuf,smb_vwv0,0);
2557   SSVAL(outbuf,smb_vwv1,0);
2558   CVAL(smb_buf(outbuf),0) = 1;
2559   SSVAL(smb_buf(outbuf),1,0);
2560   
2561   DEBUG(3,("%s printqueue cnum=%d start_index=%d max_count=%d\n",
2562         timestring(),cnum,start_index,max_count));
2563
2564   if (!OPEN_CNUM(cnum) || !Connections[cnum].printer)
2565     {
2566       int i;
2567       cnum = -1;
2568
2569       for (i=0;i<MAX_CONNECTIONS;i++)
2570         if (CAN_PRINT(i) && Connections[i].printer)
2571           cnum = i;
2572
2573       if (cnum == -1)
2574         for (i=0;i<MAX_CONNECTIONS;i++)
2575           if (OPEN_CNUM(i))
2576             cnum = i;
2577
2578       if (!OPEN_CNUM(cnum))
2579         return(ERROR(ERRSRV,ERRinvnid));
2580
2581       DEBUG(5,("connection not open or not a printer, using cnum %d\n",cnum));
2582     }
2583
2584   if (!become_user(cnum,vuid))
2585     return(ERROR(ERRSRV,ERRinvnid));
2586
2587   {
2588     print_queue_struct *queue = NULL;
2589     char *p = smb_buf(outbuf) + 3;
2590     int count = get_printqueue(SNUM(cnum),cnum,&queue,NULL);
2591     int num_to_get = ABS(max_count);
2592     int first = (max_count>0?start_index:start_index+max_count+1);
2593     int i;
2594
2595     if (first >= count)
2596       num_to_get = 0;
2597     else
2598       num_to_get = MIN(num_to_get,count-first);
2599     
2600
2601     for (i=first;i<first+num_to_get;i++)
2602       {
2603         put_dos_date2(p,0,queue[i].time);
2604         CVAL(p,4) = (queue[i].status==LPQ_PRINTING?2:3);
2605         SSVAL(p,5,printjob_encode(SNUM(cnum), queue[i].job));
2606         SIVAL(p,7,queue[i].size);
2607         CVAL(p,11) = 0;
2608         StrnCpy(p+12,queue[i].user,16);
2609         p += 28;
2610       }
2611
2612     if (count > 0)
2613       {
2614         outsize = set_message(outbuf,2,28*count+3,False);         
2615         SSVAL(outbuf,smb_vwv0,count);
2616         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
2617         CVAL(smb_buf(outbuf),0) = 1;
2618         SSVAL(smb_buf(outbuf),1,28*count);
2619       }
2620
2621     if (queue) free(queue);
2622           
2623     DEBUG(3,("%d entries returned in queue\n",count));
2624   }
2625   
2626   return(outsize);
2627 }
2628
2629
2630 /****************************************************************************
2631   reply to a printwrite
2632 ****************************************************************************/
2633 int reply_printwrite(char *inbuf,char *outbuf)
2634 {
2635   int cnum,numtowrite,fnum;
2636   int outsize = set_message(outbuf,0,0,True);
2637   char *data;
2638   
2639   cnum = SVAL(inbuf,smb_tid);
2640
2641   if (!CAN_PRINT(cnum))
2642     return(ERROR(ERRDOS,ERRnoaccess));
2643
2644   fnum = GETFNUM(inbuf,smb_vwv0);
2645
2646   CHECK_FNUM(fnum,cnum);
2647   CHECK_WRITE(fnum);
2648   CHECK_ERROR(fnum);
2649
2650   numtowrite = SVAL(smb_buf(inbuf),1);
2651   data = smb_buf(inbuf) + 3;
2652   
2653   if (write_file(fnum,data,numtowrite) != numtowrite)
2654     return(UNIXERROR(ERRDOS,ERRnoaccess));
2655   
2656   DEBUG(3,("%s printwrite fnum=%d cnum=%d num=%d\n",timestring(),fnum,cnum,numtowrite));
2657   
2658   return(outsize);
2659 }
2660
2661
2662 /****************************************************************************
2663   reply to a mkdir
2664 ****************************************************************************/
2665 int reply_mkdir(char *inbuf,char *outbuf)
2666 {
2667   pstring directory;
2668   int cnum;
2669   int outsize,ret= -1;
2670   BOOL bad_path = False;
2671  
2672   pstrcpy(directory,smb_buf(inbuf) + 1);
2673   cnum = SVAL(inbuf,smb_tid);
2674   unix_convert(directory,cnum,0,&bad_path);
2675   
2676   if (check_name(directory,cnum))
2677     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
2678   
2679   if (ret < 0)
2680   {
2681     if((errno == ENOENT) && bad_path)
2682     {
2683       unix_ERR_class = ERRDOS;
2684       unix_ERR_code = ERRbadpath;
2685     }
2686     return(UNIXERROR(ERRDOS,ERRnoaccess));
2687   }
2688  
2689   outsize = set_message(outbuf,0,0,True);
2690   
2691   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
2692   
2693   return(outsize);
2694 }
2695
2696 /****************************************************************************
2697 Static function used by reply_rmdir to delete an entire directory
2698 tree recursively.
2699 ****************************************************************************/
2700 static BOOL recursive_rmdir(char *directory)
2701 {
2702   char *dname = NULL;
2703   BOOL ret = False;
2704   void *dirptr = OpenDir(-1, directory, False);
2705
2706   if(dirptr == NULL)
2707     return True;
2708
2709   while((dname = ReadDirName(dirptr)))
2710   {
2711     pstring fullname;
2712     struct stat st;
2713
2714     if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2715       continue;
2716
2717     /* Construct the full name. */
2718     if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
2719     {
2720       errno = ENOMEM;
2721       ret = True;
2722       break;
2723     }
2724     strcpy(fullname, directory);
2725     strcat(fullname, "/");
2726     strcat(fullname, dname);
2727
2728     if(sys_lstat(fullname, &st) != 0)
2729     {
2730       ret = True;
2731       break;
2732     }
2733
2734     if(st.st_mode & S_IFDIR)
2735     {
2736       if(recursive_rmdir(fullname)!=0)
2737       {
2738         ret = True;
2739         break;
2740       }
2741       if(sys_rmdir(fullname) != 0)
2742       {
2743         ret = True;
2744         break;
2745       }
2746     }
2747     else if(sys_unlink(fullname) != 0)
2748     {
2749       ret = True;
2750       break;
2751     }
2752   }
2753   CloseDir(dirptr);
2754   return ret;
2755 }
2756
2757 /****************************************************************************
2758   reply to a rmdir
2759 ****************************************************************************/
2760 int reply_rmdir(char *inbuf,char *outbuf)
2761 {
2762   pstring directory;
2763   int cnum;
2764   int outsize = 0;
2765   BOOL ok = False;
2766   BOOL bad_path = False;
2767
2768   cnum = SVAL(inbuf,smb_tid);
2769   pstrcpy(directory,smb_buf(inbuf) + 1);
2770   unix_convert(directory,cnum,0,&bad_path);
2771   
2772   if (check_name(directory,cnum))
2773     {
2774
2775       dptr_closepath(directory,SVAL(inbuf,smb_pid));
2776       ok = (sys_rmdir(directory) == 0);
2777       if(!ok && (errno == ENOTEMPTY) && lp_veto_files(SNUM(cnum)))
2778         {
2779           /* Check to see if the only thing in this directory are
2780              vetoed files/directories. If so then delete them and
2781              retry. If we fail to delete any of them (and we *don't*
2782              do a recursive delete) then fail the rmdir. */
2783           BOOL all_veto_files = True;
2784           char *dname;
2785           void *dirptr = OpenDir(cnum, directory, False);
2786
2787           if(dirptr != NULL)
2788             {
2789               int dirpos = TellDir(dirptr);
2790                   while ((dname = ReadDirName(dirptr)))
2791                     {
2792                   if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2793                     continue;
2794                   if(!IS_VETO_PATH(cnum, dname))
2795                     {
2796                       all_veto_files = False;
2797                       break;
2798                     }
2799                 }
2800               if(all_veto_files)
2801                 {
2802                   SeekDir(dirptr,dirpos);
2803                   while ((dname = ReadDirName(dirptr)))
2804                     {
2805                       pstring fullname;
2806                       struct stat st;
2807
2808                       if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2809                         continue;
2810
2811                       /* Construct the full name. */
2812                       if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname))
2813                         {
2814                           errno = ENOMEM;
2815                           break;
2816                         }
2817                       pstrcpy(fullname, directory);
2818                       strcat(fullname, "/");
2819                       strcat(fullname, dname);
2820                       
2821                       if(sys_lstat(fullname, &st) != 0)
2822                         break;
2823                       if(st.st_mode & S_IFDIR)
2824                       {
2825                         if(lp_recursive_veto_delete(SNUM(cnum)))
2826                         {
2827                           if(recursive_rmdir(fullname) != 0)
2828                             break;
2829                         }
2830                         if(sys_rmdir(fullname) != 0)
2831                           break;
2832                       }
2833                       else if(sys_unlink(fullname) != 0)
2834                         break;
2835                     }
2836                   CloseDir(dirptr);
2837                   /* Retry the rmdir */
2838                   ok = (sys_rmdir(directory) == 0);
2839                 }
2840               else
2841                 CloseDir(dirptr);
2842             }
2843           else
2844             errno = ENOTEMPTY;
2845          }
2846           
2847       if (!ok)
2848         DEBUG(3,("couldn't remove directory %s : %s\n",
2849                  directory,strerror(errno)));
2850     }
2851   
2852   if (!ok)
2853   {
2854     if((errno == ENOENT) && bad_path)
2855     {
2856       unix_ERR_class = ERRDOS;
2857       unix_ERR_code = ERRbadpath;
2858     }
2859     return(UNIXERROR(ERRDOS,ERRbadpath));
2860   }
2861  
2862   outsize = set_message(outbuf,0,0,True);
2863   
2864   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
2865   
2866   return(outsize);
2867 }
2868
2869
2870 /*******************************************************************
2871 resolve wildcards in a filename rename
2872 ********************************************************************/
2873 static BOOL resolve_wildcards(char *name1,char *name2)
2874 {
2875   fstring root1,root2;
2876   fstring ext1,ext2;
2877   char *p,*p2;
2878
2879   name1 = strrchr(name1,'/');
2880   name2 = strrchr(name2,'/');
2881
2882   if (!name1 || !name2) return(False);
2883   
2884   fstrcpy(root1,name1);
2885   fstrcpy(root2,name2);
2886   p = strrchr(root1,'.');
2887   if (p) {
2888     *p = 0;
2889     fstrcpy(ext1,p+1);
2890   } else {
2891     fstrcpy(ext1,"");    
2892   }
2893   p = strrchr(root2,'.');
2894   if (p) {
2895     *p = 0;
2896     fstrcpy(ext2,p+1);
2897   } else {
2898     fstrcpy(ext2,"");    
2899   }
2900
2901   p = root1;
2902   p2 = root2;
2903   while (*p2) {
2904     if (*p2 == '?') {
2905       *p2 = *p;
2906       p2++;
2907     } else {
2908       p2++;
2909     }
2910     if (*p) p++;
2911   }
2912
2913   p = ext1;
2914   p2 = ext2;
2915   while (*p2) {
2916     if (*p2 == '?') {
2917       *p2 = *p;
2918       p2++;
2919     } else {
2920       p2++;
2921     }
2922     if (*p) p++;
2923   }
2924
2925   strcpy(name2,root2);
2926   if (ext2[0]) {
2927     strcat(name2,".");
2928     strcat(name2,ext2);
2929   }
2930
2931   return(True);
2932 }
2933
2934 /*******************************************************************
2935 check if a user is allowed to rename a file
2936 ********************************************************************/
2937 static BOOL can_rename(char *fname,int cnum)
2938 {
2939   struct stat sbuf;
2940
2941   if (!CAN_WRITE(cnum)) return(False);
2942
2943   if (sys_lstat(fname,&sbuf) != 0) return(False);
2944   if (!check_file_sharing(cnum,fname)) return(False);
2945
2946   return(True);
2947 }
2948
2949 /****************************************************************************
2950   reply to a mv
2951 ****************************************************************************/
2952 int reply_mv(char *inbuf,char *outbuf)
2953 {
2954   int outsize = 0;
2955   pstring name;
2956   int cnum;
2957   pstring directory;
2958   pstring mask,newname;
2959   pstring newname_last_component;
2960   char *p;
2961   int count=0;
2962   int error = ERRnoaccess;
2963   BOOL has_wild;
2964   BOOL exists=False;
2965   BOOL bad_path1 = False;
2966   BOOL bad_path2 = False;
2967
2968   *directory = *mask = 0;
2969
2970   cnum = SVAL(inbuf,smb_tid);
2971   
2972   pstrcpy(name,smb_buf(inbuf) + 1);
2973   pstrcpy(newname,smb_buf(inbuf) + 3 + strlen(name));
2974    
2975   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
2976    
2977   unix_convert(name,cnum,0,&bad_path1);
2978   unix_convert(newname,cnum,newname_last_component,&bad_path2);
2979
2980   /*
2981    * Split the old name into directory and last component
2982    * strings. Note that unix_convert may have stripped off a 
2983    * leading ./ from both name and newname if the rename is 
2984    * at the root of the share. We need to make sure either both
2985    * name and newname contain a / character or neither of them do
2986    * as this is checked in resolve_wildcards().
2987    */
2988
2989   p = strrchr(name,'/');
2990   if (!p) {
2991     strcpy(directory,".");
2992     strcpy(mask,name);
2993   } else {
2994     *p = 0;
2995     strcpy(directory,name);
2996     strcpy(mask,p+1);
2997     *p = '/'; /* Replace needed for exceptional test below. */
2998   }
2999
3000   if (is_mangled(mask))
3001     check_mangled_stack(mask);
3002
3003   has_wild = strchr(mask,'*') || strchr(mask,'?');
3004
3005   if (!has_wild) {
3006     BOOL is_short_name = is_8_3(name, True);
3007
3008     /* Add a terminating '/' to the directory name. */
3009     strcat(directory,"/");
3010     strcat(directory,mask);
3011
3012     /* Ensure newname contains a '/' also */
3013     if(strrchr(newname,'/') == 0) {
3014       pstring tmpstr;
3015
3016       strcpy(tmpstr, "./");
3017       strcat(tmpstr, newname);
3018       strcpy(newname, tmpstr);
3019     }
3020   
3021     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", 
3022             case_sensitive, case_preserve, short_case_preserve, directory, 
3023             newname, newname_last_component, is_short_name));
3024
3025     /*
3026      * Check for special case with case preserving and not
3027      * case sensitive, if directory and newname are identical,
3028      * and the old last component differs from the original
3029      * last component only by case, then we should allow
3030      * the rename (user is trying to change the case of the
3031      * filename).
3032      */
3033     if((case_sensitive == False) && ( ((case_preserve == True) && (is_short_name == False)) || 
3034             ((short_case_preserve == True) && (is_short_name == True))) &&
3035        strcsequal(directory, newname)) {
3036       pstring newname_modified_last_component;
3037
3038       /*
3039        * Get the last component of the modified name.
3040        * Note that we guarantee that newname contains a '/'
3041        * character above.
3042        */
3043       p = strrchr(newname,'/');
3044       strcpy(newname_modified_last_component,p+1);
3045
3046       if(strcsequal(newname_modified_last_component, 
3047                     newname_last_component) == False) {
3048         /*
3049          * Replace the modified last component with
3050          * the original.
3051          */
3052         strcpy(p+1, newname_last_component);
3053       }
3054     }
3055
3056     if (resolve_wildcards(directory,newname) && 
3057         can_rename(directory,cnum) && 
3058         !file_exist(newname,NULL) &&
3059         !sys_rename(directory,newname)) count++;
3060
3061     DEBUG(3,("reply_mv : %s doing rename on %s -> %s\n",(count != 0) ? "succeeded" : "failed",
3062                          directory,newname));
3063
3064     if (!count) exists = file_exist(directory,NULL);
3065     if (!count && exists && file_exist(newname,NULL)) {
3066       exists = True;
3067       error = 183;
3068     }
3069   } else {
3070     void *dirptr = NULL;
3071     char *dname;
3072     pstring destname;
3073
3074     if (check_name(directory,cnum))
3075       dirptr = OpenDir(cnum, directory, True);
3076
3077     if (dirptr)
3078       {
3079         error = ERRbadfile;
3080
3081         if (strequal(mask,"????????.???"))
3082           strcpy(mask,"*");
3083
3084         while ((dname = ReadDirName(dirptr)))
3085           {
3086             pstring fname;
3087             pstrcpy(fname,dname);
3088             
3089             if(!mask_match(fname, mask, case_sensitive, False)) continue;
3090
3091             error = ERRnoaccess;
3092             sprintf(fname,"%s/%s",directory,dname);
3093             if (!can_rename(fname,cnum)) continue;
3094             pstrcpy(destname,newname);
3095
3096             if (!resolve_wildcards(fname,destname)) continue;
3097
3098             if (file_exist(destname,NULL)) {
3099               error = 183;
3100               continue;
3101             }
3102             if (!sys_rename(fname,destname)) count++;
3103             DEBUG(3,("reply_mv : doing rename on %s -> %s\n",fname,destname));
3104           }
3105         CloseDir(dirptr);
3106       }
3107   }
3108   
3109   if (count == 0) {
3110     if (exists)
3111       return(ERROR(ERRDOS,error));
3112     else
3113     {
3114       if((errno == ENOENT) && (bad_path1 || bad_path2))
3115       {
3116         unix_ERR_class = ERRDOS;
3117         unix_ERR_code = ERRbadpath;
3118       }
3119       return(UNIXERROR(ERRDOS,error));
3120     }
3121   }
3122   
3123   outsize = set_message(outbuf,0,0,True);
3124   
3125   return(outsize);
3126 }
3127
3128 /*******************************************************************
3129   copy a file as part of a reply_copy
3130   ******************************************************************/
3131 static BOOL copy_file(char *src,char *dest1,int cnum,int ofun,
3132                       int count,BOOL target_is_directory)
3133 {
3134   int Access,action;
3135   struct stat st;
3136   int ret=0;
3137   int fnum1,fnum2;
3138   pstring dest;
3139   
3140   pstrcpy(dest,dest1);
3141   if (target_is_directory) {
3142     char *p = strrchr(src,'/');
3143     if (p) 
3144       p++;
3145     else
3146       p = src;
3147     strcat(dest,"/");
3148     strcat(dest,p);
3149   }
3150
3151   if (!file_exist(src,&st)) return(False);
3152
3153   fnum1 = find_free_file();
3154   if (fnum1<0) return(False);
3155   open_file_shared(fnum1,cnum,src,(DENY_NONE<<4),
3156                    1,0,0,&Access,&action);
3157
3158   if (!Files[fnum1].open) return(False);
3159
3160   if (!target_is_directory && count)
3161     ofun = 1;
3162
3163   fnum2 = find_free_file();
3164   if (fnum2<0) {
3165     close_file(fnum1);
3166     return(False);
3167   }
3168   open_file_shared(fnum2,cnum,dest,(DENY_NONE<<4)|1,
3169                    ofun,st.st_mode,0,&Access,&action);
3170
3171   if (!Files[fnum2].open) {
3172     close_file(fnum1);
3173     return(False);
3174   }
3175
3176   if ((ofun&3) == 1) {
3177     lseek(Files[fnum2].fd_ptr->fd,0,SEEK_END);
3178   }
3179   
3180   if (st.st_size)
3181     ret = transfer_file(Files[fnum1].fd_ptr->fd,Files[fnum2].fd_ptr->fd,st.st_size,NULL,0,0);
3182
3183   close_file(fnum1);
3184   close_file(fnum2);
3185
3186   return(ret == st.st_size);
3187 }
3188
3189
3190
3191 /****************************************************************************
3192   reply to a file copy.
3193   ****************************************************************************/
3194 int reply_copy(char *inbuf,char *outbuf)
3195 {
3196   int outsize = 0;
3197   pstring name;
3198   int cnum;
3199   pstring directory;
3200   pstring mask,newname;
3201   char *p;
3202   int count=0;
3203   int error = ERRnoaccess;
3204   BOOL has_wild;
3205   BOOL exists=False;
3206   int tid2 = SVAL(inbuf,smb_vwv0);
3207   int ofun = SVAL(inbuf,smb_vwv1);
3208   int flags = SVAL(inbuf,smb_vwv2);
3209   BOOL target_is_directory=False;
3210   BOOL bad_path1 = False;
3211   BOOL bad_path2 = False;
3212
3213   *directory = *mask = 0;
3214
3215   cnum = SVAL(inbuf,smb_tid);
3216   
3217   pstrcpy(name,smb_buf(inbuf));
3218   pstrcpy(newname,smb_buf(inbuf) + 1 + strlen(name));
3219    
3220   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
3221    
3222   if (tid2 != cnum) {
3223     /* can't currently handle inter share copies XXXX */
3224     DEBUG(3,("Rejecting inter-share copy\n"));
3225     return(ERROR(ERRSRV,ERRinvdevice));
3226   }
3227
3228   unix_convert(name,cnum,0,&bad_path1);
3229   unix_convert(newname,cnum,0,&bad_path2);
3230
3231   target_is_directory = directory_exist(newname,NULL);
3232
3233   if ((flags&1) && target_is_directory) {
3234     return(ERROR(ERRDOS,ERRbadfile));
3235   }
3236
3237   if ((flags&2) && !target_is_directory) {
3238     return(ERROR(ERRDOS,ERRbadpath));
3239   }
3240
3241   if ((flags&(1<<5)) && directory_exist(name,NULL)) {
3242     /* wants a tree copy! XXXX */
3243     DEBUG(3,("Rejecting tree copy\n"));
3244     return(ERROR(ERRSRV,ERRerror));    
3245   }
3246
3247   p = strrchr(name,'/');
3248   if (!p) {
3249     strcpy(directory,"./");
3250     strcpy(mask,name);
3251   } else {
3252     *p = 0;
3253     strcpy(directory,name);
3254     strcpy(mask,p+1);
3255   }
3256
3257   if (is_mangled(mask))
3258     check_mangled_stack(mask);
3259
3260   has_wild = strchr(mask,'*') || strchr(mask,'?');
3261
3262   if (!has_wild) {
3263     strcat(directory,"/");
3264     strcat(directory,mask);
3265     if (resolve_wildcards(directory,newname) && 
3266         copy_file(directory,newname,cnum,ofun,
3267                   count,target_is_directory)) count++;
3268     if (!count) exists = file_exist(directory,NULL);
3269   } else {
3270     void *dirptr = NULL;
3271     char *dname;
3272     pstring destname;
3273
3274     if (check_name(directory,cnum))
3275       dirptr = OpenDir(cnum, directory, True);
3276
3277     if (dirptr)
3278       {
3279         error = ERRbadfile;
3280
3281         if (strequal(mask,"????????.???"))
3282           strcpy(mask,"*");
3283
3284         while ((dname = ReadDirName(dirptr)))
3285           {
3286             pstring fname;
3287             pstrcpy(fname,dname);
3288             
3289             if(!mask_match(fname, mask, case_sensitive, False)) continue;
3290
3291             error = ERRnoaccess;
3292             sprintf(fname,"%s/%s",directory,dname);
3293             strcpy(destname,newname);
3294             if (resolve_wildcards(fname,destname) && 
3295                 copy_file(directory,newname,cnum,ofun,
3296                           count,target_is_directory)) count++;
3297             DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
3298           }
3299         CloseDir(dirptr);
3300       }
3301   }
3302   
3303   if (count == 0) {
3304     if (exists)
3305       return(ERROR(ERRDOS,error));
3306     else
3307     {
3308       if((errno == ENOENT) && (bad_path1 || bad_path2))
3309       {
3310         unix_ERR_class = ERRDOS;
3311         unix_ERR_code = ERRbadpath;
3312       }
3313       return(UNIXERROR(ERRDOS,error));
3314     }
3315   }
3316   
3317   outsize = set_message(outbuf,1,0,True);
3318   SSVAL(outbuf,smb_vwv0,count);
3319
3320   return(outsize);
3321 }
3322
3323
3324
3325 /****************************************************************************
3326   reply to a setdir
3327 ****************************************************************************/
3328 int reply_setdir(char *inbuf,char *outbuf)
3329 {
3330   int cnum,snum;
3331   int outsize = 0;
3332   BOOL ok = False;
3333   pstring newdir;
3334   
3335   cnum = SVAL(inbuf,smb_tid);
3336   
3337   snum = Connections[cnum].service;
3338   if (!CAN_SETDIR(snum))
3339     return(ERROR(ERRDOS,ERRnoaccess));
3340   
3341   pstrcpy(newdir,smb_buf(inbuf) + 1);
3342   strlower(newdir);
3343   
3344   if (strlen(newdir) == 0)
3345     ok = True;
3346   else
3347     {
3348       ok = directory_exist(newdir,NULL);
3349       if (ok)
3350         string_set(&Connections[cnum].connectpath,newdir);
3351     }
3352   
3353   if (!ok)
3354     return(ERROR(ERRDOS,ERRbadpath));
3355   
3356   outsize = set_message(outbuf,0,0,True);
3357   CVAL(outbuf,smb_reh) = CVAL(inbuf,smb_reh);
3358   
3359   DEBUG(3,("%s setdir %s cnum=%d\n",timestring(),newdir,cnum));
3360   
3361   return(outsize);
3362 }
3363
3364
3365 /****************************************************************************
3366   reply to a lockingX request
3367 ****************************************************************************/
3368 int reply_lockingX(char *inbuf,char *outbuf,int length,int bufsize)
3369 {
3370   int fnum = GETFNUM(inbuf,smb_vwv2);
3371   unsigned char locktype = CVAL(inbuf,smb_vwv3);
3372 #if 0
3373   unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
3374 #endif
3375   uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
3376   uint16 num_locks = SVAL(inbuf,smb_vwv7);
3377   uint32 count, offset;
3378
3379   int cnum;
3380   int i;
3381   char *data;
3382   uint32 ecode=0, dummy2;
3383   int eclass=0, dummy1;
3384
3385   cnum = SVAL(inbuf,smb_tid);
3386
3387   CHECK_FNUM(fnum,cnum);
3388   CHECK_ERROR(fnum);
3389
3390   data = smb_buf(inbuf);
3391
3392   /* Check if this is an oplock break on a file
3393      we have granted an oplock on.
3394    */
3395   if((locktype == LOCKING_ANDX_OPLOCK_RELEASE) && 
3396      (num_ulocks == 0) && (num_locks == 0) &&
3397      (CVAL(inbuf,smb_vwv0) == 0xFF))
3398   {
3399     share_lock_token token;
3400     files_struct *fsp = &Files[fnum];
3401     uint32 dev = fsp->fd_ptr->dev;
3402     uint32 inode = fsp->fd_ptr->inode;
3403
3404     DEBUG(5,("reply_lockingX: oplock break reply from client for fnum = %d\n",
3405               fnum));
3406     /*
3407      * Make sure we have granted an oplock on this file.
3408      */
3409     if(!fsp->granted_oplock)
3410     {
3411       DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
3412 no oplock granted on this file.\n", fnum));
3413       return ERROR(ERRDOS,ERRlock);
3414     }
3415
3416     /* Remove the oplock flag from the sharemode. */
3417     lock_share_entry(fsp->cnum, dev, inode, &token);
3418     if(remove_share_oplock( fnum, token)==False)
3419     {
3420       DEBUG(0,("reply_lockingX: failed to remove share oplock for fnum %d, \
3421 dev = %x, inode = %x\n", fnum, dev, inode));
3422       unlock_share_entry(fsp->cnum, dev, inode, token);
3423       return -1;
3424     }
3425     unlock_share_entry(fsp->cnum, dev, inode, token);
3426
3427     /* Clear the granted flag and return. */
3428
3429     fsp->granted_oplock = False;
3430     return -1;
3431   }
3432
3433   /* Data now points at the beginning of the list
3434      of smb_unlkrng structs */
3435   for(i = 0; i < (int)num_ulocks; i++) {
3436     count = IVAL(data,SMB_LKLEN_OFFSET(i));
3437     offset = IVAL(data,SMB_LKOFF_OFFSET(i));
3438     if(!do_unlock(fnum,cnum,count,offset,&eclass, &ecode))
3439       return ERROR(eclass,ecode);
3440   }
3441
3442   /* Now do any requested locks */
3443   data += 10*num_ulocks;
3444   /* Data now points at the beginning of the list
3445      of smb_lkrng structs */
3446   for(i = 0; i < (int)num_locks; i++) {
3447     count = IVAL(data,SMB_LKLEN_OFFSET(i)); 
3448     offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
3449     if(!do_lock(fnum,cnum,count,offset, &eclass, &ecode))
3450       break;
3451   }
3452
3453   /* If any of the above locks failed, then we must unlock
3454      all of the previous locks (X/Open spec). */
3455   if(i != num_locks && num_locks != 0) {
3456     for(; i >= 0; i--) {
3457       count = IVAL(data,SMB_LKLEN_OFFSET(i));  
3458       offset = IVAL(data,SMB_LKOFF_OFFSET(i)); 
3459       do_unlock(fnum,cnum,count,offset,&dummy1,&dummy2);
3460     }
3461     return ERROR(eclass,ecode);
3462   }
3463
3464   set_message(outbuf,2,0,True);
3465   
3466   DEBUG(3,("%s lockingX fnum=%d cnum=%d type=%d num_locks=%d num_ulocks=%d\n",
3467         timestring(),fnum,cnum,(unsigned int)locktype,num_locks,num_ulocks));
3468
3469   chain_fnum = fnum;
3470
3471   return chain_reply(inbuf,outbuf,length,bufsize);
3472 }
3473
3474
3475 /****************************************************************************
3476   reply to a SMBreadbmpx (read block multiplex) request
3477 ****************************************************************************/
3478 int reply_readbmpx(char *inbuf,char *outbuf,int length,int bufsize)
3479 {
3480   int cnum,fnum;
3481   int nread = -1;
3482   int total_read;
3483   char *data;
3484   uint32 startpos;
3485   int outsize, mincount, maxcount;
3486   int max_per_packet;
3487   int tcount;
3488   int pad;
3489
3490   /* this function doesn't seem to work - disable by default */
3491   if (!lp_readbmpx())
3492     return(ERROR(ERRSRV,ERRuseSTD));
3493
3494   outsize = set_message(outbuf,8,0,True);
3495
3496   cnum = SVAL(inbuf,smb_tid);
3497   fnum = GETFNUM(inbuf,smb_vwv0);
3498
3499   CHECK_FNUM(fnum,cnum);
3500   CHECK_READ(fnum);
3501   CHECK_ERROR(fnum);
3502
3503   startpos = IVAL(inbuf,smb_vwv1);
3504   maxcount = SVAL(inbuf,smb_vwv3);
3505   mincount = SVAL(inbuf,smb_vwv4);
3506
3507   data = smb_buf(outbuf);
3508   pad = ((long)data)%4;
3509   if (pad) pad = 4 - pad;
3510   data += pad;
3511
3512   max_per_packet = bufsize-(outsize+pad);
3513   tcount = maxcount;
3514   total_read = 0;
3515
3516   if (is_locked(fnum,cnum,maxcount,startpos))
3517     return(ERROR(ERRDOS,ERRlock));
3518         
3519   do
3520     {
3521       int N = MIN(max_per_packet,tcount-total_read);
3522   
3523       nread = read_file(fnum,data,startpos,N);
3524
3525       if (nread <= 0) nread = 0;
3526
3527       if (nread < N)
3528         tcount = total_read + nread;
3529
3530       set_message(outbuf,8,nread,False);
3531       SIVAL(outbuf,smb_vwv0,startpos);
3532       SSVAL(outbuf,smb_vwv2,tcount);
3533       SSVAL(outbuf,smb_vwv6,nread);
3534       SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
3535
3536       send_smb(Client,outbuf);
3537
3538       total_read += nread;
3539       startpos += nread;
3540     }
3541   while (total_read < tcount);
3542
3543   return(-1);
3544 }
3545
3546
3547 /****************************************************************************
3548   reply to a SMBwritebmpx (write block multiplex primary) request
3549 ****************************************************************************/
3550 int reply_writebmpx(char *inbuf,char *outbuf)
3551 {
3552   int cnum,numtowrite,fnum;
3553   int nwritten = -1;
3554   int outsize = 0;
3555   uint32 startpos;
3556   int tcount, write_through, smb_doff;
3557   char *data;
3558   
3559   cnum = SVAL(inbuf,smb_tid);
3560   fnum = GETFNUM(inbuf,smb_vwv0);
3561
3562   CHECK_FNUM(fnum,cnum);
3563   CHECK_WRITE(fnum);
3564   CHECK_ERROR(fnum);
3565
3566   tcount = SVAL(inbuf,smb_vwv1);
3567   startpos = IVAL(inbuf,smb_vwv3);
3568   write_through = BITSETW(inbuf+smb_vwv7,0);
3569   numtowrite = SVAL(inbuf,smb_vwv10);
3570   smb_doff = SVAL(inbuf,smb_vwv11);
3571
3572   data = smb_base(inbuf) + smb_doff;
3573
3574   /* If this fails we need to send an SMBwriteC response,
3575      not an SMBwritebmpx - set this up now so we don't forget */
3576   CVAL(outbuf,smb_com) = SMBwritec;
3577
3578   if (is_locked(fnum,cnum,tcount,startpos))
3579     return(ERROR(ERRDOS,ERRlock));
3580
3581   seek_file(fnum,startpos);
3582   nwritten = write_file(fnum,data,numtowrite);
3583
3584   if(lp_syncalways(SNUM(cnum)) || write_through)
3585     sync_file(fnum);
3586   
3587   if(nwritten < numtowrite)
3588     return(UNIXERROR(ERRHRD,ERRdiskfull));
3589
3590   /* If the maximum to be written to this file
3591      is greater than what we just wrote then set
3592      up a secondary struct to be attached to this
3593      fd, we will use this to cache error messages etc. */
3594   if(tcount > nwritten) 
3595     {
3596       write_bmpx_struct *wbms;
3597       if(Files[fnum].wbmpx_ptr != NULL)
3598         wbms = Files[fnum].wbmpx_ptr; /* Use an existing struct */
3599       else
3600         wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
3601       if(!wbms)
3602         {
3603           DEBUG(0,("Out of memory in reply_readmpx\n"));
3604           return(ERROR(ERRSRV,ERRnoresource));
3605         }
3606       wbms->wr_mode = write_through;
3607       wbms->wr_discard = False; /* No errors yet */
3608       wbms->wr_total_written = nwritten;
3609       wbms->wr_errclass = 0;
3610       wbms->wr_error = 0;
3611       Files[fnum].wbmpx_ptr = wbms;
3612     }
3613
3614   /* We are returning successfully, set the message type back to
3615      SMBwritebmpx */
3616   CVAL(outbuf,smb_com) = SMBwriteBmpx;
3617   
3618   outsize = set_message(outbuf,1,0,True);
3619   
3620   SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
3621   
3622   DEBUG(3,("%s writebmpx fnum=%d cnum=%d num=%d wrote=%d\n",
3623         timestring(),fnum,cnum,numtowrite,nwritten));
3624   
3625   if (write_through && tcount==nwritten) {
3626     /* we need to send both a primary and a secondary response */
3627     smb_setlen(outbuf,outsize - 4);
3628     send_smb(Client,outbuf);
3629
3630     /* now the secondary */
3631     outsize = set_message(outbuf,1,0,True);
3632     CVAL(outbuf,smb_com) = SMBwritec;
3633     SSVAL(outbuf,smb_vwv0,nwritten);
3634   }
3635
3636   return(outsize);
3637 }
3638
3639
3640 /****************************************************************************
3641   reply to a SMBwritebs (write block multiplex secondary) request
3642 ****************************************************************************/
3643 int reply_writebs(char *inbuf,char *outbuf)
3644 {
3645   int cnum,numtowrite,fnum;
3646   int nwritten = -1;
3647   int outsize = 0;
3648   int32 startpos;
3649   int tcount, write_through, smb_doff;
3650   char *data;
3651   write_bmpx_struct *wbms;
3652   BOOL send_response = False;
3653   
3654   cnum = SVAL(inbuf,smb_tid);
3655   fnum = GETFNUM(inbuf,smb_vwv0);
3656   CHECK_FNUM(fnum,cnum);
3657   CHECK_WRITE(fnum);
3658
3659   tcount = SVAL(inbuf,smb_vwv1);
3660   startpos = IVAL(inbuf,smb_vwv2);
3661   numtowrite = SVAL(inbuf,smb_vwv6);
3662   smb_doff = SVAL(inbuf,smb_vwv7);
3663
3664   data = smb_base(inbuf) + smb_doff;
3665
3666   /* We need to send an SMBwriteC response, not an SMBwritebs */
3667   CVAL(outbuf,smb_com) = SMBwritec;
3668
3669   /* This fd should have an auxiliary struct attached,
3670      check that it does */
3671   wbms = Files[fnum].wbmpx_ptr;
3672   if(!wbms) return(-1);
3673
3674   /* If write through is set we can return errors, else we must
3675      cache them */
3676   write_through = wbms->wr_mode;
3677
3678   /* Check for an earlier error */
3679   if(wbms->wr_discard)
3680     return -1; /* Just discard the packet */
3681
3682   seek_file(fnum,startpos);
3683   nwritten = write_file(fnum,data,numtowrite);
3684
3685   if(lp_syncalways(SNUM(cnum)) || write_through)
3686     sync_file(fnum);
3687   
3688   if (nwritten < numtowrite)
3689     {
3690       if(write_through) {
3691         /* We are returning an error - we can delete the aux struct */
3692         if (wbms) free((char *)wbms);
3693         Files[fnum].wbmpx_ptr = NULL;
3694         return(ERROR(ERRHRD,ERRdiskfull));
3695       }
3696       return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
3697     }
3698
3699   /* Increment the total written, if this matches tcount
3700      we can discard the auxiliary struct (hurrah !) and return a writeC */
3701   wbms->wr_total_written += nwritten;
3702   if(wbms->wr_total_written >= tcount)
3703     {
3704       if (write_through) {
3705         outsize = set_message(outbuf,1,0,True);
3706         SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
3707         send_response = True;
3708       }
3709
3710       free((char *)wbms);
3711       Files[fnum].wbmpx_ptr = NULL;
3712     }
3713
3714   if(send_response)
3715     return(outsize);
3716
3717   return(-1);
3718 }
3719
3720
3721 /****************************************************************************
3722   reply to a SMBsetattrE
3723 ****************************************************************************/
3724 int reply_setattrE(char *inbuf,char *outbuf)
3725 {
3726   int cnum,fnum;
3727   struct utimbuf unix_times;
3728   int outsize = 0;
3729
3730   outsize = set_message(outbuf,0,0,True);
3731
3732   cnum = SVAL(inbuf,smb_tid);
3733   fnum = GETFNUM(inbuf,smb_vwv0);
3734
3735   CHECK_FNUM(fnum,cnum);
3736   CHECK_ERROR(fnum);
3737
3738   /* Convert the DOS times into unix times. Ignore create
3739      time as UNIX can't set this.
3740      */
3741   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
3742   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
3743   
3744   /* 
3745    * Patch from Ray Frush <frush@engr.colostate.edu>
3746    * Sometimes times are sent as zero - ignore them.
3747    */
3748
3749   if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
3750   {
3751     /* Ignore request */
3752     DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d ignoring zero request - \
3753 not setting timestamps of 0\n",
3754           timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
3755     return(outsize);
3756   }
3757   else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
3758   {
3759     /* set modify time = to access time if modify time was 0 */
3760     unix_times.modtime = unix_times.actime;
3761   }
3762
3763   /* Set the date on this file */
3764   if(sys_utime(Files[fnum].name, &unix_times))
3765     return(ERROR(ERRDOS,ERRnoaccess));
3766   
3767   DEBUG(3,("%s reply_setattrE fnum=%d cnum=%d actime=%d modtime=%d\n",
3768     timestring(), fnum,cnum,unix_times.actime,unix_times.modtime));
3769
3770   return(outsize);
3771 }
3772
3773
3774 /****************************************************************************
3775   reply to a SMBgetattrE
3776 ****************************************************************************/
3777 int reply_getattrE(char *inbuf,char *outbuf)
3778 {
3779   int cnum,fnum;
3780   struct stat sbuf;
3781   int outsize = 0;
3782   int mode;
3783
3784   outsize = set_message(outbuf,11,0,True);
3785
3786   cnum = SVAL(inbuf,smb_tid);
3787   fnum = GETFNUM(inbuf,smb_vwv0);
3788
3789   CHECK_FNUM(fnum,cnum);
3790   CHECK_ERROR(fnum);
3791
3792   /* Do an fstat on this file */
3793   if(fstat(Files[fnum].fd_ptr->fd, &sbuf))
3794     return(UNIXERROR(ERRDOS,ERRnoaccess));
3795   
3796   mode = dos_mode(cnum,Files[fnum].name,&sbuf);
3797   
3798   /* Convert the times into dos times. Set create
3799      date to be last modify date as UNIX doesn't save
3800      this */
3801   put_dos_date2(outbuf,smb_vwv0,sbuf.st_mtime);
3802   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
3803   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
3804   if (mode & aDIR)
3805     {
3806       SIVAL(outbuf,smb_vwv6,0);
3807       SIVAL(outbuf,smb_vwv8,0);
3808     }
3809   else
3810     {
3811       SIVAL(outbuf,smb_vwv6,sbuf.st_size);
3812       SIVAL(outbuf,smb_vwv8,ROUNDUP(sbuf.st_size,1024));
3813     }
3814   SSVAL(outbuf,smb_vwv10, mode);
3815   
3816   DEBUG(3,("%s reply_getattrE fnum=%d cnum=%d\n",timestring(),fnum,cnum));
3817   
3818   return(outsize);
3819 }