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