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