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