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