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