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