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