source: trunk/samba/source/smbd/reply.c @ 30

Last change on this file since 30 was 30, checked in by Paul Smedley, 14 years ago

Code updated to Samba 3.0.25rc2 level

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