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