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