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