smbd: implement the strange write time update logic
[Samba.git] / source / smbd / reply.c
blob411eb98ac5b1e509bf92cd813c75b06eef8ac166
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
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.
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.
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/>.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
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;
35 extern struct current_user current_user;
36 extern bool global_encrypted_passwords_negotiated;
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 ****************************************************************************/
46 /* Custom version for processing POSIX paths. */
47 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
49 static NTSTATUS check_path_syntax_internal(char *path,
50 bool posix_path,
51 bool *p_last_component_contains_wcard)
53 char *d = path;
54 const char *s = path;
55 NTSTATUS ret = NT_STATUS_OK;
56 bool start_of_name_component = True;
58 *p_last_component_contains_wcard = False;
60 while (*s) {
61 if (IS_PATH_SEP(*s,posix_path)) {
63 * Safe to assume is not the second part of a mb char
64 * as this is handled below.
66 /* Eat multiple '/' or '\\' */
67 while (IS_PATH_SEP(*s,posix_path)) {
68 s++;
70 if ((d != path) && (*s != '\0')) {
71 /* We only care about non-leading or trailing '/' or '\\' */
72 *d++ = '/';
75 start_of_name_component = True;
76 /* New component. */
77 *p_last_component_contains_wcard = False;
78 continue;
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" ! */
86 * No mb char starts with '.' so we're safe checking the directory separator here.
89 /* If we just added a '/' - delete it */
90 if ((d > path) && (*(d-1) == '/')) {
91 *(d-1) = '\0';
92 d--;
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;
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;
108 s += 2; /* Else go past the .. */
109 /* We're still at the start of a name component, just the previous one. */
110 continue;
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;
122 if (!(*s & 0x80)) {
123 if (!posix_path) {
124 if (*s <= 0x1f) {
125 return NT_STATUS_OBJECT_NAME_INVALID;
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;
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;
166 start_of_name_component = False;
169 *d = '\0';
171 return ret;
174 /****************************************************************************
175 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
176 No wildcards allowed.
177 ****************************************************************************/
179 NTSTATUS check_path_syntax(char *path)
181 bool ignore;
182 return check_path_syntax_internal(path, False, &ignore);
185 /****************************************************************************
186 Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
187 Wildcards allowed - p_contains_wcard returns true if the last component contained
188 a wildcard.
189 ****************************************************************************/
191 NTSTATUS check_path_syntax_wcard(char *path, bool *p_contains_wcard)
193 return check_path_syntax_internal(path, False, p_contains_wcard);
196 /****************************************************************************
197 Check the path for a POSIX client.
198 We're assuming here that '/' is not the second byte in any multibyte char
199 set (a safe assumption).
200 ****************************************************************************/
202 NTSTATUS check_path_syntax_posix(char *path)
204 bool ignore;
205 return check_path_syntax_internal(path, True, &ignore);
208 /****************************************************************************
209 Pull a string and check the path allowing a wilcard - provide for error return.
210 ****************************************************************************/
212 size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
213 const char *inbuf,
214 uint16 smb_flags2,
215 char **pp_dest,
216 const char *src,
217 size_t src_len,
218 int flags,
219 NTSTATUS *err,
220 bool *contains_wcard)
222 size_t ret;
224 *pp_dest = NULL;
226 if (src_len == 0) {
227 ret = srvstr_pull_buf_talloc(ctx,
228 inbuf,
229 smb_flags2,
230 pp_dest,
231 src,
232 flags);
233 } else {
234 ret = srvstr_pull_talloc(ctx,
235 inbuf,
236 smb_flags2,
237 pp_dest,
238 src,
239 src_len,
240 flags);
243 if (!*pp_dest) {
244 *err = NT_STATUS_INVALID_PARAMETER;
245 return ret;
248 *contains_wcard = False;
250 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
252 * For a DFS path the function parse_dfs_path()
253 * will do the path processing, just make a copy.
255 *err = NT_STATUS_OK;
256 return ret;
259 if (lp_posix_pathnames()) {
260 *err = check_path_syntax_posix(*pp_dest);
261 } else {
262 *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
265 return ret;
268 /****************************************************************************
269 Pull a string and check the path - provide for error return.
270 ****************************************************************************/
272 size_t srvstr_get_path(TALLOC_CTX *ctx,
273 const char *inbuf,
274 uint16 smb_flags2,
275 char **pp_dest,
276 const char *src,
277 size_t src_len,
278 int flags,
279 NTSTATUS *err)
281 size_t ret;
283 *pp_dest = NULL;
285 if (src_len == 0) {
286 ret = srvstr_pull_buf_talloc(ctx,
287 inbuf,
288 smb_flags2,
289 pp_dest,
290 src,
291 flags);
292 } else {
293 ret = srvstr_pull_talloc(ctx,
294 inbuf,
295 smb_flags2,
296 pp_dest,
297 src,
298 src_len,
299 flags);
302 if (!*pp_dest) {
303 *err = NT_STATUS_INVALID_PARAMETER;
304 return ret;
307 if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
309 * For a DFS path the function parse_dfs_path()
310 * will do the path processing, just make a copy.
312 *err = NT_STATUS_OK;
313 return ret;
316 if (lp_posix_pathnames()) {
317 *err = check_path_syntax_posix(*pp_dest);
318 } else {
319 *err = check_path_syntax(*pp_dest);
322 return ret;
325 /****************************************************************************
326 Check if we have a correct fsp pointing to a file. Basic check for open fsp.
327 ****************************************************************************/
329 bool check_fsp_open(connection_struct *conn, struct smb_request *req,
330 files_struct *fsp, struct current_user *user)
332 if (!(fsp) || !(conn)) {
333 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
334 return False;
336 if (((conn) != (fsp)->conn) || user->vuid != (fsp)->vuid) {
337 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
338 return False;
340 return True;
343 /****************************************************************************
344 Check if we have a correct fsp pointing to a file. Replacement for the
345 CHECK_FSP macro.
346 ****************************************************************************/
348 bool check_fsp(connection_struct *conn, struct smb_request *req,
349 files_struct *fsp, struct current_user *user)
351 if (!check_fsp_open(conn, req, fsp, user)) {
352 return False;
354 if ((fsp)->is_directory) {
355 reply_nterror(req, NT_STATUS_INVALID_DEVICE_REQUEST);
356 return False;
358 if ((fsp)->fh->fd == -1) {
359 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
360 return False;
362 (fsp)->num_smb_operations++;
363 return True;
366 /****************************************************************************
367 Check if we have a correct fsp. Replacement for the FSP_BELONGS_CONN macro
368 ****************************************************************************/
370 bool fsp_belongs_conn(connection_struct *conn, struct smb_request *req,
371 files_struct *fsp, struct current_user *user)
373 if ((fsp) && (conn) && ((conn)==(fsp)->conn)
374 && (current_user.vuid==(fsp)->vuid)) {
375 return True;
378 reply_nterror(req, NT_STATUS_INVALID_HANDLE);
379 return False;
382 /****************************************************************************
383 Reply to a (netbios-level) special message.
384 ****************************************************************************/
386 void reply_special(char *inbuf)
388 int msg_type = CVAL(inbuf,0);
389 int msg_flags = CVAL(inbuf,1);
390 fstring name1,name2;
391 char name_type = 0;
394 * We only really use 4 bytes of the outbuf, but for the smb_setlen
395 * calculation & friends (srv_send_smb uses that) we need the full smb
396 * header.
398 char outbuf[smb_size];
400 static bool already_got_session = False;
402 *name1 = *name2 = 0;
404 memset(outbuf, '\0', sizeof(outbuf));
406 smb_setlen(outbuf,0);
408 switch (msg_type) {
409 case 0x81: /* session request */
411 if (already_got_session) {
412 exit_server_cleanly("multiple session request not permitted");
415 SCVAL(outbuf,0,0x82);
416 SCVAL(outbuf,3,0);
417 if (name_len(inbuf+4) > 50 ||
418 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
419 DEBUG(0,("Invalid name length in session request\n"));
420 return;
422 name_extract(inbuf,4,name1);
423 name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
424 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
425 name1,name2));
427 set_local_machine_name(name1, True);
428 set_remote_machine_name(name2, True);
430 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
431 get_local_machine_name(), get_remote_machine_name(),
432 name_type));
434 if (name_type == 'R') {
435 /* We are being asked for a pathworks session ---
436 no thanks! */
437 SCVAL(outbuf, 0,0x83);
438 break;
441 /* only add the client's machine name to the list
442 of possibly valid usernames if we are operating
443 in share mode security */
444 if (lp_security() == SEC_SHARE) {
445 add_session_user(get_remote_machine_name());
448 reload_services(True);
449 reopen_logs();
451 already_got_session = True;
452 break;
454 case 0x89: /* session keepalive request
455 (some old clients produce this?) */
456 SCVAL(outbuf,0,SMBkeepalive);
457 SCVAL(outbuf,3,0);
458 break;
460 case 0x82: /* positive session response */
461 case 0x83: /* negative session response */
462 case 0x84: /* retarget session response */
463 DEBUG(0,("Unexpected session response\n"));
464 break;
466 case SMBkeepalive: /* session keepalive */
467 default:
468 return;
471 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
472 msg_type, msg_flags));
474 srv_send_smb(smbd_server_fd(), outbuf, false);
475 return;
478 /****************************************************************************
479 Reply to a tcon.
480 conn POINTER CAN BE NULL HERE !
481 ****************************************************************************/
483 void reply_tcon(struct smb_request *req)
485 connection_struct *conn = req->conn;
486 const char *service;
487 char *service_buf = NULL;
488 char *password = NULL;
489 char *dev = NULL;
490 int pwlen=0;
491 NTSTATUS nt_status;
492 char *p;
493 DATA_BLOB password_blob;
494 TALLOC_CTX *ctx = talloc_tos();
496 START_PROFILE(SMBtcon);
498 if (smb_buflen(req->inbuf) < 4) {
499 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
500 END_PROFILE(SMBtcon);
501 return;
504 p = smb_buf(req->inbuf)+1;
505 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
506 &service_buf, p, STR_TERMINATE) + 1;
507 pwlen = srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
508 &password, p, STR_TERMINATE) + 1;
509 p += pwlen;
510 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2,
511 &dev, p, STR_TERMINATE) + 1;
513 if (service_buf == NULL || password == NULL || dev == NULL) {
514 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
515 END_PROFILE(SMBtcon);
516 return;
518 p = strrchr_m(service_buf,'\\');
519 if (p) {
520 service = p+1;
521 } else {
522 service = service_buf;
525 password_blob = data_blob(password, pwlen+1);
527 conn = make_connection(service,password_blob,dev,req->vuid,&nt_status);
528 req->conn = conn;
530 data_blob_clear_free(&password_blob);
532 if (!conn) {
533 reply_nterror(req, nt_status);
534 END_PROFILE(SMBtcon);
535 return;
538 reply_outbuf(req, 2, 0);
539 SSVAL(req->outbuf,smb_vwv0,max_recv);
540 SSVAL(req->outbuf,smb_vwv1,conn->cnum);
541 SSVAL(req->outbuf,smb_tid,conn->cnum);
543 DEBUG(3,("tcon service=%s cnum=%d\n",
544 service, conn->cnum));
546 END_PROFILE(SMBtcon);
547 return;
550 /****************************************************************************
551 Reply to a tcon and X.
552 conn POINTER CAN BE NULL HERE !
553 ****************************************************************************/
555 void reply_tcon_and_X(struct smb_request *req)
557 connection_struct *conn = req->conn;
558 char *service = NULL;
559 DATA_BLOB password;
560 TALLOC_CTX *ctx = talloc_tos();
561 /* what the cleint thinks the device is */
562 char *client_devicetype = NULL;
563 /* what the server tells the client the share represents */
564 const char *server_devicetype;
565 NTSTATUS nt_status;
566 int passlen;
567 char *path = NULL;
568 char *p, *q;
569 uint16 tcon_flags;
571 START_PROFILE(SMBtconX);
573 if (req->wct < 4) {
574 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
575 END_PROFILE(SMBtconX);
576 return;
579 passlen = SVAL(req->inbuf,smb_vwv3);
580 tcon_flags = SVAL(req->inbuf,smb_vwv2);
582 /* we might have to close an old one */
583 if ((tcon_flags & 0x1) && conn) {
584 close_cnum(conn,req->vuid);
585 req->conn = NULL;
586 conn = NULL;
589 if ((passlen > MAX_PASS_LEN) || (passlen >= smb_buflen(req->inbuf))) {
590 reply_doserror(req, ERRDOS, ERRbuftoosmall);
591 END_PROFILE(SMBtconX);
592 return;
595 if (global_encrypted_passwords_negotiated) {
596 password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
597 passlen);
598 if (lp_security() == SEC_SHARE) {
600 * Security = share always has a pad byte
601 * after the password.
603 p = smb_buf(req->inbuf) + passlen + 1;
604 } else {
605 p = smb_buf(req->inbuf) + passlen;
607 } else {
608 password = data_blob_talloc(talloc_tos(), smb_buf(req->inbuf),
609 passlen+1);
610 /* Ensure correct termination */
611 password.data[passlen]=0;
612 p = smb_buf(req->inbuf) + passlen + 1;
615 p += srvstr_pull_buf_talloc(ctx, req->inbuf, req->flags2, &path, p,
616 STR_TERMINATE);
618 if (path == NULL) {
619 data_blob_clear_free(&password);
620 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
621 END_PROFILE(SMBtconX);
622 return;
626 * the service name can be either: \\server\share
627 * or share directly like on the DELL PowerVault 705
629 if (*path=='\\') {
630 q = strchr_m(path+2,'\\');
631 if (!q) {
632 data_blob_clear_free(&password);
633 reply_doserror(req, ERRDOS, ERRnosuchshare);
634 END_PROFILE(SMBtconX);
635 return;
637 service = q+1;
638 } else {
639 service = path;
642 p += srvstr_pull_talloc(ctx, req->inbuf, req->flags2,
643 &client_devicetype, p,
644 MIN(6,smb_bufrem(req->inbuf, p)), STR_ASCII);
646 if (client_devicetype == NULL) {
647 data_blob_clear_free(&password);
648 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
649 END_PROFILE(SMBtconX);
650 return;
653 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
655 conn = make_connection(service, password, client_devicetype,
656 req->vuid, &nt_status);
657 req->conn =conn;
659 data_blob_clear_free(&password);
661 if (!conn) {
662 reply_nterror(req, nt_status);
663 END_PROFILE(SMBtconX);
664 return;
667 if ( IS_IPC(conn) )
668 server_devicetype = "IPC";
669 else if ( IS_PRINT(conn) )
670 server_devicetype = "LPT1:";
671 else
672 server_devicetype = "A:";
674 if (Protocol < PROTOCOL_NT1) {
675 reply_outbuf(req, 2, 0);
676 if (message_push_string(&req->outbuf, server_devicetype,
677 STR_TERMINATE|STR_ASCII) == -1) {
678 reply_nterror(req, NT_STATUS_NO_MEMORY);
679 END_PROFILE(SMBtconX);
680 return;
682 } else {
683 /* NT sets the fstype of IPC$ to the null string */
684 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
686 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
687 /* Return permissions. */
688 uint32 perm1 = 0;
689 uint32 perm2 = 0;
691 reply_outbuf(req, 7, 0);
693 if (IS_IPC(conn)) {
694 perm1 = FILE_ALL_ACCESS;
695 perm2 = FILE_ALL_ACCESS;
696 } else {
697 perm1 = CAN_WRITE(conn) ?
698 SHARE_ALL_ACCESS :
699 SHARE_READ_ONLY;
702 SIVAL(req->outbuf, smb_vwv3, perm1);
703 SIVAL(req->outbuf, smb_vwv5, perm2);
704 } else {
705 reply_outbuf(req, 3, 0);
708 if ((message_push_string(&req->outbuf, server_devicetype,
709 STR_TERMINATE|STR_ASCII) == -1)
710 || (message_push_string(&req->outbuf, fstype,
711 STR_TERMINATE) == -1)) {
712 reply_nterror(req, NT_STATUS_NO_MEMORY);
713 END_PROFILE(SMBtconX);
714 return;
717 /* what does setting this bit do? It is set by NT4 and
718 may affect the ability to autorun mounted cdroms */
719 SSVAL(req->outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
720 (lp_csc_policy(SNUM(conn)) << 2));
722 init_dfsroot(conn, req->inbuf, req->outbuf);
726 DEBUG(3,("tconX service=%s \n",
727 service));
729 /* set the incoming and outgoing tid to the just created one */
730 SSVAL(req->inbuf,smb_tid,conn->cnum);
731 SSVAL(req->outbuf,smb_tid,conn->cnum);
733 END_PROFILE(SMBtconX);
735 chain_reply(req);
736 return;
739 /****************************************************************************
740 Reply to an unknown type.
741 ****************************************************************************/
743 void reply_unknown_new(struct smb_request *req, uint8 type)
745 DEBUG(0, ("unknown command type (%s): type=%d (0x%X)\n",
746 smb_fn_name(type), type, type));
747 reply_doserror(req, ERRSRV, ERRunknownsmb);
748 return;
751 /****************************************************************************
752 Reply to an ioctl.
753 conn POINTER CAN BE NULL HERE !
754 ****************************************************************************/
756 void reply_ioctl(struct smb_request *req)
758 connection_struct *conn = req->conn;
759 uint16 device;
760 uint16 function;
761 uint32 ioctl_code;
762 int replysize;
763 char *p;
765 START_PROFILE(SMBioctl);
767 if (req->wct < 3) {
768 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
769 END_PROFILE(SMBioctl);
770 return;
773 device = SVAL(req->inbuf,smb_vwv1);
774 function = SVAL(req->inbuf,smb_vwv2);
775 ioctl_code = (device << 16) + function;
777 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
779 switch (ioctl_code) {
780 case IOCTL_QUERY_JOB_INFO:
781 replysize = 32;
782 break;
783 default:
784 reply_doserror(req, ERRSRV, ERRnosupport);
785 END_PROFILE(SMBioctl);
786 return;
789 reply_outbuf(req, 8, replysize+1);
790 SSVAL(req->outbuf,smb_vwv1,replysize); /* Total data bytes returned */
791 SSVAL(req->outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
792 SSVAL(req->outbuf,smb_vwv6,52); /* Offset to data */
793 p = smb_buf(req->outbuf);
794 memset(p, '\0', replysize+1); /* valgrind-safe. */
795 p += 1; /* Allow for alignment */
797 switch (ioctl_code) {
798 case IOCTL_QUERY_JOB_INFO:
800 files_struct *fsp = file_fsp(SVAL(req->inbuf,
801 smb_vwv0));
802 if (!fsp) {
803 reply_doserror(req, ERRDOS, ERRbadfid);
804 END_PROFILE(SMBioctl);
805 return;
807 SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
808 srvstr_push((char *)req->outbuf, req->flags2, p+2,
809 global_myname(), 15,
810 STR_TERMINATE|STR_ASCII);
811 if (conn) {
812 srvstr_push((char *)req->outbuf, req->flags2,
813 p+18, lp_servicename(SNUM(conn)),
814 13, STR_TERMINATE|STR_ASCII);
815 } else {
816 memset(p+18, 0, 13);
818 break;
822 END_PROFILE(SMBioctl);
823 return;
826 /****************************************************************************
827 Strange checkpath NTSTATUS mapping.
828 ****************************************************************************/
830 static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status)
832 /* Strange DOS error code semantics only for checkpath... */
833 if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
834 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
835 /* We need to map to ERRbadpath */
836 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
839 return status;
842 /****************************************************************************
843 Reply to a checkpath.
844 ****************************************************************************/
846 void reply_checkpath(struct smb_request *req)
848 connection_struct *conn = req->conn;
849 char *name = NULL;
850 SMB_STRUCT_STAT sbuf;
851 NTSTATUS status;
852 TALLOC_CTX *ctx = talloc_tos();
854 START_PROFILE(SMBcheckpath);
856 srvstr_get_path(ctx,(char *)req->inbuf, req->flags2, &name,
857 smb_buf(req->inbuf) + 1, 0,
858 STR_TERMINATE, &status);
859 if (!NT_STATUS_IS_OK(status)) {
860 status = map_checkpath_error((char *)req->inbuf, status);
861 reply_nterror(req, status);
862 END_PROFILE(SMBcheckpath);
863 return;
866 status = resolve_dfspath(ctx, conn,
867 req->flags2 & FLAGS2_DFS_PATHNAMES,
868 name,
869 &name);
870 if (!NT_STATUS_IS_OK(status)) {
871 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
872 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
873 ERRSRV, ERRbadpath);
874 END_PROFILE(SMBcheckpath);
875 return;
877 goto path_err;
880 DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(req->inbuf,smb_vwv0)));
882 status = unix_convert(ctx, conn, name, False, &name, NULL, &sbuf);
883 if (!NT_STATUS_IS_OK(status)) {
884 goto path_err;
887 status = check_name(conn, name);
888 if (!NT_STATUS_IS_OK(status)) {
889 DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status)));
890 goto path_err;
893 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
894 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
895 status = map_nt_error_from_unix(errno);
896 goto path_err;
899 if (!S_ISDIR(sbuf.st_mode)) {
900 reply_botherror(req, NT_STATUS_NOT_A_DIRECTORY,
901 ERRDOS, ERRbadpath);
902 END_PROFILE(SMBcheckpath);
903 return;
906 reply_outbuf(req, 0, 0);
908 END_PROFILE(SMBcheckpath);
909 return;
911 path_err:
913 END_PROFILE(SMBcheckpath);
915 /* We special case this - as when a Windows machine
916 is parsing a path is steps through the components
917 one at a time - if a component fails it expects
918 ERRbadpath, not ERRbadfile.
920 status = map_checkpath_error((char *)req->inbuf, status);
921 if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
923 * Windows returns different error codes if
924 * the parent directory is valid but not the
925 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
926 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
927 * if the path is invalid.
929 reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND,
930 ERRDOS, ERRbadpath);
931 return;
934 reply_nterror(req, status);
937 /****************************************************************************
938 Reply to a getatr.
939 ****************************************************************************/
941 void reply_getatr(struct smb_request *req)
943 connection_struct *conn = req->conn;
944 char *fname = NULL;
945 SMB_STRUCT_STAT sbuf;
946 int mode=0;
947 SMB_OFF_T size=0;
948 time_t mtime=0;
949 char *p;
950 NTSTATUS status;
951 TALLOC_CTX *ctx = talloc_tos();
953 START_PROFILE(SMBgetatr);
955 p = smb_buf(req->inbuf) + 1;
956 p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
957 0, STR_TERMINATE, &status);
958 if (!NT_STATUS_IS_OK(status)) {
959 reply_nterror(req, status);
960 END_PROFILE(SMBgetatr);
961 return;
964 status = resolve_dfspath(ctx, conn,
965 req->flags2 & FLAGS2_DFS_PATHNAMES,
966 fname,
967 &fname);
968 if (!NT_STATUS_IS_OK(status)) {
969 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
970 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
971 ERRSRV, ERRbadpath);
972 END_PROFILE(SMBgetatr);
973 return;
975 reply_nterror(req, status);
976 END_PROFILE(SMBgetatr);
977 return;
980 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
981 under WfWg - weird! */
982 if (*fname == '\0') {
983 mode = aHIDDEN | aDIR;
984 if (!CAN_WRITE(conn)) {
985 mode |= aRONLY;
987 size = 0;
988 mtime = 0;
989 } else {
990 status = unix_convert(ctx, conn, fname, False, &fname, NULL,&sbuf);
991 if (!NT_STATUS_IS_OK(status)) {
992 reply_nterror(req, status);
993 END_PROFILE(SMBgetatr);
994 return;
996 status = check_name(conn, fname);
997 if (!NT_STATUS_IS_OK(status)) {
998 DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
999 reply_nterror(req, status);
1000 END_PROFILE(SMBgetatr);
1001 return;
1003 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
1004 DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
1005 reply_unixerror(req, ERRDOS,ERRbadfile);
1006 END_PROFILE(SMBgetatr);
1007 return;
1010 mode = dos_mode(conn,fname,&sbuf);
1011 size = sbuf.st_size;
1012 mtime = sbuf.st_mtime;
1013 if (mode & aDIR) {
1014 size = 0;
1018 reply_outbuf(req, 10, 0);
1020 SSVAL(req->outbuf,smb_vwv0,mode);
1021 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1022 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime & ~1);
1023 } else {
1024 srv_put_dos_date3((char *)req->outbuf,smb_vwv1,mtime);
1026 SIVAL(req->outbuf,smb_vwv3,(uint32)size);
1028 if (Protocol >= PROTOCOL_NT1) {
1029 SSVAL(req->outbuf, smb_flg2,
1030 SVAL(req->outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
1033 DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
1035 END_PROFILE(SMBgetatr);
1036 return;
1039 /****************************************************************************
1040 Reply to a setatr.
1041 ****************************************************************************/
1043 void reply_setatr(struct smb_request *req)
1045 struct timespec ts[2];
1046 connection_struct *conn = req->conn;
1047 char *fname = NULL;
1048 int mode;
1049 time_t mtime;
1050 SMB_STRUCT_STAT sbuf;
1051 char *p;
1052 NTSTATUS status;
1053 TALLOC_CTX *ctx = talloc_tos();
1055 START_PROFILE(SMBsetatr);
1057 ZERO_STRUCT(ts);
1059 if (req->wct < 2) {
1060 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1061 return;
1064 p = smb_buf(req->inbuf) + 1;
1065 p += srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname, p,
1066 0, STR_TERMINATE, &status);
1067 if (!NT_STATUS_IS_OK(status)) {
1068 reply_nterror(req, status);
1069 END_PROFILE(SMBsetatr);
1070 return;
1073 status = resolve_dfspath(ctx, conn,
1074 req->flags2 & FLAGS2_DFS_PATHNAMES,
1075 fname,
1076 &fname);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
1079 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1080 ERRSRV, ERRbadpath);
1081 END_PROFILE(SMBsetatr);
1082 return;
1084 reply_nterror(req, status);
1085 END_PROFILE(SMBsetatr);
1086 return;
1089 status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 reply_nterror(req, status);
1092 END_PROFILE(SMBsetatr);
1093 return;
1096 status = check_name(conn, fname);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 reply_nterror(req, status);
1099 END_PROFILE(SMBsetatr);
1100 return;
1103 if (fname[0] == '.' && fname[1] == '\0') {
1105 * Not sure here is the right place to catch this
1106 * condition. Might be moved to somewhere else later -- vl
1108 reply_nterror(req, NT_STATUS_ACCESS_DENIED);
1109 END_PROFILE(SMBsetatr);
1110 return;
1113 mode = SVAL(req->inbuf,smb_vwv0);
1114 mtime = srv_make_unix_date3(req->inbuf+smb_vwv1);
1116 ts[1] = convert_time_t_to_timespec(mtime);
1117 status = smb_set_file_time(conn, NULL, fname,
1118 &sbuf, ts, true);
1119 if (!NT_STATUS_IS_OK(status)) {
1120 reply_unixerror(req, ERRDOS, ERRnoaccess);
1121 END_PROFILE(SMBsetatr);
1122 return;
1125 if (mode != FILE_ATTRIBUTE_NORMAL) {
1126 if (VALID_STAT_OF_DIR(sbuf))
1127 mode |= aDIR;
1128 else
1129 mode &= ~aDIR;
1131 if (file_set_dosmode(conn,fname,mode,&sbuf,NULL,false) != 0) {
1132 reply_unixerror(req, ERRDOS, ERRnoaccess);
1133 END_PROFILE(SMBsetatr);
1134 return;
1138 reply_outbuf(req, 0, 0);
1140 DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
1142 END_PROFILE(SMBsetatr);
1143 return;
1146 /****************************************************************************
1147 Reply to a dskattr.
1148 ****************************************************************************/
1150 void reply_dskattr(struct smb_request *req)
1152 connection_struct *conn = req->conn;
1153 SMB_BIG_UINT dfree,dsize,bsize;
1154 START_PROFILE(SMBdskattr);
1156 if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
1157 reply_unixerror(req, ERRHRD, ERRgeneral);
1158 END_PROFILE(SMBdskattr);
1159 return;
1162 reply_outbuf(req, 5, 0);
1164 if (Protocol <= PROTOCOL_LANMAN2) {
1165 double total_space, free_space;
1166 /* we need to scale this to a number that DOS6 can handle. We
1167 use floating point so we can handle large drives on systems
1168 that don't have 64 bit integers
1170 we end up displaying a maximum of 2G to DOS systems
1172 total_space = dsize * (double)bsize;
1173 free_space = dfree * (double)bsize;
1175 dsize = (SMB_BIG_UINT)((total_space+63*512) / (64*512));
1176 dfree = (SMB_BIG_UINT)((free_space+63*512) / (64*512));
1178 if (dsize > 0xFFFF) dsize = 0xFFFF;
1179 if (dfree > 0xFFFF) dfree = 0xFFFF;
1181 SSVAL(req->outbuf,smb_vwv0,dsize);
1182 SSVAL(req->outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
1183 SSVAL(req->outbuf,smb_vwv2,512); /* and this must be 512 */
1184 SSVAL(req->outbuf,smb_vwv3,dfree);
1185 } else {
1186 SSVAL(req->outbuf,smb_vwv0,dsize);
1187 SSVAL(req->outbuf,smb_vwv1,bsize/512);
1188 SSVAL(req->outbuf,smb_vwv2,512);
1189 SSVAL(req->outbuf,smb_vwv3,dfree);
1192 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
1194 END_PROFILE(SMBdskattr);
1195 return;
1198 /****************************************************************************
1199 Reply to a search.
1200 Can be called from SMBsearch, SMBffirst or SMBfunique.
1201 ****************************************************************************/
1203 void reply_search(struct smb_request *req)
1205 connection_struct *conn = req->conn;
1206 char *mask = NULL;
1207 char *directory = NULL;
1208 char *fname = NULL;
1209 SMB_OFF_T size;
1210 uint32 mode;
1211 time_t date;
1212 uint32 dirtype;
1213 unsigned int numentries = 0;
1214 unsigned int maxentries = 0;
1215 bool finished = False;
1216 char *p;
1217 int status_len;
1218 char *path = NULL;
1219 char status[21];
1220 int dptr_num= -1;
1221 bool check_descend = False;
1222 bool expect_close = False;
1223 NTSTATUS nt_status;
1224 bool mask_contains_wcard = False;
1225 bool allow_long_path_components = (req->flags2 & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
1226 TALLOC_CTX *ctx = talloc_tos();
1228 START_PROFILE(SMBsearch);
1230 if (req->wct < 2) {
1231 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1232 END_PROFILE(SMBsearch);
1233 return;
1236 if (lp_posix_pathnames()) {
1237 reply_unknown_new(req, CVAL(req->inbuf, smb_com));
1238 END_PROFILE(SMBsearch);
1239 return;
1242 /* If we were called as SMBffirst then we must expect close. */
1243 if(CVAL(req->inbuf,smb_com) == SMBffirst) {
1244 expect_close = True;
1247 reply_outbuf(req, 1, 3);
1248 maxentries = SVAL(req->inbuf,smb_vwv0);
1249 dirtype = SVAL(req->inbuf,smb_vwv1);
1250 p = smb_buf(req->inbuf) + 1;
1251 p += srvstr_get_path_wcard(ctx,
1252 (char *)req->inbuf,
1253 req->flags2,
1254 &path,
1257 STR_TERMINATE,
1258 &nt_status,
1259 &mask_contains_wcard);
1260 if (!NT_STATUS_IS_OK(nt_status)) {
1261 reply_nterror(req, nt_status);
1262 END_PROFILE(SMBsearch);
1263 return;
1266 nt_status = resolve_dfspath_wcard(ctx, conn,
1267 req->flags2 & FLAGS2_DFS_PATHNAMES,
1268 path,
1269 &path,
1270 &mask_contains_wcard);
1271 if (!NT_STATUS_IS_OK(nt_status)) {
1272 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
1273 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
1274 ERRSRV, ERRbadpath);
1275 END_PROFILE(SMBsearch);
1276 return;
1278 reply_nterror(req, nt_status);
1279 END_PROFILE(SMBsearch);
1280 return;
1283 p++;
1284 status_len = SVAL(p, 0);
1285 p += 2;
1287 /* dirtype &= ~aDIR; */
1289 if (status_len == 0) {
1290 SMB_STRUCT_STAT sbuf;
1292 nt_status = unix_convert(ctx, conn, path, True,
1293 &directory, NULL, &sbuf);
1294 if (!NT_STATUS_IS_OK(nt_status)) {
1295 reply_nterror(req, nt_status);
1296 END_PROFILE(SMBsearch);
1297 return;
1300 nt_status = check_name(conn, directory);
1301 if (!NT_STATUS_IS_OK(nt_status)) {
1302 reply_nterror(req, nt_status);
1303 END_PROFILE(SMBsearch);
1304 return;
1307 p = strrchr_m(directory,'/');
1308 if (!p) {
1309 mask = directory;
1310 directory = talloc_strdup(ctx,".");
1311 if (!directory) {
1312 reply_nterror(req, NT_STATUS_NO_MEMORY);
1313 END_PROFILE(SMBsearch);
1314 return;
1316 } else {
1317 *p = 0;
1318 mask = p+1;
1321 if (*directory == '\0') {
1322 directory = talloc_strdup(ctx,".");
1323 if (!directory) {
1324 reply_nterror(req, NT_STATUS_NO_MEMORY);
1325 END_PROFILE(SMBsearch);
1326 return;
1329 memset((char *)status,'\0',21);
1330 SCVAL(status,0,(dirtype & 0x1F));
1332 nt_status = dptr_create(conn,
1333 directory,
1334 True,
1335 expect_close,
1336 req->smbpid,
1337 mask,
1338 mask_contains_wcard,
1339 dirtype,
1340 &conn->dirptr);
1341 if (!NT_STATUS_IS_OK(nt_status)) {
1342 reply_nterror(req, nt_status);
1343 END_PROFILE(SMBsearch);
1344 return;
1346 dptr_num = dptr_dnum(conn->dirptr);
1347 } else {
1348 int status_dirtype;
1350 memcpy(status,p,21);
1351 status_dirtype = CVAL(status,0) & 0x1F;
1352 if (status_dirtype != (dirtype & 0x1F)) {
1353 dirtype = status_dirtype;
1356 conn->dirptr = dptr_fetch(status+12,&dptr_num);
1357 if (!conn->dirptr) {
1358 goto SearchEmpty;
1360 string_set(&conn->dirpath,dptr_path(dptr_num));
1361 mask = dptr_wcard(dptr_num);
1362 if (!mask) {
1363 goto SearchEmpty;
1366 * For a 'continue' search we have no string. So
1367 * check from the initial saved string.
1369 mask_contains_wcard = ms_has_wild(mask);
1370 dirtype = dptr_attr(dptr_num);
1373 DEBUG(4,("dptr_num is %d\n",dptr_num));
1375 if ((dirtype&0x1F) == aVOLID) {
1376 char buf[DIR_STRUCT_SIZE];
1377 memcpy(buf,status,21);
1378 if (!make_dir_struct(ctx,buf,"???????????",volume_label(SNUM(conn)),
1379 0,aVOLID,0,!allow_long_path_components)) {
1380 reply_nterror(req, NT_STATUS_NO_MEMORY);
1381 END_PROFILE(SMBsearch);
1382 return;
1384 dptr_fill(buf+12,dptr_num);
1385 if (dptr_zero(buf+12) && (status_len==0)) {
1386 numentries = 1;
1387 } else {
1388 numentries = 0;
1390 if (message_push_blob(&req->outbuf,
1391 data_blob_const(buf, sizeof(buf)))
1392 == -1) {
1393 reply_nterror(req, NT_STATUS_NO_MEMORY);
1394 END_PROFILE(SMBsearch);
1395 return;
1397 } else {
1398 unsigned int i;
1399 maxentries = MIN(
1400 maxentries,
1401 ((BUFFER_SIZE -
1402 ((uint8 *)smb_buf(req->outbuf) + 3 - req->outbuf))
1403 /DIR_STRUCT_SIZE));
1405 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
1406 conn->dirpath,lp_dontdescend(SNUM(conn))));
1407 if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True)) {
1408 check_descend = True;
1411 for (i=numentries;(i<maxentries) && !finished;i++) {
1412 finished = !get_dir_entry(ctx,conn,mask,dirtype,&fname,
1413 &size,&mode,&date,check_descend);
1414 if (!finished) {
1415 char buf[DIR_STRUCT_SIZE];
1416 memcpy(buf,status,21);
1417 if (!make_dir_struct(ctx,
1418 buf,
1419 mask,
1420 fname,
1421 size,
1422 mode,
1423 date,
1424 !allow_long_path_components)) {
1425 reply_nterror(req, NT_STATUS_NO_MEMORY);
1426 END_PROFILE(SMBsearch);
1427 return;
1429 if (!dptr_fill(buf+12,dptr_num)) {
1430 break;
1432 if (message_push_blob(&req->outbuf,
1433 data_blob_const(buf, sizeof(buf)))
1434 == -1) {
1435 reply_nterror(req, NT_STATUS_NO_MEMORY);
1436 END_PROFILE(SMBsearch);
1437 return;
1439 numentries++;
1444 SearchEmpty:
1446 /* If we were called as SMBffirst with smb_search_id == NULL
1447 and no entries were found then return error and close dirptr
1448 (X/Open spec) */
1450 if (numentries == 0) {
1451 dptr_close(&dptr_num);
1452 } else if(expect_close && status_len == 0) {
1453 /* Close the dptr - we know it's gone */
1454 dptr_close(&dptr_num);
1457 /* If we were called as SMBfunique, then we can close the dirptr now ! */
1458 if(dptr_num >= 0 && CVAL(req->inbuf,smb_com) == SMBfunique) {
1459 dptr_close(&dptr_num);
1462 if ((numentries == 0) && !mask_contains_wcard) {
1463 reply_botherror(req, STATUS_NO_MORE_FILES, ERRDOS, ERRnofiles);
1464 END_PROFILE(SMBsearch);
1465 return;
1468 SSVAL(req->outbuf,smb_vwv0,numentries);
1469 SSVAL(req->outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
1470 SCVAL(smb_buf(req->outbuf),0,5);
1471 SSVAL(smb_buf(req->outbuf),1,numentries*DIR_STRUCT_SIZE);
1473 /* The replies here are never long name. */
1474 SSVAL(req->outbuf, smb_flg2,
1475 SVAL(req->outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
1476 if (!allow_long_path_components) {
1477 SSVAL(req->outbuf, smb_flg2,
1478 SVAL(req->outbuf, smb_flg2)
1479 & (~FLAGS2_LONG_PATH_COMPONENTS));
1482 /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
1483 SSVAL(req->outbuf, smb_flg2,
1484 (SVAL(req->outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
1486 if (!directory) {
1487 directory = dptr_path(dptr_num);
1490 DEBUG(4,("%s mask=%s path=%s dtype=%d nument=%u of %u\n",
1491 smb_fn_name(CVAL(req->inbuf,smb_com)),
1492 mask,
1493 directory ? directory : "./",
1494 dirtype,
1495 numentries,
1496 maxentries ));
1498 END_PROFILE(SMBsearch);
1499 return;
1502 /****************************************************************************
1503 Reply to a fclose (stop directory search).
1504 ****************************************************************************/
1506 void reply_fclose(struct smb_request *req)
1508 int status_len;
1509 char status[21];
1510 int dptr_num= -2;
1511 char *p;
1512 char *path = NULL;
1513 NTSTATUS err;
1514 bool path_contains_wcard = False;
1515 TALLOC_CTX *ctx = talloc_tos();
1517 START_PROFILE(SMBfclose);
1519 if (lp_posix_pathnames()) {
1520 reply_unknown_new(req, CVAL(req->inbuf, smb_com));
1521 END_PROFILE(SMBfclose);
1522 return;
1525 p = smb_buf(req->inbuf) + 1;
1526 p += srvstr_get_path_wcard(ctx,
1527 (char *)req->inbuf,
1528 req->flags2,
1529 &path,
1532 STR_TERMINATE,
1533 &err,
1534 &path_contains_wcard);
1535 if (!NT_STATUS_IS_OK(err)) {
1536 reply_nterror(req, err);
1537 END_PROFILE(SMBfclose);
1538 return;
1540 p++;
1541 status_len = SVAL(p,0);
1542 p += 2;
1544 if (status_len == 0) {
1545 reply_doserror(req, ERRSRV, ERRsrverror);
1546 END_PROFILE(SMBfclose);
1547 return;
1550 memcpy(status,p,21);
1552 if(dptr_fetch(status+12,&dptr_num)) {
1553 /* Close the dptr - we know it's gone */
1554 dptr_close(&dptr_num);
1557 reply_outbuf(req, 1, 0);
1558 SSVAL(req->outbuf,smb_vwv0,0);
1560 DEBUG(3,("search close\n"));
1562 END_PROFILE(SMBfclose);
1563 return;
1566 /****************************************************************************
1567 Reply to an open.
1568 ****************************************************************************/
1570 void reply_open(struct smb_request *req)
1572 connection_struct *conn = req->conn;
1573 char *fname = NULL;
1574 uint32 fattr=0;
1575 SMB_OFF_T size = 0;
1576 time_t mtime=0;
1577 int info;
1578 SMB_STRUCT_STAT sbuf;
1579 files_struct *fsp;
1580 int oplock_request;
1581 int deny_mode;
1582 uint32 dos_attr;
1583 uint32 access_mask;
1584 uint32 share_mode;
1585 uint32 create_disposition;
1586 uint32 create_options = 0;
1587 NTSTATUS status;
1588 TALLOC_CTX *ctx = talloc_tos();
1590 START_PROFILE(SMBopen);
1592 if (req->wct < 2) {
1593 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1594 END_PROFILE(SMBopen);
1595 return;
1598 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1599 deny_mode = SVAL(req->inbuf,smb_vwv0);
1600 dos_attr = SVAL(req->inbuf,smb_vwv1);
1602 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1603 smb_buf(req->inbuf)+1, 0,
1604 STR_TERMINATE, &status);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 reply_nterror(req, status);
1607 END_PROFILE(SMBopen);
1608 return;
1611 if (!map_open_params_to_ntcreate(
1612 fname, deny_mode, OPENX_FILE_EXISTS_OPEN, &access_mask,
1613 &share_mode, &create_disposition, &create_options)) {
1614 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1615 END_PROFILE(SMBopen);
1616 return;
1619 status = create_file(conn, /* conn */
1620 req, /* req */
1621 0, /* root_dir_fid */
1622 fname, /* fname */
1623 access_mask, /* access_mask */
1624 share_mode, /* share_access */
1625 create_disposition, /* create_disposition*/
1626 create_options, /* create_options */
1627 dos_attr, /* file_attributes */
1628 oplock_request, /* oplock_request */
1629 0, /* allocation_size */
1630 NULL, /* sd */
1631 NULL, /* ea_list */
1632 &fsp, /* result */
1633 &info, /* pinfo */
1634 &sbuf); /* psbuf */
1636 if (!NT_STATUS_IS_OK(status)) {
1637 if (open_was_deferred(req->mid)) {
1638 /* We have re-scheduled this call. */
1639 END_PROFILE(SMBopen);
1640 return;
1642 reply_openerror(req, status);
1643 END_PROFILE(SMBopen);
1644 return;
1647 size = sbuf.st_size;
1648 fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
1649 mtime = sbuf.st_mtime;
1651 if (fattr & aDIR) {
1652 DEBUG(3,("attempt to open a directory %s\n",fsp->fsp_name));
1653 close_file(fsp,ERROR_CLOSE);
1654 reply_doserror(req, ERRDOS,ERRnoaccess);
1655 END_PROFILE(SMBopen);
1656 return;
1659 reply_outbuf(req, 7, 0);
1660 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
1661 SSVAL(req->outbuf,smb_vwv1,fattr);
1662 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1663 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime & ~1);
1664 } else {
1665 srv_put_dos_date3((char *)req->outbuf,smb_vwv2,mtime);
1667 SIVAL(req->outbuf,smb_vwv4,(uint32)size);
1668 SSVAL(req->outbuf,smb_vwv6,deny_mode);
1670 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
1671 SCVAL(req->outbuf,smb_flg,
1672 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1675 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1676 SCVAL(req->outbuf,smb_flg,
1677 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1679 END_PROFILE(SMBopen);
1680 return;
1683 /****************************************************************************
1684 Reply to an open and X.
1685 ****************************************************************************/
1687 void reply_open_and_X(struct smb_request *req)
1689 connection_struct *conn = req->conn;
1690 char *fname = NULL;
1691 uint16 open_flags;
1692 int deny_mode;
1693 uint32 smb_attr;
1694 /* Breakout the oplock request bits so we can set the
1695 reply bits separately. */
1696 int ex_oplock_request;
1697 int core_oplock_request;
1698 int oplock_request;
1699 #if 0
1700 int smb_sattr = SVAL(req->inbuf,smb_vwv4);
1701 uint32 smb_time = make_unix_date3(req->inbuf+smb_vwv6);
1702 #endif
1703 int smb_ofun;
1704 uint32 fattr=0;
1705 int mtime=0;
1706 SMB_STRUCT_STAT sbuf;
1707 int smb_action = 0;
1708 files_struct *fsp;
1709 NTSTATUS status;
1710 SMB_BIG_UINT allocation_size;
1711 ssize_t retval = -1;
1712 uint32 access_mask;
1713 uint32 share_mode;
1714 uint32 create_disposition;
1715 uint32 create_options = 0;
1716 TALLOC_CTX *ctx = talloc_tos();
1718 START_PROFILE(SMBopenX);
1720 if (req->wct < 15) {
1721 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1722 END_PROFILE(SMBopenX);
1723 return;
1726 open_flags = SVAL(req->inbuf,smb_vwv2);
1727 deny_mode = SVAL(req->inbuf,smb_vwv3);
1728 smb_attr = SVAL(req->inbuf,smb_vwv5);
1729 ex_oplock_request = EXTENDED_OPLOCK_REQUEST(req->inbuf);
1730 core_oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1731 oplock_request = ex_oplock_request | core_oplock_request;
1732 smb_ofun = SVAL(req->inbuf,smb_vwv8);
1733 allocation_size = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv9);
1735 /* If it's an IPC, pass off the pipe handler. */
1736 if (IS_IPC(conn)) {
1737 if (lp_nt_pipe_support()) {
1738 reply_open_pipe_and_X(conn, req);
1739 } else {
1740 reply_doserror(req, ERRSRV, ERRaccess);
1742 END_PROFILE(SMBopenX);
1743 return;
1746 /* XXXX we need to handle passed times, sattr and flags */
1747 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1748 smb_buf(req->inbuf), 0, STR_TERMINATE,
1749 &status);
1750 if (!NT_STATUS_IS_OK(status)) {
1751 reply_nterror(req, status);
1752 END_PROFILE(SMBopenX);
1753 return;
1756 if (!map_open_params_to_ntcreate(
1757 fname, deny_mode, smb_ofun, &access_mask,
1758 &share_mode, &create_disposition, &create_options)) {
1759 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRbadaccess));
1760 END_PROFILE(SMBopenX);
1761 return;
1764 status = create_file(conn, /* conn */
1765 req, /* req */
1766 0, /* root_dir_fid */
1767 fname, /* fname */
1768 access_mask, /* access_mask */
1769 share_mode, /* share_access */
1770 create_disposition, /* create_disposition*/
1771 create_options, /* create_options */
1772 smb_attr, /* file_attributes */
1773 oplock_request, /* oplock_request */
1774 0, /* allocation_size */
1775 NULL, /* sd */
1776 NULL, /* ea_list */
1777 &fsp, /* result */
1778 &smb_action, /* pinfo */
1779 &sbuf); /* psbuf */
1781 if (!NT_STATUS_IS_OK(status)) {
1782 END_PROFILE(SMBopenX);
1783 if (open_was_deferred(req->mid)) {
1784 /* We have re-scheduled this call. */
1785 return;
1787 reply_openerror(req, status);
1788 return;
1791 /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
1792 if the file is truncated or created. */
1793 if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
1794 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
1795 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
1796 close_file(fsp,ERROR_CLOSE);
1797 reply_nterror(req, NT_STATUS_DISK_FULL);
1798 END_PROFILE(SMBopenX);
1799 return;
1801 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
1802 if (retval < 0) {
1803 close_file(fsp,ERROR_CLOSE);
1804 reply_nterror(req, NT_STATUS_DISK_FULL);
1805 END_PROFILE(SMBopenX);
1806 return;
1808 sbuf.st_size = get_allocation_size(conn,fsp,&sbuf);
1811 fattr = dos_mode(conn,fsp->fsp_name,&sbuf);
1812 mtime = sbuf.st_mtime;
1813 if (fattr & aDIR) {
1814 close_file(fsp,ERROR_CLOSE);
1815 reply_doserror(req, ERRDOS, ERRnoaccess);
1816 END_PROFILE(SMBopenX);
1817 return;
1820 /* If the caller set the extended oplock request bit
1821 and we granted one (by whatever means) - set the
1822 correct bit for extended oplock reply.
1825 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1826 smb_action |= EXTENDED_OPLOCK_GRANTED;
1829 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1830 smb_action |= EXTENDED_OPLOCK_GRANTED;
1833 /* If the caller set the core oplock request bit
1834 and we granted one (by whatever means) - set the
1835 correct bit for core oplock reply.
1838 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1839 reply_outbuf(req, 19, 0);
1840 } else {
1841 reply_outbuf(req, 15, 0);
1844 if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
1845 SCVAL(req->outbuf, smb_flg,
1846 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1849 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
1850 SCVAL(req->outbuf, smb_flg,
1851 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1854 SSVAL(req->outbuf,smb_vwv2,fsp->fnum);
1855 SSVAL(req->outbuf,smb_vwv3,fattr);
1856 if(lp_dos_filetime_resolution(SNUM(conn)) ) {
1857 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime & ~1);
1858 } else {
1859 srv_put_dos_date3((char *)req->outbuf,smb_vwv4,mtime);
1861 SIVAL(req->outbuf,smb_vwv6,(uint32)sbuf.st_size);
1862 SSVAL(req->outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
1863 SSVAL(req->outbuf,smb_vwv11,smb_action);
1865 if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
1866 SIVAL(req->outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
1869 END_PROFILE(SMBopenX);
1870 chain_reply(req);
1871 return;
1874 /****************************************************************************
1875 Reply to a SMBulogoffX.
1876 ****************************************************************************/
1878 void reply_ulogoffX(struct smb_request *req)
1880 user_struct *vuser;
1882 START_PROFILE(SMBulogoffX);
1884 vuser = get_valid_user_struct(req->vuid);
1886 if(vuser == NULL) {
1887 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n",
1888 req->vuid));
1891 /* in user level security we are supposed to close any files
1892 open by this user */
1893 if ((vuser != NULL) && (lp_security() != SEC_SHARE)) {
1894 file_close_user(req->vuid);
1897 invalidate_vuid(req->vuid);
1899 reply_outbuf(req, 2, 0);
1901 DEBUG( 3, ( "ulogoffX vuid=%d\n", req->vuid ) );
1903 END_PROFILE(SMBulogoffX);
1904 chain_reply(req);
1907 /****************************************************************************
1908 Reply to a mknew or a create.
1909 ****************************************************************************/
1911 void reply_mknew(struct smb_request *req)
1913 connection_struct *conn = req->conn;
1914 char *fname = NULL;
1915 int com;
1916 uint32 fattr = 0;
1917 struct timespec ts[2];
1918 files_struct *fsp;
1919 int oplock_request = 0;
1920 SMB_STRUCT_STAT sbuf;
1921 NTSTATUS status;
1922 uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
1923 uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
1924 uint32 create_disposition;
1925 uint32 create_options = 0;
1926 TALLOC_CTX *ctx = talloc_tos();
1928 START_PROFILE(SMBcreate);
1930 if (req->wct < 3) {
1931 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
1932 END_PROFILE(SMBcreate);
1933 return;
1936 fattr = SVAL(req->inbuf,smb_vwv0);
1937 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
1938 com = SVAL(req->inbuf,smb_com);
1940 ts[1] =convert_time_t_to_timespec(
1941 srv_make_unix_date3(req->inbuf + smb_vwv1));
1942 /* mtime. */
1944 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
1945 smb_buf(req->inbuf) + 1, 0,
1946 STR_TERMINATE, &status);
1947 if (!NT_STATUS_IS_OK(status)) {
1948 reply_nterror(req, status);
1949 END_PROFILE(SMBcreate);
1950 return;
1953 if (fattr & aVOLID) {
1954 DEBUG(0,("Attempt to create file (%s) with volid set - "
1955 "please report this\n", fname));
1958 if(com == SMBmknew) {
1959 /* We should fail if file exists. */
1960 create_disposition = FILE_CREATE;
1961 } else {
1962 /* Create if file doesn't exist, truncate if it does. */
1963 create_disposition = FILE_OVERWRITE_IF;
1966 status = create_file(conn, /* conn */
1967 req, /* req */
1968 0, /* root_dir_fid */
1969 fname, /* fname */
1970 access_mask, /* access_mask */
1971 share_mode, /* share_access */
1972 create_disposition, /* create_disposition*/
1973 create_options, /* create_options */
1974 fattr, /* file_attributes */
1975 oplock_request, /* oplock_request */
1976 0, /* allocation_size */
1977 NULL, /* sd */
1978 NULL, /* ea_list */
1979 &fsp, /* result */
1980 NULL, /* pinfo */
1981 &sbuf); /* psbuf */
1983 if (!NT_STATUS_IS_OK(status)) {
1984 END_PROFILE(SMBcreate);
1985 if (open_was_deferred(req->mid)) {
1986 /* We have re-scheduled this call. */
1987 return;
1989 reply_openerror(req, status);
1990 return;
1993 ts[0] = get_atimespec(&sbuf); /* atime. */
1994 status = smb_set_file_time(conn, fsp, fname, &sbuf, ts, true);
1995 if (!NT_STATUS_IS_OK(status)) {
1996 END_PROFILE(SMBcreate);
1997 reply_openerror(req, status);
1998 return;
2001 reply_outbuf(req, 1, 0);
2002 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2004 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2005 SCVAL(req->outbuf,smb_flg,
2006 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2009 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2010 SCVAL(req->outbuf,smb_flg,
2011 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2014 DEBUG( 2, ( "reply_mknew: file %s\n", fsp->fsp_name ) );
2015 DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n",
2016 fsp->fsp_name, fsp->fh->fd, (unsigned int)fattr ) );
2018 END_PROFILE(SMBcreate);
2019 return;
2022 /****************************************************************************
2023 Reply to a create temporary file.
2024 ****************************************************************************/
2026 void reply_ctemp(struct smb_request *req)
2028 connection_struct *conn = req->conn;
2029 char *fname = NULL;
2030 uint32 fattr;
2031 files_struct *fsp;
2032 int oplock_request;
2033 int tmpfd;
2034 SMB_STRUCT_STAT sbuf;
2035 char *s;
2036 NTSTATUS status;
2037 TALLOC_CTX *ctx = talloc_tos();
2039 START_PROFILE(SMBctemp);
2041 if (req->wct < 3) {
2042 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2043 END_PROFILE(SMBctemp);
2044 return;
2047 fattr = SVAL(req->inbuf,smb_vwv0);
2048 oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
2050 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &fname,
2051 smb_buf(req->inbuf)+1, 0, STR_TERMINATE,
2052 &status);
2053 if (!NT_STATUS_IS_OK(status)) {
2054 reply_nterror(req, status);
2055 END_PROFILE(SMBctemp);
2056 return;
2058 if (*fname) {
2059 fname = talloc_asprintf(ctx,
2060 "%s/TMXXXXXX",
2061 fname);
2062 } else {
2063 fname = talloc_strdup(ctx, "TMXXXXXX");
2066 if (!fname) {
2067 reply_nterror(req, NT_STATUS_NO_MEMORY);
2068 END_PROFILE(SMBctemp);
2069 return;
2072 status = resolve_dfspath(ctx, conn,
2073 req->flags2 & FLAGS2_DFS_PATHNAMES,
2074 fname,
2075 &fname);
2076 if (!NT_STATUS_IS_OK(status)) {
2077 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2078 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2079 ERRSRV, ERRbadpath);
2080 END_PROFILE(SMBctemp);
2081 return;
2083 reply_nterror(req, status);
2084 END_PROFILE(SMBctemp);
2085 return;
2088 status = unix_convert(ctx, conn, fname, False, &fname, NULL, &sbuf);
2089 if (!NT_STATUS_IS_OK(status)) {
2090 reply_nterror(req, status);
2091 END_PROFILE(SMBctemp);
2092 return;
2095 status = check_name(conn, CONST_DISCARD(char *,fname));
2096 if (!NT_STATUS_IS_OK(status)) {
2097 reply_nterror(req, status);
2098 END_PROFILE(SMBctemp);
2099 return;
2102 tmpfd = smb_mkstemp(fname);
2103 if (tmpfd == -1) {
2104 reply_unixerror(req, ERRDOS, ERRnoaccess);
2105 END_PROFILE(SMBctemp);
2106 return;
2109 SMB_VFS_STAT(conn,fname,&sbuf);
2111 /* We should fail if file does not exist. */
2112 status = open_file_ntcreate(conn, req, fname, &sbuf,
2113 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
2114 FILE_SHARE_READ|FILE_SHARE_WRITE,
2115 FILE_OPEN,
2117 fattr,
2118 oplock_request,
2119 NULL, &fsp);
2121 /* close fd from smb_mkstemp() */
2122 close(tmpfd);
2124 if (!NT_STATUS_IS_OK(status)) {
2125 if (open_was_deferred(req->mid)) {
2126 /* We have re-scheduled this call. */
2127 END_PROFILE(SMBctemp);
2128 return;
2130 reply_openerror(req, status);
2131 END_PROFILE(SMBctemp);
2132 return;
2135 reply_outbuf(req, 1, 0);
2136 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
2138 /* the returned filename is relative to the directory */
2139 s = strrchr_m(fsp->fsp_name, '/');
2140 if (!s) {
2141 s = fsp->fsp_name;
2142 } else {
2143 s++;
2146 #if 0
2147 /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
2148 thing in the byte section. JRA */
2149 SSVALS(p, 0, -1); /* what is this? not in spec */
2150 #endif
2151 if (message_push_string(&req->outbuf, s, STR_ASCII|STR_TERMINATE)
2152 == -1) {
2153 reply_nterror(req, NT_STATUS_NO_MEMORY);
2154 END_PROFILE(SMBctemp);
2155 return;
2158 if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
2159 SCVAL(req->outbuf, smb_flg,
2160 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2163 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
2164 SCVAL(req->outbuf, smb_flg,
2165 CVAL(req->outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
2168 DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fsp->fsp_name ) );
2169 DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fsp->fsp_name,
2170 fsp->fh->fd, (unsigned int)sbuf.st_mode ) );
2172 END_PROFILE(SMBctemp);
2173 return;
2176 /*******************************************************************
2177 Check if a user is allowed to rename a file.
2178 ********************************************************************/
2180 static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
2181 uint16 dirtype, SMB_STRUCT_STAT *pst)
2183 uint32 fmode;
2185 if (!CAN_WRITE(conn)) {
2186 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2189 fmode = dos_mode(conn, fsp->fsp_name, pst);
2190 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
2191 return NT_STATUS_NO_SUCH_FILE;
2194 if (S_ISDIR(pst->st_mode)) {
2195 return NT_STATUS_OK;
2198 if (fsp->access_mask & (DELETE_ACCESS|FILE_WRITE_ATTRIBUTES)) {
2199 return NT_STATUS_OK;
2202 return NT_STATUS_ACCESS_DENIED;
2205 /*******************************************************************
2206 * unlink a file with all relevant access checks
2207 *******************************************************************/
2209 static NTSTATUS do_unlink(connection_struct *conn,
2210 struct smb_request *req,
2211 const char *fname,
2212 uint32 dirtype)
2214 SMB_STRUCT_STAT sbuf;
2215 uint32 fattr;
2216 files_struct *fsp;
2217 uint32 dirtype_orig = dirtype;
2218 NTSTATUS status;
2220 DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype ));
2222 if (!CAN_WRITE(conn)) {
2223 return NT_STATUS_MEDIA_WRITE_PROTECTED;
2226 if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
2227 return map_nt_error_from_unix(errno);
2230 fattr = dos_mode(conn,fname,&sbuf);
2232 if (dirtype & FILE_ATTRIBUTE_NORMAL) {
2233 dirtype = aDIR|aARCH|aRONLY;
2236 dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
2237 if (!dirtype) {
2238 return NT_STATUS_NO_SUCH_FILE;
2241 if (!dir_check_ftype(conn, fattr, dirtype)) {
2242 if (fattr & aDIR) {
2243 return NT_STATUS_FILE_IS_A_DIRECTORY;
2245 return NT_STATUS_NO_SUCH_FILE;
2248 if (dirtype_orig & 0x8000) {
2249 /* These will never be set for POSIX. */
2250 return NT_STATUS_NO_SUCH_FILE;
2253 #if 0
2254 if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
2255 return NT_STATUS_FILE_IS_A_DIRECTORY;
2258 if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
2259 return NT_STATUS_NO_SUCH_FILE;
2262 if (dirtype & 0xFF00) {
2263 /* These will never be set for POSIX. */
2264 return NT_STATUS_NO_SUCH_FILE;
2267 dirtype &= 0xFF;
2268 if (!dirtype) {
2269 return NT_STATUS_NO_SUCH_FILE;
2272 /* Can't delete a directory. */
2273 if (fattr & aDIR) {
2274 return NT_STATUS_FILE_IS_A_DIRECTORY;
2276 #endif
2278 #if 0 /* JRATEST */
2279 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
2280 return NT_STATUS_OBJECT_NAME_INVALID;
2281 #endif /* JRATEST */
2283 /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
2285 On a Windows share, a file with read-only dosmode can be opened with
2286 DELETE_ACCESS. But on a Samba share (delete readonly = no), it
2287 fails with NT_STATUS_CANNOT_DELETE error.
2289 This semantic causes a problem that a user can not
2290 rename a file with read-only dosmode on a Samba share
2291 from a Windows command prompt (i.e. cmd.exe, but can rename
2292 from Windows Explorer).
2295 if (!lp_delete_readonly(SNUM(conn))) {
2296 if (fattr & aRONLY) {
2297 return NT_STATUS_CANNOT_DELETE;
2301 /* On open checks the open itself will check the share mode, so
2302 don't do it here as we'll get it wrong. */
2304 status = create_file_unixpath
2305 (conn, /* conn */
2306 req, /* req */
2307 fname, /* fname */
2308 DELETE_ACCESS, /* access_mask */
2309 FILE_SHARE_NONE, /* share_access */
2310 FILE_OPEN, /* create_disposition*/
2311 FILE_NON_DIRECTORY_FILE, /* create_options */
2312 FILE_ATTRIBUTE_NORMAL, /* file_attributes */
2313 0, /* oplock_request */
2314 0, /* allocation_size */
2315 NULL, /* sd */
2316 NULL, /* ea_list */
2317 &fsp, /* result */
2318 NULL, /* pinfo */
2319 &sbuf); /* psbuf */
2321 if (!NT_STATUS_IS_OK(status)) {
2322 DEBUG(10, ("open_file_ntcreate failed: %s\n",
2323 nt_errstr(status)));
2324 return status;
2327 /* The set is across all open files on this dev/inode pair. */
2328 if (!set_delete_on_close(fsp, True, &current_user.ut)) {
2329 close_file(fsp, NORMAL_CLOSE);
2330 return NT_STATUS_ACCESS_DENIED;
2333 return close_file(fsp,NORMAL_CLOSE);
2336 /****************************************************************************
2337 The guts of the unlink command, split out so it may be called by the NT SMB
2338 code.
2339 ****************************************************************************/
2341 NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
2342 uint32 dirtype, const char *name_in, bool has_wild)
2344 const char *directory = NULL;
2345 char *mask = NULL;
2346 char *name = NULL;
2347 char *p = NULL;
2348 int count=0;
2349 NTSTATUS status = NT_STATUS_OK;
2350 SMB_STRUCT_STAT sbuf;
2351 TALLOC_CTX *ctx = talloc_tos();
2353 status = unix_convert(ctx, conn, name_in, has_wild, &name, NULL, &sbuf);
2354 if (!NT_STATUS_IS_OK(status)) {
2355 return status;
2358 p = strrchr_m(name,'/');
2359 if (!p) {
2360 directory = talloc_strdup(ctx, ".");
2361 if (!directory) {
2362 return NT_STATUS_NO_MEMORY;
2364 mask = name;
2365 } else {
2366 *p = 0;
2367 directory = name;
2368 mask = p+1;
2372 * We should only check the mangled cache
2373 * here if unix_convert failed. This means
2374 * that the path in 'mask' doesn't exist
2375 * on the file system and so we need to look
2376 * for a possible mangle. This patch from
2377 * Tine Smukavec <valentin.smukavec@hermes.si>.
2380 if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params)) {
2381 char *new_mask = NULL;
2382 mangle_lookup_name_from_8_3(ctx,
2383 mask,
2384 &new_mask,
2385 conn->params );
2386 if (new_mask) {
2387 mask = new_mask;
2391 if (!has_wild) {
2392 directory = talloc_asprintf(ctx,
2393 "%s/%s",
2394 directory,
2395 mask);
2396 if (!directory) {
2397 return NT_STATUS_NO_MEMORY;
2399 if (dirtype == 0) {
2400 dirtype = FILE_ATTRIBUTE_NORMAL;
2403 status = check_name(conn, directory);
2404 if (!NT_STATUS_IS_OK(status)) {
2405 return status;
2408 status = do_unlink(conn, req, directory, dirtype);
2409 if (!NT_STATUS_IS_OK(status)) {
2410 return status;
2413 count++;
2414 } else {
2415 struct smb_Dir *dir_hnd = NULL;
2416 long offset = 0;
2417 const char *dname;
2419 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
2420 return NT_STATUS_OBJECT_NAME_INVALID;
2423 if (strequal(mask,"????????.???")) {
2424 mask[0] = '*';
2425 mask[1] = '\0';
2428 status = check_name(conn, directory);
2429 if (!NT_STATUS_IS_OK(status)) {
2430 return status;
2433 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask,
2434 dirtype);
2435 if (dir_hnd == NULL) {
2436 return map_nt_error_from_unix(errno);
2439 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
2440 the pattern matches against the long name, otherwise the short name
2441 We don't implement this yet XXXX
2444 status = NT_STATUS_NO_SUCH_FILE;
2446 while ((dname = ReadDirName(dir_hnd, &offset))) {
2447 SMB_STRUCT_STAT st;
2448 char *fname = NULL;
2450 if (!is_visible_file(conn, directory, dname, &st, True)) {
2451 continue;
2454 /* Quick check for "." and ".." */
2455 if (ISDOT(dname) || ISDOTDOT(dname)) {
2456 continue;
2459 if(!mask_match(dname, mask, conn->case_sensitive)) {
2460 continue;
2463 fname = talloc_asprintf(ctx, "%s/%s",
2464 directory,
2465 dname);
2466 if (!fname) {
2467 return NT_STATUS_NO_MEMORY;
2470 status = check_name(conn, fname);
2471 if (!NT_STATUS_IS_OK(status)) {
2472 TALLOC_FREE(dir_hnd);
2473 return status;
2476 status = do_unlink(conn, req, fname, dirtype);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 TALLOC_FREE(fname);
2479 continue;
2482 count++;
2483 DEBUG(3,("unlink_internals: successful unlink [%s]\n",
2484 fname));
2486 TALLOC_FREE(fname);
2488 TALLOC_FREE(dir_hnd);
2491 if (count == 0 && NT_STATUS_IS_OK(status)) {
2492 status = map_nt_error_from_unix(errno);
2495 return status;
2498 /****************************************************************************
2499 Reply to a unlink
2500 ****************************************************************************/
2502 void reply_unlink(struct smb_request *req)
2504 connection_struct *conn = req->conn;
2505 char *name = NULL;
2506 uint32 dirtype;
2507 NTSTATUS status;
2508 bool path_contains_wcard = False;
2509 TALLOC_CTX *ctx = talloc_tos();
2511 START_PROFILE(SMBunlink);
2513 if (req->wct < 1) {
2514 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2515 END_PROFILE(SMBunlink);
2516 return;
2519 dirtype = SVAL(req->inbuf,smb_vwv0);
2521 srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name,
2522 smb_buf(req->inbuf) + 1, 0,
2523 STR_TERMINATE, &status, &path_contains_wcard);
2524 if (!NT_STATUS_IS_OK(status)) {
2525 reply_nterror(req, status);
2526 END_PROFILE(SMBunlink);
2527 return;
2530 status = resolve_dfspath_wcard(ctx, conn,
2531 req->flags2 & FLAGS2_DFS_PATHNAMES,
2532 name,
2533 &name,
2534 &path_contains_wcard);
2535 if (!NT_STATUS_IS_OK(status)) {
2536 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
2537 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
2538 ERRSRV, ERRbadpath);
2539 END_PROFILE(SMBunlink);
2540 return;
2542 reply_nterror(req, status);
2543 END_PROFILE(SMBunlink);
2544 return;
2547 DEBUG(3,("reply_unlink : %s\n",name));
2549 status = unlink_internals(conn, req, dirtype, name,
2550 path_contains_wcard);
2551 if (!NT_STATUS_IS_OK(status)) {
2552 if (open_was_deferred(req->mid)) {
2553 /* We have re-scheduled this call. */
2554 END_PROFILE(SMBunlink);
2555 return;
2557 reply_nterror(req, status);
2558 END_PROFILE(SMBunlink);
2559 return;
2562 reply_outbuf(req, 0, 0);
2563 END_PROFILE(SMBunlink);
2565 return;
2568 /****************************************************************************
2569 Fail for readbraw.
2570 ****************************************************************************/
2572 static void fail_readraw(void)
2574 const char *errstr = talloc_asprintf(talloc_tos(),
2575 "FAIL ! reply_readbraw: socket write fail (%s)",
2576 strerror(errno));
2577 if (!errstr) {
2578 errstr = "";
2580 exit_server_cleanly(errstr);
2583 /****************************************************************************
2584 Fake (read/write) sendfile. Returns -1 on read or write fail.
2585 ****************************************************************************/
2587 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos,
2588 size_t nread)
2590 size_t bufsize;
2591 size_t tosend = nread;
2592 char *buf;
2594 if (nread == 0) {
2595 return 0;
2598 bufsize = MIN(nread, 65536);
2600 if (!(buf = SMB_MALLOC_ARRAY(char, bufsize))) {
2601 return -1;
2604 while (tosend > 0) {
2605 ssize_t ret;
2606 size_t cur_read;
2608 if (tosend > bufsize) {
2609 cur_read = bufsize;
2610 } else {
2611 cur_read = tosend;
2613 ret = read_file(fsp,buf,startpos,cur_read);
2614 if (ret == -1) {
2615 SAFE_FREE(buf);
2616 return -1;
2619 /* If we had a short read, fill with zeros. */
2620 if (ret < cur_read) {
2621 memset(buf, '\0', cur_read - ret);
2624 if (write_data(smbd_server_fd(),buf,cur_read) != cur_read) {
2625 SAFE_FREE(buf);
2626 return -1;
2628 tosend -= cur_read;
2629 startpos += cur_read;
2632 SAFE_FREE(buf);
2633 return (ssize_t)nread;
2636 /****************************************************************************
2637 Return a readbraw error (4 bytes of zero).
2638 ****************************************************************************/
2640 static void reply_readbraw_error(void)
2642 char header[4];
2643 SIVAL(header,0,0);
2644 if (write_data(smbd_server_fd(),header,4) != 4) {
2645 fail_readraw();
2649 /****************************************************************************
2650 Use sendfile in readbraw.
2651 ****************************************************************************/
2653 void send_file_readbraw(connection_struct *conn,
2654 files_struct *fsp,
2655 SMB_OFF_T startpos,
2656 size_t nread,
2657 ssize_t mincount)
2659 char *outbuf = NULL;
2660 ssize_t ret=0;
2662 #if defined(WITH_SENDFILE)
2664 * We can only use sendfile on a non-chained packet
2665 * but we can use on a non-oplocked file. tridge proved this
2666 * on a train in Germany :-). JRA.
2667 * reply_readbraw has already checked the length.
2670 if ( (chain_size == 0) && (nread > 0) && (fsp->base_fsp == NULL) &&
2671 (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
2672 char header[4];
2673 DATA_BLOB header_blob;
2675 _smb_setlen(header,nread);
2676 header_blob = data_blob_const(header, 4);
2678 if (SMB_VFS_SENDFILE(smbd_server_fd(), fsp,
2679 &header_blob, startpos, nread) == -1) {
2680 /* Returning ENOSYS means no data at all was sent.
2681 * Do this as a normal read. */
2682 if (errno == ENOSYS) {
2683 goto normal_readbraw;
2687 * Special hack for broken Linux with no working sendfile. If we
2688 * return EINTR we sent the header but not the rest of the data.
2689 * Fake this up by doing read/write calls.
2691 if (errno == EINTR) {
2692 /* Ensure we don't do this again. */
2693 set_use_sendfile(SNUM(conn), False);
2694 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
2696 if (fake_sendfile(fsp, startpos, nread) == -1) {
2697 DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
2698 fsp->fsp_name, strerror(errno) ));
2699 exit_server_cleanly("send_file_readbraw fake_sendfile failed");
2701 return;
2704 DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
2705 fsp->fsp_name, strerror(errno) ));
2706 exit_server_cleanly("send_file_readbraw sendfile failed");
2709 return;
2711 #endif
2713 normal_readbraw:
2715 outbuf = TALLOC_ARRAY(NULL, char, nread+4);
2716 if (!outbuf) {
2717 DEBUG(0,("send_file_readbraw: TALLOC_ARRAY failed for size %u.\n",
2718 (unsigned)(nread+4)));
2719 reply_readbraw_error();
2720 return;
2723 if (nread > 0) {
2724 ret = read_file(fsp,outbuf+4,startpos,nread);
2725 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2726 if (ret < mincount)
2727 ret = 0;
2728 #else
2729 if (ret < nread)
2730 ret = 0;
2731 #endif
2734 _smb_setlen(outbuf,ret);
2735 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
2736 fail_readraw();
2738 TALLOC_FREE(outbuf);
2741 /****************************************************************************
2742 Reply to a readbraw (core+ protocol).
2743 ****************************************************************************/
2745 void reply_readbraw(struct smb_request *req)
2747 connection_struct *conn = req->conn;
2748 ssize_t maxcount,mincount;
2749 size_t nread = 0;
2750 SMB_OFF_T startpos;
2751 files_struct *fsp;
2752 SMB_STRUCT_STAT st;
2753 SMB_OFF_T size = 0;
2755 START_PROFILE(SMBreadbraw);
2757 if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
2758 exit_server_cleanly("reply_readbraw: SMB signing/sealing is active - "
2759 "raw reads/writes are disallowed.");
2762 if (req->wct < 8) {
2763 reply_readbraw_error();
2764 END_PROFILE(SMBreadbraw);
2765 return;
2769 * Special check if an oplock break has been issued
2770 * and the readraw request croses on the wire, we must
2771 * return a zero length response here.
2774 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
2777 * We have to do a check_fsp by hand here, as
2778 * we must always return 4 zero bytes on error,
2779 * not a NTSTATUS.
2782 if (!fsp || !conn || conn != fsp->conn ||
2783 current_user.vuid != fsp->vuid ||
2784 fsp->is_directory || fsp->fh->fd == -1) {
2786 * fsp could be NULL here so use the value from the packet. JRA.
2788 DEBUG(3,("reply_readbraw: fnum %d not valid "
2789 "- cache prime?\n",
2790 (int)SVAL(req->inbuf,smb_vwv0)));
2791 reply_readbraw_error();
2792 END_PROFILE(SMBreadbraw);
2793 return;
2796 /* Do a "by hand" version of CHECK_READ. */
2797 if (!(fsp->can_read ||
2798 ((req->flags2 & FLAGS2_READ_PERMIT_EXECUTE) &&
2799 (fsp->access_mask & FILE_EXECUTE)))) {
2800 DEBUG(3,("reply_readbraw: fnum %d not readable.\n",
2801 (int)SVAL(req->inbuf,smb_vwv0)));
2802 reply_readbraw_error();
2803 END_PROFILE(SMBreadbraw);
2804 return;
2807 flush_write_cache(fsp, READRAW_FLUSH);
2809 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv1);
2810 if(req->wct == 10) {
2812 * This is a large offset (64 bit) read.
2814 #ifdef LARGE_SMB_OFF_T
2816 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv8)) << 32);
2818 #else /* !LARGE_SMB_OFF_T */
2821 * Ensure we haven't been sent a >32 bit offset.
2824 if(IVAL(req->inbuf,smb_vwv8) != 0) {
2825 DEBUG(0,("reply_readbraw: large offset "
2826 "(%x << 32) used and we don't support "
2827 "64 bit offsets.\n",
2828 (unsigned int)IVAL(req->inbuf,smb_vwv8) ));
2829 reply_readbraw_error();
2830 END_PROFILE(SMBreadbraw);
2831 return;
2834 #endif /* LARGE_SMB_OFF_T */
2836 if(startpos < 0) {
2837 DEBUG(0,("reply_readbraw: negative 64 bit "
2838 "readraw offset (%.0f) !\n",
2839 (double)startpos ));
2840 reply_readbraw_error();
2841 END_PROFILE(SMBreadbraw);
2842 return;
2846 maxcount = (SVAL(req->inbuf,smb_vwv3) & 0xFFFF);
2847 mincount = (SVAL(req->inbuf,smb_vwv4) & 0xFFFF);
2849 /* ensure we don't overrun the packet size */
2850 maxcount = MIN(65535,maxcount);
2852 if (is_locked(fsp,(uint32)req->smbpid,
2853 (SMB_BIG_UINT)maxcount,
2854 (SMB_BIG_UINT)startpos,
2855 READ_LOCK)) {
2856 reply_readbraw_error();
2857 END_PROFILE(SMBreadbraw);
2858 return;
2861 if (SMB_VFS_FSTAT(fsp, &st) == 0) {
2862 size = st.st_size;
2865 if (startpos >= size) {
2866 nread = 0;
2867 } else {
2868 nread = MIN(maxcount,(size - startpos));
2871 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
2872 if (nread < mincount)
2873 nread = 0;
2874 #endif
2876 DEBUG( 3, ( "reply_readbraw: fnum=%d start=%.0f max=%lu "
2877 "min=%lu nread=%lu\n",
2878 fsp->fnum, (double)startpos,
2879 (unsigned long)maxcount,
2880 (unsigned long)mincount,
2881 (unsigned long)nread ) );
2883 send_file_readbraw(conn, fsp, startpos, nread, mincount);
2885 DEBUG(5,("reply_readbraw finished\n"));
2886 END_PROFILE(SMBreadbraw);
2889 #undef DBGC_CLASS
2890 #define DBGC_CLASS DBGC_LOCKING
2892 /****************************************************************************
2893 Reply to a lockread (core+ protocol).
2894 ****************************************************************************/
2896 void reply_lockread(struct smb_request *req)
2898 connection_struct *conn = req->conn;
2899 ssize_t nread = -1;
2900 char *data;
2901 SMB_OFF_T startpos;
2902 size_t numtoread;
2903 NTSTATUS status;
2904 files_struct *fsp;
2905 struct byte_range_lock *br_lck = NULL;
2906 char *p = NULL;
2908 START_PROFILE(SMBlockread);
2910 if (req->wct < 5) {
2911 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
2912 END_PROFILE(SMBlockread);
2913 return;
2916 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
2918 if (!check_fsp(conn, req, fsp, &current_user)) {
2919 END_PROFILE(SMBlockread);
2920 return;
2923 if (!CHECK_READ(fsp,req->inbuf)) {
2924 reply_doserror(req, ERRDOS, ERRbadaccess);
2925 END_PROFILE(SMBlockread);
2926 return;
2929 release_level_2_oplocks_on_change(fsp);
2931 numtoread = SVAL(req->inbuf,smb_vwv1);
2932 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
2934 numtoread = MIN(BUFFER_SIZE - (smb_size + 3*2 + 3), numtoread);
2936 reply_outbuf(req, 5, numtoread + 3);
2938 data = smb_buf(req->outbuf) + 3;
2941 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
2942 * protocol request that predates the read/write lock concept.
2943 * Thus instead of asking for a read lock here we need to ask
2944 * for a write lock. JRA.
2945 * Note that the requested lock size is unaffected by max_recv.
2948 br_lck = do_lock(smbd_messaging_context(),
2949 fsp,
2950 req->smbpid,
2951 (SMB_BIG_UINT)numtoread,
2952 (SMB_BIG_UINT)startpos,
2953 WRITE_LOCK,
2954 WINDOWS_LOCK,
2955 False, /* Non-blocking lock. */
2956 &status,
2957 NULL);
2958 TALLOC_FREE(br_lck);
2960 if (NT_STATUS_V(status)) {
2961 reply_nterror(req, status);
2962 END_PROFILE(SMBlockread);
2963 return;
2967 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
2970 if (numtoread > max_recv) {
2971 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
2972 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
2973 (unsigned int)numtoread, (unsigned int)max_recv ));
2974 numtoread = MIN(numtoread,max_recv);
2976 nread = read_file(fsp,data,startpos,numtoread);
2978 if (nread < 0) {
2979 reply_unixerror(req, ERRDOS, ERRnoaccess);
2980 END_PROFILE(SMBlockread);
2981 return;
2984 srv_set_message((char *)req->outbuf, 5, nread+3, False);
2986 SSVAL(req->outbuf,smb_vwv0,nread);
2987 SSVAL(req->outbuf,smb_vwv5,nread+3);
2988 p = smb_buf(req->outbuf);
2989 SCVAL(p,0,0); /* pad byte. */
2990 SSVAL(p,1,nread);
2992 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
2993 fsp->fnum, (int)numtoread, (int)nread));
2995 END_PROFILE(SMBlockread);
2996 return;
2999 #undef DBGC_CLASS
3000 #define DBGC_CLASS DBGC_ALL
3002 /****************************************************************************
3003 Reply to a read.
3004 ****************************************************************************/
3006 void reply_read(struct smb_request *req)
3008 connection_struct *conn = req->conn;
3009 size_t numtoread;
3010 ssize_t nread = 0;
3011 char *data;
3012 SMB_OFF_T startpos;
3013 int outsize = 0;
3014 files_struct *fsp;
3016 START_PROFILE(SMBread);
3018 if (req->wct < 3) {
3019 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3020 END_PROFILE(SMBread);
3021 return;
3024 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3026 if (!check_fsp(conn, req, fsp, &current_user)) {
3027 END_PROFILE(SMBread);
3028 return;
3031 if (!CHECK_READ(fsp,req->inbuf)) {
3032 reply_doserror(req, ERRDOS, ERRbadaccess);
3033 END_PROFILE(SMBread);
3034 return;
3037 numtoread = SVAL(req->inbuf,smb_vwv1);
3038 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3040 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
3043 * The requested read size cannot be greater than max_recv. JRA.
3045 if (numtoread > max_recv) {
3046 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
3047 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
3048 (unsigned int)numtoread, (unsigned int)max_recv ));
3049 numtoread = MIN(numtoread,max_recv);
3052 reply_outbuf(req, 5, numtoread+3);
3054 data = smb_buf(req->outbuf) + 3;
3056 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtoread,
3057 (SMB_BIG_UINT)startpos, READ_LOCK)) {
3058 reply_doserror(req, ERRDOS,ERRlock);
3059 END_PROFILE(SMBread);
3060 return;
3063 if (numtoread > 0)
3064 nread = read_file(fsp,data,startpos,numtoread);
3066 if (nread < 0) {
3067 reply_unixerror(req, ERRDOS,ERRnoaccess);
3068 END_PROFILE(SMBread);
3069 return;
3072 srv_set_message((char *)req->outbuf, 5, nread+3, False);
3074 SSVAL(req->outbuf,smb_vwv0,nread);
3075 SSVAL(req->outbuf,smb_vwv5,nread+3);
3076 SCVAL(smb_buf(req->outbuf),0,1);
3077 SSVAL(smb_buf(req->outbuf),1,nread);
3079 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
3080 fsp->fnum, (int)numtoread, (int)nread ) );
3082 END_PROFILE(SMBread);
3083 return;
3086 /****************************************************************************
3087 Setup readX header.
3088 ****************************************************************************/
3090 static int setup_readX_header(char *outbuf, size_t smb_maxcnt)
3092 int outsize;
3093 char *data;
3095 outsize = srv_set_message(outbuf,12,smb_maxcnt,False);
3096 data = smb_buf(outbuf);
3098 memset(outbuf+smb_vwv0,'\0',24); /* valgrind init. */
3100 SCVAL(outbuf,smb_vwv0,0xFF);
3101 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
3102 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
3103 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
3104 SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
3105 SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
3106 /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
3107 _smb_setlen_large(outbuf,(smb_size + 12*2 + smb_maxcnt - 4));
3108 return outsize;
3111 /****************************************************************************
3112 Reply to a read and X - possibly using sendfile.
3113 ****************************************************************************/
3115 static void send_file_readX(connection_struct *conn, struct smb_request *req,
3116 files_struct *fsp, SMB_OFF_T startpos,
3117 size_t smb_maxcnt)
3119 SMB_STRUCT_STAT sbuf;
3120 ssize_t nread = -1;
3122 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
3123 reply_unixerror(req, ERRDOS, ERRnoaccess);
3124 return;
3127 if (startpos > sbuf.st_size) {
3128 smb_maxcnt = 0;
3129 } else if (smb_maxcnt > (sbuf.st_size - startpos)) {
3130 smb_maxcnt = (sbuf.st_size - startpos);
3133 if (smb_maxcnt == 0) {
3134 goto normal_read;
3137 #if defined(WITH_SENDFILE)
3139 * We can only use sendfile on a non-chained packet
3140 * but we can use on a non-oplocked file. tridge proved this
3141 * on a train in Germany :-). JRA.
3144 if ((chain_size == 0) && (CVAL(req->inbuf,smb_vwv0) == 0xFF) &&
3145 !is_encrypted_packet(req->inbuf) && (fsp->base_fsp == NULL) &&
3146 lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
3147 uint8 headerbuf[smb_size + 12 * 2];
3148 DATA_BLOB header;
3151 * Set up the packet header before send. We
3152 * assume here the sendfile will work (get the
3153 * correct amount of data).
3156 header = data_blob_const(headerbuf, sizeof(headerbuf));
3158 construct_reply_common((char *)req->inbuf, (char *)headerbuf);
3159 setup_readX_header((char *)headerbuf, smb_maxcnt);
3161 if ((nread = SMB_VFS_SENDFILE(smbd_server_fd(), fsp, &header, startpos, smb_maxcnt)) == -1) {
3162 /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
3163 if (errno == ENOSYS) {
3164 goto normal_read;
3168 * Special hack for broken Linux with no working sendfile. If we
3169 * return EINTR we sent the header but not the rest of the data.
3170 * Fake this up by doing read/write calls.
3173 if (errno == EINTR) {
3174 /* Ensure we don't do this again. */
3175 set_use_sendfile(SNUM(conn), False);
3176 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
3177 nread = fake_sendfile(fsp, startpos,
3178 smb_maxcnt);
3179 if (nread == -1) {
3180 DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
3181 fsp->fsp_name, strerror(errno) ));
3182 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3184 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
3185 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3186 /* No outbuf here means successful sendfile. */
3187 TALLOC_FREE(req->outbuf);
3188 return;
3191 DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
3192 fsp->fsp_name, strerror(errno) ));
3193 exit_server_cleanly("send_file_readX sendfile failed");
3196 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
3197 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3198 /* No outbuf here means successful sendfile. */
3199 TALLOC_FREE(req->outbuf);
3200 return;
3202 #endif
3204 normal_read:
3206 if ((smb_maxcnt & 0xFF0000) > 0x10000) {
3207 uint8 headerbuf[smb_size + 2*12];
3209 construct_reply_common((char *)req->inbuf, (char *)headerbuf);
3210 setup_readX_header((char *)headerbuf, smb_maxcnt);
3212 /* Send out the header. */
3213 if (write_data(smbd_server_fd(), (char *)headerbuf,
3214 sizeof(headerbuf)) != sizeof(headerbuf)) {
3215 DEBUG(0,("send_file_readX: write_data failed for file %s (%s). Terminating\n",
3216 fsp->fsp_name, strerror(errno) ));
3217 exit_server_cleanly("send_file_readX sendfile failed");
3219 nread = fake_sendfile(fsp, startpos, smb_maxcnt);
3220 if (nread == -1) {
3221 DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
3222 fsp->fsp_name, strerror(errno) ));
3223 exit_server_cleanly("send_file_readX: fake_sendfile failed");
3225 TALLOC_FREE(req->outbuf);
3226 return;
3227 } else {
3228 reply_outbuf(req, 12, smb_maxcnt);
3230 nread = read_file(fsp, smb_buf(req->outbuf), startpos,
3231 smb_maxcnt);
3232 if (nread < 0) {
3233 reply_unixerror(req, ERRDOS, ERRnoaccess);
3234 return;
3237 setup_readX_header((char *)req->outbuf, nread);
3239 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
3240 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
3242 chain_reply(req);
3244 return;
3248 /****************************************************************************
3249 Reply to a read and X.
3250 ****************************************************************************/
3252 void reply_read_and_X(struct smb_request *req)
3254 connection_struct *conn = req->conn;
3255 files_struct *fsp;
3256 SMB_OFF_T startpos;
3257 size_t smb_maxcnt;
3258 bool big_readX = False;
3259 #if 0
3260 size_t smb_mincnt = SVAL(req->inbuf,smb_vwv6);
3261 #endif
3263 START_PROFILE(SMBreadX);
3265 if ((req->wct != 10) && (req->wct != 12)) {
3266 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3267 return;
3270 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
3271 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3272 smb_maxcnt = SVAL(req->inbuf,smb_vwv5);
3274 /* If it's an IPC, pass off the pipe handler. */
3275 if (IS_IPC(conn)) {
3276 reply_pipe_read_and_X(req);
3277 END_PROFILE(SMBreadX);
3278 return;
3281 if (!check_fsp(conn, req, fsp, &current_user)) {
3282 END_PROFILE(SMBreadX);
3283 return;
3286 if (!CHECK_READ(fsp,req->inbuf)) {
3287 reply_doserror(req, ERRDOS,ERRbadaccess);
3288 END_PROFILE(SMBreadX);
3289 return;
3292 if (global_client_caps & CAP_LARGE_READX) {
3293 size_t upper_size = SVAL(req->inbuf,smb_vwv7);
3294 smb_maxcnt |= (upper_size<<16);
3295 if (upper_size > 1) {
3296 /* Can't do this on a chained packet. */
3297 if ((CVAL(req->inbuf,smb_vwv0) != 0xFF)) {
3298 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3299 END_PROFILE(SMBreadX);
3300 return;
3302 /* We currently don't do this on signed or sealed data. */
3303 if (srv_is_signing_active() || is_encrypted_packet(req->inbuf)) {
3304 reply_nterror(req, NT_STATUS_NOT_SUPPORTED);
3305 END_PROFILE(SMBreadX);
3306 return;
3308 /* Is there room in the reply for this data ? */
3309 if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) {
3310 reply_nterror(req,
3311 NT_STATUS_INVALID_PARAMETER);
3312 END_PROFILE(SMBreadX);
3313 return;
3315 big_readX = True;
3319 if (req->wct == 12) {
3320 #ifdef LARGE_SMB_OFF_T
3322 * This is a large offset (64 bit) read.
3324 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv10)) << 32);
3326 #else /* !LARGE_SMB_OFF_T */
3329 * Ensure we haven't been sent a >32 bit offset.
3332 if(IVAL(req->inbuf,smb_vwv10) != 0) {
3333 DEBUG(0,("reply_read_and_X - large offset (%x << 32) "
3334 "used and we don't support 64 bit offsets.\n",
3335 (unsigned int)IVAL(req->inbuf,smb_vwv10) ));
3336 END_PROFILE(SMBreadX);
3337 reply_doserror(req, ERRDOS, ERRbadaccess);
3338 return;
3341 #endif /* LARGE_SMB_OFF_T */
3345 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)smb_maxcnt,
3346 (SMB_BIG_UINT)startpos, READ_LOCK)) {
3347 END_PROFILE(SMBreadX);
3348 reply_doserror(req, ERRDOS, ERRlock);
3349 return;
3352 if (!big_readX &&
3353 schedule_aio_read_and_X(conn, req, fsp, startpos, smb_maxcnt)) {
3354 END_PROFILE(SMBreadX);
3355 return;
3358 send_file_readX(conn, req, fsp, startpos, smb_maxcnt);
3360 END_PROFILE(SMBreadX);
3361 return;
3364 /****************************************************************************
3365 Error replies to writebraw must have smb_wct == 1. Fix this up.
3366 ****************************************************************************/
3368 void error_to_writebrawerr(struct smb_request *req)
3370 uint8 *old_outbuf = req->outbuf;
3372 reply_outbuf(req, 1, 0);
3374 memcpy(req->outbuf, old_outbuf, smb_size);
3375 TALLOC_FREE(old_outbuf);
3378 /****************************************************************************
3379 Reply to a writebraw (core+ or LANMAN1.0 protocol).
3380 ****************************************************************************/
3382 void reply_writebraw(struct smb_request *req)
3384 connection_struct *conn = req->conn;
3385 char *buf = NULL;
3386 ssize_t nwritten=0;
3387 ssize_t total_written=0;
3388 size_t numtowrite=0;
3389 size_t tcount;
3390 SMB_OFF_T startpos;
3391 char *data=NULL;
3392 bool write_through;
3393 files_struct *fsp;
3394 NTSTATUS status;
3396 START_PROFILE(SMBwritebraw);
3399 * If we ever reply with an error, it must have the SMB command
3400 * type of SMBwritec, not SMBwriteBraw, as this tells the client
3401 * we're finished.
3403 SCVAL(req->inbuf,smb_com,SMBwritec);
3405 if (srv_is_signing_active()) {
3406 END_PROFILE(SMBwritebraw);
3407 exit_server_cleanly("reply_writebraw: SMB signing is active - "
3408 "raw reads/writes are disallowed.");
3411 if (req->wct < 12) {
3412 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3413 error_to_writebrawerr(req);
3414 END_PROFILE(SMBwritebraw);
3415 return;
3418 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3419 if (!check_fsp(conn, req, fsp, &current_user)) {
3420 error_to_writebrawerr(req);
3421 END_PROFILE(SMBwritebraw);
3422 return;
3425 if (!CHECK_WRITE(fsp)) {
3426 reply_doserror(req, ERRDOS, ERRbadaccess);
3427 error_to_writebrawerr(req);
3428 END_PROFILE(SMBwritebraw);
3429 return;
3432 tcount = IVAL(req->inbuf,smb_vwv1);
3433 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3434 write_through = BITSETW(req->inbuf+smb_vwv7,0);
3436 /* We have to deal with slightly different formats depending
3437 on whether we are using the core+ or lanman1.0 protocol */
3439 if(Protocol <= PROTOCOL_COREPLUS) {
3440 numtowrite = SVAL(smb_buf(req->inbuf),-2);
3441 data = smb_buf(req->inbuf);
3442 } else {
3443 numtowrite = SVAL(req->inbuf,smb_vwv10);
3444 data = smb_base(req->inbuf) + SVAL(req->inbuf, smb_vwv11);
3447 /* Ensure we don't write bytes past the end of this packet. */
3448 if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
3449 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3450 error_to_writebrawerr(req);
3451 END_PROFILE(SMBwritebraw);
3452 return;
3455 if (is_locked(fsp,(uint32)req->smbpid,(SMB_BIG_UINT)tcount,
3456 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3457 reply_doserror(req, ERRDOS, ERRlock);
3458 error_to_writebrawerr(req);
3459 END_PROFILE(SMBwritebraw);
3460 return;
3463 if (numtowrite>0) {
3464 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3467 DEBUG(3,("reply_writebraw: initial write fnum=%d start=%.0f num=%d "
3468 "wrote=%d sync=%d\n",
3469 fsp->fnum, (double)startpos, (int)numtowrite,
3470 (int)nwritten, (int)write_through));
3472 if (nwritten < (ssize_t)numtowrite) {
3473 reply_unixerror(req, ERRHRD, ERRdiskfull);
3474 error_to_writebrawerr(req);
3475 END_PROFILE(SMBwritebraw);
3476 return;
3479 total_written = nwritten;
3481 /* Allocate a buffer of 64k + length. */
3482 buf = TALLOC_ARRAY(NULL, char, 65540);
3483 if (!buf) {
3484 reply_doserror(req, ERRDOS, ERRnomem);
3485 error_to_writebrawerr(req);
3486 END_PROFILE(SMBwritebraw);
3487 return;
3490 /* Return a SMBwritebraw message to the redirector to tell
3491 * it to send more bytes */
3493 memcpy(buf, req->inbuf, smb_size);
3494 srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
3495 SCVAL(buf,smb_com,SMBwritebraw);
3496 SSVALS(buf,smb_vwv0,0xFFFF);
3497 show_msg(buf);
3498 if (!srv_send_smb(smbd_server_fd(),
3499 buf,
3500 IS_CONN_ENCRYPTED(conn))) {
3501 exit_server_cleanly("reply_writebraw: srv_send_smb "
3502 "failed.");
3505 /* Now read the raw data into the buffer and write it */
3506 status = read_smb_length(smbd_server_fd(), buf, SMB_SECONDARY_WAIT,
3507 &numtowrite);
3508 if (!NT_STATUS_IS_OK(status)) {
3509 exit_server_cleanly("secondary writebraw failed");
3512 /* Set up outbuf to return the correct size */
3513 reply_outbuf(req, 1, 0);
3515 if (numtowrite != 0) {
3517 if (numtowrite > 0xFFFF) {
3518 DEBUG(0,("reply_writebraw: Oversize secondary write "
3519 "raw requested (%u). Terminating\n",
3520 (unsigned int)numtowrite ));
3521 exit_server_cleanly("secondary writebraw failed");
3524 if (tcount > nwritten+numtowrite) {
3525 DEBUG(3,("reply_writebraw: Client overestimated the "
3526 "write %d %d %d\n",
3527 (int)tcount,(int)nwritten,(int)numtowrite));
3530 status = read_data(smbd_server_fd(), buf+4, numtowrite);
3532 if (!NT_STATUS_IS_OK(status)) {
3533 DEBUG(0,("reply_writebraw: Oversize secondary write "
3534 "raw read failed (%s). Terminating\n",
3535 nt_errstr(status)));
3536 exit_server_cleanly("secondary writebraw failed");
3539 nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
3540 if (nwritten == -1) {
3541 TALLOC_FREE(buf);
3542 reply_unixerror(req, ERRHRD, ERRdiskfull);
3543 error_to_writebrawerr(req);
3544 END_PROFILE(SMBwritebraw);
3545 return;
3548 if (nwritten < (ssize_t)numtowrite) {
3549 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3550 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3553 if (nwritten > 0) {
3554 total_written += nwritten;
3558 TALLOC_FREE(buf);
3559 SSVAL(req->outbuf,smb_vwv0,total_written);
3561 status = sync_file(conn, fsp, write_through);
3562 if (!NT_STATUS_IS_OK(status)) {
3563 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
3564 fsp->fsp_name, nt_errstr(status) ));
3565 reply_nterror(req, status);
3566 error_to_writebrawerr(req);
3567 END_PROFILE(SMBwritebraw);
3568 return;
3571 DEBUG(3,("reply_writebraw: secondart write fnum=%d start=%.0f num=%d "
3572 "wrote=%d\n",
3573 fsp->fnum, (double)startpos, (int)numtowrite,
3574 (int)total_written));
3576 /* We won't return a status if write through is not selected - this
3577 * follows what WfWg does */
3578 END_PROFILE(SMBwritebraw);
3580 if (!write_through && total_written==tcount) {
3582 #if RABBIT_PELLET_FIX
3584 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
3585 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this.
3586 * JRA.
3588 if (!send_keepalive(smbd_server_fd())) {
3589 exit_server_cleanly("reply_writebraw: send of "
3590 "keepalive failed");
3592 #endif
3593 TALLOC_FREE(req->outbuf);
3595 return;
3598 #undef DBGC_CLASS
3599 #define DBGC_CLASS DBGC_LOCKING
3601 /****************************************************************************
3602 Reply to a writeunlock (core+).
3603 ****************************************************************************/
3605 void reply_writeunlock(struct smb_request *req)
3607 connection_struct *conn = req->conn;
3608 ssize_t nwritten = -1;
3609 size_t numtowrite;
3610 SMB_OFF_T startpos;
3611 char *data;
3612 NTSTATUS status = NT_STATUS_OK;
3613 files_struct *fsp;
3615 START_PROFILE(SMBwriteunlock);
3617 if (req->wct < 5) {
3618 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3619 END_PROFILE(SMBwriteunlock);
3620 return;
3623 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3625 if (!check_fsp(conn, req, fsp, &current_user)) {
3626 END_PROFILE(SMBwriteunlock);
3627 return;
3630 if (!CHECK_WRITE(fsp)) {
3631 reply_doserror(req, ERRDOS,ERRbadaccess);
3632 END_PROFILE(SMBwriteunlock);
3633 return;
3636 numtowrite = SVAL(req->inbuf,smb_vwv1);
3637 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3638 data = smb_buf(req->inbuf) + 3;
3640 if (numtowrite
3641 && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
3642 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3643 reply_doserror(req, ERRDOS, ERRlock);
3644 END_PROFILE(SMBwriteunlock);
3645 return;
3648 /* The special X/Open SMB protocol handling of
3649 zero length writes is *NOT* done for
3650 this call */
3651 if(numtowrite == 0) {
3652 nwritten = 0;
3653 } else {
3654 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3657 status = sync_file(conn, fsp, False /* write through */);
3658 if (!NT_STATUS_IS_OK(status)) {
3659 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
3660 fsp->fsp_name, nt_errstr(status) ));
3661 reply_nterror(req, status);
3662 END_PROFILE(SMBwriteunlock);
3663 return;
3666 if(((nwritten < numtowrite) && (numtowrite != 0))||(nwritten < 0)) {
3667 reply_unixerror(req, ERRHRD, ERRdiskfull);
3668 END_PROFILE(SMBwriteunlock);
3669 return;
3672 if (numtowrite) {
3673 status = do_unlock(smbd_messaging_context(),
3674 fsp,
3675 req->smbpid,
3676 (SMB_BIG_UINT)numtowrite,
3677 (SMB_BIG_UINT)startpos,
3678 WINDOWS_LOCK);
3680 if (NT_STATUS_V(status)) {
3681 reply_nterror(req, status);
3682 END_PROFILE(SMBwriteunlock);
3683 return;
3687 reply_outbuf(req, 1, 0);
3689 SSVAL(req->outbuf,smb_vwv0,nwritten);
3691 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
3692 fsp->fnum, (int)numtowrite, (int)nwritten));
3694 END_PROFILE(SMBwriteunlock);
3695 return;
3698 #undef DBGC_CLASS
3699 #define DBGC_CLASS DBGC_ALL
3701 /****************************************************************************
3702 Reply to a write.
3703 ****************************************************************************/
3705 void reply_write(struct smb_request *req)
3707 connection_struct *conn = req->conn;
3708 size_t numtowrite;
3709 ssize_t nwritten = -1;
3710 SMB_OFF_T startpos;
3711 char *data;
3712 files_struct *fsp;
3713 NTSTATUS status;
3715 START_PROFILE(SMBwrite);
3717 if (req->wct < 5) {
3718 END_PROFILE(SMBwrite);
3719 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3720 return;
3723 /* If it's an IPC, pass off the pipe handler. */
3724 if (IS_IPC(conn)) {
3725 reply_pipe_write(req);
3726 END_PROFILE(SMBwrite);
3727 return;
3730 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
3732 if (!check_fsp(conn, req, fsp, &current_user)) {
3733 END_PROFILE(SMBwrite);
3734 return;
3737 if (!CHECK_WRITE(fsp)) {
3738 reply_doserror(req, ERRDOS, ERRbadaccess);
3739 END_PROFILE(SMBwrite);
3740 return;
3743 numtowrite = SVAL(req->inbuf,smb_vwv1);
3744 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
3745 data = smb_buf(req->inbuf) + 3;
3747 if (is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
3748 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
3749 reply_doserror(req, ERRDOS, ERRlock);
3750 END_PROFILE(SMBwrite);
3751 return;
3755 * X/Open SMB protocol says that if smb_vwv1 is
3756 * zero then the file size should be extended or
3757 * truncated to the size given in smb_vwv[2-3].
3760 if(numtowrite == 0) {
3762 * This is actually an allocate call, and set EOF. JRA.
3764 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
3765 if (nwritten < 0) {
3766 reply_nterror(req, NT_STATUS_DISK_FULL);
3767 END_PROFILE(SMBwrite);
3768 return;
3770 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
3771 if (nwritten < 0) {
3772 reply_nterror(req, NT_STATUS_DISK_FULL);
3773 END_PROFILE(SMBwrite);
3774 return;
3776 } else
3777 nwritten = write_file(req,fsp,data,startpos,numtowrite);
3779 status = sync_file(conn, fsp, False);
3780 if (!NT_STATUS_IS_OK(status)) {
3781 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
3782 fsp->fsp_name, nt_errstr(status) ));
3783 reply_nterror(req, status);
3784 END_PROFILE(SMBwrite);
3785 return;
3788 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
3789 reply_unixerror(req, ERRHRD, ERRdiskfull);
3790 END_PROFILE(SMBwrite);
3791 return;
3794 reply_outbuf(req, 1, 0);
3796 SSVAL(req->outbuf,smb_vwv0,nwritten);
3798 if (nwritten < (ssize_t)numtowrite) {
3799 SCVAL(req->outbuf,smb_rcls,ERRHRD);
3800 SSVAL(req->outbuf,smb_err,ERRdiskfull);
3803 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
3805 END_PROFILE(SMBwrite);
3806 return;
3809 /****************************************************************************
3810 Ensure a buffer is a valid writeX for recvfile purposes.
3811 ****************************************************************************/
3813 #define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
3814 (2*14) + /* word count (including bcc) */ \
3815 1 /* pad byte */)
3817 bool is_valid_writeX_buffer(const uint8_t *inbuf)
3819 size_t numtowrite;
3820 connection_struct *conn = NULL;
3821 unsigned int doff = 0;
3822 size_t len = smb_len_large(inbuf);
3824 if (is_encrypted_packet(inbuf)) {
3825 /* Can't do this on encrypted
3826 * connections. */
3827 return false;
3830 if (CVAL(inbuf,smb_com) != SMBwriteX) {
3831 return false;
3834 if (CVAL(inbuf,smb_vwv0) != 0xFF ||
3835 CVAL(inbuf,smb_wct) != 14) {
3836 DEBUG(10,("is_valid_writeX_buffer: chained or "
3837 "invalid word length.\n"));
3838 return false;
3841 conn = conn_find(SVAL(inbuf, smb_tid));
3842 if (conn == NULL) {
3843 DEBUG(10,("is_valid_writeX_buffer: bad tid\n"));
3844 return false;
3846 if (IS_IPC(conn)) {
3847 DEBUG(10,("is_valid_writeX_buffer: IPC$ tid\n"));
3848 return false;
3850 doff = SVAL(inbuf,smb_vwv11);
3852 numtowrite = SVAL(inbuf,smb_vwv10);
3854 if (len > doff && len - doff > 0xFFFF) {
3855 numtowrite |= (((size_t)SVAL(inbuf,smb_vwv9))<<16);
3858 if (numtowrite == 0) {
3859 DEBUG(10,("is_valid_writeX_buffer: zero write\n"));
3860 return false;
3863 /* Ensure the sizes match up. */
3864 if (doff < STANDARD_WRITE_AND_X_HEADER_SIZE) {
3865 /* no pad byte...old smbclient :-( */
3866 DEBUG(10,("is_valid_writeX_buffer: small doff %u (min %u)\n",
3867 (unsigned int)doff,
3868 (unsigned int)STANDARD_WRITE_AND_X_HEADER_SIZE));
3869 return false;
3872 if (len - doff != numtowrite) {
3873 DEBUG(10,("is_valid_writeX_buffer: doff mismatch "
3874 "len = %u, doff = %u, numtowrite = %u\n",
3875 (unsigned int)len,
3876 (unsigned int)doff,
3877 (unsigned int)numtowrite ));
3878 return false;
3881 DEBUG(10,("is_valid_writeX_buffer: true "
3882 "len = %u, doff = %u, numtowrite = %u\n",
3883 (unsigned int)len,
3884 (unsigned int)doff,
3885 (unsigned int)numtowrite ));
3887 return true;
3890 /****************************************************************************
3891 Reply to a write and X.
3892 ****************************************************************************/
3894 void reply_write_and_X(struct smb_request *req)
3896 connection_struct *conn = req->conn;
3897 files_struct *fsp;
3898 SMB_OFF_T startpos;
3899 size_t numtowrite;
3900 bool write_through;
3901 ssize_t nwritten;
3902 unsigned int smb_doff;
3903 unsigned int smblen;
3904 char *data;
3905 NTSTATUS status;
3907 START_PROFILE(SMBwriteX);
3909 if ((req->wct != 12) && (req->wct != 14)) {
3910 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3911 END_PROFILE(SMBwriteX);
3912 return;
3915 numtowrite = SVAL(req->inbuf,smb_vwv10);
3916 smb_doff = SVAL(req->inbuf,smb_vwv11);
3917 smblen = smb_len(req->inbuf);
3919 if (req->unread_bytes > 0xFFFF ||
3920 (smblen > smb_doff &&
3921 smblen - smb_doff > 0xFFFF)) {
3922 numtowrite |= (((size_t)SVAL(req->inbuf,smb_vwv9))<<16);
3925 if (req->unread_bytes) {
3926 /* Can't do a recvfile write on IPC$ */
3927 if (IS_IPC(conn)) {
3928 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
3929 END_PROFILE(SMBwriteX);
3930 return;
3932 if (numtowrite != req->unread_bytes) {
3933 reply_doserror(req, ERRDOS, ERRbadmem);
3934 END_PROFILE(SMBwriteX);
3935 return;
3937 } else {
3938 if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
3939 smb_doff + numtowrite > smblen) {
3940 reply_doserror(req, ERRDOS, ERRbadmem);
3941 END_PROFILE(SMBwriteX);
3942 return;
3946 /* If it's an IPC, pass off the pipe handler. */
3947 if (IS_IPC(conn)) {
3948 if (req->unread_bytes) {
3949 reply_doserror(req, ERRDOS, ERRbadmem);
3950 END_PROFILE(SMBwriteX);
3951 return;
3953 reply_pipe_write_and_X(req);
3954 END_PROFILE(SMBwriteX);
3955 return;
3958 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
3959 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv3);
3960 write_through = BITSETW(req->inbuf+smb_vwv7,0);
3962 if (!check_fsp(conn, req, fsp, &current_user)) {
3963 END_PROFILE(SMBwriteX);
3964 return;
3967 if (!CHECK_WRITE(fsp)) {
3968 reply_doserror(req, ERRDOS, ERRbadaccess);
3969 END_PROFILE(SMBwriteX);
3970 return;
3973 data = smb_base(req->inbuf) + smb_doff;
3975 if(req->wct == 14) {
3976 #ifdef LARGE_SMB_OFF_T
3978 * This is a large offset (64 bit) write.
3980 startpos |= (((SMB_OFF_T)IVAL(req->inbuf,smb_vwv12)) << 32);
3982 #else /* !LARGE_SMB_OFF_T */
3985 * Ensure we haven't been sent a >32 bit offset.
3988 if(IVAL(req->inbuf,smb_vwv12) != 0) {
3989 DEBUG(0,("reply_write_and_X - large offset (%x << 32) "
3990 "used and we don't support 64 bit offsets.\n",
3991 (unsigned int)IVAL(req->inbuf,smb_vwv12) ));
3992 reply_doserror(req, ERRDOS, ERRbadaccess);
3993 END_PROFILE(SMBwriteX);
3994 return;
3997 #endif /* LARGE_SMB_OFF_T */
4000 if (is_locked(fsp,(uint32)req->smbpid,
4001 (SMB_BIG_UINT)numtowrite,
4002 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
4003 reply_doserror(req, ERRDOS, ERRlock);
4004 END_PROFILE(SMBwriteX);
4005 return;
4008 /* X/Open SMB protocol says that, unlike SMBwrite
4009 if the length is zero then NO truncation is
4010 done, just a write of zero. To truncate a file,
4011 use SMBwrite. */
4013 if(numtowrite == 0) {
4014 nwritten = 0;
4015 } else {
4017 if ((req->unread_bytes == 0) &&
4018 schedule_aio_write_and_X(conn, req, fsp, data, startpos,
4019 numtowrite)) {
4020 END_PROFILE(SMBwriteX);
4021 return;
4024 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4027 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4028 reply_unixerror(req, ERRHRD, ERRdiskfull);
4029 END_PROFILE(SMBwriteX);
4030 return;
4033 reply_outbuf(req, 6, 0);
4034 SSVAL(req->outbuf,smb_vwv2,nwritten);
4035 SSVAL(req->outbuf,smb_vwv4,nwritten>>16);
4037 if (nwritten < (ssize_t)numtowrite) {
4038 SCVAL(req->outbuf,smb_rcls,ERRHRD);
4039 SSVAL(req->outbuf,smb_err,ERRdiskfull);
4042 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
4043 fsp->fnum, (int)numtowrite, (int)nwritten));
4045 status = sync_file(conn, fsp, write_through);
4046 if (!NT_STATUS_IS_OK(status)) {
4047 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
4048 fsp->fsp_name, nt_errstr(status) ));
4049 reply_nterror(req, status);
4050 END_PROFILE(SMBwriteX);
4051 return;
4054 END_PROFILE(SMBwriteX);
4055 chain_reply(req);
4056 return;
4059 /****************************************************************************
4060 Reply to a lseek.
4061 ****************************************************************************/
4063 void reply_lseek(struct smb_request *req)
4065 connection_struct *conn = req->conn;
4066 SMB_OFF_T startpos;
4067 SMB_OFF_T res= -1;
4068 int mode,umode;
4069 files_struct *fsp;
4071 START_PROFILE(SMBlseek);
4073 if (req->wct < 4) {
4074 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4075 END_PROFILE(SMBlseek);
4076 return;
4079 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4081 if (!check_fsp(conn, req, fsp, &current_user)) {
4082 return;
4085 flush_write_cache(fsp, SEEK_FLUSH);
4087 mode = SVAL(req->inbuf,smb_vwv1) & 3;
4088 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
4089 startpos = (SMB_OFF_T)IVALS(req->inbuf,smb_vwv2);
4091 switch (mode) {
4092 case 0:
4093 umode = SEEK_SET;
4094 res = startpos;
4095 break;
4096 case 1:
4097 umode = SEEK_CUR;
4098 res = fsp->fh->pos + startpos;
4099 break;
4100 case 2:
4101 umode = SEEK_END;
4102 break;
4103 default:
4104 umode = SEEK_SET;
4105 res = startpos;
4106 break;
4109 if (umode == SEEK_END) {
4110 if((res = SMB_VFS_LSEEK(fsp,startpos,umode)) == -1) {
4111 if(errno == EINVAL) {
4112 SMB_OFF_T current_pos = startpos;
4113 SMB_STRUCT_STAT sbuf;
4115 if(SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
4116 reply_unixerror(req, ERRDOS,
4117 ERRnoaccess);
4118 END_PROFILE(SMBlseek);
4119 return;
4122 current_pos += sbuf.st_size;
4123 if(current_pos < 0)
4124 res = SMB_VFS_LSEEK(fsp,0,SEEK_SET);
4128 if(res == -1) {
4129 reply_unixerror(req, ERRDOS, ERRnoaccess);
4130 END_PROFILE(SMBlseek);
4131 return;
4135 fsp->fh->pos = res;
4137 reply_outbuf(req, 2, 0);
4138 SIVAL(req->outbuf,smb_vwv0,res);
4140 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
4141 fsp->fnum, (double)startpos, (double)res, mode));
4143 END_PROFILE(SMBlseek);
4144 return;
4147 /****************************************************************************
4148 Reply to a flush.
4149 ****************************************************************************/
4151 void reply_flush(struct smb_request *req)
4153 connection_struct *conn = req->conn;
4154 uint16 fnum;
4155 files_struct *fsp;
4157 START_PROFILE(SMBflush);
4159 if (req->wct < 1) {
4160 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4161 return;
4164 fnum = SVAL(req->inbuf,smb_vwv0);
4165 fsp = file_fsp(fnum);
4167 if ((fnum != 0xFFFF) && !check_fsp(conn, req, fsp, &current_user)) {
4168 return;
4171 if (!fsp) {
4172 file_sync_all(conn);
4173 } else {
4174 NTSTATUS status = sync_file(conn, fsp, True);
4175 if (!NT_STATUS_IS_OK(status)) {
4176 DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
4177 fsp->fsp_name, nt_errstr(status) ));
4178 reply_nterror(req, status);
4179 END_PROFILE(SMBflush);
4180 return;
4184 reply_outbuf(req, 0, 0);
4186 DEBUG(3,("flush\n"));
4187 END_PROFILE(SMBflush);
4188 return;
4191 /****************************************************************************
4192 Reply to a exit.
4193 conn POINTER CAN BE NULL HERE !
4194 ****************************************************************************/
4196 void reply_exit(struct smb_request *req)
4198 START_PROFILE(SMBexit);
4200 file_close_pid(req->smbpid, req->vuid);
4202 reply_outbuf(req, 0, 0);
4204 DEBUG(3,("exit\n"));
4206 END_PROFILE(SMBexit);
4207 return;
4210 /****************************************************************************
4211 Reply to a close - has to deal with closing a directory opened by NT SMB's.
4212 ****************************************************************************/
4214 void reply_close(struct smb_request *req)
4216 connection_struct *conn = req->conn;
4217 NTSTATUS status = NT_STATUS_OK;
4218 files_struct *fsp = NULL;
4219 START_PROFILE(SMBclose);
4221 if (req->wct < 3) {
4222 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4223 END_PROFILE(SMBclose);
4224 return;
4227 /* If it's an IPC, pass off to the pipe handler. */
4228 if (IS_IPC(conn)) {
4229 reply_pipe_close(conn, req);
4230 END_PROFILE(SMBclose);
4231 return;
4234 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4237 * We can only use CHECK_FSP if we know it's not a directory.
4240 if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) {
4241 reply_doserror(req, ERRDOS, ERRbadfid);
4242 END_PROFILE(SMBclose);
4243 return;
4246 if(fsp->is_directory) {
4248 * Special case - close NT SMB directory handle.
4250 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
4251 status = close_file(fsp,NORMAL_CLOSE);
4252 } else {
4253 time_t t;
4255 * Close ordinary file.
4258 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
4259 fsp->fh->fd, fsp->fnum,
4260 conn->num_files_open));
4263 * Take care of any time sent in the close.
4266 t = srv_make_unix_date3(req->inbuf+smb_vwv1);
4267 set_close_write_time(fsp, convert_time_t_to_timespec(t));
4270 * close_file() returns the unix errno if an error
4271 * was detected on close - normally this is due to
4272 * a disk full error. If not then it was probably an I/O error.
4275 status = close_file(fsp,NORMAL_CLOSE);
4278 if (!NT_STATUS_IS_OK(status)) {
4279 reply_nterror(req, status);
4280 END_PROFILE(SMBclose);
4281 return;
4284 reply_outbuf(req, 0, 0);
4285 END_PROFILE(SMBclose);
4286 return;
4289 /****************************************************************************
4290 Reply to a writeclose (Core+ protocol).
4291 ****************************************************************************/
4293 void reply_writeclose(struct smb_request *req)
4295 connection_struct *conn = req->conn;
4296 size_t numtowrite;
4297 ssize_t nwritten = -1;
4298 NTSTATUS close_status = NT_STATUS_OK;
4299 SMB_OFF_T startpos;
4300 char *data;
4301 struct timespec mtime;
4302 files_struct *fsp;
4304 START_PROFILE(SMBwriteclose);
4306 if (req->wct < 6) {
4307 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4308 END_PROFILE(SMBwriteclose);
4309 return;
4312 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4314 if (!check_fsp(conn, req, fsp, &current_user)) {
4315 END_PROFILE(SMBwriteclose);
4316 return;
4318 if (!CHECK_WRITE(fsp)) {
4319 reply_doserror(req, ERRDOS,ERRbadaccess);
4320 END_PROFILE(SMBwriteclose);
4321 return;
4324 numtowrite = SVAL(req->inbuf,smb_vwv1);
4325 startpos = IVAL_TO_SMB_OFF_T(req->inbuf,smb_vwv2);
4326 mtime = convert_time_t_to_timespec(srv_make_unix_date3(
4327 req->inbuf+smb_vwv4));
4328 data = smb_buf(req->inbuf) + 1;
4330 if (numtowrite
4331 && is_locked(fsp, (uint32)req->smbpid, (SMB_BIG_UINT)numtowrite,
4332 (SMB_BIG_UINT)startpos, WRITE_LOCK)) {
4333 reply_doserror(req, ERRDOS,ERRlock);
4334 END_PROFILE(SMBwriteclose);
4335 return;
4338 nwritten = write_file(req,fsp,data,startpos,numtowrite);
4340 set_close_write_time(fsp, mtime);
4343 * More insanity. W2K only closes the file if writelen > 0.
4344 * JRA.
4347 if (numtowrite) {
4348 DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
4349 fsp->fsp_name ));
4350 close_status = close_file(fsp,NORMAL_CLOSE);
4353 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
4354 fsp->fnum, (int)numtowrite, (int)nwritten,
4355 conn->num_files_open));
4357 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
4358 reply_doserror(req, ERRHRD, ERRdiskfull);
4359 END_PROFILE(SMBwriteclose);
4360 return;
4363 if(!NT_STATUS_IS_OK(close_status)) {
4364 reply_nterror(req, close_status);
4365 END_PROFILE(SMBwriteclose);
4366 return;
4369 reply_outbuf(req, 1, 0);
4371 SSVAL(req->outbuf,smb_vwv0,nwritten);
4372 END_PROFILE(SMBwriteclose);
4373 return;
4376 #undef DBGC_CLASS
4377 #define DBGC_CLASS DBGC_LOCKING
4379 /****************************************************************************
4380 Reply to a lock.
4381 ****************************************************************************/
4383 void reply_lock(struct smb_request *req)
4385 connection_struct *conn = req->conn;
4386 SMB_BIG_UINT count,offset;
4387 NTSTATUS status;
4388 files_struct *fsp;
4389 struct byte_range_lock *br_lck = NULL;
4391 START_PROFILE(SMBlock);
4393 if (req->wct < 5) {
4394 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4395 END_PROFILE(SMBlock);
4396 return;
4399 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4401 if (!check_fsp(conn, req, fsp, &current_user)) {
4402 END_PROFILE(SMBlock);
4403 return;
4406 release_level_2_oplocks_on_change(fsp);
4408 count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
4409 offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
4411 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4412 fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
4414 br_lck = do_lock(smbd_messaging_context(),
4415 fsp,
4416 req->smbpid,
4417 count,
4418 offset,
4419 WRITE_LOCK,
4420 WINDOWS_LOCK,
4421 False, /* Non-blocking lock. */
4422 &status,
4423 NULL);
4425 TALLOC_FREE(br_lck);
4427 if (NT_STATUS_V(status)) {
4428 reply_nterror(req, status);
4429 END_PROFILE(SMBlock);
4430 return;
4433 reply_outbuf(req, 0, 0);
4435 END_PROFILE(SMBlock);
4436 return;
4439 /****************************************************************************
4440 Reply to a unlock.
4441 ****************************************************************************/
4443 void reply_unlock(struct smb_request *req)
4445 connection_struct *conn = req->conn;
4446 SMB_BIG_UINT count,offset;
4447 NTSTATUS status;
4448 files_struct *fsp;
4450 START_PROFILE(SMBunlock);
4452 if (req->wct < 5) {
4453 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4454 END_PROFILE(SMBunlock);
4455 return;
4458 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4460 if (!check_fsp(conn, req, fsp, &current_user)) {
4461 END_PROFILE(SMBunlock);
4462 return;
4465 count = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv1);
4466 offset = (SMB_BIG_UINT)IVAL(req->inbuf,smb_vwv3);
4468 status = do_unlock(smbd_messaging_context(),
4469 fsp,
4470 req->smbpid,
4471 count,
4472 offset,
4473 WINDOWS_LOCK);
4475 if (NT_STATUS_V(status)) {
4476 reply_nterror(req, status);
4477 END_PROFILE(SMBunlock);
4478 return;
4481 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
4482 fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
4484 reply_outbuf(req, 0, 0);
4486 END_PROFILE(SMBunlock);
4487 return;
4490 #undef DBGC_CLASS
4491 #define DBGC_CLASS DBGC_ALL
4493 /****************************************************************************
4494 Reply to a tdis.
4495 conn POINTER CAN BE NULL HERE !
4496 ****************************************************************************/
4498 void reply_tdis(struct smb_request *req)
4500 connection_struct *conn = req->conn;
4501 START_PROFILE(SMBtdis);
4503 if (!conn) {
4504 DEBUG(4,("Invalid connection in tdis\n"));
4505 reply_doserror(req, ERRSRV, ERRinvnid);
4506 END_PROFILE(SMBtdis);
4507 return;
4510 conn->used = False;
4512 close_cnum(conn,req->vuid);
4513 req->conn = NULL;
4515 reply_outbuf(req, 0, 0);
4516 END_PROFILE(SMBtdis);
4517 return;
4520 /****************************************************************************
4521 Reply to a echo.
4522 conn POINTER CAN BE NULL HERE !
4523 ****************************************************************************/
4525 void reply_echo(struct smb_request *req)
4527 connection_struct *conn = req->conn;
4528 int smb_reverb;
4529 int seq_num;
4530 unsigned int data_len = smb_buflen(req->inbuf);
4532 START_PROFILE(SMBecho);
4534 if (req->wct < 1) {
4535 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4536 END_PROFILE(SMBecho);
4537 return;
4540 if (data_len > BUFFER_SIZE) {
4541 DEBUG(0,("reply_echo: data_len too large.\n"));
4542 reply_nterror(req, NT_STATUS_INSUFFICIENT_RESOURCES);
4543 END_PROFILE(SMBecho);
4544 return;
4547 smb_reverb = SVAL(req->inbuf,smb_vwv0);
4549 reply_outbuf(req, 1, data_len);
4551 /* copy any incoming data back out */
4552 if (data_len > 0) {
4553 memcpy(smb_buf(req->outbuf),smb_buf(req->inbuf),data_len);
4556 if (smb_reverb > 100) {
4557 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
4558 smb_reverb = 100;
4561 for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
4562 SSVAL(req->outbuf,smb_vwv0,seq_num);
4564 show_msg((char *)req->outbuf);
4565 if (!srv_send_smb(smbd_server_fd(),
4566 (char *)req->outbuf,
4567 IS_CONN_ENCRYPTED(conn)||req->encrypted))
4568 exit_server_cleanly("reply_echo: srv_send_smb failed.");
4571 DEBUG(3,("echo %d times\n", smb_reverb));
4573 TALLOC_FREE(req->outbuf);
4575 smb_echo_count++;
4577 END_PROFILE(SMBecho);
4578 return;
4581 /****************************************************************************
4582 Reply to a printopen.
4583 ****************************************************************************/
4585 void reply_printopen(struct smb_request *req)
4587 connection_struct *conn = req->conn;
4588 files_struct *fsp;
4589 NTSTATUS status;
4591 START_PROFILE(SMBsplopen);
4593 if (req->wct < 2) {
4594 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4595 END_PROFILE(SMBsplopen);
4596 return;
4599 if (!CAN_PRINT(conn)) {
4600 reply_doserror(req, ERRDOS, ERRnoaccess);
4601 END_PROFILE(SMBsplopen);
4602 return;
4605 /* Open for exclusive use, write only. */
4606 status = print_fsp_open(conn, NULL, &fsp);
4608 if (!NT_STATUS_IS_OK(status)) {
4609 reply_nterror(req, status);
4610 END_PROFILE(SMBsplopen);
4611 return;
4614 reply_outbuf(req, 1, 0);
4615 SSVAL(req->outbuf,smb_vwv0,fsp->fnum);
4617 DEBUG(3,("openprint fd=%d fnum=%d\n",
4618 fsp->fh->fd, fsp->fnum));
4620 END_PROFILE(SMBsplopen);
4621 return;
4624 /****************************************************************************
4625 Reply to a printclose.
4626 ****************************************************************************/
4628 void reply_printclose(struct smb_request *req)
4630 connection_struct *conn = req->conn;
4631 files_struct *fsp;
4632 NTSTATUS status;
4634 START_PROFILE(SMBsplclose);
4636 if (req->wct < 1) {
4637 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4638 END_PROFILE(SMBsplclose);
4639 return;
4642 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4644 if (!check_fsp(conn, req, fsp, &current_user)) {
4645 END_PROFILE(SMBsplclose);
4646 return;
4649 if (!CAN_PRINT(conn)) {
4650 reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRerror));
4651 END_PROFILE(SMBsplclose);
4652 return;
4655 DEBUG(3,("printclose fd=%d fnum=%d\n",
4656 fsp->fh->fd,fsp->fnum));
4658 status = close_file(fsp,NORMAL_CLOSE);
4660 if(!NT_STATUS_IS_OK(status)) {
4661 reply_nterror(req, status);
4662 END_PROFILE(SMBsplclose);
4663 return;
4666 END_PROFILE(SMBsplclose);
4667 return;
4670 /****************************************************************************
4671 Reply to a printqueue.
4672 ****************************************************************************/
4674 void reply_printqueue(struct smb_request *req)
4676 connection_struct *conn = req->conn;
4677 int max_count;
4678 int start_index;
4680 START_PROFILE(SMBsplretq);
4682 if (req->wct < 2) {
4683 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4684 END_PROFILE(SMBsplretq);
4685 return;
4688 max_count = SVAL(req->inbuf,smb_vwv0);
4689 start_index = SVAL(req->inbuf,smb_vwv1);
4691 /* we used to allow the client to get the cnum wrong, but that
4692 is really quite gross and only worked when there was only
4693 one printer - I think we should now only accept it if they
4694 get it right (tridge) */
4695 if (!CAN_PRINT(conn)) {
4696 reply_doserror(req, ERRDOS, ERRnoaccess);
4697 END_PROFILE(SMBsplretq);
4698 return;
4701 reply_outbuf(req, 2, 3);
4702 SSVAL(req->outbuf,smb_vwv0,0);
4703 SSVAL(req->outbuf,smb_vwv1,0);
4704 SCVAL(smb_buf(req->outbuf),0,1);
4705 SSVAL(smb_buf(req->outbuf),1,0);
4707 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
4708 start_index, max_count));
4711 print_queue_struct *queue = NULL;
4712 print_status_struct status;
4713 int count = print_queue_status(SNUM(conn), &queue, &status);
4714 int num_to_get = ABS(max_count);
4715 int first = (max_count>0?start_index:start_index+max_count+1);
4716 int i;
4718 if (first >= count)
4719 num_to_get = 0;
4720 else
4721 num_to_get = MIN(num_to_get,count-first);
4724 for (i=first;i<first+num_to_get;i++) {
4725 char blob[28];
4726 char *p = blob;
4728 srv_put_dos_date2(p,0,queue[i].time);
4729 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
4730 SSVAL(p,5, queue[i].job);
4731 SIVAL(p,7,queue[i].size);
4732 SCVAL(p,11,0);
4733 srvstr_push(blob, req->flags2, p+12,
4734 queue[i].fs_user, 16, STR_ASCII);
4736 if (message_push_blob(
4737 &req->outbuf,
4738 data_blob_const(
4739 blob, sizeof(blob))) == -1) {
4740 reply_nterror(req, NT_STATUS_NO_MEMORY);
4741 END_PROFILE(SMBsplretq);
4742 return;
4746 if (count > 0) {
4747 SSVAL(req->outbuf,smb_vwv0,count);
4748 SSVAL(req->outbuf,smb_vwv1,
4749 (max_count>0?first+count:first-1));
4750 SCVAL(smb_buf(req->outbuf),0,1);
4751 SSVAL(smb_buf(req->outbuf),1,28*count);
4754 SAFE_FREE(queue);
4756 DEBUG(3,("%d entries returned in queue\n",count));
4759 END_PROFILE(SMBsplretq);
4760 return;
4763 /****************************************************************************
4764 Reply to a printwrite.
4765 ****************************************************************************/
4767 void reply_printwrite(struct smb_request *req)
4769 connection_struct *conn = req->conn;
4770 int numtowrite;
4771 char *data;
4772 files_struct *fsp;
4774 START_PROFILE(SMBsplwr);
4776 if (req->wct < 1) {
4777 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4778 END_PROFILE(SMBsplwr);
4779 return;
4782 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
4784 if (!check_fsp(conn, req, fsp, &current_user)) {
4785 END_PROFILE(SMBsplwr);
4786 return;
4789 if (!CAN_PRINT(conn)) {
4790 reply_doserror(req, ERRDOS, ERRnoaccess);
4791 END_PROFILE(SMBsplwr);
4792 return;
4795 if (!CHECK_WRITE(fsp)) {
4796 reply_doserror(req, ERRDOS, ERRbadaccess);
4797 END_PROFILE(SMBsplwr);
4798 return;
4801 numtowrite = SVAL(smb_buf(req->inbuf),1);
4803 if (smb_buflen(req->inbuf) < numtowrite + 3) {
4804 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
4805 END_PROFILE(SMBsplwr);
4806 return;
4809 data = smb_buf(req->inbuf) + 3;
4811 if (write_file(req,fsp,data,-1,numtowrite) != numtowrite) {
4812 reply_unixerror(req, ERRHRD, ERRdiskfull);
4813 END_PROFILE(SMBsplwr);
4814 return;
4817 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
4819 END_PROFILE(SMBsplwr);
4820 return;
4823 /****************************************************************************
4824 Reply to a mkdir.
4825 ****************************************************************************/
4827 void reply_mkdir(struct smb_request *req)
4829 connection_struct *conn = req->conn;
4830 char *directory = NULL;
4831 NTSTATUS status;
4832 SMB_STRUCT_STAT sbuf;
4833 TALLOC_CTX *ctx = talloc_tos();
4835 START_PROFILE(SMBmkdir);
4837 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
4838 smb_buf(req->inbuf) + 1, 0,
4839 STR_TERMINATE, &status);
4840 if (!NT_STATUS_IS_OK(status)) {
4841 reply_nterror(req, status);
4842 END_PROFILE(SMBmkdir);
4843 return;
4846 status = resolve_dfspath(ctx, conn,
4847 req->flags2 & FLAGS2_DFS_PATHNAMES,
4848 directory,
4849 &directory);
4850 if (!NT_STATUS_IS_OK(status)) {
4851 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
4852 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
4853 ERRSRV, ERRbadpath);
4854 END_PROFILE(SMBmkdir);
4855 return;
4857 reply_nterror(req, status);
4858 END_PROFILE(SMBmkdir);
4859 return;
4862 status = unix_convert(ctx, conn, directory, False, &directory, NULL, &sbuf);
4863 if (!NT_STATUS_IS_OK(status)) {
4864 reply_nterror(req, status);
4865 END_PROFILE(SMBmkdir);
4866 return;
4869 status = check_name(conn, directory);
4870 if (!NT_STATUS_IS_OK(status)) {
4871 reply_nterror(req, status);
4872 END_PROFILE(SMBmkdir);
4873 return;
4876 status = create_directory(conn, req, directory);
4878 DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
4880 if (!NT_STATUS_IS_OK(status)) {
4882 if (!use_nt_status()
4883 && NT_STATUS_EQUAL(status,
4884 NT_STATUS_OBJECT_NAME_COLLISION)) {
4886 * Yes, in the DOS error code case we get a
4887 * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
4888 * samba4 torture test.
4890 status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
4893 reply_nterror(req, status);
4894 END_PROFILE(SMBmkdir);
4895 return;
4898 reply_outbuf(req, 0, 0);
4900 DEBUG( 3, ( "mkdir %s\n", directory ) );
4902 END_PROFILE(SMBmkdir);
4903 return;
4906 /****************************************************************************
4907 Static function used by reply_rmdir to delete an entire directory
4908 tree recursively. Return True on ok, False on fail.
4909 ****************************************************************************/
4911 static bool recursive_rmdir(TALLOC_CTX *ctx,
4912 connection_struct *conn,
4913 char *directory)
4915 const char *dname = NULL;
4916 bool ret = True;
4917 long offset = 0;
4918 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn, directory,
4919 NULL, 0);
4921 if(dir_hnd == NULL)
4922 return False;
4924 while((dname = ReadDirName(dir_hnd, &offset))) {
4925 char *fullname = NULL;
4926 SMB_STRUCT_STAT st;
4928 if (ISDOT(dname) || ISDOTDOT(dname)) {
4929 continue;
4932 if (!is_visible_file(conn, directory, dname, &st, False)) {
4933 continue;
4936 /* Construct the full name. */
4937 fullname = talloc_asprintf(ctx,
4938 "%s/%s",
4939 directory,
4940 dname);
4941 if (!fullname) {
4942 errno = ENOMEM;
4943 ret = False;
4944 break;
4947 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
4948 ret = False;
4949 break;
4952 if(st.st_mode & S_IFDIR) {
4953 if(!recursive_rmdir(ctx, conn, fullname)) {
4954 ret = False;
4955 break;
4957 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
4958 ret = False;
4959 break;
4961 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
4962 ret = False;
4963 break;
4965 TALLOC_FREE(fullname);
4967 TALLOC_FREE(dir_hnd);
4968 return ret;
4971 /****************************************************************************
4972 The internals of the rmdir code - called elsewhere.
4973 ****************************************************************************/
4975 NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
4976 connection_struct *conn,
4977 const char *directory)
4979 int ret;
4980 SMB_STRUCT_STAT st;
4982 /* Might be a symlink. */
4983 if(SMB_VFS_LSTAT(conn, directory, &st) != 0) {
4984 return map_nt_error_from_unix(errno);
4987 if (S_ISLNK(st.st_mode)) {
4988 /* Is what it points to a directory ? */
4989 if(SMB_VFS_STAT(conn, directory, &st) != 0) {
4990 return map_nt_error_from_unix(errno);
4992 if (!(S_ISDIR(st.st_mode))) {
4993 return NT_STATUS_NOT_A_DIRECTORY;
4995 ret = SMB_VFS_UNLINK(conn,directory);
4996 } else {
4997 ret = SMB_VFS_RMDIR(conn,directory);
4999 if (ret == 0) {
5000 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5001 FILE_NOTIFY_CHANGE_DIR_NAME,
5002 directory);
5003 return NT_STATUS_OK;
5006 if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
5008 * Check to see if the only thing in this directory are
5009 * vetoed files/directories. If so then delete them and
5010 * retry. If we fail to delete any of them (and we *don't*
5011 * do a recursive delete) then fail the rmdir.
5013 const char *dname;
5014 long dirpos = 0;
5015 struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
5016 directory, NULL, 0);
5018 if(dir_hnd == NULL) {
5019 errno = ENOTEMPTY;
5020 goto err;
5023 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
5024 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
5025 continue;
5026 if (!is_visible_file(conn, directory, dname, &st, False))
5027 continue;
5028 if(!IS_VETO_PATH(conn, dname)) {
5029 TALLOC_FREE(dir_hnd);
5030 errno = ENOTEMPTY;
5031 goto err;
5035 /* We only have veto files/directories. Recursive delete. */
5037 RewindDir(dir_hnd,&dirpos);
5038 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
5039 char *fullname = NULL;
5041 if (ISDOT(dname) || ISDOTDOT(dname)) {
5042 continue;
5044 if (!is_visible_file(conn, directory, dname, &st, False)) {
5045 continue;
5048 fullname = talloc_asprintf(ctx,
5049 "%s/%s",
5050 directory,
5051 dname);
5053 if(!fullname) {
5054 errno = ENOMEM;
5055 break;
5058 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
5059 break;
5061 if(st.st_mode & S_IFDIR) {
5062 if(lp_recursive_veto_delete(SNUM(conn))) {
5063 if(!recursive_rmdir(ctx, conn, fullname))
5064 break;
5066 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
5067 break;
5069 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
5070 break;
5072 TALLOC_FREE(fullname);
5074 TALLOC_FREE(dir_hnd);
5075 /* Retry the rmdir */
5076 ret = SMB_VFS_RMDIR(conn,directory);
5079 err:
5081 if (ret != 0) {
5082 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
5083 "%s\n", directory,strerror(errno)));
5084 return map_nt_error_from_unix(errno);
5087 notify_fname(conn, NOTIFY_ACTION_REMOVED,
5088 FILE_NOTIFY_CHANGE_DIR_NAME,
5089 directory);
5091 return NT_STATUS_OK;
5094 /****************************************************************************
5095 Reply to a rmdir.
5096 ****************************************************************************/
5098 void reply_rmdir(struct smb_request *req)
5100 connection_struct *conn = req->conn;
5101 char *directory = NULL;
5102 SMB_STRUCT_STAT sbuf;
5103 NTSTATUS status;
5104 TALLOC_CTX *ctx = talloc_tos();
5106 START_PROFILE(SMBrmdir);
5108 srvstr_get_path(ctx, (char *)req->inbuf, req->flags2, &directory,
5109 smb_buf(req->inbuf) + 1, 0,
5110 STR_TERMINATE, &status);
5111 if (!NT_STATUS_IS_OK(status)) {
5112 reply_nterror(req, status);
5113 END_PROFILE(SMBrmdir);
5114 return;
5117 status = resolve_dfspath(ctx, conn,
5118 req->flags2 & FLAGS2_DFS_PATHNAMES,
5119 directory,
5120 &directory);
5121 if (!NT_STATUS_IS_OK(status)) {
5122 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5123 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5124 ERRSRV, ERRbadpath);
5125 END_PROFILE(SMBrmdir);
5126 return;
5128 reply_nterror(req, status);
5129 END_PROFILE(SMBrmdir);
5130 return;
5133 status = unix_convert(ctx, conn, directory, False, &directory,
5134 NULL, &sbuf);
5135 if (!NT_STATUS_IS_OK(status)) {
5136 reply_nterror(req, status);
5137 END_PROFILE(SMBrmdir);
5138 return;
5141 status = check_name(conn, directory);
5142 if (!NT_STATUS_IS_OK(status)) {
5143 reply_nterror(req, status);
5144 END_PROFILE(SMBrmdir);
5145 return;
5148 dptr_closepath(directory, req->smbpid);
5149 status = rmdir_internals(ctx, conn, directory);
5150 if (!NT_STATUS_IS_OK(status)) {
5151 reply_nterror(req, status);
5152 END_PROFILE(SMBrmdir);
5153 return;
5156 reply_outbuf(req, 0, 0);
5158 DEBUG( 3, ( "rmdir %s\n", directory ) );
5160 END_PROFILE(SMBrmdir);
5161 return;
5164 /*******************************************************************
5165 Resolve wildcards in a filename rename.
5166 ********************************************************************/
5168 static bool resolve_wildcards(TALLOC_CTX *ctx,
5169 const char *name1,
5170 const char *name2,
5171 char **pp_newname)
5173 char *name2_copy = NULL;
5174 char *root1 = NULL;
5175 char *root2 = NULL;
5176 char *ext1 = NULL;
5177 char *ext2 = NULL;
5178 char *p,*p2, *pname1, *pname2;
5180 name2_copy = talloc_strdup(ctx, name2);
5181 if (!name2_copy) {
5182 return False;
5185 pname1 = strrchr_m(name1,'/');
5186 pname2 = strrchr_m(name2_copy,'/');
5188 if (!pname1 || !pname2) {
5189 return False;
5192 /* Truncate the copy of name2 at the last '/' */
5193 *pname2 = '\0';
5195 /* Now go past the '/' */
5196 pname1++;
5197 pname2++;
5199 root1 = talloc_strdup(ctx, pname1);
5200 root2 = talloc_strdup(ctx, pname2);
5202 if (!root1 || !root2) {
5203 return False;
5206 p = strrchr_m(root1,'.');
5207 if (p) {
5208 *p = 0;
5209 ext1 = talloc_strdup(ctx, p+1);
5210 } else {
5211 ext1 = talloc_strdup(ctx, "");
5213 p = strrchr_m(root2,'.');
5214 if (p) {
5215 *p = 0;
5216 ext2 = talloc_strdup(ctx, p+1);
5217 } else {
5218 ext2 = talloc_strdup(ctx, "");
5221 if (!ext1 || !ext2) {
5222 return False;
5225 p = root1;
5226 p2 = root2;
5227 while (*p2) {
5228 if (*p2 == '?') {
5229 /* Hmmm. Should this be mb-aware ? */
5230 *p2 = *p;
5231 p2++;
5232 } else if (*p2 == '*') {
5233 *p2 = '\0';
5234 root2 = talloc_asprintf(ctx, "%s%s",
5235 root2,
5237 if (!root2) {
5238 return False;
5240 break;
5241 } else {
5242 p2++;
5244 if (*p) {
5245 p++;
5249 p = ext1;
5250 p2 = ext2;
5251 while (*p2) {
5252 if (*p2 == '?') {
5253 /* Hmmm. Should this be mb-aware ? */
5254 *p2 = *p;
5255 p2++;
5256 } else if (*p2 == '*') {
5257 *p2 = '\0';
5258 ext2 = talloc_asprintf(ctx, "%s%s",
5259 ext2,
5261 if (!ext2) {
5262 return False;
5264 break;
5265 } else {
5266 p2++;
5268 if (*p) {
5269 p++;
5273 if (*ext2) {
5274 *pp_newname = talloc_asprintf(ctx, "%s/%s.%s",
5275 name2_copy,
5276 root2,
5277 ext2);
5278 } else {
5279 *pp_newname = talloc_asprintf(ctx, "%s/%s",
5280 name2_copy,
5281 root2);
5284 if (!*pp_newname) {
5285 return False;
5288 return True;
5291 /****************************************************************************
5292 Ensure open files have their names updated. Updated to notify other smbd's
5293 asynchronously.
5294 ****************************************************************************/
5296 static void rename_open_files(connection_struct *conn,
5297 struct share_mode_lock *lck,
5298 const char *newname)
5300 files_struct *fsp;
5301 bool did_rename = False;
5303 for(fsp = file_find_di_first(lck->id); fsp;
5304 fsp = file_find_di_next(fsp)) {
5305 /* fsp_name is a relative path under the fsp. To change this for other
5306 sharepaths we need to manipulate relative paths. */
5307 /* TODO - create the absolute path and manipulate the newname
5308 relative to the sharepath. */
5309 if (!strequal(fsp->conn->connectpath, conn->connectpath)) {
5310 continue;
5312 DEBUG(10,("rename_open_files: renaming file fnum %d (file_id %s) from %s -> %s\n",
5313 fsp->fnum, file_id_string_tos(&fsp->file_id),
5314 fsp->fsp_name, newname ));
5315 string_set(&fsp->fsp_name, newname);
5316 did_rename = True;
5319 if (!did_rename) {
5320 DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
5321 file_id_string_tos(&lck->id), newname ));
5324 /* Send messages to all smbd's (not ourself) that the name has changed. */
5325 rename_share_filename(smbd_messaging_context(), lck, conn->connectpath,
5326 newname);
5329 /****************************************************************************
5330 We need to check if the source path is a parent directory of the destination
5331 (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
5332 refuse the rename with a sharing violation. Under UNIX the above call can
5333 *succeed* if /foo/bar/baz is a symlink to another area in the share. We
5334 probably need to check that the client is a Windows one before disallowing
5335 this as a UNIX client (one with UNIX extensions) can know the source is a
5336 symlink and make this decision intelligently. Found by an excellent bug
5337 report from <AndyLiebman@aol.com>.
5338 ****************************************************************************/
5340 static bool rename_path_prefix_equal(const char *src, const char *dest)
5342 const char *psrc = src;
5343 const char *pdst = dest;
5344 size_t slen;
5346 if (psrc[0] == '.' && psrc[1] == '/') {
5347 psrc += 2;
5349 if (pdst[0] == '.' && pdst[1] == '/') {
5350 pdst += 2;
5352 if ((slen = strlen(psrc)) > strlen(pdst)) {
5353 return False;
5355 return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
5359 * Do the notify calls from a rename
5362 static void notify_rename(connection_struct *conn, bool is_dir,
5363 const char *oldpath, const char *newpath)
5365 char *olddir, *newdir;
5366 const char *oldname, *newname;
5367 uint32 mask;
5369 mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
5370 : FILE_NOTIFY_CHANGE_FILE_NAME;
5372 if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
5373 || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
5374 TALLOC_FREE(olddir);
5375 return;
5378 if (strcmp(olddir, newdir) == 0) {
5379 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
5380 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
5382 else {
5383 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
5384 notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
5386 TALLOC_FREE(olddir);
5387 TALLOC_FREE(newdir);
5389 /* this is a strange one. w2k3 gives an additional event for
5390 CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
5391 files, but not directories */
5392 if (!is_dir) {
5393 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
5394 FILE_NOTIFY_CHANGE_ATTRIBUTES
5395 |FILE_NOTIFY_CHANGE_CREATION,
5396 newpath);
5400 /****************************************************************************
5401 Rename an open file - given an fsp.
5402 ****************************************************************************/
5404 NTSTATUS rename_internals_fsp(connection_struct *conn,
5405 files_struct *fsp,
5406 char *newname,
5407 const char *newname_last_component,
5408 uint32 attrs,
5409 bool replace_if_exists)
5411 TALLOC_CTX *ctx = talloc_tos();
5412 SMB_STRUCT_STAT sbuf, sbuf1;
5413 NTSTATUS status = NT_STATUS_OK;
5414 struct share_mode_lock *lck = NULL;
5415 bool dst_exists;
5417 ZERO_STRUCT(sbuf);
5419 status = check_name(conn, newname);
5420 if (!NT_STATUS_IS_OK(status)) {
5421 return status;
5424 /* Ensure newname contains a '/' */
5425 if(strrchr_m(newname,'/') == 0) {
5426 newname = talloc_asprintf(ctx,
5427 "./%s",
5428 newname);
5429 if (!newname) {
5430 return NT_STATUS_NO_MEMORY;
5435 * Check for special case with case preserving and not
5436 * case sensitive. If the old last component differs from the original
5437 * last component only by case, then we should allow
5438 * the rename (user is trying to change the case of the
5439 * filename).
5442 if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
5443 strequal(newname, fsp->fsp_name)) {
5444 char *p;
5445 char *newname_modified_last_component = NULL;
5448 * Get the last component of the modified name.
5449 * Note that we guarantee that newname contains a '/'
5450 * character above.
5452 p = strrchr_m(newname,'/');
5453 newname_modified_last_component = talloc_strdup(ctx,
5454 p+1);
5455 if (!newname_modified_last_component) {
5456 return NT_STATUS_NO_MEMORY;
5459 if(strcsequal(newname_modified_last_component,
5460 newname_last_component) == False) {
5462 * Replace the modified last component with
5463 * the original.
5465 *p = '\0'; /* Truncate at the '/' */
5466 newname = talloc_asprintf(ctx,
5467 "%s/%s",
5468 newname,
5469 newname_last_component);
5474 * If the src and dest names are identical - including case,
5475 * don't do the rename, just return success.
5478 if (strcsequal(fsp->fsp_name, newname)) {
5479 DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
5480 newname));
5481 return NT_STATUS_OK;
5485 * Have vfs_object_exist also fill sbuf1
5487 dst_exists = vfs_object_exist(conn, newname, &sbuf1);
5489 if(!replace_if_exists && dst_exists) {
5490 DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
5491 fsp->fsp_name,newname));
5492 return NT_STATUS_OBJECT_NAME_COLLISION;
5495 if (dst_exists) {
5496 struct file_id fileid = vfs_file_id_from_sbuf(conn, &sbuf1);
5497 files_struct *dst_fsp = file_find_di_first(fileid);
5498 if (dst_fsp) {
5499 DEBUG(3, ("rename_internals_fsp: Target file open\n"));
5500 return NT_STATUS_ACCESS_DENIED;
5504 /* Ensure we have a valid stat struct for the source. */
5505 if (fsp->fh->fd != -1) {
5506 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
5507 return map_nt_error_from_unix(errno);
5509 } else {
5510 if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
5511 return map_nt_error_from_unix(errno);
5515 status = can_rename(conn, fsp, attrs, &sbuf);
5517 if (!NT_STATUS_IS_OK(status)) {
5518 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
5519 nt_errstr(status), fsp->fsp_name,newname));
5520 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
5521 status = NT_STATUS_ACCESS_DENIED;
5522 return status;
5525 if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
5526 return NT_STATUS_ACCESS_DENIED;
5529 lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL,
5530 NULL);
5533 * We have the file open ourselves, so not being able to get the
5534 * corresponding share mode lock is a fatal error.
5537 SMB_ASSERT(lck != NULL);
5539 if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
5540 uint32 create_options = fsp->fh->private_options;
5542 DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
5543 fsp->fsp_name,newname));
5545 rename_open_files(conn, lck, newname);
5547 notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname);
5550 * A rename acts as a new file create w.r.t. allowing an initial delete
5551 * on close, probably because in Windows there is a new handle to the
5552 * new file. If initial delete on close was requested but not
5553 * originally set, we need to set it here. This is probably not 100% correct,
5554 * but will work for the CIFSFS client which in non-posix mode
5555 * depends on these semantics. JRA.
5558 set_allow_initial_delete_on_close(lck, fsp, True);
5560 if (create_options & FILE_DELETE_ON_CLOSE) {
5561 status = can_set_delete_on_close(fsp, True, 0);
5563 if (NT_STATUS_IS_OK(status)) {
5564 /* Note that here we set the *inital* delete on close flag,
5565 * not the regular one. The magic gets handled in close. */
5566 fsp->initial_delete_on_close = True;
5569 TALLOC_FREE(lck);
5570 return NT_STATUS_OK;
5573 TALLOC_FREE(lck);
5575 if (errno == ENOTDIR || errno == EISDIR) {
5576 status = NT_STATUS_OBJECT_NAME_COLLISION;
5577 } else {
5578 status = map_nt_error_from_unix(errno);
5581 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
5582 nt_errstr(status), fsp->fsp_name,newname));
5584 return status;
5587 /****************************************************************************
5588 The guts of the rename command, split out so it may be called by the NT SMB
5589 code.
5590 ****************************************************************************/
5592 NTSTATUS rename_internals(TALLOC_CTX *ctx,
5593 connection_struct *conn,
5594 struct smb_request *req,
5595 const char *name_in,
5596 const char *newname_in,
5597 uint32 attrs,
5598 bool replace_if_exists,
5599 bool src_has_wild,
5600 bool dest_has_wild,
5601 uint32_t access_mask)
5603 char *directory = NULL;
5604 char *mask = NULL;
5605 char *last_component_src = NULL;
5606 char *last_component_dest = NULL;
5607 char *name = NULL;
5608 char *newname = NULL;
5609 char *p;
5610 int count=0;
5611 NTSTATUS status = NT_STATUS_OK;
5612 SMB_STRUCT_STAT sbuf1, sbuf2;
5613 struct smb_Dir *dir_hnd = NULL;
5614 const char *dname;
5615 long offset = 0;
5617 ZERO_STRUCT(sbuf1);
5618 ZERO_STRUCT(sbuf2);
5620 status = unix_convert(ctx, conn, name_in, src_has_wild, &name,
5621 &last_component_src, &sbuf1);
5622 if (!NT_STATUS_IS_OK(status)) {
5623 return status;
5626 status = unix_convert(ctx, conn, newname_in, dest_has_wild, &newname,
5627 &last_component_dest, &sbuf2);
5628 if (!NT_STATUS_IS_OK(status)) {
5629 return status;
5633 * Split the old name into directory and last component
5634 * strings. Note that unix_convert may have stripped off a
5635 * leading ./ from both name and newname if the rename is
5636 * at the root of the share. We need to make sure either both
5637 * name and newname contain a / character or neither of them do
5638 * as this is checked in resolve_wildcards().
5641 p = strrchr_m(name,'/');
5642 if (!p) {
5643 directory = talloc_strdup(ctx, ".");
5644 if (!directory) {
5645 return NT_STATUS_NO_MEMORY;
5647 mask = name;
5648 } else {
5649 *p = 0;
5650 directory = talloc_strdup(ctx, name);
5651 if (!directory) {
5652 return NT_STATUS_NO_MEMORY;
5654 mask = p+1;
5655 *p = '/'; /* Replace needed for exceptional test below. */
5659 * We should only check the mangled cache
5660 * here if unix_convert failed. This means
5661 * that the path in 'mask' doesn't exist
5662 * on the file system and so we need to look
5663 * for a possible mangle. This patch from
5664 * Tine Smukavec <valentin.smukavec@hermes.si>.
5667 if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
5668 char *new_mask = NULL;
5669 mangle_lookup_name_from_8_3(ctx,
5670 mask,
5671 &new_mask,
5672 conn->params );
5673 if (new_mask) {
5674 mask = new_mask;
5678 if (!src_has_wild) {
5679 files_struct *fsp;
5682 * No wildcards - just process the one file.
5684 bool is_short_name = mangle_is_8_3(name, True, conn->params);
5686 /* Add a terminating '/' to the directory name. */
5687 directory = talloc_asprintf_append(directory,
5688 "/%s",
5689 mask);
5690 if (!directory) {
5691 return NT_STATUS_NO_MEMORY;
5694 /* Ensure newname contains a '/' also */
5695 if(strrchr_m(newname,'/') == 0) {
5696 newname = talloc_asprintf(ctx,
5697 "./%s",
5698 newname);
5699 if (!newname) {
5700 return NT_STATUS_NO_MEMORY;
5704 DEBUG(3, ("rename_internals: case_sensitive = %d, "
5705 "case_preserve = %d, short case preserve = %d, "
5706 "directory = %s, newname = %s, "
5707 "last_component_dest = %s, is_8_3 = %d\n",
5708 conn->case_sensitive, conn->case_preserve,
5709 conn->short_case_preserve, directory,
5710 newname, last_component_dest, is_short_name));
5712 /* The dest name still may have wildcards. */
5713 if (dest_has_wild) {
5714 char *mod_newname = NULL;
5715 if (!resolve_wildcards(ctx,
5716 directory,newname,&mod_newname)) {
5717 DEBUG(6, ("rename_internals: resolve_wildcards "
5718 "%s %s failed\n",
5719 directory,
5720 newname));
5721 return NT_STATUS_NO_MEMORY;
5723 newname = mod_newname;
5726 ZERO_STRUCT(sbuf1);
5727 SMB_VFS_STAT(conn, directory, &sbuf1);
5729 status = S_ISDIR(sbuf1.st_mode) ?
5730 open_directory(conn, req, directory, &sbuf1,
5731 access_mask,
5732 FILE_SHARE_READ|FILE_SHARE_WRITE,
5733 FILE_OPEN, 0, 0, NULL,
5734 &fsp)
5735 : open_file_ntcreate(conn, req, directory, &sbuf1,
5736 access_mask,
5737 FILE_SHARE_READ|FILE_SHARE_WRITE,
5738 FILE_OPEN, 0, 0, 0, NULL,
5739 &fsp);
5741 if (!NT_STATUS_IS_OK(status)) {
5742 DEBUG(3, ("Could not open rename source %s: %s\n",
5743 directory, nt_errstr(status)));
5744 return status;
5747 status = rename_internals_fsp(conn, fsp, newname,
5748 last_component_dest,
5749 attrs, replace_if_exists);
5751 close_file(fsp, NORMAL_CLOSE);
5753 DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
5754 nt_errstr(status), directory,newname));
5756 return status;
5760 * Wildcards - process each file that matches.
5762 if (strequal(mask,"????????.???")) {
5763 mask[0] = '*';
5764 mask[1] = '\0';
5767 status = check_name(conn, directory);
5768 if (!NT_STATUS_IS_OK(status)) {
5769 return status;
5772 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, attrs);
5773 if (dir_hnd == NULL) {
5774 return map_nt_error_from_unix(errno);
5777 status = NT_STATUS_NO_SUCH_FILE;
5779 * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
5780 * - gentest fix. JRA
5783 while ((dname = ReadDirName(dir_hnd, &offset))) {
5784 files_struct *fsp = NULL;
5785 char *fname = NULL;
5786 char *destname = NULL;
5787 bool sysdir_entry = False;
5789 /* Quick check for "." and ".." */
5790 if (ISDOT(dname) || ISDOTDOT(dname)) {
5791 if (attrs & aDIR) {
5792 sysdir_entry = True;
5793 } else {
5794 continue;
5798 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
5799 continue;
5802 if(!mask_match(dname, mask, conn->case_sensitive)) {
5803 continue;
5806 if (sysdir_entry) {
5807 status = NT_STATUS_OBJECT_NAME_INVALID;
5808 break;
5811 fname = talloc_asprintf(ctx,
5812 "%s/%s",
5813 directory,
5814 dname);
5815 if (!fname) {
5816 return NT_STATUS_NO_MEMORY;
5819 if (!resolve_wildcards(ctx,
5820 fname,newname,&destname)) {
5821 DEBUG(6, ("resolve_wildcards %s %s failed\n",
5822 fname, destname));
5823 TALLOC_FREE(fname);
5824 continue;
5826 if (!destname) {
5827 return NT_STATUS_NO_MEMORY;
5830 ZERO_STRUCT(sbuf1);
5831 SMB_VFS_STAT(conn, fname, &sbuf1);
5833 status = S_ISDIR(sbuf1.st_mode) ?
5834 open_directory(conn, req, fname, &sbuf1,
5835 access_mask,
5836 FILE_SHARE_READ|FILE_SHARE_WRITE,
5837 FILE_OPEN, 0, 0, NULL,
5838 &fsp)
5839 : open_file_ntcreate(conn, req, fname, &sbuf1,
5840 access_mask,
5841 FILE_SHARE_READ|FILE_SHARE_WRITE,
5842 FILE_OPEN, 0, 0, 0, NULL,
5843 &fsp);
5845 if (!NT_STATUS_IS_OK(status)) {
5846 DEBUG(3,("rename_internals: open_file_ntcreate "
5847 "returned %s rename %s -> %s\n",
5848 nt_errstr(status), directory, newname));
5849 break;
5852 status = rename_internals_fsp(conn, fsp, destname, dname,
5853 attrs, replace_if_exists);
5855 close_file(fsp, NORMAL_CLOSE);
5857 if (!NT_STATUS_IS_OK(status)) {
5858 DEBUG(3, ("rename_internals_fsp returned %s for "
5859 "rename %s -> %s\n", nt_errstr(status),
5860 directory, newname));
5861 break;
5864 count++;
5866 DEBUG(3,("rename_internals: doing rename on %s -> "
5867 "%s\n",fname,destname));
5869 TALLOC_FREE(fname);
5870 TALLOC_FREE(destname);
5872 TALLOC_FREE(dir_hnd);
5874 if (count == 0 && NT_STATUS_IS_OK(status)) {
5875 status = map_nt_error_from_unix(errno);
5878 return status;
5881 /****************************************************************************
5882 Reply to a mv.
5883 ****************************************************************************/
5885 void reply_mv(struct smb_request *req)
5887 connection_struct *conn = req->conn;
5888 char *name = NULL;
5889 char *newname = NULL;
5890 char *p;
5891 uint32 attrs;
5892 NTSTATUS status;
5893 bool src_has_wcard = False;
5894 bool dest_has_wcard = False;
5895 TALLOC_CTX *ctx = talloc_tos();
5897 START_PROFILE(SMBmv);
5899 if (req->wct < 1) {
5900 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
5901 END_PROFILE(SMBmv);
5902 return;
5905 attrs = SVAL(req->inbuf,smb_vwv0);
5907 p = smb_buf(req->inbuf) + 1;
5908 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
5909 0, STR_TERMINATE, &status,
5910 &src_has_wcard);
5911 if (!NT_STATUS_IS_OK(status)) {
5912 reply_nterror(req, status);
5913 END_PROFILE(SMBmv);
5914 return;
5916 p++;
5917 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
5918 0, STR_TERMINATE, &status,
5919 &dest_has_wcard);
5920 if (!NT_STATUS_IS_OK(status)) {
5921 reply_nterror(req, status);
5922 END_PROFILE(SMBmv);
5923 return;
5926 status = resolve_dfspath_wcard(ctx, conn,
5927 req->flags2 & FLAGS2_DFS_PATHNAMES,
5928 name,
5929 &name,
5930 &src_has_wcard);
5931 if (!NT_STATUS_IS_OK(status)) {
5932 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5933 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5934 ERRSRV, ERRbadpath);
5935 END_PROFILE(SMBmv);
5936 return;
5938 reply_nterror(req, status);
5939 END_PROFILE(SMBmv);
5940 return;
5943 status = resolve_dfspath_wcard(ctx, conn,
5944 req->flags2 & FLAGS2_DFS_PATHNAMES,
5945 newname,
5946 &newname,
5947 &dest_has_wcard);
5948 if (!NT_STATUS_IS_OK(status)) {
5949 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
5950 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
5951 ERRSRV, ERRbadpath);
5952 END_PROFILE(SMBmv);
5953 return;
5955 reply_nterror(req, status);
5956 END_PROFILE(SMBmv);
5957 return;
5960 DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
5962 status = rename_internals(ctx, conn, req, name, newname, attrs, False,
5963 src_has_wcard, dest_has_wcard, DELETE_ACCESS);
5964 if (!NT_STATUS_IS_OK(status)) {
5965 if (open_was_deferred(req->mid)) {
5966 /* We have re-scheduled this call. */
5967 END_PROFILE(SMBmv);
5968 return;
5970 reply_nterror(req, status);
5971 END_PROFILE(SMBmv);
5972 return;
5975 reply_outbuf(req, 0, 0);
5977 END_PROFILE(SMBmv);
5978 return;
5981 /*******************************************************************
5982 Copy a file as part of a reply_copy.
5983 ******************************************************************/
5986 * TODO: check error codes on all callers
5989 NTSTATUS copy_file(TALLOC_CTX *ctx,
5990 connection_struct *conn,
5991 const char *src,
5992 const char *dest1,
5993 int ofun,
5994 int count,
5995 bool target_is_directory)
5997 SMB_STRUCT_STAT src_sbuf, sbuf2;
5998 SMB_OFF_T ret=-1;
5999 files_struct *fsp1,*fsp2;
6000 char *dest = NULL;
6001 uint32 dosattrs;
6002 uint32 new_create_disposition;
6003 NTSTATUS status;
6005 dest = talloc_strdup(ctx, dest1);
6006 if (!dest) {
6007 return NT_STATUS_NO_MEMORY;
6009 if (target_is_directory) {
6010 const char *p = strrchr_m(src,'/');
6011 if (p) {
6012 p++;
6013 } else {
6014 p = src;
6016 dest = talloc_asprintf_append(dest,
6017 "/%s",
6019 if (!dest) {
6020 return NT_STATUS_NO_MEMORY;
6024 if (!vfs_file_exist(conn,src,&src_sbuf)) {
6025 TALLOC_FREE(dest);
6026 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
6029 if (!target_is_directory && count) {
6030 new_create_disposition = FILE_OPEN;
6031 } else {
6032 if (!map_open_params_to_ntcreate(dest1,0,ofun,
6033 NULL, NULL, &new_create_disposition, NULL)) {
6034 TALLOC_FREE(dest);
6035 return NT_STATUS_INVALID_PARAMETER;
6039 status = open_file_ntcreate(conn, NULL, src, &src_sbuf,
6040 FILE_GENERIC_READ,
6041 FILE_SHARE_READ|FILE_SHARE_WRITE,
6042 FILE_OPEN,
6044 FILE_ATTRIBUTE_NORMAL,
6045 INTERNAL_OPEN_ONLY,
6046 NULL, &fsp1);
6048 if (!NT_STATUS_IS_OK(status)) {
6049 TALLOC_FREE(dest);
6050 return status;
6053 dosattrs = dos_mode(conn, src, &src_sbuf);
6054 if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) {
6055 ZERO_STRUCTP(&sbuf2);
6058 status = open_file_ntcreate(conn, NULL, dest, &sbuf2,
6059 FILE_GENERIC_WRITE,
6060 FILE_SHARE_READ|FILE_SHARE_WRITE,
6061 new_create_disposition,
6063 dosattrs,
6064 INTERNAL_OPEN_ONLY,
6065 NULL, &fsp2);
6067 TALLOC_FREE(dest);
6069 if (!NT_STATUS_IS_OK(status)) {
6070 close_file(fsp1,ERROR_CLOSE);
6071 return status;
6074 if ((ofun&3) == 1) {
6075 if(SMB_VFS_LSEEK(fsp2,0,SEEK_END) == -1) {
6076 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
6078 * Stop the copy from occurring.
6080 ret = -1;
6081 src_sbuf.st_size = 0;
6085 if (src_sbuf.st_size) {
6086 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
6089 close_file(fsp1,NORMAL_CLOSE);
6091 /* Ensure the modtime is set correctly on the destination file. */
6092 set_close_write_time(fsp2, get_mtimespec(&src_sbuf));
6095 * As we are opening fsp1 read-only we only expect
6096 * an error on close on fsp2 if we are out of space.
6097 * Thus we don't look at the error return from the
6098 * close of fsp1.
6100 status = close_file(fsp2,NORMAL_CLOSE);
6102 if (!NT_STATUS_IS_OK(status)) {
6103 return status;
6106 if (ret != (SMB_OFF_T)src_sbuf.st_size) {
6107 return NT_STATUS_DISK_FULL;
6110 return NT_STATUS_OK;
6113 /****************************************************************************
6114 Reply to a file copy.
6115 ****************************************************************************/
6117 void reply_copy(struct smb_request *req)
6119 connection_struct *conn = req->conn;
6120 char *name = NULL;
6121 char *newname = NULL;
6122 char *directory = NULL;
6123 char *mask = NULL;
6124 char *p;
6125 int count=0;
6126 int error = ERRnoaccess;
6127 int err = 0;
6128 int tid2;
6129 int ofun;
6130 int flags;
6131 bool target_is_directory=False;
6132 bool source_has_wild = False;
6133 bool dest_has_wild = False;
6134 SMB_STRUCT_STAT sbuf1, sbuf2;
6135 NTSTATUS status;
6136 TALLOC_CTX *ctx = talloc_tos();
6138 START_PROFILE(SMBcopy);
6140 if (req->wct < 3) {
6141 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6142 END_PROFILE(SMBcopy);
6143 return;
6146 tid2 = SVAL(req->inbuf,smb_vwv0);
6147 ofun = SVAL(req->inbuf,smb_vwv1);
6148 flags = SVAL(req->inbuf,smb_vwv2);
6150 p = smb_buf(req->inbuf);
6151 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &name, p,
6152 0, STR_TERMINATE, &status,
6153 &source_has_wild);
6154 if (!NT_STATUS_IS_OK(status)) {
6155 reply_nterror(req, status);
6156 END_PROFILE(SMBcopy);
6157 return;
6159 p += srvstr_get_path_wcard(ctx, (char *)req->inbuf, req->flags2, &newname, p,
6160 0, STR_TERMINATE, &status,
6161 &dest_has_wild);
6162 if (!NT_STATUS_IS_OK(status)) {
6163 reply_nterror(req, status);
6164 END_PROFILE(SMBcopy);
6165 return;
6168 DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
6170 if (tid2 != conn->cnum) {
6171 /* can't currently handle inter share copies XXXX */
6172 DEBUG(3,("Rejecting inter-share copy\n"));
6173 reply_doserror(req, ERRSRV, ERRinvdevice);
6174 END_PROFILE(SMBcopy);
6175 return;
6178 status = resolve_dfspath_wcard(ctx, conn,
6179 req->flags2 & FLAGS2_DFS_PATHNAMES,
6180 name,
6181 &name,
6182 &source_has_wild);
6183 if (!NT_STATUS_IS_OK(status)) {
6184 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6185 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6186 ERRSRV, ERRbadpath);
6187 END_PROFILE(SMBcopy);
6188 return;
6190 reply_nterror(req, status);
6191 END_PROFILE(SMBcopy);
6192 return;
6195 status = resolve_dfspath_wcard(ctx, conn,
6196 req->flags2 & FLAGS2_DFS_PATHNAMES,
6197 newname,
6198 &newname,
6199 &dest_has_wild);
6200 if (!NT_STATUS_IS_OK(status)) {
6201 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
6202 reply_botherror(req, NT_STATUS_PATH_NOT_COVERED,
6203 ERRSRV, ERRbadpath);
6204 END_PROFILE(SMBcopy);
6205 return;
6207 reply_nterror(req, status);
6208 END_PROFILE(SMBcopy);
6209 return;
6212 status = unix_convert(ctx, conn, name, source_has_wild,
6213 &name, NULL, &sbuf1);
6214 if (!NT_STATUS_IS_OK(status)) {
6215 reply_nterror(req, status);
6216 END_PROFILE(SMBcopy);
6217 return;
6220 status = unix_convert(ctx, conn, newname, dest_has_wild,
6221 &newname, NULL, &sbuf2);
6222 if (!NT_STATUS_IS_OK(status)) {
6223 reply_nterror(req, status);
6224 END_PROFILE(SMBcopy);
6225 return;
6228 target_is_directory = VALID_STAT_OF_DIR(sbuf2);
6230 if ((flags&1) && target_is_directory) {
6231 reply_doserror(req, ERRDOS, ERRbadfile);
6232 END_PROFILE(SMBcopy);
6233 return;
6236 if ((flags&2) && !target_is_directory) {
6237 reply_doserror(req, ERRDOS, ERRbadpath);
6238 END_PROFILE(SMBcopy);
6239 return;
6242 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
6243 /* wants a tree copy! XXXX */
6244 DEBUG(3,("Rejecting tree copy\n"));
6245 reply_doserror(req, ERRSRV, ERRerror);
6246 END_PROFILE(SMBcopy);
6247 return;
6250 p = strrchr_m(name,'/');
6251 if (!p) {
6252 directory = talloc_strdup(ctx, "./");
6253 if (!directory) {
6254 reply_nterror(req, NT_STATUS_NO_MEMORY);
6255 END_PROFILE(SMBcopy);
6256 return;
6258 mask = name;
6259 } else {
6260 *p = 0;
6261 directory = talloc_strdup(ctx, name);
6262 if (!directory) {
6263 reply_nterror(req, NT_STATUS_NO_MEMORY);
6264 END_PROFILE(SMBcopy);
6265 return;
6267 mask = p+1;
6271 * We should only check the mangled cache
6272 * here if unix_convert failed. This means
6273 * that the path in 'mask' doesn't exist
6274 * on the file system and so we need to look
6275 * for a possible mangle. This patch from
6276 * Tine Smukavec <valentin.smukavec@hermes.si>.
6279 if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
6280 char *new_mask = NULL;
6281 mangle_lookup_name_from_8_3(ctx,
6282 mask,
6283 &new_mask,
6284 conn->params );
6285 if (new_mask) {
6286 mask = new_mask;
6290 if (!source_has_wild) {
6291 directory = talloc_asprintf_append(directory,
6292 "/%s",
6293 mask);
6294 if (dest_has_wild) {
6295 char *mod_newname = NULL;
6296 if (!resolve_wildcards(ctx,
6297 directory,newname,&mod_newname)) {
6298 reply_nterror(req, NT_STATUS_NO_MEMORY);
6299 END_PROFILE(SMBcopy);
6300 return;
6302 newname = mod_newname;
6305 status = check_name(conn, directory);
6306 if (!NT_STATUS_IS_OK(status)) {
6307 reply_nterror(req, status);
6308 END_PROFILE(SMBcopy);
6309 return;
6312 status = check_name(conn, newname);
6313 if (!NT_STATUS_IS_OK(status)) {
6314 reply_nterror(req, status);
6315 END_PROFILE(SMBcopy);
6316 return;
6319 status = copy_file(ctx,conn,directory,newname,ofun,
6320 count,target_is_directory);
6322 if(!NT_STATUS_IS_OK(status)) {
6323 reply_nterror(req, status);
6324 END_PROFILE(SMBcopy);
6325 return;
6326 } else {
6327 count++;
6329 } else {
6330 struct smb_Dir *dir_hnd = NULL;
6331 const char *dname = NULL;
6332 long offset = 0;
6334 if (strequal(mask,"????????.???")) {
6335 mask[0] = '*';
6336 mask[1] = '\0';
6339 status = check_name(conn, directory);
6340 if (!NT_STATUS_IS_OK(status)) {
6341 reply_nterror(req, status);
6342 END_PROFILE(SMBcopy);
6343 return;
6346 dir_hnd = OpenDir(talloc_tos(), conn, directory, mask, 0);
6347 if (dir_hnd == NULL) {
6348 status = map_nt_error_from_unix(errno);
6349 reply_nterror(req, status);
6350 END_PROFILE(SMBcopy);
6351 return;
6354 error = ERRbadfile;
6356 while ((dname = ReadDirName(dir_hnd, &offset))) {
6357 char *destname = NULL;
6358 char *fname = NULL;
6360 if (ISDOT(dname) || ISDOTDOT(dname)) {
6361 continue;
6364 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
6365 continue;
6368 if(!mask_match(dname, mask, conn->case_sensitive)) {
6369 continue;
6372 error = ERRnoaccess;
6373 fname = talloc_asprintf(ctx,
6374 "%s/%s",
6375 directory,
6376 dname);
6377 if (!fname) {
6378 TALLOC_FREE(dir_hnd);
6379 reply_nterror(req, NT_STATUS_NO_MEMORY);
6380 END_PROFILE(SMBcopy);
6381 return;
6384 if (!resolve_wildcards(ctx,
6385 fname,newname,&destname)) {
6386 continue;
6388 if (!destname) {
6389 TALLOC_FREE(dir_hnd);
6390 reply_nterror(req, NT_STATUS_NO_MEMORY);
6391 END_PROFILE(SMBcopy);
6392 return;
6395 status = check_name(conn, fname);
6396 if (!NT_STATUS_IS_OK(status)) {
6397 TALLOC_FREE(dir_hnd);
6398 reply_nterror(req, status);
6399 END_PROFILE(SMBcopy);
6400 return;
6403 status = check_name(conn, destname);
6404 if (!NT_STATUS_IS_OK(status)) {
6405 TALLOC_FREE(dir_hnd);
6406 reply_nterror(req, status);
6407 END_PROFILE(SMBcopy);
6408 return;
6411 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
6413 status = copy_file(ctx,conn,fname,destname,ofun,
6414 count,target_is_directory);
6415 if (NT_STATUS_IS_OK(status)) {
6416 count++;
6418 TALLOC_FREE(fname);
6419 TALLOC_FREE(destname);
6421 TALLOC_FREE(dir_hnd);
6424 if (count == 0) {
6425 if(err) {
6426 /* Error on close... */
6427 errno = err;
6428 reply_unixerror(req, ERRHRD, ERRgeneral);
6429 END_PROFILE(SMBcopy);
6430 return;
6433 reply_doserror(req, ERRDOS, error);
6434 END_PROFILE(SMBcopy);
6435 return;
6438 reply_outbuf(req, 1, 0);
6439 SSVAL(req->outbuf,smb_vwv0,count);
6441 END_PROFILE(SMBcopy);
6442 return;
6445 #undef DBGC_CLASS
6446 #define DBGC_CLASS DBGC_LOCKING
6448 /****************************************************************************
6449 Get a lock pid, dealing with large count requests.
6450 ****************************************************************************/
6452 uint32 get_lock_pid( char *data, int data_offset, bool large_file_format)
6454 if(!large_file_format)
6455 return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
6456 else
6457 return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
6460 /****************************************************************************
6461 Get a lock count, dealing with large count requests.
6462 ****************************************************************************/
6464 SMB_BIG_UINT get_lock_count( char *data, int data_offset, bool large_file_format)
6466 SMB_BIG_UINT count = 0;
6468 if(!large_file_format) {
6469 count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
6470 } else {
6472 #if defined(HAVE_LONGLONG)
6473 count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
6474 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
6475 #else /* HAVE_LONGLONG */
6478 * NT4.x seems to be broken in that it sends large file (64 bit)
6479 * lockingX calls even if the CAP_LARGE_FILES was *not*
6480 * negotiated. For boxes without large unsigned ints truncate the
6481 * lock count by dropping the top 32 bits.
6484 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
6485 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
6486 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
6487 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
6488 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
6491 count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
6492 #endif /* HAVE_LONGLONG */
6495 return count;
6498 #if !defined(HAVE_LONGLONG)
6499 /****************************************************************************
6500 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
6501 ****************************************************************************/
6503 static uint32 map_lock_offset(uint32 high, uint32 low)
6505 unsigned int i;
6506 uint32 mask = 0;
6507 uint32 highcopy = high;
6510 * Try and find out how many significant bits there are in high.
6513 for(i = 0; highcopy; i++)
6514 highcopy >>= 1;
6517 * We use 31 bits not 32 here as POSIX
6518 * lock offsets may not be negative.
6521 mask = (~0) << (31 - i);
6523 if(low & mask)
6524 return 0; /* Fail. */
6526 high <<= (31 - i);
6528 return (high|low);
6530 #endif /* !defined(HAVE_LONGLONG) */
6532 /****************************************************************************
6533 Get a lock offset, dealing with large offset requests.
6534 ****************************************************************************/
6536 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, bool large_file_format, bool *err)
6538 SMB_BIG_UINT offset = 0;
6540 *err = False;
6542 if(!large_file_format) {
6543 offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
6544 } else {
6546 #if defined(HAVE_LONGLONG)
6547 offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
6548 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
6549 #else /* HAVE_LONGLONG */
6552 * NT4.x seems to be broken in that it sends large file (64 bit)
6553 * lockingX calls even if the CAP_LARGE_FILES was *not*
6554 * negotiated. For boxes without large unsigned ints mangle the
6555 * lock offset by mapping the top 32 bits onto the lower 32.
6558 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
6559 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6560 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
6561 uint32 new_low = 0;
6563 if((new_low = map_lock_offset(high, low)) == 0) {
6564 *err = True;
6565 return (SMB_BIG_UINT)-1;
6568 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
6569 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
6570 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
6571 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
6574 offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
6575 #endif /* HAVE_LONGLONG */
6578 return offset;
6581 /****************************************************************************
6582 Reply to a lockingX request.
6583 ****************************************************************************/
6585 void reply_lockingX(struct smb_request *req)
6587 connection_struct *conn = req->conn;
6588 files_struct *fsp;
6589 unsigned char locktype;
6590 unsigned char oplocklevel;
6591 uint16 num_ulocks;
6592 uint16 num_locks;
6593 SMB_BIG_UINT count = 0, offset = 0;
6594 uint32 lock_pid;
6595 int32 lock_timeout;
6596 int i;
6597 char *data;
6598 bool large_file_format;
6599 bool err;
6600 NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
6602 START_PROFILE(SMBlockingX);
6604 if (req->wct < 8) {
6605 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6606 END_PROFILE(SMBlockingX);
6607 return;
6610 fsp = file_fsp(SVAL(req->inbuf,smb_vwv2));
6611 locktype = CVAL(req->inbuf,smb_vwv3);
6612 oplocklevel = CVAL(req->inbuf,smb_vwv3+1);
6613 num_ulocks = SVAL(req->inbuf,smb_vwv6);
6614 num_locks = SVAL(req->inbuf,smb_vwv7);
6615 lock_timeout = IVAL(req->inbuf,smb_vwv4);
6616 large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
6618 if (!check_fsp(conn, req, fsp, &current_user)) {
6619 END_PROFILE(SMBlockingX);
6620 return;
6623 data = smb_buf(req->inbuf);
6625 if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
6626 /* we don't support these - and CANCEL_LOCK makes w2k
6627 and XP reboot so I don't really want to be
6628 compatible! (tridge) */
6629 reply_nterror(req, NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
6630 END_PROFILE(SMBlockingX);
6631 return;
6634 /* Check if this is an oplock break on a file
6635 we have granted an oplock on.
6637 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
6638 /* Client can insist on breaking to none. */
6639 bool break_to_none = (oplocklevel == 0);
6640 bool result;
6642 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
6643 "for fnum = %d\n", (unsigned int)oplocklevel,
6644 fsp->fnum ));
6647 * Make sure we have granted an exclusive or batch oplock on
6648 * this file.
6651 if (fsp->oplock_type == 0) {
6653 /* The Samba4 nbench simulator doesn't understand
6654 the difference between break to level2 and break
6655 to none from level2 - it sends oplock break
6656 replies in both cases. Don't keep logging an error
6657 message here - just ignore it. JRA. */
6659 DEBUG(5,("reply_lockingX: Error : oplock break from "
6660 "client for fnum = %d (oplock=%d) and no "
6661 "oplock granted on this file (%s).\n",
6662 fsp->fnum, fsp->oplock_type, fsp->fsp_name));
6664 /* if this is a pure oplock break request then don't
6665 * send a reply */
6666 if (num_locks == 0 && num_ulocks == 0) {
6667 END_PROFILE(SMBlockingX);
6668 return;
6669 } else {
6670 END_PROFILE(SMBlockingX);
6671 reply_doserror(req, ERRDOS, ERRlock);
6672 return;
6676 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
6677 (break_to_none)) {
6678 result = remove_oplock(fsp);
6679 } else {
6680 result = downgrade_oplock(fsp);
6683 if (!result) {
6684 DEBUG(0, ("reply_lockingX: error in removing "
6685 "oplock on file %s\n", fsp->fsp_name));
6686 /* Hmmm. Is this panic justified? */
6687 smb_panic("internal tdb error");
6690 reply_to_oplock_break_requests(fsp);
6692 /* if this is a pure oplock break request then don't send a
6693 * reply */
6694 if (num_locks == 0 && num_ulocks == 0) {
6695 /* Sanity check - ensure a pure oplock break is not a
6696 chained request. */
6697 if(CVAL(req->inbuf,smb_vwv0) != 0xff)
6698 DEBUG(0,("reply_lockingX: Error : pure oplock "
6699 "break is a chained %d request !\n",
6700 (unsigned int)CVAL(req->inbuf,
6701 smb_vwv0) ));
6702 END_PROFILE(SMBlockingX);
6703 return;
6708 * We do this check *after* we have checked this is not a oplock break
6709 * response message. JRA.
6712 release_level_2_oplocks_on_change(fsp);
6714 if (smb_buflen(req->inbuf) <
6715 (num_ulocks + num_locks) * (large_file_format ? 20 : 10)) {
6716 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6717 END_PROFILE(SMBlockingX);
6718 return;
6721 /* Data now points at the beginning of the list
6722 of smb_unlkrng structs */
6723 for(i = 0; i < (int)num_ulocks; i++) {
6724 lock_pid = get_lock_pid( data, i, large_file_format);
6725 count = get_lock_count( data, i, large_file_format);
6726 offset = get_lock_offset( data, i, large_file_format, &err);
6729 * There is no error code marked "stupid client bug".... :-).
6731 if(err) {
6732 END_PROFILE(SMBlockingX);
6733 reply_doserror(req, ERRDOS, ERRnoaccess);
6734 return;
6737 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
6738 "pid %u, file %s\n", (double)offset, (double)count,
6739 (unsigned int)lock_pid, fsp->fsp_name ));
6741 status = do_unlock(smbd_messaging_context(),
6742 fsp,
6743 lock_pid,
6744 count,
6745 offset,
6746 WINDOWS_LOCK);
6748 if (NT_STATUS_V(status)) {
6749 END_PROFILE(SMBlockingX);
6750 reply_nterror(req, status);
6751 return;
6755 /* Setup the timeout in seconds. */
6757 if (!lp_blocking_locks(SNUM(conn))) {
6758 lock_timeout = 0;
6761 /* Now do any requested locks */
6762 data += ((large_file_format ? 20 : 10)*num_ulocks);
6764 /* Data now points at the beginning of the list
6765 of smb_lkrng structs */
6767 for(i = 0; i < (int)num_locks; i++) {
6768 enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
6769 READ_LOCK:WRITE_LOCK);
6770 lock_pid = get_lock_pid( data, i, large_file_format);
6771 count = get_lock_count( data, i, large_file_format);
6772 offset = get_lock_offset( data, i, large_file_format, &err);
6775 * There is no error code marked "stupid client bug".... :-).
6777 if(err) {
6778 END_PROFILE(SMBlockingX);
6779 reply_doserror(req, ERRDOS, ERRnoaccess);
6780 return;
6783 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
6784 "%u, file %s timeout = %d\n", (double)offset,
6785 (double)count, (unsigned int)lock_pid,
6786 fsp->fsp_name, (int)lock_timeout ));
6788 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
6789 if (lp_blocking_locks(SNUM(conn))) {
6791 /* Schedule a message to ourselves to
6792 remove the blocking lock record and
6793 return the right error. */
6795 if (!blocking_lock_cancel(fsp,
6796 lock_pid,
6797 offset,
6798 count,
6799 WINDOWS_LOCK,
6800 locktype,
6801 NT_STATUS_FILE_LOCK_CONFLICT)) {
6802 END_PROFILE(SMBlockingX);
6803 reply_nterror(
6804 req,
6805 NT_STATUS_DOS(
6806 ERRDOS,
6807 ERRcancelviolation));
6808 return;
6811 /* Remove a matching pending lock. */
6812 status = do_lock_cancel(fsp,
6813 lock_pid,
6814 count,
6815 offset,
6816 WINDOWS_LOCK);
6817 } else {
6818 bool blocking_lock = lock_timeout ? True : False;
6819 bool defer_lock = False;
6820 struct byte_range_lock *br_lck;
6821 uint32 block_smbpid;
6823 br_lck = do_lock(smbd_messaging_context(),
6824 fsp,
6825 lock_pid,
6826 count,
6827 offset,
6828 lock_type,
6829 WINDOWS_LOCK,
6830 blocking_lock,
6831 &status,
6832 &block_smbpid);
6834 if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
6835 /* Windows internal resolution for blocking locks seems
6836 to be about 200ms... Don't wait for less than that. JRA. */
6837 if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) {
6838 lock_timeout = lp_lock_spin_time();
6840 defer_lock = True;
6843 /* This heuristic seems to match W2K3 very well. If a
6844 lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
6845 it pretends we asked for a timeout of between 150 - 300 milliseconds as
6846 far as I can tell. Replacement for do_lock_spin(). JRA. */
6848 if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
6849 NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
6850 defer_lock = True;
6851 lock_timeout = lp_lock_spin_time();
6854 if (br_lck && defer_lock) {
6856 * A blocking lock was requested. Package up
6857 * this smb into a queued request and push it
6858 * onto the blocking lock queue.
6860 if(push_blocking_lock_request(br_lck,
6861 req,
6862 fsp,
6863 lock_timeout,
6865 lock_pid,
6866 lock_type,
6867 WINDOWS_LOCK,
6868 offset,
6869 count,
6870 block_smbpid)) {
6871 TALLOC_FREE(br_lck);
6872 END_PROFILE(SMBlockingX);
6873 return;
6877 TALLOC_FREE(br_lck);
6880 if (NT_STATUS_V(status)) {
6881 END_PROFILE(SMBlockingX);
6882 reply_nterror(req, status);
6883 return;
6887 /* If any of the above locks failed, then we must unlock
6888 all of the previous locks (X/Open spec). */
6890 if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
6891 (i != num_locks) &&
6892 (num_locks != 0)) {
6894 * Ensure we don't do a remove on the lock that just failed,
6895 * as under POSIX rules, if we have a lock already there, we
6896 * will delete it (and we shouldn't) .....
6898 for(i--; i >= 0; i--) {
6899 lock_pid = get_lock_pid( data, i, large_file_format);
6900 count = get_lock_count( data, i, large_file_format);
6901 offset = get_lock_offset( data, i, large_file_format,
6902 &err);
6905 * There is no error code marked "stupid client
6906 * bug".... :-).
6908 if(err) {
6909 END_PROFILE(SMBlockingX);
6910 reply_doserror(req, ERRDOS, ERRnoaccess);
6911 return;
6914 do_unlock(smbd_messaging_context(),
6915 fsp,
6916 lock_pid,
6917 count,
6918 offset,
6919 WINDOWS_LOCK);
6921 END_PROFILE(SMBlockingX);
6922 reply_nterror(req, status);
6923 return;
6926 reply_outbuf(req, 2, 0);
6928 DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
6929 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
6931 END_PROFILE(SMBlockingX);
6932 chain_reply(req);
6935 #undef DBGC_CLASS
6936 #define DBGC_CLASS DBGC_ALL
6938 /****************************************************************************
6939 Reply to a SMBreadbmpx (read block multiplex) request.
6940 Always reply with an error, if someone has a platform really needs this,
6941 please contact vl@samba.org
6942 ****************************************************************************/
6944 void reply_readbmpx(struct smb_request *req)
6946 START_PROFILE(SMBreadBmpx);
6947 reply_doserror(req, ERRSRV, ERRuseSTD);
6948 END_PROFILE(SMBreadBmpx);
6949 return;
6952 /****************************************************************************
6953 Reply to a SMBreadbs (read block multiplex secondary) request.
6954 Always reply with an error, if someone has a platform really needs this,
6955 please contact vl@samba.org
6956 ****************************************************************************/
6958 void reply_readbs(struct smb_request *req)
6960 START_PROFILE(SMBreadBs);
6961 reply_doserror(req, ERRSRV, ERRuseSTD);
6962 END_PROFILE(SMBreadBs);
6963 return;
6966 /****************************************************************************
6967 Reply to a SMBsetattrE.
6968 ****************************************************************************/
6970 void reply_setattrE(struct smb_request *req)
6972 connection_struct *conn = req->conn;
6973 struct timespec ts[2];
6974 files_struct *fsp;
6975 SMB_STRUCT_STAT sbuf;
6976 NTSTATUS status;
6978 START_PROFILE(SMBsetattrE);
6980 if (req->wct < 7) {
6981 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
6982 END_PROFILE(SMBsetattrE);
6983 return;
6986 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
6988 if(!fsp || (fsp->conn != conn)) {
6989 reply_doserror(req, ERRDOS, ERRbadfid);
6990 END_PROFILE(SMBsetattrE);
6991 return;
6996 * Convert the DOS times into unix times. Ignore create
6997 * time as UNIX can't set this.
7000 ts[0] = convert_time_t_to_timespec(
7001 srv_make_unix_date2(req->inbuf+smb_vwv3)); /* atime. */
7002 ts[1] = convert_time_t_to_timespec(
7003 srv_make_unix_date2(req->inbuf+smb_vwv5)); /* mtime. */
7005 reply_outbuf(req, 0, 0);
7008 * Patch from Ray Frush <frush@engr.colostate.edu>
7009 * Sometimes times are sent as zero - ignore them.
7012 /* Ensure we have a valid stat struct for the source. */
7013 if (fsp->fh->fd != -1) {
7014 if (SMB_VFS_FSTAT(fsp, &sbuf) == -1) {
7015 status = map_nt_error_from_unix(errno);
7016 reply_nterror(req, status);
7017 END_PROFILE(SMBsetattrE);
7018 return;
7020 } else {
7021 if (SMB_VFS_STAT(conn, fsp->fsp_name, &sbuf) == -1) {
7022 status = map_nt_error_from_unix(errno);
7023 reply_nterror(req, status)
7024 END_PROFILE(SMBsetattrE);
7025 return;
7029 status = smb_set_file_time(conn, fsp, fsp->fsp_name,
7030 &sbuf, ts, true);
7031 if (!NT_STATUS_IS_OK(status)) {
7032 reply_doserror(req, ERRDOS, ERRnoaccess)
7033 END_PROFILE(SMBsetattrE);
7034 return;
7037 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
7038 fsp->fnum,
7039 (unsigned int)ts[0].tv_sec,
7040 (unsigned int)ts[1].tv_sec));
7042 END_PROFILE(SMBsetattrE);
7043 return;
7047 /* Back from the dead for OS/2..... JRA. */
7049 /****************************************************************************
7050 Reply to a SMBwritebmpx (write block multiplex primary) request.
7051 Always reply with an error, if someone has a platform really needs this,
7052 please contact vl@samba.org
7053 ****************************************************************************/
7055 void reply_writebmpx(struct smb_request *req)
7057 START_PROFILE(SMBwriteBmpx);
7058 reply_doserror(req, ERRSRV, ERRuseSTD);
7059 END_PROFILE(SMBwriteBmpx);
7060 return;
7063 /****************************************************************************
7064 Reply to a SMBwritebs (write block multiplex secondary) request.
7065 Always reply with an error, if someone has a platform really needs this,
7066 please contact vl@samba.org
7067 ****************************************************************************/
7069 void reply_writebs(struct smb_request *req)
7071 START_PROFILE(SMBwriteBs);
7072 reply_doserror(req, ERRSRV, ERRuseSTD);
7073 END_PROFILE(SMBwriteBs);
7074 return;
7077 /****************************************************************************
7078 Reply to a SMBgetattrE.
7079 ****************************************************************************/
7081 void reply_getattrE(struct smb_request *req)
7083 connection_struct *conn = req->conn;
7084 SMB_STRUCT_STAT sbuf;
7085 int mode;
7086 files_struct *fsp;
7088 START_PROFILE(SMBgetattrE);
7090 if (req->wct < 1) {
7091 reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
7092 END_PROFILE(SMBgetattrE);
7093 return;
7096 fsp = file_fsp(SVAL(req->inbuf,smb_vwv0));
7098 if(!fsp || (fsp->conn != conn)) {
7099 reply_doserror(req, ERRDOS, ERRbadfid);
7100 END_PROFILE(SMBgetattrE);
7101 return;
7104 /* Do an fstat on this file */
7105 if(fsp_stat(fsp, &sbuf)) {
7106 reply_unixerror(req, ERRDOS, ERRnoaccess);
7107 END_PROFILE(SMBgetattrE);
7108 return;
7111 mode = dos_mode(conn,fsp->fsp_name,&sbuf);
7114 * Convert the times into dos times. Set create
7115 * date to be last modify date as UNIX doesn't save
7116 * this.
7119 reply_outbuf(req, 11, 0);
7121 srv_put_dos_date2((char *)req->outbuf, smb_vwv0,
7122 get_create_time(&sbuf,
7123 lp_fake_dir_create_times(SNUM(conn))));
7124 srv_put_dos_date2((char *)req->outbuf, smb_vwv2, sbuf.st_atime);
7125 /* Should we check pending modtime here ? JRA */
7126 srv_put_dos_date2((char *)req->outbuf, smb_vwv4, sbuf.st_mtime);
7128 if (mode & aDIR) {
7129 SIVAL(req->outbuf, smb_vwv6, 0);
7130 SIVAL(req->outbuf, smb_vwv8, 0);
7131 } else {
7132 uint32 allocation_size = get_allocation_size(conn,fsp, &sbuf);
7133 SIVAL(req->outbuf, smb_vwv6, (uint32)sbuf.st_size);
7134 SIVAL(req->outbuf, smb_vwv8, allocation_size);
7136 SSVAL(req->outbuf,smb_vwv10, mode);
7138 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
7140 END_PROFILE(SMBgetattrE);
7141 return;