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