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