0af2ea3716a841ee23ed44d98154ca5a7a9e50b3
[tprouty/samba.git] / source / smbd / reply.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Main SMB reply routines
4    Copyright (C) Andrew Tridgell 1992-1998
5    Copyright (C) Andrew Bartlett      2001
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
29 /* look in server.c for some explanation of these variables */
30 extern int Protocol;
31 extern int max_send;
32 extern int max_recv;
33 extern char magic_char;
34 extern BOOL case_sensitive;
35 extern BOOL case_preserve;
36 extern BOOL short_case_preserve;
37 extern pstring global_myname;
38 extern int global_oplock_break;
39 unsigned int smb_echo_count = 0;
40
41 extern fstring remote_machine;
42 extern BOOL global_encrypted_passwords_negotiated;
43
44
45 /****************************************************************************
46   reply to an special message 
47 ****************************************************************************/
48
49 int reply_special(char *inbuf,char *outbuf)
50 {
51         int outsize = 4;
52         int msg_type = CVAL(inbuf,0);
53         int msg_flags = CVAL(inbuf,1);
54         pstring name1,name2;
55
56         extern fstring local_machine;
57         int len;
58         char name_type = 0;
59         
60         *name1 = *name2 = 0;
61         
62         memset(outbuf,'\0',smb_size);
63
64         smb_setlen(outbuf,0);
65         
66         switch (msg_type) {
67         case 0x81: /* session request */
68                 SCVAL(outbuf,0,0x82);
69                 SCVAL(outbuf,3,0);
70                 if (name_len(inbuf+4) > 50 || 
71                     name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
72                         DEBUG(0,("Invalid name length in session request\n"));
73                         return(0);
74                 }
75                 name_extract(inbuf,4,name1);
76                 name_extract(inbuf,4 + name_len(inbuf + 4),name2);
77                 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
78                          name1,name2));      
79
80                 fstrcpy(remote_machine,name2);
81                 remote_machine[15] = 0;
82                 trim_string(remote_machine," "," ");
83                 strlower(remote_machine);
84                 alpha_strcpy(remote_machine,remote_machine,SAFE_NETBIOS_CHARS,sizeof(remote_machine)-1);
85
86                 fstrcpy(local_machine,name1);
87                 len = strlen(local_machine);
88                 if (len == 16) {
89                         name_type = local_machine[15];
90                         local_machine[15] = 0;
91                 }
92                 trim_string(local_machine," "," ");
93                 strlower(local_machine);
94                 alpha_strcpy(local_machine,local_machine,SAFE_NETBIOS_CHARS,sizeof(local_machine)-1);
95
96                 DEBUG(2,("netbios connect: local=%s remote=%s\n",
97                         local_machine, remote_machine ));
98
99                 if (name_type == 'R') {
100                         /* We are being asked for a pathworks session --- 
101                            no thanks! */
102                         SCVAL(outbuf, 0,0x83);
103                         break;
104                 }
105
106                 /* only add the client's machine name to the list
107                    of possibly valid usernames if we are operating
108                    in share mode security */
109                 if (lp_security() == SEC_SHARE) {
110                         add_session_user(remote_machine);
111                 }
112
113                 reload_services(True);
114                 reopen_logs();
115
116                 claim_connection(NULL,"",MAXSTATUS,True);
117
118                 break;
119                 
120         case 0x89: /* session keepalive request 
121                       (some old clients produce this?) */
122                 SCVAL(outbuf,0,SMBkeepalive);
123                 SCVAL(outbuf,3,0);
124                 break;
125                 
126         case 0x82: /* positive session response */
127         case 0x83: /* negative session response */
128         case 0x84: /* retarget session response */
129                 DEBUG(0,("Unexpected session response\n"));
130                 break;
131                 
132         case SMBkeepalive: /* session keepalive */
133         default:
134                 return(0);
135         }
136         
137         DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
138                     msg_type, msg_flags));
139         
140         return(outsize);
141 }
142
143
144 /****************************************************************************
145  Reply to a tcon.
146 ****************************************************************************/
147
148 int reply_tcon(connection_struct *conn,
149                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
150 {
151         pstring service;
152         pstring password;
153         pstring dev;
154         int outsize = 0;
155         uint16 vuid = SVAL(inbuf,smb_uid);
156         int pwlen=0;
157         NTSTATUS nt_status;
158         char *p;
159         DATA_BLOB password_blob;
160         
161         START_PROFILE(SMBtcon);
162
163         *service = *password = *dev = 0;
164
165         p = smb_buf(inbuf)+1;
166         p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
167         pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
168         p += pwlen;
169         p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
170
171         p = strrchr_m(service,'\\');
172         if (p) {
173                 pstrcpy(service, p+1);
174         }
175
176         password_blob = data_blob(password, pwlen+1);
177
178         conn = make_connection(service,password_blob,dev,vuid,&nt_status);
179
180         data_blob_clear_free(&password_blob);
181   
182         if (!conn) {
183                 END_PROFILE(SMBtcon);
184                 return ERROR_NT(nt_status);
185         }
186   
187         outsize = set_message(outbuf,2,0,True);
188         SSVAL(outbuf,smb_vwv0,max_recv);
189         SSVAL(outbuf,smb_vwv1,conn->cnum);
190         SSVAL(outbuf,smb_tid,conn->cnum);
191   
192         DEBUG(3,("tcon service=%s cnum=%d\n", 
193                  service, conn->cnum));
194   
195         END_PROFILE(SMBtcon);
196         return(outsize);
197 }
198
199 /****************************************************************************
200  Reply to a tcon and X.
201 ****************************************************************************/
202
203 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
204 {
205         fstring service;
206         DATA_BLOB password;
207         pstring devicename;
208         NTSTATUS nt_status;
209         uint16 vuid = SVAL(inbuf,smb_uid);
210         int passlen = SVAL(inbuf,smb_vwv3);
211         pstring path;
212         char *p, *q;
213         extern BOOL global_encrypted_passwords_negotiated;
214         START_PROFILE(SMBtconX);        
215
216         *service = *devicename = 0;
217
218         /* we might have to close an old one */
219         if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
220                 close_cnum(conn,vuid);
221         }
222
223         if (passlen > MAX_PASS_LEN) {
224                 return ERROR_DOS(ERRDOS,ERRbuftoosmall);
225         }
226  
227         if (global_encrypted_passwords_negotiated) {
228                 password = data_blob(smb_buf(inbuf),passlen);
229         } else {
230                 password = data_blob(smb_buf(inbuf),passlen+1);
231                 /* Ensure correct termination */
232                 password.data[passlen]=0;    
233         }
234
235         p = smb_buf(inbuf) + passlen;
236         p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
237
238         /*
239          * the service name can be either: \\server\share
240          * or share directly like on the DELL PowerVault 705
241          */
242         if (*path=='\\') {      
243                 q = strchr_m(path+2,'\\');
244                 if (!q) {
245                         END_PROFILE(SMBtconX);
246                         return(ERROR_DOS(ERRDOS,ERRnosuchshare));
247                 }
248                 fstrcpy(service,q+1);
249         }
250         else
251                 fstrcpy(service,path);
252                 
253         p += srvstr_pull(inbuf, devicename, p, sizeof(devicename), 6, STR_ASCII);
254
255         DEBUG(4,("Got device type %s\n",devicename));
256
257         conn = make_connection(service,password,devicename,vuid,&nt_status);
258         
259         data_blob_clear_free(&password);
260
261         if (!conn) {
262                 END_PROFILE(SMBtconX);
263                 return ERROR_NT(nt_status);
264         }
265
266         if (Protocol < PROTOCOL_NT1) {
267                 set_message(outbuf,2,0,True);
268                 p = smb_buf(outbuf);
269                 p += srvstr_push(outbuf, p, devicename, -1, 
270                                  STR_TERMINATE|STR_ASCII);
271                 set_message_end(outbuf,p);
272         } else {
273                 /* NT sets the fstype of IPC$ to the null string */
274                 char *fsname = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
275
276                 set_message(outbuf,3,0,True);
277
278                 p = smb_buf(outbuf);
279                 p += srvstr_push(outbuf, p, devicename, -1, 
280                                  STR_TERMINATE|STR_ASCII);
281                 p += srvstr_push(outbuf, p, fsname, -1, 
282                                  STR_TERMINATE);
283                 
284                 set_message_end(outbuf,p);
285                 
286                 /* what does setting this bit do? It is set by NT4 and
287                    may affect the ability to autorun mounted cdroms */
288                 SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS); 
289                 
290                 init_dfsroot(conn, inbuf, outbuf);
291         }
292
293   
294         DEBUG(3,("tconX service=%s \n",
295                  service));
296   
297         /* set the incoming and outgoing tid to the just created one */
298         SSVAL(inbuf,smb_tid,conn->cnum);
299         SSVAL(outbuf,smb_tid,conn->cnum);
300
301         END_PROFILE(SMBtconX);
302         return chain_reply(inbuf,outbuf,length,bufsize);
303 }
304
305
306 /****************************************************************************
307   reply to an unknown type
308 ****************************************************************************/
309 int reply_unknown(char *inbuf,char *outbuf)
310 {
311         int type;
312         type = CVAL(inbuf,smb_com);
313   
314         DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
315                  smb_fn_name(type), type, type));
316   
317         return(ERROR_DOS(ERRSRV,ERRunknownsmb));
318 }
319
320
321 /****************************************************************************
322   reply to an ioctl
323 ****************************************************************************/
324 int reply_ioctl(connection_struct *conn,
325                 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
326 {
327         uint16 device     = SVAL(inbuf,smb_vwv1);
328         uint16 function   = SVAL(inbuf,smb_vwv2);
329         uint32 ioctl_code = (device << 16) + function;
330         int replysize, outsize;
331         char *p;
332         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
333         START_PROFILE(SMBioctl);
334
335         DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
336
337         switch (ioctl_code)
338         {
339             case IOCTL_QUERY_JOB_INFO:
340                 replysize = 32;
341                 break;
342             default:
343                 END_PROFILE(SMBioctl);
344                 return(ERROR_DOS(ERRSRV,ERRnosupport));
345         }
346
347         outsize = set_message(outbuf,8,replysize+1,True);
348         SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
349         SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
350         SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
351         p = smb_buf(outbuf) + 1;          /* Allow for alignment */
352
353         switch (ioctl_code)
354         {
355             case IOCTL_QUERY_JOB_INFO:              
356                 SSVAL(p,0,fsp->print_jobid);             /* Job number */
357                 srvstr_push(outbuf, p+2, global_myname, 15, STR_TERMINATE|STR_ASCII);
358                 srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII);
359                 break;
360         }
361
362         END_PROFILE(SMBioctl);
363         return outsize;
364 }
365
366 /****************************************************************************
367   reply to a chkpth
368 ****************************************************************************/
369 int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
370 {
371   int outsize = 0;
372   int mode;
373   pstring name;
374   BOOL ok = False;
375   BOOL bad_path = False;
376   SMB_STRUCT_STAT sbuf;
377   START_PROFILE(SMBchkpth);
378
379   srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
380
381   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
382
383   unix_convert(name,conn,0,&bad_path,&sbuf);
384
385   mode = SVAL(inbuf,smb_vwv0);
386
387   if (check_name(name,conn)) {
388     if (VALID_STAT(sbuf) || vfs_stat(conn,name,&sbuf) == 0)
389       ok = S_ISDIR(sbuf.st_mode);
390   }
391
392   if (!ok) {
393     /* We special case this - as when a Windows machine
394        is parsing a path is steps through the components
395        one at a time - if a component fails it expects
396        ERRbadpath, not ERRbadfile.
397      */
398     if(errno == ENOENT) {
399             return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
400     }
401
402     return(UNIXERROR(ERRDOS,ERRbadpath));
403   }
404
405   outsize = set_message(outbuf,0,0,True);
406
407   DEBUG(3,("chkpth %s mode=%d\n", name, mode));
408
409   END_PROFILE(SMBchkpth);
410   return(outsize);
411 }
412
413
414 /****************************************************************************
415   reply to a getatr
416 ****************************************************************************/
417 int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
418 {
419   pstring fname;
420   int outsize = 0;
421   SMB_STRUCT_STAT sbuf;
422   BOOL ok = False;
423   int mode=0;
424   SMB_OFF_T size=0;
425   time_t mtime=0;
426   BOOL bad_path = False;
427   char *p;
428   START_PROFILE(SMBgetatr);
429
430   p = smb_buf(inbuf) + 1;
431   p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
432
433   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
434   
435   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
436      under WfWg - weird! */
437   if (! (*fname))
438   {
439     mode = aHIDDEN | aDIR;
440     if (!CAN_WRITE(conn)) mode |= aRONLY;
441     size = 0;
442     mtime = 0;
443     ok = True;
444   }
445   else
446   {
447     unix_convert(fname,conn,0,&bad_path,&sbuf);
448     if (check_name(fname,conn))
449     {
450       if (VALID_STAT(sbuf) || vfs_stat(conn,fname,&sbuf) == 0)
451       {
452         mode = dos_mode(conn,fname,&sbuf);
453         size = sbuf.st_size;
454         mtime = sbuf.st_mtime;
455         if (mode & aDIR)
456           size = 0;
457         ok = True;
458       }
459       else
460         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
461     }
462   }
463   
464   if (!ok)
465   {
466     if((errno == ENOENT) && bad_path)
467     {
468       unix_ERR_class = ERRDOS;
469       unix_ERR_code = ERRbadpath;
470     }
471
472     END_PROFILE(SMBgetatr);
473     return(UNIXERROR(ERRDOS,ERRbadfile));
474   }
475  
476   outsize = set_message(outbuf,10,0,True);
477
478   SSVAL(outbuf,smb_vwv0,mode);
479   if(lp_dos_filetime_resolution(SNUM(conn)) )
480     put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
481   else
482     put_dos_date3(outbuf,smb_vwv1,mtime);
483   SIVAL(outbuf,smb_vwv3,(uint32)size);
484
485   if (Protocol >= PROTOCOL_NT1)
486           SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
487   
488   DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
489   
490   END_PROFILE(SMBgetatr);
491   return(outsize);
492 }
493
494
495 /****************************************************************************
496   reply to a setatr
497 ****************************************************************************/
498 int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
499 {
500   pstring fname;
501   int outsize = 0;
502   BOOL ok=False;
503   int mode;
504   time_t mtime;
505   SMB_STRUCT_STAT sbuf;
506   BOOL bad_path = False;
507   char *p;
508
509   START_PROFILE(SMBsetatr);
510
511   p = smb_buf(inbuf) + 1;
512   p += srvstr_pull(inbuf, fname, p, sizeof(fname), -1, STR_TERMINATE);
513   unix_convert(fname,conn,0,&bad_path,&sbuf);
514
515   mode = SVAL(inbuf,smb_vwv0);
516   mtime = make_unix_date3(inbuf+smb_vwv1);
517   
518   if (VALID_STAT_OF_DIR(sbuf))
519     mode |= aDIR;
520   else
521     mode &= ~aDIR;
522
523   if (check_name(fname,conn))
524     ok =  (file_chmod(conn,fname,mode,NULL) == 0);
525   if (ok)
526     ok = set_filetime(conn,fname,mtime);
527   
528   if (!ok)
529   {
530     if((errno == ENOENT) && bad_path)
531     {
532       unix_ERR_class = ERRDOS;
533       unix_ERR_code = ERRbadpath;
534     }
535
536     END_PROFILE(SMBsetatr);
537     return(UNIXERROR(ERRDOS,ERRnoaccess));
538   }
539  
540   outsize = set_message(outbuf,0,0,True);
541   
542   DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
543   
544   END_PROFILE(SMBsetatr);
545   return(outsize);
546 }
547
548
549 /****************************************************************************
550   reply to a dskattr
551 ****************************************************************************/
552 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
553 {
554   int outsize = 0;
555   SMB_BIG_UINT dfree,dsize,bsize;
556   START_PROFILE(SMBdskattr);
557   
558   conn->vfs_ops.disk_free(conn,".",True,&bsize,&dfree,&dsize);
559   
560   outsize = set_message(outbuf,5,0,True);
561   
562   SSVAL(outbuf,smb_vwv0,dsize);
563   SSVAL(outbuf,smb_vwv1,bsize/512);
564   SSVAL(outbuf,smb_vwv2,512);
565   SSVAL(outbuf,smb_vwv3,dfree);
566
567   DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
568
569   END_PROFILE(SMBdskattr);
570   return(outsize);
571 }
572
573
574 /****************************************************************************
575   reply to a search
576   Can be called from SMBsearch, SMBffirst or SMBfunique.
577 ****************************************************************************/
578 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
579 {
580   pstring mask;
581   pstring directory;
582   pstring fname;
583   SMB_OFF_T size;
584   int mode;
585   time_t date;
586   int dirtype;
587   int outsize = 0;
588   int numentries = 0;
589   BOOL finished = False;
590   int maxentries;
591   int i;
592   char *p;
593   BOOL ok = False;
594   int status_len;
595   pstring path;
596   char status[21];
597   int dptr_num= -1;
598   BOOL check_descend = False;
599   BOOL expect_close = False;
600   BOOL can_open = True;
601   BOOL bad_path = False;
602   START_PROFILE(SMBsearch);
603
604   *mask = *directory = *fname = 0;
605
606   /* If we were called as SMBffirst then we must expect close. */
607   if(CVAL(inbuf,smb_com) == SMBffirst)
608     expect_close = True;
609   
610   outsize = set_message(outbuf,1,3,True);
611   maxentries = SVAL(inbuf,smb_vwv0); 
612   dirtype = SVAL(inbuf,smb_vwv1);
613   p = smb_buf(inbuf) + 1;
614   p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
615   p++;
616   status_len = SVAL(p, 0);
617   p += 2;
618   
619   /* dirtype &= ~aDIR; */
620   
621   if (status_len == 0)
622   {
623     SMB_STRUCT_STAT sbuf;
624     pstring dir2;
625
626     pstrcpy(directory,path);
627     pstrcpy(dir2,path);
628     unix_convert(directory,conn,0,&bad_path,&sbuf);
629     unix_format(dir2);
630
631     if (!check_name(directory,conn))
632       can_open = False;
633
634     p = strrchr_m(dir2,'/');
635     if (p == NULL) 
636     {
637       pstrcpy(mask,dir2);
638       *dir2 = 0;
639     }
640     else
641     {
642       *p = 0;
643       pstrcpy(mask,p+1);
644     }
645
646     p = strrchr_m(directory,'/');
647     if (!p) 
648       *directory = 0;
649     else
650       *p = 0;
651
652     if (strlen(directory) == 0)
653       pstrcpy(directory,"./");
654     memset((char *)status,'\0',21);
655     SCVAL(status,0,dirtype);
656   }
657   else
658   {
659     memcpy(status,p,21);
660     dirtype = CVAL(status,0) & 0x1F;
661     conn->dirptr = dptr_fetch(status+12,&dptr_num);      
662     if (!conn->dirptr)
663       goto SearchEmpty;
664     string_set(&conn->dirpath,dptr_path(dptr_num));
665     fstrcpy(mask, dptr_wcard(dptr_num));
666   }
667
668   if (can_open)
669   {
670     p = smb_buf(outbuf) + 3;
671       
672     ok = True;
673      
674     if (status_len == 0)
675     {
676       dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
677       if (dptr_num < 0)
678       {
679         if(dptr_num == -2)
680         {
681           if((errno == ENOENT) && bad_path)
682           {
683             unix_ERR_class = ERRDOS;
684             unix_ERR_code = ERRbadpath;
685           }
686                  END_PROFILE(SMBsearch);
687           return (UNIXERROR(ERRDOS,ERRnofids));
688         }
689                 END_PROFILE(SMBsearch);
690         return ERROR_DOS(ERRDOS,ERRnofids);
691       }
692       dptr_set_wcard(dptr_num, strdup(mask));
693     }
694
695     DEBUG(4,("dptr_num is %d\n",dptr_num));
696
697     if (ok)
698     {
699       if ((dirtype&0x1F) == aVOLID)
700       {   
701         memcpy(p,status,21);
702         make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
703         dptr_fill(p+12,dptr_num);
704         if (dptr_zero(p+12) && (status_len==0))
705           numentries = 1;
706         else
707           numentries = 0;
708         p += DIR_STRUCT_SIZE;
709       }
710       else 
711       {
712         DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
713               conn->dirpath,lp_dontdescend(SNUM(conn))));
714         if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
715           check_descend = True;
716
717         for (i=numentries;(i<maxentries) && !finished;i++)
718         {
719           finished = 
720             !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
721           if (!finished)
722           {
723             memcpy(p,status,21);
724             make_dir_struct(p,mask,fname,size,mode,date);
725             dptr_fill(p+12,dptr_num);
726             numentries++;
727           }
728           p += DIR_STRUCT_SIZE;
729         }
730       }
731         } /* if (ok ) */
732   }
733
734
735   SearchEmpty:
736
737   if (numentries == 0 || !ok)
738   {
739     SCVAL(outbuf,smb_rcls,ERRDOS);
740     SSVAL(outbuf,smb_err,ERRnofiles);
741     dptr_close(&dptr_num);
742   }
743
744   /* If we were called as SMBffirst with smb_search_id == NULL
745      and no entries were found then return error and close dirptr 
746      (X/Open spec) */
747
748   if(ok && expect_close && numentries == 0 && status_len == 0)
749   {
750     SCVAL(outbuf,smb_rcls,ERRDOS);
751     SSVAL(outbuf,smb_err,ERRnofiles);
752     /* Also close the dptr - we know it's gone */
753     dptr_close(&dptr_num);
754   }
755
756   /* If we were called as SMBfunique, then we can close the dirptr now ! */
757   if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
758     dptr_close(&dptr_num);
759
760   SSVAL(outbuf,smb_vwv0,numentries);
761   SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
762   SCVAL(smb_buf(outbuf),0,5);
763   SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
764
765   if (Protocol >= PROTOCOL_NT1)
766     SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
767   
768   outsize += DIR_STRUCT_SIZE*numentries;
769   smb_setlen(outbuf,outsize - 4);
770   
771   if ((! *directory) && dptr_path(dptr_num))
772     slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
773
774   DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%d of %d\n",
775         smb_fn_name(CVAL(inbuf,smb_com)), 
776         mask, directory, dirtype, numentries, maxentries ) );
777
778   END_PROFILE(SMBsearch);
779   return(outsize);
780 }
781
782
783 /****************************************************************************
784   reply to a fclose (stop directory search)
785 ****************************************************************************/
786 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
787 {
788   int outsize = 0;
789   int status_len;
790   pstring path;
791   char status[21];
792   int dptr_num= -2;
793   char *p;
794
795   START_PROFILE(SMBfclose);
796
797   outsize = set_message(outbuf,1,0,True);
798   p = smb_buf(inbuf) + 1;
799   p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
800   p++;
801   status_len = SVAL(p,0);
802   p += 2;
803
804   if (status_len == 0) {
805     END_PROFILE(SMBfclose);
806     return ERROR_DOS(ERRSRV,ERRsrverror);
807   }
808
809   memcpy(status,p,21);
810
811   if(dptr_fetch(status+12,&dptr_num)) {
812     /*  Close the dptr - we know it's gone */
813     dptr_close(&dptr_num);
814   }
815
816   SSVAL(outbuf,smb_vwv0,0);
817
818   DEBUG(3,("search close\n"));
819
820   END_PROFILE(SMBfclose);
821   return(outsize);
822 }
823
824
825 /****************************************************************************
826   reply to an open
827 ****************************************************************************/
828
829 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
830 {
831   pstring fname;
832   int outsize = 0;
833   int fmode=0;
834   int share_mode;
835   SMB_OFF_T size = 0;
836   time_t mtime=0;
837   mode_t unixmode;
838   int rmode=0;
839   SMB_STRUCT_STAT sbuf;
840   BOOL bad_path = False;
841   files_struct *fsp;
842   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
843   START_PROFILE(SMBopen);
844  
845   share_mode = SVAL(inbuf,smb_vwv0);
846
847   srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
848
849   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
850
851   unix_convert(fname,conn,0,&bad_path,&sbuf);
852     
853   unixmode = unix_mode(conn,aARCH,fname);
854       
855   fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
856                    unixmode, oplock_request,&rmode,NULL);
857
858   if (!fsp)
859   {
860     if((errno == ENOENT) && bad_path)
861     {
862       unix_ERR_class = ERRDOS;
863       unix_ERR_code = ERRbadpath;
864     }
865     END_PROFILE(SMBopen);
866     return(UNIXERROR(ERRDOS,ERRnoaccess));
867   }
868
869   size = sbuf.st_size;
870   fmode = dos_mode(conn,fname,&sbuf);
871   mtime = sbuf.st_mtime;
872
873   if (fmode & aDIR) {
874     DEBUG(3,("attempt to open a directory %s\n",fname));
875     close_file(fsp,False);
876     END_PROFILE(SMBopen);
877     return ERROR_DOS(ERRDOS,ERRnoaccess);
878   }
879   
880   outsize = set_message(outbuf,7,0,True);
881   SSVAL(outbuf,smb_vwv0,fsp->fnum);
882   SSVAL(outbuf,smb_vwv1,fmode);
883   if(lp_dos_filetime_resolution(SNUM(conn)) )
884     put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
885   else
886     put_dos_date3(outbuf,smb_vwv2,mtime);
887   SIVAL(outbuf,smb_vwv4,(uint32)size);
888   SSVAL(outbuf,smb_vwv6,rmode);
889
890   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
891     SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
892   }
893     
894   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
895     SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
896   END_PROFILE(SMBopen);
897   return(outsize);
898 }
899
900
901 /****************************************************************************
902   reply to an open and X
903 ****************************************************************************/
904 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
905 {
906   pstring fname;
907   int smb_mode = SVAL(inbuf,smb_vwv3);
908   int smb_attr = SVAL(inbuf,smb_vwv5);
909   /* Breakout the oplock request bits so we can set the
910      reply bits separately. */
911   BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
912   BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
913   BOOL oplock_request = ex_oplock_request | core_oplock_request;
914 #if 0
915   int open_flags = SVAL(inbuf,smb_vwv2);
916   int smb_sattr = SVAL(inbuf,smb_vwv4); 
917   uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
918 #endif
919   int smb_ofun = SVAL(inbuf,smb_vwv8);
920   mode_t unixmode;
921   SMB_OFF_T size=0;
922   int fmode=0,mtime=0,rmode=0;
923   SMB_STRUCT_STAT sbuf;
924   int smb_action = 0;
925   BOOL bad_path = False;
926   files_struct *fsp;
927   START_PROFILE(SMBopenX);
928
929   /* If it's an IPC, pass off the pipe handler. */
930   if (IS_IPC(conn)) {
931     if (lp_nt_pipe_support()) {
932             END_PROFILE(SMBopenX);
933             return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
934     } else {
935                 END_PROFILE(SMBopenX);
936         return ERROR_DOS(ERRSRV,ERRaccess);
937     }
938   }
939
940   /* XXXX we need to handle passed times, sattr and flags */
941   srvstr_pull(inbuf, fname, smb_buf(inbuf), sizeof(fname), -1, STR_TERMINATE);
942
943   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
944
945   unix_convert(fname,conn,0,&bad_path,&sbuf);
946     
947   unixmode = unix_mode(conn,smb_attr | aARCH, fname);
948       
949   fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
950                        oplock_request, &rmode,&smb_action);
951       
952   if (!fsp)
953   {
954     if((errno == ENOENT) && bad_path)
955     {
956       unix_ERR_class = ERRDOS;
957       unix_ERR_code = ERRbadpath;
958     }
959     END_PROFILE(SMBopenX);
960     return(UNIXERROR(ERRDOS,ERRnoaccess));
961   }
962
963   size = sbuf.st_size;
964   fmode = dos_mode(conn,fname,&sbuf);
965   mtime = sbuf.st_mtime;
966   if (fmode & aDIR) {
967     close_file(fsp,False);
968     END_PROFILE(SMBopenX);
969     return ERROR_DOS(ERRDOS,ERRnoaccess);
970   }
971
972   /* If the caller set the extended oplock request bit
973      and we granted one (by whatever means) - set the
974      correct bit for extended oplock reply.
975    */
976
977   if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
978     smb_action |= EXTENDED_OPLOCK_GRANTED;
979   }
980
981   if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
982     smb_action |= EXTENDED_OPLOCK_GRANTED;
983   }
984
985   /* If the caller set the core oplock request bit
986      and we granted one (by whatever means) - set the
987      correct bit for core oplock reply.
988    */
989
990   if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
991     SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
992   }
993
994   if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
995     SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
996   }
997
998   set_message(outbuf,15,0,True);
999   SSVAL(outbuf,smb_vwv2,fsp->fnum);
1000   SSVAL(outbuf,smb_vwv3,fmode);
1001   if(lp_dos_filetime_resolution(SNUM(conn)) )
1002     put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
1003   else
1004     put_dos_date3(outbuf,smb_vwv4,mtime);
1005   SIVAL(outbuf,smb_vwv6,(uint32)size);
1006   SSVAL(outbuf,smb_vwv8,rmode);
1007   SSVAL(outbuf,smb_vwv11,smb_action);
1008
1009   END_PROFILE(SMBopenX);
1010   return chain_reply(inbuf,outbuf,length,bufsize);
1011 }
1012
1013
1014 /****************************************************************************
1015   reply to a SMBulogoffX
1016 ****************************************************************************/
1017 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1018 {
1019   uint16 vuid = SVAL(inbuf,smb_uid);
1020   user_struct *vuser = get_valid_user_struct(vuid);
1021   START_PROFILE(SMBulogoffX);
1022
1023   if(vuser == 0) {
1024     DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
1025   }
1026
1027   /* in user level security we are supposed to close any files
1028      open by this user */
1029   if ((vuser != 0) && (lp_security() != SEC_SHARE)) {
1030           file_close_user(vuid);
1031   }
1032
1033   invalidate_vuid(vuid);
1034
1035   set_message(outbuf,2,0,True);
1036
1037   DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
1038
1039   END_PROFILE(SMBulogoffX);
1040   return chain_reply(inbuf,outbuf,length,bufsize);
1041 }
1042
1043
1044 /****************************************************************************
1045   reply to a mknew or a create
1046 ****************************************************************************/
1047 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1048 {
1049   pstring fname;
1050   int com;
1051   int outsize = 0;
1052   int createmode;
1053   mode_t unixmode;
1054   int ofun = 0;
1055   BOOL bad_path = False;
1056   files_struct *fsp;
1057   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1058   SMB_STRUCT_STAT sbuf;
1059   START_PROFILE(SMBcreate);
1060  
1061   com = SVAL(inbuf,smb_com);
1062
1063   createmode = SVAL(inbuf,smb_vwv0);
1064   srvstr_pull(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), -1, STR_TERMINATE);
1065
1066   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1067
1068   unix_convert(fname,conn,0,&bad_path,&sbuf);
1069
1070   if (createmode & aVOLID) {
1071       DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1072   }
1073   
1074   unixmode = unix_mode(conn,createmode,fname);
1075   
1076   if(com == SMBmknew)
1077   {
1078     /* We should fail if file exists. */
1079     ofun = FILE_CREATE_IF_NOT_EXIST;
1080   }
1081   else
1082   {
1083     /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1084     ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
1085   }
1086
1087   /* Open file in dos compatibility share mode. */
1088   fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB), 
1089                    ofun, unixmode, oplock_request, NULL, NULL);
1090   
1091   if (!fsp)
1092   {
1093     if((errno == ENOENT) && bad_path) 
1094     {
1095       unix_ERR_class = ERRDOS;
1096       unix_ERR_code = ERRbadpath;
1097     }
1098     END_PROFILE(SMBcreate);
1099     return(UNIXERROR(ERRDOS,ERRnoaccess));
1100   }
1101  
1102   outsize = set_message(outbuf,1,0,True);
1103   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1104
1105   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1106     SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1107   }
1108  
1109   if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1110     SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1111  
1112   DEBUG( 2, ( "new file %s\n", fname ) );
1113   DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n",
1114         fname, fsp->fd, createmode, (int)unixmode ) );
1115
1116   END_PROFILE(SMBcreate);
1117   return(outsize);
1118 }
1119
1120
1121 /****************************************************************************
1122   reply to a create temporary file
1123 ****************************************************************************/
1124 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1125 {
1126   pstring fname;
1127   int outsize = 0;
1128   int createmode;
1129   mode_t unixmode;
1130   BOOL bad_path = False;
1131   files_struct *fsp;
1132   int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1133   int tmpfd;
1134   SMB_STRUCT_STAT sbuf;
1135   char *p, *s;
1136
1137   START_PROFILE(SMBctemp);
1138
1139   createmode = SVAL(inbuf,smb_vwv0);
1140   srvstr_pull(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), -1, STR_TERMINATE);
1141   pstrcat(fname,"\\TMXXXXXX");
1142
1143   RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1144
1145   unix_convert(fname,conn,0,&bad_path,&sbuf);
1146   
1147   unixmode = unix_mode(conn,createmode,fname);
1148   
1149   tmpfd = smb_mkstemp(fname);
1150   if (tmpfd == -1) {
1151       END_PROFILE(SMBctemp);
1152       return(UNIXERROR(ERRDOS,ERRnoaccess));
1153   }
1154
1155   vfs_stat(conn,fname,&sbuf);
1156
1157   /* Open file in dos compatibility share mode. */
1158   /* We should fail if file does not exist. */
1159   fsp = open_file_shared(conn,fname,&sbuf,
1160                          SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
1161                          FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
1162                          unixmode, oplock_request, NULL, NULL);
1163
1164   /* close fd from smb_mkstemp() */
1165   close(tmpfd);
1166
1167         if (!fsp) {
1168                 if((errno == ENOENT) && bad_path) {
1169       unix_ERR_class = ERRDOS;
1170       unix_ERR_code = ERRbadpath;
1171     }
1172     END_PROFILE(SMBctemp);
1173     return(UNIXERROR(ERRDOS,ERRnoaccess));
1174   }
1175
1176   outsize = set_message(outbuf,1,0,True);
1177   SSVAL(outbuf,smb_vwv0,fsp->fnum);
1178
1179   /* the returned filename is relative to the directory */
1180   s = strrchr_m(fname, '/');
1181   if (!s) {
1182           s = fname;
1183   } else {
1184           s++;
1185   }
1186
1187   p = smb_buf(outbuf);
1188   SSVALS(p, 0, -1); /* what is this? not in spec */
1189   SSVAL(p, 2, strlen(s));
1190   p += 4;
1191   p += srvstr_push(outbuf, p, s, -1, STR_ASCII);
1192   outsize = set_message_end(outbuf, p);
1193
1194   if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1195           SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1196   }
1197   
1198   if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1199           SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1200
1201   DEBUG( 2, ( "created temp file %s\n", fname ) );
1202   DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
1203         fname, fsp->fd, createmode, (int)unixmode ) );
1204
1205   END_PROFILE(SMBctemp);
1206   return(outsize);
1207 }
1208
1209 /*******************************************************************
1210  Check if a user is allowed to delete a file.
1211 ********************************************************************/
1212
1213 static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype)
1214 {
1215         SMB_STRUCT_STAT sbuf;
1216         int fmode;
1217
1218         if (!CAN_WRITE(conn))
1219                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1220
1221         if (conn->vfs_ops.lstat(conn,fname,&sbuf) != 0)
1222                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1223
1224         fmode = dos_mode(conn,fname,&sbuf);
1225         if (fmode & aDIR)
1226                 return NT_STATUS_FILE_IS_A_DIRECTORY;
1227         if (!lp_delete_readonly(SNUM(conn))) {
1228                 if (fmode & aRONLY)
1229                         return NT_STATUS_CANNOT_DELETE;
1230         }
1231         if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1232                 return NT_STATUS_CANNOT_DELETE;
1233
1234         if (!check_file_sharing(conn,fname,False))
1235                 return NT_STATUS_SHARING_VIOLATION;
1236
1237         return NT_STATUS_OK;
1238 }
1239
1240 /****************************************************************************
1241  The guts of the unlink command, split out so it may be called by the NT SMB
1242  code.
1243 ****************************************************************************/
1244
1245 NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
1246 {
1247         pstring directory;
1248         pstring mask;
1249         char *p;
1250         int count=0;
1251         NTSTATUS error = NT_STATUS_OK;
1252         BOOL has_wild;
1253         BOOL exists=False;
1254         BOOL bad_path = False;
1255         BOOL rc = True;
1256         SMB_STRUCT_STAT sbuf;
1257         
1258         *directory = *mask = 0;
1259         
1260         rc = unix_convert(name,conn,0,&bad_path,&sbuf);
1261         
1262         p = strrchr_m(name,'/');
1263         if (!p) {
1264                 pstrcpy(directory,".");
1265                 pstrcpy(mask,name);
1266         } else {
1267                 *p = 0;
1268                 pstrcpy(directory,name);
1269                 pstrcpy(mask,p+1);
1270         }
1271         
1272         /*
1273          * We should only check the mangled cache
1274          * here if unix_convert failed. This means
1275          * that the path in 'mask' doesn't exist
1276          * on the file system and so we need to look
1277          * for a possible mangle. This patch from
1278          * Tine Smukavec <valentin.smukavec@hermes.si>.
1279          */
1280         
1281         if (!rc && is_mangled(mask))
1282                 check_mangled_cache( mask );
1283         
1284         has_wild = ms_has_wild(mask);
1285         
1286         if (!has_wild) {
1287                 pstrcat(directory,"/");
1288                 pstrcat(directory,mask);
1289                 error = can_delete(directory,conn,dirtype);
1290                 if (!NT_STATUS_IS_OK(error)) return error;
1291
1292                 if (vfs_unlink(conn,directory) == 0) {
1293                         count++;
1294                 }
1295                 if (!count)
1296                         exists = vfs_file_exist(conn,directory,&sbuf);    
1297         } else {
1298                 void *dirptr = NULL;
1299                 char *dname;
1300                 
1301                 if (check_name(directory,conn))
1302                         dirptr = OpenDir(conn, directory, True);
1303                 
1304                 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
1305                    the pattern matches against the long name, otherwise the short name 
1306                    We don't implement this yet XXXX
1307                 */
1308                 
1309                 if (dirptr) {
1310                         error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
1311                         
1312                         if (strequal(mask,"????????.???"))
1313                                 pstrcpy(mask,"*");
1314
1315                         while ((dname = ReadDirName(dirptr))) {
1316                                 pstring fname;
1317                                 pstrcpy(fname,dname);
1318                                 
1319                                 if(!mask_match(fname, mask, case_sensitive)) continue;
1320                                 
1321                                 slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
1322                                 error = can_delete(fname,conn,dirtype);
1323                                 if (!NT_STATUS_IS_OK(error)) continue;
1324                                 if (vfs_unlink(conn,fname) == 0) count++;
1325                                 DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
1326                         }
1327                         CloseDir(dirptr);
1328                 }
1329         }
1330         
1331         if (count == 0 && NT_STATUS_IS_OK(error)) {
1332                 error = map_nt_error_from_unix(errno);
1333         }
1334
1335         return error;
1336 }
1337
1338 /****************************************************************************
1339  Reply to a unlink
1340 ****************************************************************************/
1341
1342 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
1343                  int dum_buffsize)
1344 {
1345         int outsize = 0;
1346         pstring name;
1347         int dirtype;
1348         NTSTATUS status;
1349         START_PROFILE(SMBunlink);
1350         
1351         dirtype = SVAL(inbuf,smb_vwv0);
1352         
1353         srvstr_pull(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), -1, STR_TERMINATE);
1354         
1355         RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1356         
1357         DEBUG(3,("reply_unlink : %s\n",name));
1358         
1359         status = unlink_internals(conn, dirtype, name);
1360         if (!NT_STATUS_IS_OK(status)) return ERROR_NT(status);
1361
1362         /*
1363          * Win2k needs a changenotify request response before it will
1364          * update after a rename..
1365          */
1366         process_pending_change_notify_queue((time_t)0);
1367         
1368         outsize = set_message(outbuf,0,0,True);
1369   
1370         END_PROFILE(SMBunlink);
1371         return outsize;
1372 }
1373
1374 /****************************************************************************
1375  Fail for readbraw.
1376 ****************************************************************************/
1377
1378 void fail_readraw(void)
1379 {
1380         pstring errstr;
1381         slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
1382                 strerror(errno) );
1383         exit_server(errstr);
1384 }
1385
1386 /****************************************************************************
1387  Reply to a readbraw (core+ protocol).
1388 ****************************************************************************/
1389
1390 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
1391 {
1392         ssize_t maxcount,mincount;
1393         size_t nread = 0;
1394         SMB_OFF_T startpos;
1395         char *header = outbuf;
1396         ssize_t ret=0;
1397         files_struct *fsp;
1398         START_PROFILE(SMBreadbraw);
1399
1400         /*
1401          * Special check if an oplock break has been issued
1402          * and the readraw request croses on the wire, we must
1403          * return a zero length response here.
1404          */
1405
1406         if(global_oplock_break) {
1407                 _smb_setlen(header,0);
1408                 if (write_data(smbd_server_fd(),header,4) != 4)
1409                         fail_readraw();
1410                 DEBUG(5,("readbraw - oplock break finished\n"));
1411                 END_PROFILE(SMBreadbraw);
1412                 return -1;
1413         }
1414
1415         fsp = file_fsp(inbuf,smb_vwv0);
1416
1417         if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
1418                 /*
1419                  * fsp could be NULL here so use the value from the packet. JRA.
1420                  */
1421                 DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
1422                 _smb_setlen(header,0);
1423                 if (write_data(smbd_server_fd(),header,4) != 4)
1424                         fail_readraw();
1425                 END_PROFILE(SMBreadbraw);
1426                 return(-1);
1427         }
1428
1429         CHECK_FSP(fsp,conn);
1430
1431         flush_write_cache(fsp, READRAW_FLUSH);
1432
1433         startpos = IVAL(inbuf,smb_vwv1);
1434         if(CVAL(inbuf,smb_wct) == 10) {
1435                 /*
1436                  * This is a large offset (64 bit) read.
1437                  */
1438 #ifdef LARGE_SMB_OFF_T
1439
1440                 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
1441
1442 #else /* !LARGE_SMB_OFF_T */
1443
1444                 /*
1445                  * Ensure we haven't been sent a >32 bit offset.
1446                  */
1447
1448                 if(IVAL(inbuf,smb_vwv8) != 0) {
1449                         DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
1450 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
1451                         _smb_setlen(header,0);
1452                         if (write_data(smbd_server_fd(),header,4) != 4)
1453                                 fail_readraw();
1454                         END_PROFILE(SMBreadbraw);
1455                         return(-1);
1456                 }
1457
1458 #endif /* LARGE_SMB_OFF_T */
1459
1460                 if(startpos < 0) {
1461                         DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
1462                         _smb_setlen(header,0);
1463                         if (write_data(smbd_server_fd(),header,4) != 4)
1464                                 fail_readraw();
1465                         END_PROFILE(SMBreadbraw);
1466                         return(-1);
1467                 }      
1468         }
1469         maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
1470         mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
1471
1472         /* ensure we don't overrun the packet size */
1473         maxcount = MIN(65535,maxcount);
1474         maxcount = MAX(mincount,maxcount);
1475
1476         if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
1477                 SMB_OFF_T size = fsp->size;
1478                 SMB_OFF_T sizeneeded = startpos + maxcount;
1479   
1480                 if (size < sizeneeded) {
1481                         SMB_STRUCT_STAT st;
1482                         if (vfs_fstat(fsp,fsp->fd,&st) == 0)
1483                                 size = st.st_size;
1484                         if (!fsp->can_write) 
1485                                 fsp->size = size;
1486                 }
1487
1488                 if (startpos >= size)
1489                         nread = 0;
1490                 else
1491                         nread = MIN(maxcount,(size - startpos));          
1492         }
1493
1494         if (nread < mincount)
1495                 nread = 0;
1496   
1497         DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
1498                                 (int)maxcount, (int)mincount, (int)nread ) );
1499   
1500         if (nread > 0) {
1501                 ret = read_file(fsp,header+4,startpos,nread);
1502                 if (ret < mincount)
1503                         ret = 0;
1504         }
1505
1506         _smb_setlen(header,ret);
1507         if (write_data(smbd_server_fd(),header,4+ret) != 4+ret)
1508                 fail_readraw();
1509
1510         DEBUG(5,("readbraw finished\n"));
1511         END_PROFILE(SMBreadbraw);
1512         return -1;
1513 }
1514
1515 /****************************************************************************
1516   reply to a lockread (core+ protocol)
1517 ****************************************************************************/
1518 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
1519 {
1520         ssize_t nread = -1;
1521         char *data;
1522         int outsize = 0;
1523         SMB_OFF_T startpos;
1524         size_t numtoread;
1525         NTSTATUS status;
1526         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1527         START_PROFILE(SMBlockread);
1528
1529         CHECK_FSP(fsp,conn);
1530         CHECK_READ(fsp);
1531
1532         release_level_2_oplocks_on_change(fsp);
1533
1534         numtoread = SVAL(inbuf,smb_vwv1);
1535         startpos = IVAL(inbuf,smb_vwv2);
1536   
1537         outsize = set_message(outbuf,5,3,True);
1538         numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1539         data = smb_buf(outbuf) + 3;
1540         
1541         /*
1542          * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
1543          * protocol request that predates the read/write lock concept. 
1544          * Thus instead of asking for a read lock here we need to ask
1545          * for a write lock. JRA.
1546          */
1547         
1548         status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), 
1549                          (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK);
1550
1551         if (NT_STATUS_V(status)) {
1552                 if (lp_blocking_locks(SNUM(conn))) {
1553                         /*
1554                          * A blocking lock was requested. Package up
1555                          * this smb into a queued request and push it
1556                          * onto the blocking lock queue.
1557                          */
1558                         if(push_blocking_lock_request(inbuf, length, -1, 0))
1559                                 END_PROFILE(SMBlockread);
1560                         return -1;
1561                 }
1562                 END_PROFILE(SMBlockread);
1563                 return ERROR_NT(status);
1564         }
1565
1566         nread = read_file(fsp,data,startpos,numtoread);
1567
1568         if (nread < 0) {
1569                 END_PROFILE(SMBlockread);
1570                 return(UNIXERROR(ERRDOS,ERRnoaccess));
1571         }
1572         
1573         outsize += nread;
1574         SSVAL(outbuf,smb_vwv0,nread);
1575         SSVAL(outbuf,smb_vwv5,nread+3);
1576         SSVAL(smb_buf(outbuf),1,nread);
1577         
1578         DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
1579                  fsp->fnum, (int)numtoread, (int)nread));
1580
1581         END_PROFILE(SMBlockread);
1582         return(outsize);
1583 }
1584
1585
1586 /****************************************************************************
1587   reply to a read
1588 ****************************************************************************/
1589
1590 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
1591 {
1592   size_t numtoread;
1593   ssize_t nread = 0;
1594   char *data;
1595   SMB_OFF_T startpos;
1596   int outsize = 0;
1597   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1598   START_PROFILE(SMBread);
1599
1600   CHECK_FSP(fsp,conn);
1601   CHECK_READ(fsp);
1602
1603   numtoread = SVAL(inbuf,smb_vwv1);
1604   startpos = IVAL(inbuf,smb_vwv2);
1605
1606
1607   outsize = set_message(outbuf,5,3,True);
1608   numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1609   data = smb_buf(outbuf) + 3;
1610   
1611   if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
1612     END_PROFILE(SMBread);
1613     return ERROR_DOS(ERRDOS,ERRlock);
1614   }
1615
1616   if (numtoread > 0)
1617     nread = read_file(fsp,data,startpos,numtoread);
1618
1619   if (nread < 0) {
1620     END_PROFILE(SMBread);
1621     return(UNIXERROR(ERRDOS,ERRnoaccess));
1622   }
1623   
1624   outsize += nread;
1625   SSVAL(outbuf,smb_vwv0,nread);
1626   SSVAL(outbuf,smb_vwv5,nread+3);
1627   SCVAL(smb_buf(outbuf),0,1);
1628   SSVAL(smb_buf(outbuf),1,nread);
1629   
1630   DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
1631             fsp->fnum, (int)numtoread, (int)nread ) );
1632
1633   END_PROFILE(SMBread);
1634   return(outsize);
1635 }
1636
1637
1638 /****************************************************************************
1639   reply to a read and X
1640 ****************************************************************************/
1641 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1642 {
1643   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
1644   SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
1645   size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
1646   size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
1647   ssize_t nread = -1;
1648   char *data;
1649   START_PROFILE(SMBreadX);
1650
1651   /* If it's an IPC, pass off the pipe handler. */
1652   if (IS_IPC(conn)) {
1653     END_PROFILE(SMBreadX);
1654     return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
1655   }
1656
1657   CHECK_FSP(fsp,conn);
1658   CHECK_READ(fsp);
1659
1660   set_message(outbuf,12,0,True);
1661   data = smb_buf(outbuf);
1662
1663   if(CVAL(inbuf,smb_wct) == 12) {
1664 #ifdef LARGE_SMB_OFF_T
1665     /*
1666      * This is a large offset (64 bit) read.
1667      */
1668     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
1669
1670 #else /* !LARGE_SMB_OFF_T */
1671
1672     /*
1673      * Ensure we haven't been sent a >32 bit offset.
1674      */
1675
1676     if(IVAL(inbuf,smb_vwv10) != 0) {
1677       DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
1678 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
1679       END_PROFILE(SMBreadX);
1680       return ERROR_DOS(ERRDOS,ERRbadaccess);
1681     }
1682
1683 #endif /* LARGE_SMB_OFF_T */
1684
1685   }
1686
1687   if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
1688     END_PROFILE(SMBreadX);
1689     return ERROR_DOS(ERRDOS,ERRlock);
1690   }
1691   nread = read_file(fsp,data,startpos,smb_maxcnt);
1692
1693   if (nread < 0) {
1694     END_PROFILE(SMBreadX);
1695     return(UNIXERROR(ERRDOS,ERRnoaccess));
1696   }
1697   
1698   SSVAL(outbuf,smb_vwv5,nread);
1699   SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
1700   SSVAL(smb_buf(outbuf),-2,nread);
1701   
1702   DEBUG( 3, ( "readX fnum=%d min=%d max=%d nread=%d\n",
1703               fsp->fnum, (int)smb_mincnt, (int)smb_maxcnt, (int)nread ) );
1704
1705   END_PROFILE(SMBreadX);
1706   return chain_reply(inbuf,outbuf,length,bufsize);
1707 }
1708
1709 /****************************************************************************
1710   reply to a writebraw (core+ or LANMAN1.0 protocol)
1711 ****************************************************************************/
1712
1713 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
1714 {
1715         ssize_t nwritten=0;
1716         ssize_t total_written=0;
1717         size_t numtowrite=0;
1718         size_t tcount;
1719         SMB_OFF_T startpos;
1720         char *data=NULL;
1721         BOOL write_through;
1722         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1723         int outsize = 0;
1724         START_PROFILE(SMBwritebraw);
1725
1726         CHECK_FSP(fsp,conn);
1727         CHECK_WRITE(fsp);
1728   
1729         tcount = IVAL(inbuf,smb_vwv1);
1730         startpos = IVAL(inbuf,smb_vwv3);
1731         write_through = BITSETW(inbuf+smb_vwv7,0);
1732
1733         /* We have to deal with slightly different formats depending
1734                 on whether we are using the core+ or lanman1.0 protocol */
1735
1736         if(Protocol <= PROTOCOL_COREPLUS) {
1737                 numtowrite = SVAL(smb_buf(inbuf),-2);
1738                 data = smb_buf(inbuf);
1739         } else {
1740                 numtowrite = SVAL(inbuf,smb_vwv10);
1741                 data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
1742         }
1743
1744         /* force the error type */
1745         SCVAL(inbuf,smb_com,SMBwritec);
1746         SCVAL(outbuf,smb_com,SMBwritec);
1747
1748         if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
1749                 END_PROFILE(SMBwritebraw);
1750                 return(ERROR_DOS(ERRDOS,ERRlock));
1751         }
1752
1753         if (numtowrite>0)
1754                 nwritten = write_file(fsp,data,startpos,numtowrite);
1755   
1756         DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
1757                 fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
1758
1759         if (nwritten < numtowrite)  {
1760                 END_PROFILE(SMBwritebraw);
1761                 return(UNIXERROR(ERRHRD,ERRdiskfull));
1762         }
1763
1764         total_written = nwritten;
1765
1766         /* Return a message to the redirector to tell it to send more bytes */
1767         SCVAL(outbuf,smb_com,SMBwritebraw);
1768         SSVALS(outbuf,smb_vwv0,-1);
1769         outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
1770         if (!send_smb(smbd_server_fd(),outbuf))
1771                 exit_server("reply_writebraw: send_smb failed.");
1772   
1773         /* Now read the raw data into the buffer and write it */
1774         if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
1775                 exit_server("secondary writebraw failed");
1776         }
1777   
1778         /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
1779         numtowrite = smb_len(inbuf);
1780
1781         /* Set up outbuf to return the correct return */
1782         outsize = set_message(outbuf,1,0,True);
1783         SCVAL(outbuf,smb_com,SMBwritec);
1784         SSVAL(outbuf,smb_vwv0,total_written);
1785
1786         if (numtowrite != 0) {
1787
1788                 if (numtowrite > BUFFER_SIZE) {
1789                         DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
1790                                 (unsigned int)numtowrite ));
1791                         exit_server("secondary writebraw failed");
1792                 }
1793
1794                 if (tcount > nwritten+numtowrite) {
1795                         DEBUG(3,("Client overestimated the write %d %d %d\n",
1796                                 (int)tcount,(int)nwritten,(int)numtowrite));
1797                 }
1798
1799                 if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
1800                         DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
1801                                 strerror(errno) ));
1802                         exit_server("secondary writebraw failed");
1803                 }
1804
1805                 nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
1806
1807                 if (nwritten < (ssize_t)numtowrite) {
1808                         SCVAL(outbuf,smb_rcls,ERRHRD);
1809                         SSVAL(outbuf,smb_err,ERRdiskfull);      
1810                 }
1811
1812                 if (nwritten > 0)
1813                         total_written += nwritten;
1814         }
1815  
1816         if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn)))
1817                 sync_file(conn,fsp);
1818
1819         DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
1820                 fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
1821
1822         /* we won't return a status if write through is not selected - this follows what WfWg does */
1823         END_PROFILE(SMBwritebraw);
1824         if (!write_through && total_written==tcount) {
1825                 /*
1826                  * Fix for "rabbit pellet" mode, trigger an early TCP ack by
1827                  * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
1828                  */
1829                 if (!send_keepalive(smbd_server_fd()))
1830                         exit_server("reply_writebraw: send of keepalive failed");
1831                 return(-1);
1832         }
1833
1834         return(outsize);
1835 }
1836
1837 /****************************************************************************
1838   reply to a writeunlock (core+)
1839 ****************************************************************************/
1840
1841 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, 
1842                       int size, int dum_buffsize)
1843 {
1844         ssize_t nwritten = -1;
1845         size_t numtowrite;
1846         SMB_OFF_T startpos;
1847         char *data;
1848         NTSTATUS status;
1849         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1850         int outsize = 0;
1851         START_PROFILE(SMBwriteunlock);
1852         
1853         CHECK_FSP(fsp,conn);
1854         CHECK_WRITE(fsp);
1855
1856         numtowrite = SVAL(inbuf,smb_vwv1);
1857         startpos = IVAL(inbuf,smb_vwv2);
1858         data = smb_buf(inbuf) + 3;
1859   
1860         if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, 
1861                       WRITE_LOCK,False)) {
1862                 END_PROFILE(SMBwriteunlock);
1863                 return ERROR_DOS(ERRDOS,ERRlock);
1864         }
1865
1866         /* The special X/Open SMB protocol handling of
1867            zero length writes is *NOT* done for
1868            this call */
1869         if(numtowrite == 0)
1870                 nwritten = 0;
1871         else
1872                 nwritten = write_file(fsp,data,startpos,numtowrite);
1873   
1874         if (lp_syncalways(SNUM(conn)))
1875                 sync_file(conn,fsp);
1876
1877         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
1878                 END_PROFILE(SMBwriteunlock);
1879                 return(UNIXERROR(ERRDOS,ERRnoaccess));
1880         }
1881
1882         status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite, 
1883                            (SMB_BIG_UINT)startpos);
1884         if (NT_STATUS_V(status)) {
1885                 END_PROFILE(SMBwriteunlock);
1886                 return ERROR_NT(status);
1887         }
1888         
1889         outsize = set_message(outbuf,1,0,True);
1890         
1891         SSVAL(outbuf,smb_vwv0,nwritten);
1892         
1893         DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
1894                  fsp->fnum, (int)numtowrite, (int)nwritten));
1895         
1896         END_PROFILE(SMBwriteunlock);
1897         return outsize;
1898 }
1899
1900
1901 /****************************************************************************
1902  Reply to a write.
1903 ****************************************************************************/
1904
1905 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
1906 {
1907         size_t numtowrite;
1908         ssize_t nwritten = -1;
1909         SMB_OFF_T startpos;
1910         char *data;
1911         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1912         int outsize = 0;
1913         START_PROFILE(SMBwrite);
1914
1915         /* If it's an IPC, pass off the pipe handler. */
1916         if (IS_IPC(conn)) {
1917                 END_PROFILE(SMBwrite);
1918                 return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
1919         }
1920
1921         CHECK_FSP(fsp,conn);
1922         CHECK_WRITE(fsp);
1923
1924         numtowrite = SVAL(inbuf,smb_vwv1);
1925         startpos = IVAL(inbuf,smb_vwv2);
1926         data = smb_buf(inbuf) + 3;
1927   
1928         if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
1929                 END_PROFILE(SMBwrite);
1930                 return ERROR_DOS(ERRDOS,ERRlock);
1931         }
1932
1933         /*
1934          * X/Open SMB protocol says that if smb_vwv1 is
1935          * zero then the file size should be extended or
1936          * truncated to the size given in smb_vwv[2-3].
1937          */
1938
1939         if(numtowrite == 0) {
1940                 /*
1941                  * This is actually an allocate call, and set EOF. JRA.
1942                  */
1943                 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
1944                 if (nwritten < 0) {
1945                         END_PROFILE(SMBwrite);
1946                         return ERROR_NT(NT_STATUS_DISK_FULL);
1947                 }
1948                 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
1949                 if (nwritten < 0) {
1950                         END_PROFILE(SMBwrite);
1951                         return ERROR_NT(NT_STATUS_DISK_FULL);
1952                 }
1953         } else
1954                 nwritten = write_file(fsp,data,startpos,numtowrite);
1955   
1956         if (lp_syncalways(SNUM(conn)))
1957                 sync_file(conn,fsp);
1958
1959         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
1960                 END_PROFILE(SMBwrite);
1961                 return(UNIXERROR(ERRDOS,ERRnoaccess));
1962         }
1963
1964         outsize = set_message(outbuf,1,0,True);
1965   
1966         SSVAL(outbuf,smb_vwv0,nwritten);
1967
1968         if (nwritten < (ssize_t)numtowrite) {
1969                 SCVAL(outbuf,smb_rcls,ERRHRD);
1970                 SSVAL(outbuf,smb_err,ERRdiskfull);      
1971         }
1972   
1973         DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
1974
1975         END_PROFILE(SMBwrite);
1976         return(outsize);
1977 }
1978
1979
1980 /****************************************************************************
1981   reply to a write and X
1982 ****************************************************************************/
1983 int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1984 {
1985   files_struct *fsp = file_fsp(inbuf,smb_vwv2);
1986   SMB_OFF_T startpos = IVAL(inbuf,smb_vwv3);
1987   size_t numtowrite = SVAL(inbuf,smb_vwv10);
1988   BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
1989   ssize_t nwritten = -1;
1990   unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
1991   unsigned int smblen = smb_len(inbuf);
1992   char *data;
1993   BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
1994   START_PROFILE(SMBwriteX);
1995
1996   /* If it's an IPC, pass off the pipe handler. */
1997   if (IS_IPC(conn)) {
1998     END_PROFILE(SMBwriteX);
1999     return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
2000   }
2001
2002   CHECK_FSP(fsp,conn);
2003   CHECK_WRITE(fsp);
2004
2005   /* Deal with possible LARGE_WRITEX */
2006   if (large_writeX)
2007     numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
2008
2009   if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
2010     END_PROFILE(SMBwriteX);
2011     return ERROR_DOS(ERRDOS,ERRbadmem);
2012   }
2013
2014   data = smb_base(inbuf) + smb_doff;
2015
2016   if(CVAL(inbuf,smb_wct) == 14) {
2017 #ifdef LARGE_SMB_OFF_T
2018     /*
2019      * This is a large offset (64 bit) write.
2020      */
2021     startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
2022
2023 #else /* !LARGE_SMB_OFF_T */
2024
2025     /*
2026      * Ensure we haven't been sent a >32 bit offset.
2027      */
2028
2029     if(IVAL(inbuf,smb_vwv12) != 0) {
2030       DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
2031 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
2032       END_PROFILE(SMBwriteX);
2033       return ERROR_DOS(ERRDOS,ERRbadaccess);
2034     }
2035
2036 #endif /* LARGE_SMB_OFF_T */
2037   }
2038
2039   if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2040     END_PROFILE(SMBwriteX);
2041     return ERROR_DOS(ERRDOS,ERRlock);
2042   }
2043
2044   /* X/Open SMB protocol says that, unlike SMBwrite
2045      if the length is zero then NO truncation is
2046      done, just a write of zero. To truncate a file,
2047      use SMBwrite. */
2048   if(numtowrite == 0)
2049     nwritten = 0;
2050   else
2051     nwritten = write_file(fsp,data,startpos,numtowrite);
2052   
2053   if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2054     END_PROFILE(SMBwriteX);
2055     return(UNIXERROR(ERRDOS,ERRnoaccess));
2056   }
2057
2058   set_message(outbuf,6,0,True);
2059   
2060   SSVAL(outbuf,smb_vwv2,nwritten);
2061   if (large_writeX)
2062     SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
2063
2064   if (nwritten < (ssize_t)numtowrite) {
2065     SCVAL(outbuf,smb_rcls,ERRHRD);
2066     SSVAL(outbuf,smb_err,ERRdiskfull);      
2067   }
2068
2069   DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
2070            fsp->fnum, (int)numtowrite, (int)nwritten));
2071
2072   if (lp_syncalways(SNUM(conn)) || write_through)
2073     sync_file(conn,fsp);
2074
2075   END_PROFILE(SMBwriteX);
2076   return chain_reply(inbuf,outbuf,length,bufsize);
2077 }
2078
2079
2080 /****************************************************************************
2081   reply to a lseek
2082 ****************************************************************************/
2083
2084 int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2085 {
2086   SMB_OFF_T startpos;
2087   SMB_OFF_T res= -1;
2088   int mode,umode;
2089   int outsize = 0;
2090   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2091   START_PROFILE(SMBlseek);
2092
2093   CHECK_FSP(fsp,conn);
2094
2095   flush_write_cache(fsp, SEEK_FLUSH);
2096
2097   mode = SVAL(inbuf,smb_vwv1) & 3;
2098   startpos = IVALS(inbuf,smb_vwv2);
2099
2100   switch (mode) {
2101     case 0: umode = SEEK_SET; break;
2102     case 1: umode = SEEK_CUR; break;
2103     case 2: umode = SEEK_END; break;
2104     default:
2105       umode = SEEK_SET; break;
2106   }
2107
2108   if((res = conn->vfs_ops.lseek(fsp,fsp->fd,startpos,umode)) == -1) {
2109     /*
2110      * Check for the special case where a seek before the start
2111      * of the file sets the offset to zero. Added in the CIFS spec,
2112      * section 4.2.7.
2113      */
2114
2115     if(errno == EINVAL) {
2116       SMB_OFF_T current_pos = startpos;
2117
2118       if(umode == SEEK_CUR) {
2119
2120         if((current_pos = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_CUR)) == -1) {
2121                         END_PROFILE(SMBlseek);
2122           return(UNIXERROR(ERRDOS,ERRnoaccess));
2123         }
2124
2125         current_pos += startpos;
2126
2127       } else if (umode == SEEK_END) {
2128
2129         SMB_STRUCT_STAT sbuf;
2130
2131         if(vfs_fstat(fsp,fsp->fd, &sbuf) == -1) {
2132                   END_PROFILE(SMBlseek);
2133           return(UNIXERROR(ERRDOS,ERRnoaccess));
2134         }
2135
2136         current_pos += sbuf.st_size;
2137       }
2138  
2139       if(current_pos < 0)
2140         res = conn->vfs_ops.lseek(fsp,fsp->fd,0,SEEK_SET);
2141     }
2142
2143     if(res == -1) {
2144       END_PROFILE(SMBlseek);
2145       return(UNIXERROR(ERRDOS,ERRnoaccess));
2146     }
2147   }
2148
2149   fsp->pos = res;
2150   
2151   outsize = set_message(outbuf,2,0,True);
2152   SIVAL(outbuf,smb_vwv0,res);
2153   
2154   DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
2155            fsp->fnum, (double)startpos, (double)res, mode));
2156
2157   END_PROFILE(SMBlseek);
2158   return(outsize);
2159 }
2160
2161 /****************************************************************************
2162   reply to a flush
2163 ****************************************************************************/
2164
2165 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2166 {
2167         int outsize = set_message(outbuf,0,0,True);
2168         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2169         START_PROFILE(SMBflush);
2170
2171         CHECK_FSP(fsp,conn);
2172         
2173         if (!fsp) {
2174                 file_sync_all(conn);
2175         } else {
2176                 sync_file(conn,fsp);
2177         }
2178         
2179         DEBUG(3,("flush\n"));
2180         END_PROFILE(SMBflush);
2181         return(outsize);
2182 }
2183
2184
2185 /****************************************************************************
2186   reply to a exit
2187 ****************************************************************************/
2188 int reply_exit(connection_struct *conn, 
2189                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2190 {
2191         int outsize;
2192         START_PROFILE(SMBexit);
2193         outsize = set_message(outbuf,0,0,True);
2194
2195         DEBUG(3,("exit\n"));
2196
2197         END_PROFILE(SMBexit);
2198         return(outsize);
2199 }
2200
2201
2202 /****************************************************************************
2203  Reply to a close - has to deal with closing a directory opened by NT SMB's.
2204 ****************************************************************************/
2205 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
2206                 int dum_buffsize)
2207 {
2208         int outsize = 0;
2209         time_t mtime;
2210         int32 eclass = 0, err = 0;
2211         files_struct *fsp = NULL;
2212         START_PROFILE(SMBclose);
2213
2214         outsize = set_message(outbuf,0,0,True);
2215
2216         /* If it's an IPC, pass off to the pipe handler. */
2217         if (IS_IPC(conn)) {
2218                 END_PROFILE(SMBclose);
2219                 return reply_pipe_close(conn, inbuf,outbuf);
2220         }
2221
2222         fsp = file_fsp(inbuf,smb_vwv0);
2223
2224         /*
2225          * We can only use CHECK_FSP if we know it's not a directory.
2226          */
2227
2228         if(!fsp || (fsp->conn != conn)) {
2229                 END_PROFILE(SMBclose);
2230                 return ERROR_DOS(ERRDOS,ERRbadfid);
2231         }
2232
2233         if(fsp->is_directory || fsp->stat_open) {
2234                 /*
2235                  * Special case - close NT SMB directory or stat file
2236                  * handle.
2237                  */
2238                 DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
2239                 close_file(fsp,True);
2240         } else {
2241                 /*
2242                  * Close ordinary file.
2243                  */
2244                 int close_err;
2245                 pstring file_name;
2246
2247                 /* Save the name for time set in close. */
2248                 pstrcpy( file_name, fsp->fsp_name);
2249
2250                 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
2251                          fsp->fd, fsp->fnum,
2252                          conn->num_files_open));
2253  
2254                 /*
2255                  * close_file() returns the unix errno if an error
2256                  * was detected on close - normally this is due to
2257                  * a disk full error. If not then it was probably an I/O error.
2258                  */
2259  
2260                 if((close_err = close_file(fsp,True)) != 0) {
2261                         errno = close_err;
2262                         END_PROFILE(SMBclose);
2263                         return (UNIXERROR(ERRHRD,ERRgeneral));
2264                 }
2265
2266                 /*
2267                  * Now take care of any time sent in the close.
2268                  */
2269
2270                 mtime = make_unix_date3(inbuf+smb_vwv1);
2271                 
2272                 /* try and set the date */
2273                 set_filetime(conn, file_name, mtime);
2274
2275         }  
2276
2277         /* We have a cached error */
2278         if(eclass || err) {
2279                 END_PROFILE(SMBclose);
2280                 return ERROR_DOS(eclass,err);
2281         }
2282
2283         END_PROFILE(SMBclose);
2284         return(outsize);
2285 }
2286
2287
2288 /****************************************************************************
2289   reply to a writeclose (Core+ protocol)
2290 ****************************************************************************/
2291
2292 int reply_writeclose(connection_struct *conn,
2293                      char *inbuf,char *outbuf, int size, int dum_buffsize)
2294 {
2295         size_t numtowrite;
2296         ssize_t nwritten = -1;
2297         int outsize = 0;
2298         int close_err = 0;
2299         SMB_OFF_T startpos;
2300         char *data;
2301         time_t mtime;
2302         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2303         START_PROFILE(SMBwriteclose);
2304
2305         CHECK_FSP(fsp,conn);
2306         CHECK_WRITE(fsp);
2307
2308         numtowrite = SVAL(inbuf,smb_vwv1);
2309         startpos = IVAL(inbuf,smb_vwv2);
2310         mtime = make_unix_date3(inbuf+smb_vwv4);
2311         data = smb_buf(inbuf) + 1;
2312   
2313         if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2314                 END_PROFILE(SMBwriteclose);
2315                 return ERROR_DOS(ERRDOS,ERRlock);
2316         }
2317   
2318         nwritten = write_file(fsp,data,startpos,numtowrite);
2319
2320         set_filetime(conn, fsp->fsp_name,mtime);
2321   
2322         close_err = close_file(fsp,True);
2323
2324         DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
2325                  fsp->fnum, (int)numtowrite, (int)nwritten,
2326                  conn->num_files_open));
2327   
2328         if (nwritten <= 0) {
2329                 END_PROFILE(SMBwriteclose);
2330                 return(UNIXERROR(ERRDOS,ERRnoaccess));
2331         }
2332  
2333         if(close_err != 0) {
2334                 errno = close_err;
2335                 END_PROFILE(SMBwriteclose);
2336                 return(UNIXERROR(ERRHRD,ERRgeneral));
2337         }
2338  
2339         outsize = set_message(outbuf,1,0,True);
2340   
2341         SSVAL(outbuf,smb_vwv0,nwritten);
2342         END_PROFILE(SMBwriteclose);
2343         return(outsize);
2344 }
2345
2346
2347 /****************************************************************************
2348   reply to a lock
2349 ****************************************************************************/
2350 int reply_lock(connection_struct *conn,
2351                char *inbuf,char *outbuf, int length, int dum_buffsize)
2352 {
2353         int outsize = set_message(outbuf,0,0,True);
2354         SMB_BIG_UINT count,offset;
2355         NTSTATUS status;
2356         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2357         START_PROFILE(SMBlock);
2358
2359         CHECK_FSP(fsp,conn);
2360
2361         release_level_2_oplocks_on_change(fsp);
2362
2363         count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
2364         offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
2365
2366         DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2367                  fsp->fd, fsp->fnum, (double)offset, (double)count));
2368
2369         status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK);
2370         if (NT_STATUS_V(status)) {
2371                 if (lp_blocking_locks(SNUM(conn))) {
2372                         /*
2373                          * A blocking lock was requested. Package up
2374                          * this smb into a queued request and push it
2375                          * onto the blocking lock queue.
2376                          */
2377                         if(push_blocking_lock_request(inbuf, length, -1, 0)) {
2378                                 END_PROFILE(SMBlock);
2379                                 return -1;
2380                         }
2381                 }
2382                 END_PROFILE(SMBlock);
2383                 return ERROR_NT(status);
2384         }
2385
2386         END_PROFILE(SMBlock);
2387         return(outsize);
2388 }
2389
2390
2391 /****************************************************************************
2392   reply to a unlock
2393 ****************************************************************************/
2394 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, 
2395                  int dum_buffsize)
2396 {
2397         int outsize = set_message(outbuf,0,0,True);
2398         SMB_BIG_UINT count,offset;
2399         NTSTATUS status;
2400         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2401         START_PROFILE(SMBunlock);
2402
2403         CHECK_FSP(fsp,conn);
2404         
2405         count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
2406         offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
2407         
2408         status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
2409         if (NT_STATUS_V(status)) {
2410                 END_PROFILE(SMBunlock);
2411                 return ERROR_NT(status);
2412         }
2413
2414         DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2415                     fsp->fd, fsp->fnum, (double)offset, (double)count ) );
2416         
2417         END_PROFILE(SMBunlock);
2418         return(outsize);
2419 }
2420
2421
2422 /****************************************************************************
2423   reply to a tdis
2424 ****************************************************************************/
2425 int reply_tdis(connection_struct *conn, 
2426                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2427 {
2428         int outsize = set_message(outbuf,0,0,True);
2429         uint16 vuid;
2430         START_PROFILE(SMBtdis);
2431
2432         vuid = SVAL(inbuf,smb_uid);
2433
2434         if (!conn) {
2435                 DEBUG(4,("Invalid connection in tdis\n"));
2436                 END_PROFILE(SMBtdis);
2437                 return ERROR_DOS(ERRSRV,ERRinvnid);
2438         }
2439
2440         conn->used = False;
2441
2442         close_cnum(conn,vuid);
2443   
2444         END_PROFILE(SMBtdis);
2445         return outsize;
2446 }
2447
2448
2449
2450 /****************************************************************************
2451   reply to a echo
2452 ****************************************************************************/
2453 int reply_echo(connection_struct *conn,
2454                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2455 {
2456         int smb_reverb = SVAL(inbuf,smb_vwv0);
2457         int seq_num;
2458         unsigned int data_len = smb_buflen(inbuf);
2459         int outsize = set_message(outbuf,1,data_len,True);
2460         START_PROFILE(SMBecho);
2461
2462         data_len = MIN(data_len, (sizeof(inbuf)-(smb_buf(inbuf)-inbuf)));
2463
2464         /* copy any incoming data back out */
2465         if (data_len > 0)
2466                 memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2467
2468         if (smb_reverb > 100) {
2469                 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2470                 smb_reverb = 100;
2471         }
2472
2473         for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
2474                 SSVAL(outbuf,smb_vwv0,seq_num);
2475
2476                 smb_setlen(outbuf,outsize - 4);
2477
2478                 if (!send_smb(smbd_server_fd(),outbuf))
2479                         exit_server("reply_echo: send_smb failed.");
2480         }
2481
2482         DEBUG(3,("echo %d times\n", smb_reverb));
2483
2484         smb_echo_count++;
2485
2486         END_PROFILE(SMBecho);
2487         return -1;
2488 }
2489
2490
2491 /****************************************************************************
2492   reply to a printopen
2493 ****************************************************************************/
2494 int reply_printopen(connection_struct *conn, 
2495                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2496 {
2497         int outsize = 0;
2498         files_struct *fsp;
2499         START_PROFILE(SMBsplopen);
2500         
2501         if (!CAN_PRINT(conn)) {
2502                 END_PROFILE(SMBsplopen);
2503                 return ERROR_DOS(ERRDOS,ERRnoaccess);
2504         }
2505
2506         /* Open for exclusive use, write only. */
2507         fsp = print_fsp_open(conn, NULL);
2508
2509         if (!fsp) {
2510                 END_PROFILE(SMBsplopen);
2511                 return(UNIXERROR(ERRDOS,ERRnoaccess));
2512         }
2513
2514         outsize = set_message(outbuf,1,0,True);
2515         SSVAL(outbuf,smb_vwv0,fsp->fnum);
2516   
2517         DEBUG(3,("openprint fd=%d fnum=%d\n",
2518                  fsp->fd, fsp->fnum));
2519
2520         END_PROFILE(SMBsplopen);
2521         return(outsize);
2522 }
2523
2524
2525 /****************************************************************************
2526   reply to a printclose
2527 ****************************************************************************/
2528 int reply_printclose(connection_struct *conn,
2529                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2530 {
2531         int outsize = set_message(outbuf,0,0,True);
2532         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2533         int close_err = 0;
2534         START_PROFILE(SMBsplclose);
2535
2536         CHECK_FSP(fsp,conn);
2537
2538         if (!CAN_PRINT(conn)) {
2539                 END_PROFILE(SMBsplclose);
2540                 return ERROR_DOS(ERRDOS,ERRnoaccess);
2541         }
2542   
2543         DEBUG(3,("printclose fd=%d fnum=%d\n",
2544                  fsp->fd,fsp->fnum));
2545   
2546         close_err = close_file(fsp,True);
2547
2548         if(close_err != 0) {
2549                 errno = close_err;
2550                 END_PROFILE(SMBsplclose);
2551                 return(UNIXERROR(ERRHRD,ERRgeneral));
2552         }
2553
2554         END_PROFILE(SMBsplclose);
2555         return(outsize);
2556 }
2557
2558
2559 /****************************************************************************
2560   reply to a printqueue
2561 ****************************************************************************/
2562 int reply_printqueue(connection_struct *conn,
2563                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2564 {
2565         int outsize = set_message(outbuf,2,3,True);
2566         int max_count = SVAL(inbuf,smb_vwv0);
2567         int start_index = SVAL(inbuf,smb_vwv1);
2568         START_PROFILE(SMBsplretq);
2569
2570         /* we used to allow the client to get the cnum wrong, but that
2571            is really quite gross and only worked when there was only
2572            one printer - I think we should now only accept it if they
2573            get it right (tridge) */
2574         if (!CAN_PRINT(conn)) {
2575                 END_PROFILE(SMBsplretq);
2576                 return ERROR_DOS(ERRDOS,ERRnoaccess);
2577         }
2578
2579         SSVAL(outbuf,smb_vwv0,0);
2580         SSVAL(outbuf,smb_vwv1,0);
2581         SCVAL(smb_buf(outbuf),0,1);
2582         SSVAL(smb_buf(outbuf),1,0);
2583   
2584         DEBUG(3,("printqueue start_index=%d max_count=%d\n",
2585                  start_index, max_count));
2586
2587         {
2588                 print_queue_struct *queue = NULL;
2589                 print_status_struct status;
2590                 char *p = smb_buf(outbuf) + 3;
2591                 int count = print_queue_status(SNUM(conn), &queue, &status);
2592                 int num_to_get = ABS(max_count);
2593                 int first = (max_count>0?start_index:start_index+max_count+1);
2594                 int i;
2595
2596                 if (first >= count)
2597                         num_to_get = 0;
2598                 else
2599                         num_to_get = MIN(num_to_get,count-first);
2600     
2601
2602                 for (i=first;i<first+num_to_get;i++) {
2603                         put_dos_date2(p,0,queue[i].time);
2604                         SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
2605                         SSVAL(p,5, queue[i].job);
2606                         SIVAL(p,7,queue[i].size);
2607                         SCVAL(p,11,0);
2608                         srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII);
2609                         p += 28;
2610                 }
2611
2612                 if (count > 0) {
2613                         outsize = set_message(outbuf,2,28*count+3,False); 
2614                         SSVAL(outbuf,smb_vwv0,count);
2615                         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
2616                         SCVAL(smb_buf(outbuf),0,1);
2617                         SSVAL(smb_buf(outbuf),1,28*count);
2618                 }
2619
2620                 SAFE_FREE(queue);
2621           
2622                 DEBUG(3,("%d entries returned in queue\n",count));
2623         }
2624   
2625         END_PROFILE(SMBsplretq);
2626         return(outsize);
2627 }
2628
2629
2630 /****************************************************************************
2631   reply to a printwrite
2632 ****************************************************************************/
2633 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2634 {
2635   int numtowrite;
2636   int outsize = set_message(outbuf,0,0,True);
2637   char *data;
2638   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2639   START_PROFILE(SMBsplwr);
2640   
2641   if (!CAN_PRINT(conn)) {
2642     END_PROFILE(SMBsplwr);
2643     return ERROR_DOS(ERRDOS,ERRnoaccess);
2644   }
2645
2646   CHECK_FSP(fsp,conn);
2647   CHECK_WRITE(fsp);
2648
2649   numtowrite = SVAL(smb_buf(inbuf),1);
2650   data = smb_buf(inbuf) + 3;
2651   
2652   if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
2653     END_PROFILE(SMBsplwr);
2654     return(UNIXERROR(ERRDOS,ERRnoaccess));
2655   }
2656
2657   DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
2658   
2659   END_PROFILE(SMBsplwr);
2660   return(outsize);
2661 }
2662
2663
2664 /****************************************************************************
2665  The guts of the mkdir command, split out so it may be called by the NT SMB
2666  code. 
2667 ****************************************************************************/
2668 NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
2669 {
2670         BOOL bad_path = False;
2671         SMB_STRUCT_STAT sbuf;
2672         int ret= -1;
2673         
2674         unix_convert(directory,conn,0,&bad_path,&sbuf);
2675         
2676         if (check_name(directory, conn))
2677                 ret = vfs_mkdir(conn,directory,unix_mode(conn,aDIR,directory));
2678         
2679         if (ret == -1) {
2680                 return map_nt_error_from_unix(errno);
2681         }
2682         
2683         return NT_STATUS_OK;
2684 }
2685
2686 /****************************************************************************
2687  Reply to a mkdir.
2688 ****************************************************************************/
2689
2690 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2691 {
2692         pstring directory;
2693         int outsize;
2694         NTSTATUS status;
2695         START_PROFILE(SMBmkdir);
2696  
2697         srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
2698
2699         status = mkdir_internal(conn, directory);
2700         if (!NT_STATUS_IS_OK(status))
2701                 return ERROR_NT(status);
2702
2703         outsize = set_message(outbuf,0,0,True);
2704
2705         DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
2706
2707         END_PROFILE(SMBmkdir);
2708         return(outsize);
2709 }
2710
2711 /****************************************************************************
2712  Static function used by reply_rmdir to delete an entire directory
2713  tree recursively. Return False on ok, True on fail.
2714 ****************************************************************************/
2715
2716 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
2717 {
2718         char *dname = NULL;
2719         BOOL ret = False;
2720         void *dirptr = OpenDir(conn, directory, False);
2721
2722         if(dirptr == NULL)
2723                 return True;
2724
2725         while((dname = ReadDirName(dirptr))) {
2726                 pstring fullname;
2727                 SMB_STRUCT_STAT st;
2728
2729                 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2730                         continue;
2731
2732                 /* Construct the full name. */
2733                 if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
2734                         errno = ENOMEM;
2735                         ret = True;
2736                         break;
2737                 }
2738
2739                 pstrcpy(fullname, directory);
2740                 pstrcat(fullname, "/");
2741                 pstrcat(fullname, dname);
2742
2743                 if(conn->vfs_ops.lstat(conn,fullname, &st) != 0) {
2744                         ret = True;
2745                         break;
2746                 }
2747
2748                 if(st.st_mode & S_IFDIR) {
2749                         if(recursive_rmdir(conn, fullname)!=0) {
2750                                 ret = True;
2751                                 break;
2752                         }
2753                         if(vfs_rmdir(conn,fullname) != 0) {
2754                                 ret = True;
2755                                 break;
2756                         }
2757                 } else if(vfs_unlink(conn,fullname) != 0) {
2758                         ret = True;
2759                         break;
2760                 }
2761         }
2762         CloseDir(dirptr);
2763         return ret;
2764 }
2765
2766 /****************************************************************************
2767  The internals of the rmdir code - called elsewhere.
2768 ****************************************************************************/
2769
2770 BOOL rmdir_internals(connection_struct *conn, char *directory)
2771 {
2772         BOOL ok;
2773
2774         ok = (vfs_rmdir(conn,directory) == 0);
2775         if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
2776                 /* 
2777                  * Check to see if the only thing in this directory are
2778                  * vetoed files/directories. If so then delete them and
2779                  * retry. If we fail to delete any of them (and we *don't*
2780                  * do a recursive delete) then fail the rmdir.
2781                  */
2782                 BOOL all_veto_files = True;
2783                 char *dname;
2784                 void *dirptr = OpenDir(conn, directory, False);
2785
2786                 if(dirptr != NULL) {
2787                         int dirpos = TellDir(dirptr);
2788                         while ((dname = ReadDirName(dirptr))) {
2789                                 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2790                                         continue;
2791                                 if(!IS_VETO_PATH(conn, dname)) {
2792                                         all_veto_files = False;
2793                                         break;
2794                                 }
2795                         }
2796
2797                         if(all_veto_files) {
2798                                 SeekDir(dirptr,dirpos);
2799                                 while ((dname = ReadDirName(dirptr))) {
2800                                         pstring fullname;
2801                                         SMB_STRUCT_STAT st;
2802
2803                                         if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
2804                                                 continue;
2805
2806                                         /* Construct the full name. */
2807                                         if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
2808                                                 errno = ENOMEM;
2809                                                 break;
2810                                         }
2811
2812                                         pstrcpy(fullname, directory);
2813                                         pstrcat(fullname, "/");
2814                                         pstrcat(fullname, dname);
2815                      
2816                                         if(conn->vfs_ops.lstat(conn,fullname, &st) != 0)
2817                                                 break;
2818                                         if(st.st_mode & S_IFDIR) {
2819                                                 if(lp_recursive_veto_delete(SNUM(conn))) {
2820                                                         if(recursive_rmdir(conn, fullname) != 0)
2821                                                                 break;
2822                                                 }
2823                                                 if(vfs_rmdir(conn,fullname) != 0)
2824                                                         break;
2825                                         } else if(vfs_unlink(conn,fullname) != 0)
2826                                                 break;
2827                                 }
2828                                 CloseDir(dirptr);
2829                                 /* Retry the rmdir */
2830                                 ok = (vfs_rmdir(conn,directory) == 0);
2831                         } else {
2832                                 CloseDir(dirptr);
2833                         }
2834                 } else {
2835                         errno = ENOTEMPTY;
2836                 }
2837         }
2838
2839         if (!ok)
2840                 DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
2841
2842         return ok;
2843 }
2844
2845 /****************************************************************************
2846  Reply to a rmdir.
2847 ****************************************************************************/
2848
2849 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2850 {
2851   pstring directory;
2852   int outsize = 0;
2853   BOOL ok = False;
2854   BOOL bad_path = False;
2855   SMB_STRUCT_STAT sbuf;
2856   START_PROFILE(SMBrmdir);
2857
2858   srvstr_pull(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), -1, STR_TERMINATE);
2859
2860   RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
2861
2862   unix_convert(directory,conn, NULL,&bad_path,&sbuf);
2863   
2864   if (check_name(directory,conn))
2865   {
2866     dptr_closepath(directory,SVAL(inbuf,smb_pid));
2867     ok = rmdir_internals(conn, directory);
2868   }
2869   
2870   if (!ok)
2871   {
2872     if((errno == ENOENT) && bad_path)
2873     {
2874       unix_ERR_class = ERRDOS;
2875       unix_ERR_code = ERRbadpath;
2876     }
2877     END_PROFILE(SMBrmdir);
2878     return(UNIXERROR(ERRDOS,ERRbadpath));
2879   }
2880  
2881   outsize = set_message(outbuf,0,0,True);
2882   
2883   DEBUG( 3, ( "rmdir %s\n", directory ) );
2884   
2885   END_PROFILE(SMBrmdir);
2886   return(outsize);
2887 }
2888
2889
2890 /*******************************************************************
2891 resolve wildcards in a filename rename
2892 ********************************************************************/
2893 static BOOL resolve_wildcards(char *name1,char *name2)
2894 {
2895   fstring root1,root2;
2896   fstring ext1,ext2;
2897   char *p,*p2;
2898
2899   name1 = strrchr_m(name1,'/');
2900   name2 = strrchr_m(name2,'/');
2901
2902   if (!name1 || !name2) return(False);
2903   
2904   fstrcpy(root1,name1);
2905   fstrcpy(root2,name2);
2906   p = strrchr_m(root1,'.');
2907   if (p) {
2908     *p = 0;
2909     fstrcpy(ext1,p+1);
2910   } else {
2911     fstrcpy(ext1,"");    
2912   }
2913   p = strrchr_m(root2,'.');
2914   if (p) {
2915     *p = 0;
2916     fstrcpy(ext2,p+1);
2917   } else {
2918     fstrcpy(ext2,"");    
2919   }
2920
2921   p = root1;
2922   p2 = root2;
2923   while (*p2) {
2924     if (*p2 == '?') {
2925       *p2 = *p;
2926       p2++;
2927     } else {
2928       p2++;
2929     }
2930     if (*p) p++;
2931   }
2932
2933   p = ext1;
2934   p2 = ext2;
2935   while (*p2) {
2936     if (*p2 == '?') {
2937       *p2 = *p;
2938       p2++;
2939     } else {
2940       p2++;
2941     }
2942     if (*p) p++;
2943   }
2944
2945   pstrcpy(name2,root2);
2946   if (ext2[0]) {
2947     pstrcat(name2,".");
2948     pstrcat(name2,ext2);
2949   }
2950
2951   return(True);
2952 }
2953
2954 /*******************************************************************
2955  Check if a user is allowed to rename a file.
2956 ********************************************************************/
2957
2958 static NTSTATUS can_rename(char *fname,connection_struct *conn)
2959 {
2960         if (!CAN_WRITE(conn))
2961                 return NT_STATUS_ACCESS_DENIED;
2962
2963         if (!check_file_sharing(conn,fname,True))
2964                 return NT_STATUS_SHARING_VIOLATION;
2965
2966         return NT_STATUS_OK;
2967 }
2968
2969 /****************************************************************************
2970  The guts of the rename command, split out so it may be called by the NT SMB
2971  code. 
2972 ****************************************************************************/
2973
2974 NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, BOOL replace_if_exists)
2975 {
2976         pstring directory;
2977         pstring mask;
2978         pstring newname_last_component;
2979         char *p;
2980         BOOL has_wild;
2981         BOOL bad_path1 = False;
2982         BOOL bad_path2 = False;
2983         int count=0;
2984         NTSTATUS error = NT_STATUS_OK;
2985         BOOL rc = True;
2986         SMB_STRUCT_STAT sbuf1, sbuf2;
2987
2988         *directory = *mask = 0;
2989
2990         rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
2991         unix_convert(newname,conn,newname_last_component,&bad_path2,&sbuf2);
2992
2993         /*
2994          * Split the old name into directory and last component
2995          * strings. Note that unix_convert may have stripped off a 
2996          * leading ./ from both name and newname if the rename is 
2997          * at the root of the share. We need to make sure either both
2998          * name and newname contain a / character or neither of them do
2999          * as this is checked in resolve_wildcards().
3000          */
3001         
3002         p = strrchr_m(name,'/');
3003         if (!p) {
3004                 pstrcpy(directory,".");
3005                 pstrcpy(mask,name);
3006         } else {
3007                 *p = 0;
3008                 pstrcpy(directory,name);
3009                 pstrcpy(mask,p+1);
3010                 *p = '/'; /* Replace needed for exceptional test below. */
3011         }
3012
3013         /*
3014          * We should only check the mangled cache
3015          * here if unix_convert failed. This means
3016          * that the path in 'mask' doesn't exist
3017          * on the file system and so we need to look
3018          * for a possible mangle. This patch from
3019          * Tine Smukavec <valentin.smukavec@hermes.si>.
3020          */
3021
3022 #if 0
3023         if (!rc && is_mangled(mask))
3024                 check_mangled_cache( mask );
3025 #endif
3026         if (!rc)
3027         {
3028                 char *unmangled;
3029                 
3030                 unmangled = dos_unmangle(mask);
3031                 if (unmangled)
3032                         strncpy(mask, unmangled, strlen(unmangled) + 1);
3033                         
3034                 SAFE_FREE(unmangled);
3035         }
3036
3037         has_wild = ms_has_wild(mask);
3038
3039         if (!has_wild) {
3040                 /*
3041                  * No wildcards - just process the one file.
3042                  */
3043                 BOOL is_short_name = is_8_3(name, True);
3044
3045                 /* Add a terminating '/' to the directory name. */
3046                 pstrcat(directory,"/");
3047                 pstrcat(directory,mask);
3048                 
3049                 /* Ensure newname contains a '/' also */
3050                 if(strrchr_m(newname,'/') == 0) {
3051                         pstring tmpstr;
3052                         
3053                         pstrcpy(tmpstr, "./");
3054                         pstrcat(tmpstr, newname);
3055                         pstrcpy(newname, tmpstr);
3056                 }
3057                 
3058                 DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
3059 directory = %s, newname = %s, newname_last_component = %s, is_8_3 = %d\n", 
3060                          case_sensitive, case_preserve, short_case_preserve, directory, 
3061                          newname, newname_last_component, is_short_name));
3062
3063                 /*
3064                  * Check for special case with case preserving and not
3065                  * case sensitive, if directory and newname are identical,
3066                  * and the old last component differs from the original
3067                  * last component only by case, then we should allow
3068                  * the rename (user is trying to change the case of the
3069                  * filename).
3070                  */
3071                 if((case_sensitive == False) && 
3072                    (((case_preserve == True) && 
3073                      (is_short_name == False)) || 
3074                     ((short_case_preserve == True) && 
3075                      (is_short_name == True))) &&
3076                    strcsequal(directory, newname)) {
3077                         pstring newname_modified_last_component;
3078
3079                         /*
3080                          * Get the last component of the modified name.
3081                          * Note that we guarantee that newname contains a '/'
3082                          * character above.
3083                          */
3084                         p = strrchr_m(newname,'/');
3085                         pstrcpy(newname_modified_last_component,p+1);
3086                         
3087                         if(strcsequal(newname_modified_last_component, 
3088                                       newname_last_component) == False) {
3089                                 /*
3090                                  * Replace the modified last component with
3091                                  * the original.
3092                                  */
3093                                 pstrcpy(p+1, newname_last_component);
3094                         }
3095                 }
3096         
3097                 resolve_wildcards(directory,newname);
3098         
3099                 /*
3100                  * The source object must exist.
3101                  */
3102
3103                 if (!vfs_object_exist(conn, directory, NULL)) {
3104                         DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
3105                                 directory,newname));
3106
3107                         if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
3108                                 /*
3109                                  * Must return different errors depending on whether the parent
3110                                  * directory existed or not.
3111                                  */
3112
3113                                 p = strrchr_m(directory, '/');
3114                                 if (!p)
3115                                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3116                                 *p = '\0';
3117                                 if (vfs_object_exist(conn, directory, NULL))
3118                                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3119                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3120                         }
3121                         error = map_nt_error_from_unix(errno);
3122                         DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3123                                 nt_errstr(error), directory,newname));
3124
3125                         return error;
3126                 }
3127
3128                 error = can_rename(directory,conn);
3129
3130                 if (!NT_STATUS_IS_OK(error)) {
3131                         DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3132                                 nt_errstr(error), directory,newname));
3133                         return error;
3134                 }
3135
3136                 /*
3137                  * If the src and dest names are identical - including case,
3138                  * don't do the rename, just return success.
3139                  */
3140
3141                 if (strcsequal(directory, newname)) {
3142                         DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
3143                         return NT_STATUS_OK;
3144                 }
3145
3146                 if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
3147                         DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
3148                                 directory,newname));
3149                         return NT_STATUS_OBJECT_NAME_COLLISION;
3150                 }
3151
3152                 if(conn->vfs_ops.rename(conn,directory, newname) == 0) {
3153                         DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
3154                                 directory,newname));
3155                         return NT_STATUS_OK;    
3156                 }
3157
3158                 if (errno == ENOTDIR || errno == EISDIR)
3159                         error = NT_STATUS_OBJECT_NAME_COLLISION;
3160                 else
3161                         error = map_nt_error_from_unix(errno);
3162                 
3163                 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3164                         nt_errstr(error), directory,newname));
3165
3166                 return error;
3167         } else {
3168                 /*
3169                  * Wildcards - process each file that matches.
3170                  */
3171                 void *dirptr = NULL;
3172                 char *dname;
3173                 pstring destname;
3174                 
3175                 if (check_name(directory,conn))
3176                         dirptr = OpenDir(conn, directory, True);
3177                 
3178                 if (dirptr) {
3179                         error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3180                         
3181                         if (strequal(mask,"????????.???"))
3182                                 pstrcpy(mask,"*");
3183                         
3184                         while ((dname = ReadDirName(dirptr))) {
3185                                 pstring fname;
3186
3187                                 pstrcpy(fname,dname);
3188                                 
3189                                 if(!mask_match(fname, mask, case_sensitive))
3190                                         continue;
3191                                 
3192                                 error = NT_STATUS_ACCESS_DENIED;
3193                                 slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
3194                                 error = can_rename(fname,conn);
3195                                 if (!NT_STATUS_IS_OK(error)) {
3196                                         DEBUG(6,("rename %s refused\n", fname));
3197                                         continue;
3198                                 }
3199                                 pstrcpy(destname,newname);
3200                                 
3201                                 if (!resolve_wildcards(fname,destname)) {
3202                                         DEBUG(6,("resolve_wildcards %s %s failed\n", 
3203                                                  fname, destname));
3204                                         continue;
3205                                 }
3206                                 
3207                                 if (!replace_if_exists && 
3208                                     vfs_file_exist(conn,destname, NULL)) {
3209                                         DEBUG(6,("file_exist %s\n", destname));
3210                                         error = NT_STATUS_OBJECT_NAME_COLLISION;
3211                                         continue;
3212                                 }
3213                                 
3214                                 if (!conn->vfs_ops.rename(conn,fname,destname))
3215                                         count++;
3216                                 DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
3217                         }
3218                         CloseDir(dirptr);
3219                 }
3220         }
3221         
3222         if (count == 0 && NT_STATUS_IS_OK(error)) {
3223                 error = map_nt_error_from_unix(errno);
3224         }
3225         
3226         return error;
3227 }
3228
3229 /****************************************************************************
3230  Reply to a mv.
3231 ****************************************************************************/
3232
3233 int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
3234              int dum_buffsize)
3235 {
3236         int outsize = 0;
3237         pstring name;
3238         pstring newname;
3239         char *p;
3240         NTSTATUS status;
3241
3242         START_PROFILE(SMBmv);
3243
3244         p = smb_buf(inbuf) + 1;
3245         p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
3246         p++;
3247         p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
3248         
3249         RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
3250         RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
3251         
3252         DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
3253         
3254         status = rename_internals(conn, name, newname, False);
3255         if (!NT_STATUS_IS_OK(status)) {
3256                 return ERROR_NT(status);
3257         }
3258
3259         /*
3260          * Win2k needs a changenotify request response before it will
3261          * update after a rename..
3262          */     
3263         process_pending_change_notify_queue((time_t)0);
3264         outsize = set_message(outbuf,0,0,True);
3265   
3266         END_PROFILE(SMBmv);
3267         return(outsize);
3268 }
3269
3270 /*******************************************************************
3271  Copy a file as part of a reply_copy.
3272 ******************************************************************/
3273
3274 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
3275                       int count,BOOL target_is_directory, int *err_ret)
3276 {
3277         int Access,action;
3278         SMB_STRUCT_STAT src_sbuf, sbuf2;
3279         SMB_OFF_T ret=-1;
3280         files_struct *fsp1,*fsp2;
3281         pstring dest;
3282   
3283         *err_ret = 0;
3284
3285         pstrcpy(dest,dest1);
3286         if (target_is_directory) {
3287                 char *p = strrchr_m(src,'/');
3288                 if (p) 
3289                         p++;
3290                 else
3291                         p = src;
3292                 pstrcat(dest,"/");
3293                 pstrcat(dest,p);
3294         }
3295
3296         if (!vfs_file_exist(conn,src,&src_sbuf))
3297                 return(False);
3298
3299         fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
3300                                         (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
3301
3302         if (!fsp1)
3303                 return(False);
3304
3305         if (!target_is_directory && count)
3306                 ofun = FILE_EXISTS_OPEN;
3307
3308         if (vfs_stat(conn,dest,&sbuf2) == -1)
3309                 ZERO_STRUCTP(&sbuf2);
3310
3311         fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
3312                         ofun,src_sbuf.st_mode,0,&Access,&action);
3313
3314         if (!fsp2) {
3315                 close_file(fsp1,False);
3316                 return(False);
3317         }
3318
3319         if ((ofun&3) == 1) {
3320                 if(conn->vfs_ops.lseek(fsp2,fsp2->fd,0,SEEK_END) == -1) {
3321                         DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
3322                         /*
3323                          * Stop the copy from occurring.
3324                          */
3325                         ret = -1;
3326                         src_sbuf.st_size = 0;
3327                 }
3328         }
3329   
3330         if (src_sbuf.st_size)
3331                 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
3332
3333         close_file(fsp1,False);
3334
3335         /* Ensure the modtime is set correctly on the destination file. */
3336         fsp2->pending_modtime = src_sbuf.st_mtime;
3337
3338         /*
3339          * As we are opening fsp1 read-only we only expect
3340          * an error on close on fsp2 if we are out of space.
3341          * Thus we don't look at the error return from the
3342          * close of fsp1.
3343          */
3344         *err_ret = close_file(fsp2,False);
3345
3346         return(ret == (SMB_OFF_T)src_sbuf.st_size);
3347 }
3348
3349 /****************************************************************************
3350   reply to a file copy.
3351   ****************************************************************************/
3352 int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3353 {
3354   int outsize = 0;
3355   pstring name;
3356   pstring directory;
3357   pstring mask,newname;
3358   char *p;
3359   int count=0;
3360   int error = ERRnoaccess;
3361   int err = 0;
3362   BOOL has_wild;
3363   BOOL exists=False;
3364   int tid2 = SVAL(inbuf,smb_vwv0);
3365   int ofun = SVAL(inbuf,smb_vwv1);
3366   int flags = SVAL(inbuf,smb_vwv2);
3367   BOOL target_is_directory=False;
3368   BOOL bad_path1 = False;
3369   BOOL bad_path2 = False;
3370   BOOL rc = True;
3371   SMB_STRUCT_STAT sbuf1, sbuf2;
3372   START_PROFILE(SMBcopy);
3373
3374   *directory = *mask = 0;
3375
3376   p = smb_buf(inbuf);
3377   p += srvstr_pull(inbuf, name, p, sizeof(name), -1, STR_TERMINATE);
3378   p += srvstr_pull(inbuf, newname, p, sizeof(newname), -1, STR_TERMINATE);
3379    
3380   DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
3381    
3382   if (tid2 != conn->cnum) {
3383     /* can't currently handle inter share copies XXXX */
3384     DEBUG(3,("Rejecting inter-share copy\n"));
3385     END_PROFILE(SMBcopy);
3386     return ERROR_DOS(ERRSRV,ERRinvdevice);
3387   }
3388
3389   RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
3390   RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
3391
3392   rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
3393   unix_convert(newname,conn,0,&bad_path2,&sbuf2);
3394
3395   target_is_directory = VALID_STAT_OF_DIR(sbuf2);
3396
3397   if ((flags&1) && target_is_directory) {
3398     END_PROFILE(SMBcopy);
3399     return ERROR_DOS(ERRDOS,ERRbadfile);
3400   }
3401
3402   if ((flags&2) && !target_is_directory) {
3403     END_PROFILE(SMBcopy);
3404     return ERROR_DOS(ERRDOS,ERRbadpath);
3405   }
3406
3407   if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
3408     /* wants a tree copy! XXXX */
3409     DEBUG(3,("Rejecting tree copy\n"));
3410     END_PROFILE(SMBcopy);
3411     return ERROR_DOS(ERRSRV,ERRerror);
3412   }
3413
3414   p = strrchr_m(name,'/');
3415   if (!p) {
3416     pstrcpy(directory,"./");
3417     pstrcpy(mask,name);
3418   } else {
3419     *p = 0;
3420     pstrcpy(directory,name);
3421     pstrcpy(mask,p+1);
3422   }
3423
3424   /*
3425    * We should only check the mangled cache
3426    * here if unix_convert failed. This means
3427    * that the path in 'mask' doesn't exist
3428    * on the file system and so we need to look
3429    * for a possible mangle. This patch from
3430    * Tine Smukavec <valentin.smukavec@hermes.si>.
3431    */
3432
3433 #if 0
3434         if (!rc && is_mangled(mask))
3435                 check_mangled_cache( mask );
3436 #endif
3437         if (!rc)
3438         {
3439                 char *unmangled;
3440                 
3441                 unmangled = dos_unmangle(mask);
3442                 if (unmangled)
3443                         strncpy(mask, unmangled, strlen(unmangled) + 1);
3444                         
3445                 SAFE_FREE(unmangled);
3446         }
3447
3448
3449   has_wild = ms_has_wild(mask);
3450
3451   if (!has_wild) {
3452     pstrcat(directory,"/");
3453     pstrcat(directory,mask);
3454     if (resolve_wildcards(directory,newname) && 
3455         copy_file(directory,newname,conn,ofun,
3456                   count,target_is_directory,&err)) count++;
3457     if(!count && err) {
3458                 errno = err;
3459                 END_PROFILE(SMBcopy);
3460                 return(UNIXERROR(ERRHRD,ERRgeneral));
3461         }
3462     if (!count) exists = vfs_file_exist(conn,directory,NULL);
3463   } else {
3464     void *dirptr = NULL;
3465     char *dname;
3466     pstring destname;
3467
3468     if (check_name(directory,conn))
3469       dirptr = OpenDir(conn, directory, True);
3470
3471     if (dirptr) {
3472         error = ERRbadfile;
3473
3474         if (strequal(mask,"????????.???"))
3475           pstrcpy(mask,"*");
3476
3477         while ((dname = ReadDirName(dirptr))) {
3478             pstring fname;
3479             pstrcpy(fname,dname);
3480             
3481             if(!mask_match(fname, mask, case_sensitive))
3482                         continue;
3483
3484             error = ERRnoaccess;
3485             slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
3486             pstrcpy(destname,newname);
3487             if (resolve_wildcards(fname,destname) && 
3488                 copy_file(fname,destname,conn,ofun,
3489                           count,target_is_directory,&err)) count++;
3490             DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
3491           }
3492         CloseDir(dirptr);
3493     }
3494   }
3495   
3496   if (count == 0) {
3497     if(err) {
3498       /* Error on close... */
3499       errno = err;
3500       END_PROFILE(SMBcopy);
3501       return(UNIXERROR(ERRHRD,ERRgeneral));
3502     }
3503
3504     if (exists) {
3505       END_PROFILE(SMBcopy);
3506       return ERROR_DOS(ERRDOS,error);
3507     } else
3508     {
3509       if((errno == ENOENT) && (bad_path1 || bad_path2))
3510       {
3511         unix_ERR_class = ERRDOS;
3512         unix_ERR_code = ERRbadpath;
3513       }
3514       END_PROFILE(SMBcopy);
3515       return(UNIXERROR(ERRDOS,error));
3516     }
3517   }
3518   
3519   outsize = set_message(outbuf,1,0,True);
3520   SSVAL(outbuf,smb_vwv0,count);
3521
3522   END_PROFILE(SMBcopy);
3523   return(outsize);
3524 }
3525
3526 /****************************************************************************
3527   reply to a setdir
3528 ****************************************************************************/
3529 int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3530 {
3531   int snum;
3532   int outsize = 0;
3533   BOOL ok = False;
3534   pstring newdir;
3535   START_PROFILE(pathworks_setdir);
3536   
3537   snum = SNUM(conn);
3538   if (!CAN_SETDIR(snum)) {
3539     END_PROFILE(pathworks_setdir);
3540     return ERROR_DOS(ERRDOS,ERRnoaccess);
3541   }
3542
3543   srvstr_pull(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), -1, STR_TERMINATE);
3544   
3545   if (strlen(newdir) == 0) {
3546           ok = True;
3547   } else {
3548           ok = vfs_directory_exist(conn,newdir,NULL);
3549           if (ok) {
3550                   string_set(&conn->connectpath,newdir);
3551           }
3552   }
3553   
3554   if (!ok) {
3555           END_PROFILE(pathworks_setdir);
3556           return ERROR_DOS(ERRDOS,ERRbadpath);
3557   }
3558   
3559   outsize = set_message(outbuf,0,0,True);
3560   SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
3561   
3562   DEBUG(3,("setdir %s\n", newdir));
3563
3564   END_PROFILE(pathworks_setdir);
3565   return(outsize);
3566 }
3567
3568 /****************************************************************************
3569  Get a lock pid, dealing with large count requests.
3570 ****************************************************************************/
3571
3572 uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
3573 {
3574         if(!large_file_format)
3575                 return SVAL(data,SMB_LPID_OFFSET(data_offset));
3576         else
3577                 return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
3578 }
3579
3580 /****************************************************************************
3581  Get a lock count, dealing with large count requests.
3582 ****************************************************************************/
3583
3584 SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
3585 {
3586   SMB_BIG_UINT count = 0;
3587
3588   if(!large_file_format) {
3589     count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
3590   } else {
3591
3592 #if defined(HAVE_LONGLONG)
3593     count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
3594             ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
3595 #else /* HAVE_LONGLONG */
3596
3597     /*
3598      * NT4.x seems to be broken in that it sends large file (64 bit)
3599      * lockingX calls even if the CAP_LARGE_FILES was *not*
3600      * negotiated. For boxes without large unsigned ints truncate the
3601      * lock count by dropping the top 32 bits.
3602      */
3603
3604     if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
3605       DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
3606             (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
3607             (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
3608       SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
3609     }
3610
3611     count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
3612 #endif /* HAVE_LONGLONG */
3613   }
3614
3615   return count;
3616 }
3617
3618 #if !defined(HAVE_LONGLONG)
3619 /****************************************************************************
3620  Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
3621 ****************************************************************************/
3622 static uint32 map_lock_offset(uint32 high, uint32 low)
3623 {
3624         unsigned int i;
3625         uint32 mask = 0;
3626         uint32 highcopy = high;
3627  
3628         /*
3629          * Try and find out how many significant bits there are in high.
3630          */
3631  
3632         for(i = 0; highcopy; i++)
3633                 highcopy >>= 1;
3634  
3635         /*
3636          * We use 31 bits not 32 here as POSIX
3637          * lock offsets may not be negative.
3638          */
3639  
3640         mask = (~0) << (31 - i);
3641  
3642         if(low & mask)
3643                 return 0; /* Fail. */
3644  
3645         high <<= (31 - i);
3646  
3647         return (high|low);
3648 }
3649 #endif /* !defined(HAVE_LONGLONG) */
3650
3651 /****************************************************************************
3652  Get a lock offset, dealing with large offset requests.
3653 ****************************************************************************/
3654
3655 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
3656 {
3657   SMB_BIG_UINT offset = 0;
3658
3659   *err = False;
3660
3661   if(!large_file_format) {
3662     offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
3663   } else {
3664
3665 #if defined(HAVE_LONGLONG)
3666     offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
3667             ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
3668 #else /* HAVE_LONGLONG */
3669
3670     /*
3671      * NT4.x seems to be broken in that it sends large file (64 bit)
3672      * lockingX calls even if the CAP_LARGE_FILES was *not*
3673      * negotiated. For boxes without large unsigned ints mangle the
3674      * lock offset by mapping the top 32 bits onto the lower 32.
3675      */
3676       
3677     if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
3678       uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
3679       uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
3680       uint32 new_low = 0;
3681
3682       if((new_low = map_lock_offset(high, low)) == 0) {
3683         *err = True;
3684         return (SMB_BIG_UINT)-1;
3685       }
3686
3687       DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
3688             (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
3689       SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
3690       SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
3691     }
3692
3693     offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
3694 #endif /* HAVE_LONGLONG */
3695   }
3696
3697   return offset;
3698 }
3699
3700 /****************************************************************************
3701   reply to a lockingX request
3702 ****************************************************************************/
3703
3704 int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
3705 {
3706         files_struct *fsp = file_fsp(inbuf,smb_vwv2);
3707         unsigned char locktype = CVAL(inbuf,smb_vwv3);
3708         unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
3709         uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
3710         uint16 num_locks = SVAL(inbuf,smb_vwv7);
3711         SMB_BIG_UINT count = 0, offset = 0;
3712         uint16 lock_pid;
3713         int32 lock_timeout = IVAL(inbuf,smb_vwv4);
3714         int i;
3715         char *data;
3716         BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
3717         BOOL err;
3718         NTSTATUS status;
3719
3720         START_PROFILE(SMBlockingX);
3721         
3722         CHECK_FSP(fsp,conn);
3723         
3724         data = smb_buf(inbuf);
3725
3726         if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) {
3727                 /* we don't support these - and CANCEL_LOCK makes w2k
3728                    and XP reboot so I don't really want to be
3729                    compatible! (tridge) */
3730                 return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
3731         }
3732         
3733         /* Check if this is an oplock break on a file
3734            we have granted an oplock on.
3735         */
3736         if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
3737                 /* Client can insist on breaking to none. */
3738                 BOOL break_to_none = (oplocklevel == 0);
3739                 
3740                 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
3741                          (unsigned int)oplocklevel, fsp->fnum ));
3742
3743                 /*
3744                  * Make sure we have granted an exclusive or batch oplock on this file.
3745                  */
3746                 
3747                 if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
3748                         DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
3749 no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
3750
3751                         /* if this is a pure oplock break request then don't send a reply */
3752                         if (num_locks == 0 && num_ulocks == 0) {
3753                                 END_PROFILE(SMBlockingX);
3754                                 return -1;
3755                         } else {
3756                                 END_PROFILE(SMBlockingX);
3757                                 return ERROR_DOS(ERRDOS,ERRlock);
3758                         }
3759                 }
3760
3761                 if (remove_oplock(fsp, break_to_none) == False) {
3762                         DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
3763                                  fsp->fsp_name ));
3764                 }
3765                 
3766                 /* if this is a pure oplock break request then don't send a reply */
3767                 if (num_locks == 0 && num_ulocks == 0) {
3768                         /* Sanity check - ensure a pure oplock break is not a
3769                            chained request. */
3770                         if(CVAL(inbuf,smb_vwv0) != 0xff)
3771                                 DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
3772                                          (unsigned int)CVAL(inbuf,smb_vwv0) ));
3773                         END_PROFILE(SMBlockingX);
3774                         return -1;
3775                 }
3776         }
3777
3778         /*
3779          * We do this check *after* we have checked this is not a oplock break
3780          * response message. JRA.
3781          */
3782         
3783         release_level_2_oplocks_on_change(fsp);
3784         
3785         /* Data now points at the beginning of the list
3786            of smb_unlkrng structs */
3787         for(i = 0; i < (int)num_ulocks; i++) {
3788                 lock_pid = get_lock_pid( data, i, large_file_format);
3789                 count = get_lock_count( data, i, large_file_format);
3790                 offset = get_lock_offset( data, i, large_file_format, &err);
3791                 
3792                 /*
3793                  * There is no error code marked "stupid client bug".... :-).
3794                  */
3795                 if(err) {
3796                         END_PROFILE(SMBlockingX);
3797                         return ERROR_DOS(ERRDOS,ERRnoaccess);
3798                 }
3799
3800                 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
3801                           (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
3802                 
3803                 status = do_unlock(fsp,conn,lock_pid,count,offset);
3804                 if (NT_STATUS_V(status)) {
3805                         END_PROFILE(SMBlockingX);
3806                         return ERROR_NT(status);
3807                 }
3808         }
3809
3810         /* Setup the timeout in seconds. */
3811
3812         lock_timeout = ((lock_timeout == -1) ? -1 : lock_timeout/1000);
3813         
3814         /* Now do any requested locks */
3815         data += ((large_file_format ? 20 : 10)*num_ulocks);
3816         
3817         /* Data now points at the beginning of the list
3818            of smb_lkrng structs */
3819         
3820         for(i = 0; i < (int)num_locks; i++) {
3821                 lock_pid = get_lock_pid( data, i, large_file_format);
3822                 count = get_lock_count( data, i, large_file_format);
3823                 offset = get_lock_offset( data, i, large_file_format, &err);
3824                 
3825                 /*
3826                  * There is no error code marked "stupid client bug".... :-).
3827                  */
3828                 if(err) {
3829                         END_PROFILE(SMBlockingX);
3830                         return ERROR_DOS(ERRDOS,ERRnoaccess);
3831                 }
3832                 
3833                 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n",
3834                         (double)offset, (double)count, (unsigned int)lock_pid,
3835                         fsp->fsp_name, (int)lock_timeout ));
3836                 
3837                 status = do_lock_spin(fsp,conn,lock_pid, count,offset, 
3838                                  ((locktype & 1) ? READ_LOCK : WRITE_LOCK));
3839                 if (NT_STATUS_V(status)) {
3840                         if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn))) {
3841                                 /*
3842                                  * A blocking lock was requested. Package up
3843                                  * this smb into a queued request and push it
3844                                  * onto the blocking lock queue.
3845                                  */
3846                                 if(push_blocking_lock_request(inbuf, length, lock_timeout, i)) {
3847                                         END_PROFILE(SMBlockingX);
3848                                         return -1;
3849                                 }
3850                         }
3851                         break;
3852                 }
3853         }
3854         
3855         /* If any of the above locks failed, then we must unlock
3856            all of the previous locks (X/Open spec). */
3857         if (i != num_locks && num_locks != 0) {
3858                 /*
3859                  * Ensure we don't do a remove on the lock that just failed,
3860                  * as under POSIX rules, if we have a lock already there, we
3861                  * will delete it (and we shouldn't) .....
3862                  */
3863                 for(i--; i >= 0; i--) {
3864                         lock_pid = get_lock_pid( data, i, large_file_format);
3865                         count = get_lock_count( data, i, large_file_format);
3866                         offset = get_lock_offset( data, i, large_file_format, &err);
3867                         
3868                         /*
3869                          * There is no error code marked "stupid client bug".... :-).
3870                          */
3871                         if(err) {
3872                                 END_PROFILE(SMBlockingX);
3873                                 return ERROR_DOS(ERRDOS,ERRnoaccess);
3874                         }
3875                         
3876                         do_unlock(fsp,conn,lock_pid,count,offset);
3877                 }
3878                 END_PROFILE(SMBlockingX);
3879                 return ERROR_NT(status);
3880         }
3881
3882         set_message(outbuf,2,0,True);
3883         
3884         DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
3885                     fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
3886         
3887         END_PROFILE(SMBlockingX);
3888         return chain_reply(inbuf,outbuf,length,bufsize);
3889 }
3890
3891 /****************************************************************************
3892  Reply to a SMBreadbmpx (read block multiplex) request.
3893 ****************************************************************************/
3894
3895 int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
3896 {
3897         ssize_t nread = -1;
3898         ssize_t total_read;
3899         char *data;
3900         SMB_OFF_T startpos;
3901         int outsize;
3902         size_t maxcount;
3903         int max_per_packet;
3904         size_t tcount;
3905         int pad;
3906         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3907         START_PROFILE(SMBreadBmpx);
3908
3909         /* this function doesn't seem to work - disable by default */
3910         if (!lp_readbmpx()) {
3911                 END_PROFILE(SMBreadBmpx);
3912                 return ERROR_DOS(ERRSRV,ERRuseSTD);
3913         }
3914
3915         outsize = set_message(outbuf,8,0,True);
3916
3917         CHECK_FSP(fsp,conn);
3918         CHECK_READ(fsp);
3919
3920         startpos = IVAL(inbuf,smb_vwv1);
3921         maxcount = SVAL(inbuf,smb_vwv3);
3922
3923         data = smb_buf(outbuf);
3924         pad = ((long)data)%4;
3925         if (pad)
3926                 pad = 4 - pad;
3927         data += pad;
3928
3929         max_per_packet = bufsize-(outsize+pad);
3930         tcount = maxcount;
3931         total_read = 0;
3932
3933         if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
3934                 END_PROFILE(SMBreadBmpx);
3935                 return ERROR_DOS(ERRDOS,ERRlock);
3936         }
3937
3938         do {
3939                 size_t N = MIN(max_per_packet,tcount-total_read);
3940   
3941                 nread = read_file(fsp,data,startpos,N);
3942
3943                 if (nread <= 0)
3944                         nread = 0;
3945
3946                 if (nread < (ssize_t)N)
3947                         tcount = total_read + nread;
3948
3949                 set_message(outbuf,8,nread,False);
3950                 SIVAL(outbuf,smb_vwv0,startpos);
3951                 SSVAL(outbuf,smb_vwv2,tcount);
3952                 SSVAL(outbuf,smb_vwv6,nread);
3953                 SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
3954
3955                 if (!send_smb(smbd_server_fd(),outbuf))
3956                         exit_server("reply_readbmpx: send_smb failed.");
3957
3958                 total_read += nread;
3959                 startpos += nread;
3960         } while (total_read < (ssize_t)tcount);
3961
3962         END_PROFILE(SMBreadBmpx);
3963         return(-1);
3964 }
3965
3966 /****************************************************************************
3967  Reply to a SMBsetattrE.
3968 ****************************************************************************/
3969
3970 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
3971 {
3972   struct utimbuf unix_times;
3973   int outsize = 0;
3974   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3975   START_PROFILE(SMBsetattrE);
3976
3977   outsize = set_message(outbuf,0,0,True);
3978
3979   CHECK_FSP(fsp,conn);
3980
3981   /* Convert the DOS times into unix times. Ignore create
3982      time as UNIX can't set this.
3983      */
3984   unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
3985   unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
3986   
3987   /* 
3988    * Patch from Ray Frush <frush@engr.colostate.edu>
3989    * Sometimes times are sent as zero - ignore them.
3990    */
3991
3992   if ((unix_times.actime == 0) && (unix_times.modtime == 0)) 
3993   {
3994     /* Ignore request */
3995     if( DEBUGLVL( 3 ) )
3996       {
3997       dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
3998       dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
3999       }
4000     END_PROFILE(SMBsetattrE);
4001     return(outsize);
4002   }
4003   else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) 
4004   {
4005     /* set modify time = to access time if modify time was 0 */
4006     unix_times.modtime = unix_times.actime;
4007   }
4008
4009   /* Set the date on this file */
4010   if(file_utime(conn, fsp->fsp_name, &unix_times)) {
4011     END_PROFILE(SMBsetattrE);
4012     return ERROR_DOS(ERRDOS,ERRnoaccess);
4013   }
4014   
4015   DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
4016             fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
4017
4018   END_PROFILE(SMBsetattrE);
4019   return(outsize);
4020 }
4021
4022
4023 /* Back from the dead for OS/2..... JRA. */
4024
4025 /****************************************************************************
4026  Reply to a SMBwritebmpx (write block multiplex primary) request.
4027 ****************************************************************************/
4028
4029 int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4030 {
4031         size_t numtowrite;
4032         ssize_t nwritten = -1;
4033         int outsize = 0;
4034         SMB_OFF_T startpos;
4035         size_t tcount;
4036         BOOL write_through;
4037         int smb_doff;
4038         char *data;
4039         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4040         START_PROFILE(SMBwriteBmpx);
4041
4042         CHECK_FSP(fsp,conn);
4043         CHECK_WRITE(fsp);
4044         CHECK_ERROR(fsp);
4045
4046         tcount = SVAL(inbuf,smb_vwv1);
4047         startpos = IVAL(inbuf,smb_vwv3);
4048         write_through = BITSETW(inbuf+smb_vwv7,0);
4049         numtowrite = SVAL(inbuf,smb_vwv10);
4050         smb_doff = SVAL(inbuf,smb_vwv11);
4051
4052         data = smb_base(inbuf) + smb_doff;
4053
4054         /* If this fails we need to send an SMBwriteC response,
4055                 not an SMBwritebmpx - set this up now so we don't forget */
4056         SCVAL(outbuf,smb_com,SMBwritec);
4057
4058         if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
4059                 END_PROFILE(SMBwriteBmpx);
4060                 return(ERROR_DOS(ERRDOS,ERRlock));
4061         }
4062
4063         nwritten = write_file(fsp,data,startpos,numtowrite);
4064
4065         if(lp_syncalways(SNUM(conn)) || write_through)
4066                 sync_file(conn,fsp);
4067   
4068         if(nwritten < (ssize_t)numtowrite) {
4069                 END_PROFILE(SMBwriteBmpx);
4070                 return(UNIXERROR(ERRHRD,ERRdiskfull));
4071         }
4072
4073         /* If the maximum to be written to this file
4074                 is greater than what we just wrote then set
4075                 up a secondary struct to be attached to this
4076                 fd, we will use this to cache error messages etc. */
4077
4078         if((ssize_t)tcount > nwritten) {
4079                 write_bmpx_struct *wbms;
4080                 if(fsp->wbmpx_ptr != NULL)
4081                         wbms = fsp->wbmpx_ptr; /* Use an existing struct */
4082                 else
4083                         wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
4084                 if(!wbms) {
4085                         DEBUG(0,("Out of memory in reply_readmpx\n"));
4086                         END_PROFILE(SMBwriteBmpx);
4087                         return(ERROR_DOS(ERRSRV,ERRnoresource));
4088                 }
4089                 wbms->wr_mode = write_through;
4090                 wbms->wr_discard = False; /* No errors yet */
4091                 wbms->wr_total_written = nwritten;
4092                 wbms->wr_errclass = 0;
4093                 wbms->wr_error = 0;
4094                 fsp->wbmpx_ptr = wbms;
4095         }
4096
4097         /* We are returning successfully, set the message type back to
4098                 SMBwritebmpx */
4099         SCVAL(outbuf,smb_com,SMBwriteBmpx);
4100   
4101         outsize = set_message(outbuf,1,0,True);
4102   
4103         SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
4104   
4105         DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
4106                         fsp->fnum, (int)numtowrite, (int)nwritten ) );
4107
4108         if (write_through && tcount==nwritten) {
4109                 /* We need to send both a primary and a secondary response */
4110                 smb_setlen(outbuf,outsize - 4);
4111                 if (!send_smb(smbd_server_fd(),outbuf))
4112                         exit_server("reply_writebmpx: send_smb failed.");
4113
4114                 /* Now the secondary */
4115                 outsize = set_message(outbuf,1,0,True);
4116                 SCVAL(outbuf,smb_com,SMBwritec);
4117                 SSVAL(outbuf,smb_vwv0,nwritten);
4118         }
4119
4120         END_PROFILE(SMBwriteBmpx);
4121         return(outsize);
4122 }
4123
4124 /****************************************************************************
4125  Reply to a SMBwritebs (write block multiplex secondary) request.
4126 ****************************************************************************/
4127
4128 int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4129 {
4130         size_t numtowrite;
4131         ssize_t nwritten = -1;
4132         int outsize = 0;
4133         SMB_OFF_T startpos;
4134         size_t tcount;
4135         BOOL write_through;
4136         int smb_doff;
4137         char *data;
4138         write_bmpx_struct *wbms;
4139         BOOL send_response = False; 
4140         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4141         START_PROFILE(SMBwriteBs);
4142
4143         CHECK_FSP(fsp,conn);
4144         CHECK_WRITE(fsp);
4145
4146         tcount = SVAL(inbuf,smb_vwv1);
4147         startpos = IVAL(inbuf,smb_vwv2);
4148         numtowrite = SVAL(inbuf,smb_vwv6);
4149         smb_doff = SVAL(inbuf,smb_vwv7);
4150
4151         data = smb_base(inbuf) + smb_doff;
4152
4153         /* We need to send an SMBwriteC response, not an SMBwritebs */
4154         SCVAL(outbuf,smb_com,SMBwritec);
4155
4156         /* This fd should have an auxiliary struct attached,
4157                 check that it does */
4158         wbms = fsp->wbmpx_ptr;
4159         if(!wbms) {
4160                 END_PROFILE(SMBwriteBs);
4161                 return(-1);
4162         }
4163
4164         /* If write through is set we can return errors, else we must cache them */
4165         write_through = wbms->wr_mode;
4166
4167         /* Check for an earlier error */
4168         if(wbms->wr_discard) {
4169                 END_PROFILE(SMBwriteBs);
4170                 return -1; /* Just discard the packet */
4171         }
4172
4173         nwritten = write_file(fsp,data,startpos,numtowrite);
4174
4175         if(lp_syncalways(SNUM(conn)) || write_through)
4176                 sync_file(conn,fsp);
4177   
4178         if (nwritten < (ssize_t)numtowrite) {
4179                 if(write_through) {
4180                         /* We are returning an error - we can delete the aux struct */
4181                         if (wbms)
4182                                 free((char *)wbms);
4183                         fsp->wbmpx_ptr = NULL;
4184                         END_PROFILE(SMBwriteBs);
4185                         return(ERROR_DOS(ERRHRD,ERRdiskfull));
4186                 }
4187                 END_PROFILE(SMBwriteBs);
4188                 return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
4189         }
4190
4191         /* Increment the total written, if this matches tcount
4192                 we can discard the auxiliary struct (hurrah !) and return a writeC */
4193         wbms->wr_total_written += nwritten;
4194         if(wbms->wr_total_written >= tcount) {
4195                 if (write_through) {
4196                         outsize = set_message(outbuf,1,0,True);
4197                         SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
4198                         send_response = True;
4199                 }
4200
4201                 free((char *)wbms);
4202                 fsp->wbmpx_ptr = NULL;
4203         }
4204
4205         if(send_response) {
4206                 END_PROFILE(SMBwriteBs);
4207                 return(outsize);
4208         }
4209
4210         END_PROFILE(SMBwriteBs);
4211         return(-1);
4212 }
4213
4214 /****************************************************************************
4215  Reply to a SMBgetattrE.
4216 ****************************************************************************/
4217
4218 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4219 {
4220   SMB_STRUCT_STAT sbuf;
4221   int outsize = 0;
4222   int mode;
4223   files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4224   START_PROFILE(SMBgetattrE);
4225
4226   outsize = set_message(outbuf,11,0,True);
4227
4228   CHECK_FSP(fsp,conn);
4229
4230   /* Do an fstat on this file */
4231   if(vfs_fstat(fsp,fsp->fd, &sbuf)) {
4232     END_PROFILE(SMBgetattrE);
4233     return(UNIXERROR(ERRDOS,ERRnoaccess));
4234   }
4235   
4236   mode = dos_mode(conn,fsp->fsp_name,&sbuf);
4237   
4238   /* Convert the times into dos times. Set create
4239      date to be last modify date as UNIX doesn't save
4240      this */
4241   put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
4242   put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
4243   put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
4244   if (mode & aDIR)
4245     {
4246       SIVAL(outbuf,smb_vwv6,0);
4247       SIVAL(outbuf,smb_vwv8,0);
4248     }
4249   else
4250     {
4251       SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
4252       SIVAL(outbuf,smb_vwv8,SMB_ROUNDUP(sbuf.st_size,1024));
4253     }
4254   SSVAL(outbuf,smb_vwv10, mode);
4255   
4256   DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
4257   
4258   END_PROFILE(SMBgetattrE);
4259   return(outsize);
4260 }