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