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