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