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