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