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