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