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