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