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