Change check_path_syntax() to use the new next_mb_char_size() function
[Samba/gebeck_regimport.git] / source3 / smbd / reply.c
blob0fe73cddc28f6e08a795baef25c643799b82ede3
1 /*
2 Unix SMB/CIFS implementation.
3 Main SMB reply routines
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jeremy Allison 1992-2004.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 This file handles most of the reply_ calls that the server
24 makes to handle specific protocols
27 #include "includes.h"
29 /* look in server.c for some explanation of these variables */
30 extern int Protocol;
31 extern int max_send;
32 extern int max_recv;
33 extern char magic_char;
34 extern BOOL case_sensitive;
35 extern BOOL case_preserve;
36 extern BOOL short_case_preserve;
37 extern int global_oplock_break;
38 unsigned int smb_echo_count = 0;
40 extern BOOL global_encrypted_passwords_negotiated;
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 ****************************************************************************/
49 NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
51 char *d = destname;
52 const char *s = srcname;
53 NTSTATUS ret = NT_STATUS_OK;
55 while (*s) {
56 if (IS_DIRECTORY_SEP(*s)) {
58 * Safe to assume is not the second part of a mb char as this is handled below.
60 /* Eat multiple '/' or '\\' */
61 while (IS_DIRECTORY_SEP(*s)) {
62 s++;
64 if ((d != destname) && (*s != '\0')) {
65 /* We only care about non-leading or trailing '/' or '\\' */
66 *d++ = '/';
68 } else if ((s[0] == '.') && (s[1] == '.') && (IS_DIRECTORY_SEP(s[2]) || s[2] == '\0')) {
69 /* Uh oh - "../" or "..\\" or "..\0" ! */
72 * No mb char starts with '.' so we're safe checking the directory separator here.
75 /* If we just added a '/', delete it. */
77 if ((d > destname) && (*(d-1) == '/')) {
78 *(d-1) = '\0';
79 if (d == (destname + 1)) {
80 d--;
81 } else {
82 d -= 2;
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;
89 /* Go back one level... */
90 /* We know this is safe as '/' cannot be part of a mb sequence. */
91 /* NOTE - if this assumption is invalid we are not in good shape... */
92 while (d > destname) {
93 if (*d == '/')
94 break;
95 d--;
97 s += 3;
98 } else if ((s[0] == '.') && IS_DIRECTORY_SEP(s[1])) {
101 * No mb char starts with '.' so we're safe checking the directory separator here.
104 /* "./" or ".\\" fails with a different error depending on where it is... */
106 if (s == srcname) {
107 ret = NT_STATUS_OBJECT_NAME_INVALID;
108 } else {
109 if (s[2] == '\0') {
110 return NT_STATUS_INVALID_PARAMETER;
112 ret = NT_STATUS_OBJECT_PATH_NOT_FOUND;
114 s++;
115 } else {
116 switch(next_mb_char_size(s)) {
117 case 4:
118 *d++ = *s++;
119 case 3:
120 *d++ = *s++;
121 case 2:
122 *d++ = *s++;
123 case 1:
124 *d++ = *s++;
125 break;
126 default:
127 DEBUG(0,("check_path_syntax: character length assumptions invalid !\n"));
128 return NT_STATUS_INVALID_PARAMETER;
132 *d = '\0';
133 return ret;
136 /****************************************************************************
137 Pull a string and check the path - provide for error return.
138 ****************************************************************************/
140 size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err)
142 pstring tmppath;
143 char *tmppath_ptr = tmppath;
144 size_t ret;
145 #ifdef DEVELOPER
146 SMB_ASSERT(dest_len == sizeof(pstring));
147 #endif
149 if (src_len == 0) {
150 ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
151 } else {
152 ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
154 *err = check_path_syntax(dest, tmppath);
155 return ret;
158 /****************************************************************************
159 Reply to a special message.
160 ****************************************************************************/
162 int reply_special(char *inbuf,char *outbuf)
164 int outsize = 4;
165 int msg_type = CVAL(inbuf,0);
166 int msg_flags = CVAL(inbuf,1);
167 fstring name1,name2;
168 char name_type = 0;
170 static BOOL already_got_session = False;
172 *name1 = *name2 = 0;
174 memset(outbuf,'\0',smb_size);
176 smb_setlen(outbuf,0);
178 switch (msg_type) {
179 case 0x81: /* session request */
181 if (already_got_session) {
182 exit_server("multiple session request not permitted");
185 SCVAL(outbuf,0,0x82);
186 SCVAL(outbuf,3,0);
187 if (name_len(inbuf+4) > 50 ||
188 name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
189 DEBUG(0,("Invalid name length in session request\n"));
190 return(0);
192 name_extract(inbuf,4,name1);
193 name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
194 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
195 name1,name2));
197 set_local_machine_name(name1, True);
198 set_remote_machine_name(name2, True);
200 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
201 get_local_machine_name(), get_remote_machine_name(),
202 name_type));
204 if (name_type == 'R') {
205 /* We are being asked for a pathworks session ---
206 no thanks! */
207 SCVAL(outbuf, 0,0x83);
208 break;
211 /* only add the client's machine name to the list
212 of possibly valid usernames if we are operating
213 in share mode security */
214 if (lp_security() == SEC_SHARE) {
215 add_session_user(get_remote_machine_name());
218 reload_services(True);
219 reopen_logs();
221 claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD);
223 already_got_session = True;
224 break;
226 case 0x89: /* session keepalive request
227 (some old clients produce this?) */
228 SCVAL(outbuf,0,SMBkeepalive);
229 SCVAL(outbuf,3,0);
230 break;
232 case 0x82: /* positive session response */
233 case 0x83: /* negative session response */
234 case 0x84: /* retarget session response */
235 DEBUG(0,("Unexpected session response\n"));
236 break;
238 case SMBkeepalive: /* session keepalive */
239 default:
240 return(0);
243 DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
244 msg_type, msg_flags));
246 return(outsize);
249 /****************************************************************************
250 Reply to a tcon.
251 ****************************************************************************/
253 int reply_tcon(connection_struct *conn,
254 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
256 const char *service;
257 pstring service_buf;
258 pstring password;
259 pstring dev;
260 int outsize = 0;
261 uint16 vuid = SVAL(inbuf,smb_uid);
262 int pwlen=0;
263 NTSTATUS nt_status;
264 char *p;
265 DATA_BLOB password_blob;
267 START_PROFILE(SMBtcon);
269 *service_buf = *password = *dev = 0;
271 p = smb_buf(inbuf)+1;
272 p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service_buf), STR_TERMINATE) + 1;
273 pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1;
274 p += pwlen;
275 p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1;
277 p = strrchr_m(service_buf,'\\');
278 if (p) {
279 service = p+1;
280 } else {
281 service = service_buf;
284 password_blob = data_blob(password, pwlen+1);
286 conn = make_connection(service,password_blob,dev,vuid,&nt_status);
288 data_blob_clear_free(&password_blob);
290 if (!conn) {
291 END_PROFILE(SMBtcon);
292 return ERROR_NT(nt_status);
295 outsize = set_message(outbuf,2,0,True);
296 SSVAL(outbuf,smb_vwv0,max_recv);
297 SSVAL(outbuf,smb_vwv1,conn->cnum);
298 SSVAL(outbuf,smb_tid,conn->cnum);
300 DEBUG(3,("tcon service=%s cnum=%d\n",
301 service, conn->cnum));
303 END_PROFILE(SMBtcon);
304 return(outsize);
307 /****************************************************************************
308 Reply to a tcon and X.
309 ****************************************************************************/
311 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
313 fstring service;
314 DATA_BLOB password;
316 /* what the cleint thinks the device is */
317 fstring client_devicetype;
318 /* what the server tells the client the share represents */
319 const char *server_devicetype;
320 NTSTATUS nt_status;
321 uint16 vuid = SVAL(inbuf,smb_uid);
322 int passlen = SVAL(inbuf,smb_vwv3);
323 pstring path;
324 char *p, *q;
325 extern BOOL global_encrypted_passwords_negotiated;
327 START_PROFILE(SMBtconX);
329 *service = *client_devicetype = 0;
331 /* we might have to close an old one */
332 if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
333 close_cnum(conn,vuid);
336 if (passlen > MAX_PASS_LEN) {
337 return ERROR_DOS(ERRDOS,ERRbuftoosmall);
340 if (global_encrypted_passwords_negotiated) {
341 password = data_blob(smb_buf(inbuf),passlen);
342 } else {
343 password = data_blob(smb_buf(inbuf),passlen+1);
344 /* Ensure correct termination */
345 password.data[passlen]=0;
348 p = smb_buf(inbuf) + passlen;
349 p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
352 * the service name can be either: \\server\share
353 * or share directly like on the DELL PowerVault 705
355 if (*path=='\\') {
356 q = strchr_m(path+2,'\\');
357 if (!q) {
358 END_PROFILE(SMBtconX);
359 return(ERROR_DOS(ERRDOS,ERRnosuchshare));
361 fstrcpy(service,q+1);
363 else
364 fstrcpy(service,path);
366 p += srvstr_pull(inbuf, client_devicetype, p, sizeof(client_devicetype), 6, STR_ASCII);
368 DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
370 conn = make_connection(service,password,client_devicetype,vuid,&nt_status);
372 data_blob_clear_free(&password);
374 if (!conn) {
375 END_PROFILE(SMBtconX);
376 return ERROR_NT(nt_status);
379 if ( IS_IPC(conn) )
380 server_devicetype = "IPC";
381 else if ( IS_PRINT(conn) )
382 server_devicetype = "LPT1:";
383 else
384 server_devicetype = "A:";
386 if (Protocol < PROTOCOL_NT1) {
387 set_message(outbuf,2,0,True);
388 p = smb_buf(outbuf);
389 p += srvstr_push(outbuf, p, server_devicetype, -1,
390 STR_TERMINATE|STR_ASCII);
391 set_message_end(outbuf,p);
392 } else {
393 /* NT sets the fstype of IPC$ to the null string */
394 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
396 set_message(outbuf,3,0,True);
398 p = smb_buf(outbuf);
399 p += srvstr_push(outbuf, p, server_devicetype, -1,
400 STR_TERMINATE|STR_ASCII);
401 p += srvstr_push(outbuf, p, fstype, -1,
402 STR_TERMINATE);
404 set_message_end(outbuf,p);
406 /* what does setting this bit do? It is set by NT4 and
407 may affect the ability to autorun mounted cdroms */
408 SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
409 (lp_csc_policy(SNUM(conn)) << 2));
411 init_dfsroot(conn, inbuf, outbuf);
415 DEBUG(3,("tconX service=%s \n",
416 service));
418 /* set the incoming and outgoing tid to the just created one */
419 SSVAL(inbuf,smb_tid,conn->cnum);
420 SSVAL(outbuf,smb_tid,conn->cnum);
422 END_PROFILE(SMBtconX);
423 return chain_reply(inbuf,outbuf,length,bufsize);
426 /****************************************************************************
427 Reply to an unknown type.
428 ****************************************************************************/
430 int reply_unknown(char *inbuf,char *outbuf)
432 int type;
433 type = CVAL(inbuf,smb_com);
435 DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
436 smb_fn_name(type), type, type));
438 return(ERROR_DOS(ERRSRV,ERRunknownsmb));
441 /****************************************************************************
442 Reply to an ioctl.
443 ****************************************************************************/
445 int reply_ioctl(connection_struct *conn,
446 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
448 uint16 device = SVAL(inbuf,smb_vwv1);
449 uint16 function = SVAL(inbuf,smb_vwv2);
450 uint32 ioctl_code = (device << 16) + function;
451 int replysize, outsize;
452 char *p;
453 START_PROFILE(SMBioctl);
455 DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
457 switch (ioctl_code) {
458 case IOCTL_QUERY_JOB_INFO:
459 replysize = 32;
460 break;
461 default:
462 END_PROFILE(SMBioctl);
463 return(ERROR_DOS(ERRSRV,ERRnosupport));
466 outsize = set_message(outbuf,8,replysize+1,True);
467 SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
468 SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
469 SSVAL(outbuf,smb_vwv6,52); /* Offset to data */
470 p = smb_buf(outbuf) + 1; /* Allow for alignment */
472 switch (ioctl_code) {
473 case IOCTL_QUERY_JOB_INFO:
475 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
476 if (!fsp) {
477 END_PROFILE(SMBioctl);
478 return(UNIXERROR(ERRDOS,ERRbadfid));
480 SSVAL(p,0,fsp->rap_print_jobid); /* Job number */
481 srvstr_push(outbuf, p+2, global_myname(), 15, STR_TERMINATE|STR_ASCII);
482 srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII);
483 break;
487 END_PROFILE(SMBioctl);
488 return outsize;
491 /****************************************************************************
492 Reply to a chkpth.
493 ****************************************************************************/
495 int reply_chkpth(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
497 int outsize = 0;
498 int mode;
499 pstring name;
500 BOOL ok = False;
501 BOOL bad_path = False;
502 SMB_STRUCT_STAT sbuf;
503 NTSTATUS status;
505 START_PROFILE(SMBchkpth);
507 srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
508 if (!NT_STATUS_IS_OK(status)) {
509 END_PROFILE(SMBchkpth);
510 return ERROR_NT(status);
513 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
515 unix_convert(name,conn,0,&bad_path,&sbuf);
517 mode = SVAL(inbuf,smb_vwv0);
519 if (check_name(name,conn)) {
520 if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,name,&sbuf) == 0)
521 if (!(ok = S_ISDIR(sbuf.st_mode))) {
522 END_PROFILE(SMBchkpth);
523 return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath);
527 if (!ok) {
528 /* We special case this - as when a Windows machine
529 is parsing a path is steps through the components
530 one at a time - if a component fails it expects
531 ERRbadpath, not ERRbadfile.
533 if(errno == ENOENT) {
535 * Windows returns different error codes if
536 * the parent directory is valid but not the
537 * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
538 * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
539 * if the path is invalid.
541 if (bad_path) {
542 END_PROFILE(SMBchkpth);
543 return ERROR_NT(NT_STATUS_OBJECT_PATH_NOT_FOUND);
544 } else {
545 END_PROFILE(SMBchkpth);
546 return ERROR_NT(NT_STATUS_OBJECT_NAME_NOT_FOUND);
548 } else if (errno == ENOTDIR) {
549 END_PROFILE(SMBchkpth);
550 return ERROR_NT(NT_STATUS_NOT_A_DIRECTORY);
553 END_PROFILE(SMBchkpth);
554 return(UNIXERROR(ERRDOS,ERRbadpath));
557 outsize = set_message(outbuf,0,0,True);
559 DEBUG(3,("chkpth %s mode=%d\n", name, mode));
561 END_PROFILE(SMBchkpth);
562 return(outsize);
565 /****************************************************************************
566 Reply to a getatr.
567 ****************************************************************************/
569 int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
571 pstring fname;
572 int outsize = 0;
573 SMB_STRUCT_STAT sbuf;
574 BOOL ok = False;
575 int mode=0;
576 SMB_OFF_T size=0;
577 time_t mtime=0;
578 BOOL bad_path = False;
579 char *p;
580 NTSTATUS status;
582 START_PROFILE(SMBgetatr);
584 p = smb_buf(inbuf) + 1;
585 p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
586 if (!NT_STATUS_IS_OK(status)) {
587 END_PROFILE(SMBgetatr);
588 return ERROR_NT(status);
591 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
593 /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
594 under WfWg - weird! */
595 if (! (*fname)) {
596 mode = aHIDDEN | aDIR;
597 if (!CAN_WRITE(conn))
598 mode |= aRONLY;
599 size = 0;
600 mtime = 0;
601 ok = True;
602 } else {
603 unix_convert(fname,conn,0,&bad_path,&sbuf);
604 if (check_name(fname,conn)) {
605 if (VALID_STAT(sbuf) || SMB_VFS_STAT(conn,fname,&sbuf) == 0) {
606 mode = dos_mode(conn,fname,&sbuf);
607 size = sbuf.st_size;
608 mtime = sbuf.st_mtime;
609 if (mode & aDIR)
610 size = 0;
611 ok = True;
612 } else {
613 DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
618 if (!ok) {
619 END_PROFILE(SMBgetatr);
620 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS,ERRbadfile);
623 outsize = set_message(outbuf,10,0,True);
625 SSVAL(outbuf,smb_vwv0,mode);
626 if(lp_dos_filetime_resolution(SNUM(conn)) )
627 put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
628 else
629 put_dos_date3(outbuf,smb_vwv1,mtime);
630 SIVAL(outbuf,smb_vwv3,(uint32)size);
632 if (Protocol >= PROTOCOL_NT1)
633 SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
635 DEBUG( 3, ( "getatr name=%s mode=%d size=%d\n", fname, mode, (uint32)size ) );
637 END_PROFILE(SMBgetatr);
638 return(outsize);
641 /****************************************************************************
642 Reply to a setatr.
643 ****************************************************************************/
645 int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
647 pstring fname;
648 int outsize = 0;
649 BOOL ok=False;
650 int mode;
651 time_t mtime;
652 SMB_STRUCT_STAT sbuf;
653 BOOL bad_path = False;
654 char *p;
655 NTSTATUS status;
657 START_PROFILE(SMBsetatr);
659 p = smb_buf(inbuf) + 1;
660 p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
661 if (!NT_STATUS_IS_OK(status)) {
662 END_PROFILE(SMBsetatr);
663 return ERROR_NT(status);
666 unix_convert(fname,conn,0,&bad_path,&sbuf);
668 mode = SVAL(inbuf,smb_vwv0);
669 mtime = make_unix_date3(inbuf+smb_vwv1);
671 if (mode != FILE_ATTRIBUTE_NORMAL) {
672 if (VALID_STAT_OF_DIR(sbuf))
673 mode |= aDIR;
674 else
675 mode &= ~aDIR;
677 if (check_name(fname,conn))
678 ok = (file_chmod(conn,fname,mode,NULL) == 0);
679 } else {
680 ok = True;
683 if (ok)
684 ok = set_filetime(conn,fname,mtime);
686 if (!ok) {
687 END_PROFILE(SMBsetatr);
688 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
691 outsize = set_message(outbuf,0,0,True);
693 DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
695 END_PROFILE(SMBsetatr);
696 return(outsize);
699 /****************************************************************************
700 Reply to a dskattr.
701 ****************************************************************************/
703 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
705 int outsize = 0;
706 SMB_BIG_UINT dfree,dsize,bsize;
707 START_PROFILE(SMBdskattr);
709 SMB_VFS_DISK_FREE(conn,".",True,&bsize,&dfree,&dsize);
711 outsize = set_message(outbuf,5,0,True);
713 if (Protocol <= PROTOCOL_LANMAN2) {
714 double total_space, free_space;
715 /* we need to scale this to a number that DOS6 can handle. We
716 use floating point so we can handle large drives on systems
717 that don't have 64 bit integers
719 we end up displaying a maximum of 2G to DOS systems
721 total_space = dsize * (double)bsize;
722 free_space = dfree * (double)bsize;
724 dsize = (total_space+63*512) / (64*512);
725 dfree = (free_space+63*512) / (64*512);
727 if (dsize > 0xFFFF) dsize = 0xFFFF;
728 if (dfree > 0xFFFF) dfree = 0xFFFF;
730 SSVAL(outbuf,smb_vwv0,dsize);
731 SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
732 SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */
733 SSVAL(outbuf,smb_vwv3,dfree);
734 } else {
735 SSVAL(outbuf,smb_vwv0,dsize);
736 SSVAL(outbuf,smb_vwv1,bsize/512);
737 SSVAL(outbuf,smb_vwv2,512);
738 SSVAL(outbuf,smb_vwv3,dfree);
741 DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
743 END_PROFILE(SMBdskattr);
744 return(outsize);
747 /****************************************************************************
748 Reply to a search.
749 Can be called from SMBsearch, SMBffirst or SMBfunique.
750 ****************************************************************************/
752 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
754 pstring mask;
755 pstring directory;
756 pstring fname;
757 SMB_OFF_T size;
758 int mode;
759 time_t date;
760 int dirtype;
761 int outsize = 0;
762 unsigned int numentries = 0;
763 unsigned int maxentries = 0;
764 BOOL finished = False;
765 char *p;
766 BOOL ok = False;
767 int status_len;
768 pstring path;
769 char status[21];
770 int dptr_num= -1;
771 BOOL check_descend = False;
772 BOOL expect_close = False;
773 BOOL can_open = True;
774 BOOL bad_path = False;
775 NTSTATUS nt_status;
776 START_PROFILE(SMBsearch);
778 *mask = *directory = *fname = 0;
780 /* If we were called as SMBffirst then we must expect close. */
781 if(CVAL(inbuf,smb_com) == SMBffirst)
782 expect_close = True;
784 outsize = set_message(outbuf,1,3,True);
785 maxentries = SVAL(inbuf,smb_vwv0);
786 dirtype = SVAL(inbuf,smb_vwv1);
787 p = smb_buf(inbuf) + 1;
788 p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status);
789 if (!NT_STATUS_IS_OK(nt_status)) {
790 END_PROFILE(SMBsearch);
791 return ERROR_NT(nt_status);
793 p++;
794 status_len = SVAL(p, 0);
795 p += 2;
797 /* dirtype &= ~aDIR; */
799 if (status_len == 0) {
800 SMB_STRUCT_STAT sbuf;
801 pstring dir2;
803 pstrcpy(directory,path);
804 pstrcpy(dir2,path);
805 unix_convert(directory,conn,0,&bad_path,&sbuf);
806 unix_format(dir2);
808 if (!check_name(directory,conn))
809 can_open = False;
811 p = strrchr_m(dir2,'/');
812 if (p == NULL) {
813 pstrcpy(mask,dir2);
814 *dir2 = 0;
815 } else {
816 *p = 0;
817 pstrcpy(mask,p+1);
820 p = strrchr_m(directory,'/');
821 if (!p)
822 *directory = 0;
823 else
824 *p = 0;
826 if (strlen(directory) == 0)
827 pstrcpy(directory,".");
828 memset((char *)status,'\0',21);
829 SCVAL(status,0,(dirtype & 0x1F));
830 } else {
831 int status_dirtype;
833 memcpy(status,p,21);
834 status_dirtype = CVAL(status,0) & 0x1F;
835 if (status_dirtype != (dirtype & 0x1F))
836 dirtype = status_dirtype;
838 conn->dirptr = dptr_fetch(status+12,&dptr_num);
839 if (!conn->dirptr)
840 goto SearchEmpty;
841 string_set(&conn->dirpath,dptr_path(dptr_num));
842 pstrcpy(mask, dptr_wcard(dptr_num));
845 if (can_open) {
846 p = smb_buf(outbuf) + 3;
847 ok = True;
849 if (status_len == 0) {
850 dptr_num = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid));
851 if (dptr_num < 0) {
852 if(dptr_num == -2) {
853 END_PROFILE(SMBsearch);
854 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnofids);
856 END_PROFILE(SMBsearch);
857 return ERROR_DOS(ERRDOS,ERRnofids);
859 dptr_set_wcard(dptr_num, strdup(mask));
860 dptr_set_attr(dptr_num, dirtype);
861 } else {
862 dirtype = dptr_attr(dptr_num);
865 DEBUG(4,("dptr_num is %d\n",dptr_num));
867 if (ok) {
868 if ((dirtype&0x1F) == aVOLID) {
869 memcpy(p,status,21);
870 make_dir_struct(p,"???????????",volume_label(SNUM(conn)),0,aVOLID,0);
871 dptr_fill(p+12,dptr_num);
872 if (dptr_zero(p+12) && (status_len==0))
873 numentries = 1;
874 else
875 numentries = 0;
876 p += DIR_STRUCT_SIZE;
877 } else {
878 unsigned int i;
879 maxentries = MIN(maxentries, ((BUFFER_SIZE - (p - outbuf))/DIR_STRUCT_SIZE));
881 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
882 conn->dirpath,lp_dontdescend(SNUM(conn))));
883 if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True))
884 check_descend = True;
886 for (i=numentries;(i<maxentries) && !finished;i++) {
887 finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
888 if (!finished) {
889 memcpy(p,status,21);
890 make_dir_struct(p,mask,fname,size,mode,date);
891 dptr_fill(p+12,dptr_num);
892 numentries++;
894 p += DIR_STRUCT_SIZE;
897 } /* if (ok ) */
901 SearchEmpty:
903 /* If we were called as SMBffirst with smb_search_id == NULL
904 and no entries were found then return error and close dirptr
905 (X/Open spec) */
907 if(ok && expect_close && numentries == 0 && status_len == 0) {
908 if (Protocol < PROTOCOL_NT1) {
909 SCVAL(outbuf,smb_rcls,ERRDOS);
910 SSVAL(outbuf,smb_err,ERRnofiles);
912 /* Also close the dptr - we know it's gone */
913 dptr_close(&dptr_num);
914 } else if (numentries == 0 || !ok) {
915 if (Protocol < PROTOCOL_NT1) {
916 SCVAL(outbuf,smb_rcls,ERRDOS);
917 SSVAL(outbuf,smb_err,ERRnofiles);
919 dptr_close(&dptr_num);
922 /* If we were called as SMBfunique, then we can close the dirptr now ! */
923 if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique)
924 dptr_close(&dptr_num);
926 SSVAL(outbuf,smb_vwv0,numentries);
927 SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
928 SCVAL(smb_buf(outbuf),0,5);
929 SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
931 if (Protocol >= PROTOCOL_NT1)
932 SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
934 outsize += DIR_STRUCT_SIZE*numentries;
935 smb_setlen(outbuf,outsize - 4);
937 if ((! *directory) && dptr_path(dptr_num))
938 slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
940 DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%u of %u\n",
941 smb_fn_name(CVAL(inbuf,smb_com)),
942 mask, directory, dirtype, numentries, maxentries ) );
944 END_PROFILE(SMBsearch);
945 return(outsize);
948 /****************************************************************************
949 Reply to a fclose (stop directory search).
950 ****************************************************************************/
952 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
954 int outsize = 0;
955 int status_len;
956 pstring path;
957 char status[21];
958 int dptr_num= -2;
959 char *p;
960 NTSTATUS err;
962 START_PROFILE(SMBfclose);
964 outsize = set_message(outbuf,1,0,True);
965 p = smb_buf(inbuf) + 1;
966 p += srvstr_get_path(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err);
967 if (!NT_STATUS_IS_OK(err)) {
968 END_PROFILE(SMBfclose);
969 return ERROR_NT(err);
971 p++;
972 status_len = SVAL(p,0);
973 p += 2;
975 if (status_len == 0) {
976 END_PROFILE(SMBfclose);
977 return ERROR_DOS(ERRSRV,ERRsrverror);
980 memcpy(status,p,21);
982 if(dptr_fetch(status+12,&dptr_num)) {
983 /* Close the dptr - we know it's gone */
984 dptr_close(&dptr_num);
987 SSVAL(outbuf,smb_vwv0,0);
989 DEBUG(3,("search close\n"));
991 END_PROFILE(SMBfclose);
992 return(outsize);
995 /****************************************************************************
996 Reply to an open.
997 ****************************************************************************/
999 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1001 pstring fname;
1002 int outsize = 0;
1003 int fmode=0;
1004 int share_mode;
1005 SMB_OFF_T size = 0;
1006 time_t mtime=0;
1007 mode_t unixmode;
1008 int rmode=0;
1009 SMB_STRUCT_STAT sbuf;
1010 BOOL bad_path = False;
1011 files_struct *fsp;
1012 int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1013 NTSTATUS status;
1014 START_PROFILE(SMBopen);
1016 share_mode = SVAL(inbuf,smb_vwv0);
1018 srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
1019 if (!NT_STATUS_IS_OK(status)) {
1020 END_PROFILE(SMBopen);
1021 return ERROR_NT(status);
1024 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1026 unix_convert(fname,conn,0,&bad_path,&sbuf);
1028 unixmode = unix_mode(conn,aARCH,fname);
1030 fsp = open_file_shared(conn,fname,&sbuf,share_mode,(FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
1031 unixmode, oplock_request,&rmode,NULL);
1033 if (!fsp) {
1034 END_PROFILE(SMBopen);
1035 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
1038 size = sbuf.st_size;
1039 fmode = dos_mode(conn,fname,&sbuf);
1040 mtime = sbuf.st_mtime;
1042 if (fmode & aDIR) {
1043 DEBUG(3,("attempt to open a directory %s\n",fname));
1044 close_file(fsp,False);
1045 END_PROFILE(SMBopen);
1046 return ERROR_DOS(ERRDOS,ERRnoaccess);
1049 outsize = set_message(outbuf,7,0,True);
1050 SSVAL(outbuf,smb_vwv0,fsp->fnum);
1051 SSVAL(outbuf,smb_vwv1,fmode);
1052 if(lp_dos_filetime_resolution(SNUM(conn)) )
1053 put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
1054 else
1055 put_dos_date3(outbuf,smb_vwv2,mtime);
1056 SIVAL(outbuf,smb_vwv4,(uint32)size);
1057 SSVAL(outbuf,smb_vwv6,rmode);
1059 if (oplock_request && lp_fake_oplocks(SNUM(conn)))
1060 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1062 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1063 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1064 END_PROFILE(SMBopen);
1065 return(outsize);
1068 /****************************************************************************
1069 Reply to an open and X.
1070 ****************************************************************************/
1072 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1074 pstring fname;
1075 int smb_mode = SVAL(inbuf,smb_vwv3);
1076 int smb_attr = SVAL(inbuf,smb_vwv5);
1077 /* Breakout the oplock request bits so we can set the
1078 reply bits separately. */
1079 BOOL ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
1080 BOOL core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1081 BOOL oplock_request = ex_oplock_request | core_oplock_request;
1082 #if 0
1083 int open_flags = SVAL(inbuf,smb_vwv2);
1084 int smb_sattr = SVAL(inbuf,smb_vwv4);
1085 uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
1086 #endif
1087 int smb_ofun = SVAL(inbuf,smb_vwv8);
1088 mode_t unixmode;
1089 SMB_OFF_T size=0;
1090 int fmode=0,mtime=0,rmode=0;
1091 SMB_STRUCT_STAT sbuf;
1092 int smb_action = 0;
1093 BOOL bad_path = False;
1094 files_struct *fsp;
1095 NTSTATUS status;
1096 START_PROFILE(SMBopenX);
1098 /* If it's an IPC, pass off the pipe handler. */
1099 if (IS_IPC(conn)) {
1100 if (lp_nt_pipe_support()) {
1101 END_PROFILE(SMBopenX);
1102 return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
1103 } else {
1104 END_PROFILE(SMBopenX);
1105 return ERROR_DOS(ERRSRV,ERRaccess);
1109 /* XXXX we need to handle passed times, sattr and flags */
1110 srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 END_PROFILE(SMBopenX);
1113 return ERROR_NT(status);
1116 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1118 unix_convert(fname,conn,0,&bad_path,&sbuf);
1120 unixmode = unix_mode(conn,smb_attr | aARCH, fname);
1122 fsp = open_file_shared(conn,fname,&sbuf,smb_mode,smb_ofun,unixmode,
1123 oplock_request, &rmode,&smb_action);
1125 if (!fsp) {
1126 END_PROFILE(SMBopenX);
1127 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
1130 size = sbuf.st_size;
1131 fmode = dos_mode(conn,fname,&sbuf);
1132 mtime = sbuf.st_mtime;
1133 if (fmode & aDIR) {
1134 close_file(fsp,False);
1135 END_PROFILE(SMBopenX);
1136 return ERROR_DOS(ERRDOS,ERRnoaccess);
1139 /* If the caller set the extended oplock request bit
1140 and we granted one (by whatever means) - set the
1141 correct bit for extended oplock reply.
1144 if (ex_oplock_request && lp_fake_oplocks(SNUM(conn)))
1145 smb_action |= EXTENDED_OPLOCK_GRANTED;
1147 if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1148 smb_action |= EXTENDED_OPLOCK_GRANTED;
1150 /* If the caller set the core oplock request bit
1151 and we granted one (by whatever means) - set the
1152 correct bit for core oplock reply.
1155 if (core_oplock_request && lp_fake_oplocks(SNUM(conn)))
1156 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1158 if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1159 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1161 set_message(outbuf,15,0,True);
1162 SSVAL(outbuf,smb_vwv2,fsp->fnum);
1163 SSVAL(outbuf,smb_vwv3,fmode);
1164 if(lp_dos_filetime_resolution(SNUM(conn)) )
1165 put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
1166 else
1167 put_dos_date3(outbuf,smb_vwv4,mtime);
1168 SIVAL(outbuf,smb_vwv6,(uint32)size);
1169 SSVAL(outbuf,smb_vwv8,rmode);
1170 SSVAL(outbuf,smb_vwv11,smb_action);
1172 END_PROFILE(SMBopenX);
1173 return chain_reply(inbuf,outbuf,length,bufsize);
1176 /****************************************************************************
1177 Reply to a SMBulogoffX.
1178 ****************************************************************************/
1180 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
1182 uint16 vuid = SVAL(inbuf,smb_uid);
1183 user_struct *vuser = get_valid_user_struct(vuid);
1184 START_PROFILE(SMBulogoffX);
1186 if(vuser == 0)
1187 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
1189 /* in user level security we are supposed to close any files
1190 open by this user */
1191 if ((vuser != 0) && (lp_security() != SEC_SHARE))
1192 file_close_user(vuid);
1194 invalidate_vuid(vuid);
1196 set_message(outbuf,2,0,True);
1198 DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
1200 END_PROFILE(SMBulogoffX);
1201 return chain_reply(inbuf,outbuf,length,bufsize);
1204 /****************************************************************************
1205 Reply to a mknew or a create.
1206 ****************************************************************************/
1208 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1210 pstring fname;
1211 int com;
1212 int outsize = 0;
1213 int createmode;
1214 mode_t unixmode;
1215 int ofun = 0;
1216 BOOL bad_path = False;
1217 files_struct *fsp;
1218 int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1219 SMB_STRUCT_STAT sbuf;
1220 NTSTATUS status;
1221 START_PROFILE(SMBcreate);
1223 com = SVAL(inbuf,smb_com);
1225 createmode = SVAL(inbuf,smb_vwv0);
1226 srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 END_PROFILE(SMBcreate);
1229 return ERROR_NT(status);
1232 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1234 unix_convert(fname,conn,0,&bad_path,&sbuf);
1236 if (createmode & aVOLID)
1237 DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
1239 unixmode = unix_mode(conn,createmode,fname);
1241 if(com == SMBmknew) {
1242 /* We should fail if file exists. */
1243 ofun = FILE_CREATE_IF_NOT_EXIST;
1244 } else {
1245 /* SMBcreate - Create if file doesn't exist, truncate if it does. */
1246 ofun = FILE_CREATE_IF_NOT_EXIST|FILE_EXISTS_TRUNCATE;
1249 /* Open file in dos compatibility share mode. */
1250 fsp = open_file_shared(conn,fname,&sbuf,SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
1251 ofun, unixmode, oplock_request, NULL, NULL);
1253 if (!fsp) {
1254 END_PROFILE(SMBcreate);
1255 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
1258 outsize = set_message(outbuf,1,0,True);
1259 SSVAL(outbuf,smb_vwv0,fsp->fnum);
1261 if (oplock_request && lp_fake_oplocks(SNUM(conn)))
1262 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1264 if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1265 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1267 DEBUG( 2, ( "new file %s\n", fname ) );
1268 DEBUG( 3, ( "mknew %s fd=%d dmode=%d umode=%o\n", fname, fsp->fd, createmode, (int)unixmode ) );
1270 END_PROFILE(SMBcreate);
1271 return(outsize);
1274 /****************************************************************************
1275 Reply to a create temporary file.
1276 ****************************************************************************/
1278 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
1280 pstring fname;
1281 int outsize = 0;
1282 int createmode;
1283 mode_t unixmode;
1284 BOOL bad_path = False;
1285 files_struct *fsp;
1286 int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
1287 int tmpfd;
1288 SMB_STRUCT_STAT sbuf;
1289 char *p, *s;
1290 NTSTATUS status;
1292 START_PROFILE(SMBctemp);
1294 createmode = SVAL(inbuf,smb_vwv0);
1295 srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
1296 if (!NT_STATUS_IS_OK(status)) {
1297 END_PROFILE(SMBctemp);
1298 return ERROR_NT(status);
1300 pstrcat(fname,"\\TMXXXXXX");
1302 RESOLVE_DFSPATH(fname, conn, inbuf, outbuf);
1304 unix_convert(fname,conn,0,&bad_path,&sbuf);
1306 unixmode = unix_mode(conn,createmode,fname);
1308 tmpfd = smb_mkstemp(fname);
1309 if (tmpfd == -1) {
1310 END_PROFILE(SMBctemp);
1311 return(UNIXERROR(ERRDOS,ERRnoaccess));
1314 SMB_VFS_STAT(conn,fname,&sbuf);
1316 /* Open file in dos compatibility share mode. */
1317 /* We should fail if file does not exist. */
1318 fsp = open_file_shared(conn,fname,&sbuf,
1319 SET_DENY_MODE(DENY_FCB)|SET_OPEN_MODE(DOS_OPEN_FCB),
1320 FILE_EXISTS_OPEN|FILE_FAIL_IF_NOT_EXIST,
1321 unixmode, oplock_request, NULL, NULL);
1323 /* close fd from smb_mkstemp() */
1324 close(tmpfd);
1326 if (!fsp) {
1327 END_PROFILE(SMBctemp);
1328 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRnoaccess);
1331 outsize = set_message(outbuf,1,0,True);
1332 SSVAL(outbuf,smb_vwv0,fsp->fnum);
1334 /* the returned filename is relative to the directory */
1335 s = strrchr_m(fname, '/');
1336 if (!s)
1337 s = fname;
1338 else
1339 s++;
1341 p = smb_buf(outbuf);
1342 SSVALS(p, 0, -1); /* what is this? not in spec */
1343 SSVAL(p, 2, strlen(s));
1344 p += 4;
1345 p += srvstr_push(outbuf, p, s, -1, STR_ASCII);
1346 outsize = set_message_end(outbuf, p);
1348 if (oplock_request && lp_fake_oplocks(SNUM(conn)))
1349 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1351 if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type))
1352 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
1354 DEBUG( 2, ( "created temp file %s\n", fname ) );
1355 DEBUG( 3, ( "ctemp %s fd=%d dmode=%d umode=%o\n",
1356 fname, fsp->fd, createmode, (int)unixmode ) );
1358 END_PROFILE(SMBctemp);
1359 return(outsize);
1362 /*******************************************************************
1363 Check if a user is allowed to rename a file.
1364 ********************************************************************/
1366 static NTSTATUS can_rename(char *fname,connection_struct *conn, SMB_STRUCT_STAT *pst)
1368 int smb_action;
1369 int access_mode;
1370 files_struct *fsp;
1372 if (!CAN_WRITE(conn))
1373 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1375 if (S_ISDIR(pst->st_mode))
1376 return NT_STATUS_OK;
1378 /* We need a better way to return NT status codes from open... */
1379 unix_ERR_class = 0;
1380 unix_ERR_code = 0;
1382 fsp = open_file_shared1(conn, fname, pst, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
1383 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
1385 if (!fsp) {
1386 NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
1387 if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
1388 ret = NT_STATUS_SHARING_VIOLATION;
1389 unix_ERR_class = 0;
1390 unix_ERR_code = 0;
1391 unix_ERR_ntstatus = NT_STATUS_OK;
1392 return ret;
1394 close_file(fsp,False);
1395 return NT_STATUS_OK;
1398 /*******************************************************************
1399 Check if a user is allowed to delete a file.
1400 ********************************************************************/
1402 static NTSTATUS can_delete(char *fname,connection_struct *conn, int dirtype, BOOL bad_path)
1404 SMB_STRUCT_STAT sbuf;
1405 int fmode;
1406 int smb_action;
1407 int access_mode;
1408 files_struct *fsp;
1410 DEBUG(10,("can_delete: %s, dirtype = %d\n",
1411 fname, dirtype ));
1413 if (!CAN_WRITE(conn))
1414 return NT_STATUS_MEDIA_WRITE_PROTECTED;
1416 if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
1417 if(errno == ENOENT) {
1418 if (bad_path)
1419 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
1420 else
1421 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1423 return map_nt_error_from_unix(errno);
1426 fmode = dos_mode(conn,fname,&sbuf);
1428 /* Can't delete a directory. */
1429 if (fmode & aDIR)
1430 return NT_STATUS_FILE_IS_A_DIRECTORY;
1431 #if 0 /* JRATEST */
1432 else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
1433 return NT_STATUS_OBJECT_NAME_INVALID;
1434 #endif /* JRATEST */
1436 if (!lp_delete_readonly(SNUM(conn))) {
1437 if (fmode & aRONLY)
1438 return NT_STATUS_CANNOT_DELETE;
1440 if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM))
1441 return NT_STATUS_NO_SUCH_FILE;
1443 /* We need a better way to return NT status codes from open... */
1444 unix_ERR_class = 0;
1445 unix_ERR_code = 0;
1447 fsp = open_file_shared1(conn, fname, &sbuf, DELETE_ACCESS, SET_DENY_MODE(DENY_ALL),
1448 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN), 0, 0, &access_mode, &smb_action);
1450 if (!fsp) {
1451 NTSTATUS ret = NT_STATUS_ACCESS_DENIED;
1452 if (!NT_STATUS_IS_OK(unix_ERR_ntstatus))
1453 ret = unix_ERR_ntstatus;
1454 else if (unix_ERR_class == ERRDOS && unix_ERR_code == ERRbadshare)
1455 ret = NT_STATUS_SHARING_VIOLATION;
1456 unix_ERR_class = 0;
1457 unix_ERR_code = 0;
1458 unix_ERR_ntstatus = NT_STATUS_OK;
1459 return ret;
1461 close_file(fsp,False);
1462 return NT_STATUS_OK;
1465 /****************************************************************************
1466 The guts of the unlink command, split out so it may be called by the NT SMB
1467 code.
1468 ****************************************************************************/
1470 NTSTATUS unlink_internals(connection_struct *conn, int dirtype, char *name)
1472 pstring directory;
1473 pstring mask;
1474 char *p;
1475 int count=0;
1476 NTSTATUS error = NT_STATUS_OK;
1477 BOOL has_wild;
1478 BOOL bad_path = False;
1479 BOOL rc = True;
1480 SMB_STRUCT_STAT sbuf;
1482 *directory = *mask = 0;
1484 /* We must check for wildcards in the name given
1485 * directly by the client - before any unmangling.
1486 * This prevents an unmangling of a UNIX name containing
1487 * a DOS wildcard like '*' or '?' from unmangling into
1488 * a wildcard delete which was not intended.
1489 * FIX for #226. JRA.
1492 has_wild = ms_has_wild(name);
1494 rc = unix_convert(name,conn,0,&bad_path,&sbuf);
1496 p = strrchr_m(name,'/');
1497 if (!p) {
1498 pstrcpy(directory,".");
1499 pstrcpy(mask,name);
1500 } else {
1501 *p = 0;
1502 pstrcpy(directory,name);
1503 pstrcpy(mask,p+1);
1507 * We should only check the mangled cache
1508 * here if unix_convert failed. This means
1509 * that the path in 'mask' doesn't exist
1510 * on the file system and so we need to look
1511 * for a possible mangle. This patch from
1512 * Tine Smukavec <valentin.smukavec@hermes.si>.
1515 if (!rc && mangle_is_mangled(mask))
1516 mangle_check_cache( mask );
1518 if (!has_wild) {
1519 pstrcat(directory,"/");
1520 pstrcat(directory,mask);
1521 error = can_delete(directory,conn,dirtype,bad_path);
1522 if (!NT_STATUS_IS_OK(error))
1523 return error;
1525 if (SMB_VFS_UNLINK(conn,directory) == 0) {
1526 count++;
1528 } else {
1529 void *dirptr = NULL;
1530 const char *dname;
1532 if (check_name(directory,conn))
1533 dirptr = OpenDir(conn, directory, True);
1535 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
1536 the pattern matches against the long name, otherwise the short name
1537 We don't implement this yet XXXX
1540 if (dirptr) {
1541 error = NT_STATUS_NO_SUCH_FILE;
1543 if (strequal(mask,"????????.???"))
1544 pstrcpy(mask,"*");
1546 while ((dname = ReadDirName(dirptr))) {
1547 pstring fname;
1548 BOOL sys_direntry = False;
1549 pstrcpy(fname,dname);
1551 /* Quick check for "." and ".." */
1552 if (fname[0] == '.') {
1553 if (!fname[1] || (fname[1] == '.' && !fname[2])) {
1554 if ((dirtype & aDIR)) {
1555 sys_direntry = True;
1556 } else {
1557 continue;
1562 if(!mask_match(fname, mask, case_sensitive))
1563 continue;
1565 if (sys_direntry) {
1566 error = NT_STATUS_OBJECT_NAME_INVALID;
1567 continue;
1570 slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
1571 error = can_delete(fname,conn,dirtype,bad_path);
1572 if (!NT_STATUS_IS_OK(error))
1573 continue;
1574 if (SMB_VFS_UNLINK(conn,fname) == 0)
1575 count++;
1576 DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname));
1578 CloseDir(dirptr);
1582 if (count == 0 && NT_STATUS_IS_OK(error)) {
1583 error = map_nt_error_from_unix(errno);
1586 return error;
1589 /****************************************************************************
1590 Reply to a unlink
1591 ****************************************************************************/
1593 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
1594 int dum_buffsize)
1596 int outsize = 0;
1597 pstring name;
1598 int dirtype;
1599 NTSTATUS status;
1600 START_PROFILE(SMBunlink);
1602 dirtype = SVAL(inbuf,smb_vwv0);
1604 srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 END_PROFILE(SMBunlink);
1607 return ERROR_NT(status);
1610 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
1612 DEBUG(3,("reply_unlink : %s\n",name));
1614 status = unlink_internals(conn, dirtype, name);
1615 if (!NT_STATUS_IS_OK(status))
1616 return ERROR_NT(status);
1619 * Win2k needs a changenotify request response before it will
1620 * update after a rename..
1622 process_pending_change_notify_queue((time_t)0);
1624 outsize = set_message(outbuf,0,0,True);
1626 END_PROFILE(SMBunlink);
1627 return outsize;
1630 /****************************************************************************
1631 Fail for readbraw.
1632 ****************************************************************************/
1634 void fail_readraw(void)
1636 pstring errstr;
1637 slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
1638 strerror(errno) );
1639 exit_server(errstr);
1642 /****************************************************************************
1643 Use sendfile in readbraw.
1644 ****************************************************************************/
1646 void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
1647 ssize_t mincount, char *outbuf)
1649 ssize_t ret=0;
1651 #if defined(WITH_SENDFILE)
1653 * We can only use sendfile on a non-chained packet and on a file
1654 * that is exclusively oplocked. reply_readbraw has already checked the length.
1657 if ((nread > 0) && (lp_write_cache_size(SNUM(conn)) == 0) &&
1658 EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && lp_use_sendfile(SNUM(conn)) ) {
1659 DATA_BLOB header;
1661 _smb_setlen(outbuf,nread);
1662 header.data = outbuf;
1663 header.length = 4;
1664 header.free = NULL;
1666 if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, nread) == -1) {
1668 * Special hack for broken Linux with no 64 bit clean sendfile. If we
1669 * return ENOSYS then pretend we just got a normal read.
1671 if (errno == ENOSYS)
1672 goto normal_read;
1674 DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
1675 fsp->fsp_name, strerror(errno) ));
1676 exit_server("send_file_readbraw sendfile failed");
1681 normal_read:
1682 #endif
1684 if (nread > 0) {
1685 ret = read_file(fsp,outbuf+4,startpos,nread);
1686 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
1687 if (ret < mincount)
1688 ret = 0;
1689 #else
1690 if (ret < nread)
1691 ret = 0;
1692 #endif
1695 _smb_setlen(outbuf,ret);
1696 if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
1697 fail_readraw();
1700 /****************************************************************************
1701 Reply to a readbraw (core+ protocol).
1702 ****************************************************************************/
1704 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int dum_buffsize)
1706 extern struct current_user current_user;
1707 ssize_t maxcount,mincount;
1708 size_t nread = 0;
1709 SMB_OFF_T startpos;
1710 char *header = outbuf;
1711 files_struct *fsp;
1712 START_PROFILE(SMBreadbraw);
1714 if (srv_is_signing_active()) {
1715 exit_server("reply_readbraw: SMB signing is active - raw reads/writes are disallowed.");
1719 * Special check if an oplock break has been issued
1720 * and the readraw request croses on the wire, we must
1721 * return a zero length response here.
1724 if(global_oplock_break) {
1725 _smb_setlen(header,0);
1726 if (write_data(smbd_server_fd(),header,4) != 4)
1727 fail_readraw();
1728 DEBUG(5,("readbraw - oplock break finished\n"));
1729 END_PROFILE(SMBreadbraw);
1730 return -1;
1733 fsp = file_fsp(inbuf,smb_vwv0);
1735 if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
1737 * fsp could be NULL here so use the value from the packet. JRA.
1739 DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
1740 _smb_setlen(header,0);
1741 if (write_data(smbd_server_fd(),header,4) != 4)
1742 fail_readraw();
1743 END_PROFILE(SMBreadbraw);
1744 return(-1);
1747 CHECK_FSP(fsp,conn);
1749 flush_write_cache(fsp, READRAW_FLUSH);
1751 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
1752 if(CVAL(inbuf,smb_wct) == 10) {
1754 * This is a large offset (64 bit) read.
1756 #ifdef LARGE_SMB_OFF_T
1758 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
1760 #else /* !LARGE_SMB_OFF_T */
1763 * Ensure we haven't been sent a >32 bit offset.
1766 if(IVAL(inbuf,smb_vwv8) != 0) {
1767 DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
1768 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
1769 _smb_setlen(header,0);
1770 if (write_data(smbd_server_fd(),header,4) != 4)
1771 fail_readraw();
1772 END_PROFILE(SMBreadbraw);
1773 return(-1);
1776 #endif /* LARGE_SMB_OFF_T */
1778 if(startpos < 0) {
1779 DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
1780 _smb_setlen(header,0);
1781 if (write_data(smbd_server_fd(),header,4) != 4)
1782 fail_readraw();
1783 END_PROFILE(SMBreadbraw);
1784 return(-1);
1787 maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
1788 mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
1790 /* ensure we don't overrun the packet size */
1791 maxcount = MIN(65535,maxcount);
1793 if (!is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
1794 SMB_OFF_T size = fsp->size;
1795 SMB_OFF_T sizeneeded = startpos + maxcount;
1797 if (size < sizeneeded) {
1798 SMB_STRUCT_STAT st;
1799 if (SMB_VFS_FSTAT(fsp,fsp->fd,&st) == 0)
1800 size = st.st_size;
1801 if (!fsp->can_write)
1802 fsp->size = size;
1805 if (startpos >= size)
1806 nread = 0;
1807 else
1808 nread = MIN(maxcount,(size - startpos));
1811 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
1812 if (nread < mincount)
1813 nread = 0;
1814 #endif
1816 DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%d min=%d nread=%d\n", fsp->fnum, (double)startpos,
1817 (int)maxcount, (int)mincount, (int)nread ) );
1819 send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf);
1821 DEBUG(5,("readbraw finished\n"));
1822 END_PROFILE(SMBreadbraw);
1823 return -1;
1826 /****************************************************************************
1827 Reply to a lockread (core+ protocol).
1828 ****************************************************************************/
1830 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
1832 ssize_t nread = -1;
1833 char *data;
1834 int outsize = 0;
1835 SMB_OFF_T startpos;
1836 size_t numtoread;
1837 NTSTATUS status;
1838 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1839 BOOL my_lock_ctx = False;
1840 START_PROFILE(SMBlockread);
1842 CHECK_FSP(fsp,conn);
1843 CHECK_READ(fsp);
1845 release_level_2_oplocks_on_change(fsp);
1847 numtoread = SVAL(inbuf,smb_vwv1);
1848 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
1850 outsize = set_message(outbuf,5,3,True);
1851 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1852 data = smb_buf(outbuf) + 3;
1855 * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
1856 * protocol request that predates the read/write lock concept.
1857 * Thus instead of asking for a read lock here we need to ask
1858 * for a write lock. JRA.
1859 * Note that the requested lock size is unaffected by max_recv.
1862 status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid),
1863 (SMB_BIG_UINT)numtoread, (SMB_BIG_UINT)startpos, WRITE_LOCK, &my_lock_ctx);
1865 if (NT_STATUS_V(status)) {
1866 #if 0
1868 * We used to make lockread a blocking lock. It turns out
1869 * that this isn't on W2k. Found by the Samba 4 RAW-READ torture
1870 * tester. JRA.
1873 if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
1875 * A blocking lock was requested. Package up
1876 * this smb into a queued request and push it
1877 * onto the blocking lock queue.
1879 if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)startpos,
1880 (SMB_BIG_UINT)numtoread)) {
1881 END_PROFILE(SMBlockread);
1882 return -1;
1885 #endif
1886 END_PROFILE(SMBlockread);
1887 return ERROR_NT(status);
1891 * However the requested READ size IS affected by max_recv. Insanity.... JRA.
1894 if (numtoread > max_recv) {
1895 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
1896 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
1897 (unsigned int)numtoread, (unsigned int)max_recv ));
1898 numtoread = MIN(numtoread,max_recv);
1900 nread = read_file(fsp,data,startpos,numtoread);
1902 if (nread < 0) {
1903 END_PROFILE(SMBlockread);
1904 return(UNIXERROR(ERRDOS,ERRnoaccess));
1907 outsize += nread;
1908 SSVAL(outbuf,smb_vwv0,nread);
1909 SSVAL(outbuf,smb_vwv5,nread+3);
1910 SSVAL(smb_buf(outbuf),1,nread);
1912 DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
1913 fsp->fnum, (int)numtoread, (int)nread));
1915 END_PROFILE(SMBlockread);
1916 return(outsize);
1919 /****************************************************************************
1920 Reply to a read.
1921 ****************************************************************************/
1923 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
1925 size_t numtoread;
1926 ssize_t nread = 0;
1927 char *data;
1928 SMB_OFF_T startpos;
1929 int outsize = 0;
1930 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
1931 START_PROFILE(SMBread);
1933 CHECK_FSP(fsp,conn);
1934 CHECK_READ(fsp);
1936 numtoread = SVAL(inbuf,smb_vwv1);
1937 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
1939 outsize = set_message(outbuf,5,3,True);
1940 numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
1942 * The requested read size cannot be greater than max_recv. JRA.
1944 if (numtoread > max_recv) {
1945 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
1946 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
1947 (unsigned int)numtoread, (unsigned int)max_recv ));
1948 numtoread = MIN(numtoread,max_recv);
1951 data = smb_buf(outbuf) + 3;
1953 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
1954 END_PROFILE(SMBread);
1955 return ERROR_DOS(ERRDOS,ERRlock);
1958 if (numtoread > 0)
1959 nread = read_file(fsp,data,startpos,numtoread);
1961 if (nread < 0) {
1962 END_PROFILE(SMBread);
1963 return(UNIXERROR(ERRDOS,ERRnoaccess));
1966 outsize += nread;
1967 SSVAL(outbuf,smb_vwv0,nread);
1968 SSVAL(outbuf,smb_vwv5,nread+3);
1969 SCVAL(smb_buf(outbuf),0,1);
1970 SSVAL(smb_buf(outbuf),1,nread);
1972 DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
1973 fsp->fnum, (int)numtoread, (int)nread ) );
1975 END_PROFILE(SMBread);
1976 return(outsize);
1979 /****************************************************************************
1980 Reply to a read and X - possibly using sendfile.
1981 ****************************************************************************/
1983 int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length,
1984 files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
1986 ssize_t nread = -1;
1987 char *data = smb_buf(outbuf);
1989 #if defined(WITH_SENDFILE)
1991 * We can only use sendfile on a non-chained packet and on a file
1992 * that is exclusively oplocked.
1995 if ((CVAL(inbuf,smb_vwv0) == 0xFF) && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) &&
1996 lp_use_sendfile(SNUM(conn)) && (lp_write_cache_size(SNUM(conn)) == 0) ) {
1997 SMB_STRUCT_STAT sbuf;
1998 DATA_BLOB header;
2000 if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1)
2001 return(UNIXERROR(ERRDOS,ERRnoaccess));
2003 if (startpos > sbuf.st_size)
2004 goto normal_read;
2006 if (smb_maxcnt > (sbuf.st_size - startpos))
2007 smb_maxcnt = (sbuf.st_size - startpos);
2009 if (smb_maxcnt == 0)
2010 goto normal_read;
2013 * Set up the packet header before send. We
2014 * assume here the sendfile will work (get the
2015 * correct amount of data).
2018 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
2019 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
2020 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2021 SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
2022 SCVAL(outbuf,smb_vwv0,0xFF);
2023 set_message(outbuf,12,smb_maxcnt,False);
2024 header.data = outbuf;
2025 header.length = data - outbuf;
2026 header.free = NULL;
2028 if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fd, &header, startpos, smb_maxcnt) == -1) {
2030 * Special hack for broken Linux with no 64 bit clean sendfile. If we
2031 * return ENOSYS then pretend we just got a normal read.
2033 if (errno == ENOSYS)
2034 goto normal_read;
2036 DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
2037 fsp->fsp_name, strerror(errno) ));
2038 exit_server("send_file_readX sendfile failed");
2041 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
2042 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
2043 return -1;
2046 normal_read:
2048 #endif
2050 nread = read_file(fsp,data,startpos,smb_maxcnt);
2052 if (nread < 0) {
2053 END_PROFILE(SMBreadX);
2054 return(UNIXERROR(ERRDOS,ERRnoaccess));
2057 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
2058 SSVAL(outbuf,smb_vwv5,nread);
2059 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
2060 SSVAL(smb_buf(outbuf),-2,nread);
2062 DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
2063 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
2065 return nread;
2068 /****************************************************************************
2069 Reply to a read and X.
2070 ****************************************************************************/
2072 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2074 files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2075 SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
2076 ssize_t nread = -1;
2077 size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
2078 #if 0
2079 size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
2080 #endif
2082 START_PROFILE(SMBreadX);
2084 /* If it's an IPC, pass off the pipe handler. */
2085 if (IS_IPC(conn)) {
2086 END_PROFILE(SMBreadX);
2087 return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
2090 CHECK_FSP(fsp,conn);
2091 CHECK_READ(fsp);
2093 set_message(outbuf,12,0,True);
2095 if(CVAL(inbuf,smb_wct) == 12) {
2096 #ifdef LARGE_SMB_OFF_T
2098 * This is a large offset (64 bit) read.
2100 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
2102 #else /* !LARGE_SMB_OFF_T */
2105 * Ensure we haven't been sent a >32 bit offset.
2108 if(IVAL(inbuf,smb_vwv10) != 0) {
2109 DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
2110 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
2111 END_PROFILE(SMBreadX);
2112 return ERROR_DOS(ERRDOS,ERRbadaccess);
2115 #endif /* LARGE_SMB_OFF_T */
2119 if (is_locked(fsp,conn,(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
2120 END_PROFILE(SMBreadX);
2121 return ERROR_DOS(ERRDOS,ERRlock);
2124 nread = send_file_readX(conn, inbuf, outbuf, length, fsp, startpos, smb_maxcnt);
2125 if (nread != -1)
2126 nread = chain_reply(inbuf,outbuf,length,bufsize);
2128 END_PROFILE(SMBreadX);
2129 return nread;
2132 /****************************************************************************
2133 Reply to a writebraw (core+ or LANMAN1.0 protocol).
2134 ****************************************************************************/
2136 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2138 ssize_t nwritten=0;
2139 ssize_t total_written=0;
2140 size_t numtowrite=0;
2141 size_t tcount;
2142 SMB_OFF_T startpos;
2143 char *data=NULL;
2144 BOOL write_through;
2145 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2146 int outsize = 0;
2147 START_PROFILE(SMBwritebraw);
2149 if (srv_is_signing_active()) {
2150 exit_server("reply_writebraw: SMB signing is active - raw reads/writes are disallowed.");
2153 CHECK_FSP(fsp,conn);
2154 CHECK_WRITE(fsp);
2156 tcount = IVAL(inbuf,smb_vwv1);
2157 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
2158 write_through = BITSETW(inbuf+smb_vwv7,0);
2160 /* We have to deal with slightly different formats depending
2161 on whether we are using the core+ or lanman1.0 protocol */
2163 if(Protocol <= PROTOCOL_COREPLUS) {
2164 numtowrite = SVAL(smb_buf(inbuf),-2);
2165 data = smb_buf(inbuf);
2166 } else {
2167 numtowrite = SVAL(inbuf,smb_vwv10);
2168 data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
2171 /* force the error type */
2172 SCVAL(inbuf,smb_com,SMBwritec);
2173 SCVAL(outbuf,smb_com,SMBwritec);
2175 if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2176 END_PROFILE(SMBwritebraw);
2177 return(ERROR_DOS(ERRDOS,ERRlock));
2180 if (numtowrite>0)
2181 nwritten = write_file(fsp,data,startpos,numtowrite);
2183 DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
2184 fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
2186 if (nwritten < (ssize_t)numtowrite) {
2187 END_PROFILE(SMBwritebraw);
2188 return(UNIXERROR(ERRHRD,ERRdiskfull));
2191 total_written = nwritten;
2193 /* Return a message to the redirector to tell it to send more bytes */
2194 SCVAL(outbuf,smb_com,SMBwritebraw);
2195 SSVALS(outbuf,smb_vwv0,-1);
2196 outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
2197 if (!send_smb(smbd_server_fd(),outbuf))
2198 exit_server("reply_writebraw: send_smb failed.");
2200 /* Now read the raw data into the buffer and write it */
2201 if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
2202 exit_server("secondary writebraw failed");
2205 /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
2206 numtowrite = smb_len(inbuf);
2208 /* Set up outbuf to return the correct return */
2209 outsize = set_message(outbuf,1,0,True);
2210 SCVAL(outbuf,smb_com,SMBwritec);
2211 SSVAL(outbuf,smb_vwv0,total_written);
2213 if (numtowrite != 0) {
2215 if (numtowrite > BUFFER_SIZE) {
2216 DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
2217 (unsigned int)numtowrite ));
2218 exit_server("secondary writebraw failed");
2221 if (tcount > nwritten+numtowrite) {
2222 DEBUG(3,("Client overestimated the write %d %d %d\n",
2223 (int)tcount,(int)nwritten,(int)numtowrite));
2226 if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
2227 DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
2228 strerror(errno) ));
2229 exit_server("secondary writebraw failed");
2232 nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
2234 if (nwritten < (ssize_t)numtowrite) {
2235 SCVAL(outbuf,smb_rcls,ERRHRD);
2236 SSVAL(outbuf,smb_err,ERRdiskfull);
2239 if (nwritten > 0)
2240 total_written += nwritten;
2243 if ((lp_syncalways(SNUM(conn)) || write_through) && lp_strict_sync(SNUM(conn)))
2244 sync_file(conn,fsp);
2246 DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
2247 fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
2249 /* we won't return a status if write through is not selected - this follows what WfWg does */
2250 END_PROFILE(SMBwritebraw);
2251 if (!write_through && total_written==tcount) {
2253 #if RABBIT_PELLET_FIX
2255 * Fix for "rabbit pellet" mode, trigger an early TCP ack by
2256 * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
2258 if (!send_keepalive(smbd_server_fd()))
2259 exit_server("reply_writebraw: send of keepalive failed");
2260 #endif
2261 return(-1);
2264 return(outsize);
2267 /****************************************************************************
2268 Reply to a writeunlock (core+).
2269 ****************************************************************************/
2271 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf,
2272 int size, int dum_buffsize)
2274 ssize_t nwritten = -1;
2275 size_t numtowrite;
2276 SMB_OFF_T startpos;
2277 char *data;
2278 NTSTATUS status = NT_STATUS_OK;
2279 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2280 int outsize = 0;
2281 START_PROFILE(SMBwriteunlock);
2283 CHECK_FSP(fsp,conn);
2284 CHECK_WRITE(fsp);
2286 numtowrite = SVAL(inbuf,smb_vwv1);
2287 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2288 data = smb_buf(inbuf) + 3;
2290 if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos,
2291 WRITE_LOCK,False)) {
2292 END_PROFILE(SMBwriteunlock);
2293 return ERROR_DOS(ERRDOS,ERRlock);
2296 /* The special X/Open SMB protocol handling of
2297 zero length writes is *NOT* done for
2298 this call */
2299 if(numtowrite == 0)
2300 nwritten = 0;
2301 else
2302 nwritten = write_file(fsp,data,startpos,numtowrite);
2304 if (lp_syncalways(SNUM(conn)))
2305 sync_file(conn,fsp);
2307 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2308 END_PROFILE(SMBwriteunlock);
2309 return(UNIXERROR(ERRHRD,ERRdiskfull));
2312 if (numtowrite) {
2313 status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), (SMB_BIG_UINT)numtowrite,
2314 (SMB_BIG_UINT)startpos);
2315 if (NT_STATUS_V(status)) {
2316 END_PROFILE(SMBwriteunlock);
2317 return ERROR_NT(status);
2321 outsize = set_message(outbuf,1,0,True);
2323 SSVAL(outbuf,smb_vwv0,nwritten);
2325 DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
2326 fsp->fnum, (int)numtowrite, (int)nwritten));
2328 END_PROFILE(SMBwriteunlock);
2329 return outsize;
2332 /****************************************************************************
2333 Reply to a write.
2334 ****************************************************************************/
2336 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
2338 size_t numtowrite;
2339 ssize_t nwritten = -1;
2340 SMB_OFF_T startpos;
2341 char *data;
2342 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2343 int outsize = 0;
2344 START_PROFILE(SMBwrite);
2346 /* If it's an IPC, pass off the pipe handler. */
2347 if (IS_IPC(conn)) {
2348 END_PROFILE(SMBwrite);
2349 return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
2352 CHECK_FSP(fsp,conn);
2353 CHECK_WRITE(fsp);
2355 numtowrite = SVAL(inbuf,smb_vwv1);
2356 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2357 data = smb_buf(inbuf) + 3;
2359 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2360 END_PROFILE(SMBwrite);
2361 return ERROR_DOS(ERRDOS,ERRlock);
2365 * X/Open SMB protocol says that if smb_vwv1 is
2366 * zero then the file size should be extended or
2367 * truncated to the size given in smb_vwv[2-3].
2370 if(numtowrite == 0) {
2372 * This is actually an allocate call, and set EOF. JRA.
2374 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
2375 if (nwritten < 0) {
2376 END_PROFILE(SMBwrite);
2377 return ERROR_NT(NT_STATUS_DISK_FULL);
2379 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
2380 if (nwritten < 0) {
2381 END_PROFILE(SMBwrite);
2382 return ERROR_NT(NT_STATUS_DISK_FULL);
2384 } else
2385 nwritten = write_file(fsp,data,startpos,numtowrite);
2387 if (lp_syncalways(SNUM(conn)))
2388 sync_file(conn,fsp);
2390 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2391 END_PROFILE(SMBwrite);
2392 return(UNIXERROR(ERRHRD,ERRdiskfull));
2395 outsize = set_message(outbuf,1,0,True);
2397 SSVAL(outbuf,smb_vwv0,nwritten);
2399 if (nwritten < (ssize_t)numtowrite) {
2400 SCVAL(outbuf,smb_rcls,ERRHRD);
2401 SSVAL(outbuf,smb_err,ERRdiskfull);
2404 DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
2406 END_PROFILE(SMBwrite);
2407 return(outsize);
2410 /****************************************************************************
2411 Reply to a write and X.
2412 ****************************************************************************/
2414 int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
2416 files_struct *fsp = file_fsp(inbuf,smb_vwv2);
2417 SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
2418 size_t numtowrite = SVAL(inbuf,smb_vwv10);
2419 BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
2420 ssize_t nwritten = -1;
2421 unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
2422 unsigned int smblen = smb_len(inbuf);
2423 char *data;
2424 BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
2425 START_PROFILE(SMBwriteX);
2427 /* If it's an IPC, pass off the pipe handler. */
2428 if (IS_IPC(conn)) {
2429 END_PROFILE(SMBwriteX);
2430 return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
2433 CHECK_FSP(fsp,conn);
2434 CHECK_WRITE(fsp);
2436 /* Deal with possible LARGE_WRITEX */
2437 if (large_writeX)
2438 numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
2440 if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
2441 END_PROFILE(SMBwriteX);
2442 return ERROR_DOS(ERRDOS,ERRbadmem);
2445 data = smb_base(inbuf) + smb_doff;
2447 if(CVAL(inbuf,smb_wct) == 14) {
2448 #ifdef LARGE_SMB_OFF_T
2450 * This is a large offset (64 bit) write.
2452 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
2454 #else /* !LARGE_SMB_OFF_T */
2457 * Ensure we haven't been sent a >32 bit offset.
2460 if(IVAL(inbuf,smb_vwv12) != 0) {
2461 DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
2462 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
2463 END_PROFILE(SMBwriteX);
2464 return ERROR_DOS(ERRDOS,ERRbadaccess);
2467 #endif /* LARGE_SMB_OFF_T */
2470 if (is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2471 END_PROFILE(SMBwriteX);
2472 return ERROR_DOS(ERRDOS,ERRlock);
2475 /* X/Open SMB protocol says that, unlike SMBwrite
2476 if the length is zero then NO truncation is
2477 done, just a write of zero. To truncate a file,
2478 use SMBwrite. */
2480 if(numtowrite == 0)
2481 nwritten = 0;
2482 else
2483 nwritten = write_file(fsp,data,startpos,numtowrite);
2485 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2486 END_PROFILE(SMBwriteX);
2487 return(UNIXERROR(ERRHRD,ERRdiskfull));
2490 set_message(outbuf,6,0,True);
2492 SSVAL(outbuf,smb_vwv2,nwritten);
2493 if (large_writeX)
2494 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
2496 if (nwritten < (ssize_t)numtowrite) {
2497 SCVAL(outbuf,smb_rcls,ERRHRD);
2498 SSVAL(outbuf,smb_err,ERRdiskfull);
2501 DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
2502 fsp->fnum, (int)numtowrite, (int)nwritten));
2504 if (lp_syncalways(SNUM(conn)) || write_through)
2505 sync_file(conn,fsp);
2507 END_PROFILE(SMBwriteX);
2508 return chain_reply(inbuf,outbuf,length,bufsize);
2511 /****************************************************************************
2512 Reply to a lseek.
2513 ****************************************************************************/
2515 int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2517 SMB_OFF_T startpos;
2518 SMB_OFF_T res= -1;
2519 int mode,umode;
2520 int outsize = 0;
2521 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2522 START_PROFILE(SMBlseek);
2524 CHECK_FSP(fsp,conn);
2526 flush_write_cache(fsp, SEEK_FLUSH);
2528 mode = SVAL(inbuf,smb_vwv1) & 3;
2529 /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
2530 startpos = (SMB_OFF_T)IVALS(inbuf,smb_vwv2);
2532 switch (mode) {
2533 case 0:
2534 umode = SEEK_SET;
2535 res = startpos;
2536 break;
2537 case 1:
2538 umode = SEEK_CUR;
2539 res = fsp->pos + startpos;
2540 break;
2541 case 2:
2542 umode = SEEK_END;
2543 break;
2544 default:
2545 umode = SEEK_SET;
2546 res = startpos;
2547 break;
2550 if (umode == SEEK_END) {
2551 if((res = SMB_VFS_LSEEK(fsp,fsp->fd,startpos,umode)) == -1) {
2552 if(errno == EINVAL) {
2553 SMB_OFF_T current_pos = startpos;
2554 SMB_STRUCT_STAT sbuf;
2556 if(SMB_VFS_FSTAT(fsp,fsp->fd, &sbuf) == -1) {
2557 END_PROFILE(SMBlseek);
2558 return(UNIXERROR(ERRDOS,ERRnoaccess));
2561 current_pos += sbuf.st_size;
2562 if(current_pos < 0)
2563 res = SMB_VFS_LSEEK(fsp,fsp->fd,0,SEEK_SET);
2567 if(res == -1) {
2568 END_PROFILE(SMBlseek);
2569 return(UNIXERROR(ERRDOS,ERRnoaccess));
2573 fsp->pos = res;
2575 outsize = set_message(outbuf,2,0,True);
2576 SIVAL(outbuf,smb_vwv0,res);
2578 DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
2579 fsp->fnum, (double)startpos, (double)res, mode));
2581 END_PROFILE(SMBlseek);
2582 return(outsize);
2585 /****************************************************************************
2586 Reply to a flush.
2587 ****************************************************************************/
2589 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
2591 int outsize = set_message(outbuf,0,0,True);
2592 uint16 fnum = SVAL(inbuf,smb_vwv0);
2593 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2594 START_PROFILE(SMBflush);
2596 if (fnum != 0xFFFF)
2597 CHECK_FSP(fsp,conn);
2599 if (!fsp) {
2600 file_sync_all(conn);
2601 } else {
2602 sync_file(conn,fsp);
2605 DEBUG(3,("flush\n"));
2606 END_PROFILE(SMBflush);
2607 return(outsize);
2610 /****************************************************************************
2611 Reply to a exit.
2612 ****************************************************************************/
2614 int reply_exit(connection_struct *conn,
2615 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2617 int outsize;
2618 START_PROFILE(SMBexit);
2620 file_close_pid(SVAL(inbuf,smb_pid));
2622 outsize = set_message(outbuf,0,0,True);
2624 DEBUG(3,("exit\n"));
2626 END_PROFILE(SMBexit);
2627 return(outsize);
2630 /****************************************************************************
2631 Reply to a close - has to deal with closing a directory opened by NT SMB's.
2632 ****************************************************************************/
2634 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
2635 int dum_buffsize)
2637 extern struct current_user current_user;
2638 int outsize = 0;
2639 time_t mtime;
2640 int32 eclass = 0, err = 0;
2641 files_struct *fsp = NULL;
2642 START_PROFILE(SMBclose);
2644 outsize = set_message(outbuf,0,0,True);
2646 /* If it's an IPC, pass off to the pipe handler. */
2647 if (IS_IPC(conn)) {
2648 END_PROFILE(SMBclose);
2649 return reply_pipe_close(conn, inbuf,outbuf);
2652 fsp = file_fsp(inbuf,smb_vwv0);
2655 * We can only use CHECK_FSP if we know it's not a directory.
2658 if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) {
2659 END_PROFILE(SMBclose);
2660 return ERROR_DOS(ERRDOS,ERRbadfid);
2663 if(fsp->is_directory) {
2665 * Special case - close NT SMB directory handle.
2667 DEBUG(3,("close %s fnum=%d\n", fsp->is_directory ? "directory" : "stat file open", fsp->fnum));
2668 close_file(fsp,True);
2669 } else {
2671 * Close ordinary file.
2673 int close_err;
2674 pstring file_name;
2676 /* Save the name for time set in close. */
2677 pstrcpy( file_name, fsp->fsp_name);
2679 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
2680 fsp->fd, fsp->fnum,
2681 conn->num_files_open));
2684 * close_file() returns the unix errno if an error
2685 * was detected on close - normally this is due to
2686 * a disk full error. If not then it was probably an I/O error.
2689 if((close_err = close_file(fsp,True)) != 0) {
2690 errno = close_err;
2691 END_PROFILE(SMBclose);
2692 return (UNIXERROR(ERRHRD,ERRgeneral));
2696 * Now take care of any time sent in the close.
2699 mtime = make_unix_date3(inbuf+smb_vwv1);
2701 /* try and set the date */
2702 set_filetime(conn, file_name, mtime);
2706 /* We have a cached error */
2707 if(eclass || err) {
2708 END_PROFILE(SMBclose);
2709 return ERROR_DOS(eclass,err);
2712 END_PROFILE(SMBclose);
2713 return(outsize);
2716 /****************************************************************************
2717 Reply to a writeclose (Core+ protocol).
2718 ****************************************************************************/
2720 int reply_writeclose(connection_struct *conn,
2721 char *inbuf,char *outbuf, int size, int dum_buffsize)
2723 size_t numtowrite;
2724 ssize_t nwritten = -1;
2725 int outsize = 0;
2726 int close_err = 0;
2727 SMB_OFF_T startpos;
2728 char *data;
2729 time_t mtime;
2730 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2731 START_PROFILE(SMBwriteclose);
2733 CHECK_FSP(fsp,conn);
2734 CHECK_WRITE(fsp);
2736 numtowrite = SVAL(inbuf,smb_vwv1);
2737 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
2738 mtime = make_unix_date3(inbuf+smb_vwv4);
2739 data = smb_buf(inbuf) + 1;
2741 if (numtowrite && is_locked(fsp,conn,(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK,False)) {
2742 END_PROFILE(SMBwriteclose);
2743 return ERROR_DOS(ERRDOS,ERRlock);
2746 nwritten = write_file(fsp,data,startpos,numtowrite);
2748 set_filetime(conn, fsp->fsp_name,mtime);
2751 * More insanity. W2K only closes the file if writelen > 0.
2752 * JRA.
2755 if (numtowrite) {
2756 DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
2757 fsp->fsp_name ));
2758 close_err = close_file(fsp,True);
2761 DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
2762 fsp->fnum, (int)numtowrite, (int)nwritten,
2763 conn->num_files_open));
2765 if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
2766 END_PROFILE(SMBwriteclose);
2767 return(UNIXERROR(ERRHRD,ERRdiskfull));
2770 if(close_err != 0) {
2771 errno = close_err;
2772 END_PROFILE(SMBwriteclose);
2773 return(UNIXERROR(ERRHRD,ERRgeneral));
2776 outsize = set_message(outbuf,1,0,True);
2778 SSVAL(outbuf,smb_vwv0,nwritten);
2779 END_PROFILE(SMBwriteclose);
2780 return(outsize);
2783 /****************************************************************************
2784 Reply to a lock.
2785 ****************************************************************************/
2787 int reply_lock(connection_struct *conn,
2788 char *inbuf,char *outbuf, int length, int dum_buffsize)
2790 int outsize = set_message(outbuf,0,0,True);
2791 SMB_BIG_UINT count,offset;
2792 NTSTATUS status;
2793 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2794 BOOL my_lock_ctx = False;
2796 START_PROFILE(SMBlock);
2798 CHECK_FSP(fsp,conn);
2800 release_level_2_oplocks_on_change(fsp);
2802 count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
2803 offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
2805 DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2806 fsp->fd, fsp->fnum, (double)offset, (double)count));
2808 status = do_lock_spin(fsp, conn, SVAL(inbuf,smb_pid), count, offset, WRITE_LOCK, &my_lock_ctx);
2809 if (NT_STATUS_V(status)) {
2810 #if 0
2811 /* Tests using Samba4 against W2K show this call never creates a blocking lock. */
2812 if (lp_blocking_locks(SNUM(conn)) && !my_lock_ctx && ERROR_WAS_LOCK_DENIED(status)) {
2814 * A blocking lock was requested. Package up
2815 * this smb into a queued request and push it
2816 * onto the blocking lock queue.
2818 if(push_blocking_lock_request(inbuf, length, -1, 0, SVAL(inbuf,smb_pid), offset, count)) {
2819 END_PROFILE(SMBlock);
2820 return -1;
2823 #endif
2824 END_PROFILE(SMBlock);
2825 return ERROR_NT(status);
2828 END_PROFILE(SMBlock);
2829 return(outsize);
2832 /****************************************************************************
2833 Reply to a unlock.
2834 ****************************************************************************/
2836 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size,
2837 int dum_buffsize)
2839 int outsize = set_message(outbuf,0,0,True);
2840 SMB_BIG_UINT count,offset;
2841 NTSTATUS status;
2842 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2843 START_PROFILE(SMBunlock);
2845 CHECK_FSP(fsp,conn);
2847 count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
2848 offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
2850 status = do_unlock(fsp, conn, SVAL(inbuf,smb_pid), count, offset);
2851 if (NT_STATUS_V(status)) {
2852 END_PROFILE(SMBunlock);
2853 return ERROR_NT(status);
2856 DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
2857 fsp->fd, fsp->fnum, (double)offset, (double)count ) );
2859 END_PROFILE(SMBunlock);
2860 return(outsize);
2863 /****************************************************************************
2864 Reply to a tdis.
2865 ****************************************************************************/
2867 int reply_tdis(connection_struct *conn,
2868 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2870 int outsize = set_message(outbuf,0,0,True);
2871 uint16 vuid;
2872 START_PROFILE(SMBtdis);
2874 vuid = SVAL(inbuf,smb_uid);
2876 if (!conn) {
2877 DEBUG(4,("Invalid connection in tdis\n"));
2878 END_PROFILE(SMBtdis);
2879 return ERROR_DOS(ERRSRV,ERRinvnid);
2882 conn->used = False;
2884 close_cnum(conn,vuid);
2886 END_PROFILE(SMBtdis);
2887 return outsize;
2890 /****************************************************************************
2891 Reply to a echo.
2892 ****************************************************************************/
2894 int reply_echo(connection_struct *conn,
2895 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2897 int smb_reverb = SVAL(inbuf,smb_vwv0);
2898 int seq_num;
2899 unsigned int data_len = smb_buflen(inbuf);
2900 int outsize = set_message(outbuf,1,data_len,True);
2901 START_PROFILE(SMBecho);
2903 if (data_len > BUFFER_SIZE) {
2904 DEBUG(0,("reply_echo: data_len too large.\n"));
2905 END_PROFILE(SMBecho);
2906 return -1;
2909 /* copy any incoming data back out */
2910 if (data_len > 0)
2911 memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
2913 if (smb_reverb > 100) {
2914 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
2915 smb_reverb = 100;
2918 for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
2919 SSVAL(outbuf,smb_vwv0,seq_num);
2921 smb_setlen(outbuf,outsize - 4);
2923 if (!send_smb(smbd_server_fd(),outbuf))
2924 exit_server("reply_echo: send_smb failed.");
2927 DEBUG(3,("echo %d times\n", smb_reverb));
2929 smb_echo_count++;
2931 END_PROFILE(SMBecho);
2932 return -1;
2935 /****************************************************************************
2936 Reply to a printopen.
2937 ****************************************************************************/
2939 int reply_printopen(connection_struct *conn,
2940 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2942 int outsize = 0;
2943 files_struct *fsp;
2944 START_PROFILE(SMBsplopen);
2946 if (!CAN_PRINT(conn)) {
2947 END_PROFILE(SMBsplopen);
2948 return ERROR_DOS(ERRDOS,ERRnoaccess);
2951 /* Open for exclusive use, write only. */
2952 fsp = print_fsp_open(conn, NULL);
2954 if (!fsp) {
2955 END_PROFILE(SMBsplopen);
2956 return(UNIXERROR(ERRDOS,ERRnoaccess));
2959 outsize = set_message(outbuf,1,0,True);
2960 SSVAL(outbuf,smb_vwv0,fsp->fnum);
2962 DEBUG(3,("openprint fd=%d fnum=%d\n",
2963 fsp->fd, fsp->fnum));
2965 END_PROFILE(SMBsplopen);
2966 return(outsize);
2969 /****************************************************************************
2970 Reply to a printclose.
2971 ****************************************************************************/
2973 int reply_printclose(connection_struct *conn,
2974 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
2976 int outsize = set_message(outbuf,0,0,True);
2977 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
2978 int close_err = 0;
2979 START_PROFILE(SMBsplclose);
2981 CHECK_FSP(fsp,conn);
2983 if (!CAN_PRINT(conn)) {
2984 END_PROFILE(SMBsplclose);
2985 return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
2988 DEBUG(3,("printclose fd=%d fnum=%d\n",
2989 fsp->fd,fsp->fnum));
2991 close_err = close_file(fsp,True);
2993 if(close_err != 0) {
2994 errno = close_err;
2995 END_PROFILE(SMBsplclose);
2996 return(UNIXERROR(ERRHRD,ERRgeneral));
2999 END_PROFILE(SMBsplclose);
3000 return(outsize);
3003 /****************************************************************************
3004 Reply to a printqueue.
3005 ****************************************************************************/
3007 int reply_printqueue(connection_struct *conn,
3008 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3010 int outsize = set_message(outbuf,2,3,True);
3011 int max_count = SVAL(inbuf,smb_vwv0);
3012 int start_index = SVAL(inbuf,smb_vwv1);
3013 START_PROFILE(SMBsplretq);
3015 /* we used to allow the client to get the cnum wrong, but that
3016 is really quite gross and only worked when there was only
3017 one printer - I think we should now only accept it if they
3018 get it right (tridge) */
3019 if (!CAN_PRINT(conn)) {
3020 END_PROFILE(SMBsplretq);
3021 return ERROR_DOS(ERRDOS,ERRnoaccess);
3024 SSVAL(outbuf,smb_vwv0,0);
3025 SSVAL(outbuf,smb_vwv1,0);
3026 SCVAL(smb_buf(outbuf),0,1);
3027 SSVAL(smb_buf(outbuf),1,0);
3029 DEBUG(3,("printqueue start_index=%d max_count=%d\n",
3030 start_index, max_count));
3033 print_queue_struct *queue = NULL;
3034 print_status_struct status;
3035 char *p = smb_buf(outbuf) + 3;
3036 int count = print_queue_status(SNUM(conn), &queue, &status);
3037 int num_to_get = ABS(max_count);
3038 int first = (max_count>0?start_index:start_index+max_count+1);
3039 int i;
3041 if (first >= count)
3042 num_to_get = 0;
3043 else
3044 num_to_get = MIN(num_to_get,count-first);
3047 for (i=first;i<first+num_to_get;i++) {
3048 put_dos_date2(p,0,queue[i].time);
3049 SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
3050 SSVAL(p,5, queue[i].job);
3051 SIVAL(p,7,queue[i].size);
3052 SCVAL(p,11,0);
3053 srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII);
3054 p += 28;
3057 if (count > 0) {
3058 outsize = set_message(outbuf,2,28*count+3,False);
3059 SSVAL(outbuf,smb_vwv0,count);
3060 SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
3061 SCVAL(smb_buf(outbuf),0,1);
3062 SSVAL(smb_buf(outbuf),1,28*count);
3065 SAFE_FREE(queue);
3067 DEBUG(3,("%d entries returned in queue\n",count));
3070 END_PROFILE(SMBsplretq);
3071 return(outsize);
3074 /****************************************************************************
3075 Reply to a printwrite.
3076 ****************************************************************************/
3078 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3080 int numtowrite;
3081 int outsize = set_message(outbuf,0,0,True);
3082 char *data;
3083 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
3085 START_PROFILE(SMBsplwr);
3087 if (!CAN_PRINT(conn)) {
3088 END_PROFILE(SMBsplwr);
3089 return ERROR_DOS(ERRDOS,ERRnoaccess);
3092 CHECK_FSP(fsp,conn);
3093 CHECK_WRITE(fsp);
3095 numtowrite = SVAL(smb_buf(inbuf),1);
3096 data = smb_buf(inbuf) + 3;
3098 if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
3099 END_PROFILE(SMBsplwr);
3100 return(UNIXERROR(ERRHRD,ERRdiskfull));
3103 DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
3105 END_PROFILE(SMBsplwr);
3106 return(outsize);
3109 /****************************************************************************
3110 The guts of the mkdir command, split out so it may be called by the NT SMB
3111 code.
3112 ****************************************************************************/
3114 NTSTATUS mkdir_internal(connection_struct *conn, pstring directory)
3116 BOOL bad_path = False;
3117 SMB_STRUCT_STAT sbuf;
3118 int ret= -1;
3120 unix_convert(directory,conn,0,&bad_path,&sbuf);
3122 if( strchr_m(directory, ':')) {
3123 return NT_STATUS_NOT_A_DIRECTORY;
3126 if (ms_has_wild(directory)) {
3127 return NT_STATUS_OBJECT_NAME_INVALID;
3130 if (check_name(directory, conn))
3131 ret = vfs_MkDir(conn,directory,unix_mode(conn,aDIR,directory));
3133 if (ret == -1) {
3134 if(errno == ENOENT) {
3135 if (bad_path)
3136 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3137 else
3138 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3140 return map_nt_error_from_unix(errno);
3143 return NT_STATUS_OK;
3146 /****************************************************************************
3147 Reply to a mkdir.
3148 ****************************************************************************/
3150 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3152 pstring directory;
3153 int outsize;
3154 NTSTATUS status;
3155 START_PROFILE(SMBmkdir);
3157 srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
3158 if (!NT_STATUS_IS_OK(status)) {
3159 END_PROFILE(SMBmkdir);
3160 return ERROR_NT(status);
3163 RESOLVE_DFSPATH(directory, conn, inbuf, outbuf);
3165 status = mkdir_internal(conn, directory);
3166 if (!NT_STATUS_IS_OK(status)) {
3167 END_PROFILE(SMBmkdir);
3168 return ERROR_NT(status);
3171 outsize = set_message(outbuf,0,0,True);
3173 DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
3175 END_PROFILE(SMBmkdir);
3176 return(outsize);
3179 /****************************************************************************
3180 Static function used by reply_rmdir to delete an entire directory
3181 tree recursively. Return False on ok, True on fail.
3182 ****************************************************************************/
3184 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
3186 const char *dname = NULL;
3187 BOOL ret = False;
3188 void *dirptr = OpenDir(conn, directory, False);
3190 if(dirptr == NULL)
3191 return True;
3193 while((dname = ReadDirName(dirptr))) {
3194 pstring fullname;
3195 SMB_STRUCT_STAT st;
3197 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3198 continue;
3200 /* Construct the full name. */
3201 if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
3202 errno = ENOMEM;
3203 ret = True;
3204 break;
3207 pstrcpy(fullname, directory);
3208 pstrcat(fullname, "/");
3209 pstrcat(fullname, dname);
3211 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
3212 ret = True;
3213 break;
3216 if(st.st_mode & S_IFDIR) {
3217 if(recursive_rmdir(conn, fullname)!=0) {
3218 ret = True;
3219 break;
3221 if(SMB_VFS_RMDIR(conn,fullname) != 0) {
3222 ret = True;
3223 break;
3225 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
3226 ret = True;
3227 break;
3230 CloseDir(dirptr);
3231 return ret;
3234 /****************************************************************************
3235 The internals of the rmdir code - called elsewhere.
3236 ****************************************************************************/
3238 BOOL rmdir_internals(connection_struct *conn, char *directory)
3240 BOOL ok;
3242 ok = (SMB_VFS_RMDIR(conn,directory) == 0);
3243 if(!ok && ((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
3245 * Check to see if the only thing in this directory are
3246 * vetoed files/directories. If so then delete them and
3247 * retry. If we fail to delete any of them (and we *don't*
3248 * do a recursive delete) then fail the rmdir.
3250 BOOL all_veto_files = True;
3251 const char *dname;
3252 void *dirptr = OpenDir(conn, directory, False);
3254 if(dirptr != NULL) {
3255 int dirpos = TellDir(dirptr);
3256 while ((dname = ReadDirName(dirptr))) {
3257 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3258 continue;
3259 if(!IS_VETO_PATH(conn, dname)) {
3260 all_veto_files = False;
3261 break;
3265 if(all_veto_files) {
3266 SeekDir(dirptr,dirpos);
3267 while ((dname = ReadDirName(dirptr))) {
3268 pstring fullname;
3269 SMB_STRUCT_STAT st;
3271 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
3272 continue;
3274 /* Construct the full name. */
3275 if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
3276 errno = ENOMEM;
3277 break;
3280 pstrcpy(fullname, directory);
3281 pstrcat(fullname, "/");
3282 pstrcat(fullname, dname);
3284 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0)
3285 break;
3286 if(st.st_mode & S_IFDIR) {
3287 if(lp_recursive_veto_delete(SNUM(conn))) {
3288 if(recursive_rmdir(conn, fullname) != 0)
3289 break;
3291 if(SMB_VFS_RMDIR(conn,fullname) != 0)
3292 break;
3293 } else if(SMB_VFS_UNLINK(conn,fullname) != 0)
3294 break;
3296 CloseDir(dirptr);
3297 /* Retry the rmdir */
3298 ok = (SMB_VFS_RMDIR(conn,directory) == 0);
3299 } else {
3300 CloseDir(dirptr);
3302 } else {
3303 errno = ENOTEMPTY;
3307 if (!ok)
3308 DEBUG(3,("rmdir_internals: couldn't remove directory %s : %s\n", directory,strerror(errno)));
3310 return ok;
3313 /****************************************************************************
3314 Reply to a rmdir.
3315 ****************************************************************************/
3317 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
3319 pstring directory;
3320 int outsize = 0;
3321 BOOL ok = False;
3322 BOOL bad_path = False;
3323 SMB_STRUCT_STAT sbuf;
3324 NTSTATUS status;
3325 START_PROFILE(SMBrmdir);
3327 srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
3328 if (!NT_STATUS_IS_OK(status)) {
3329 END_PROFILE(SMBrmdir);
3330 return ERROR_NT(status);
3333 RESOLVE_DFSPATH(directory, conn, inbuf, outbuf)
3335 unix_convert(directory,conn, NULL,&bad_path,&sbuf);
3337 if (check_name(directory,conn)) {
3338 dptr_closepath(directory,SVAL(inbuf,smb_pid));
3339 ok = rmdir_internals(conn, directory);
3342 if (!ok) {
3343 END_PROFILE(SMBrmdir);
3344 return set_bad_path_error(errno, bad_path, outbuf, ERRDOS, ERRbadpath);
3347 outsize = set_message(outbuf,0,0,True);
3349 DEBUG( 3, ( "rmdir %s\n", directory ) );
3351 END_PROFILE(SMBrmdir);
3352 return(outsize);
3355 /*******************************************************************
3356 Resolve wildcards in a filename rename.
3357 Note that name is in UNIX charset and thus potentially can be more
3358 than fstring buffer (255 bytes) especially in default UTF-8 case.
3359 Therefore, we use pstring inside and all calls should ensure that
3360 name2 is at least pstring-long (they do already)
3361 ********************************************************************/
3363 static BOOL resolve_wildcards(const char *name1, char *name2)
3365 pstring root1,root2;
3366 pstring ext1,ext2;
3367 char *p,*p2, *pname1, *pname2;
3368 int available_space, actual_space;
3371 pname1 = strrchr_m(name1,'/');
3372 pname2 = strrchr_m(name2,'/');
3374 if (!pname1 || !pname2)
3375 return(False);
3377 pstrcpy(root1,pname1);
3378 pstrcpy(root2,pname2);
3379 p = strrchr_m(root1,'.');
3380 if (p) {
3381 *p = 0;
3382 pstrcpy(ext1,p+1);
3383 } else {
3384 pstrcpy(ext1,"");
3386 p = strrchr_m(root2,'.');
3387 if (p) {
3388 *p = 0;
3389 pstrcpy(ext2,p+1);
3390 } else {
3391 pstrcpy(ext2,"");
3394 p = root1;
3395 p2 = root2;
3396 while (*p2) {
3397 if (*p2 == '?') {
3398 *p2 = *p;
3399 p2++;
3400 } else {
3401 p2++;
3403 if (*p)
3404 p++;
3407 p = ext1;
3408 p2 = ext2;
3409 while (*p2) {
3410 if (*p2 == '?') {
3411 *p2 = *p;
3412 p2++;
3413 } else {
3414 p2++;
3416 if (*p)
3417 p++;
3420 available_space = sizeof(pstring) - PTR_DIFF(pname2, name2);
3422 if (ext2[0]) {
3423 actual_space = snprintf(pname2, available_space - 1, "%s.%s", root2, ext2);
3424 if (actual_space >= available_space - 1) {
3425 DEBUG(1,("resolve_wildcards: can't fit resolved name into specified buffer (overrun by %d bytes)\n",
3426 actual_space - available_space));
3428 } else {
3429 pstrcpy_base(pname2, root2, name2);
3432 return(True);
3435 /****************************************************************************
3436 Ensure open files have their names updates.
3437 ****************************************************************************/
3439 static void rename_open_files(connection_struct *conn, SMB_DEV_T dev, SMB_INO_T inode, char *newname)
3441 files_struct *fsp;
3442 BOOL did_rename = False;
3444 for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
3445 DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n",
3446 fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode,
3447 fsp->fsp_name, newname ));
3448 string_set(&fsp->fsp_name, newname);
3449 did_rename = True;
3452 if (!did_rename)
3453 DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n",
3454 (unsigned int)dev, (double)inode, newname ));
3457 /****************************************************************************
3458 Rename an open file - given an fsp.
3459 ****************************************************************************/
3461 NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, char *newname, BOOL replace_if_exists)
3463 SMB_STRUCT_STAT sbuf;
3464 BOOL bad_path = False;
3465 pstring newname_last_component;
3466 NTSTATUS error = NT_STATUS_OK;
3467 BOOL dest_exists;
3468 BOOL rcdest = True;
3470 ZERO_STRUCT(sbuf);
3471 rcdest = unix_convert(newname,conn,newname_last_component,&bad_path,&sbuf);
3473 /* Quick check for "." and ".." */
3474 if (!bad_path && newname_last_component[0] == '.') {
3475 if (!newname_last_component[1] || (newname_last_component[1] == '.' && !newname_last_component[2])) {
3476 return NT_STATUS_ACCESS_DENIED;
3479 if (!rcdest && bad_path) {
3480 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3483 /* Ensure newname contains a '/' */
3484 if(strrchr_m(newname,'/') == 0) {
3485 pstring tmpstr;
3487 pstrcpy(tmpstr, "./");
3488 pstrcat(tmpstr, newname);
3489 pstrcpy(newname, tmpstr);
3493 * Check for special case with case preserving and not
3494 * case sensitive. If the old last component differs from the original
3495 * last component only by case, then we should allow
3496 * the rename (user is trying to change the case of the
3497 * filename).
3500 if((case_sensitive == False) && (case_preserve == True) &&
3501 strequal(newname, fsp->fsp_name)) {
3502 char *p;
3503 pstring newname_modified_last_component;
3506 * Get the last component of the modified name.
3507 * Note that we guarantee that newname contains a '/'
3508 * character above.
3510 p = strrchr_m(newname,'/');
3511 pstrcpy(newname_modified_last_component,p+1);
3513 if(strcsequal(newname_modified_last_component,
3514 newname_last_component) == False) {
3516 * Replace the modified last component with
3517 * the original.
3519 pstrcpy(p+1, newname_last_component);
3524 * If the src and dest names are identical - including case,
3525 * don't do the rename, just return success.
3528 if (strcsequal(fsp->fsp_name, newname)) {
3529 DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
3530 newname));
3531 return NT_STATUS_OK;
3534 dest_exists = vfs_object_exist(conn,newname,NULL);
3536 if(!replace_if_exists && dest_exists) {
3537 DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
3538 fsp->fsp_name,newname));
3539 return NT_STATUS_OBJECT_NAME_COLLISION;
3542 error = can_rename(newname,conn,&sbuf);
3544 if (dest_exists && !NT_STATUS_IS_OK(error)) {
3545 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3546 nt_errstr(error), fsp->fsp_name,newname));
3547 if (NT_STATUS_EQUAL(error,NT_STATUS_SHARING_VIOLATION))
3548 error = NT_STATUS_ACCESS_DENIED;
3549 return error;
3552 if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
3553 DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
3554 fsp->fsp_name,newname));
3555 rename_open_files(conn, fsp->dev, fsp->inode, newname);
3556 return NT_STATUS_OK;
3559 if (errno == ENOTDIR || errno == EISDIR)
3560 error = NT_STATUS_OBJECT_NAME_COLLISION;
3561 else
3562 error = map_nt_error_from_unix(errno);
3564 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
3565 nt_errstr(error), fsp->fsp_name,newname));
3567 return error;
3570 /****************************************************************************
3571 The guts of the rename command, split out so it may be called by the NT SMB
3572 code.
3573 ****************************************************************************/
3575 NTSTATUS rename_internals(connection_struct *conn, char *name, char *newname, uint16 attrs, BOOL replace_if_exists)
3577 pstring directory;
3578 pstring mask;
3579 pstring last_component_src;
3580 pstring last_component_dest;
3581 char *p;
3582 BOOL has_wild;
3583 BOOL bad_path_src = False;
3584 BOOL bad_path_dest = False;
3585 int count=0;
3586 NTSTATUS error = NT_STATUS_OK;
3587 BOOL rc = True;
3588 BOOL rcdest = True;
3589 SMB_STRUCT_STAT sbuf1, sbuf2;
3591 *directory = *mask = 0;
3593 ZERO_STRUCT(sbuf1);
3594 ZERO_STRUCT(sbuf2);
3596 rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1);
3597 if (!rc && bad_path_src) {
3598 if (ms_has_wild(last_component_src))
3599 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3600 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3603 /* Quick check for "." and ".." */
3604 if (last_component_src[0] == '.') {
3605 if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) {
3606 return NT_STATUS_OBJECT_NAME_INVALID;
3610 rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2);
3612 /* Quick check for "." and ".." */
3613 if (last_component_dest[0] == '.') {
3614 if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) {
3615 return NT_STATUS_OBJECT_NAME_INVALID;
3620 * Split the old name into directory and last component
3621 * strings. Note that unix_convert may have stripped off a
3622 * leading ./ from both name and newname if the rename is
3623 * at the root of the share. We need to make sure either both
3624 * name and newname contain a / character or neither of them do
3625 * as this is checked in resolve_wildcards().
3628 p = strrchr_m(name,'/');
3629 if (!p) {
3630 pstrcpy(directory,".");
3631 pstrcpy(mask,name);
3632 } else {
3633 *p = 0;
3634 pstrcpy(directory,name);
3635 pstrcpy(mask,p+1);
3636 *p = '/'; /* Replace needed for exceptional test below. */
3640 * We should only check the mangled cache
3641 * here if unix_convert failed. This means
3642 * that the path in 'mask' doesn't exist
3643 * on the file system and so we need to look
3644 * for a possible mangle. This patch from
3645 * Tine Smukavec <valentin.smukavec@hermes.si>.
3648 if (!rc && mangle_is_mangled(mask))
3649 mangle_check_cache( mask );
3651 has_wild = ms_has_wild(mask);
3653 if (!has_wild) {
3655 * No wildcards - just process the one file.
3657 BOOL is_short_name = mangle_is_8_3(name, True);
3659 /* Add a terminating '/' to the directory name. */
3660 pstrcat(directory,"/");
3661 pstrcat(directory,mask);
3663 /* Ensure newname contains a '/' also */
3664 if(strrchr_m(newname,'/') == 0) {
3665 pstring tmpstr;
3667 pstrcpy(tmpstr, "./");
3668 pstrcat(tmpstr, newname);
3669 pstrcpy(newname, tmpstr);
3672 DEBUG(3,("rename_internals: case_sensitive = %d, case_preserve = %d, short case preserve = %d, \
3673 directory = %s, newname = %s, last_component_dest = %s, is_8_3 = %d\n",
3674 case_sensitive, case_preserve, short_case_preserve, directory,
3675 newname, last_component_dest, is_short_name));
3678 * Check for special case with case preserving and not
3679 * case sensitive, if directory and newname are identical,
3680 * and the old last component differs from the original
3681 * last component only by case, then we should allow
3682 * the rename (user is trying to change the case of the
3683 * filename).
3685 if((case_sensitive == False) &&
3686 (((case_preserve == True) &&
3687 (is_short_name == False)) ||
3688 ((short_case_preserve == True) &&
3689 (is_short_name == True))) &&
3690 strcsequal(directory, newname)) {
3691 pstring modified_last_component;
3694 * Get the last component of the modified name.
3695 * Note that we guarantee that newname contains a '/'
3696 * character above.
3698 p = strrchr_m(newname,'/');
3699 pstrcpy(modified_last_component,p+1);
3701 if(strcsequal(modified_last_component,
3702 last_component_dest) == False) {
3704 * Replace the modified last component with
3705 * the original.
3707 pstrcpy(p+1, last_component_dest);
3711 resolve_wildcards(directory,newname);
3714 * The source object must exist.
3717 if (!vfs_object_exist(conn, directory, &sbuf1)) {
3718 DEBUG(3,("rename_internals: source doesn't exist doing rename %s -> %s\n",
3719 directory,newname));
3721 if (errno == ENOTDIR || errno == EISDIR || errno == ENOENT) {
3723 * Must return different errors depending on whether the parent
3724 * directory existed or not.
3727 p = strrchr_m(directory, '/');
3728 if (!p)
3729 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3730 *p = '\0';
3731 if (vfs_object_exist(conn, directory, NULL))
3732 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
3733 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3735 error = map_nt_error_from_unix(errno);
3736 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3737 nt_errstr(error), directory,newname));
3739 return error;
3742 if (!rcdest && bad_path_dest) {
3743 if (ms_has_wild(last_component_dest))
3744 return NT_STATUS_OBJECT_NAME_INVALID;
3745 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3748 error = can_rename(directory,conn,&sbuf1);
3750 if (!NT_STATUS_IS_OK(error)) {
3751 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3752 nt_errstr(error), directory,newname));
3753 return error;
3757 * If the src and dest names are identical - including case,
3758 * don't do the rename, just return success.
3761 if (strcsequal(directory, newname)) {
3762 rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname);
3763 DEBUG(3,("rename_internals: identical names in rename %s - returning success\n", directory));
3764 return NT_STATUS_OK;
3767 if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
3768 DEBUG(3,("rename_internals: dest exists doing rename %s -> %s\n",
3769 directory,newname));
3770 return NT_STATUS_OBJECT_NAME_COLLISION;
3773 if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
3774 DEBUG(3,("rename_internals: succeeded doing rename on %s -> %s\n",
3775 directory,newname));
3776 rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname);
3777 return NT_STATUS_OK;
3780 if (errno == ENOTDIR || errno == EISDIR)
3781 error = NT_STATUS_OBJECT_NAME_COLLISION;
3782 else
3783 error = map_nt_error_from_unix(errno);
3785 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
3786 nt_errstr(error), directory,newname));
3788 return error;
3789 } else {
3791 * Wildcards - process each file that matches.
3793 void *dirptr = NULL;
3794 const char *dname;
3795 pstring destname;
3797 if (check_name(directory,conn))
3798 dirptr = OpenDir(conn, directory, True);
3800 if (dirptr) {
3801 error = NT_STATUS_NO_SUCH_FILE;
3802 /* Was error = NT_STATUS_OBJECT_NAME_NOT_FOUND; - gentest fix. JRA */
3804 if (strequal(mask,"????????.???"))
3805 pstrcpy(mask,"*");
3807 while ((dname = ReadDirName(dirptr))) {
3808 pstring fname;
3809 BOOL sysdir_entry = False;
3811 pstrcpy(fname,dname);
3813 /* Quick check for "." and ".." */
3814 if (fname[0] == '.') {
3815 if (!fname[1] || (fname[1] == '.' && !fname[2])) {
3816 if (attrs & aDIR) {
3817 sysdir_entry = True;
3818 } else {
3819 continue;
3824 if(!mask_match(fname, mask, case_sensitive))
3825 continue;
3827 if (sysdir_entry) {
3828 error = NT_STATUS_OBJECT_NAME_INVALID;
3829 continue;
3832 error = NT_STATUS_ACCESS_DENIED;
3833 slprintf(fname,sizeof(fname)-1,"%s/%s",directory,dname);
3834 if (!vfs_object_exist(conn, fname, &sbuf1)) {
3835 error = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3836 DEBUG(6,("rename %s failed. Error %s\n", fname, nt_errstr(error)));
3837 continue;
3839 error = can_rename(fname,conn,&sbuf1);
3840 if (!NT_STATUS_IS_OK(error)) {
3841 DEBUG(6,("rename %s refused\n", fname));
3842 continue;
3844 pstrcpy(destname,newname);
3846 if (!resolve_wildcards(fname,destname)) {
3847 DEBUG(6,("resolve_wildcards %s %s failed\n",
3848 fname, destname));
3849 continue;
3852 if (!replace_if_exists &&
3853 vfs_file_exist(conn,destname, NULL)) {
3854 DEBUG(6,("file_exist %s\n", destname));
3855 error = NT_STATUS_OBJECT_NAME_COLLISION;
3856 continue;
3859 if (!SMB_VFS_RENAME(conn,fname,destname)) {
3860 rename_open_files(conn, sbuf1.st_dev, sbuf1.st_ino, newname);
3861 count++;
3862 error = NT_STATUS_OK;
3864 DEBUG(3,("rename_internals: doing rename on %s -> %s\n",fname,destname));
3866 CloseDir(dirptr);
3869 if (!NT_STATUS_EQUAL(error,NT_STATUS_NO_SUCH_FILE)) {
3870 if (!rcdest && bad_path_dest) {
3871 if (ms_has_wild(last_component_dest))
3872 return NT_STATUS_OBJECT_NAME_INVALID;
3873 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
3878 if (count == 0 && NT_STATUS_IS_OK(error)) {
3879 error = map_nt_error_from_unix(errno);
3882 return error;
3885 /****************************************************************************
3886 Reply to a mv.
3887 ****************************************************************************/
3889 int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size,
3890 int dum_buffsize)
3892 int outsize = 0;
3893 pstring name;
3894 pstring newname;
3895 char *p;
3896 uint16 attrs = SVAL(inbuf,smb_vwv0);
3897 NTSTATUS status;
3899 START_PROFILE(SMBmv);
3901 p = smb_buf(inbuf) + 1;
3902 p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status);
3903 if (!NT_STATUS_IS_OK(status)) {
3904 END_PROFILE(SMBmv);
3905 return ERROR_NT(status);
3907 p++;
3908 p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
3909 if (!NT_STATUS_IS_OK(status)) {
3910 END_PROFILE(SMBmv);
3911 return ERROR_NT(status);
3914 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
3915 RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
3917 DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
3919 status = rename_internals(conn, name, newname, attrs, False);
3920 if (!NT_STATUS_IS_OK(status)) {
3921 END_PROFILE(SMBmv);
3922 return ERROR_NT(status);
3926 * Win2k needs a changenotify request response before it will
3927 * update after a rename..
3929 process_pending_change_notify_queue((time_t)0);
3930 outsize = set_message(outbuf,0,0,True);
3932 END_PROFILE(SMBmv);
3933 return(outsize);
3936 /*******************************************************************
3937 Copy a file as part of a reply_copy.
3938 ******************************************************************/
3940 static BOOL copy_file(char *src,char *dest1,connection_struct *conn, int ofun,
3941 int count,BOOL target_is_directory, int *err_ret)
3943 int Access,action;
3944 SMB_STRUCT_STAT src_sbuf, sbuf2;
3945 SMB_OFF_T ret=-1;
3946 files_struct *fsp1,*fsp2;
3947 pstring dest;
3949 *err_ret = 0;
3951 pstrcpy(dest,dest1);
3952 if (target_is_directory) {
3953 char *p = strrchr_m(src,'/');
3954 if (p)
3955 p++;
3956 else
3957 p = src;
3958 pstrcat(dest,"/");
3959 pstrcat(dest,p);
3962 if (!vfs_file_exist(conn,src,&src_sbuf))
3963 return(False);
3965 fsp1 = open_file_shared(conn,src,&src_sbuf,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_RDONLY),
3966 (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),0,0,&Access,&action);
3968 if (!fsp1)
3969 return(False);
3971 if (!target_is_directory && count)
3972 ofun = FILE_EXISTS_OPEN;
3974 if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1)
3975 ZERO_STRUCTP(&sbuf2);
3977 fsp2 = open_file_shared(conn,dest,&sbuf2,SET_DENY_MODE(DENY_NONE)|SET_OPEN_MODE(DOS_OPEN_WRONLY),
3978 ofun,src_sbuf.st_mode,0,&Access,&action);
3980 if (!fsp2) {
3981 close_file(fsp1,False);
3982 return(False);
3985 if ((ofun&3) == 1) {
3986 if(SMB_VFS_LSEEK(fsp2,fsp2->fd,0,SEEK_END) == -1) {
3987 DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
3989 * Stop the copy from occurring.
3991 ret = -1;
3992 src_sbuf.st_size = 0;
3996 if (src_sbuf.st_size)
3997 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
3999 close_file(fsp1,False);
4001 /* Ensure the modtime is set correctly on the destination file. */
4002 fsp2->pending_modtime = src_sbuf.st_mtime;
4005 * As we are opening fsp1 read-only we only expect
4006 * an error on close on fsp2 if we are out of space.
4007 * Thus we don't look at the error return from the
4008 * close of fsp1.
4010 *err_ret = close_file(fsp2,False);
4012 return(ret == (SMB_OFF_T)src_sbuf.st_size);
4015 /****************************************************************************
4016 Reply to a file copy.
4017 ****************************************************************************/
4019 int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4021 int outsize = 0;
4022 pstring name;
4023 pstring directory;
4024 pstring mask,newname;
4025 char *p;
4026 int count=0;
4027 int error = ERRnoaccess;
4028 int err = 0;
4029 BOOL has_wild;
4030 BOOL exists=False;
4031 int tid2 = SVAL(inbuf,smb_vwv0);
4032 int ofun = SVAL(inbuf,smb_vwv1);
4033 int flags = SVAL(inbuf,smb_vwv2);
4034 BOOL target_is_directory=False;
4035 BOOL bad_path1 = False;
4036 BOOL bad_path2 = False;
4037 BOOL rc = True;
4038 SMB_STRUCT_STAT sbuf1, sbuf2;
4039 NTSTATUS status;
4041 START_PROFILE(SMBcopy);
4043 *directory = *mask = 0;
4045 p = smb_buf(inbuf);
4046 p += srvstr_get_path(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status);
4047 if (!NT_STATUS_IS_OK(status)) {
4048 END_PROFILE(SMBcopy);
4049 return ERROR_NT(status);
4051 p += srvstr_get_path(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status);
4052 if (!NT_STATUS_IS_OK(status)) {
4053 END_PROFILE(SMBcopy);
4054 return ERROR_NT(status);
4057 DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
4059 if (tid2 != conn->cnum) {
4060 /* can't currently handle inter share copies XXXX */
4061 DEBUG(3,("Rejecting inter-share copy\n"));
4062 END_PROFILE(SMBcopy);
4063 return ERROR_DOS(ERRSRV,ERRinvdevice);
4066 RESOLVE_DFSPATH(name, conn, inbuf, outbuf);
4067 RESOLVE_DFSPATH(newname, conn, inbuf, outbuf);
4069 rc = unix_convert(name,conn,0,&bad_path1,&sbuf1);
4070 unix_convert(newname,conn,0,&bad_path2,&sbuf2);
4072 target_is_directory = VALID_STAT_OF_DIR(sbuf2);
4074 if ((flags&1) && target_is_directory) {
4075 END_PROFILE(SMBcopy);
4076 return ERROR_DOS(ERRDOS,ERRbadfile);
4079 if ((flags&2) && !target_is_directory) {
4080 END_PROFILE(SMBcopy);
4081 return ERROR_DOS(ERRDOS,ERRbadpath);
4084 if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
4085 /* wants a tree copy! XXXX */
4086 DEBUG(3,("Rejecting tree copy\n"));
4087 END_PROFILE(SMBcopy);
4088 return ERROR_DOS(ERRSRV,ERRerror);
4091 p = strrchr_m(name,'/');
4092 if (!p) {
4093 pstrcpy(directory,"./");
4094 pstrcpy(mask,name);
4095 } else {
4096 *p = 0;
4097 pstrcpy(directory,name);
4098 pstrcpy(mask,p+1);
4102 * We should only check the mangled cache
4103 * here if unix_convert failed. This means
4104 * that the path in 'mask' doesn't exist
4105 * on the file system and so we need to look
4106 * for a possible mangle. This patch from
4107 * Tine Smukavec <valentin.smukavec@hermes.si>.
4110 if (!rc && mangle_is_mangled(mask))
4111 mangle_check_cache( mask );
4113 has_wild = ms_has_wild(mask);
4115 if (!has_wild) {
4116 pstrcat(directory,"/");
4117 pstrcat(directory,mask);
4118 if (resolve_wildcards(directory,newname) &&
4119 copy_file(directory,newname,conn,ofun, count,target_is_directory,&err))
4120 count++;
4121 if(!count && err) {
4122 errno = err;
4123 END_PROFILE(SMBcopy);
4124 return(UNIXERROR(ERRHRD,ERRgeneral));
4126 if (!count) {
4127 exists = vfs_file_exist(conn,directory,NULL);
4129 } else {
4130 void *dirptr = NULL;
4131 const char *dname;
4132 pstring destname;
4134 if (check_name(directory,conn))
4135 dirptr = OpenDir(conn, directory, True);
4137 if (dirptr) {
4138 error = ERRbadfile;
4140 if (strequal(mask,"????????.???"))
4141 pstrcpy(mask,"*");
4143 while ((dname = ReadDirName(dirptr))) {
4144 pstring fname;
4145 pstrcpy(fname,dname);
4147 if(!mask_match(fname, mask, case_sensitive))
4148 continue;
4150 error = ERRnoaccess;
4151 slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
4152 pstrcpy(destname,newname);
4153 if (resolve_wildcards(fname,destname) &&
4154 copy_file(fname,destname,conn,ofun,
4155 count,target_is_directory,&err))
4156 count++;
4157 DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname,destname));
4159 CloseDir(dirptr);
4163 if (count == 0) {
4164 if(err) {
4165 /* Error on close... */
4166 errno = err;
4167 END_PROFILE(SMBcopy);
4168 return(UNIXERROR(ERRHRD,ERRgeneral));
4171 if (exists) {
4172 END_PROFILE(SMBcopy);
4173 return ERROR_DOS(ERRDOS,error);
4174 } else {
4175 if((errno == ENOENT) && (bad_path1 || bad_path2)) {
4176 unix_ERR_class = ERRDOS;
4177 unix_ERR_code = ERRbadpath;
4179 END_PROFILE(SMBcopy);
4180 return(UNIXERROR(ERRDOS,error));
4184 outsize = set_message(outbuf,1,0,True);
4185 SSVAL(outbuf,smb_vwv0,count);
4187 END_PROFILE(SMBcopy);
4188 return(outsize);
4191 /****************************************************************************
4192 Reply to a setdir.
4193 ****************************************************************************/
4195 int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4197 int snum;
4198 int outsize = 0;
4199 BOOL ok = False;
4200 pstring newdir;
4201 NTSTATUS status;
4203 START_PROFILE(pathworks_setdir);
4205 snum = SNUM(conn);
4206 if (!CAN_SETDIR(snum)) {
4207 END_PROFILE(pathworks_setdir);
4208 return ERROR_DOS(ERRDOS,ERRnoaccess);
4211 srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status);
4212 if (!NT_STATUS_IS_OK(status)) {
4213 END_PROFILE(pathworks_setdir);
4214 return ERROR_NT(status);
4217 if (strlen(newdir) == 0) {
4218 ok = True;
4219 } else {
4220 ok = vfs_directory_exist(conn,newdir,NULL);
4221 if (ok)
4222 string_set(&conn->connectpath,newdir);
4225 if (!ok) {
4226 END_PROFILE(pathworks_setdir);
4227 return ERROR_DOS(ERRDOS,ERRbadpath);
4230 outsize = set_message(outbuf,0,0,True);
4231 SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
4233 DEBUG(3,("setdir %s\n", newdir));
4235 END_PROFILE(pathworks_setdir);
4236 return(outsize);
4239 /****************************************************************************
4240 Get a lock pid, dealing with large count requests.
4241 ****************************************************************************/
4243 uint16 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
4245 if(!large_file_format)
4246 return SVAL(data,SMB_LPID_OFFSET(data_offset));
4247 else
4248 return SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
4251 /****************************************************************************
4252 Get a lock count, dealing with large count requests.
4253 ****************************************************************************/
4255 SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
4257 SMB_BIG_UINT count = 0;
4259 if(!large_file_format) {
4260 count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
4261 } else {
4263 #if defined(HAVE_LONGLONG)
4264 count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
4265 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
4266 #else /* HAVE_LONGLONG */
4269 * NT4.x seems to be broken in that it sends large file (64 bit)
4270 * lockingX calls even if the CAP_LARGE_FILES was *not*
4271 * negotiated. For boxes without large unsigned ints truncate the
4272 * lock count by dropping the top 32 bits.
4275 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
4276 DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
4277 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
4278 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
4279 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
4282 count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
4283 #endif /* HAVE_LONGLONG */
4286 return count;
4289 #if !defined(HAVE_LONGLONG)
4290 /****************************************************************************
4291 Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
4292 ****************************************************************************/
4294 static uint32 map_lock_offset(uint32 high, uint32 low)
4296 unsigned int i;
4297 uint32 mask = 0;
4298 uint32 highcopy = high;
4301 * Try and find out how many significant bits there are in high.
4304 for(i = 0; highcopy; i++)
4305 highcopy >>= 1;
4308 * We use 31 bits not 32 here as POSIX
4309 * lock offsets may not be negative.
4312 mask = (~0) << (31 - i);
4314 if(low & mask)
4315 return 0; /* Fail. */
4317 high <<= (31 - i);
4319 return (high|low);
4321 #endif /* !defined(HAVE_LONGLONG) */
4323 /****************************************************************************
4324 Get a lock offset, dealing with large offset requests.
4325 ****************************************************************************/
4327 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
4329 SMB_BIG_UINT offset = 0;
4331 *err = False;
4333 if(!large_file_format) {
4334 offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
4335 } else {
4337 #if defined(HAVE_LONGLONG)
4338 offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
4339 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
4340 #else /* HAVE_LONGLONG */
4343 * NT4.x seems to be broken in that it sends large file (64 bit)
4344 * lockingX calls even if the CAP_LARGE_FILES was *not*
4345 * negotiated. For boxes without large unsigned ints mangle the
4346 * lock offset by mapping the top 32 bits onto the lower 32.
4349 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
4350 uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4351 uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
4352 uint32 new_low = 0;
4354 if((new_low = map_lock_offset(high, low)) == 0) {
4355 *err = True;
4356 return (SMB_BIG_UINT)-1;
4359 DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
4360 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
4361 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
4362 SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
4365 offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
4366 #endif /* HAVE_LONGLONG */
4369 return offset;
4372 /****************************************************************************
4373 Reply to a lockingX request.
4374 ****************************************************************************/
4376 int reply_lockingX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
4378 files_struct *fsp = file_fsp(inbuf,smb_vwv2);
4379 unsigned char locktype = CVAL(inbuf,smb_vwv3);
4380 unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
4381 uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
4382 uint16 num_locks = SVAL(inbuf,smb_vwv7);
4383 SMB_BIG_UINT count = 0, offset = 0;
4384 uint16 lock_pid;
4385 int32 lock_timeout = IVAL(inbuf,smb_vwv4);
4386 int i;
4387 char *data;
4388 BOOL large_file_format = (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
4389 BOOL err;
4390 BOOL my_lock_ctx = False;
4391 NTSTATUS status;
4393 START_PROFILE(SMBlockingX);
4395 CHECK_FSP(fsp,conn);
4397 data = smb_buf(inbuf);
4399 if (locktype & (LOCKING_ANDX_CANCEL_LOCK | LOCKING_ANDX_CHANGE_LOCKTYPE)) {
4400 /* we don't support these - and CANCEL_LOCK makes w2k
4401 and XP reboot so I don't really want to be
4402 compatible! (tridge) */
4403 return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
4406 /* Check if this is an oplock break on a file
4407 we have granted an oplock on.
4409 if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
4410 /* Client can insist on breaking to none. */
4411 BOOL break_to_none = (oplocklevel == 0);
4413 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client for fnum = %d\n",
4414 (unsigned int)oplocklevel, fsp->fnum ));
4417 * Make sure we have granted an exclusive or batch oplock on this file.
4420 if(!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
4421 DEBUG(0,("reply_lockingX: Error : oplock break from client for fnum = %d and \
4422 no oplock granted on this file (%s).\n", fsp->fnum, fsp->fsp_name));
4424 /* if this is a pure oplock break request then don't send a reply */
4425 if (num_locks == 0 && num_ulocks == 0) {
4426 END_PROFILE(SMBlockingX);
4427 return -1;
4428 } else {
4429 END_PROFILE(SMBlockingX);
4430 return ERROR_DOS(ERRDOS,ERRlock);
4434 if (remove_oplock(fsp, break_to_none) == False) {
4435 DEBUG(0,("reply_lockingX: error in removing oplock on file %s\n",
4436 fsp->fsp_name ));
4439 /* if this is a pure oplock break request then don't send a reply */
4440 if (num_locks == 0 && num_ulocks == 0) {
4441 /* Sanity check - ensure a pure oplock break is not a
4442 chained request. */
4443 if(CVAL(inbuf,smb_vwv0) != 0xff)
4444 DEBUG(0,("reply_lockingX: Error : pure oplock break is a chained %d request !\n",
4445 (unsigned int)CVAL(inbuf,smb_vwv0) ));
4446 END_PROFILE(SMBlockingX);
4447 return -1;
4452 * We do this check *after* we have checked this is not a oplock break
4453 * response message. JRA.
4456 release_level_2_oplocks_on_change(fsp);
4458 /* Data now points at the beginning of the list
4459 of smb_unlkrng structs */
4460 for(i = 0; i < (int)num_ulocks; i++) {
4461 lock_pid = get_lock_pid( data, i, large_file_format);
4462 count = get_lock_count( data, i, large_file_format);
4463 offset = get_lock_offset( data, i, large_file_format, &err);
4466 * There is no error code marked "stupid client bug".... :-).
4468 if(err) {
4469 END_PROFILE(SMBlockingX);
4470 return ERROR_DOS(ERRDOS,ERRnoaccess);
4473 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for pid %u, file %s\n",
4474 (double)offset, (double)count, (unsigned int)lock_pid, fsp->fsp_name ));
4476 status = do_unlock(fsp,conn,lock_pid,count,offset);
4477 if (NT_STATUS_V(status)) {
4478 END_PROFILE(SMBlockingX);
4479 return ERROR_NT(status);
4483 /* Setup the timeout in seconds. */
4485 lock_timeout = ((lock_timeout == -1) ? -1 : (lock_timeout+999)/1000);
4487 /* Now do any requested locks */
4488 data += ((large_file_format ? 20 : 10)*num_ulocks);
4490 /* Data now points at the beginning of the list
4491 of smb_lkrng structs */
4493 for(i = 0; i < (int)num_locks; i++) {
4494 lock_pid = get_lock_pid( data, i, large_file_format);
4495 count = get_lock_count( data, i, large_file_format);
4496 offset = get_lock_offset( data, i, large_file_format, &err);
4499 * There is no error code marked "stupid client bug".... :-).
4501 if(err) {
4502 END_PROFILE(SMBlockingX);
4503 return ERROR_DOS(ERRDOS,ERRnoaccess);
4506 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid %u, file %s timeout = %d\n",
4507 (double)offset, (double)count, (unsigned int)lock_pid,
4508 fsp->fsp_name, (int)lock_timeout ));
4510 status = do_lock_spin(fsp,conn,lock_pid, count,offset,
4511 ((locktype & 1) ? READ_LOCK : WRITE_LOCK), &my_lock_ctx);
4512 if (NT_STATUS_V(status)) {
4514 * Interesting fact found by IFSTEST /t LockOverlappedTest...
4515 * Even if it's our own lock context, we need to wait here as
4516 * there may be an unlock on the way.
4517 * So I removed a "&& !my_lock_ctx" from the following
4518 * if statement. JRA.
4520 if ((lock_timeout != 0) && lp_blocking_locks(SNUM(conn)) && ERROR_WAS_LOCK_DENIED(status)) {
4522 * A blocking lock was requested. Package up
4523 * this smb into a queued request and push it
4524 * onto the blocking lock queue.
4526 if(push_blocking_lock_request(inbuf, length, lock_timeout, i, lock_pid, offset, count)) {
4527 END_PROFILE(SMBlockingX);
4528 return -1;
4531 break;
4535 /* If any of the above locks failed, then we must unlock
4536 all of the previous locks (X/Open spec). */
4537 if (i != num_locks && num_locks != 0) {
4539 * Ensure we don't do a remove on the lock that just failed,
4540 * as under POSIX rules, if we have a lock already there, we
4541 * will delete it (and we shouldn't) .....
4543 for(i--; i >= 0; i--) {
4544 lock_pid = get_lock_pid( data, i, large_file_format);
4545 count = get_lock_count( data, i, large_file_format);
4546 offset = get_lock_offset( data, i, large_file_format, &err);
4549 * There is no error code marked "stupid client bug".... :-).
4551 if(err) {
4552 END_PROFILE(SMBlockingX);
4553 return ERROR_DOS(ERRDOS,ERRnoaccess);
4556 do_unlock(fsp,conn,lock_pid,count,offset);
4558 END_PROFILE(SMBlockingX);
4559 return ERROR_NT(status);
4562 set_message(outbuf,2,0,True);
4564 DEBUG( 3, ( "lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
4565 fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks ) );
4567 END_PROFILE(SMBlockingX);
4568 return chain_reply(inbuf,outbuf,length,bufsize);
4571 /****************************************************************************
4572 Reply to a SMBreadbmpx (read block multiplex) request.
4573 ****************************************************************************/
4575 int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
4577 ssize_t nread = -1;
4578 ssize_t total_read;
4579 char *data;
4580 SMB_OFF_T startpos;
4581 int outsize;
4582 size_t maxcount;
4583 int max_per_packet;
4584 size_t tcount;
4585 int pad;
4586 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4587 START_PROFILE(SMBreadBmpx);
4589 /* this function doesn't seem to work - disable by default */
4590 if (!lp_readbmpx()) {
4591 END_PROFILE(SMBreadBmpx);
4592 return ERROR_DOS(ERRSRV,ERRuseSTD);
4595 outsize = set_message(outbuf,8,0,True);
4597 CHECK_FSP(fsp,conn);
4598 CHECK_READ(fsp);
4600 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
4601 maxcount = SVAL(inbuf,smb_vwv3);
4603 data = smb_buf(outbuf);
4604 pad = ((long)data)%4;
4605 if (pad)
4606 pad = 4 - pad;
4607 data += pad;
4609 max_per_packet = bufsize-(outsize+pad);
4610 tcount = maxcount;
4611 total_read = 0;
4613 if (is_locked(fsp,conn,(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK,False)) {
4614 END_PROFILE(SMBreadBmpx);
4615 return ERROR_DOS(ERRDOS,ERRlock);
4618 do {
4619 size_t N = MIN(max_per_packet,tcount-total_read);
4621 nread = read_file(fsp,data,startpos,N);
4623 if (nread <= 0)
4624 nread = 0;
4626 if (nread < (ssize_t)N)
4627 tcount = total_read + nread;
4629 set_message(outbuf,8,nread,False);
4630 SIVAL(outbuf,smb_vwv0,startpos);
4631 SSVAL(outbuf,smb_vwv2,tcount);
4632 SSVAL(outbuf,smb_vwv6,nread);
4633 SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
4635 if (!send_smb(smbd_server_fd(),outbuf))
4636 exit_server("reply_readbmpx: send_smb failed.");
4638 total_read += nread;
4639 startpos += nread;
4640 } while (total_read < (ssize_t)tcount);
4642 END_PROFILE(SMBreadBmpx);
4643 return(-1);
4646 /****************************************************************************
4647 Reply to a SMBsetattrE.
4648 ****************************************************************************/
4650 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4652 struct utimbuf unix_times;
4653 int outsize = 0;
4654 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4655 START_PROFILE(SMBsetattrE);
4657 outsize = set_message(outbuf,0,0,True);
4659 if(!fsp || (fsp->conn != conn)) {
4660 END_PROFILE(SMBgetattrE);
4661 return ERROR_DOS(ERRDOS,ERRbadfid);
4665 * Convert the DOS times into unix times. Ignore create
4666 * time as UNIX can't set this.
4669 unix_times.actime = make_unix_date2(inbuf+smb_vwv3);
4670 unix_times.modtime = make_unix_date2(inbuf+smb_vwv5);
4673 * Patch from Ray Frush <frush@engr.colostate.edu>
4674 * Sometimes times are sent as zero - ignore them.
4677 if ((unix_times.actime == 0) && (unix_times.modtime == 0)) {
4678 /* Ignore request */
4679 if( DEBUGLVL( 3 ) ) {
4680 dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
4681 dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
4683 END_PROFILE(SMBsetattrE);
4684 return(outsize);
4685 } else if ((unix_times.actime != 0) && (unix_times.modtime == 0)) {
4686 /* set modify time = to access time if modify time was 0 */
4687 unix_times.modtime = unix_times.actime;
4690 /* Set the date on this file */
4691 if(file_utime(conn, fsp->fsp_name, &unix_times)) {
4692 END_PROFILE(SMBsetattrE);
4693 return ERROR_DOS(ERRDOS,ERRnoaccess);
4696 DEBUG( 3, ( "reply_setattrE fnum=%d actime=%d modtime=%d\n",
4697 fsp->fnum, (int)unix_times.actime, (int)unix_times.modtime ) );
4699 END_PROFILE(SMBsetattrE);
4700 return(outsize);
4704 /* Back from the dead for OS/2..... JRA. */
4706 /****************************************************************************
4707 Reply to a SMBwritebmpx (write block multiplex primary) request.
4708 ****************************************************************************/
4710 int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4712 size_t numtowrite;
4713 ssize_t nwritten = -1;
4714 int outsize = 0;
4715 SMB_OFF_T startpos;
4716 size_t tcount;
4717 BOOL write_through;
4718 int smb_doff;
4719 char *data;
4720 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4721 START_PROFILE(SMBwriteBmpx);
4723 CHECK_FSP(fsp,conn);
4724 CHECK_WRITE(fsp);
4725 CHECK_ERROR(fsp);
4727 tcount = SVAL(inbuf,smb_vwv1);
4728 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
4729 write_through = BITSETW(inbuf+smb_vwv7,0);
4730 numtowrite = SVAL(inbuf,smb_vwv10);
4731 smb_doff = SVAL(inbuf,smb_vwv11);
4733 data = smb_base(inbuf) + smb_doff;
4735 /* If this fails we need to send an SMBwriteC response,
4736 not an SMBwritebmpx - set this up now so we don't forget */
4737 SCVAL(outbuf,smb_com,SMBwritec);
4739 if (is_locked(fsp,conn,(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK,False)) {
4740 END_PROFILE(SMBwriteBmpx);
4741 return(ERROR_DOS(ERRDOS,ERRlock));
4744 nwritten = write_file(fsp,data,startpos,numtowrite);
4746 if(lp_syncalways(SNUM(conn)) || write_through)
4747 sync_file(conn,fsp);
4749 if(nwritten < (ssize_t)numtowrite) {
4750 END_PROFILE(SMBwriteBmpx);
4751 return(UNIXERROR(ERRHRD,ERRdiskfull));
4754 /* If the maximum to be written to this file
4755 is greater than what we just wrote then set
4756 up a secondary struct to be attached to this
4757 fd, we will use this to cache error messages etc. */
4759 if((ssize_t)tcount > nwritten) {
4760 write_bmpx_struct *wbms;
4761 if(fsp->wbmpx_ptr != NULL)
4762 wbms = fsp->wbmpx_ptr; /* Use an existing struct */
4763 else
4764 wbms = (write_bmpx_struct *)malloc(sizeof(write_bmpx_struct));
4765 if(!wbms) {
4766 DEBUG(0,("Out of memory in reply_readmpx\n"));
4767 END_PROFILE(SMBwriteBmpx);
4768 return(ERROR_DOS(ERRSRV,ERRnoresource));
4770 wbms->wr_mode = write_through;
4771 wbms->wr_discard = False; /* No errors yet */
4772 wbms->wr_total_written = nwritten;
4773 wbms->wr_errclass = 0;
4774 wbms->wr_error = 0;
4775 fsp->wbmpx_ptr = wbms;
4778 /* We are returning successfully, set the message type back to
4779 SMBwritebmpx */
4780 SCVAL(outbuf,smb_com,SMBwriteBmpx);
4782 outsize = set_message(outbuf,1,0,True);
4784 SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
4786 DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
4787 fsp->fnum, (int)numtowrite, (int)nwritten ) );
4789 if (write_through && tcount==nwritten) {
4790 /* We need to send both a primary and a secondary response */
4791 smb_setlen(outbuf,outsize - 4);
4792 if (!send_smb(smbd_server_fd(),outbuf))
4793 exit_server("reply_writebmpx: send_smb failed.");
4795 /* Now the secondary */
4796 outsize = set_message(outbuf,1,0,True);
4797 SCVAL(outbuf,smb_com,SMBwritec);
4798 SSVAL(outbuf,smb_vwv0,nwritten);
4801 END_PROFILE(SMBwriteBmpx);
4802 return(outsize);
4805 /****************************************************************************
4806 Reply to a SMBwritebs (write block multiplex secondary) request.
4807 ****************************************************************************/
4809 int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
4811 size_t numtowrite;
4812 ssize_t nwritten = -1;
4813 int outsize = 0;
4814 SMB_OFF_T startpos;
4815 size_t tcount;
4816 BOOL write_through;
4817 int smb_doff;
4818 char *data;
4819 write_bmpx_struct *wbms;
4820 BOOL send_response = False;
4821 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4822 START_PROFILE(SMBwriteBs);
4824 CHECK_FSP(fsp,conn);
4825 CHECK_WRITE(fsp);
4827 tcount = SVAL(inbuf,smb_vwv1);
4828 startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
4829 numtowrite = SVAL(inbuf,smb_vwv6);
4830 smb_doff = SVAL(inbuf,smb_vwv7);
4832 data = smb_base(inbuf) + smb_doff;
4834 /* We need to send an SMBwriteC response, not an SMBwritebs */
4835 SCVAL(outbuf,smb_com,SMBwritec);
4837 /* This fd should have an auxiliary struct attached,
4838 check that it does */
4839 wbms = fsp->wbmpx_ptr;
4840 if(!wbms) {
4841 END_PROFILE(SMBwriteBs);
4842 return(-1);
4845 /* If write through is set we can return errors, else we must cache them */
4846 write_through = wbms->wr_mode;
4848 /* Check for an earlier error */
4849 if(wbms->wr_discard) {
4850 END_PROFILE(SMBwriteBs);
4851 return -1; /* Just discard the packet */
4854 nwritten = write_file(fsp,data,startpos,numtowrite);
4856 if(lp_syncalways(SNUM(conn)) || write_through)
4857 sync_file(conn,fsp);
4859 if (nwritten < (ssize_t)numtowrite) {
4860 if(write_through) {
4861 /* We are returning an error - we can delete the aux struct */
4862 if (wbms)
4863 free((char *)wbms);
4864 fsp->wbmpx_ptr = NULL;
4865 END_PROFILE(SMBwriteBs);
4866 return(ERROR_DOS(ERRHRD,ERRdiskfull));
4868 END_PROFILE(SMBwriteBs);
4869 return(CACHE_ERROR(wbms,ERRHRD,ERRdiskfull));
4872 /* Increment the total written, if this matches tcount
4873 we can discard the auxiliary struct (hurrah !) and return a writeC */
4874 wbms->wr_total_written += nwritten;
4875 if(wbms->wr_total_written >= tcount) {
4876 if (write_through) {
4877 outsize = set_message(outbuf,1,0,True);
4878 SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);
4879 send_response = True;
4882 free((char *)wbms);
4883 fsp->wbmpx_ptr = NULL;
4886 if(send_response) {
4887 END_PROFILE(SMBwriteBs);
4888 return(outsize);
4891 END_PROFILE(SMBwriteBs);
4892 return(-1);
4895 /****************************************************************************
4896 Reply to a SMBgetattrE.
4897 ****************************************************************************/
4899 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
4901 SMB_STRUCT_STAT sbuf;
4902 int outsize = 0;
4903 int mode;
4904 files_struct *fsp = file_fsp(inbuf,smb_vwv0);
4905 START_PROFILE(SMBgetattrE);
4907 outsize = set_message(outbuf,11,0,True);
4909 if(!fsp || (fsp->conn != conn)) {
4910 END_PROFILE(SMBgetattrE);
4911 return ERROR_DOS(ERRDOS,ERRbadfid);
4914 /* Do an fstat on this file */
4915 if(fsp_stat(fsp, &sbuf)) {
4916 END_PROFILE(SMBgetattrE);
4917 return(UNIXERROR(ERRDOS,ERRnoaccess));
4920 mode = dos_mode(conn,fsp->fsp_name,&sbuf);
4923 * Convert the times into dos times. Set create
4924 * date to be last modify date as UNIX doesn't save
4925 * this.
4928 put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
4929 put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
4930 put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
4932 if (mode & aDIR) {
4933 SIVAL(outbuf,smb_vwv6,0);
4934 SIVAL(outbuf,smb_vwv8,0);
4935 } else {
4936 uint32 allocation_size = get_allocation_size(fsp, &sbuf);
4937 SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
4938 SIVAL(outbuf,smb_vwv8,allocation_size);
4940 SSVAL(outbuf,smb_vwv10, mode);
4942 DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
4944 END_PROFILE(SMBgetattrE);
4945 return(outsize);