smbd/reply.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    Main SMB reply routines
00004    Copyright (C) Andrew Tridgell 1992-1998
00005    Copyright (C) Andrew Bartlett      2001
00006    Copyright (C) Jeremy Allison 1992-2007.
00007 
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021 */
00022 /*
00023    This file handles most of the reply_ calls that the server
00024    makes to handle specific protocols
00025 */
00026 
00027 #include "includes.h"
00028 
00029 /* look in server.c for some explanation of these variables */
00030 extern enum protocol_types Protocol;
00031 extern int max_send;
00032 extern int max_recv;
00033 unsigned int smb_echo_count = 0;
00034 extern uint32 global_client_caps;
00035 
00036 extern struct current_user current_user;
00037 extern BOOL global_encrypted_passwords_negotiated;
00038 
00039 /****************************************************************************
00040  Ensure we check the path in *exactly* the same way as W2K for a findfirst/findnext
00041  path or anything including wildcards.
00042  We're assuming here that '/' is not the second byte in any multibyte char
00043  set (a safe assumption). '\\' *may* be the second byte in a multibyte char
00044  set.
00045 ****************************************************************************/
00046 
00047 /* Custom version for processing POSIX paths. */
00048 #define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
00049 
00050 NTSTATUS check_path_syntax_internal(pstring destname,
00051                                     const pstring srcname,
00052                                     BOOL posix_path,
00053                                     BOOL *p_last_component_contains_wcard)
00054 {
00055         char *d = destname;
00056         const char *s = srcname;
00057         NTSTATUS ret = NT_STATUS_OK;
00058         BOOL start_of_name_component = True;
00059 
00060         *p_last_component_contains_wcard = False;
00061 
00062         while (*s) {
00063                 if (IS_PATH_SEP(*s,posix_path)) {
00064                         /*
00065                          * Safe to assume is not the second part of a mb char as this is handled below.
00066                          */
00067                         /* Eat multiple '/' or '\\' */
00068                         while (IS_PATH_SEP(*s,posix_path)) {
00069                                 s++;
00070                         }
00071                         if ((d != destname) && (*s != '\0')) {
00072                                 /* We only care about non-leading or trailing '/' or '\\' */
00073                                 *d++ = '/';
00074                         }
00075 
00076                         start_of_name_component = True;
00077                         /* New component. */
00078                         *p_last_component_contains_wcard = False;
00079                         continue;
00080                 }
00081 
00082                 if (start_of_name_component) {
00083                         if ((s[0] == '.') && (s[1] == '.') && (IS_PATH_SEP(s[2],posix_path) || s[2] == '\0')) {
00084                                 /* Uh oh - "/../" or "\\..\\"  or "/..\0" or "\\..\0" ! */
00085 
00086                                 /*
00087                                  * No mb char starts with '.' so we're safe checking the directory separator here.
00088                                  */
00089 
00090                                 /* If  we just added a '/' - delete it */
00091                                 if ((d > destname) && (*(d-1) == '/')) {
00092                                         *(d-1) = '\0';
00093                                         d--;
00094                                 }
00095 
00096                                 /* Are we at the start ? Can't go back further if so. */
00097                                 if (d <= destname) {
00098                                         ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
00099                                         break;
00100                                 }
00101                                 /* Go back one level... */
00102                                 /* We know this is safe as '/' cannot be part of a mb sequence. */
00103                                 /* NOTE - if this assumption is invalid we are not in good shape... */
00104                                 /* Decrement d first as d points to the *next* char to write into. */
00105                                 for (d--; d > destname; d--) {
00106                                         if (*d == '/')
00107                                                 break;
00108                                 }
00109                                 s += 2; /* Else go past the .. */
00110                                 /* We're still at the start of a name component, just the previous one. */
00111                                 continue;
00112 
00113                         } else if ((s[0] == '.') && ((s[1] == '\0') || IS_PATH_SEP(s[1],posix_path))) {
00114                                 if (posix_path) {
00115                                         /* Eat the '.' */
00116                                         s++;
00117                                         continue;
00118                                 }
00119                         }
00120 
00121                 }
00122 
00123                 if (!(*s & 0x80)) {
00124                         if (!posix_path) {
00125                                 if (*s <= 0x1f) {
00126                                         return NT_STATUS_OBJECT_NAME_INVALID;
00127                                 }
00128                                 switch (*s) {
00129                                         case '*':
00130                                         case '?':
00131                                         case '<':
00132                                         case '>':
00133                                         case '"':
00134                                                 *p_last_component_contains_wcard = True;
00135                                                 break;
00136                                         default:
00137                                                 break;
00138                                 }
00139                         }
00140                         *d++ = *s++;
00141                 } else {
00142                         size_t siz;
00143                         /* Get the size of the next MB character. */
00144                         next_codepoint(s,&siz);
00145                         switch(siz) {
00146                                 case 5:
00147                                         *d++ = *s++;
00148                                         /*fall through*/
00149                                 case 4:
00150                                         *d++ = *s++;
00151                                         /*fall through*/
00152                                 case 3:
00153                                         *d++ = *s++;
00154                                         /*fall through*/
00155                                 case 2:
00156                                         *d++ = *s++;
00157                                         /*fall through*/
00158                                 case 1:
00159                                         *d++ = *s++;
00160                                         break;
00161                                 default:
00162                                         DEBUG(0,("check_path_syntax_internal: character length assumptions invalid !\n"));
00163                                         *d = '\0';
00164                                         return NT_STATUS_INVALID_PARAMETER;
00165                         }
00166                 }
00167                 start_of_name_component = False;
00168         }
00169 
00170         *d = '\0';
00171         return ret;
00172 }
00173 
00174 /****************************************************************************
00175  Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
00176  No wildcards allowed.
00177 ****************************************************************************/
00178 
00179 NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
00180 {
00181         BOOL ignore;
00182         return check_path_syntax_internal(destname, srcname, False, &ignore);
00183 }
00184 
00185 /****************************************************************************
00186  Ensure we check the path in *exactly* the same way as W2K for regular pathnames.
00187  Wildcards allowed - p_contains_wcard returns true if the last component contained
00188  a wildcard.
00189 ****************************************************************************/
00190 
00191 NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
00192 {
00193         return check_path_syntax_internal(destname, srcname, False, p_contains_wcard);
00194 }
00195 
00196 /****************************************************************************
00197  Check the path for a POSIX client.
00198  We're assuming here that '/' is not the second byte in any multibyte char
00199  set (a safe assumption).
00200 ****************************************************************************/
00201 
00202 NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
00203 {
00204         BOOL ignore;
00205         return check_path_syntax_internal(destname, srcname, True, &ignore);
00206 }
00207 
00208 /****************************************************************************
00209  Pull a string and check the path allowing a wilcard - provide for error return.
00210 ****************************************************************************/
00211 
00212 size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags,
00213                                 NTSTATUS *err, BOOL *contains_wcard)
00214 {
00215         pstring tmppath;
00216         char *tmppath_ptr = tmppath;
00217         size_t ret;
00218 #ifdef DEVELOPER
00219         SMB_ASSERT(dest_len == sizeof(pstring));
00220 #endif
00221 
00222         if (src_len == 0) {
00223                 ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
00224         } else {
00225                 ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
00226         }
00227 
00228         *contains_wcard = False;
00229 
00230         if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
00231                 /* 
00232                  * For a DFS path the function parse_dfs_path()
00233                  * will do the path processing, just make a copy.
00234                  */
00235                 pstrcpy(dest, tmppath);
00236                 *err = NT_STATUS_OK;
00237                 return ret;
00238         }
00239 
00240         if (lp_posix_pathnames()) {
00241                 *err = check_path_syntax_posix(dest, tmppath);
00242         } else {
00243                 *err = check_path_syntax_wcard(dest, tmppath, contains_wcard);
00244         }
00245 
00246         return ret;
00247 }
00248 
00249 /****************************************************************************
00250  Pull a string and check the path - provide for error return.
00251 ****************************************************************************/
00252 
00253 size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err)
00254 {
00255         pstring tmppath;
00256         char *tmppath_ptr = tmppath;
00257         size_t ret;
00258 #ifdef DEVELOPER
00259         SMB_ASSERT(dest_len == sizeof(pstring));
00260 #endif
00261 
00262         if (src_len == 0) {
00263                 ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
00264         } else {
00265                 ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
00266         }
00267 
00268         if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
00269                 /* 
00270                  * For a DFS path the function parse_dfs_path()
00271                  * will do the path processing, just make a copy.
00272                  */
00273                 pstrcpy(dest, tmppath);
00274                 *err = NT_STATUS_OK;
00275                 return ret;
00276         }
00277 
00278         if (lp_posix_pathnames()) {
00279                 *err = check_path_syntax_posix(dest, tmppath);
00280         } else {
00281                 *err = check_path_syntax(dest, tmppath);
00282         }
00283 
00284         return ret;
00285 }
00286 
00287 /****************************************************************************
00288  Reply to a special message.
00289 ****************************************************************************/
00290 
00291 int reply_special(char *inbuf,char *outbuf)
00292 {
00293         int outsize = 4;
00294         int msg_type = CVAL(inbuf,0);
00295         int msg_flags = CVAL(inbuf,1);
00296         fstring name1,name2;
00297         char name_type = 0;
00298         
00299         static BOOL already_got_session = False;
00300 
00301         *name1 = *name2 = 0;
00302         
00303         memset(outbuf,'\0',smb_size);
00304 
00305         smb_setlen(outbuf,0);
00306         
00307         switch (msg_type) {
00308         case 0x81: /* session request */
00309                 
00310                 if (already_got_session) {
00311                         exit_server_cleanly("multiple session request not permitted");
00312                 }
00313                 
00314                 SCVAL(outbuf,0,0x82);
00315                 SCVAL(outbuf,3,0);
00316                 if (name_len(inbuf+4) > 50 || 
00317                     name_len(inbuf+4 + name_len(inbuf + 4)) > 50) {
00318                         DEBUG(0,("Invalid name length in session request\n"));
00319                         return(0);
00320                 }
00321                 name_extract(inbuf,4,name1);
00322                 name_type = name_extract(inbuf,4 + name_len(inbuf + 4),name2);
00323                 DEBUG(2,("netbios connect: name1=%s name2=%s\n",
00324                          name1,name2));      
00325 
00326                 set_local_machine_name(name1, True);
00327                 set_remote_machine_name(name2, True);
00328 
00329                 DEBUG(2,("netbios connect: local=%s remote=%s, name type = %x\n",
00330                          get_local_machine_name(), get_remote_machine_name(),
00331                          name_type));
00332 
00333                 if (name_type == 'R') {
00334                         /* We are being asked for a pathworks session --- 
00335                            no thanks! */
00336                         SCVAL(outbuf, 0,0x83);
00337                         break;
00338                 }
00339 
00340                 /* only add the client's machine name to the list
00341                    of possibly valid usernames if we are operating
00342                    in share mode security */
00343                 if (lp_security() == SEC_SHARE) {
00344                         add_session_user(get_remote_machine_name());
00345                 }
00346 
00347                 reload_services(True);
00348                 reopen_logs();
00349 
00350                 already_got_session = True;
00351                 break;
00352                 
00353         case 0x89: /* session keepalive request 
00354                       (some old clients produce this?) */
00355                 SCVAL(outbuf,0,SMBkeepalive);
00356                 SCVAL(outbuf,3,0);
00357                 break;
00358                 
00359         case 0x82: /* positive session response */
00360         case 0x83: /* negative session response */
00361         case 0x84: /* retarget session response */
00362                 DEBUG(0,("Unexpected session response\n"));
00363                 break;
00364                 
00365         case SMBkeepalive: /* session keepalive */
00366         default:
00367                 return(0);
00368         }
00369         
00370         DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
00371                     msg_type, msg_flags));
00372         
00373         return(outsize);
00374 }
00375 
00376 /****************************************************************************
00377  Reply to a tcon.
00378  conn POINTER CAN BE NULL HERE !
00379 ****************************************************************************/
00380 
00381 int reply_tcon(connection_struct *conn,
00382                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00383 {
00384         const char *service;
00385         pstring service_buf;
00386         pstring password;
00387         pstring dev;
00388         int outsize = 0;
00389         uint16 vuid = SVAL(inbuf,smb_uid);
00390         int pwlen=0;
00391         NTSTATUS nt_status;
00392         char *p;
00393         DATA_BLOB password_blob;
00394         
00395         START_PROFILE(SMBtcon);
00396 
00397         *service_buf = *password = *dev = 0;
00398 
00399         p = smb_buf(inbuf)+1;
00400         p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service_buf), STR_TERMINATE) + 1;
00401         pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1;
00402         p += pwlen;
00403         p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1;
00404 
00405         p = strrchr_m(service_buf,'\\');
00406         if (p) {
00407                 service = p+1;
00408         } else {
00409                 service = service_buf;
00410         }
00411 
00412         password_blob = data_blob(password, pwlen+1);
00413 
00414         conn = make_connection(service,password_blob,dev,vuid,&nt_status);
00415 
00416         data_blob_clear_free(&password_blob);
00417   
00418         if (!conn) {
00419                 END_PROFILE(SMBtcon);
00420                 return ERROR_NT(nt_status);
00421         }
00422   
00423         outsize = set_message(outbuf,2,0,True);
00424         SSVAL(outbuf,smb_vwv0,max_recv);
00425         SSVAL(outbuf,smb_vwv1,conn->cnum);
00426         SSVAL(outbuf,smb_tid,conn->cnum);
00427   
00428         DEBUG(3,("tcon service=%s cnum=%d\n", 
00429                  service, conn->cnum));
00430   
00431         END_PROFILE(SMBtcon);
00432         return(outsize);
00433 }
00434 
00435 /****************************************************************************
00436  Reply to a tcon and X.
00437  conn POINTER CAN BE NULL HERE !
00438 ****************************************************************************/
00439 
00440 int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
00441 {
00442         fstring service;
00443         DATA_BLOB password;
00444 
00445         /* what the cleint thinks the device is */
00446         fstring client_devicetype;
00447         /* what the server tells the client the share represents */
00448         const char *server_devicetype;
00449         NTSTATUS nt_status;
00450         uint16 vuid = SVAL(inbuf,smb_uid);
00451         int passlen = SVAL(inbuf,smb_vwv3);
00452         pstring path;
00453         char *p, *q;
00454         uint16 tcon_flags = SVAL(inbuf,smb_vwv2);
00455         
00456         START_PROFILE(SMBtconX);        
00457 
00458         *service = *client_devicetype = 0;
00459 
00460         /* we might have to close an old one */
00461         if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
00462                 close_cnum(conn,vuid);
00463         }
00464 
00465         if (passlen > MAX_PASS_LEN) {
00466                 return ERROR_DOS(ERRDOS,ERRbuftoosmall);
00467         }
00468  
00469         if (global_encrypted_passwords_negotiated) {
00470                 password = data_blob(smb_buf(inbuf),passlen);
00471                 if (lp_security() == SEC_SHARE) {
00472                         /*
00473                          * Security = share always has a pad byte
00474                          * after the password.
00475                          */
00476                         p = smb_buf(inbuf) + passlen + 1;
00477                 } else {
00478                         p = smb_buf(inbuf) + passlen;
00479                 }
00480         } else {
00481                 password = data_blob(smb_buf(inbuf),passlen+1);
00482                 /* Ensure correct termination */
00483                 password.data[passlen]=0;
00484                 p = smb_buf(inbuf) + passlen + 1;
00485         }
00486 
00487         p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
00488 
00489         /*
00490          * the service name can be either: \\server\share
00491          * or share directly like on the DELL PowerVault 705
00492          */
00493         if (*path=='\\') {      
00494                 q = strchr_m(path+2,'\\');
00495                 if (!q) {
00496                         END_PROFILE(SMBtconX);
00497                         return(ERROR_DOS(ERRDOS,ERRnosuchshare));
00498                 }
00499                 fstrcpy(service,q+1);
00500         }
00501         else
00502                 fstrcpy(service,path);
00503                 
00504         p += srvstr_pull(inbuf, client_devicetype, p, sizeof(client_devicetype), 6, STR_ASCII);
00505 
00506         DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
00507 
00508         conn = make_connection(service,password,client_devicetype,vuid,&nt_status);
00509         
00510         data_blob_clear_free(&password);
00511 
00512         if (!conn) {
00513                 END_PROFILE(SMBtconX);
00514                 return ERROR_NT(nt_status);
00515         }
00516 
00517         if ( IS_IPC(conn) )
00518                 server_devicetype = "IPC";
00519         else if ( IS_PRINT(conn) )
00520                 server_devicetype = "LPT1:";
00521         else 
00522                 server_devicetype = "A:";
00523 
00524         if (Protocol < PROTOCOL_NT1) {
00525                 set_message(outbuf,2,0,True);
00526                 p = smb_buf(outbuf);
00527                 p += srvstr_push(outbuf, p, server_devicetype, BUFFER_SIZE - (p - outbuf),
00528                                  STR_TERMINATE|STR_ASCII);
00529                 set_message_end(outbuf,p);
00530         } else {
00531                 /* NT sets the fstype of IPC$ to the null string */
00532                 const char *fstype = IS_IPC(conn) ? "" : lp_fstype(SNUM(conn));
00533                 
00534                 if (tcon_flags & TCONX_FLAG_EXTENDED_RESPONSE) {
00535                         /* Return permissions. */
00536                         uint32 perm1 = 0;
00537                         uint32 perm2 = 0;
00538 
00539                         set_message(outbuf,7,0,True);
00540 
00541                         if (IS_IPC(conn)) {
00542                                 perm1 = FILE_ALL_ACCESS;
00543                                 perm2 = FILE_ALL_ACCESS;
00544                         } else {
00545                                 perm1 = CAN_WRITE(conn) ?
00546                                                 SHARE_ALL_ACCESS :
00547                                                 SHARE_READ_ONLY;
00548                         }
00549 
00550                         SIVAL(outbuf, smb_vwv3, perm1);
00551                         SIVAL(outbuf, smb_vwv5, perm2);
00552                 } else {
00553                         set_message(outbuf,3,0,True);
00554                 }
00555 
00556                 p = smb_buf(outbuf);
00557                 p += srvstr_push(outbuf, p, server_devicetype, BUFFER_SIZE - (p - outbuf),
00558                                  STR_TERMINATE|STR_ASCII);
00559                 p += srvstr_push(outbuf, p, fstype, BUFFER_SIZE - (p - outbuf),
00560                                  STR_TERMINATE);
00561                 
00562                 set_message_end(outbuf,p);
00563                 
00564                 /* what does setting this bit do? It is set by NT4 and
00565                    may affect the ability to autorun mounted cdroms */
00566                 SSVAL(outbuf, smb_vwv2, SMB_SUPPORT_SEARCH_BITS|
00567                                 (lp_csc_policy(SNUM(conn)) << 2));
00568                 
00569                 init_dfsroot(conn, inbuf, outbuf);
00570         }
00571 
00572   
00573         DEBUG(3,("tconX service=%s \n",
00574                  service));
00575   
00576         /* set the incoming and outgoing tid to the just created one */
00577         SSVAL(inbuf,smb_tid,conn->cnum);
00578         SSVAL(outbuf,smb_tid,conn->cnum);
00579 
00580         END_PROFILE(SMBtconX);
00581         return chain_reply(inbuf,outbuf,length,bufsize);
00582 }
00583 
00584 /****************************************************************************
00585  Reply to an unknown type.
00586 ****************************************************************************/
00587 
00588 int reply_unknown(char *inbuf,char *outbuf)
00589 {
00590         int type;
00591         type = CVAL(inbuf,smb_com);
00592   
00593         DEBUG(0,("unknown command type (%s): type=%d (0x%X)\n",
00594                  smb_fn_name(type), type, type));
00595   
00596         return(ERROR_DOS(ERRSRV,ERRunknownsmb));
00597 }
00598 
00599 /****************************************************************************
00600  Reply to an ioctl.
00601  conn POINTER CAN BE NULL HERE !
00602 ****************************************************************************/
00603 
00604 int reply_ioctl(connection_struct *conn,
00605                 char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00606 {
00607         uint16 device     = SVAL(inbuf,smb_vwv1);
00608         uint16 function   = SVAL(inbuf,smb_vwv2);
00609         uint32 ioctl_code = (device << 16) + function;
00610         int replysize, outsize;
00611         char *p;
00612         START_PROFILE(SMBioctl);
00613 
00614         DEBUG(4, ("Received IOCTL (code 0x%x)\n", ioctl_code));
00615 
00616         switch (ioctl_code) {
00617             case IOCTL_QUERY_JOB_INFO:
00618                 replysize = 32;
00619                 break;
00620             default:
00621                 END_PROFILE(SMBioctl);
00622                 return(ERROR_DOS(ERRSRV,ERRnosupport));
00623         }
00624 
00625         outsize = set_message(outbuf,8,replysize+1,True);
00626         SSVAL(outbuf,smb_vwv1,replysize); /* Total data bytes returned */
00627         SSVAL(outbuf,smb_vwv5,replysize); /* Data bytes this buffer */
00628         SSVAL(outbuf,smb_vwv6,52);        /* Offset to data */
00629         p = smb_buf(outbuf) + 1;          /* Allow for alignment */
00630 
00631         switch (ioctl_code) {
00632                 case IOCTL_QUERY_JOB_INFO:                  
00633                 {
00634                         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
00635                         if (!fsp) {
00636                                 END_PROFILE(SMBioctl);
00637                                 return(UNIXERROR(ERRDOS,ERRbadfid));
00638                         }
00639                         SSVAL(p,0,fsp->rap_print_jobid);             /* Job number */
00640                         srvstr_push(outbuf, p+2, global_myname(), 15, STR_TERMINATE|STR_ASCII);
00641                         if (conn) {
00642                                 srvstr_push(outbuf, p+18, lp_servicename(SNUM(conn)), 13, STR_TERMINATE|STR_ASCII);
00643                         }
00644                         break;
00645                 }
00646         }
00647 
00648         END_PROFILE(SMBioctl);
00649         return outsize;
00650 }
00651 
00652 /****************************************************************************
00653  Strange checkpath NTSTATUS mapping.
00654 ****************************************************************************/
00655 
00656 static NTSTATUS map_checkpath_error(const char *inbuf, NTSTATUS status)
00657 {
00658         /* Strange DOS error code semantics only for checkpath... */
00659         if (!(SVAL(inbuf,smb_flg2) & FLAGS2_32_BIT_ERROR_CODES)) {
00660                 if (NT_STATUS_EQUAL(NT_STATUS_OBJECT_NAME_INVALID,status)) {
00661                         /* We need to map to ERRbadpath */
00662                         return NT_STATUS_OBJECT_PATH_NOT_FOUND;
00663                 }
00664         }
00665         return status;
00666 }
00667         
00668 /****************************************************************************
00669  Reply to a checkpath.
00670 ****************************************************************************/
00671 
00672 int reply_checkpath(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00673 {
00674         int outsize = 0;
00675         pstring name;
00676         SMB_STRUCT_STAT sbuf;
00677         NTSTATUS status;
00678 
00679         START_PROFILE(SMBcheckpath);
00680 
00681         srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
00682         if (!NT_STATUS_IS_OK(status)) {
00683                 END_PROFILE(SMBcheckpath);
00684                 status = map_checkpath_error(inbuf, status);
00685                 return ERROR_NT(status);
00686         }
00687 
00688         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name);
00689         if (!NT_STATUS_IS_OK(status)) {
00690                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
00691                         END_PROFILE(SMBcheckpath);
00692                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
00693                 }
00694                 goto path_err;
00695         }
00696 
00697         DEBUG(3,("reply_checkpath %s mode=%d\n", name, (int)SVAL(inbuf,smb_vwv0)));
00698 
00699         status = unix_convert(conn, name, False, NULL, &sbuf);
00700         if (!NT_STATUS_IS_OK(status)) {
00701                 goto path_err;
00702         }
00703 
00704         status = check_name(conn, name);
00705         if (!NT_STATUS_IS_OK(status)) {
00706                 DEBUG(3,("reply_checkpath: check_name of %s failed (%s)\n",name,nt_errstr(status)));
00707                 goto path_err;
00708         }
00709 
00710         if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,name,&sbuf) != 0)) {
00711                 DEBUG(3,("reply_checkpath: stat of %s failed (%s)\n",name,strerror(errno)));
00712                 status = map_nt_error_from_unix(errno);
00713                 goto path_err;
00714         }
00715 
00716         if (!S_ISDIR(sbuf.st_mode)) {
00717                 END_PROFILE(SMBcheckpath);
00718                 return ERROR_BOTH(NT_STATUS_NOT_A_DIRECTORY,ERRDOS,ERRbadpath);
00719         }
00720 
00721         outsize = set_message(outbuf,0,0,False);
00722 
00723         END_PROFILE(SMBcheckpath);
00724         return outsize;
00725 
00726   path_err:
00727 
00728         END_PROFILE(SMBcheckpath);
00729 
00730         /* We special case this - as when a Windows machine
00731                 is parsing a path is steps through the components
00732                 one at a time - if a component fails it expects
00733                 ERRbadpath, not ERRbadfile.
00734         */
00735         status = map_checkpath_error(inbuf, status);
00736         if(NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
00737                 /*
00738                  * Windows returns different error codes if
00739                  * the parent directory is valid but not the
00740                  * last component - it returns NT_STATUS_OBJECT_NAME_NOT_FOUND
00741                  * for that case and NT_STATUS_OBJECT_PATH_NOT_FOUND
00742                  * if the path is invalid.
00743                  */
00744                 return ERROR_BOTH(NT_STATUS_OBJECT_NAME_NOT_FOUND,ERRDOS,ERRbadpath);
00745         }
00746 
00747         return ERROR_NT(status);
00748 }
00749 
00750 /****************************************************************************
00751  Reply to a getatr.
00752 ****************************************************************************/
00753 
00754 int reply_getatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00755 {
00756         pstring fname;
00757         int outsize = 0;
00758         SMB_STRUCT_STAT sbuf;
00759         int mode=0;
00760         SMB_OFF_T size=0;
00761         time_t mtime=0;
00762         char *p;
00763         NTSTATUS status;
00764 
00765         START_PROFILE(SMBgetatr);
00766 
00767         p = smb_buf(inbuf) + 1;
00768         p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
00769         if (!NT_STATUS_IS_OK(status)) {
00770                 END_PROFILE(SMBgetatr);
00771                 return ERROR_NT(status);
00772         }
00773 
00774         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
00775         if (!NT_STATUS_IS_OK(status)) {
00776                 END_PROFILE(SMBgetatr);
00777                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
00778                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
00779                 }
00780                 return ERROR_NT(status);
00781         }
00782   
00783         /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
00784                 under WfWg - weird! */
00785         if (*fname == '\0') {
00786                 mode = aHIDDEN | aDIR;
00787                 if (!CAN_WRITE(conn)) {
00788                         mode |= aRONLY;
00789                 }
00790                 size = 0;
00791                 mtime = 0;
00792         } else {
00793                 status = unix_convert(conn, fname, False, NULL,&sbuf);
00794                 if (!NT_STATUS_IS_OK(status)) {
00795                         END_PROFILE(SMBgetatr);
00796                         return ERROR_NT(status);
00797                 }
00798                 status = check_name(conn, fname);
00799                 if (!NT_STATUS_IS_OK(status)) {
00800                         DEBUG(3,("reply_getatr: check_name of %s failed (%s)\n",fname,nt_errstr(status)));
00801                         END_PROFILE(SMBgetatr);
00802                         return ERROR_NT(status);
00803                 }
00804                 if (!VALID_STAT(sbuf) && (SMB_VFS_STAT(conn,fname,&sbuf) != 0)) {
00805                         DEBUG(3,("reply_getatr: stat of %s failed (%s)\n",fname,strerror(errno)));
00806                         return UNIXERROR(ERRDOS,ERRbadfile);
00807                 }
00808 
00809                 mode = dos_mode(conn,fname,&sbuf);
00810                 size = sbuf.st_size;
00811                 mtime = sbuf.st_mtime;
00812                 if (mode & aDIR) {
00813                         size = 0;
00814                 }
00815         }
00816   
00817         outsize = set_message(outbuf,10,0,True);
00818 
00819         SSVAL(outbuf,smb_vwv0,mode);
00820         if(lp_dos_filetime_resolution(SNUM(conn)) ) {
00821                 srv_put_dos_date3(outbuf,smb_vwv1,mtime & ~1);
00822         } else {
00823                 srv_put_dos_date3(outbuf,smb_vwv1,mtime);
00824         }
00825         SIVAL(outbuf,smb_vwv3,(uint32)size);
00826 
00827         if (Protocol >= PROTOCOL_NT1) {
00828                 SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) | FLAGS2_IS_LONG_NAME);
00829         }
00830   
00831         DEBUG(3,("reply_getatr: name=%s mode=%d size=%u\n", fname, mode, (unsigned int)size ) );
00832   
00833         END_PROFILE(SMBgetatr);
00834         return(outsize);
00835 }
00836 
00837 /****************************************************************************
00838  Reply to a setatr.
00839 ****************************************************************************/
00840 
00841 int reply_setatr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00842 {
00843         pstring fname;
00844         int outsize = 0;
00845         int mode;
00846         time_t mtime;
00847         SMB_STRUCT_STAT sbuf;
00848         char *p;
00849         NTSTATUS status;
00850 
00851         START_PROFILE(SMBsetatr);
00852 
00853         p = smb_buf(inbuf) + 1;
00854         p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
00855         if (!NT_STATUS_IS_OK(status)) {
00856                 END_PROFILE(SMBsetatr);
00857                 return ERROR_NT(status);
00858         }
00859 
00860         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
00861         if (!NT_STATUS_IS_OK(status)) {
00862                 END_PROFILE(SMBsetatr);
00863                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
00864                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
00865                 }
00866                 return ERROR_NT(status);
00867         }
00868   
00869         status = unix_convert(conn, fname, False, NULL, &sbuf);
00870         if (!NT_STATUS_IS_OK(status)) {
00871                 END_PROFILE(SMBsetatr);
00872                 return ERROR_NT(status);
00873         }
00874 
00875         status = check_name(conn, fname);
00876         if (!NT_STATUS_IS_OK(status)) {
00877                 END_PROFILE(SMBsetatr);
00878                 return ERROR_NT(status);
00879         }
00880 
00881         if (fname[0] == '.' && fname[1] == '\0') {
00882                 /*
00883                  * Not sure here is the right place to catch this
00884                  * condition. Might be moved to somewhere else later -- vl
00885                  */
00886                 END_PROFILE(SMBsetatr);
00887                 return ERROR_NT(NT_STATUS_ACCESS_DENIED);
00888         }
00889 
00890         mode = SVAL(inbuf,smb_vwv0);
00891         mtime = srv_make_unix_date3(inbuf+smb_vwv1);
00892   
00893         if (mode != FILE_ATTRIBUTE_NORMAL) {
00894                 if (VALID_STAT_OF_DIR(sbuf))
00895                         mode |= aDIR;
00896                 else
00897                         mode &= ~aDIR;
00898 
00899                 if (file_set_dosmode(conn,fname,mode,&sbuf,False) != 0) {
00900                         END_PROFILE(SMBsetatr);
00901                         return UNIXERROR(ERRDOS, ERRnoaccess);
00902                 }
00903         }
00904 
00905         if (!set_filetime(conn,fname,convert_time_t_to_timespec(mtime))) {
00906                 END_PROFILE(SMBsetatr);
00907                 return UNIXERROR(ERRDOS, ERRnoaccess);
00908         }
00909  
00910         outsize = set_message(outbuf,0,0,False);
00911   
00912         DEBUG( 3, ( "setatr name=%s mode=%d\n", fname, mode ) );
00913   
00914         END_PROFILE(SMBsetatr);
00915         return(outsize);
00916 }
00917 
00918 /****************************************************************************
00919  Reply to a dskattr.
00920 ****************************************************************************/
00921 
00922 int reply_dskattr(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00923 {
00924         int outsize = 0;
00925         SMB_BIG_UINT dfree,dsize,bsize;
00926         START_PROFILE(SMBdskattr);
00927 
00928         if (get_dfree_info(conn,".",True,&bsize,&dfree,&dsize) == (SMB_BIG_UINT)-1) {
00929                 END_PROFILE(SMBdskattr);
00930                 return(UNIXERROR(ERRHRD,ERRgeneral));
00931         }
00932   
00933         outsize = set_message(outbuf,5,0,True);
00934         
00935         if (Protocol <= PROTOCOL_LANMAN2) {
00936                 double total_space, free_space;
00937                 /* we need to scale this to a number that DOS6 can handle. We
00938                    use floating point so we can handle large drives on systems
00939                    that don't have 64 bit integers 
00940 
00941                    we end up displaying a maximum of 2G to DOS systems
00942                 */
00943                 total_space = dsize * (double)bsize;
00944                 free_space = dfree * (double)bsize;
00945 
00946                 dsize = (total_space+63*512) / (64*512);
00947                 dfree = (free_space+63*512) / (64*512);
00948                 
00949                 if (dsize > 0xFFFF) dsize = 0xFFFF;
00950                 if (dfree > 0xFFFF) dfree = 0xFFFF;
00951 
00952                 SSVAL(outbuf,smb_vwv0,dsize);
00953                 SSVAL(outbuf,smb_vwv1,64); /* this must be 64 for dos systems */
00954                 SSVAL(outbuf,smb_vwv2,512); /* and this must be 512 */
00955                 SSVAL(outbuf,smb_vwv3,dfree);
00956         } else {
00957                 SSVAL(outbuf,smb_vwv0,dsize);
00958                 SSVAL(outbuf,smb_vwv1,bsize/512);
00959                 SSVAL(outbuf,smb_vwv2,512);
00960                 SSVAL(outbuf,smb_vwv3,dfree);
00961         }
00962 
00963         DEBUG(3,("dskattr dfree=%d\n", (unsigned int)dfree));
00964 
00965         END_PROFILE(SMBdskattr);
00966         return(outsize);
00967 }
00968 
00969 /****************************************************************************
00970  Reply to a search.
00971  Can be called from SMBsearch, SMBffirst or SMBfunique.
00972 ****************************************************************************/
00973 
00974 int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
00975 {
00976         pstring mask;
00977         pstring directory;
00978         pstring fname;
00979         SMB_OFF_T size;
00980         uint32 mode;
00981         time_t date;
00982         uint32 dirtype;
00983         int outsize = 0;
00984         unsigned int numentries = 0;
00985         unsigned int maxentries = 0;
00986         BOOL finished = False;
00987         char *p;
00988         int status_len;
00989         pstring path;
00990         char status[21];
00991         int dptr_num= -1;
00992         BOOL check_descend = False;
00993         BOOL expect_close = False;
00994         NTSTATUS nt_status;
00995         BOOL mask_contains_wcard = False;
00996         BOOL allow_long_path_components = (SVAL(inbuf,smb_flg2) & FLAGS2_LONG_PATH_COMPONENTS) ? True : False;
00997 
00998         START_PROFILE(SMBsearch);
00999 
01000         if (lp_posix_pathnames()) {
01001                 END_PROFILE(SMBsearch);
01002                 return reply_unknown(inbuf, outbuf);
01003         }
01004 
01005         *mask = *directory = *fname = 0;
01006 
01007         /* If we were called as SMBffirst then we must expect close. */
01008         if(CVAL(inbuf,smb_com) == SMBffirst) {
01009                 expect_close = True;
01010         }
01011   
01012         outsize = set_message(outbuf,1,3,True);
01013         maxentries = SVAL(inbuf,smb_vwv0); 
01014         dirtype = SVAL(inbuf,smb_vwv1);
01015         p = smb_buf(inbuf) + 1;
01016         p += srvstr_get_path_wcard(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status, &mask_contains_wcard);
01017         if (!NT_STATUS_IS_OK(nt_status)) {
01018                 END_PROFILE(SMBsearch);
01019                 return ERROR_NT(nt_status);
01020         }
01021 
01022         nt_status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, path, &mask_contains_wcard);
01023         if (!NT_STATUS_IS_OK(nt_status)) {
01024                 END_PROFILE(SMBsearch);
01025                 if (NT_STATUS_EQUAL(nt_status,NT_STATUS_PATH_NOT_COVERED)) {
01026                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
01027                 }
01028                 return ERROR_NT(nt_status);
01029         }
01030   
01031         p++;
01032         status_len = SVAL(p, 0);
01033         p += 2;
01034   
01035         /* dirtype &= ~aDIR; */
01036 
01037         if (status_len == 0) {
01038                 SMB_STRUCT_STAT sbuf;
01039 
01040                 pstrcpy(directory,path);
01041                 nt_status = unix_convert(conn, directory, True, NULL, &sbuf);
01042                 if (!NT_STATUS_IS_OK(nt_status)) {
01043                         END_PROFILE(SMBsearch);
01044                         return ERROR_NT(nt_status);
01045                 }
01046 
01047                 nt_status = check_name(conn, directory);
01048                 if (!NT_STATUS_IS_OK(nt_status)) {
01049                         END_PROFILE(SMBsearch);
01050                         return ERROR_NT(nt_status);
01051                 }
01052 
01053                 p = strrchr_m(directory,'/');
01054                 if (!p) {
01055                         pstrcpy(mask,directory);
01056                         pstrcpy(directory,".");
01057                 } else {
01058                         *p = 0;
01059                         pstrcpy(mask,p+1);
01060                 }
01061 
01062                 if (*directory == '\0') {
01063                         pstrcpy(directory,".");
01064                 }
01065                 memset((char *)status,'\0',21);
01066                 SCVAL(status,0,(dirtype & 0x1F));
01067         } else {
01068                 int status_dirtype;
01069 
01070                 memcpy(status,p,21);
01071                 status_dirtype = CVAL(status,0) & 0x1F;
01072                 if (status_dirtype != (dirtype & 0x1F)) {
01073                         dirtype = status_dirtype;
01074                 }
01075 
01076                 conn->dirptr = dptr_fetch(status+12,&dptr_num);      
01077                 if (!conn->dirptr) {
01078                         goto SearchEmpty;
01079                 }
01080                 string_set(&conn->dirpath,dptr_path(dptr_num));
01081                 pstrcpy(mask, dptr_wcard(dptr_num));
01082                 /*
01083                  * For a 'continue' search we have no string. So
01084                  * check from the initial saved string.
01085                  */
01086                 mask_contains_wcard = ms_has_wild(mask);
01087         }
01088 
01089         p = smb_buf(outbuf) + 3;
01090      
01091         if (status_len == 0) {
01092                 nt_status = dptr_create(conn,
01093                                         directory,
01094                                         True,
01095                                         expect_close,
01096                                         SVAL(inbuf,smb_pid),
01097                                         mask,
01098                                         mask_contains_wcard,
01099                                         dirtype,
01100                                         &conn->dirptr);
01101                 if (!NT_STATUS_IS_OK(nt_status)) {
01102                         return ERROR_NT(nt_status);
01103                 }
01104                 dptr_num = dptr_dnum(conn->dirptr);
01105         } else {
01106                 dirtype = dptr_attr(dptr_num);
01107         }
01108 
01109         DEBUG(4,("dptr_num is %d\n",dptr_num));
01110 
01111         if ((dirtype&0x1F) == aVOLID) {   
01112                 memcpy(p,status,21);
01113                 make_dir_struct(p,"???????????",volume_label(SNUM(conn)),
01114                                 0,aVOLID,0,!allow_long_path_components);
01115                 dptr_fill(p+12,dptr_num);
01116                 if (dptr_zero(p+12) && (status_len==0)) {
01117                         numentries = 1;
01118                 } else {
01119                         numentries = 0;
01120                 }
01121                 p += DIR_STRUCT_SIZE;
01122         } else {
01123                 unsigned int i;
01124                 maxentries = MIN(maxentries, ((BUFFER_SIZE - (p - outbuf))/DIR_STRUCT_SIZE));
01125 
01126                 DEBUG(8,("dirpath=<%s> dontdescend=<%s>\n",
01127                         conn->dirpath,lp_dontdescend(SNUM(conn))));
01128                 if (in_list(conn->dirpath, lp_dontdescend(SNUM(conn)),True)) {
01129                         check_descend = True;
01130                 }
01131 
01132                 for (i=numentries;(i<maxentries) && !finished;i++) {
01133                         finished = !get_dir_entry(conn,mask,dirtype,fname,&size,&mode,&date,check_descend);
01134                         if (!finished) {
01135                                 memcpy(p,status,21);
01136                                 make_dir_struct(p,mask,fname,size, mode,date,
01137                                                 !allow_long_path_components);
01138                                 if (!dptr_fill(p+12,dptr_num)) {
01139                                         break;
01140                                 }
01141                                 numentries++;
01142                                 p += DIR_STRUCT_SIZE;
01143                         }
01144                 }
01145         }
01146 
01147   SearchEmpty:
01148 
01149         /* If we were called as SMBffirst with smb_search_id == NULL
01150                 and no entries were found then return error and close dirptr 
01151                 (X/Open spec) */
01152 
01153         if (numentries == 0) {
01154                 dptr_close(&dptr_num);
01155         } else if(expect_close && status_len == 0) {
01156                 /* Close the dptr - we know it's gone */
01157                 dptr_close(&dptr_num);
01158         }
01159 
01160         /* If we were called as SMBfunique, then we can close the dirptr now ! */
01161         if(dptr_num >= 0 && CVAL(inbuf,smb_com) == SMBfunique) {
01162                 dptr_close(&dptr_num);
01163         }
01164 
01165         if ((numentries == 0) && !mask_contains_wcard) {
01166                 return ERROR_BOTH(STATUS_NO_MORE_FILES,ERRDOS,ERRnofiles);
01167         }
01168 
01169         SSVAL(outbuf,smb_vwv0,numentries);
01170         SSVAL(outbuf,smb_vwv1,3 + numentries * DIR_STRUCT_SIZE);
01171         SCVAL(smb_buf(outbuf),0,5);
01172         SSVAL(smb_buf(outbuf),1,numentries*DIR_STRUCT_SIZE);
01173 
01174         /* The replies here are never long name. */
01175         SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) & (~FLAGS2_IS_LONG_NAME));
01176         if (!allow_long_path_components) {
01177                 SSVAL(outbuf,smb_flg2,SVAL(outbuf, smb_flg2) & (~FLAGS2_LONG_PATH_COMPONENTS));
01178         }
01179 
01180         /* This SMB *always* returns ASCII names. Remove the unicode bit in flags2. */
01181         SSVAL(outbuf,smb_flg2, (SVAL(outbuf, smb_flg2) & (~FLAGS2_UNICODE_STRINGS)));
01182           
01183         outsize += DIR_STRUCT_SIZE*numentries;
01184         smb_setlen(outbuf,outsize - 4);
01185   
01186         if ((! *directory) && dptr_path(dptr_num))
01187                 slprintf(directory, sizeof(directory)-1, "(%s)",dptr_path(dptr_num));
01188 
01189         DEBUG( 4, ( "%s mask=%s path=%s dtype=%d nument=%u of %u\n",
01190                 smb_fn_name(CVAL(inbuf,smb_com)), 
01191                 mask, directory, dirtype, numentries, maxentries ) );
01192 
01193         END_PROFILE(SMBsearch);
01194         return(outsize);
01195 }
01196 
01197 /****************************************************************************
01198  Reply to a fclose (stop directory search).
01199 ****************************************************************************/
01200 
01201 int reply_fclose(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
01202 {
01203         int outsize = 0;
01204         int status_len;
01205         pstring path;
01206         char status[21];
01207         int dptr_num= -2;
01208         char *p;
01209         NTSTATUS err;
01210         BOOL path_contains_wcard = False;
01211 
01212         START_PROFILE(SMBfclose);
01213 
01214         if (lp_posix_pathnames()) {
01215                 END_PROFILE(SMBfclose);
01216                 return reply_unknown(inbuf, outbuf);
01217         }
01218 
01219         outsize = set_message(outbuf,1,0,True);
01220         p = smb_buf(inbuf) + 1;
01221         p += srvstr_get_path_wcard(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, &path_contains_wcard);
01222         if (!NT_STATUS_IS_OK(err)) {
01223                 END_PROFILE(SMBfclose);
01224                 return ERROR_NT(err);
01225         }
01226         p++;
01227         status_len = SVAL(p,0);
01228         p += 2;
01229 
01230         if (status_len == 0) {
01231                 END_PROFILE(SMBfclose);
01232                 return ERROR_DOS(ERRSRV,ERRsrverror);
01233         }
01234 
01235         memcpy(status,p,21);
01236 
01237         if(dptr_fetch(status+12,&dptr_num)) {
01238                 /*  Close the dptr - we know it's gone */
01239                 dptr_close(&dptr_num);
01240         }
01241 
01242         SSVAL(outbuf,smb_vwv0,0);
01243 
01244         DEBUG(3,("search close\n"));
01245 
01246         END_PROFILE(SMBfclose);
01247         return(outsize);
01248 }
01249 
01250 /****************************************************************************
01251  Reply to an open.
01252 ****************************************************************************/
01253 
01254 int reply_open(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
01255 {
01256         pstring fname;
01257         int outsize = 0;
01258         uint32 fattr=0;
01259         SMB_OFF_T size = 0;
01260         time_t mtime=0;
01261         int info;
01262         SMB_STRUCT_STAT sbuf;
01263         files_struct *fsp;
01264         int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
01265         int deny_mode;
01266         uint32 dos_attr = SVAL(inbuf,smb_vwv1);
01267         uint32 access_mask;
01268         uint32 share_mode;
01269         uint32 create_disposition;
01270         uint32 create_options = 0;
01271         NTSTATUS status;
01272         START_PROFILE(SMBopen);
01273  
01274         deny_mode = SVAL(inbuf,smb_vwv0);
01275 
01276         srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
01277         if (!NT_STATUS_IS_OK(status)) {
01278                 END_PROFILE(SMBopen);
01279                 return ERROR_NT(status);
01280         }
01281 
01282         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
01283         if (!NT_STATUS_IS_OK(status)) {
01284                 END_PROFILE(SMBopen);
01285                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
01286                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
01287                 }
01288                 return ERROR_NT(status);
01289         }
01290 
01291         status = unix_convert(conn, fname, False, NULL, &sbuf);
01292         if (!NT_STATUS_IS_OK(status)) {
01293                 END_PROFILE(SMBopen);
01294                 return ERROR_NT(status);
01295         }
01296     
01297         status = check_name(conn, fname);
01298         if (!NT_STATUS_IS_OK(status)) {
01299                 END_PROFILE(SMBopen);
01300                 return ERROR_NT(status);
01301         }
01302 
01303         if (!map_open_params_to_ntcreate(fname, deny_mode, OPENX_FILE_EXISTS_OPEN,
01304                         &access_mask, &share_mode, &create_disposition, &create_options)) {
01305                 END_PROFILE(SMBopen);
01306                 return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRbadaccess));
01307         }
01308 
01309         status = open_file_ntcreate(conn,fname,&sbuf,
01310                         access_mask,
01311                         share_mode,
01312                         create_disposition,
01313                         create_options,
01314                         dos_attr,
01315                         oplock_request,
01316                         &info, &fsp);
01317 
01318         if (!NT_STATUS_IS_OK(status)) {
01319                 END_PROFILE(SMBopen);
01320                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
01321                         /* We have re-scheduled this call. */
01322                         return -1;
01323                 }
01324                 return ERROR_OPEN(status);
01325         }
01326 
01327         size = sbuf.st_size;
01328         fattr = dos_mode(conn,fname,&sbuf);
01329         mtime = sbuf.st_mtime;
01330 
01331         if (fattr & aDIR) {
01332                 DEBUG(3,("attempt to open a directory %s\n",fname));
01333                 close_file(fsp,ERROR_CLOSE);
01334                 END_PROFILE(SMBopen);
01335                 return ERROR_DOS(ERRDOS,ERRnoaccess);
01336         }
01337   
01338         outsize = set_message(outbuf,7,0,True);
01339         SSVAL(outbuf,smb_vwv0,fsp->fnum);
01340         SSVAL(outbuf,smb_vwv1,fattr);
01341         if(lp_dos_filetime_resolution(SNUM(conn)) ) {
01342                 srv_put_dos_date3(outbuf,smb_vwv2,mtime & ~1);
01343         } else {
01344                 srv_put_dos_date3(outbuf,smb_vwv2,mtime);
01345         }
01346         SIVAL(outbuf,smb_vwv4,(uint32)size);
01347         SSVAL(outbuf,smb_vwv6,deny_mode);
01348 
01349         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
01350                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01351         }
01352     
01353         if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
01354                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01355         }
01356         END_PROFILE(SMBopen);
01357         return(outsize);
01358 }
01359 
01360 /****************************************************************************
01361  Reply to an open and X.
01362 ****************************************************************************/
01363 
01364 int reply_open_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
01365 {
01366         pstring fname;
01367         uint16 open_flags = SVAL(inbuf,smb_vwv2);
01368         int deny_mode = SVAL(inbuf,smb_vwv3);
01369         uint32 smb_attr = SVAL(inbuf,smb_vwv5);
01370         /* Breakout the oplock request bits so we can set the
01371                 reply bits separately. */
01372         int ex_oplock_request = EXTENDED_OPLOCK_REQUEST(inbuf);
01373         int core_oplock_request = CORE_OPLOCK_REQUEST(inbuf);
01374         int oplock_request = ex_oplock_request | core_oplock_request;
01375 #if 0
01376         int smb_sattr = SVAL(inbuf,smb_vwv4); 
01377         uint32 smb_time = make_unix_date3(inbuf+smb_vwv6);
01378 #endif
01379         int smb_ofun = SVAL(inbuf,smb_vwv8);
01380         uint32 fattr=0;
01381         int mtime=0;
01382         SMB_STRUCT_STAT sbuf;
01383         int smb_action = 0;
01384         files_struct *fsp;
01385         NTSTATUS status;
01386         SMB_BIG_UINT allocation_size = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv9);
01387         ssize_t retval = -1;
01388         uint32 access_mask;
01389         uint32 share_mode;
01390         uint32 create_disposition;
01391         uint32 create_options = 0;
01392 
01393         START_PROFILE(SMBopenX);
01394 
01395         /* If it's an IPC, pass off the pipe handler. */
01396         if (IS_IPC(conn)) {
01397                 if (lp_nt_pipe_support()) {
01398                         END_PROFILE(SMBopenX);
01399                         return reply_open_pipe_and_X(conn, inbuf,outbuf,length,bufsize);
01400                 } else {
01401                         END_PROFILE(SMBopenX);
01402                         return ERROR_DOS(ERRSRV,ERRaccess);
01403                 }
01404         }
01405 
01406         /* XXXX we need to handle passed times, sattr and flags */
01407         srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
01408         if (!NT_STATUS_IS_OK(status)) {
01409                 END_PROFILE(SMBopenX);
01410                 return ERROR_NT(status);
01411         }
01412 
01413         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
01414         if (!NT_STATUS_IS_OK(status)) {
01415                 END_PROFILE(SMBopenX);
01416                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
01417                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
01418                 }
01419                 return ERROR_NT(status);
01420         }
01421 
01422         status = unix_convert(conn, fname, False, NULL, &sbuf);
01423         if (!NT_STATUS_IS_OK(status)) {
01424                 END_PROFILE(SMBopenX);
01425                 return ERROR_NT(status);
01426         }
01427 
01428         status = check_name(conn, fname);
01429         if (!NT_STATUS_IS_OK(status)) {
01430                 END_PROFILE(SMBopenX);
01431                 return ERROR_NT(status);
01432         }
01433 
01434         if (!map_open_params_to_ntcreate(fname, deny_mode, smb_ofun,
01435                                 &access_mask,
01436                                 &share_mode,
01437                                 &create_disposition,
01438                                 &create_options)) {
01439                 END_PROFILE(SMBopenX);
01440                 return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRbadaccess));
01441         }
01442 
01443         status = open_file_ntcreate(conn,fname,&sbuf,
01444                         access_mask,
01445                         share_mode,
01446                         create_disposition,
01447                         create_options,
01448                         smb_attr,
01449                         oplock_request,
01450                         &smb_action, &fsp);
01451       
01452         if (!NT_STATUS_IS_OK(status)) {
01453                 END_PROFILE(SMBopenX);
01454                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
01455                         /* We have re-scheduled this call. */
01456                         return -1;
01457                 }
01458                 return ERROR_OPEN(status);
01459         }
01460 
01461         /* Setting the "size" field in vwv9 and vwv10 causes the file to be set to this size,
01462            if the file is truncated or created. */
01463         if (((smb_action == FILE_WAS_CREATED) || (smb_action == FILE_WAS_OVERWRITTEN)) && allocation_size) {
01464                 fsp->initial_allocation_size = smb_roundup(fsp->conn, allocation_size);
01465                 if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) {
01466                         close_file(fsp,ERROR_CLOSE);
01467                         END_PROFILE(SMBopenX);
01468                         return ERROR_NT(NT_STATUS_DISK_FULL);
01469                 }
01470                 retval = vfs_set_filelen(fsp, (SMB_OFF_T)allocation_size);
01471                 if (retval < 0) {
01472                         close_file(fsp,ERROR_CLOSE);
01473                         END_PROFILE(SMBopenX);
01474                         return ERROR_NT(NT_STATUS_DISK_FULL);
01475                 }
01476                 sbuf.st_size = get_allocation_size(conn,fsp,&sbuf);
01477         }
01478 
01479         fattr = dos_mode(conn,fname,&sbuf);
01480         mtime = sbuf.st_mtime;
01481         if (fattr & aDIR) {
01482                 close_file(fsp,ERROR_CLOSE);
01483                 END_PROFILE(SMBopenX);
01484                 return ERROR_DOS(ERRDOS,ERRnoaccess);
01485         }
01486 
01487         /* If the caller set the extended oplock request bit
01488                 and we granted one (by whatever means) - set the
01489                 correct bit for extended oplock reply.
01490         */
01491 
01492         if (ex_oplock_request && lp_fake_oplocks(SNUM(conn))) {
01493                 smb_action |= EXTENDED_OPLOCK_GRANTED;
01494         }
01495 
01496         if(ex_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
01497                 smb_action |= EXTENDED_OPLOCK_GRANTED;
01498         }
01499 
01500         /* If the caller set the core oplock request bit
01501                 and we granted one (by whatever means) - set the
01502                 correct bit for core oplock reply.
01503         */
01504 
01505         if (core_oplock_request && lp_fake_oplocks(SNUM(conn))) {
01506                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01507         }
01508 
01509         if(core_oplock_request && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
01510                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01511         }
01512 
01513         if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
01514                 set_message(outbuf,19,0,True);
01515         } else {
01516                 set_message(outbuf,15,0,True);
01517         }
01518         SSVAL(outbuf,smb_vwv2,fsp->fnum);
01519         SSVAL(outbuf,smb_vwv3,fattr);
01520         if(lp_dos_filetime_resolution(SNUM(conn)) ) {
01521                 srv_put_dos_date3(outbuf,smb_vwv4,mtime & ~1);
01522         } else {
01523                 srv_put_dos_date3(outbuf,smb_vwv4,mtime);
01524         }
01525         SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
01526         SSVAL(outbuf,smb_vwv8,GET_OPENX_MODE(deny_mode));
01527         SSVAL(outbuf,smb_vwv11,smb_action);
01528 
01529         if (open_flags & EXTENDED_RESPONSE_REQUIRED) {
01530                 SIVAL(outbuf, smb_vwv15, STD_RIGHT_ALL_ACCESS);
01531         }
01532 
01533         END_PROFILE(SMBopenX);
01534         return chain_reply(inbuf,outbuf,length,bufsize);
01535 }
01536 
01537 /****************************************************************************
01538  Reply to a SMBulogoffX.
01539  conn POINTER CAN BE NULL HERE !
01540 ****************************************************************************/
01541 
01542 int reply_ulogoffX(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
01543 {
01544         uint16 vuid = SVAL(inbuf,smb_uid);
01545         user_struct *vuser = get_valid_user_struct(vuid);
01546         START_PROFILE(SMBulogoffX);
01547 
01548         if(vuser == 0)
01549                 DEBUG(3,("ulogoff, vuser id %d does not map to user.\n", vuid));
01550 
01551         /* in user level security we are supposed to close any files
01552                 open by this user */
01553         if ((vuser != 0) && (lp_security() != SEC_SHARE))
01554                 file_close_user(vuid);
01555 
01556         invalidate_vuid(vuid);
01557 
01558         set_message(outbuf,2,0,True);
01559 
01560         DEBUG( 3, ( "ulogoffX vuid=%d\n", vuid ) );
01561 
01562         END_PROFILE(SMBulogoffX);
01563         return chain_reply(inbuf,outbuf,length,bufsize);
01564 }
01565 
01566 /****************************************************************************
01567  Reply to a mknew or a create.
01568 ****************************************************************************/
01569 
01570 int reply_mknew(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
01571 {
01572         pstring fname;
01573         int com;
01574         int outsize = 0;
01575         uint32 fattr = SVAL(inbuf,smb_vwv0);
01576         struct timespec ts[2];
01577         files_struct *fsp;
01578         int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
01579         SMB_STRUCT_STAT sbuf;
01580         NTSTATUS status;
01581         uint32 access_mask = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
01582         uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
01583         uint32 create_disposition;
01584         uint32 create_options = 0;
01585 
01586         START_PROFILE(SMBcreate);
01587  
01588         com = SVAL(inbuf,smb_com);
01589 
01590         ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(inbuf + smb_vwv1)); /* mtime. */
01591 
01592         srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
01593         if (!NT_STATUS_IS_OK(status)) {
01594                 END_PROFILE(SMBcreate);
01595                 return ERROR_NT(status);
01596         }
01597 
01598         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
01599         if (!NT_STATUS_IS_OK(status)) {
01600                 END_PROFILE(SMBcreate);
01601                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
01602                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
01603                 }
01604                 return ERROR_NT(status);
01605         }
01606 
01607         status = unix_convert(conn, fname, False, NULL, &sbuf);
01608         if (!NT_STATUS_IS_OK(status)) {
01609                 END_PROFILE(SMBcreate);
01610                 return ERROR_NT(status);
01611         }
01612 
01613         status = check_name(conn, fname);
01614         if (!NT_STATUS_IS_OK(status)) {
01615                 END_PROFILE(SMBcreate);
01616                 return ERROR_NT(status);
01617         }
01618 
01619         if (fattr & aVOLID) {
01620                 DEBUG(0,("Attempt to create file (%s) with volid set - please report this\n",fname));
01621         }
01622 
01623         if(com == SMBmknew) {
01624                 /* We should fail if file exists. */
01625                 create_disposition = FILE_CREATE;
01626         } else {
01627                 /* Create if file doesn't exist, truncate if it does. */
01628                 create_disposition = FILE_OVERWRITE_IF;
01629         }
01630 
01631         /* Open file using ntcreate. */
01632         status = open_file_ntcreate(conn,fname,&sbuf,
01633                                 access_mask,
01634                                 share_mode,
01635                                 create_disposition,
01636                                 create_options,
01637                                 fattr,
01638                                 oplock_request,
01639                                 NULL, &fsp);
01640   
01641         if (!NT_STATUS_IS_OK(status)) {
01642                 END_PROFILE(SMBcreate);
01643                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
01644                         /* We have re-scheduled this call. */
01645                         return -1;
01646                 }
01647                 return ERROR_OPEN(status);
01648         }
01649  
01650         ts[0] = get_atimespec(&sbuf); /* atime. */
01651         file_ntimes(conn, fname, ts);
01652 
01653         outsize = set_message(outbuf,1,0,True);
01654         SSVAL(outbuf,smb_vwv0,fsp->fnum);
01655 
01656         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
01657                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01658         }
01659  
01660         if(EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
01661                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01662         }
01663  
01664         DEBUG( 2, ( "reply_mknew: file %s\n", fname ) );
01665         DEBUG( 3, ( "reply_mknew %s fd=%d dmode=0x%x\n", fname, fsp->fh->fd, (unsigned int)fattr ) );
01666 
01667         END_PROFILE(SMBcreate);
01668         return(outsize);
01669 }
01670 
01671 /****************************************************************************
01672  Reply to a create temporary file.
01673 ****************************************************************************/
01674 
01675 int reply_ctemp(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
01676 {
01677         pstring fname;
01678         int outsize = 0;
01679         uint32 fattr = SVAL(inbuf,smb_vwv0);
01680         files_struct *fsp;
01681         int oplock_request = CORE_OPLOCK_REQUEST(inbuf);
01682         int tmpfd;
01683         SMB_STRUCT_STAT sbuf;
01684         char *p, *s;
01685         NTSTATUS status;
01686         unsigned int namelen;
01687 
01688         START_PROFILE(SMBctemp);
01689 
01690         srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
01691         if (!NT_STATUS_IS_OK(status)) {
01692                 END_PROFILE(SMBctemp);
01693                 return ERROR_NT(status);
01694         }
01695         if (*fname) {
01696                 pstrcat(fname,"/TMXXXXXX");
01697         } else {
01698                 pstrcat(fname,"TMXXXXXX");
01699         }
01700 
01701         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, fname);
01702         if (!NT_STATUS_IS_OK(status)) {
01703                 END_PROFILE(SMBctemp);
01704                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
01705                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
01706                 }
01707                 return ERROR_NT(status);
01708         }
01709 
01710         status = unix_convert(conn, fname, False, NULL, &sbuf);
01711         if (!NT_STATUS_IS_OK(status)) {
01712                 END_PROFILE(SMBctemp);
01713                 return ERROR_NT(status);
01714         }
01715 
01716         status = check_name(conn, fname);
01717         if (!NT_STATUS_IS_OK(status)) {
01718                 END_PROFILE(SMBctemp);
01719                 return ERROR_NT(status);
01720         }
01721   
01722         tmpfd = smb_mkstemp(fname);
01723         if (tmpfd == -1) {
01724                 END_PROFILE(SMBctemp);
01725                 return(UNIXERROR(ERRDOS,ERRnoaccess));
01726         }
01727 
01728         SMB_VFS_STAT(conn,fname,&sbuf);
01729 
01730         /* We should fail if file does not exist. */
01731         status = open_file_ntcreate(conn,fname,&sbuf,
01732                                 FILE_GENERIC_READ | FILE_GENERIC_WRITE,
01733                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
01734                                 FILE_OPEN,
01735                                 0,
01736                                 fattr,
01737                                 oplock_request,
01738                                 NULL, &fsp);
01739 
01740         /* close fd from smb_mkstemp() */
01741         close(tmpfd);
01742 
01743         if (!NT_STATUS_IS_OK(status)) {
01744                 END_PROFILE(SMBctemp);
01745                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
01746                         /* We have re-scheduled this call. */
01747                         return -1;
01748                 }
01749                 return ERROR_OPEN(status);
01750         }
01751 
01752         outsize = set_message(outbuf,1,0,True);
01753         SSVAL(outbuf,smb_vwv0,fsp->fnum);
01754 
01755         /* the returned filename is relative to the directory */
01756         s = strrchr_m(fname, '/');
01757         if (!s) {
01758                 s = fname;
01759         } else {
01760                 s++;
01761         }
01762 
01763         p = smb_buf(outbuf);
01764 #if 0
01765         /* Tested vs W2K3 - this doesn't seem to be here - null terminated filename is the only
01766            thing in the byte section. JRA */
01767         SSVALS(p, 0, -1); /* what is this? not in spec */
01768 #endif
01769         namelen = srvstr_push(outbuf, p, s, BUFFER_SIZE - (p - outbuf), STR_ASCII|STR_TERMINATE);
01770         p += namelen;
01771         outsize = set_message_end(outbuf, p);
01772 
01773         if (oplock_request && lp_fake_oplocks(SNUM(conn))) {
01774                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01775         }
01776   
01777         if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
01778                 SCVAL(outbuf,smb_flg,CVAL(outbuf,smb_flg)|CORE_OPLOCK_GRANTED);
01779         }
01780 
01781         DEBUG( 2, ( "reply_ctemp: created temp file %s\n", fname ) );
01782         DEBUG( 3, ( "reply_ctemp %s fd=%d umode=0%o\n", fname, fsp->fh->fd,
01783                         (unsigned int)sbuf.st_mode ) );
01784 
01785         END_PROFILE(SMBctemp);
01786         return(outsize);
01787 }
01788 
01789 /*******************************************************************
01790  Check if a user is allowed to rename a file.
01791 ********************************************************************/
01792 
01793 static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open)
01794 {
01795         files_struct *fsp;
01796         uint32 fmode;
01797         NTSTATUS status;
01798 
01799         if (!CAN_WRITE(conn)) {
01800                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
01801         }
01802 
01803         fmode = dos_mode(conn,fname,pst);
01804         if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
01805                 return NT_STATUS_NO_SUCH_FILE;
01806         }
01807 
01808         if (S_ISDIR(pst->st_mode)) {
01809                 return NT_STATUS_OK;
01810         }
01811 
01812         status = open_file_ntcreate(conn, fname, pst,
01813                                 DELETE_ACCESS,
01814                                 /* If we're checking our fsp don't deny for delete. */
01815                                 self_open ?
01816                                         FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE :
01817                                         FILE_SHARE_READ|FILE_SHARE_WRITE,
01818                                 FILE_OPEN,
01819                                 0,
01820                                 FILE_ATTRIBUTE_NORMAL,
01821                                 0,
01822                                 NULL, &fsp);
01823 
01824         if (!NT_STATUS_IS_OK(status)) {
01825                 return status;
01826         }
01827         close_file(fsp,NORMAL_CLOSE);
01828         return NT_STATUS_OK;
01829 }
01830 
01831 /*******************************************************************
01832  Check if a user is allowed to delete a file.
01833 ********************************************************************/
01834 
01835 static NTSTATUS can_delete(connection_struct *conn, char *fname,
01836                            uint32 dirtype, BOOL can_defer)
01837 {
01838         SMB_STRUCT_STAT sbuf;
01839         uint32 fattr;
01840         files_struct *fsp;
01841         uint32 dirtype_orig = dirtype;
01842         NTSTATUS status;
01843 
01844         DEBUG(10,("can_delete: %s, dirtype = %d\n", fname, dirtype ));
01845 
01846         if (!CAN_WRITE(conn)) {
01847                 return NT_STATUS_MEDIA_WRITE_PROTECTED;
01848         }
01849 
01850         if (SMB_VFS_LSTAT(conn,fname,&sbuf) != 0) {
01851                 return map_nt_error_from_unix(errno);
01852         }
01853 
01854         fattr = dos_mode(conn,fname,&sbuf);
01855 
01856         if (dirtype & FILE_ATTRIBUTE_NORMAL) {
01857                 dirtype = aDIR|aARCH|aRONLY;
01858         }
01859 
01860         dirtype &= (aDIR|aARCH|aRONLY|aHIDDEN|aSYSTEM);
01861         if (!dirtype) {
01862                 return NT_STATUS_NO_SUCH_FILE;
01863         }
01864 
01865         if (!dir_check_ftype(conn, fattr, dirtype)) {
01866                 if (fattr & aDIR) {
01867                         return NT_STATUS_FILE_IS_A_DIRECTORY;
01868                 }
01869                 return NT_STATUS_NO_SUCH_FILE;
01870         }
01871 
01872         if (dirtype_orig & 0x8000) {
01873                 /* These will never be set for POSIX. */
01874                 return NT_STATUS_NO_SUCH_FILE;
01875         }
01876 
01877 #if 0
01878         if ((fattr & dirtype) & FILE_ATTRIBUTE_DIRECTORY) {
01879                 return NT_STATUS_FILE_IS_A_DIRECTORY;
01880         }
01881 
01882         if ((fattr & ~dirtype) & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM)) {
01883                 return NT_STATUS_NO_SUCH_FILE;
01884         }
01885 
01886         if (dirtype & 0xFF00) {
01887                 /* These will never be set for POSIX. */
01888                 return NT_STATUS_NO_SUCH_FILE;
01889         }
01890 
01891         dirtype &= 0xFF;
01892         if (!dirtype) {
01893                 return NT_STATUS_NO_SUCH_FILE;
01894         }
01895 
01896         /* Can't delete a directory. */
01897         if (fattr & aDIR) {
01898                 return NT_STATUS_FILE_IS_A_DIRECTORY;
01899         }
01900 #endif
01901 
01902 #if 0 /* JRATEST */
01903         else if (dirtype & aDIR) /* Asked for a directory and it isn't. */
01904                 return NT_STATUS_OBJECT_NAME_INVALID;
01905 #endif /* JRATEST */
01906 
01907         /* Fix for bug #3035 from SATOH Fumiyasu <fumiyas@miraclelinux.com>
01908 
01909           On a Windows share, a file with read-only dosmode can be opened with
01910           DELETE_ACCESS. But on a Samba share (delete readonly = no), it
01911           fails with NT_STATUS_CANNOT_DELETE error.
01912 
01913           This semantic causes a problem that a user can not
01914           rename a file with read-only dosmode on a Samba share
01915           from a Windows command prompt (i.e. cmd.exe, but can rename
01916           from Windows Explorer).
01917         */
01918 
01919         if (!lp_delete_readonly(SNUM(conn))) {
01920                 if (fattr & aRONLY) {
01921                         return NT_STATUS_CANNOT_DELETE;
01922                 }
01923         }
01924 
01925         /* On open checks the open itself will check the share mode, so
01926            don't do it here as we'll get it wrong. */
01927 
01928         status = open_file_ntcreate(conn, fname, &sbuf,
01929                                     DELETE_ACCESS,
01930                                     FILE_SHARE_NONE,
01931                                     FILE_OPEN,
01932                                     0,
01933                                     FILE_ATTRIBUTE_NORMAL,
01934                                     can_defer ? 0 : INTERNAL_OPEN_ONLY,
01935                                     NULL, &fsp);
01936 
01937         if (NT_STATUS_IS_OK(status)) {
01938                 close_file(fsp,NORMAL_CLOSE);
01939         }
01940         return status;
01941 }
01942 
01943 /****************************************************************************
01944  The guts of the unlink command, split out so it may be called by the NT SMB
01945  code.
01946 ****************************************************************************/
01947 
01948 NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
01949                           char *name, BOOL has_wild, BOOL can_defer)
01950 {
01951         pstring directory;
01952         pstring mask;
01953         char *p;
01954         int count=0;
01955         NTSTATUS status = NT_STATUS_OK;
01956         SMB_STRUCT_STAT sbuf;
01957         
01958         *directory = *mask = 0;
01959         
01960         status = unix_convert(conn, name, has_wild, NULL, &sbuf);
01961         if (!NT_STATUS_IS_OK(status)) {
01962                 return status;
01963         }
01964         
01965         p = strrchr_m(name,'/');
01966         if (!p) {
01967                 pstrcpy(directory,".");
01968                 pstrcpy(mask,name);
01969         } else {
01970                 *p = 0;
01971                 pstrcpy(directory,name);
01972                 pstrcpy(mask,p+1);
01973         }
01974         
01975         /*
01976          * We should only check the mangled cache
01977          * here if unix_convert failed. This means
01978          * that the path in 'mask' doesn't exist
01979          * on the file system and so we need to look
01980          * for a possible mangle. This patch from
01981          * Tine Smukavec <valentin.smukavec@hermes.si>.
01982          */
01983         
01984         if (!VALID_STAT(sbuf) && mangle_is_mangled(mask,conn->params))
01985                 mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
01986         
01987         if (!has_wild) {
01988                 pstrcat(directory,"/");
01989                 pstrcat(directory,mask);
01990                 if (dirtype == 0) {
01991                         dirtype = FILE_ATTRIBUTE_NORMAL;
01992                 }
01993 
01994                 status = check_name(conn, directory);
01995                 if (!NT_STATUS_IS_OK(status)) {
01996                         return status;
01997                 }
01998 
01999                 status = can_delete(conn,directory,dirtype,can_defer);
02000                 if (!NT_STATUS_IS_OK(status)) {
02001                         return status;
02002                 }
02003 
02004                 if (SMB_VFS_UNLINK(conn,directory) == 0) {
02005                         count++;
02006                         notify_fname(conn, NOTIFY_ACTION_REMOVED,
02007                                      FILE_NOTIFY_CHANGE_FILE_NAME,
02008                                      directory);
02009                 }
02010         } else {
02011                 struct smb_Dir *dir_hnd = NULL;
02012                 long offset = 0;
02013                 const char *dname;
02014                 
02015                 if ((dirtype & SAMBA_ATTRIBUTES_MASK) == aDIR) {
02016                         return NT_STATUS_OBJECT_NAME_INVALID;
02017                 }
02018 
02019                 if (strequal(mask,"????????.???")) {
02020                         pstrcpy(mask,"*");
02021                 }
02022 
02023                 status = check_name(conn, directory);
02024                 if (!NT_STATUS_IS_OK(status)) {
02025                         return status;
02026                 }
02027 
02028                 dir_hnd = OpenDir(conn, directory, mask, dirtype);
02029                 if (dir_hnd == NULL) {
02030                         return map_nt_error_from_unix(errno);
02031                 }
02032                 
02033                 /* XXXX the CIFS spec says that if bit0 of the flags2 field is set then
02034                    the pattern matches against the long name, otherwise the short name 
02035                    We don't implement this yet XXXX
02036                 */
02037                 
02038                 status = NT_STATUS_NO_SUCH_FILE;
02039 
02040                 while ((dname = ReadDirName(dir_hnd, &offset))) {
02041                         SMB_STRUCT_STAT st;
02042                         pstring fname;
02043                         pstrcpy(fname,dname);
02044 
02045                         if (!is_visible_file(conn, directory, dname, &st, True)) {
02046                                 continue;
02047                         }
02048 
02049                         /* Quick check for "." and ".." */
02050                         if (fname[0] == '.') {
02051                                 if (!fname[1] || (fname[1] == '.' && !fname[2])) {
02052                                         continue;
02053                                 }
02054                         }
02055 
02056                         if(!mask_match(fname, mask, conn->case_sensitive)) {
02057                                 continue;
02058                         }
02059                                 
02060                         slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
02061 
02062                         status = check_name(conn, fname);
02063                         if (!NT_STATUS_IS_OK(status)) {
02064                                 CloseDir(dir_hnd);
02065                                 return status;
02066                         }
02067 
02068                         status = can_delete(conn, fname, dirtype, can_defer);
02069                         if (!NT_STATUS_IS_OK(status)) {
02070                                 continue;
02071                         }
02072                         if (SMB_VFS_UNLINK(conn,fname) == 0) {
02073                                 count++;
02074                                 DEBUG(3,("unlink_internals: successful unlink "
02075                                          "[%s]\n",fname));
02076                                 notify_fname(conn, NOTIFY_ACTION_REMOVED,
02077                                              FILE_NOTIFY_CHANGE_FILE_NAME,
02078                                              fname);
02079                         }
02080                                 
02081                 }
02082                 CloseDir(dir_hnd);
02083         }
02084         
02085         if (count == 0 && NT_STATUS_IS_OK(status)) {
02086                 status = map_nt_error_from_unix(errno);
02087         }
02088 
02089         return status;
02090 }
02091 
02092 /****************************************************************************
02093  Reply to a unlink
02094 ****************************************************************************/
02095 
02096 int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
02097                  int dum_buffsize)
02098 {
02099         int outsize = 0;
02100         pstring name;
02101         uint32 dirtype;
02102         NTSTATUS status;
02103         BOOL path_contains_wcard = False;
02104 
02105         START_PROFILE(SMBunlink);
02106 
02107         dirtype = SVAL(inbuf,smb_vwv0);
02108         
02109         srvstr_get_path_wcard(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard);
02110         if (!NT_STATUS_IS_OK(status)) {
02111                 END_PROFILE(SMBunlink);
02112                 return ERROR_NT(status);
02113         }
02114 
02115         status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &path_contains_wcard);
02116         if (!NT_STATUS_IS_OK(status)) {
02117                 END_PROFILE(SMBunlink);
02118                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
02119                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
02120                 }
02121                 return ERROR_NT(status);
02122         }
02123         
02124         DEBUG(3,("reply_unlink : %s\n",name));
02125         
02126         status = unlink_internals(conn, dirtype, name, path_contains_wcard,
02127                                   True);
02128         if (!NT_STATUS_IS_OK(status)) {
02129                 END_PROFILE(SMBunlink);
02130                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
02131                         /* We have re-scheduled this call. */
02132                         return -1;
02133                 }
02134                 return ERROR_NT(status);
02135         }
02136 
02137         outsize = set_message(outbuf,0,0,False);
02138   
02139         END_PROFILE(SMBunlink);
02140         return outsize;
02141 }
02142 
02143 /****************************************************************************
02144  Fail for readbraw.
02145 ****************************************************************************/
02146 
02147 static void fail_readraw(void)
02148 {
02149         pstring errstr;
02150         slprintf(errstr, sizeof(errstr)-1, "FAIL ! reply_readbraw: socket write fail (%s)",
02151                 strerror(errno) );
02152         exit_server_cleanly(errstr);
02153 }
02154 
02155 #if defined(WITH_SENDFILE)
02156 /****************************************************************************
02157  Fake (read/write) sendfile. Returns -1 on read or write fail.
02158 ****************************************************************************/
02159 
02160 static ssize_t fake_sendfile(files_struct *fsp, SMB_OFF_T startpos, size_t nread, char *buf, int bufsize)
02161 {
02162         ssize_t ret=0;
02163 
02164         /* Paranioa check... */
02165         if (nread > bufsize) {
02166                 fail_readraw();
02167         }
02168 
02169         if (nread > 0) {
02170                 ret = read_file(fsp,buf,startpos,nread);
02171                 if (ret == -1) {
02172                         return -1;
02173                 }
02174         }
02175 
02176         /* If we had a short read, fill with zeros. */
02177         if (ret < nread) {
02178                 memset(buf, '\0', nread - ret);
02179         }
02180 
02181         if (write_data(smbd_server_fd(),buf,nread) != nread) {
02182                 return -1;
02183         }       
02184 
02185         return (ssize_t)nread;
02186 }
02187 #endif
02188 
02189 /****************************************************************************
02190  Use sendfile in readbraw.
02191 ****************************************************************************/
02192 
02193 void send_file_readbraw(connection_struct *conn, files_struct *fsp, SMB_OFF_T startpos, size_t nread,
02194                 ssize_t mincount, char *outbuf, int out_buffsize)
02195 {
02196         ssize_t ret=0;
02197 
02198 #if defined(WITH_SENDFILE)
02199         /*
02200          * We can only use sendfile on a non-chained packet 
02201          * but we can use on a non-oplocked file. tridge proved this
02202          * on a train in Germany :-). JRA.
02203          * reply_readbraw has already checked the length.
02204          */
02205 
02206         if ( (chain_size == 0) && (nread > 0) &&
02207             (fsp->wcp == NULL) && lp_use_sendfile(SNUM(conn)) ) {
02208                 DATA_BLOB header;
02209 
02210                 _smb_setlen(outbuf,nread);
02211                 header.data = (uint8 *)outbuf;
02212                 header.length = 4;
02213                 header.free = NULL;
02214 
02215                 if ( SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, nread) == -1) {
02216                         /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
02217                         if (errno == ENOSYS) {
02218                                 goto normal_readbraw;
02219                         }
02220 
02221                         /*
02222                          * Special hack for broken Linux with no working sendfile. If we
02223                          * return EINTR we sent the header but not the rest of the data.
02224                          * Fake this up by doing read/write calls.
02225                          */
02226                         if (errno == EINTR) {
02227                                 /* Ensure we don't do this again. */
02228                                 set_use_sendfile(SNUM(conn), False);
02229                                 DEBUG(0,("send_file_readbraw: sendfile not available. Faking..\n"));
02230 
02231                                 if (fake_sendfile(fsp, startpos, nread, outbuf + 4, out_buffsize - 4) == -1) {
02232                                         DEBUG(0,("send_file_readbraw: fake_sendfile failed for file %s (%s).\n",
02233                                                 fsp->fsp_name, strerror(errno) ));
02234                                         exit_server_cleanly("send_file_readbraw fake_sendfile failed");
02235                                 }
02236                                 return;
02237                         }
02238 
02239                         DEBUG(0,("send_file_readbraw: sendfile failed for file %s (%s). Terminating\n",
02240                                 fsp->fsp_name, strerror(errno) ));
02241                         exit_server_cleanly("send_file_readbraw sendfile failed");
02242                 }
02243 
02244                 return;
02245         }
02246 
02247   normal_readbraw:
02248 
02249 #endif
02250 
02251         if (nread > 0) {
02252                 ret = read_file(fsp,outbuf+4,startpos,nread);
02253 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
02254                 if (ret < mincount)
02255                         ret = 0;
02256 #else
02257                 if (ret < nread)
02258                         ret = 0;
02259 #endif
02260         }
02261 
02262         _smb_setlen(outbuf,ret);
02263         if (write_data(smbd_server_fd(),outbuf,4+ret) != 4+ret)
02264                 fail_readraw();
02265 }
02266 
02267 /****************************************************************************
02268  Reply to a readbraw (core+ protocol).
02269 ****************************************************************************/
02270 
02271 int reply_readbraw(connection_struct *conn, char *inbuf, char *outbuf, int dum_size, int out_buffsize)
02272 {
02273         ssize_t maxcount,mincount;
02274         size_t nread = 0;
02275         SMB_OFF_T startpos;
02276         char *header = outbuf;
02277         files_struct *fsp;
02278         START_PROFILE(SMBreadbraw);
02279 
02280         if (srv_is_signing_active()) {
02281                 exit_server_cleanly("reply_readbraw: SMB signing is active - raw reads/writes are disallowed.");
02282         }
02283 
02284         /*
02285          * Special check if an oplock break has been issued
02286          * and the readraw request croses on the wire, we must
02287          * return a zero length response here.
02288          */
02289 
02290         fsp = file_fsp(inbuf,smb_vwv0);
02291 
02292         if (!FNUM_OK(fsp,conn) || !fsp->can_read) {
02293                 /*
02294                  * fsp could be NULL here so use the value from the packet. JRA.
02295                  */
02296                 DEBUG(3,("fnum %d not open in readbraw - cache prime?\n",(int)SVAL(inbuf,smb_vwv0)));
02297                 _smb_setlen(header,0);
02298                 if (write_data(smbd_server_fd(),header,4) != 4)
02299                         fail_readraw();
02300                 END_PROFILE(SMBreadbraw);
02301                 return(-1);
02302         }
02303 
02304         CHECK_FSP(fsp,conn);
02305 
02306         flush_write_cache(fsp, READRAW_FLUSH);
02307 
02308         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
02309         if(CVAL(inbuf,smb_wct) == 10) {
02310                 /*
02311                  * This is a large offset (64 bit) read.
02312                  */
02313 #ifdef LARGE_SMB_OFF_T
02314 
02315                 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv8)) << 32);
02316 
02317 #else /* !LARGE_SMB_OFF_T */
02318 
02319                 /*
02320                  * Ensure we haven't been sent a >32 bit offset.
02321                  */
02322 
02323                 if(IVAL(inbuf,smb_vwv8) != 0) {
02324                         DEBUG(0,("readbraw - large offset (%x << 32) used and we don't support \
02325 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv8) ));
02326                         _smb_setlen(header,0);
02327                         if (write_data(smbd_server_fd(),header,4) != 4)
02328                                 fail_readraw();
02329                         END_PROFILE(SMBreadbraw);
02330                         return(-1);
02331                 }
02332 
02333 #endif /* LARGE_SMB_OFF_T */
02334 
02335                 if(startpos < 0) {
02336                         DEBUG(0,("readbraw - negative 64 bit readraw offset (%.0f) !\n", (double)startpos ));
02337                         _smb_setlen(header,0);
02338                         if (write_data(smbd_server_fd(),header,4) != 4)
02339                                 fail_readraw();
02340                         END_PROFILE(SMBreadbraw);
02341                         return(-1);
02342                 }      
02343         }
02344         maxcount = (SVAL(inbuf,smb_vwv3) & 0xFFFF);
02345         mincount = (SVAL(inbuf,smb_vwv4) & 0xFFFF);
02346 
02347         /* ensure we don't overrun the packet size */
02348         maxcount = MIN(65535,maxcount);
02349 
02350         if (!is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
02351                 SMB_STRUCT_STAT st;
02352                 SMB_OFF_T size = 0;
02353   
02354                 if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) {
02355                         size = st.st_size;
02356                 }
02357 
02358                 if (startpos >= size) {
02359                         nread = 0;
02360                 } else {
02361                         nread = MIN(maxcount,(size - startpos));          
02362                 }
02363         }
02364 
02365 #if 0 /* mincount appears to be ignored in a W2K server. JRA. */
02366         if (nread < mincount)
02367                 nread = 0;
02368 #endif
02369   
02370         DEBUG( 3, ( "readbraw fnum=%d start=%.0f max=%lu min=%lu nread=%lu\n", fsp->fnum, (double)startpos,
02371                                 (unsigned long)maxcount, (unsigned long)mincount, (unsigned long)nread ) );
02372   
02373         send_file_readbraw(conn, fsp, startpos, nread, mincount, outbuf, out_buffsize);
02374 
02375         DEBUG(5,("readbraw finished\n"));
02376         END_PROFILE(SMBreadbraw);
02377         return -1;
02378 }
02379 
02380 #undef DBGC_CLASS
02381 #define DBGC_CLASS DBGC_LOCKING
02382 
02383 /****************************************************************************
02384  Reply to a lockread (core+ protocol).
02385 ****************************************************************************/
02386 
02387 int reply_lockread(connection_struct *conn, char *inbuf,char *outbuf, int length, int dum_buffsiz)
02388 {
02389         ssize_t nread = -1;
02390         char *data;
02391         int outsize = 0;
02392         SMB_OFF_T startpos;
02393         size_t numtoread;
02394         NTSTATUS status;
02395         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
02396         struct byte_range_lock *br_lck = NULL;
02397         START_PROFILE(SMBlockread);
02398 
02399         CHECK_FSP(fsp,conn);
02400         if (!CHECK_READ(fsp,inbuf)) {
02401                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
02402         }
02403 
02404         release_level_2_oplocks_on_change(fsp);
02405 
02406         numtoread = SVAL(inbuf,smb_vwv1);
02407         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
02408   
02409         outsize = set_message(outbuf,5,3,True);
02410         numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
02411         data = smb_buf(outbuf) + 3;
02412         
02413         /*
02414          * NB. Discovered by Menny Hamburger at Mainsoft. This is a core+
02415          * protocol request that predates the read/write lock concept. 
02416          * Thus instead of asking for a read lock here we need to ask
02417          * for a write lock. JRA.
02418          * Note that the requested lock size is unaffected by max_recv.
02419          */
02420         
02421         br_lck = do_lock(fsp,
02422                         (uint32)SVAL(inbuf,smb_pid), 
02423                         (SMB_BIG_UINT)numtoread,
02424                         (SMB_BIG_UINT)startpos,
02425                         WRITE_LOCK,
02426                         WINDOWS_LOCK,
02427                         False, /* Non-blocking lock. */
02428                         &status,
02429                         NULL);
02430         TALLOC_FREE(br_lck);
02431 
02432         if (NT_STATUS_V(status)) {
02433                 END_PROFILE(SMBlockread);
02434                 return ERROR_NT(status);
02435         }
02436 
02437         /*
02438          * However the requested READ size IS affected by max_recv. Insanity.... JRA.
02439          */
02440 
02441         if (numtoread > max_recv) {
02442                 DEBUG(0,("reply_lockread: requested read size (%u) is greater than maximum allowed (%u). \
02443 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
02444                         (unsigned int)numtoread, (unsigned int)max_recv ));
02445                 numtoread = MIN(numtoread,max_recv);
02446         }
02447         nread = read_file(fsp,data,startpos,numtoread);
02448 
02449         if (nread < 0) {
02450                 END_PROFILE(SMBlockread);
02451                 return(UNIXERROR(ERRDOS,ERRnoaccess));
02452         }
02453         
02454         outsize += nread;
02455         SSVAL(outbuf,smb_vwv0,nread);
02456         SSVAL(outbuf,smb_vwv5,nread+3);
02457         SSVAL(smb_buf(outbuf),1,nread);
02458         
02459         DEBUG(3,("lockread fnum=%d num=%d nread=%d\n",
02460                  fsp->fnum, (int)numtoread, (int)nread));
02461 
02462         END_PROFILE(SMBlockread);
02463         return(outsize);
02464 }
02465 
02466 #undef DBGC_CLASS
02467 #define DBGC_CLASS DBGC_ALL
02468 
02469 /****************************************************************************
02470  Reply to a read.
02471 ****************************************************************************/
02472 
02473 int reply_read(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
02474 {
02475         size_t numtoread;
02476         ssize_t nread = 0;
02477         char *data;
02478         SMB_OFF_T startpos;
02479         int outsize = 0;
02480         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
02481         START_PROFILE(SMBread);
02482 
02483         CHECK_FSP(fsp,conn);
02484         if (!CHECK_READ(fsp,inbuf)) {
02485                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
02486         }
02487 
02488         numtoread = SVAL(inbuf,smb_vwv1);
02489         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
02490 
02491         outsize = set_message(outbuf,5,3,True);
02492         numtoread = MIN(BUFFER_SIZE-outsize,numtoread);
02493         /*
02494          * The requested read size cannot be greater than max_recv. JRA.
02495          */
02496         if (numtoread > max_recv) {
02497                 DEBUG(0,("reply_read: requested read size (%u) is greater than maximum allowed (%u). \
02498 Returning short read of maximum allowed for compatibility with Windows 2000.\n",
02499                         (unsigned int)numtoread, (unsigned int)max_recv ));
02500                 numtoread = MIN(numtoread,max_recv);
02501         }
02502 
02503         data = smb_buf(outbuf) + 3;
02504   
02505         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtoread,(SMB_BIG_UINT)startpos, READ_LOCK)) {
02506                 END_PROFILE(SMBread);
02507                 return ERROR_DOS(ERRDOS,ERRlock);
02508         }
02509 
02510         if (numtoread > 0)
02511                 nread = read_file(fsp,data,startpos,numtoread);
02512 
02513         if (nread < 0) {
02514                 END_PROFILE(SMBread);
02515                 return(UNIXERROR(ERRDOS,ERRnoaccess));
02516         }
02517   
02518         outsize += nread;
02519         SSVAL(outbuf,smb_vwv0,nread);
02520         SSVAL(outbuf,smb_vwv5,nread+3);
02521         SCVAL(smb_buf(outbuf),0,1);
02522         SSVAL(smb_buf(outbuf),1,nread);
02523   
02524         DEBUG( 3, ( "read fnum=%d num=%d nread=%d\n",
02525                 fsp->fnum, (int)numtoread, (int)nread ) );
02526 
02527         END_PROFILE(SMBread);
02528         return(outsize);
02529 }
02530 
02531 /****************************************************************************
02532  Reply to a read and X - possibly using sendfile.
02533 ****************************************************************************/
02534 
02535 int send_file_readX(connection_struct *conn, char *inbuf,char *outbuf,int length, int len_outbuf,
02536                 files_struct *fsp, SMB_OFF_T startpos, size_t smb_maxcnt)
02537 {
02538         int outsize = 0;
02539         ssize_t nread = -1;
02540         char *data = smb_buf(outbuf);
02541 
02542 #if defined(WITH_SENDFILE)
02543         /*
02544          * We can only use sendfile on a non-chained packet 
02545          * but we can use on a non-oplocked file. tridge proved this
02546          * on a train in Germany :-). JRA.
02547          */
02548 
02549         if ((chain_size == 0) && (CVAL(inbuf,smb_vwv0) == 0xFF) &&
02550             lp_use_sendfile(SNUM(conn)) && (fsp->wcp == NULL) ) {
02551                 SMB_STRUCT_STAT sbuf;
02552                 DATA_BLOB header;
02553 
02554                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1)
02555                         return(UNIXERROR(ERRDOS,ERRnoaccess));
02556 
02557                 if (startpos > sbuf.st_size)
02558                         goto normal_read;
02559 
02560                 if (smb_maxcnt > (sbuf.st_size - startpos))
02561                         smb_maxcnt = (sbuf.st_size - startpos);
02562 
02563                 if (smb_maxcnt == 0)
02564                         goto normal_read;
02565 
02566                 /* 
02567                  * Set up the packet header before send. We
02568                  * assume here the sendfile will work (get the
02569                  * correct amount of data).
02570                  */
02571 
02572                 SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
02573                 SSVAL(outbuf,smb_vwv5,smb_maxcnt);
02574                 SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
02575                 SSVAL(outbuf,smb_vwv7,((smb_maxcnt >> 16) & 1));
02576                 SSVAL(smb_buf(outbuf),-2,smb_maxcnt);
02577                 SCVAL(outbuf,smb_vwv0,0xFF);
02578                 set_message(outbuf,12,smb_maxcnt,False);
02579                 header.data = (uint8 *)outbuf;
02580                 header.length = data - outbuf;
02581                 header.free = NULL;
02582 
02583                 if ((nread = SMB_VFS_SENDFILE( smbd_server_fd(), fsp, fsp->fh->fd, &header, startpos, smb_maxcnt)) == -1) {
02584                         /* Returning ENOSYS means no data at all was sent. Do this as a normal read. */
02585                         if (errno == ENOSYS) {
02586                                 goto normal_read;
02587                         }
02588 
02589                         /*
02590                          * Special hack for broken Linux with no working sendfile. If we
02591                          * return EINTR we sent the header but not the rest of the data.
02592                          * Fake this up by doing read/write calls.
02593                          */
02594 
02595                         if (errno == EINTR) {
02596                                 /* Ensure we don't do this again. */
02597                                 set_use_sendfile(SNUM(conn), False);
02598                                 DEBUG(0,("send_file_readX: sendfile not available. Faking..\n"));
02599 
02600                                 if ((nread = fake_sendfile(fsp, startpos, smb_maxcnt, data,
02601                                                         len_outbuf - (data-outbuf))) == -1) {
02602                                         DEBUG(0,("send_file_readX: fake_sendfile failed for file %s (%s).\n",
02603                                                 fsp->fsp_name, strerror(errno) ));
02604                                         exit_server_cleanly("send_file_readX: fake_sendfile failed");
02605                                 }
02606                                 DEBUG( 3, ( "send_file_readX: fake_sendfile fnum=%d max=%d nread=%d\n",
02607                                         fsp->fnum, (int)smb_maxcnt, (int)nread ) );
02608                                 /* Returning -1 here means successful sendfile. */
02609                                 return -1;
02610                         }
02611 
02612                         DEBUG(0,("send_file_readX: sendfile failed for file %s (%s). Terminating\n",
02613                                 fsp->fsp_name, strerror(errno) ));
02614                         exit_server_cleanly("send_file_readX sendfile failed");
02615                 }
02616 
02617                 DEBUG( 3, ( "send_file_readX: sendfile fnum=%d max=%d nread=%d\n",
02618                         fsp->fnum, (int)smb_maxcnt, (int)nread ) );
02619                 /* Returning -1 here means successful sendfile. */
02620                 return -1;
02621         }
02622 
02623   normal_read:
02624 
02625 #endif
02626 
02627         nread = read_file(fsp,data,startpos,smb_maxcnt);
02628   
02629         if (nread < 0) {
02630                 return(UNIXERROR(ERRDOS,ERRnoaccess));
02631         }
02632 
02633         outsize = set_message(outbuf,12,nread,False);
02634         SSVAL(outbuf,smb_vwv2,0xFFFF); /* Remaining - must be -1. */
02635         SSVAL(outbuf,smb_vwv5,nread);
02636         SSVAL(outbuf,smb_vwv6,smb_offset(data,outbuf));
02637         SSVAL(outbuf,smb_vwv7,((nread >> 16) & 1));
02638         SSVAL(smb_buf(outbuf),-2,nread);
02639   
02640         DEBUG( 3, ( "send_file_readX fnum=%d max=%d nread=%d\n",
02641                 fsp->fnum, (int)smb_maxcnt, (int)nread ) );
02642 
02643         /* Returning the number of bytes we want to send back - including header. */
02644         return outsize;
02645 }
02646 
02647 /****************************************************************************
02648  Reply to a read and X.
02649 ****************************************************************************/
02650 
02651 int reply_read_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
02652 {
02653         files_struct *fsp = file_fsp(inbuf,smb_vwv2);
02654         SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
02655         ssize_t nread = -1;
02656         size_t smb_maxcnt = SVAL(inbuf,smb_vwv5);
02657 #if 0
02658         size_t smb_mincnt = SVAL(inbuf,smb_vwv6);
02659 #endif
02660 
02661         START_PROFILE(SMBreadX);
02662 
02663         /* If it's an IPC, pass off the pipe handler. */
02664         if (IS_IPC(conn)) {
02665                 END_PROFILE(SMBreadX);
02666                 return reply_pipe_read_and_X(inbuf,outbuf,length,bufsize);
02667         }
02668 
02669         CHECK_FSP(fsp,conn);
02670         if (!CHECK_READ(fsp,inbuf)) {
02671                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
02672         }
02673 
02674         set_message(outbuf,12,0,True);
02675 
02676         if (global_client_caps & CAP_LARGE_READX) {
02677                 if (SVAL(inbuf,smb_vwv7) == 1) {
02678                         smb_maxcnt |= (1<<16);
02679                 }
02680                 if (smb_maxcnt > BUFFER_SIZE) {
02681                         DEBUG(0,("reply_read_and_X - read too large (%u) for reply buffer %u\n",
02682                                 (unsigned int)smb_maxcnt, (unsigned int)BUFFER_SIZE));
02683                         END_PROFILE(SMBreadX);
02684                         return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
02685                 }
02686         }
02687 
02688         if(CVAL(inbuf,smb_wct) == 12) {
02689 #ifdef LARGE_SMB_OFF_T
02690                 /*
02691                  * This is a large offset (64 bit) read.
02692                  */
02693                 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv10)) << 32);
02694 
02695 #else /* !LARGE_SMB_OFF_T */
02696 
02697                 /*
02698                  * Ensure we haven't been sent a >32 bit offset.
02699                  */
02700 
02701                 if(IVAL(inbuf,smb_vwv10) != 0) {
02702                         DEBUG(0,("reply_read_and_X - large offset (%x << 32) used and we don't support \
02703 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv10) ));
02704                         END_PROFILE(SMBreadX);
02705                         return ERROR_DOS(ERRDOS,ERRbadaccess);
02706                 }
02707 
02708 #endif /* LARGE_SMB_OFF_T */
02709 
02710         }
02711 
02712         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)smb_maxcnt,(SMB_BIG_UINT)startpos, READ_LOCK)) {
02713                 END_PROFILE(SMBreadX);
02714                 return ERROR_DOS(ERRDOS,ERRlock);
02715         }
02716 
02717         if (schedule_aio_read_and_X(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt)) {
02718                 END_PROFILE(SMBreadX);
02719                 return -1;
02720         }
02721 
02722         nread = send_file_readX(conn, inbuf, outbuf, length, bufsize, fsp, startpos, smb_maxcnt);
02723         /* Only call chain_reply if not an error. */
02724         if (nread != -1 && SVAL(outbuf,smb_rcls) == 0) {
02725                 nread = chain_reply(inbuf,outbuf,length,bufsize);
02726         }
02727 
02728         END_PROFILE(SMBreadX);
02729         return nread;
02730 }
02731 
02732 /****************************************************************************
02733  Reply to a writebraw (core+ or LANMAN1.0 protocol).
02734 ****************************************************************************/
02735 
02736 int reply_writebraw(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
02737 {
02738         ssize_t nwritten=0;
02739         ssize_t total_written=0;
02740         size_t numtowrite=0;
02741         size_t tcount;
02742         SMB_OFF_T startpos;
02743         char *data=NULL;
02744         BOOL write_through;
02745         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
02746         int outsize = 0;
02747         NTSTATUS status;
02748         START_PROFILE(SMBwritebraw);
02749 
02750         if (srv_is_signing_active()) {
02751                 exit_server_cleanly("reply_writebraw: SMB signing is active - raw reads/writes are disallowed.");
02752         }
02753 
02754         CHECK_FSP(fsp,conn);
02755         if (!CHECK_WRITE(fsp)) {
02756                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
02757         }
02758   
02759         tcount = IVAL(inbuf,smb_vwv1);
02760         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
02761         write_through = BITSETW(inbuf+smb_vwv7,0);
02762 
02763         /* We have to deal with slightly different formats depending
02764                 on whether we are using the core+ or lanman1.0 protocol */
02765 
02766         if(Protocol <= PROTOCOL_COREPLUS) {
02767                 numtowrite = SVAL(smb_buf(inbuf),-2);
02768                 data = smb_buf(inbuf);
02769         } else {
02770                 numtowrite = SVAL(inbuf,smb_vwv10);
02771                 data = smb_base(inbuf) + SVAL(inbuf, smb_vwv11);
02772         }
02773 
02774         /* force the error type */
02775         SCVAL(inbuf,smb_com,SMBwritec);
02776         SCVAL(outbuf,smb_com,SMBwritec);
02777 
02778         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
02779                 END_PROFILE(SMBwritebraw);
02780                 return(ERROR_DOS(ERRDOS,ERRlock));
02781         }
02782 
02783         if (numtowrite>0)
02784                 nwritten = write_file(fsp,data,startpos,numtowrite);
02785   
02786         DEBUG(3,("writebraw1 fnum=%d start=%.0f num=%d wrote=%d sync=%d\n",
02787                 fsp->fnum, (double)startpos, (int)numtowrite, (int)nwritten, (int)write_through));
02788 
02789         if (nwritten < (ssize_t)numtowrite)  {
02790                 END_PROFILE(SMBwritebraw);
02791                 return(UNIXERROR(ERRHRD,ERRdiskfull));
02792         }
02793 
02794         total_written = nwritten;
02795 
02796         /* Return a message to the redirector to tell it to send more bytes */
02797         SCVAL(outbuf,smb_com,SMBwritebraw);
02798         SSVALS(outbuf,smb_vwv0,-1);
02799         outsize = set_message(outbuf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
02800         show_msg(outbuf);
02801         if (!send_smb(smbd_server_fd(),outbuf))
02802                 exit_server_cleanly("reply_writebraw: send_smb failed.");
02803   
02804         /* Now read the raw data into the buffer and write it */
02805         if (read_smb_length(smbd_server_fd(),inbuf,SMB_SECONDARY_WAIT) == -1) {
02806                 exit_server_cleanly("secondary writebraw failed");
02807         }
02808   
02809         /* Even though this is not an smb message, smb_len returns the generic length of an smb message */
02810         numtowrite = smb_len(inbuf);
02811 
02812         /* Set up outbuf to return the correct return */
02813         outsize = set_message(outbuf,1,0,True);
02814         SCVAL(outbuf,smb_com,SMBwritec);
02815 
02816         if (numtowrite != 0) {
02817 
02818                 if (numtowrite > BUFFER_SIZE) {
02819                         DEBUG(0,("reply_writebraw: Oversize secondary write raw requested (%u). Terminating\n",
02820                                 (unsigned int)numtowrite ));
02821                         exit_server_cleanly("secondary writebraw failed");
02822                 }
02823 
02824                 if (tcount > nwritten+numtowrite) {
02825                         DEBUG(3,("Client overestimated the write %d %d %d\n",
02826                                 (int)tcount,(int)nwritten,(int)numtowrite));
02827                 }
02828 
02829                 if (read_data( smbd_server_fd(), inbuf+4, numtowrite) != numtowrite ) {
02830                         DEBUG(0,("reply_writebraw: Oversize secondary write raw read failed (%s). Terminating\n",
02831                                 strerror(errno) ));
02832                         exit_server_cleanly("secondary writebraw failed");
02833                 }
02834 
02835                 nwritten = write_file(fsp,inbuf+4,startpos+nwritten,numtowrite);
02836                 if (nwritten == -1) {
02837                         END_PROFILE(SMBwritebraw);
02838                         return(UNIXERROR(ERRHRD,ERRdiskfull));
02839                 }
02840 
02841                 if (nwritten < (ssize_t)numtowrite) {
02842                         SCVAL(outbuf,smb_rcls,ERRHRD);
02843                         SSVAL(outbuf,smb_err,ERRdiskfull);      
02844                 }
02845 
02846                 if (nwritten > 0)
02847                         total_written += nwritten;
02848         }
02849  
02850         SSVAL(outbuf,smb_vwv0,total_written);
02851 
02852         status = sync_file(conn, fsp, write_through);
02853         if (!NT_STATUS_IS_OK(status)) {
02854                 DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
02855                         fsp->fsp_name, nt_errstr(status) ));
02856                 END_PROFILE(SMBwritebraw);
02857                 return ERROR_NT(status);
02858         }
02859 
02860         DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
02861                 fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
02862 
02863         /* we won't return a status if write through is not selected - this follows what WfWg does */
02864         END_PROFILE(SMBwritebraw);
02865         if (!write_through && total_written==tcount) {
02866 
02867 #if RABBIT_PELLET_FIX
02868                 /*
02869                  * Fix for "rabbit pellet" mode, trigger an early TCP ack by
02870                  * sending a SMBkeepalive. Thanks to DaveCB at Sun for this. JRA.
02871                  */
02872                 if (!send_keepalive(smbd_server_fd()))
02873                         exit_server_cleanly("reply_writebraw: send of keepalive failed");
02874 #endif
02875                 return(-1);
02876         }
02877 
02878         return(outsize);
02879 }
02880 
02881 #undef DBGC_CLASS
02882 #define DBGC_CLASS DBGC_LOCKING
02883 
02884 /****************************************************************************
02885  Reply to a writeunlock (core+).
02886 ****************************************************************************/
02887 
02888 int reply_writeunlock(connection_struct *conn, char *inbuf,char *outbuf, 
02889                       int size, int dum_buffsize)
02890 {
02891         ssize_t nwritten = -1;
02892         size_t numtowrite;
02893         SMB_OFF_T startpos;
02894         char *data;
02895         NTSTATUS status = NT_STATUS_OK;
02896         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
02897         int outsize = 0;
02898         START_PROFILE(SMBwriteunlock);
02899         
02900         CHECK_FSP(fsp,conn);
02901         if (!CHECK_WRITE(fsp)) {
02902                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
02903         }
02904 
02905         numtowrite = SVAL(inbuf,smb_vwv1);
02906         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
02907         data = smb_buf(inbuf) + 3;
02908   
02909         if (numtowrite && is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
02910                 END_PROFILE(SMBwriteunlock);
02911                 return ERROR_DOS(ERRDOS,ERRlock);
02912         }
02913 
02914         /* The special X/Open SMB protocol handling of
02915            zero length writes is *NOT* done for
02916            this call */
02917         if(numtowrite == 0) {
02918                 nwritten = 0;
02919         } else {
02920                 nwritten = write_file(fsp,data,startpos,numtowrite);
02921         }
02922   
02923         status = sync_file(conn, fsp, False /* write through */);
02924         if (!NT_STATUS_IS_OK(status)) {
02925                 END_PROFILE(SMBwriteunlock);
02926                 DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
02927                         fsp->fsp_name, nt_errstr(status) ));
02928                 return ERROR_NT(status);
02929         }
02930 
02931         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
02932                 END_PROFILE(SMBwriteunlock);
02933                 return(UNIXERROR(ERRHRD,ERRdiskfull));
02934         }
02935 
02936         if (numtowrite) {
02937                 status = do_unlock(fsp,
02938                                 (uint32)SVAL(inbuf,smb_pid),
02939                                 (SMB_BIG_UINT)numtowrite, 
02940                                 (SMB_BIG_UINT)startpos,
02941                                 WINDOWS_LOCK);
02942 
02943                 if (NT_STATUS_V(status)) {
02944                         END_PROFILE(SMBwriteunlock);
02945                         return ERROR_NT(status);
02946                 }
02947         }
02948         
02949         outsize = set_message(outbuf,1,0,True);
02950         
02951         SSVAL(outbuf,smb_vwv0,nwritten);
02952         
02953         DEBUG(3,("writeunlock fnum=%d num=%d wrote=%d\n",
02954                  fsp->fnum, (int)numtowrite, (int)nwritten));
02955         
02956         END_PROFILE(SMBwriteunlock);
02957         return outsize;
02958 }
02959 
02960 #undef DBGC_CLASS
02961 #define DBGC_CLASS DBGC_ALL
02962 
02963 /****************************************************************************
02964  Reply to a write.
02965 ****************************************************************************/
02966 
02967 int reply_write(connection_struct *conn, char *inbuf,char *outbuf,int size,int dum_buffsize)
02968 {
02969         size_t numtowrite;
02970         ssize_t nwritten = -1;
02971         SMB_OFF_T startpos;
02972         char *data;
02973         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
02974         int outsize = 0;
02975         NTSTATUS status;
02976         START_PROFILE(SMBwrite);
02977 
02978         /* If it's an IPC, pass off the pipe handler. */
02979         if (IS_IPC(conn)) {
02980                 END_PROFILE(SMBwrite);
02981                 return reply_pipe_write(inbuf,outbuf,size,dum_buffsize);
02982         }
02983 
02984         CHECK_FSP(fsp,conn);
02985         if (!CHECK_WRITE(fsp)) {
02986                 END_PROFILE(SMBwrite);
02987                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
02988         }
02989 
02990         numtowrite = SVAL(inbuf,smb_vwv1);
02991         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
02992         data = smb_buf(inbuf) + 3;
02993   
02994         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
02995                 END_PROFILE(SMBwrite);
02996                 return ERROR_DOS(ERRDOS,ERRlock);
02997         }
02998 
02999         /*
03000          * X/Open SMB protocol says that if smb_vwv1 is
03001          * zero then the file size should be extended or
03002          * truncated to the size given in smb_vwv[2-3].
03003          */
03004 
03005         if(numtowrite == 0) {
03006                 /*
03007                  * This is actually an allocate call, and set EOF. JRA.
03008                  */
03009                 nwritten = vfs_allocate_file_space(fsp, (SMB_OFF_T)startpos);
03010                 if (nwritten < 0) {
03011                         END_PROFILE(SMBwrite);
03012                         return ERROR_NT(NT_STATUS_DISK_FULL);
03013                 }
03014                 nwritten = vfs_set_filelen(fsp, (SMB_OFF_T)startpos);
03015                 if (nwritten < 0) {
03016                         END_PROFILE(SMBwrite);
03017                         return ERROR_NT(NT_STATUS_DISK_FULL);
03018                 }
03019         } else
03020                 nwritten = write_file(fsp,data,startpos,numtowrite);
03021   
03022         status = sync_file(conn, fsp, False);
03023         if (!NT_STATUS_IS_OK(status)) {
03024                 END_PROFILE(SMBwrite);
03025                 DEBUG(5,("reply_write: sync_file for %s returned %s\n",
03026                         fsp->fsp_name, nt_errstr(status) ));
03027                 return ERROR_NT(status);
03028         }
03029 
03030         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
03031                 END_PROFILE(SMBwrite);
03032                 return(UNIXERROR(ERRHRD,ERRdiskfull));
03033         }
03034 
03035         outsize = set_message(outbuf,1,0,True);
03036   
03037         SSVAL(outbuf,smb_vwv0,nwritten);
03038 
03039         if (nwritten < (ssize_t)numtowrite) {
03040                 SCVAL(outbuf,smb_rcls,ERRHRD);
03041                 SSVAL(outbuf,smb_err,ERRdiskfull);      
03042         }
03043   
03044         DEBUG(3,("write fnum=%d num=%d wrote=%d\n", fsp->fnum, (int)numtowrite, (int)nwritten));
03045 
03046         END_PROFILE(SMBwrite);
03047         return(outsize);
03048 }
03049 
03050 /****************************************************************************
03051  Reply to a write and X.
03052 ****************************************************************************/
03053 
03054 int reply_write_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
03055 {
03056         files_struct *fsp = file_fsp(inbuf,smb_vwv2);
03057         SMB_OFF_T startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
03058         size_t numtowrite = SVAL(inbuf,smb_vwv10);
03059         BOOL write_through = BITSETW(inbuf+smb_vwv7,0);
03060         ssize_t nwritten = -1;
03061         unsigned int smb_doff = SVAL(inbuf,smb_vwv11);
03062         unsigned int smblen = smb_len(inbuf);
03063         char *data;
03064         BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
03065         NTSTATUS status;
03066         START_PROFILE(SMBwriteX);
03067 
03068         /* If it's an IPC, pass off the pipe handler. */
03069         if (IS_IPC(conn)) {
03070                 END_PROFILE(SMBwriteX);
03071                 return reply_pipe_write_and_X(inbuf,outbuf,length,bufsize);
03072         }
03073 
03074         CHECK_FSP(fsp,conn);
03075         if (!CHECK_WRITE(fsp)) {
03076                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
03077         }
03078 
03079         set_message(outbuf,6,0,True);
03080   
03081         /* Deal with possible LARGE_WRITEX */
03082         if (large_writeX) {
03083                 numtowrite |= ((((size_t)SVAL(inbuf,smb_vwv9)) & 1 )<<16);
03084         }
03085 
03086         if(smb_doff > smblen || (smb_doff + numtowrite > smblen)) {
03087                 END_PROFILE(SMBwriteX);
03088                 return ERROR_DOS(ERRDOS,ERRbadmem);
03089         }
03090 
03091         data = smb_base(inbuf) + smb_doff;
03092 
03093         if(CVAL(inbuf,smb_wct) == 14) {
03094 #ifdef LARGE_SMB_OFF_T
03095                 /*
03096                  * This is a large offset (64 bit) write.
03097                  */
03098                 startpos |= (((SMB_OFF_T)IVAL(inbuf,smb_vwv12)) << 32);
03099 
03100 #else /* !LARGE_SMB_OFF_T */
03101 
03102                 /*
03103                  * Ensure we haven't been sent a >32 bit offset.
03104                  */
03105 
03106                 if(IVAL(inbuf,smb_vwv12) != 0) {
03107                         DEBUG(0,("reply_write_and_X - large offset (%x << 32) used and we don't support \
03108 64 bit offsets.\n", (unsigned int)IVAL(inbuf,smb_vwv12) ));
03109                         END_PROFILE(SMBwriteX);
03110                         return ERROR_DOS(ERRDOS,ERRbadaccess);
03111                 }
03112 
03113 #endif /* LARGE_SMB_OFF_T */
03114         }
03115 
03116         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
03117                 END_PROFILE(SMBwriteX);
03118                 return ERROR_DOS(ERRDOS,ERRlock);
03119         }
03120 
03121         /* X/Open SMB protocol says that, unlike SMBwrite
03122         if the length is zero then NO truncation is
03123         done, just a write of zero. To truncate a file,
03124         use SMBwrite. */
03125 
03126         if(numtowrite == 0) {
03127                 nwritten = 0;
03128         } else {
03129 
03130                 if (schedule_aio_write_and_X(conn, inbuf, outbuf, length, bufsize,
03131                                         fsp,data,startpos,numtowrite)) {
03132                         END_PROFILE(SMBwriteX);
03133                         return -1;
03134                 }
03135 
03136                 nwritten = write_file(fsp,data,startpos,numtowrite);
03137         }
03138   
03139         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
03140                 END_PROFILE(SMBwriteX);
03141                 return(UNIXERROR(ERRHRD,ERRdiskfull));
03142         }
03143 
03144         SSVAL(outbuf,smb_vwv2,nwritten);
03145         if (large_writeX)
03146                 SSVAL(outbuf,smb_vwv4,(nwritten>>16)&1);
03147 
03148         if (nwritten < (ssize_t)numtowrite) {
03149                 SCVAL(outbuf,smb_rcls,ERRHRD);
03150                 SSVAL(outbuf,smb_err,ERRdiskfull);      
03151         }
03152 
03153         DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
03154                 fsp->fnum, (int)numtowrite, (int)nwritten));
03155 
03156         status = sync_file(conn, fsp, write_through);
03157         if (!NT_STATUS_IS_OK(status)) {
03158                 END_PROFILE(SMBwriteX);
03159                 DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
03160                         fsp->fsp_name, nt_errstr(status) ));
03161                 return ERROR_NT(status);
03162         }
03163 
03164         END_PROFILE(SMBwriteX);
03165         return chain_reply(inbuf,outbuf,length,bufsize);
03166 }
03167 
03168 /****************************************************************************
03169  Reply to a lseek.
03170 ****************************************************************************/
03171 
03172 int reply_lseek(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
03173 {
03174         SMB_OFF_T startpos;
03175         SMB_OFF_T res= -1;
03176         int mode,umode;
03177         int outsize = 0;
03178         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03179         START_PROFILE(SMBlseek);
03180 
03181         CHECK_FSP(fsp,conn);
03182 
03183         flush_write_cache(fsp, SEEK_FLUSH);
03184 
03185         mode = SVAL(inbuf,smb_vwv1) & 3;
03186         /* NB. This doesn't use IVAL_TO_SMB_OFF_T as startpos can be signed in this case. */
03187         startpos = (SMB_OFF_T)IVALS(inbuf,smb_vwv2);
03188 
03189         switch (mode) {
03190                 case 0:
03191                         umode = SEEK_SET;
03192                         res = startpos;
03193                         break;
03194                 case 1:
03195                         umode = SEEK_CUR;
03196                         res = fsp->fh->pos + startpos;
03197                         break;
03198                 case 2:
03199                         umode = SEEK_END;
03200                         break;
03201                 default:
03202                         umode = SEEK_SET;
03203                         res = startpos;
03204                         break;
03205         }
03206 
03207         if (umode == SEEK_END) {
03208                 if((res = SMB_VFS_LSEEK(fsp,fsp->fh->fd,startpos,umode)) == -1) {
03209                         if(errno == EINVAL) {
03210                                 SMB_OFF_T current_pos = startpos;
03211                                 SMB_STRUCT_STAT sbuf;
03212 
03213                                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd, &sbuf) == -1) {
03214                                         END_PROFILE(SMBlseek);
03215                                         return(UNIXERROR(ERRDOS,ERRnoaccess));
03216                                 }
03217 
03218                                 current_pos += sbuf.st_size;
03219                                 if(current_pos < 0)
03220                                         res = SMB_VFS_LSEEK(fsp,fsp->fh->fd,0,SEEK_SET);
03221                         }
03222                 }
03223 
03224                 if(res == -1) {
03225                         END_PROFILE(SMBlseek);
03226                         return(UNIXERROR(ERRDOS,ERRnoaccess));
03227                 }
03228         }
03229 
03230         fsp->fh->pos = res;
03231   
03232         outsize = set_message(outbuf,2,0,True);
03233         SIVAL(outbuf,smb_vwv0,res);
03234   
03235         DEBUG(3,("lseek fnum=%d ofs=%.0f newpos = %.0f mode=%d\n",
03236                 fsp->fnum, (double)startpos, (double)res, mode));
03237 
03238         END_PROFILE(SMBlseek);
03239         return(outsize);
03240 }
03241 
03242 /****************************************************************************
03243  Reply to a flush.
03244 ****************************************************************************/
03245 
03246 int reply_flush(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
03247 {
03248         int outsize = set_message(outbuf,0,0,False);
03249         uint16 fnum = SVAL(inbuf,smb_vwv0);
03250         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03251         START_PROFILE(SMBflush);
03252 
03253         if (fnum != 0xFFFF)
03254                 CHECK_FSP(fsp,conn);
03255         
03256         if (!fsp) {
03257                 file_sync_all(conn);
03258         } else {
03259                 NTSTATUS status = sync_file(conn, fsp, True);
03260                 if (!NT_STATUS_IS_OK(status)) {
03261                         END_PROFILE(SMBflush);
03262                         DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
03263                                 fsp->fsp_name, nt_errstr(status) ));
03264                         return ERROR_NT(status);
03265                 }
03266         }
03267         
03268         DEBUG(3,("flush\n"));
03269         END_PROFILE(SMBflush);
03270         return(outsize);
03271 }
03272 
03273 /****************************************************************************
03274  Reply to a exit.
03275  conn POINTER CAN BE NULL HERE !
03276 ****************************************************************************/
03277 
03278 int reply_exit(connection_struct *conn, 
03279                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03280 {
03281         int outsize;
03282         START_PROFILE(SMBexit);
03283 
03284         file_close_pid(SVAL(inbuf,smb_pid),SVAL(inbuf,smb_uid));
03285 
03286         outsize = set_message(outbuf,0,0,False);
03287 
03288         DEBUG(3,("exit\n"));
03289 
03290         END_PROFILE(SMBexit);
03291         return(outsize);
03292 }
03293 
03294 /****************************************************************************
03295  Reply to a close - has to deal with closing a directory opened by NT SMB's.
03296 ****************************************************************************/
03297 
03298 int reply_close(connection_struct *conn, char *inbuf,char *outbuf, int size,
03299                 int dum_buffsize)
03300 {
03301         NTSTATUS status = NT_STATUS_OK;
03302         int outsize = 0;
03303         files_struct *fsp = NULL;
03304         START_PROFILE(SMBclose);
03305 
03306         outsize = set_message(outbuf,0,0,False);
03307 
03308         /* If it's an IPC, pass off to the pipe handler. */
03309         if (IS_IPC(conn)) {
03310                 END_PROFILE(SMBclose);
03311                 return reply_pipe_close(conn, inbuf,outbuf);
03312         }
03313 
03314         fsp = file_fsp(inbuf,smb_vwv0);
03315 
03316         /*
03317          * We can only use CHECK_FSP if we know it's not a directory.
03318          */
03319 
03320         if(!fsp || (fsp->conn != conn) || (fsp->vuid != current_user.vuid)) {
03321                 END_PROFILE(SMBclose);
03322                 return ERROR_DOS(ERRDOS,ERRbadfid);
03323         }
03324 
03325         if(fsp->is_directory) {
03326                 /*
03327                  * Special case - close NT SMB directory handle.
03328                  */
03329                 DEBUG(3,("close directory fnum=%d\n", fsp->fnum));
03330                 status = close_file(fsp,NORMAL_CLOSE);
03331         } else {
03332                 /*
03333                  * Close ordinary file.
03334                  */
03335 
03336                 DEBUG(3,("close fd=%d fnum=%d (numopen=%d)\n",
03337                          fsp->fh->fd, fsp->fnum,
03338                          conn->num_files_open));
03339  
03340                 /*
03341                  * Take care of any time sent in the close.
03342                  */
03343 
03344                 fsp_set_pending_modtime(fsp,
03345                                 convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv1)));
03346 
03347                 /*
03348                  * close_file() returns the unix errno if an error
03349                  * was detected on close - normally this is due to
03350                  * a disk full error. If not then it was probably an I/O error.
03351                  */
03352  
03353                 status = close_file(fsp,NORMAL_CLOSE);
03354         }  
03355 
03356         if(!NT_STATUS_IS_OK(status)) {
03357                 END_PROFILE(SMBclose);
03358                 return ERROR_NT(status);
03359         }
03360 
03361         END_PROFILE(SMBclose);
03362         return(outsize);
03363 }
03364 
03365 /****************************************************************************
03366  Reply to a writeclose (Core+ protocol).
03367 ****************************************************************************/
03368 
03369 int reply_writeclose(connection_struct *conn,
03370                      char *inbuf,char *outbuf, int size, int dum_buffsize)
03371 {
03372         size_t numtowrite;
03373         ssize_t nwritten = -1;
03374         int outsize = 0;
03375         NTSTATUS close_status = NT_STATUS_OK;
03376         SMB_OFF_T startpos;
03377         char *data;
03378         struct timespec mtime;
03379         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03380         START_PROFILE(SMBwriteclose);
03381 
03382         CHECK_FSP(fsp,conn);
03383         if (!CHECK_WRITE(fsp)) {
03384                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
03385         }
03386 
03387         numtowrite = SVAL(inbuf,smb_vwv1);
03388         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
03389         mtime = convert_time_t_to_timespec(srv_make_unix_date3(inbuf+smb_vwv4));
03390         data = smb_buf(inbuf) + 1;
03391   
03392         if (numtowrite && is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)numtowrite,(SMB_BIG_UINT)startpos, WRITE_LOCK)) {
03393                 END_PROFILE(SMBwriteclose);
03394                 return ERROR_DOS(ERRDOS,ERRlock);
03395         }
03396   
03397         nwritten = write_file(fsp,data,startpos,numtowrite);
03398 
03399         set_filetime(conn, fsp->fsp_name, mtime);
03400   
03401         /*
03402          * More insanity. W2K only closes the file if writelen > 0.
03403          * JRA.
03404          */
03405 
03406         if (numtowrite) {
03407                 DEBUG(3,("reply_writeclose: zero length write doesn't close file %s\n",
03408                         fsp->fsp_name ));
03409                 close_status = close_file(fsp,NORMAL_CLOSE);
03410         }
03411 
03412         DEBUG(3,("writeclose fnum=%d num=%d wrote=%d (numopen=%d)\n",
03413                  fsp->fnum, (int)numtowrite, (int)nwritten,
03414                  conn->num_files_open));
03415   
03416         if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
03417                 END_PROFILE(SMBwriteclose);
03418                 return(UNIXERROR(ERRHRD,ERRdiskfull));
03419         }
03420  
03421         if(!NT_STATUS_IS_OK(close_status)) {
03422                 END_PROFILE(SMBwriteclose);
03423                 return ERROR_NT(close_status);
03424         }
03425  
03426         outsize = set_message(outbuf,1,0,True);
03427   
03428         SSVAL(outbuf,smb_vwv0,nwritten);
03429         END_PROFILE(SMBwriteclose);
03430         return(outsize);
03431 }
03432 
03433 #undef DBGC_CLASS
03434 #define DBGC_CLASS DBGC_LOCKING
03435 
03436 /****************************************************************************
03437  Reply to a lock.
03438 ****************************************************************************/
03439 
03440 int reply_lock(connection_struct *conn,
03441                char *inbuf,char *outbuf, int length, int dum_buffsize)
03442 {
03443         int outsize = set_message(outbuf,0,0,False);
03444         SMB_BIG_UINT count,offset;
03445         NTSTATUS status;
03446         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03447         struct byte_range_lock *br_lck = NULL;
03448 
03449         START_PROFILE(SMBlock);
03450 
03451         CHECK_FSP(fsp,conn);
03452 
03453         release_level_2_oplocks_on_change(fsp);
03454 
03455         count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
03456         offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
03457 
03458         DEBUG(3,("lock fd=%d fnum=%d offset=%.0f count=%.0f\n",
03459                  fsp->fh->fd, fsp->fnum, (double)offset, (double)count));
03460 
03461         br_lck = do_lock(fsp,
03462                         (uint32)SVAL(inbuf,smb_pid),
03463                         count,
03464                         offset,
03465                         WRITE_LOCK,
03466                         WINDOWS_LOCK,
03467                         False, /* Non-blocking lock. */
03468                         &status,
03469                         NULL);
03470 
03471         TALLOC_FREE(br_lck);
03472 
03473         if (NT_STATUS_V(status)) {
03474                 END_PROFILE(SMBlock);
03475                 return ERROR_NT(status);
03476         }
03477 
03478         END_PROFILE(SMBlock);
03479         return(outsize);
03480 }
03481 
03482 /****************************************************************************
03483  Reply to a unlock.
03484 ****************************************************************************/
03485 
03486 int reply_unlock(connection_struct *conn, char *inbuf,char *outbuf, int size, 
03487                  int dum_buffsize)
03488 {
03489         int outsize = set_message(outbuf,0,0,False);
03490         SMB_BIG_UINT count,offset;
03491         NTSTATUS status;
03492         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03493         START_PROFILE(SMBunlock);
03494 
03495         CHECK_FSP(fsp,conn);
03496         
03497         count = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv1);
03498         offset = (SMB_BIG_UINT)IVAL(inbuf,smb_vwv3);
03499         
03500         status = do_unlock(fsp,
03501                         (uint32)SVAL(inbuf,smb_pid),
03502                         count,
03503                         offset,
03504                         WINDOWS_LOCK);
03505 
03506         if (NT_STATUS_V(status)) {
03507                 END_PROFILE(SMBunlock);
03508                 return ERROR_NT(status);
03509         }
03510 
03511         DEBUG( 3, ( "unlock fd=%d fnum=%d offset=%.0f count=%.0f\n",
03512                     fsp->fh->fd, fsp->fnum, (double)offset, (double)count ) );
03513         
03514         END_PROFILE(SMBunlock);
03515         return(outsize);
03516 }
03517 
03518 #undef DBGC_CLASS
03519 #define DBGC_CLASS DBGC_ALL
03520 
03521 /****************************************************************************
03522  Reply to a tdis.
03523  conn POINTER CAN BE NULL HERE !
03524 ****************************************************************************/
03525 
03526 int reply_tdis(connection_struct *conn, 
03527                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03528 {
03529         int outsize = set_message(outbuf,0,0,False);
03530         uint16 vuid;
03531         START_PROFILE(SMBtdis);
03532 
03533         vuid = SVAL(inbuf,smb_uid);
03534 
03535         if (!conn) {
03536                 DEBUG(4,("Invalid connection in tdis\n"));
03537                 END_PROFILE(SMBtdis);
03538                 return ERROR_DOS(ERRSRV,ERRinvnid);
03539         }
03540 
03541         conn->used = False;
03542 
03543         close_cnum(conn,vuid);
03544   
03545         END_PROFILE(SMBtdis);
03546         return outsize;
03547 }
03548 
03549 /****************************************************************************
03550  Reply to a echo.
03551  conn POINTER CAN BE NULL HERE !
03552 ****************************************************************************/
03553 
03554 int reply_echo(connection_struct *conn,
03555                char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03556 {
03557         int smb_reverb = SVAL(inbuf,smb_vwv0);
03558         int seq_num;
03559         unsigned int data_len = smb_buflen(inbuf);
03560         int outsize = set_message(outbuf,1,data_len,True);
03561         START_PROFILE(SMBecho);
03562 
03563         if (data_len > BUFFER_SIZE) {
03564                 DEBUG(0,("reply_echo: data_len too large.\n"));
03565                 END_PROFILE(SMBecho);
03566                 return -1;
03567         }
03568 
03569         /* copy any incoming data back out */
03570         if (data_len > 0)
03571                 memcpy(smb_buf(outbuf),smb_buf(inbuf),data_len);
03572 
03573         if (smb_reverb > 100) {
03574                 DEBUG(0,("large reverb (%d)?? Setting to 100\n",smb_reverb));
03575                 smb_reverb = 100;
03576         }
03577 
03578         for (seq_num =1 ; seq_num <= smb_reverb ; seq_num++) {
03579                 SSVAL(outbuf,smb_vwv0,seq_num);
03580 
03581                 smb_setlen(outbuf,outsize - 4);
03582 
03583                 show_msg(outbuf);
03584                 if (!send_smb(smbd_server_fd(),outbuf))
03585                         exit_server_cleanly("reply_echo: send_smb failed.");
03586         }
03587 
03588         DEBUG(3,("echo %d times\n", smb_reverb));
03589 
03590         smb_echo_count++;
03591 
03592         END_PROFILE(SMBecho);
03593         return -1;
03594 }
03595 
03596 /****************************************************************************
03597  Reply to a printopen.
03598 ****************************************************************************/
03599 
03600 int reply_printopen(connection_struct *conn, 
03601                     char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03602 {
03603         int outsize = 0;
03604         files_struct *fsp;
03605         NTSTATUS status;
03606         
03607         START_PROFILE(SMBsplopen);
03608         
03609         if (!CAN_PRINT(conn)) {
03610                 END_PROFILE(SMBsplopen);
03611                 return ERROR_DOS(ERRDOS,ERRnoaccess);
03612         }
03613 
03614         /* Open for exclusive use, write only. */
03615         status = print_fsp_open(conn, NULL, &fsp);
03616 
03617         if (!NT_STATUS_IS_OK(status)) {
03618                 END_PROFILE(SMBsplopen);
03619                 return(ERROR_NT(status));
03620         }
03621 
03622         outsize = set_message(outbuf,1,0,True);
03623         SSVAL(outbuf,smb_vwv0,fsp->fnum);
03624   
03625         DEBUG(3,("openprint fd=%d fnum=%d\n",
03626                  fsp->fh->fd, fsp->fnum));
03627 
03628         END_PROFILE(SMBsplopen);
03629         return(outsize);
03630 }
03631 
03632 /****************************************************************************
03633  Reply to a printclose.
03634 ****************************************************************************/
03635 
03636 int reply_printclose(connection_struct *conn,
03637                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03638 {
03639         int outsize = set_message(outbuf,0,0,False);
03640         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03641         NTSTATUS status;
03642         START_PROFILE(SMBsplclose);
03643 
03644         CHECK_FSP(fsp,conn);
03645 
03646         if (!CAN_PRINT(conn)) {
03647                 END_PROFILE(SMBsplclose);
03648                 return ERROR_NT(NT_STATUS_DOS(ERRSRV, ERRerror));
03649         }
03650   
03651         DEBUG(3,("printclose fd=%d fnum=%d\n",
03652                  fsp->fh->fd,fsp->fnum));
03653   
03654         status = close_file(fsp,NORMAL_CLOSE);
03655 
03656         if(!NT_STATUS_IS_OK(status)) {
03657                 END_PROFILE(SMBsplclose);
03658                 return ERROR_NT(status);
03659         }
03660 
03661         END_PROFILE(SMBsplclose);
03662         return(outsize);
03663 }
03664 
03665 /****************************************************************************
03666  Reply to a printqueue.
03667 ****************************************************************************/
03668 
03669 int reply_printqueue(connection_struct *conn,
03670                      char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03671 {
03672         int outsize = set_message(outbuf,2,3,True);
03673         int max_count = SVAL(inbuf,smb_vwv0);
03674         int start_index = SVAL(inbuf,smb_vwv1);
03675         START_PROFILE(SMBsplretq);
03676 
03677         /* we used to allow the client to get the cnum wrong, but that
03678            is really quite gross and only worked when there was only
03679            one printer - I think we should now only accept it if they
03680            get it right (tridge) */
03681         if (!CAN_PRINT(conn)) {
03682                 END_PROFILE(SMBsplretq);
03683                 return ERROR_DOS(ERRDOS,ERRnoaccess);
03684         }
03685 
03686         SSVAL(outbuf,smb_vwv0,0);
03687         SSVAL(outbuf,smb_vwv1,0);
03688         SCVAL(smb_buf(outbuf),0,1);
03689         SSVAL(smb_buf(outbuf),1,0);
03690   
03691         DEBUG(3,("printqueue start_index=%d max_count=%d\n",
03692                  start_index, max_count));
03693 
03694         {
03695                 print_queue_struct *queue = NULL;
03696                 print_status_struct status;
03697                 char *p = smb_buf(outbuf) + 3;
03698                 int count = print_queue_status(SNUM(conn), &queue, &status);
03699                 int num_to_get = ABS(max_count);
03700                 int first = (max_count>0?start_index:start_index+max_count+1);
03701                 int i;
03702 
03703                 if (first >= count)
03704                         num_to_get = 0;
03705                 else
03706                         num_to_get = MIN(num_to_get,count-first);
03707     
03708 
03709                 for (i=first;i<first+num_to_get;i++) {
03710                         srv_put_dos_date2(p,0,queue[i].time);
03711                         SCVAL(p,4,(queue[i].status==LPQ_PRINTING?2:3));
03712                         SSVAL(p,5, queue[i].job);
03713                         SIVAL(p,7,queue[i].size);
03714                         SCVAL(p,11,0);
03715                         srvstr_push(outbuf, p+12, queue[i].fs_user, 16, STR_ASCII);
03716                         p += 28;
03717                 }
03718 
03719                 if (count > 0) {
03720                         outsize = set_message(outbuf,2,28*count+3,False); 
03721                         SSVAL(outbuf,smb_vwv0,count);
03722                         SSVAL(outbuf,smb_vwv1,(max_count>0?first+count:first-1));
03723                         SCVAL(smb_buf(outbuf),0,1);
03724                         SSVAL(smb_buf(outbuf),1,28*count);
03725                 }
03726 
03727                 SAFE_FREE(queue);
03728           
03729                 DEBUG(3,("%d entries returned in queue\n",count));
03730         }
03731   
03732         END_PROFILE(SMBsplretq);
03733         return(outsize);
03734 }
03735 
03736 /****************************************************************************
03737  Reply to a printwrite.
03738 ****************************************************************************/
03739 
03740 int reply_printwrite(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03741 {
03742         int numtowrite;
03743         int outsize = set_message(outbuf,0,0,False);
03744         char *data;
03745         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
03746 
03747         START_PROFILE(SMBsplwr);
03748   
03749         if (!CAN_PRINT(conn)) {
03750                 END_PROFILE(SMBsplwr);
03751                 return ERROR_DOS(ERRDOS,ERRnoaccess);
03752         }
03753 
03754         CHECK_FSP(fsp,conn);
03755         if (!CHECK_WRITE(fsp)) {
03756                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
03757         }
03758 
03759         numtowrite = SVAL(smb_buf(inbuf),1);
03760         data = smb_buf(inbuf) + 3;
03761   
03762         if (write_file(fsp,data,-1,numtowrite) != numtowrite) {
03763                 END_PROFILE(SMBsplwr);
03764                 return(UNIXERROR(ERRHRD,ERRdiskfull));
03765         }
03766 
03767         DEBUG( 3, ( "printwrite fnum=%d num=%d\n", fsp->fnum, numtowrite ) );
03768   
03769         END_PROFILE(SMBsplwr);
03770         return(outsize);
03771 }
03772 
03773 /****************************************************************************
03774  Reply to a mkdir.
03775 ****************************************************************************/
03776 
03777 int reply_mkdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
03778 {
03779         pstring directory;
03780         int outsize;
03781         NTSTATUS status;
03782         SMB_STRUCT_STAT sbuf;
03783 
03784         START_PROFILE(SMBmkdir);
03785  
03786         srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
03787         if (!NT_STATUS_IS_OK(status)) {
03788                 END_PROFILE(SMBmkdir);
03789                 return ERROR_NT(status);
03790         }
03791 
03792         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
03793         if (!NT_STATUS_IS_OK(status)) {
03794                 END_PROFILE(SMBmkdir);
03795                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
03796                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
03797                 }
03798                 return ERROR_NT(status);
03799         }
03800 
03801         status = unix_convert(conn, directory, False, NULL, &sbuf);
03802         if (!NT_STATUS_IS_OK(status)) {
03803                 END_PROFILE(SMBmkdir);
03804                 return ERROR_NT(status);
03805         }
03806 
03807         status = check_name(conn, directory);
03808         if (!NT_STATUS_IS_OK(status)) {
03809                 END_PROFILE(SMBmkdir);
03810                 return ERROR_NT(status);
03811         }
03812   
03813         status = create_directory(conn, directory);
03814 
03815         DEBUG(5, ("create_directory returned %s\n", nt_errstr(status)));
03816 
03817         if (!NT_STATUS_IS_OK(status)) {
03818 
03819                 if (!use_nt_status()
03820                     && NT_STATUS_EQUAL(status,
03821                                        NT_STATUS_OBJECT_NAME_COLLISION)) {
03822                         /*
03823                          * Yes, in the DOS error code case we get a
03824                          * ERRDOS:ERRnoaccess here. See BASE-SAMBA3ERROR
03825                          * samba4 torture test.
03826                          */
03827                         status = NT_STATUS_DOS(ERRDOS, ERRnoaccess);
03828                 }
03829 
03830                 END_PROFILE(SMBmkdir);
03831                 return ERROR_NT(status);
03832         }
03833 
03834         outsize = set_message(outbuf,0,0,False);
03835 
03836         DEBUG( 3, ( "mkdir %s ret=%d\n", directory, outsize ) );
03837 
03838         END_PROFILE(SMBmkdir);
03839         return(outsize);
03840 }
03841 
03842 /****************************************************************************
03843  Static function used by reply_rmdir to delete an entire directory
03844  tree recursively. Return True on ok, False on fail.
03845 ****************************************************************************/
03846 
03847 static BOOL recursive_rmdir(connection_struct *conn, char *directory)
03848 {
03849         const char *dname = NULL;
03850         BOOL ret = True;
03851         long offset = 0;
03852         struct smb_Dir *dir_hnd = OpenDir(conn, directory, NULL, 0);
03853 
03854         if(dir_hnd == NULL)
03855                 return False;
03856 
03857         while((dname = ReadDirName(dir_hnd, &offset))) {
03858                 pstring fullname;
03859                 SMB_STRUCT_STAT st;
03860 
03861                 if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
03862                         continue;
03863 
03864                 if (!is_visible_file(conn, directory, dname, &st, False))
03865                         continue;
03866 
03867                 /* Construct the full name. */
03868                 if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
03869                         errno = ENOMEM;
03870                         ret = False;
03871                         break;
03872                 }
03873 
03874                 pstrcpy(fullname, directory);
03875                 pstrcat(fullname, "/");
03876                 pstrcat(fullname, dname);
03877 
03878                 if(SMB_VFS_LSTAT(conn,fullname, &st) != 0) {
03879                         ret = False;
03880                         break;
03881                 }
03882 
03883                 if(st.st_mode & S_IFDIR) {
03884                         if(!recursive_rmdir(conn, fullname)) {
03885                                 ret = False;
03886                                 break;
03887                         }
03888                         if(SMB_VFS_RMDIR(conn,fullname) != 0) {
03889                                 ret = False;
03890                                 break;
03891                         }
03892                 } else if(SMB_VFS_UNLINK(conn,fullname) != 0) {
03893                         ret = False;
03894                         break;
03895                 }
03896         }
03897         CloseDir(dir_hnd);
03898         return ret;
03899 }
03900 
03901 /****************************************************************************
03902  The internals of the rmdir code - called elsewhere.
03903 ****************************************************************************/
03904 
03905 NTSTATUS rmdir_internals(connection_struct *conn, const char *directory)
03906 {
03907         int ret;
03908         SMB_STRUCT_STAT st;
03909 
03910         /* Might be a symlink. */
03911         if(SMB_VFS_LSTAT(conn, directory, &st) != 0) {
03912                 return map_nt_error_from_unix(errno);
03913         }
03914 
03915         if (S_ISLNK(st.st_mode)) {
03916                 /* Is what it points to a directory ? */
03917                 if(SMB_VFS_STAT(conn, directory, &st) != 0) {
03918                         return map_nt_error_from_unix(errno);
03919                 }
03920                 if (!(S_ISDIR(st.st_mode))) {
03921                         return NT_STATUS_NOT_A_DIRECTORY;
03922                 }
03923                 ret = SMB_VFS_UNLINK(conn,directory);
03924         } else {
03925                 ret = SMB_VFS_RMDIR(conn,directory);
03926         }
03927         if (ret == 0) {
03928                 notify_fname(conn, NOTIFY_ACTION_REMOVED,
03929                              FILE_NOTIFY_CHANGE_DIR_NAME,
03930                              directory);
03931                 return NT_STATUS_OK;
03932         }
03933 
03934         if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
03935                 /* 
03936                  * Check to see if the only thing in this directory are
03937                  * vetoed files/directories. If so then delete them and
03938                  * retry. If we fail to delete any of them (and we *don't*
03939                  * do a recursive delete) then fail the rmdir.
03940                  */
03941                 const char *dname;
03942                 long dirpos = 0;
03943                 struct smb_Dir *dir_hnd = OpenDir(conn, directory, NULL, 0);
03944 
03945                 if(dir_hnd == NULL) {
03946                         errno = ENOTEMPTY;
03947                         goto err;
03948                 }
03949 
03950                 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
03951                         if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
03952                                 continue;
03953                         if (!is_visible_file(conn, directory, dname, &st, False))
03954                                 continue;
03955                         if(!IS_VETO_PATH(conn, dname)) {
03956                                 CloseDir(dir_hnd);
03957                                 errno = ENOTEMPTY;
03958                                 goto err;
03959                         }
03960                 }
03961 
03962                 /* We only have veto files/directories. Recursive delete. */
03963 
03964                 RewindDir(dir_hnd,&dirpos);
03965                 while ((dname = ReadDirName(dir_hnd,&dirpos))) {
03966                         pstring fullname;
03967 
03968                         if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0))
03969                                 continue;
03970                         if (!is_visible_file(conn, directory, dname, &st, False))
03971                                 continue;
03972 
03973                         /* Construct the full name. */
03974                         if(strlen(directory) + strlen(dname) + 1 >= sizeof(fullname)) {
03975                                 errno = ENOMEM;
03976                                 break;
03977                         }
03978 
03979                         pstrcpy(fullname, directory);
03980                         pstrcat(fullname, "/");
03981                         pstrcat(fullname, dname);
03982                    
03983                         if(SMB_VFS_LSTAT(conn,fullname, &st) != 0)
03984                                 break;
03985                         if(st.st_mode & S_IFDIR) {
03986                                 if(lp_recursive_veto_delete(SNUM(conn))) {
03987                                         if(!recursive_rmdir(conn, fullname))
03988                                                 break;
03989                                 }
03990                                 if(SMB_VFS_RMDIR(conn,fullname) != 0)
03991                                         break;
03992                         } else if(SMB_VFS_UNLINK(conn,fullname) != 0)
03993                                 break;
03994                 }
03995                 CloseDir(dir_hnd);
03996                 /* Retry the rmdir */
03997                 ret = SMB_VFS_RMDIR(conn,directory);
03998         }
03999 
04000   err:
04001 
04002         if (ret != 0) {
04003                 DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
04004                          "%s\n", directory,strerror(errno)));
04005                 return map_nt_error_from_unix(errno);
04006         }
04007 
04008         notify_fname(conn, NOTIFY_ACTION_REMOVED,
04009                      FILE_NOTIFY_CHANGE_DIR_NAME,
04010                      directory);
04011 
04012         return NT_STATUS_OK;
04013 }
04014 
04015 /****************************************************************************
04016  Reply to a rmdir.
04017 ****************************************************************************/
04018 
04019 int reply_rmdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
04020 {
04021         pstring directory;
04022         int outsize = 0;
04023         SMB_STRUCT_STAT sbuf;
04024         NTSTATUS status;
04025         START_PROFILE(SMBrmdir);
04026 
04027         srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
04028         if (!NT_STATUS_IS_OK(status)) {
04029                 END_PROFILE(SMBrmdir);
04030                 return ERROR_NT(status);
04031         }
04032 
04033         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, directory);
04034         if (!NT_STATUS_IS_OK(status)) {
04035                 END_PROFILE(SMBrmdir);
04036                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
04037                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
04038                 }
04039                 return ERROR_NT(status);
04040         }
04041 
04042         status = unix_convert(conn, directory, False, NULL, &sbuf);
04043         if (!NT_STATUS_IS_OK(status)) {
04044                 END_PROFILE(SMBrmdir);
04045                 return ERROR_NT(status);
04046         }
04047   
04048         status = check_name(conn, directory);
04049         if (!NT_STATUS_IS_OK(status)) {
04050                 END_PROFILE(SMBrmdir);
04051                 return ERROR_NT(status);
04052         }
04053 
04054         dptr_closepath(directory,SVAL(inbuf,smb_pid));
04055         status = rmdir_internals(conn, directory);
04056         if (!NT_STATUS_IS_OK(status)) {
04057                 END_PROFILE(SMBrmdir);
04058                 return ERROR_NT(status);
04059         }
04060  
04061         outsize = set_message(outbuf,0,0,False);
04062   
04063         DEBUG( 3, ( "rmdir %s\n", directory ) );
04064   
04065         END_PROFILE(SMBrmdir);
04066         return(outsize);
04067 }
04068 
04069 /*******************************************************************
04070  Resolve wildcards in a filename rename.
04071  Note that name is in UNIX charset and thus potentially can be more
04072  than fstring buffer (255 bytes) especially in default UTF-8 case.
04073  Therefore, we use pstring inside and all calls should ensure that
04074  name2 is at least pstring-long (they do already)
04075 ********************************************************************/
04076 
04077 static BOOL resolve_wildcards(const char *name1, char *name2)
04078 {
04079         pstring root1,root2;
04080         pstring ext1,ext2;
04081         char *p,*p2, *pname1, *pname2;
04082         int available_space, actual_space;
04083         
04084         pname1 = strrchr_m(name1,'/');
04085         pname2 = strrchr_m(name2,'/');
04086 
04087         if (!pname1 || !pname2)
04088                 return(False);
04089   
04090         pstrcpy(root1,pname1);
04091         pstrcpy(root2,pname2);
04092         p = strrchr_m(root1,'.');
04093         if (p) {
04094                 *p = 0;
04095                 pstrcpy(ext1,p+1);
04096         } else {
04097                 pstrcpy(ext1,"");    
04098         }
04099         p = strrchr_m(root2,'.');
04100         if (p) {
04101                 *p = 0;
04102                 pstrcpy(ext2,p+1);
04103         } else {
04104                 pstrcpy(ext2,"");    
04105         }
04106 
04107         p = root1;
04108         p2 = root2;
04109         while (*p2) {
04110                 if (*p2 == '?') {
04111                         *p2 = *p;
04112                         p2++;
04113                 } else if (*p2 == '*') {
04114                         pstrcpy(p2, p);
04115                         break;
04116                 } else {
04117                         p2++;
04118                 }
04119                 if (*p)
04120                         p++;
04121         }
04122 
04123         p = ext1;
04124         p2 = ext2;
04125         while (*p2) {
04126                 if (*p2 == '?') {
04127                         *p2 = *p;
04128                         p2++;
04129                 } else if (*p2 == '*') {
04130                         pstrcpy(p2, p);
04131                         break;
04132                 } else {
04133                         p2++;
04134                 }
04135                 if (*p)
04136                         p++;
04137         }
04138 
04139         available_space = sizeof(pstring) - PTR_DIFF(pname2, name2);
04140         
04141         if (ext2[0]) {
04142                 actual_space = snprintf(pname2, available_space - 1, "%s.%s", root2, ext2);
04143                 if (actual_space >= available_space - 1) {
04144                         DEBUG(1,("resolve_wildcards: can't fit resolved name into specified buffer (overrun by %d bytes)\n",
04145                                 actual_space - available_space));
04146                 }
04147         } else {
04148                 pstrcpy_base(pname2, root2, name2);
04149         }
04150 
04151         return(True);
04152 }
04153 
04154 /****************************************************************************
04155  Ensure open files have their names updated. Updated to notify other smbd's
04156  asynchronously.
04157 ****************************************************************************/
04158 
04159 static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck,
04160                                 SMB_DEV_T dev, SMB_INO_T inode, const char *newname)
04161 {
04162         files_struct *fsp;
04163         BOOL did_rename = False;
04164 
04165         for(fsp = file_find_di_first(dev, inode); fsp; fsp = file_find_di_next(fsp)) {
04166                 /* fsp_name is a relative path under the fsp. To change this for other
04167                    sharepaths we need to manipulate relative paths. */
04168                 /* TODO - create the absolute path and manipulate the newname
04169                    relative to the sharepath. */
04170                 if (fsp->conn != conn) {
04171                         continue;
04172                 }
04173                 DEBUG(10,("rename_open_files: renaming file fnum %d (dev = %x, inode = %.0f) from %s -> %s\n",
04174                         fsp->fnum, (unsigned int)fsp->dev, (double)fsp->inode,
04175                         fsp->fsp_name, newname ));
04176                 string_set(&fsp->fsp_name, newname);
04177                 did_rename = True;
04178         }
04179 
04180         if (!did_rename) {
04181                 DEBUG(10,("rename_open_files: no open files on dev %x, inode %.0f for %s\n",
04182                         (unsigned int)dev, (double)inode, newname ));
04183         }
04184 
04185         /* Send messages to all smbd's (not ourself) that the name has changed. */
04186         rename_share_filename(lck, conn->connectpath, newname);
04187 }
04188 
04189 /****************************************************************************
04190  We need to check if the source path is a parent directory of the destination
04191  (ie. a rename of /foo/bar/baz -> /foo/bar/baz/bibble/bobble. If so we must
04192  refuse the rename with a sharing violation. Under UNIX the above call can
04193  *succeed* if /foo/bar/baz is a symlink to another area in the share. We
04194  probably need to check that the client is a Windows one before disallowing
04195  this as a UNIX client (one with UNIX extensions) can know the source is a
04196  symlink and make this decision intelligently. Found by an excellent bug
04197  report from <AndyLiebman@aol.com>.
04198 ****************************************************************************/
04199 
04200 static BOOL rename_path_prefix_equal(const char *src, const char *dest)
04201 {
04202         const char *psrc = src;
04203         const char *pdst = dest;
04204         size_t slen;
04205 
04206         if (psrc[0] == '.' && psrc[1] == '/') {
04207                 psrc += 2;
04208         }
04209         if (pdst[0] == '.' && pdst[1] == '/') {
04210                 pdst += 2;
04211         }
04212         if ((slen = strlen(psrc)) > strlen(pdst)) {
04213                 return False;
04214         }
04215         return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
04216 }
04217 
04218 /****************************************************************************
04219  Rename an open file - given an fsp.
04220 ****************************************************************************/
04221 
04222 NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstring newname, uint32 attrs, BOOL replace_if_exists)
04223 {
04224         SMB_STRUCT_STAT sbuf;
04225         pstring newname_last_component;
04226         NTSTATUS status = NT_STATUS_OK;
04227         BOOL dest_exists;
04228         struct share_mode_lock *lck = NULL;
04229 
04230         ZERO_STRUCT(sbuf);
04231 
04232         status = unix_convert(conn, newname, False, newname_last_component, &sbuf);
04233 
04234         /* If an error we expect this to be NT_STATUS_OBJECT_PATH_NOT_FOUND */
04235 
04236         if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(NT_STATUS_OBJECT_PATH_NOT_FOUND, status)) {
04237                 return status;
04238         }
04239 
04240         status = check_name(conn, newname);
04241         if (!NT_STATUS_IS_OK(status)) {
04242                 return status;
04243         }
04244   
04245         /* Ensure newname contains a '/' */
04246         if(strrchr_m(newname,'/') == 0) {
04247                 pstring tmpstr;
04248                 
04249                 pstrcpy(tmpstr, "./");
04250                 pstrcat(tmpstr, newname);
04251                 pstrcpy(newname, tmpstr);
04252         }
04253 
04254         /*
04255          * Check for special case with case preserving and not
04256          * case sensitive. If the old last component differs from the original
04257          * last component only by case, then we should allow
04258          * the rename (user is trying to change the case of the
04259          * filename).
04260          */
04261 
04262         if((conn->case_sensitive == False) && (conn->case_preserve == True) &&
04263                         strequal(newname, fsp->fsp_name)) {
04264                 char *p;
04265                 pstring newname_modified_last_component;
04266 
04267                 /*
04268                  * Get the last component of the modified name.
04269                  * Note that we guarantee that newname contains a '/'
04270                  * character above.
04271                  */
04272                 p = strrchr_m(newname,'/');
04273                 pstrcpy(newname_modified_last_component,p+1);
04274                         
04275                 if(strcsequal(newname_modified_last_component, 
04276                               newname_last_component) == False) {
04277                         /*
04278                          * Replace the modified last component with
04279                          * the original.
04280                          */
04281                         pstrcpy(p+1, newname_last_component);
04282                 }
04283         }
04284 
04285         /*
04286          * If the src and dest names are identical - including case,
04287          * don't do the rename, just return success.
04288          */
04289 
04290         if (strcsequal(fsp->fsp_name, newname)) {
04291                 DEBUG(3,("rename_internals_fsp: identical names in rename %s - returning success\n",
04292                         newname));
04293                 return NT_STATUS_OK;
04294         }
04295 
04296         dest_exists = vfs_object_exist(conn,newname,NULL);
04297 
04298         if(!replace_if_exists && dest_exists) {
04299                 DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
04300                         fsp->fsp_name,newname));
04301                 return NT_STATUS_OBJECT_NAME_COLLISION;
04302         }
04303 
04304         /* Ensure we have a valid stat struct for the source. */
04305         if (fsp->fh->fd != -1) {
04306                 if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) {
04307                         return map_nt_error_from_unix(errno);
04308                 }
04309         } else {
04310                 if (SMB_VFS_STAT(conn,fsp->fsp_name,&sbuf) == -1) {
04311                         return map_nt_error_from_unix(errno);
04312                 }
04313         }
04314 
04315         status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
04316 
04317         if (!NT_STATUS_IS_OK(status)) {
04318                 DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
04319                         nt_errstr(status), fsp->fsp_name,newname));
04320                 if (NT_STATUS_EQUAL(status,NT_STATUS_SHARING_VIOLATION))
04321                         status = NT_STATUS_ACCESS_DENIED;
04322                 return status;
04323         }
04324 
04325         if (rename_path_prefix_equal(fsp->fsp_name, newname)) {
04326                 return NT_STATUS_ACCESS_DENIED;
04327         }
04328 
04329         lck = get_share_mode_lock(NULL, fsp->dev, fsp->inode, NULL, NULL);
04330 
04331         if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
04332                 uint32 create_options = fsp->fh->private_options;
04333 
04334                 DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
04335                         fsp->fsp_name,newname));
04336 
04337                 rename_open_files(conn, lck, fsp->dev, fsp->inode, newname);
04338 
04339                 /*
04340                  * A rename acts as a new file create w.r.t. allowing an initial delete
04341                  * on close, probably because in Windows there is a new handle to the
04342                  * new file. If initial delete on close was requested but not
04343                  * originally set, we need to set it here. This is probably not 100% correct,
04344                  * but will work for the CIFSFS client which in non-posix mode
04345                  * depends on these semantics. JRA.
04346                  */
04347 
04348                 set_allow_initial_delete_on_close(lck, fsp, True);
04349 
04350                 if (create_options & FILE_DELETE_ON_CLOSE) {
04351                         status = can_set_delete_on_close(fsp, True, 0);
04352 
04353                         if (NT_STATUS_IS_OK(status)) {
04354                                 /* Note that here we set the *inital* delete on close flag,
04355                                  * not the regular one. The magic gets handled in close. */
04356                                 fsp->initial_delete_on_close = True;
04357                         }
04358                 }
04359                 TALLOC_FREE(lck);
04360                 return NT_STATUS_OK;    
04361         }
04362 
04363         TALLOC_FREE(lck);
04364 
04365         if (errno == ENOTDIR || errno == EISDIR) {
04366                 status = NT_STATUS_OBJECT_NAME_COLLISION;
04367         } else {
04368                 status = map_nt_error_from_unix(errno);
04369         }
04370                 
04371         DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
04372                 nt_errstr(status), fsp->fsp_name,newname));
04373 
04374         return status;
04375 }
04376 
04377 /*
04378  * Do the notify calls from a rename
04379  */
04380 
04381 static void notify_rename(connection_struct *conn, BOOL is_dir,
04382                           const char *oldpath, const char *newpath)
04383 {
04384         char *olddir, *newdir;
04385         const char *oldname, *newname;
04386         uint32 mask;
04387 
04388         mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
04389                 : FILE_NOTIFY_CHANGE_FILE_NAME;
04390 
04391         if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
04392             || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
04393                 TALLOC_FREE(olddir);
04394                 return;
04395         }
04396 
04397         if (strcmp(olddir, newdir) == 0) {
04398                 notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
04399                 notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
04400         }
04401         else {
04402                 notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
04403                 notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
04404         }
04405         TALLOC_FREE(olddir);
04406         TALLOC_FREE(newdir);
04407 
04408         /* this is a strange one. w2k3 gives an additional event for
04409            CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
04410            files, but not directories */
04411         if (!is_dir) {
04412                 notify_fname(conn, NOTIFY_ACTION_MODIFIED,
04413                              FILE_NOTIFY_CHANGE_ATTRIBUTES
04414                              |FILE_NOTIFY_CHANGE_CREATION,
04415                              newpath);
04416         }
04417 }
04418 
04419 /****************************************************************************
04420  The guts of the rename command, split out so it may be called by the NT SMB
04421  code. 
04422 ****************************************************************************/
04423 
04424 NTSTATUS rename_internals(connection_struct *conn,
04425                                 pstring name,
04426                                 pstring newname,
04427                                 uint32 attrs,
04428                                 BOOL replace_if_exists,
04429                                 BOOL src_has_wild,
04430                                 BOOL dest_has_wild)
04431 {
04432         pstring directory;
04433         pstring mask;
04434         pstring last_component_src;
04435         pstring last_component_dest;
04436         char *p;
04437         int count=0;
04438         NTSTATUS status = NT_STATUS_OK;
04439         SMB_STRUCT_STAT sbuf1, sbuf2;
04440         struct share_mode_lock *lck = NULL;
04441         struct smb_Dir *dir_hnd = NULL;
04442         const char *dname;
04443         long offset = 0;
04444         pstring destname;
04445 
04446         *directory = *mask = 0;
04447 
04448         ZERO_STRUCT(sbuf1);
04449         ZERO_STRUCT(sbuf2);
04450 
04451         status = unix_convert(conn, name, src_has_wild, last_component_src, &sbuf1);
04452         if (!NT_STATUS_IS_OK(status)) {
04453                 return status;
04454         }
04455 
04456         status = unix_convert(conn, newname, dest_has_wild, last_component_dest, &sbuf2);
04457         if (!NT_STATUS_IS_OK(status)) {
04458                 return status;
04459         }
04460 
04461         /*
04462          * Split the old name into directory and last component
04463          * strings. Note that unix_convert may have stripped off a 
04464          * leading ./ from both name and newname if the rename is 
04465          * at the root of the share. We need to make sure either both
04466          * name and newname contain a / character or neither of them do
04467          * as this is checked in resolve_wildcards().
04468          */
04469 
04470         p = strrchr_m(name,'/');
04471         if (!p) {
04472                 pstrcpy(directory,".");
04473                 pstrcpy(mask,name);
04474         } else {
04475                 *p = 0;
04476                 pstrcpy(directory,name);
04477                 pstrcpy(mask,p+1);
04478                 *p = '/'; /* Replace needed for exceptional test below. */
04479         }
04480 
04481         /*
04482          * We should only check the mangled cache
04483          * here if unix_convert failed. This means
04484          * that the path in 'mask' doesn't exist
04485          * on the file system and so we need to look
04486          * for a possible mangle. This patch from
04487          * Tine Smukavec <valentin.smukavec@hermes.si>.
04488          */
04489 
04490         if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
04491                 mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
04492         }
04493 
04494         if (!src_has_wild) {
04495                 /*
04496                  * No wildcards - just process the one file.
04497                  */
04498                 BOOL is_short_name = mangle_is_8_3(name, True, conn->params);
04499 
04500                 /* Add a terminating '/' to the directory name. */
04501                 pstrcat(directory,"/");
04502                 pstrcat(directory,mask);
04503                 
04504                 /* Ensure newname contains a '/' also */
04505                 if(strrchr_m(newname,'/') == 0) {
04506                         pstring tmpstr;
04507                         
04508                         pstrcpy(tmpstr, "./");
04509                         pstrcat(tmpstr, newname);
04510                         pstrcpy(newname, tmpstr);
04511                 }
04512                 
04513                 DEBUG(3, ("rename_internals: case_sensitive = %d, "
04514                           "case_preserve = %d, short case preserve = %d, "
04515                           "directory = %s, newname = %s, "
04516                           "last_component_dest = %s, is_8_3 = %d\n", 
04517                           conn->case_sensitive, conn->case_preserve,
04518                           conn->short_case_preserve, directory, 
04519                           newname, last_component_dest, is_short_name));
04520 
04521                 /* Ensure the source name is valid for us to access. */
04522                 status = check_name(conn, directory);
04523                 if (!NT_STATUS_IS_OK(status)) {
04524                         return status;
04525                 }
04526 
04527                 /* The dest name still may have wildcards. */
04528                 if (dest_has_wild) {
04529                         if (!resolve_wildcards(directory,newname)) {
04530                                 DEBUG(6, ("rename_internals: resolve_wildcards %s %s failed\n", 
04531                                           directory,newname));
04532                                 return NT_STATUS_NO_MEMORY;
04533                         }
04534                 }
04535                                 
04536                 /*
04537                  * Check for special case with case preserving and not
04538                  * case sensitive, if directory and newname are identical,
04539                  * and the old last component differs from the original
04540                  * last component only by case, then we should allow
04541                  * the rename (user is trying to change the case of the
04542                  * filename).
04543                  */
04544                 if((conn->case_sensitive == False) && 
04545                    (((conn->case_preserve == True) && 
04546                      (is_short_name == False)) || 
04547                     ((conn->short_case_preserve == True) && 
04548                      (is_short_name == True))) &&
04549                    strcsequal(directory, newname)) {
04550                         pstring modified_last_component;
04551 
04552                         /*
04553                          * Get the last component of the modified name.
04554                          * Note that we guarantee that newname contains a '/'
04555                          * character above.
04556                          */
04557                         p = strrchr_m(newname,'/');
04558                         pstrcpy(modified_last_component,p+1);
04559                         
04560                         if(strcsequal(modified_last_component, 
04561                                       last_component_dest) == False) {
04562                                 /*
04563                                  * Replace the modified last component with
04564                                  * the original.
04565                                  */
04566                                 pstrcpy(p+1, last_component_dest);
04567                         }
04568                 }
04569         
04570                 /* Ensure the dest name is valid for us to access. */
04571                 status = check_name(conn, newname);
04572                 if (!NT_STATUS_IS_OK(status)) {
04573                         return status;
04574                 }
04575 
04576                 /*
04577                  * The source object must exist.
04578                  */
04579 
04580                 if (!vfs_object_exist(conn, directory, &sbuf1)) {
04581                         DEBUG(3, ("rename_internals: source doesn't exist "
04582                                   "doing rename %s -> %s\n",
04583                                 directory,newname));
04584 
04585                         if (errno == ENOTDIR || errno == EISDIR
04586                             || errno == ENOENT) {
04587                                 /*
04588                                  * Must return different errors depending on
04589                                  * whether the parent directory existed or
04590                                  * not.
04591                                  */
04592 
04593                                 p = strrchr_m(directory, '/');
04594                                 if (!p)
04595                                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04596                                 *p = '\0';
04597                                 if (vfs_object_exist(conn, directory, NULL))
04598                                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04599                                 return NT_STATUS_OBJECT_PATH_NOT_FOUND;
04600                         }
04601                         status = map_nt_error_from_unix(errno);
04602                         DEBUG(3, ("rename_internals: Error %s rename %s -> "
04603                                   "%s\n", nt_errstr(status), directory,
04604                                   newname));
04605 
04606                         return status;
04607                 }
04608 
04609                 status = can_rename(conn,directory,attrs,&sbuf1,False);
04610 
04611                 if (!NT_STATUS_IS_OK(status)) {
04612                         DEBUG(3,("rename_internals: Error %s rename %s -> "
04613                                  "%s\n", nt_errstr(status), directory,
04614                                  newname));
04615                         return status;
04616                 }
04617 
04618                 /*
04619                  * If the src and dest names are identical - including case,
04620                  * don't do the rename, just return success.
04621                  */
04622 
04623                 if (strcsequal(directory, newname)) {
04624                         DEBUG(3, ("rename_internals: identical names in "
04625                                   "rename %s - returning success\n",
04626                                   directory));
04627                         return NT_STATUS_OK;
04628                 }
04629 
04630                 if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
04631                         DEBUG(3,("rename_internals: dest exists doing "
04632                                  "rename %s -> %s\n", directory, newname));
04633                         return NT_STATUS_OBJECT_NAME_COLLISION;
04634                 }
04635 
04636                 if (rename_path_prefix_equal(directory, newname)) {
04637                         return NT_STATUS_SHARING_VIOLATION;
04638                 }
04639 
04640                 lck = get_share_mode_lock(NULL, sbuf1.st_dev, sbuf1.st_ino,
04641                                           NULL, NULL);
04642 
04643                 if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
04644                         DEBUG(3,("rename_internals: succeeded doing rename "
04645                                  "on %s -> %s\n", directory, newname));
04646                         rename_open_files(conn, lck, sbuf1.st_dev,
04647                                           sbuf1.st_ino, newname);
04648                         TALLOC_FREE(lck);
04649                         notify_rename(conn, S_ISDIR(sbuf1.st_mode),
04650                                       directory, newname);
04651                         return NT_STATUS_OK;    
04652                 }
04653 
04654                 TALLOC_FREE(lck);
04655                 if (errno == ENOTDIR || errno == EISDIR) {
04656                         status = NT_STATUS_OBJECT_NAME_COLLISION;
04657                 } else {
04658                         status = map_nt_error_from_unix(errno);
04659                 }
04660                 
04661                 DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
04662                         nt_errstr(status), directory,newname));
04663 
04664                 return status;
04665         }
04666 
04667         /*
04668          * Wildcards - process each file that matches.
04669          */
04670         if (strequal(mask,"????????.???")) {
04671                 pstrcpy(mask,"*");
04672         }
04673                         
04674         status = check_name(conn, directory);
04675         if (!NT_STATUS_IS_OK(status)) {
04676                 return status;
04677         }
04678         
04679         dir_hnd = OpenDir(conn, directory, mask, attrs);
04680         if (dir_hnd == NULL) {
04681                 return map_nt_error_from_unix(errno);
04682         }
04683                 
04684         status = NT_STATUS_NO_SUCH_FILE;
04685         /*
04686          * Was status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
04687          * - gentest fix. JRA
04688          */
04689                         
04690         while ((dname = ReadDirName(dir_hnd, &offset))) {
04691                 pstring fname;
04692                 BOOL sysdir_entry = False;
04693 
04694                 pstrcpy(fname,dname);
04695                                 
04696                 /* Quick check for "." and ".." */
04697                 if (fname[0] == '.') {
04698                         if (!fname[1] || (fname[1] == '.' && !fname[2])) {
04699                                 if (attrs & aDIR) {
04700                                         sysdir_entry = True;
04701                                 } else {
04702                                         continue;
04703                                 }
04704                         }
04705                 }
04706 
04707                 if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
04708                         continue;
04709                 }
04710 
04711                 if(!mask_match(fname, mask, conn->case_sensitive)) {
04712                         continue;
04713                 }
04714                                 
04715                 if (sysdir_entry) {
04716                         status = NT_STATUS_OBJECT_NAME_INVALID;
04717                         break;
04718                 }
04719 
04720                 status = NT_STATUS_ACCESS_DENIED;
04721                 slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname);
04722 
04723                 /* Ensure the source name is valid for us to access. */
04724                 status = check_name(conn, fname);
04725                 if (!NT_STATUS_IS_OK(status)) {
04726                         return status;
04727                 }
04728 
04729                 if (!vfs_object_exist(conn, fname, &sbuf1)) {
04730                         status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
04731                         DEBUG(6, ("rename %s failed. Error %s\n",
04732                                   fname, nt_errstr(status)));
04733                         continue;
04734                 }
04735                 status = can_rename(conn,fname,attrs,&sbuf1,False);
04736                 if (!NT_STATUS_IS_OK(status)) {
04737                         DEBUG(6, ("rename %s refused\n", fname));
04738                         continue;
04739                 }
04740                 pstrcpy(destname,newname);
04741                         
04742                 if (!resolve_wildcards(fname,destname)) {
04743                         DEBUG(6, ("resolve_wildcards %s %s failed\n", 
04744                                   fname, destname));
04745                         continue;
04746                 }
04747                                 
04748                 /* Ensure the dest name is valid for us to access. */
04749                 status = check_name(conn, destname);
04750                 if (!NT_STATUS_IS_OK(status)) {
04751                         return status;
04752                 }
04753 
04754                 if (strcsequal(fname,destname)) {
04755                         DEBUG(3,("rename_internals: identical names "
04756                                  "in wildcard rename %s - success\n",
04757                                  fname));
04758                         count++;
04759                         status = NT_STATUS_OK;
04760                         continue;
04761                 }
04762 
04763                 if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) {
04764                         DEBUG(6,("file_exist %s\n", destname));
04765                         status = NT_STATUS_OBJECT_NAME_COLLISION;
04766                         continue;
04767                 }
04768                                 
04769                 if (rename_path_prefix_equal(fname, destname)) {
04770                         return NT_STATUS_SHARING_VIOLATION;
04771                 }
04772 
04773                 lck = get_share_mode_lock(NULL, sbuf1.st_dev,
04774                                           sbuf1.st_ino, NULL, NULL);
04775 
04776                 if (!SMB_VFS_RENAME(conn,fname,destname)) {
04777                         rename_open_files(conn, lck, sbuf1.st_dev,
04778                                           sbuf1.st_ino, newname);
04779                         count++;
04780                         status = NT_STATUS_OK;
04781                 }
04782                 TALLOC_FREE(lck);
04783                 DEBUG(3,("rename_internals: doing rename on %s -> "
04784                          "%s\n",fname,destname));
04785         }
04786         CloseDir(dir_hnd);
04787 
04788         if (count == 0 && NT_STATUS_IS_OK(status)) {
04789                 status = map_nt_error_from_unix(errno);
04790         }
04791         
04792         return status;
04793 }
04794 
04795 /****************************************************************************
04796  Reply to a mv.
04797 ****************************************************************************/
04798 
04799 int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, 
04800              int dum_buffsize)
04801 {
04802         int outsize = 0;
04803         pstring name;
04804         pstring newname;
04805         char *p;
04806         uint32 attrs = SVAL(inbuf,smb_vwv0);
04807         NTSTATUS status;
04808         BOOL src_has_wcard = False;
04809         BOOL dest_has_wcard = False;
04810 
04811         START_PROFILE(SMBmv);
04812 
04813         p = smb_buf(inbuf) + 1;
04814         p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &src_has_wcard);
04815         if (!NT_STATUS_IS_OK(status)) {
04816                 END_PROFILE(SMBmv);
04817                 return ERROR_NT(status);
04818         }
04819         p++;
04820         p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard);
04821         if (!NT_STATUS_IS_OK(status)) {
04822                 END_PROFILE(SMBmv);
04823                 return ERROR_NT(status);
04824         }
04825         
04826         status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &src_has_wcard);
04827         if (!NT_STATUS_IS_OK(status)) {
04828                 END_PROFILE(SMBmv);
04829                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
04830                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
04831                 }
04832                 return ERROR_NT(status);
04833         }
04834 
04835         status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wcard);
04836         if (!NT_STATUS_IS_OK(status)) {
04837                 END_PROFILE(SMBmv);
04838                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
04839                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
04840                 }
04841                 return ERROR_NT(status);
04842         }
04843         
04844         DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
04845         
04846         status = rename_internals(conn, name, newname, attrs, False, src_has_wcard, dest_has_wcard);
04847         if (!NT_STATUS_IS_OK(status)) {
04848                 END_PROFILE(SMBmv);
04849                 if (open_was_deferred(SVAL(inbuf,smb_mid))) {
04850                         /* We have re-scheduled this call. */
04851                         return -1;
04852                 }
04853                 return ERROR_NT(status);
04854         }
04855 
04856         outsize = set_message(outbuf,0,0,False);
04857   
04858         END_PROFILE(SMBmv);
04859         return(outsize);
04860 }
04861 
04862 /*******************************************************************
04863  Copy a file as part of a reply_copy.
04864 ******************************************************************/
04865 
04866 /*
04867  * TODO: check error codes on all callers
04868  */
04869 
04870 NTSTATUS copy_file(connection_struct *conn,
04871                         char *src,
04872                         char *dest1,
04873                         int ofun,
04874                         int count,
04875                         BOOL target_is_directory)
04876 {
04877         SMB_STRUCT_STAT src_sbuf, sbuf2;
04878         SMB_OFF_T ret=-1;
04879         files_struct *fsp1,*fsp2;
04880         pstring dest;
04881         uint32 dosattrs;
04882         uint32 new_create_disposition;
04883         NTSTATUS status;
04884  
04885         pstrcpy(dest,dest1);
04886         if (target_is_directory) {
04887                 char *p = strrchr_m(src,'/');
04888                 if (p) {
04889                         p++;
04890                 } else {
04891                         p = src;
04892                 }
04893                 pstrcat(dest,"/");
04894                 pstrcat(dest,p);
04895         }
04896 
04897         if (!vfs_file_exist(conn,src,&src_sbuf)) {
04898                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
04899         }
04900 
04901         if (!target_is_directory && count) {
04902                 new_create_disposition = FILE_OPEN;
04903         } else {
04904                 if (!map_open_params_to_ntcreate(dest1,0,ofun,
04905                                 NULL, NULL, &new_create_disposition, NULL)) {
04906                         return NT_STATUS_INVALID_PARAMETER;
04907                 }
04908         }
04909 
04910         status = open_file_ntcreate(conn,src,&src_sbuf,
04911                         FILE_GENERIC_READ,
04912                         FILE_SHARE_READ|FILE_SHARE_WRITE,
04913                         FILE_OPEN,
04914                         0,
04915                         FILE_ATTRIBUTE_NORMAL,
04916                         INTERNAL_OPEN_ONLY,
04917                         NULL, &fsp1);
04918 
04919         if (!NT_STATUS_IS_OK(status)) {
04920                 return status;
04921         }
04922 
04923         dosattrs = dos_mode(conn, src, &src_sbuf);
04924         if (SMB_VFS_STAT(conn,dest,&sbuf2) == -1) {
04925                 ZERO_STRUCTP(&sbuf2);
04926         }
04927 
04928         status = open_file_ntcreate(conn,dest,&sbuf2,
04929                         FILE_GENERIC_WRITE,
04930                         FILE_SHARE_READ|FILE_SHARE_WRITE,
04931                         new_create_disposition,
04932                         0,
04933                         dosattrs,
04934                         INTERNAL_OPEN_ONLY,
04935                         NULL, &fsp2);
04936 
04937         if (!NT_STATUS_IS_OK(status)) {
04938                 close_file(fsp1,ERROR_CLOSE);
04939                 return status;
04940         }
04941 
04942         if ((ofun&3) == 1) {
04943                 if(SMB_VFS_LSEEK(fsp2,fsp2->fh->fd,0,SEEK_END) == -1) {
04944                         DEBUG(0,("copy_file: error - vfs lseek returned error %s\n", strerror(errno) ));
04945                         /*
04946                          * Stop the copy from occurring.
04947                          */
04948                         ret = -1;
04949                         src_sbuf.st_size = 0;
04950                 }
04951         }
04952   
04953         if (src_sbuf.st_size) {
04954                 ret = vfs_transfer_file(fsp1, fsp2, src_sbuf.st_size);
04955         }
04956 
04957         close_file(fsp1,NORMAL_CLOSE);
04958 
04959         /* Ensure the modtime is set correctly on the destination file. */
04960         fsp_set_pending_modtime( fsp2, get_mtimespec(&src_sbuf));
04961 
04962         /*
04963          * As we are opening fsp1 read-only we only expect
04964          * an error on close on fsp2 if we are out of space.
04965          * Thus we don't look at the error return from the
04966          * close of fsp1.
04967          */
04968         status = close_file(fsp2,NORMAL_CLOSE);
04969 
04970         if (!NT_STATUS_IS_OK(status)) {
04971                 return status;
04972         }
04973 
04974         if (ret != (SMB_OFF_T)src_sbuf.st_size) {
04975                 return NT_STATUS_DISK_FULL;
04976         }
04977 
04978         return NT_STATUS_OK;
04979 }
04980 
04981 /****************************************************************************
04982  Reply to a file copy.
04983 ****************************************************************************/
04984 
04985 int reply_copy(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
04986 {
04987         int outsize = 0;
04988         pstring name;
04989         pstring directory;
04990         pstring mask,newname;
04991         char *p;
04992         int count=0;
04993         int error = ERRnoaccess;
04994         int err = 0;
04995         int tid2 = SVAL(inbuf,smb_vwv0);
04996         int ofun = SVAL(inbuf,smb_vwv1);
04997         int flags = SVAL(inbuf,smb_vwv2);
04998         BOOL target_is_directory=False;
04999         BOOL source_has_wild = False;
05000         BOOL dest_has_wild = False;
05001         SMB_STRUCT_STAT sbuf1, sbuf2;
05002         NTSTATUS status;
05003         START_PROFILE(SMBcopy);
05004 
05005         *directory = *mask = 0;
05006 
05007         p = smb_buf(inbuf);
05008         p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &source_has_wild);
05009         if (!NT_STATUS_IS_OK(status)) {
05010                 END_PROFILE(SMBcopy);
05011                 return ERROR_NT(status);
05012         }
05013         p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wild);
05014         if (!NT_STATUS_IS_OK(status)) {
05015                 END_PROFILE(SMBcopy);
05016                 return ERROR_NT(status);
05017         }
05018    
05019         DEBUG(3,("reply_copy : %s -> %s\n",name,newname));
05020    
05021         if (tid2 != conn->cnum) {
05022                 /* can't currently handle inter share copies XXXX */
05023                 DEBUG(3,("Rejecting inter-share copy\n"));
05024                 END_PROFILE(SMBcopy);
05025                 return ERROR_DOS(ERRSRV,ERRinvdevice);
05026         }
05027 
05028         status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, name, &source_has_wild);
05029         if (!NT_STATUS_IS_OK(status)) {
05030                 END_PROFILE(SMBcopy);
05031                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
05032                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
05033                 }
05034                 return ERROR_NT(status);
05035         }
05036 
05037         status = resolve_dfspath_wcard(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newname, &dest_has_wild);
05038         if (!NT_STATUS_IS_OK(status)) {
05039                 END_PROFILE(SMBcopy);
05040                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
05041                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
05042                 }
05043                 return ERROR_NT(status);
05044         }
05045 
05046         status = unix_convert(conn, name, source_has_wild, NULL, &sbuf1);
05047         if (!NT_STATUS_IS_OK(status)) {
05048                 END_PROFILE(SMBcopy);
05049                 return ERROR_NT(status);
05050         }
05051 
05052         status = unix_convert(conn, newname, dest_has_wild, NULL, &sbuf2);
05053         if (!NT_STATUS_IS_OK(status)) {
05054                 END_PROFILE(SMBcopy);
05055                 return ERROR_NT(status);
05056         }
05057 
05058         target_is_directory = VALID_STAT_OF_DIR(sbuf2);
05059 
05060         if ((flags&1) && target_is_directory) {
05061                 END_PROFILE(SMBcopy);
05062                 return ERROR_DOS(ERRDOS,ERRbadfile);
05063         }
05064 
05065         if ((flags&2) && !target_is_directory) {
05066                 END_PROFILE(SMBcopy);
05067                 return ERROR_DOS(ERRDOS,ERRbadpath);
05068         }
05069 
05070         if ((flags&(1<<5)) && VALID_STAT_OF_DIR(sbuf1)) {
05071                 /* wants a tree copy! XXXX */
05072                 DEBUG(3,("Rejecting tree copy\n"));
05073                 END_PROFILE(SMBcopy);
05074                 return ERROR_DOS(ERRSRV,ERRerror);
05075         }
05076 
05077         p = strrchr_m(name,'/');
05078         if (!p) {
05079                 pstrcpy(directory,"./");
05080                 pstrcpy(mask,name);
05081         } else {
05082                 *p = 0;
05083                 pstrcpy(directory,name);
05084                 pstrcpy(mask,p+1);
05085         }
05086 
05087         /*
05088          * We should only check the mangled cache
05089          * here if unix_convert failed. This means
05090          * that the path in 'mask' doesn't exist
05091          * on the file system and so we need to look
05092          * for a possible mangle. This patch from
05093          * Tine Smukavec <valentin.smukavec@hermes.si>.
05094          */
05095 
05096         if (!VALID_STAT(sbuf1) && mangle_is_mangled(mask, conn->params)) {
05097                 mangle_check_cache( mask, sizeof(pstring)-1, conn->params );
05098         }
05099 
05100         if (!source_has_wild) {
05101                 pstrcat(directory,"/");
05102                 pstrcat(directory,mask);
05103                 if (dest_has_wild) {
05104                         if (!resolve_wildcards(directory,newname)) {
05105                                 END_PROFILE(SMBcopy);
05106                                 return ERROR_NT(NT_STATUS_NO_MEMORY);
05107                         }
05108                 }
05109 
05110                 status = check_name(conn, directory);
05111                 if (!NT_STATUS_IS_OK(status)) {
05112                         return ERROR_NT(status);
05113                 }
05114                 
05115                 status = check_name(conn, newname);
05116                 if (!NT_STATUS_IS_OK(status)) {
05117                         return ERROR_NT(status);
05118                 }
05119                 
05120                 status = copy_file(conn,directory,newname,ofun,
05121                                         count,target_is_directory);
05122 
05123                 if(!NT_STATUS_IS_OK(status)) {
05124                         END_PROFILE(SMBcopy);
05125                         return ERROR_NT(status);
05126                 } else {
05127                         count++;
05128                 }
05129         } else {
05130                 struct smb_Dir *dir_hnd = NULL;
05131                 const char *dname;
05132                 long offset = 0;
05133                 pstring destname;
05134 
05135                 if (strequal(mask,"????????.???"))
05136                         pstrcpy(mask,"*");
05137 
05138                 status = check_name(conn, directory);
05139                 if (!NT_STATUS_IS_OK(status)) {
05140                         return ERROR_NT(status);
05141                 }
05142                 
05143                 dir_hnd = OpenDir(conn, directory, mask, 0);
05144                 if (dir_hnd == NULL) {
05145                         status = map_nt_error_from_unix(errno);
05146                         return ERROR_NT(status);
05147                 }
05148 
05149                 error = ERRbadfile;
05150 
05151                 while ((dname = ReadDirName(dir_hnd, &offset))) {
05152                         pstring fname;
05153                         pstrcpy(fname,dname);
05154     
05155                         if (!is_visible_file(conn, directory, dname, &sbuf1, False)) {
05156                                 continue;
05157                         }
05158 
05159                         if(!mask_match(fname, mask, conn->case_sensitive)) {
05160                                 continue;
05161                         }
05162 
05163                         error = ERRnoaccess;
05164                         slprintf(fname,sizeof(fname)-1, "%s/%s",directory,dname);
05165                         pstrcpy(destname,newname);
05166                         if (!resolve_wildcards(fname,destname)) {
05167                                 continue;
05168                         }
05169 
05170                         status = check_name(conn, fname);
05171                         if (!NT_STATUS_IS_OK(status)) {
05172                                 CloseDir(dir_hnd);
05173                                 return ERROR_NT(status);
05174                         }
05175                 
05176                         status = check_name(conn, destname);
05177                         if (!NT_STATUS_IS_OK(status)) {
05178                                 CloseDir(dir_hnd);
05179                                 return ERROR_NT(status);
05180                         }
05181                 
05182                         DEBUG(3,("reply_copy : doing copy on %s -> %s\n",fname, destname));
05183 
05184                         status = copy_file(conn,fname,destname,ofun,
05185                                         count,target_is_directory);
05186                         if (NT_STATUS_IS_OK(status)) {
05187                                 count++;
05188                         }
05189                 }
05190                 CloseDir(dir_hnd);
05191         }
05192   
05193         if (count == 0) {
05194                 if(err) {
05195                         /* Error on close... */
05196                         errno = err;
05197                         END_PROFILE(SMBcopy);
05198                         return(UNIXERROR(ERRHRD,ERRgeneral));
05199                 }
05200 
05201                 END_PROFILE(SMBcopy);
05202                 return ERROR_DOS(ERRDOS,error);
05203         }
05204   
05205         outsize = set_message(outbuf,1,0,True);
05206         SSVAL(outbuf,smb_vwv0,count);
05207 
05208         END_PROFILE(SMBcopy);
05209         return(outsize);
05210 }
05211 
05212 /****************************************************************************
05213  Reply to a setdir.
05214 ****************************************************************************/
05215 
05216 int reply_setdir(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
05217 {
05218         int snum;
05219         int outsize = 0;
05220         pstring newdir;
05221         NTSTATUS status;
05222 
05223         START_PROFILE(pathworks_setdir);
05224   
05225         snum = SNUM(conn);
05226         if (!CAN_SETDIR(snum)) {
05227                 END_PROFILE(pathworks_setdir);
05228                 return ERROR_DOS(ERRDOS,ERRnoaccess);
05229         }
05230 
05231         srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status);
05232         if (!NT_STATUS_IS_OK(status)) {
05233                 END_PROFILE(pathworks_setdir);
05234                 return ERROR_NT(status);
05235         }
05236   
05237         status = resolve_dfspath(conn, SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES, newdir);
05238         if (!NT_STATUS_IS_OK(status)) {
05239                 END_PROFILE(pathworks_setdir);
05240                 if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
05241                         return ERROR_BOTH(NT_STATUS_PATH_NOT_COVERED, ERRSRV, ERRbadpath);
05242                 }
05243                 return ERROR_NT(status);
05244         }
05245 
05246         if (strlen(newdir) != 0) {
05247                 if (!vfs_directory_exist(conn,newdir,NULL)) {
05248                         END_PROFILE(pathworks_setdir);
05249                         return ERROR_DOS(ERRDOS,ERRbadpath);
05250                 }
05251                 set_conn_connectpath(conn,newdir);
05252         }
05253   
05254         outsize = set_message(outbuf,0,0,False);
05255         SCVAL(outbuf,smb_reh,CVAL(inbuf,smb_reh));
05256   
05257         DEBUG(3,("setdir %s\n", newdir));
05258 
05259         END_PROFILE(pathworks_setdir);
05260         return(outsize);
05261 }
05262 
05263 #undef DBGC_CLASS
05264 #define DBGC_CLASS DBGC_LOCKING
05265 
05266 /****************************************************************************
05267  Get a lock pid, dealing with large count requests.
05268 ****************************************************************************/
05269 
05270 uint32 get_lock_pid( char *data, int data_offset, BOOL large_file_format)
05271 {
05272         if(!large_file_format)
05273                 return (uint32)SVAL(data,SMB_LPID_OFFSET(data_offset));
05274         else
05275                 return (uint32)SVAL(data,SMB_LARGE_LPID_OFFSET(data_offset));
05276 }
05277 
05278 /****************************************************************************
05279  Get a lock count, dealing with large count requests.
05280 ****************************************************************************/
05281 
05282 SMB_BIG_UINT get_lock_count( char *data, int data_offset, BOOL large_file_format)
05283 {
05284         SMB_BIG_UINT count = 0;
05285 
05286         if(!large_file_format) {
05287                 count = (SMB_BIG_UINT)IVAL(data,SMB_LKLEN_OFFSET(data_offset));
05288         } else {
05289 
05290 #if defined(HAVE_LONGLONG)
05291                 count = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset))) << 32) |
05292                         ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)));
05293 #else /* HAVE_LONGLONG */
05294 
05295                 /*
05296                  * NT4.x seems to be broken in that it sends large file (64 bit)
05297                  * lockingX calls even if the CAP_LARGE_FILES was *not*
05298                  * negotiated. For boxes without large unsigned ints truncate the
05299                  * lock count by dropping the top 32 bits.
05300                  */
05301 
05302                 if(IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)) != 0) {
05303                         DEBUG(3,("get_lock_count: truncating lock count (high)0x%x (low)0x%x to just low count.\n",
05304                                 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset)),
05305                                 (unsigned int)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset)) ));
05306                                 SIVAL(data,SMB_LARGE_LKLEN_OFFSET_HIGH(data_offset),0);
05307                 }
05308 
05309                 count = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKLEN_OFFSET_LOW(data_offset));
05310 #endif /* HAVE_LONGLONG */
05311         }
05312 
05313         return count;
05314 }
05315 
05316 #if !defined(HAVE_LONGLONG)
05317 /****************************************************************************
05318  Pathetically try and map a 64 bit lock offset into 31 bits. I hate Windows :-).
05319 ****************************************************************************/
05320 
05321 static uint32 map_lock_offset(uint32 high, uint32 low)
05322 {
05323         unsigned int i;
05324         uint32 mask = 0;
05325         uint32 highcopy = high;
05326  
05327         /*
05328          * Try and find out how many significant bits there are in high.
05329          */
05330  
05331         for(i = 0; highcopy; i++)
05332                 highcopy >>= 1;
05333  
05334         /*
05335          * We use 31 bits not 32 here as POSIX
05336          * lock offsets may not be negative.
05337          */
05338  
05339         mask = (~0) << (31 - i);
05340  
05341         if(low & mask)
05342                 return 0; /* Fail. */
05343  
05344         high <<= (31 - i);
05345  
05346         return (high|low);
05347 }
05348 #endif /* !defined(HAVE_LONGLONG) */
05349 
05350 /****************************************************************************
05351  Get a lock offset, dealing with large offset requests.
05352 ****************************************************************************/
05353 
05354 SMB_BIG_UINT get_lock_offset( char *data, int data_offset, BOOL large_file_format, BOOL *err)
05355 {
05356         SMB_BIG_UINT offset = 0;
05357 
05358         *err = False;
05359 
05360         if(!large_file_format) {
05361                 offset = (SMB_BIG_UINT)IVAL(data,SMB_LKOFF_OFFSET(data_offset));
05362         } else {
05363 
05364 #if defined(HAVE_LONGLONG)
05365                 offset = (((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset))) << 32) |
05366                                 ((SMB_BIG_UINT) IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset)));
05367 #else /* HAVE_LONGLONG */
05368 
05369                 /*
05370                  * NT4.x seems to be broken in that it sends large file (64 bit)
05371                  * lockingX calls even if the CAP_LARGE_FILES was *not*
05372                  * negotiated. For boxes without large unsigned ints mangle the
05373                  * lock offset by mapping the top 32 bits onto the lower 32.
05374                  */
05375       
05376                 if(IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset)) != 0) {
05377                         uint32 low = IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
05378                         uint32 high = IVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset));
05379                         uint32 new_low = 0;
05380 
05381                         if((new_low = map_lock_offset(high, low)) == 0) {
05382                                 *err = True;
05383                                 return (SMB_BIG_UINT)-1;
05384                         }
05385 
05386                         DEBUG(3,("get_lock_offset: truncating lock offset (high)0x%x (low)0x%x to offset 0x%x.\n",
05387                                 (unsigned int)high, (unsigned int)low, (unsigned int)new_low ));
05388                         SIVAL(data,SMB_LARGE_LKOFF_OFFSET_HIGH(data_offset),0);
05389                         SIVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset),new_low);
05390                 }
05391 
05392                 offset = (SMB_BIG_UINT)IVAL(data,SMB_LARGE_LKOFF_OFFSET_LOW(data_offset));
05393 #endif /* HAVE_LONGLONG */
05394         }
05395 
05396         return offset;
05397 }
05398 
05399 /****************************************************************************
05400  Reply to a lockingX request.
05401 ****************************************************************************/
05402 
05403 int reply_lockingX(connection_struct *conn, char *inbuf, char *outbuf,
05404                    int length, int bufsize)
05405 {
05406         files_struct *fsp = file_fsp(inbuf,smb_vwv2);
05407         unsigned char locktype = CVAL(inbuf,smb_vwv3);
05408         unsigned char oplocklevel = CVAL(inbuf,smb_vwv3+1);
05409         uint16 num_ulocks = SVAL(inbuf,smb_vwv6);
05410         uint16 num_locks = SVAL(inbuf,smb_vwv7);
05411         SMB_BIG_UINT count = 0, offset = 0;
05412         uint32 lock_pid;
05413         int32 lock_timeout = IVAL(inbuf,smb_vwv4);
05414         int i;
05415         char *data;
05416         BOOL large_file_format =
05417                 (locktype & LOCKING_ANDX_LARGE_FILES)?True:False;
05418         BOOL err;
05419         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
05420 
05421         START_PROFILE(SMBlockingX);
05422         
05423         CHECK_FSP(fsp,conn);
05424         
05425         data = smb_buf(inbuf);
05426 
05427         if (locktype & LOCKING_ANDX_CHANGE_LOCKTYPE) {
05428                 /* we don't support these - and CANCEL_LOCK makes w2k
05429                    and XP reboot so I don't really want to be
05430                    compatible! (tridge) */
05431                 return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRnoatomiclocks));
05432         }
05433         
05434         /* Check if this is an oplock break on a file
05435            we have granted an oplock on.
05436         */
05437         if ((locktype & LOCKING_ANDX_OPLOCK_RELEASE)) {
05438                 /* Client can insist on breaking to none. */
05439                 BOOL break_to_none = (oplocklevel == 0);
05440                 BOOL result;
05441 
05442                 DEBUG(5,("reply_lockingX: oplock break reply (%u) from client "
05443                          "for fnum = %d\n", (unsigned int)oplocklevel,
05444                          fsp->fnum ));
05445 
05446                 /*
05447                  * Make sure we have granted an exclusive or batch oplock on
05448                  * this file.
05449                  */
05450                 
05451                 if (fsp->oplock_type == 0) {
05452 
05453                         /* The Samba4 nbench simulator doesn't understand
05454                            the difference between break to level2 and break
05455                            to none from level2 - it sends oplock break
05456                            replies in both cases. Don't keep logging an error
05457                            message here - just ignore it. JRA. */
05458 
05459                         DEBUG(5,("reply_lockingX: Error : oplock break from "
05460                                  "client for fnum = %d (oplock=%d) and no "
05461                                  "oplock granted on this file (%s).\n",
05462                                  fsp->fnum, fsp->oplock_type, fsp->fsp_name));
05463 
05464                         /* if this is a pure oplock break request then don't
05465                          * send a reply */
05466                         if (num_locks == 0 && num_ulocks == 0) {
05467                                 END_PROFILE(SMBlockingX);
05468                                 return -1;
05469                         } else {
05470                                 END_PROFILE(SMBlockingX);
05471                                 return ERROR_DOS(ERRDOS,ERRlock);
05472                         }
05473                 }
05474 
05475                 if ((fsp->sent_oplock_break == BREAK_TO_NONE_SENT) ||
05476                     (break_to_none)) {
05477                         result = remove_oplock(fsp);
05478                 } else {
05479                         result = downgrade_oplock(fsp);
05480                 }
05481                 
05482                 if (!result) {
05483                         DEBUG(0, ("reply_lockingX: error in removing "
05484                                   "oplock on file %s\n", fsp->fsp_name));
05485                         /* Hmmm. Is this panic justified? */
05486                         smb_panic("internal tdb error");
05487                 }
05488 
05489                 reply_to_oplock_break_requests(fsp);
05490 
05491                 /* if this is a pure oplock break request then don't send a
05492                  * reply */
05493                 if (num_locks == 0 && num_ulocks == 0) {
05494                         /* Sanity check - ensure a pure oplock break is not a
05495                            chained request. */
05496                         if(CVAL(inbuf,smb_vwv0) != 0xff)
05497                                 DEBUG(0,("reply_lockingX: Error : pure oplock "
05498                                          "break is a chained %d request !\n",
05499                                          (unsigned int)CVAL(inbuf,smb_vwv0) ));
05500                         END_PROFILE(SMBlockingX);
05501                         return -1;
05502                 }
05503         }
05504 
05505         /*
05506          * We do this check *after* we have checked this is not a oplock break
05507          * response message. JRA.
05508          */
05509         
05510         release_level_2_oplocks_on_change(fsp);
05511         
05512         /* Data now points at the beginning of the list
05513            of smb_unlkrng structs */
05514         for(i = 0; i < (int)num_ulocks; i++) {
05515                 lock_pid = get_lock_pid( data, i, large_file_format);
05516                 count = get_lock_count( data, i, large_file_format);
05517                 offset = get_lock_offset( data, i, large_file_format, &err);
05518                 
05519                 /*
05520                  * There is no error code marked "stupid client bug".... :-).
05521                  */
05522                 if(err) {
05523                         END_PROFILE(SMBlockingX);
05524                         return ERROR_DOS(ERRDOS,ERRnoaccess);
05525                 }
05526 
05527                 DEBUG(10,("reply_lockingX: unlock start=%.0f, len=%.0f for "
05528                           "pid %u, file %s\n", (double)offset, (double)count,
05529                           (unsigned int)lock_pid, fsp->fsp_name ));
05530                 
05531                 status = do_unlock(fsp,
05532                                 lock_pid,
05533                                 count,
05534                                 offset,
05535                                 WINDOWS_LOCK);
05536 
05537                 if (NT_STATUS_V(status)) {
05538                         END_PROFILE(SMBlockingX);
05539                         return ERROR_NT(status);
05540                 }
05541         }
05542 
05543         /* Setup the timeout in seconds. */
05544 
05545         if (!lp_blocking_locks(SNUM(conn))) {
05546                 lock_timeout = 0;
05547         }
05548         
05549         /* Now do any requested locks */
05550         data += ((large_file_format ? 20 : 10)*num_ulocks);
05551         
05552         /* Data now points at the beginning of the list
05553            of smb_lkrng structs */
05554         
05555         for(i = 0; i < (int)num_locks; i++) {
05556                 enum brl_type lock_type = ((locktype & LOCKING_ANDX_SHARED_LOCK) ?
05557                                 READ_LOCK:WRITE_LOCK);
05558                 lock_pid = get_lock_pid( data, i, large_file_format);
05559                 count = get_lock_count( data, i, large_file_format);
05560                 offset = get_lock_offset( data, i, large_file_format, &err);
05561                 
05562                 /*
05563                  * There is no error code marked "stupid client bug".... :-).
05564                  */
05565                 if(err) {
05566                         END_PROFILE(SMBlockingX);
05567                         return ERROR_DOS(ERRDOS,ERRnoaccess);
05568                 }
05569                 
05570                 DEBUG(10,("reply_lockingX: lock start=%.0f, len=%.0f for pid "
05571                           "%u, file %s timeout = %d\n", (double)offset,
05572                           (double)count, (unsigned int)lock_pid,
05573                           fsp->fsp_name, (int)lock_timeout ));
05574                 
05575                 if (locktype & LOCKING_ANDX_CANCEL_LOCK) {
05576                         if (lp_blocking_locks(SNUM(conn))) {
05577 
05578                                 /* Schedule a message to ourselves to
05579                                    remove the blocking lock record and
05580                                    return the right error. */
05581 
05582                                 if (!blocking_lock_cancel(fsp,
05583                                                 lock_pid,
05584                                                 offset,
05585                                                 count,
05586                                                 WINDOWS_LOCK,
05587                                                 locktype,
05588                                                 NT_STATUS_FILE_LOCK_CONFLICT)) {
05589                                         END_PROFILE(SMBlockingX);
05590                                         return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRcancelviolation));
05591                                 }
05592                         }
05593                         /* Remove a matching pending lock. */
05594                         status = do_lock_cancel(fsp,
05595                                                 lock_pid,
05596                                                 count,
05597                                                 offset,
05598                                                 WINDOWS_LOCK);
05599                 } else {
05600                         BOOL blocking_lock = lock_timeout ? True : False;
05601                         BOOL defer_lock = False;
05602                         struct byte_range_lock *br_lck;
05603                         uint32 block_smbpid;
05604 
05605                         br_lck = do_lock(fsp,
05606                                         lock_pid,
05607                                         count,
05608                                         offset, 
05609                                         lock_type,
05610                                         WINDOWS_LOCK,
05611                                         blocking_lock,
05612                                         &status,
05613                                         &block_smbpid);
05614 
05615                         if (br_lck && blocking_lock && ERROR_WAS_LOCK_DENIED(status)) {
05616                                 /* Windows internal resolution for blocking locks seems
05617                                    to be about 200ms... Don't wait for less than that. JRA. */
05618                                 if (lock_timeout != -1 && lock_timeout < lp_lock_spin_time()) {
05619                                         lock_timeout = lp_lock_spin_time();
05620                                 }
05621                                 defer_lock = True;
05622                         }
05623 
05624                         /* This heuristic seems to match W2K3 very well. If a
05625                            lock sent with timeout of zero would fail with NT_STATUS_FILE_LOCK_CONFLICT
05626                            it pretends we asked for a timeout of between 150 - 300 milliseconds as
05627                            far as I can tell. Replacement for do_lock_spin(). JRA. */
05628 
05629                         if (br_lck && lp_blocking_locks(SNUM(conn)) && !blocking_lock &&
05630                                         NT_STATUS_EQUAL((status), NT_STATUS_FILE_LOCK_CONFLICT)) {
05631                                 defer_lock = True;
05632                                 lock_timeout = lp_lock_spin_time();
05633                         }
05634 
05635                         if (br_lck && defer_lock) {
05636                                 /*
05637                                  * A blocking lock was requested. Package up
05638                                  * this smb into a queued request and push it
05639                                  * onto the blocking lock queue.
05640                                  */
05641                                 if(push_blocking_lock_request(br_lck,
05642                                                         inbuf, length,
05643                                                         fsp,
05644                                                         lock_timeout,
05645                                                         i,
05646                                                         lock_pid,
05647                                                         lock_type,
05648                                                         WINDOWS_LOCK,
05649                                                         offset,
05650                                                         count,
05651                                                         block_smbpid)) {
05652                                         TALLOC_FREE(br_lck);
05653                                         END_PROFILE(SMBlockingX);
05654                                         return -1;
05655                                 }
05656                         }
05657 
05658                         TALLOC_FREE(br_lck);
05659                 }
05660 
05661                 if (NT_STATUS_V(status)) {
05662                         END_PROFILE(SMBlockingX);
05663                         return ERROR_NT(status);
05664                 }
05665         }
05666         
05667         /* If any of the above locks failed, then we must unlock
05668            all of the previous locks (X/Open spec). */
05669 
05670         if (!(locktype & LOCKING_ANDX_CANCEL_LOCK) &&
05671                         (i != num_locks) &&
05672                         (num_locks != 0)) {
05673                 /*
05674                  * Ensure we don't do a remove on the lock that just failed,
05675                  * as under POSIX rules, if we have a lock already there, we
05676                  * will delete it (and we shouldn't) .....
05677                  */
05678                 for(i--; i >= 0; i--) {
05679                         lock_pid = get_lock_pid( data, i, large_file_format);
05680                         count = get_lock_count( data, i, large_file_format);
05681                         offset = get_lock_offset( data, i, large_file_format,
05682                                                   &err);
05683                         
05684                         /*
05685                          * There is no error code marked "stupid client
05686                          * bug".... :-).
05687                          */
05688                         if(err) {
05689                                 END_PROFILE(SMBlockingX);
05690                                 return ERROR_DOS(ERRDOS,ERRnoaccess);
05691                         }
05692                         
05693                         do_unlock(fsp,
05694                                 lock_pid,
05695                                 count,
05696                                 offset,
05697                                 WINDOWS_LOCK);
05698                 }
05699                 END_PROFILE(SMBlockingX);
05700                 return ERROR_NT(status);
05701         }
05702 
05703         set_message(outbuf,2,0,True);
05704         
05705         DEBUG(3, ("lockingX fnum=%d type=%d num_locks=%d num_ulocks=%d\n",
05706                   fsp->fnum, (unsigned int)locktype, num_locks, num_ulocks));
05707         
05708         END_PROFILE(SMBlockingX);
05709         return chain_reply(inbuf,outbuf,length,bufsize);
05710 }
05711 
05712 #undef DBGC_CLASS
05713 #define DBGC_CLASS DBGC_ALL
05714 
05715 /****************************************************************************
05716  Reply to a SMBreadbmpx (read block multiplex) request.
05717 ****************************************************************************/
05718 
05719 int reply_readbmpx(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
05720 {
05721         ssize_t nread = -1;
05722         ssize_t total_read;
05723         char *data;
05724         SMB_OFF_T startpos;
05725         int outsize;
05726         size_t maxcount;
05727         int max_per_packet;
05728         size_t tcount;
05729         int pad;
05730         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
05731         START_PROFILE(SMBreadBmpx);
05732 
05733         /* this function doesn't seem to work - disable by default */
05734         if (!lp_readbmpx()) {
05735                 END_PROFILE(SMBreadBmpx);
05736                 return ERROR_DOS(ERRSRV,ERRuseSTD);
05737         }
05738 
05739         outsize = set_message(outbuf,8,0,True);
05740 
05741         CHECK_FSP(fsp,conn);
05742         if (!CHECK_READ(fsp,inbuf)) {
05743                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
05744         }
05745 
05746         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv1);
05747         maxcount = SVAL(inbuf,smb_vwv3);
05748 
05749         data = smb_buf(outbuf);
05750         pad = ((long)data)%4;
05751         if (pad)
05752                 pad = 4 - pad;
05753         data += pad;
05754 
05755         max_per_packet = bufsize-(outsize+pad);
05756         tcount = maxcount;
05757         total_read = 0;
05758 
05759         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)maxcount,(SMB_BIG_UINT)startpos, READ_LOCK)) {
05760                 END_PROFILE(SMBreadBmpx);
05761                 return ERROR_DOS(ERRDOS,ERRlock);
05762         }
05763 
05764         do {
05765                 size_t N = MIN(max_per_packet,tcount-total_read);
05766   
05767                 nread = read_file(fsp,data,startpos,N);
05768 
05769                 if (nread <= 0)
05770                         nread = 0;
05771 
05772                 if (nread < (ssize_t)N)
05773                         tcount = total_read + nread;
05774 
05775                 set_message(outbuf,8,nread+pad,False);
05776                 SIVAL(outbuf,smb_vwv0,startpos);
05777                 SSVAL(outbuf,smb_vwv2,tcount);
05778                 SSVAL(outbuf,smb_vwv6,nread);
05779                 SSVAL(outbuf,smb_vwv7,smb_offset(data,outbuf));
05780 
05781                 show_msg(outbuf);
05782                 if (!send_smb(smbd_server_fd(),outbuf))
05783                         exit_server_cleanly("reply_readbmpx: send_smb failed.");
05784 
05785                 total_read += nread;
05786                 startpos += nread;
05787         } while (total_read < (ssize_t)tcount);
05788 
05789         END_PROFILE(SMBreadBmpx);
05790         return(-1);
05791 }
05792 
05793 /****************************************************************************
05794  Reply to a SMBsetattrE.
05795 ****************************************************************************/
05796 
05797 int reply_setattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
05798 {
05799         struct timespec ts[2];
05800         int outsize = 0;
05801         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
05802         START_PROFILE(SMBsetattrE);
05803 
05804         outsize = set_message(outbuf,0,0,False);
05805 
05806         if(!fsp || (fsp->conn != conn)) {
05807                 END_PROFILE(SMBsetattrE);
05808                 return ERROR_DOS(ERRDOS,ERRbadfid);
05809         }
05810 
05811         /*
05812          * Convert the DOS times into unix times. Ignore create
05813          * time as UNIX can't set this.
05814          */
05815 
05816         ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv3)); /* atime. */
05817         ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(inbuf+smb_vwv5)); /* mtime. */
05818   
05819         /* 
05820          * Patch from Ray Frush <frush@engr.colostate.edu>
05821          * Sometimes times are sent as zero - ignore them.
05822          */
05823 
05824         if (null_timespec(ts[0]) && null_timespec(ts[1])) {
05825                 /* Ignore request */
05826                 if( DEBUGLVL( 3 ) ) {
05827                         dbgtext( "reply_setattrE fnum=%d ", fsp->fnum);
05828                         dbgtext( "ignoring zero request - not setting timestamps of 0\n" );
05829                 }
05830                 END_PROFILE(SMBsetattrE);
05831                 return(outsize);
05832         } else if (!null_timespec(ts[0]) && null_timespec(ts[1])) {
05833                 /* set modify time = to access time if modify time was unset */
05834                 ts[1] = ts[0];
05835         }
05836 
05837         /* Set the date on this file */
05838         /* Should we set pending modtime here ? JRA */
05839         if(file_ntimes(conn, fsp->fsp_name, ts)) {
05840                 END_PROFILE(SMBsetattrE);
05841                 return ERROR_DOS(ERRDOS,ERRnoaccess);
05842         }
05843   
05844         DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
05845                 fsp->fnum,
05846                 (unsigned int)ts[0].tv_sec,
05847                 (unsigned int)ts[1].tv_sec));
05848 
05849         END_PROFILE(SMBsetattrE);
05850         return(outsize);
05851 }
05852 
05853 
05854 /* Back from the dead for OS/2..... JRA. */
05855 
05856 /****************************************************************************
05857  Reply to a SMBwritebmpx (write block multiplex primary) request.
05858 ****************************************************************************/
05859 
05860 int reply_writebmpx(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
05861 {
05862         size_t numtowrite;
05863         ssize_t nwritten = -1;
05864         int outsize = 0;
05865         SMB_OFF_T startpos;
05866         size_t tcount;
05867         BOOL write_through;
05868         int smb_doff;
05869         char *data;
05870         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
05871         NTSTATUS status;
05872         START_PROFILE(SMBwriteBmpx);
05873 
05874         CHECK_FSP(fsp,conn);
05875         if (!CHECK_WRITE(fsp)) {
05876                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
05877         }
05878         if (HAS_CACHED_ERROR(fsp)) {
05879                 return(CACHED_ERROR(fsp));
05880         }
05881 
05882         tcount = SVAL(inbuf,smb_vwv1);
05883         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv3);
05884         write_through = BITSETW(inbuf+smb_vwv7,0);
05885         numtowrite = SVAL(inbuf,smb_vwv10);
05886         smb_doff = SVAL(inbuf,smb_vwv11);
05887 
05888         data = smb_base(inbuf) + smb_doff;
05889 
05890         /* If this fails we need to send an SMBwriteC response,
05891                 not an SMBwritebmpx - set this up now so we don't forget */
05892         SCVAL(outbuf,smb_com,SMBwritec);
05893 
05894         if (is_locked(fsp,(uint32)SVAL(inbuf,smb_pid),(SMB_BIG_UINT)tcount,(SMB_BIG_UINT)startpos,WRITE_LOCK)) {
05895                 END_PROFILE(SMBwriteBmpx);
05896                 return(ERROR_DOS(ERRDOS,ERRlock));
05897         }
05898 
05899         nwritten = write_file(fsp,data,startpos,numtowrite);
05900 
05901         status = sync_file(conn, fsp, write_through);
05902         if (!NT_STATUS_IS_OK(status)) {
05903                 END_PROFILE(SMBwriteBmpx);
05904                 DEBUG(5,("reply_writebmpx: sync_file for %s returned %s\n",
05905                         fsp->fsp_name, nt_errstr(status) ));
05906                 return ERROR_NT(status);
05907         }
05908   
05909         if(nwritten < (ssize_t)numtowrite) {
05910                 END_PROFILE(SMBwriteBmpx);
05911                 return(UNIXERROR(ERRHRD,ERRdiskfull));
05912         }
05913 
05914         /* If the maximum to be written to this file
05915                 is greater than what we just wrote then set
05916                 up a secondary struct to be attached to this
05917                 fd, we will use this to cache error messages etc. */
05918 
05919         if((ssize_t)tcount > nwritten) {
05920                 write_bmpx_struct *wbms;
05921                 if(fsp->wbmpx_ptr != NULL)
05922                         wbms = fsp->wbmpx_ptr; /* Use an existing struct */
05923                 else
05924                         wbms = SMB_MALLOC_P(write_bmpx_struct);
05925                 if(!wbms) {
05926                         DEBUG(0,("Out of memory in reply_readmpx\n"));
05927                         END_PROFILE(SMBwriteBmpx);
05928                         return(ERROR_DOS(ERRSRV,ERRnoresource));
05929                 }
05930                 wbms->wr_mode = write_through;
05931                 wbms->wr_discard = False; /* No errors yet */
05932                 wbms->wr_total_written = nwritten;
05933                 wbms->wr_errclass = 0;
05934                 wbms->wr_error = 0;
05935                 fsp->wbmpx_ptr = wbms;
05936         }
05937 
05938         /* We are returning successfully, set the message type back to
05939                 SMBwritebmpx */
05940         SCVAL(outbuf,smb_com,SMBwriteBmpx);
05941   
05942         outsize = set_message(outbuf,1,0,True);
05943   
05944         SSVALS(outbuf,smb_vwv0,-1); /* We don't support smb_remaining */
05945   
05946         DEBUG( 3, ( "writebmpx fnum=%d num=%d wrote=%d\n",
05947                         fsp->fnum, (int)numtowrite, (int)nwritten ) );
05948 
05949         if (write_through && tcount==nwritten) {
05950                 /* We need to send both a primary and a secondary response */
05951                 smb_setlen(outbuf,outsize - 4);
05952                 show_msg(outbuf);
05953                 if (!send_smb(smbd_server_fd(),outbuf))
05954                         exit_server_cleanly("reply_writebmpx: send_smb failed.");
05955 
05956                 /* Now the secondary */
05957                 outsize = set_message(outbuf,1,0,True);
05958                 SCVAL(outbuf,smb_com,SMBwritec);
05959                 SSVAL(outbuf,smb_vwv0,nwritten);
05960         }
05961 
05962         END_PROFILE(SMBwriteBmpx);
05963         return(outsize);
05964 }
05965 
05966 /****************************************************************************
05967  Reply to a SMBwritebs (write block multiplex secondary) request.
05968 ****************************************************************************/
05969 
05970 int reply_writebs(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, int dum_buffsize)
05971 {
05972         size_t numtowrite;
05973         ssize_t nwritten = -1;
05974         int outsize = 0;
05975         SMB_OFF_T startpos;
05976         size_t tcount;
05977         BOOL write_through;
05978         int smb_doff;
05979         char *data;
05980         write_bmpx_struct *wbms;
05981         BOOL send_response = False; 
05982         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
05983         NTSTATUS status;
05984         START_PROFILE(SMBwriteBs);
05985 
05986         CHECK_FSP(fsp,conn);
05987         if (!CHECK_WRITE(fsp)) {
05988                 return(ERROR_DOS(ERRDOS,ERRbadaccess));
05989         }
05990 
05991         tcount = SVAL(inbuf,smb_vwv1);
05992         startpos = IVAL_TO_SMB_OFF_T(inbuf,smb_vwv2);
05993         numtowrite = SVAL(inbuf,smb_vwv6);
05994         smb_doff = SVAL(inbuf,smb_vwv7);
05995 
05996         data = smb_base(inbuf) + smb_doff;
05997 
05998         /* We need to send an SMBwriteC response, not an SMBwritebs */
05999         SCVAL(outbuf,smb_com,SMBwritec);
06000 
06001         /* This fd should have an auxiliary struct attached,
06002                 check that it does */
06003         wbms = fsp->wbmpx_ptr;
06004         if(!wbms) {
06005                 END_PROFILE(SMBwriteBs);
06006                 return(-1);
06007         }
06008 
06009         /* If write through is set we can return errors, else we must cache them */
06010         write_through = wbms->wr_mode;
06011 
06012         /* Check for an earlier error */
06013         if(wbms->wr_discard) {
06014                 END_PROFILE(SMBwriteBs);
06015                 return -1; /* Just discard the packet */
06016         }
06017 
06018         nwritten = write_file(fsp,data,startpos,numtowrite);
06019 
06020         status = sync_file(conn, fsp, write_through);
06021   
06022         if (nwritten < (ssize_t)numtowrite || !NT_STATUS_IS_OK(status)) {
06023                 if(write_through) {
06024                         /* We are returning an error - we can delete the aux struct */
06025                         if (wbms)
06026                                 free((char *)wbms);
06027                         fsp->wbmpx_ptr = NULL;
06028                         END_PROFILE(SMBwriteBs);
06029                         return(ERROR_DOS(ERRHRD,ERRdiskfull));
06030                 }
06031                 wbms->wr_errclass = ERRHRD;
06032                 wbms->wr_error = ERRdiskfull;
06033                 wbms->wr_status = NT_STATUS_DISK_FULL;
06034                 wbms->wr_discard = True;
06035                 END_PROFILE(SMBwriteBs);
06036                 return -1;
06037         }
06038 
06039         /* Increment the total written, if this matches tcount
06040                 we can discard the auxiliary struct (hurrah !) and return a writeC */
06041         wbms->wr_total_written += nwritten;
06042         if(wbms->wr_total_written >= tcount) {
06043                 if (write_through) {
06044                         outsize = set_message(outbuf,1,0,True);
06045                         SSVAL(outbuf,smb_vwv0,wbms->wr_total_written);    
06046                         send_response = True;
06047                 }
06048 
06049                 free((char *)wbms);
06050                 fsp->wbmpx_ptr = NULL;
06051         }
06052 
06053         if(send_response) {
06054                 END_PROFILE(SMBwriteBs);
06055                 return(outsize);
06056         }
06057 
06058         END_PROFILE(SMBwriteBs);
06059         return(-1);
06060 }
06061 
06062 /****************************************************************************
06063  Reply to a SMBgetattrE.
06064 ****************************************************************************/
06065 
06066 int reply_getattrE(connection_struct *conn, char *inbuf,char *outbuf, int size, int dum_buffsize)
06067 {
06068         SMB_STRUCT_STAT sbuf;
06069         int outsize = 0;
06070         int mode;
06071         files_struct *fsp = file_fsp(inbuf,smb_vwv0);
06072         START_PROFILE(SMBgetattrE);
06073 
06074         outsize = set_message(outbuf,11,0,True);
06075 
06076         if(!fsp || (fsp->conn != conn)) {
06077                 END_PROFILE(SMBgetattrE);
06078                 return ERROR_DOS(ERRDOS,ERRbadfid);
06079         }
06080 
06081         /* Do an fstat on this file */
06082         if(fsp_stat(fsp, &sbuf)) {
06083                 END_PROFILE(SMBgetattrE);
06084                 return(UNIXERROR(ERRDOS,ERRnoaccess));
06085         }
06086   
06087         mode = dos_mode(conn,fsp->fsp_name,&sbuf);
06088   
06089         /*
06090          * Convert the times into dos times. Set create
06091          * date to be last modify date as UNIX doesn't save
06092          * this.
06093          */
06094 
06095         srv_put_dos_date2(outbuf,smb_vwv0,get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))));
06096         srv_put_dos_date2(outbuf,smb_vwv2,sbuf.st_atime);
06097         /* Should we check pending modtime here ? JRA */
06098         srv_put_dos_date2(outbuf,smb_vwv4,sbuf.st_mtime);
06099 
06100         if (mode & aDIR) {
06101                 SIVAL(outbuf,smb_vwv6,0);
06102                 SIVAL(outbuf,smb_vwv8,0);
06103         } else {
06104                 uint32 allocation_size = get_allocation_size(conn,fsp, &sbuf);
06105                 SIVAL(outbuf,smb_vwv6,(uint32)sbuf.st_size);
06106                 SIVAL(outbuf,smb_vwv8,allocation_size);
06107         }
06108         SSVAL(outbuf,smb_vwv10, mode);
06109   
06110         DEBUG( 3, ( "reply_getattrE fnum=%d\n", fsp->fnum));
06111   
06112         END_PROFILE(SMBgetattrE);
06113         return(outsize);
06114 }

Sambaに対してSat Aug 29 21:23:25 2009に生成されました。  doxygen 1.4.7