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