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