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