This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file handles most of the reply_ calls that the server
/* Custom version for processing POSIX paths. */
#define IS_PATH_SEP(c,posix_only) ((c) == '/' || (!(posix_only) && (c) == '\\'))
-NTSTATUS check_path_syntax_internal(pstring destname,
- const pstring srcname,
- BOOL posix_path,
- BOOL *p_last_component_contains_wcard)
+static NTSTATUS check_path_syntax_internal(char *path,
+ BOOL posix_path,
+ BOOL *p_last_component_contains_wcard)
{
- char *d = destname;
- const char *s = srcname;
+ char *d = path;
+ const char *s = path;
NTSTATUS ret = NT_STATUS_OK;
BOOL start_of_name_component = True;
while (IS_PATH_SEP(*s,posix_path)) {
s++;
}
- if ((d != destname) && (*s != '\0')) {
+ if ((d != path) && (*s != '\0')) {
/* We only care about non-leading or trailing '/' or '\\' */
*d++ = '/';
}
*/
/* If we just added a '/' - delete it */
- if ((d > destname) && (*(d-1) == '/')) {
+ if ((d > path) && (*(d-1) == '/')) {
*(d-1) = '\0';
d--;
}
/* Are we at the start ? Can't go back further if so. */
- if (d <= destname) {
+ if (d <= path) {
ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
break;
}
/* We know this is safe as '/' cannot be part of a mb sequence. */
/* NOTE - if this assumption is invalid we are not in good shape... */
/* Decrement d first as d points to the *next* char to write into. */
- for (d--; d > destname; d--) {
+ for (d--; d > path; d--) {
if (*d == '/')
break;
}
No wildcards allowed.
****************************************************************************/
-NTSTATUS check_path_syntax(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax(char *path)
{
BOOL ignore;
- return check_path_syntax_internal(destname, srcname, False, &ignore);
+ return check_path_syntax_internal(path, False, &ignore);
}
/****************************************************************************
a wildcard.
****************************************************************************/
-NTSTATUS check_path_syntax_wcard(pstring destname, const pstring srcname, BOOL *p_contains_wcard)
+NTSTATUS check_path_syntax_wcard(char *path, BOOL *p_contains_wcard)
{
- return check_path_syntax_internal(destname, srcname, False, p_contains_wcard);
+ return check_path_syntax_internal(path, False, p_contains_wcard);
}
/****************************************************************************
set (a safe assumption).
****************************************************************************/
-NTSTATUS check_path_syntax_posix(pstring destname, const pstring srcname)
+NTSTATUS check_path_syntax_posix(char *path)
{
BOOL ignore;
- return check_path_syntax_internal(destname, srcname, True, &ignore);
+ return check_path_syntax_internal(path, True, &ignore);
}
/****************************************************************************
Pull a string and check the path allowing a wilcard - provide for error return.
****************************************************************************/
-size_t srvstr_get_path_wcard(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags,
- NTSTATUS *err, BOOL *contains_wcard)
+size_t srvstr_get_path_wcard(char *inbuf, uint16 smb_flags2, char *dest,
+ const char *src, size_t dest_len, size_t src_len,
+ int flags, NTSTATUS *err, BOOL *contains_wcard)
{
- pstring tmppath;
- char *tmppath_ptr = tmppath;
size_t ret;
#ifdef DEVELOPER
SMB_ASSERT(dest_len == sizeof(pstring));
#endif
if (src_len == 0) {
- ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
+ ret = srvstr_pull_buf(inbuf, smb_flags2, dest, src,
+ dest_len, flags);
} else {
- ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
+ ret = srvstr_pull(inbuf, smb_flags2, dest, src,
+ dest_len, src_len, flags);
}
*contains_wcard = False;
- if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+ if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
/*
* For a DFS path the function parse_dfs_path()
* will do the path processing, just make a copy.
*/
- pstrcpy(dest, tmppath);
*err = NT_STATUS_OK;
return ret;
}
if (lp_posix_pathnames()) {
- *err = check_path_syntax_posix(dest, tmppath);
+ *err = check_path_syntax_posix(dest);
} else {
- *err = check_path_syntax_wcard(dest, tmppath, contains_wcard);
+ *err = check_path_syntax_wcard(dest, contains_wcard);
}
return ret;
Pull a string and check the path - provide for error return.
****************************************************************************/
-size_t srvstr_get_path(char *inbuf, char *dest, const char *src, size_t dest_len, size_t src_len, int flags, NTSTATUS *err)
+size_t srvstr_get_path(char *inbuf, uint16 smb_flags2, char *dest,
+ const char *src, size_t dest_len, size_t src_len,
+ int flags, NTSTATUS *err)
{
- pstring tmppath;
- char *tmppath_ptr = tmppath;
size_t ret;
#ifdef DEVELOPER
SMB_ASSERT(dest_len == sizeof(pstring));
#endif
if (src_len == 0) {
- ret = srvstr_pull_buf( inbuf, tmppath_ptr, src, dest_len, flags);
+ ret = srvstr_pull_buf(inbuf, smb_flags2, dest, src,
+ dest_len, flags);
} else {
- ret = srvstr_pull( inbuf, tmppath_ptr, src, dest_len, src_len, flags);
+ ret = srvstr_pull(inbuf, smb_flags2, dest, src,
+ dest_len, src_len, flags);
}
- if (SVAL(inbuf,smb_flg2) & FLAGS2_DFS_PATHNAMES) {
+ if (smb_flags2 & FLAGS2_DFS_PATHNAMES) {
/*
* For a DFS path the function parse_dfs_path()
* will do the path processing, just make a copy.
*/
- pstrcpy(dest, tmppath);
*err = NT_STATUS_OK;
return ret;
}
if (lp_posix_pathnames()) {
- *err = check_path_syntax_posix(dest, tmppath);
+ *err = check_path_syntax_posix(dest);
} else {
- *err = check_path_syntax(dest, tmppath);
+ *err = check_path_syntax(dest);
}
return ret;
*service_buf = *password = *dev = 0;
p = smb_buf(inbuf)+1;
- p += srvstr_pull_buf(inbuf, service_buf, p, sizeof(service_buf), STR_TERMINATE) + 1;
- pwlen = srvstr_pull_buf(inbuf, password, p, sizeof(password), STR_TERMINATE) + 1;
+ p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), service_buf, p,
+ sizeof(service_buf), STR_TERMINATE) + 1;
+ pwlen = srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), password, p,
+ sizeof(password), STR_TERMINATE) + 1;
p += pwlen;
- p += srvstr_pull_buf(inbuf, dev, p, sizeof(dev), STR_TERMINATE) + 1;
+ p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), dev, p, sizeof(dev),
+ STR_TERMINATE) + 1;
p = strrchr_m(service_buf,'\\');
if (p) {
p = smb_buf(inbuf) + passlen + 1;
}
- p += srvstr_pull_buf(inbuf, path, p, sizeof(path), STR_TERMINATE);
+ p += srvstr_pull_buf(inbuf, SVAL(inbuf, smb_flg2), path, p,
+ sizeof(path), STR_TERMINATE);
/*
* the service name can be either: \\server\share
else
fstrcpy(service,path);
- p += srvstr_pull(inbuf, client_devicetype, p, sizeof(client_devicetype), 6, STR_ASCII);
+ p += srvstr_pull(inbuf, SVAL(inbuf, smb_flg2), client_devicetype, p,
+ sizeof(client_devicetype), 6, STR_ASCII);
DEBUG(4,("Client requested device type [%s] for share [%s]\n", client_devicetype, service));
START_PROFILE(SMBcheckpath);
- srvstr_get_path(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), name, smb_buf(inbuf) + 1,
+ sizeof(name), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcheckpath);
status = map_checkpath_error(inbuf, status);
START_PROFILE(SMBgetatr);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, p,
+ sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBgetatr);
return ERROR_NT(status);
START_PROFILE(SMBsetatr);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path(inbuf, fname, p, sizeof(fname), 0, STR_TERMINATE, &status);
+ p += srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, p,
+ sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBsetatr);
return ERROR_NT(status);
maxentries = SVAL(inbuf,smb_vwv0);
dirtype = SVAL(inbuf,smb_vwv1);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path_wcard(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &nt_status, &mask_contains_wcard);
+ p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), path, p,
+ sizeof(path), 0, STR_TERMINATE, &nt_status,
+ &mask_contains_wcard);
if (!NT_STATUS_IS_OK(nt_status)) {
END_PROFILE(SMBsearch);
return ERROR_NT(nt_status);
outsize = set_message(inbuf,outbuf,1,0,True);
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path_wcard(inbuf, path, p, sizeof(path), 0, STR_TERMINATE, &err, &path_contains_wcard);
+ p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), path, p,
+ sizeof(path), 0, STR_TERMINATE, &err,
+ &path_contains_wcard);
if (!NT_STATUS_IS_OK(err)) {
END_PROFILE(SMBfclose);
return ERROR_NT(err);
uint32 create_disposition;
uint32 create_options = 0;
NTSTATUS status;
+ struct smb_request req;
+
START_PROFILE(SMBopen);
+
+ init_smb_request(&req, (uint8 *)inbuf);
deny_mode = SVAL(inbuf,smb_vwv0);
- srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, smb_buf(inbuf)+1,
+ sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBopen);
return ERROR_NT(status);
return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRbadaccess));
}
- status = open_file_ntcreate(conn,fname,&sbuf,
+ status = open_file_ntcreate(conn, &req, fname, &sbuf,
access_mask,
share_mode,
create_disposition,
uint32 share_mode;
uint32 create_disposition;
uint32 create_options = 0;
+ struct smb_request req;
START_PROFILE(SMBopenX);
+ init_smb_request(&req, (uint8 *)inbuf);
+
/* If it's an IPC, pass off the pipe handler. */
if (IS_IPC(conn)) {
if (lp_nt_pipe_support()) {
}
/* XXXX we need to handle passed times, sattr and flags */
- srvstr_get_path(inbuf, fname, smb_buf(inbuf), sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, smb_buf(inbuf),
+ sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBopenX);
return ERROR_NT(status);
return ERROR_NT(NT_STATUS_DOS(ERRDOS, ERRbadaccess));
}
- status = open_file_ntcreate(conn,fname,&sbuf,
+ status = open_file_ntcreate(conn, &req, fname, &sbuf,
access_mask,
share_mode,
create_disposition,
uint32 share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
uint32 create_disposition;
uint32 create_options = 0;
+ struct smb_request req;
START_PROFILE(SMBcreate);
+
+ init_smb_request(&req, (uint8 *)inbuf);
com = SVAL(inbuf,smb_com);
ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(inbuf + smb_vwv1)); /* mtime. */
- srvstr_get_path(inbuf, fname, smb_buf(inbuf) + 1, sizeof(fname), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, smb_buf(inbuf) + 1,
+ sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcreate);
return ERROR_NT(status);
}
/* Open file using ntcreate. */
- status = open_file_ntcreate(conn,fname,&sbuf,
+ status = open_file_ntcreate(conn, &req, fname, &sbuf,
access_mask,
share_mode,
create_disposition,
char *p, *s;
NTSTATUS status;
unsigned int namelen;
+ struct smb_request req;
START_PROFILE(SMBctemp);
- srvstr_get_path(inbuf, fname, smb_buf(inbuf)+1, sizeof(fname), 0, STR_TERMINATE, &status);
+ init_smb_request(&req, (uint8 *)inbuf);
+
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), fname, smb_buf(inbuf)+1,
+ sizeof(fname), 0, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBctemp);
return ERROR_NT(status);
SMB_VFS_STAT(conn,fname,&sbuf);
/* We should fail if file does not exist. */
- status = open_file_ntcreate(conn,fname,&sbuf,
+ status = open_file_ntcreate(conn, &req, fname, &sbuf,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
Check if a user is allowed to rename a file.
********************************************************************/
-static NTSTATUS can_rename(connection_struct *conn, char *fname, uint16 dirtype, SMB_STRUCT_STAT *pst, BOOL self_open)
+static NTSTATUS can_rename(connection_struct *conn, files_struct *fsp,
+ uint16 dirtype, SMB_STRUCT_STAT *pst)
{
- files_struct *fsp;
uint32 fmode;
- NTSTATUS status;
if (!CAN_WRITE(conn)) {
return NT_STATUS_MEDIA_WRITE_PROTECTED;
}
- fmode = dos_mode(conn,fname,pst);
+ fmode = dos_mode(conn, fsp->fsp_name, pst);
if ((fmode & ~dirtype) & (aHIDDEN | aSYSTEM)) {
return NT_STATUS_NO_SUCH_FILE;
}
return NT_STATUS_OK;
}
- status = open_file_ntcreate(conn, fname, pst,
- DELETE_ACCESS,
- /* If we're checking our fsp don't deny for delete. */
- self_open ?
- FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE :
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- FILE_OPEN,
- 0,
- FILE_ATTRIBUTE_NORMAL,
- 0,
- NULL, &fsp);
-
- if (!NT_STATUS_IS_OK(status)) {
- return status;
+ if (fsp->access_mask & DELETE_ACCESS) {
+ return NT_STATUS_OK;
}
- close_file(fsp,NORMAL_CLOSE);
- return NT_STATUS_OK;
+
+ return NT_STATUS_ACCESS_DENIED;
}
/*******************************************************************
- Check if a user is allowed to delete a file.
-********************************************************************/
+ * unlink a file with all relevant access checks
+ *******************************************************************/
-static NTSTATUS can_delete(connection_struct *conn, char *fname,
- uint32 dirtype, BOOL can_defer)
+static NTSTATUS do_unlink(connection_struct *conn, struct smb_request *req,
+ char *fname, uint32 dirtype)
{
SMB_STRUCT_STAT sbuf;
uint32 fattr;
uint32 dirtype_orig = dirtype;
NTSTATUS status;
- DEBUG(10,("can_delete: %s, dirtype = %d\n", fname, dirtype ));
+ DEBUG(10,("do_unlink: %s, dirtype = %d\n", fname, dirtype ));
if (!CAN_WRITE(conn)) {
return NT_STATUS_MEDIA_WRITE_PROTECTED;
/* On open checks the open itself will check the share mode, so
don't do it here as we'll get it wrong. */
- status = open_file_ntcreate(conn, fname, &sbuf,
+ status = open_file_ntcreate(conn, req, fname, &sbuf,
DELETE_ACCESS,
FILE_SHARE_NONE,
FILE_OPEN,
0,
FILE_ATTRIBUTE_NORMAL,
- can_defer ? 0 : INTERNAL_OPEN_ONLY,
+ req != NULL ? 0 : INTERNAL_OPEN_ONLY,
NULL, &fsp);
- if (NT_STATUS_IS_OK(status)) {
- close_file(fsp,NORMAL_CLOSE);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("open_file_ntcreate failed: %s\n",
+ nt_errstr(status)));
+ return status;
}
- return status;
+
+ /* The set is across all open files on this dev/inode pair. */
+ if (!set_delete_on_close(fsp, True, ¤t_user.ut)) {
+ close_file(fsp, NORMAL_CLOSE);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
+ return close_file(fsp,NORMAL_CLOSE);
}
/****************************************************************************
code.
****************************************************************************/
-NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype,
- char *name, BOOL has_wild, BOOL can_defer)
+NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
+ uint32 dirtype, char *name, BOOL has_wild)
{
pstring directory;
pstring mask;
return status;
}
- status = can_delete(conn,directory,dirtype,can_defer);
+ status = do_unlink(conn, req, directory, dirtype);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- if (SMB_VFS_UNLINK(conn,directory) == 0) {
- count++;
- notify_fname(conn, NOTIFY_ACTION_REMOVED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- directory);
- }
+ count++;
} else {
struct smb_Dir *dir_hnd = NULL;
long offset = 0;
return status;
}
- status = can_delete(conn, fname, dirtype, can_defer);
+ status = do_unlink(conn, req, fname, dirtype);
if (!NT_STATUS_IS_OK(status)) {
continue;
}
- if (SMB_VFS_UNLINK(conn,fname) == 0) {
- count++;
- DEBUG(3,("unlink_internals: succesful unlink "
- "[%s]\n",fname));
- notify_fname(conn, NOTIFY_ACTION_REMOVED,
- FILE_NOTIFY_CHANGE_FILE_NAME,
- fname);
- }
-
+
+ count++;
+ DEBUG(3,("unlink_internals: succesful unlink [%s]\n",
+ fname));
}
CloseDir(dir_hnd);
}
uint32 dirtype;
NTSTATUS status;
BOOL path_contains_wcard = False;
+ struct smb_request req;
START_PROFILE(SMBunlink);
+ init_smb_request(&req, (uint8 *)inbuf);
+
dirtype = SVAL(inbuf,smb_vwv0);
- srvstr_get_path_wcard(inbuf, name, smb_buf(inbuf) + 1, sizeof(name), 0, STR_TERMINATE, &status, &path_contains_wcard);
+ srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), name,
+ smb_buf(inbuf) + 1, sizeof(name), 0,
+ STR_TERMINATE, &status, &path_contains_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBunlink);
return ERROR_NT(status);
DEBUG(3,("reply_unlink : %s\n",name));
- status = unlink_internals(conn, dirtype, name, path_contains_wcard,
- True);
+ status = unlink_internals(conn, &req, dirtype, name,
+ path_contains_wcard);
if (!NT_STATUS_IS_OK(status)) {
if (open_was_deferred(SVAL(inbuf,smb_mid))) {
/* We have re-scheduled this call. */
if (startpos > sbuf.st_size) {
smb_maxcnt = 0;
- }
-
- if (smb_maxcnt > (sbuf.st_size - startpos)) {
+ } else if (smb_maxcnt > (sbuf.st_size - startpos)) {
smb_maxcnt = (sbuf.st_size - startpos);
}
BOOL write_through;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
int outsize = 0;
+ NTSTATUS status;
START_PROFILE(SMBwritebraw);
if (srv_is_signing_active()) {
SSVAL(outbuf,smb_vwv0,total_written);
- sync_file(conn, fsp, write_through);
+ status = sync_file(conn, fsp, write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5,("reply_writebraw: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ END_PROFILE(SMBwritebraw);
+ return ERROR_NT(status);
+ }
DEBUG(3,("writebraw2 fnum=%d start=%.0f num=%d wrote=%d\n",
fsp->fnum, (double)startpos, (int)numtowrite,(int)total_written));
nwritten = write_file(fsp,data,startpos,numtowrite);
}
- sync_file(conn, fsp, False /* write through */);
+ status = sync_file(conn, fsp, False /* write through */);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBwriteunlock);
+ DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ return ERROR_NT(status);
+ }
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
END_PROFILE(SMBwriteunlock);
char *data;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
int outsize = 0;
+ NTSTATUS status;
START_PROFILE(SMBwrite);
/* If it's an IPC, pass off the pipe handler. */
CHECK_FSP(fsp,conn);
if (!CHECK_WRITE(fsp)) {
+ END_PROFILE(SMBwrite);
return(ERROR_DOS(ERRDOS,ERRbadaccess));
}
} else
nwritten = write_file(fsp,data,startpos,numtowrite);
- sync_file(conn, fsp, False);
+ status = sync_file(conn, fsp, False);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBwrite);
+ DEBUG(5,("reply_write: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ return ERROR_NT(status);
+ }
if(((nwritten == 0) && (numtowrite != 0))||(nwritten < 0)) {
END_PROFILE(SMBwrite);
unsigned int smblen = smb_len(inbuf);
char *data;
BOOL large_writeX = ((CVAL(inbuf,smb_wct) == 14) && (smblen > 0xFFFF));
+ NTSTATUS status;
START_PROFILE(SMBwriteX);
/* If it's an IPC, pass off the pipe handler. */
DEBUG(3,("writeX fnum=%d num=%d wrote=%d\n",
fsp->fnum, (int)numtowrite, (int)nwritten));
- sync_file(conn, fsp, write_through);
+ status = sync_file(conn, fsp, write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBwriteX);
+ DEBUG(5,("reply_write_and_X: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ return ERROR_NT(status);
+ }
END_PROFILE(SMBwriteX);
return chain_reply(inbuf,outbuf,length,bufsize);
if (!fsp) {
file_sync_all(conn);
} else {
- sync_file(conn,fsp, True);
+ NTSTATUS status = sync_file(conn, fsp, True);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBflush);
+ DEBUG(5,("reply_flush: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ return ERROR_NT(status);
+ }
}
DEBUG(3,("flush\n"));
START_PROFILE(SMBmkdir);
- srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), directory,
+ smb_buf(inbuf) + 1, sizeof(directory), 0,
+ STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmkdir);
return ERROR_NT(status);
NTSTATUS status;
START_PROFILE(SMBrmdir);
- srvstr_get_path(inbuf, directory, smb_buf(inbuf) + 1, sizeof(directory), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), directory,
+ smb_buf(inbuf) + 1, sizeof(directory), 0,
+ STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBrmdir);
return ERROR_NT(status);
asynchronously.
****************************************************************************/
-static void rename_open_files(connection_struct *conn, struct share_mode_lock *lck,
- struct file_id id, const char *newname)
+static void rename_open_files(connection_struct *conn,
+ struct share_mode_lock *lck,
+ const char *newname)
{
files_struct *fsp;
BOOL did_rename = False;
- for(fsp = file_find_di_first(id); fsp; fsp = file_find_di_next(fsp)) {
+ for(fsp = file_find_di_first(lck->id); fsp;
+ fsp = file_find_di_next(fsp)) {
/* fsp_name is a relative path under the fsp. To change this for other
sharepaths we need to manipulate relative paths. */
/* TODO - create the absolute path and manipulate the newname
if (!did_rename) {
DEBUG(10,("rename_open_files: no open files on file_id %s for %s\n",
- file_id_static_string(&id), newname ));
+ file_id_static_string(&lck->id), newname ));
}
/* Send messages to all smbd's (not ourself) that the name has changed. */
return ((memcmp(psrc, pdst, slen) == 0) && pdst[slen] == '/');
}
+/*
+ * Do the notify calls from a rename
+ */
+
+static void notify_rename(connection_struct *conn, BOOL is_dir,
+ const char *oldpath, const char *newpath)
+{
+ char *olddir, *newdir;
+ const char *oldname, *newname;
+ uint32 mask;
+
+ mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
+ : FILE_NOTIFY_CHANGE_FILE_NAME;
+
+ if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
+ || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
+ TALLOC_FREE(olddir);
+ return;
+ }
+
+ if (strcmp(olddir, newdir) == 0) {
+ notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
+ notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
+ }
+ else {
+ notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
+ notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
+ }
+ TALLOC_FREE(olddir);
+ TALLOC_FREE(newdir);
+
+ /* this is a strange one. w2k3 gives an additional event for
+ CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
+ files, but not directories */
+ if (!is_dir) {
+ notify_fname(conn, NOTIFY_ACTION_MODIFIED,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES
+ |FILE_NOTIFY_CHANGE_CREATION,
+ newpath);
+ }
+}
+
/****************************************************************************
Rename an open file - given an fsp.
****************************************************************************/
NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstring newname, uint32 attrs, BOOL replace_if_exists)
{
- SMB_STRUCT_STAT sbuf;
+ SMB_STRUCT_STAT sbuf, sbuf1;
pstring newname_last_component;
NTSTATUS status = NT_STATUS_OK;
- BOOL dest_exists;
struct share_mode_lock *lck = NULL;
+ BOOL dst_exists;
ZERO_STRUCT(sbuf);
return NT_STATUS_OK;
}
- dest_exists = vfs_object_exist(conn,newname,NULL);
+ /*
+ * Have vfs_object_exist also fill sbuf1
+ */
+ dst_exists = vfs_object_exist(conn, newname, &sbuf1);
- if(!replace_if_exists && dest_exists) {
+ if(!replace_if_exists && dst_exists) {
DEBUG(3,("rename_internals_fsp: dest exists doing rename %s -> %s\n",
fsp->fsp_name,newname));
return NT_STATUS_OBJECT_NAME_COLLISION;
}
+ if (dst_exists && file_find_di_first(file_id_sbuf(&sbuf1)) != NULL) {
+ DEBUG(3, ("rename_internals_fsp: Target file open\n"));
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
/* Ensure we have a valid stat struct for the source. */
if (fsp->fh->fd != -1) {
if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) == -1) {
}
}
- status = can_rename(conn,fsp->fsp_name,attrs,&sbuf,True);
+ status = can_rename(conn, fsp, attrs, &sbuf);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3,("rename_internals_fsp: Error %s rename %s -> %s\n",
lck = get_share_mode_lock(NULL, fsp->file_id, NULL, NULL);
+ /*
+ * We have the file open ourselves, so not being able to get the
+ * corresponding share mode lock is a fatal error.
+ */
+
+ SMB_ASSERT(lck != NULL);
+
if(SMB_VFS_RENAME(conn,fsp->fsp_name, newname) == 0) {
uint32 create_options = fsp->fh->private_options;
DEBUG(3,("rename_internals_fsp: succeeded doing rename on %s -> %s\n",
fsp->fsp_name,newname));
- rename_open_files(conn, lck, fsp->file_id, newname);
+ rename_open_files(conn, lck, newname);
+
+ notify_rename(conn, fsp->is_directory, fsp->fsp_name, newname);
/*
* A rename acts as a new file create w.r.t. allowing an initial delete
return status;
}
-/*
- * Do the notify calls from a rename
- */
-
-static void notify_rename(connection_struct *conn, BOOL is_dir,
- const char *oldpath, const char *newpath)
-{
- char *olddir, *newdir;
- const char *oldname, *newname;
- uint32 mask;
-
- mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME
- : FILE_NOTIFY_CHANGE_FILE_NAME;
-
- if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname)
- || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) {
- TALLOC_FREE(olddir);
- return;
- }
-
- if (strcmp(olddir, newdir) == 0) {
- notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath);
- notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath);
- }
- else {
- notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath);
- notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath);
- }
- TALLOC_FREE(olddir);
- TALLOC_FREE(newdir);
-
- /* this is a strange one. w2k3 gives an additional event for
- CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming
- files, but not directories */
- if (!is_dir) {
- notify_fname(conn, NOTIFY_ACTION_MODIFIED,
- FILE_NOTIFY_CHANGE_ATTRIBUTES
- |FILE_NOTIFY_CHANGE_CREATION,
- newpath);
- }
-}
-
/****************************************************************************
The guts of the rename command, split out so it may be called by the NT SMB
code.
****************************************************************************/
-NTSTATUS rename_internals(connection_struct *conn,
+NTSTATUS rename_internals(connection_struct *conn, struct smb_request *req,
pstring name,
pstring newname,
uint32 attrs,
int count=0;
NTSTATUS status = NT_STATUS_OK;
SMB_STRUCT_STAT sbuf1, sbuf2;
- struct share_mode_lock *lck = NULL;
struct smb_Dir *dir_hnd = NULL;
const char *dname;
long offset = 0;
pstring destname;
- struct file_id id;
*directory = *mask = 0;
}
if (!src_has_wild) {
+ files_struct *fsp;
+
/*
* No wildcards - just process the one file.
*/
conn->short_case_preserve, directory,
newname, last_component_dest, is_short_name));
- /* Ensure the source name is valid for us to access. */
- status = check_name(conn, directory);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
/* The dest name still may have wildcards. */
if (dest_has_wild) {
if (!resolve_wildcards(directory,newname)) {
}
}
- /*
- * Check for special case with case preserving and not
- * case sensitive, if directory and newname are identical,
- * and the old last component differs from the original
- * last component only by case, then we should allow
- * the rename (user is trying to change the case of the
- * filename).
- */
- if((conn->case_sensitive == False) &&
- (((conn->case_preserve == True) &&
- (is_short_name == False)) ||
- ((conn->short_case_preserve == True) &&
- (is_short_name == True))) &&
- strcsequal(directory, newname)) {
- pstring modified_last_component;
+ ZERO_STRUCT(sbuf1);
+ SMB_VFS_STAT(conn, directory, &sbuf1);
+
+ status = S_ISDIR(sbuf1.st_mode) ?
+ open_directory(conn, req, directory, &sbuf1,
+ DELETE_ACCESS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, NULL,
+ &fsp)
+ : open_file_ntcreate(conn, req, directory, &sbuf1,
+ DELETE_ACCESS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, 0, NULL,
+ &fsp);
- /*
- * Get the last component of the modified name.
- * Note that we guarantee that newname contains a '/'
- * character above.
- */
- p = strrchr_m(newname,'/');
- pstrcpy(modified_last_component,p+1);
-
- if(strcsequal(modified_last_component,
- last_component_dest) == False) {
- /*
- * Replace the modified last component with
- * the original.
- */
- pstrcpy(p+1, last_component_dest);
- }
- }
-
- /* Ensure the dest name is valid for us to access. */
- status = check_name(conn, newname);
if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("Could not open rename source %s: %s\n",
+ directory, nt_errstr(status)));
return status;
}
- /*
- * The source object must exist.
- */
+ status = rename_internals_fsp(conn, fsp, newname, attrs,
+ replace_if_exists);
- if (!vfs_object_exist(conn, directory, &sbuf1)) {
- DEBUG(3, ("rename_internals: source doesn't exist "
- "doing rename %s -> %s\n",
- directory,newname));
+ close_file(fsp, NORMAL_CLOSE);
- if (errno == ENOTDIR || errno == EISDIR
- || errno == ENOENT) {
- /*
- * Must return different errors depending on
- * whether the parent directory existed or
- * not.
- */
-
- p = strrchr_m(directory, '/');
- if (!p)
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- *p = '\0';
- if (vfs_object_exist(conn, directory, NULL))
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
- }
- status = map_nt_error_from_unix(errno);
- DEBUG(3, ("rename_internals: Error %s rename %s -> "
- "%s\n", nt_errstr(status), directory,
- newname));
-
- return status;
- }
-
- status = can_rename(conn,directory,attrs,&sbuf1,False);
-
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3,("rename_internals: Error %s rename %s -> "
- "%s\n", nt_errstr(status), directory,
- newname));
- return status;
- }
-
- /*
- * If the src and dest names are identical - including case,
- * don't do the rename, just return success.
- */
-
- id = file_id_sbuf(&sbuf1);
-
- if (strcsequal(directory, newname)) {
- rename_open_files(conn, NULL, id, newname);
- DEBUG(3, ("rename_internals: identical names in "
- "rename %s - returning success\n",
- directory));
- return NT_STATUS_OK;
- }
-
- if(!replace_if_exists && vfs_object_exist(conn,newname,NULL)) {
- DEBUG(3,("rename_internals: dest exists doing "
- "rename %s -> %s\n", directory, newname));
- return NT_STATUS_OBJECT_NAME_COLLISION;
- }
-
- if (rename_path_prefix_equal(directory, newname)) {
- return NT_STATUS_SHARING_VIOLATION;
- }
-
- lck = get_share_mode_lock(NULL, id, NULL, NULL);
-
- if(SMB_VFS_RENAME(conn,directory, newname) == 0) {
- DEBUG(3,("rename_internals: succeeded doing rename "
- "on %s -> %s\n", directory, newname));
- rename_open_files(conn, lck, id, newname);
- TALLOC_FREE(lck);
- notify_rename(conn, S_ISDIR(sbuf1.st_mode),
- directory, newname);
- return NT_STATUS_OK;
- }
-
- TALLOC_FREE(lck);
- if (errno == ENOTDIR || errno == EISDIR) {
- status = NT_STATUS_OBJECT_NAME_COLLISION;
- } else {
- status = map_nt_error_from_unix(errno);
- }
-
- DEBUG(3,("rename_internals: Error %s rename %s -> %s\n",
- nt_errstr(status), directory,newname));
+ DEBUG(3, ("rename_internals: Error %s rename %s -> %s\n",
+ nt_errstr(status), directory,newname));
return status;
}
*/
while ((dname = ReadDirName(dir_hnd, &offset))) {
+ files_struct *fsp;
pstring fname;
BOOL sysdir_entry = False;
break;
}
- status = NT_STATUS_ACCESS_DENIED;
slprintf(fname, sizeof(fname)-1, "%s/%s", directory, dname);
- /* Ensure the source name is valid for us to access. */
- status = check_name(conn, fname);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- if (!vfs_object_exist(conn, fname, &sbuf1)) {
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- DEBUG(6, ("rename %s failed. Error %s\n",
- fname, nt_errstr(status)));
- continue;
- }
- status = can_rename(conn,fname,attrs,&sbuf1,False);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(6, ("rename %s refused\n", fname));
- continue;
- }
pstrcpy(destname,newname);
if (!resolve_wildcards(fname,destname)) {
continue;
}
- /* Ensure the dest name is valid for us to access. */
- status = check_name(conn, destname);
+ ZERO_STRUCT(sbuf1);
+ SMB_VFS_STAT(conn, fname, &sbuf1);
+
+ status = S_ISDIR(sbuf1.st_mode) ?
+ open_directory(conn, req, fname, &sbuf1,
+ DELETE_ACCESS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, NULL,
+ &fsp)
+ : open_file_ntcreate(conn, req, fname, &sbuf1,
+ DELETE_ACCESS,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_OPEN, 0, 0, 0, NULL,
+ &fsp);
+
if (!NT_STATUS_IS_OK(status)) {
- return status;
+ DEBUG(3,("rename_internals: open_file_ntcreate "
+ "returned %s rename %s -> %s\n",
+ nt_errstr(status), directory, newname));
+ break;
}
- id = file_id_sbuf(&sbuf1);
+ status = rename_internals_fsp(conn, fsp, destname, attrs,
+ replace_if_exists);
- if (strcsequal(fname,destname)) {
- rename_open_files(conn, NULL, id, newname);
- DEBUG(3,("rename_internals: identical names "
- "in wildcard rename %s - success\n",
- fname));
- count++;
- status = NT_STATUS_OK;
- continue;
- }
+ close_file(fsp, NORMAL_CLOSE);
- if (!replace_if_exists && vfs_file_exist(conn,destname, NULL)) {
- DEBUG(6,("file_exist %s\n", destname));
- status = NT_STATUS_OBJECT_NAME_COLLISION;
- continue;
- }
-
- if (rename_path_prefix_equal(fname, destname)) {
- return NT_STATUS_SHARING_VIOLATION;
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("rename_internals_fsp returned %s for "
+ "rename %s -> %s\n", nt_errstr(status),
+ directory, newname));
+ break;
}
- lck = get_share_mode_lock(NULL, id, NULL, NULL);
+ count++;
- if (!SMB_VFS_RENAME(conn,fname,destname)) {
- rename_open_files(conn, lck, id, newname);
- count++;
- status = NT_STATUS_OK;
- }
- TALLOC_FREE(lck);
DEBUG(3,("rename_internals: doing rename on %s -> "
"%s\n",fname,destname));
}
NTSTATUS status;
BOOL src_has_wcard = False;
BOOL dest_has_wcard = False;
+ struct smb_request req;
START_PROFILE(SMBmv);
+ init_smb_request(&req, (uint8 *)inbuf);
+
p = smb_buf(inbuf) + 1;
- p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &src_has_wcard);
+ p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), name, p,
+ sizeof(name), 0, STR_TERMINATE, &status,
+ &src_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
return ERROR_NT(status);
}
p++;
- p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wcard);
+ p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), newname, p,
+ sizeof(newname), 0, STR_TERMINATE, &status,
+ &dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
return ERROR_NT(status);
DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
- status = rename_internals(conn, name, newname, attrs, False, src_has_wcard, dest_has_wcard);
+ status = rename_internals(conn, &req, name, newname, attrs, False,
+ src_has_wcard, dest_has_wcard);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBmv);
if (open_was_deferred(SVAL(inbuf,smb_mid))) {
}
}
- status = open_file_ntcreate(conn,src,&src_sbuf,
+ status = open_file_ntcreate(conn, NULL, src, &src_sbuf,
FILE_GENERIC_READ,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN,
ZERO_STRUCTP(&sbuf2);
}
- status = open_file_ntcreate(conn,dest,&sbuf2,
+ status = open_file_ntcreate(conn, NULL, dest, &sbuf2,
FILE_GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
new_create_disposition,
*directory = *mask = 0;
p = smb_buf(inbuf);
- p += srvstr_get_path_wcard(inbuf, name, p, sizeof(name), 0, STR_TERMINATE, &status, &source_has_wild);
+ p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), name, p,
+ sizeof(name), 0, STR_TERMINATE, &status,
+ &source_has_wild);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
}
- p += srvstr_get_path_wcard(inbuf, newname, p, sizeof(newname), 0, STR_TERMINATE, &status, &dest_has_wild);
+ p += srvstr_get_path_wcard(inbuf, SVAL(inbuf,smb_flg2), newname, p,
+ sizeof(newname), 0, STR_TERMINATE, &status,
+ &dest_has_wild);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcopy);
return ERROR_NT(status);
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
- srvstr_get_path(inbuf, newdir, smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE, &status);
+ srvstr_get_path(inbuf, SVAL(inbuf,smb_flg2), newdir,
+ smb_buf(inbuf) + 1, sizeof(newdir), 0, STR_TERMINATE,
+ &status);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(pathworks_setdir);
return ERROR_NT(status);
int smb_doff;
char *data;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ NTSTATUS status;
START_PROFILE(SMBwriteBmpx);
CHECK_FSP(fsp,conn);
nwritten = write_file(fsp,data,startpos,numtowrite);
- sync_file(conn, fsp, write_through);
+ status = sync_file(conn, fsp, write_through);
+ if (!NT_STATUS_IS_OK(status)) {
+ END_PROFILE(SMBwriteBmpx);
+ DEBUG(5,("reply_writebmpx: sync_file for %s returned %s\n",
+ fsp->fsp_name, nt_errstr(status) ));
+ return ERROR_NT(status);
+ }
if(nwritten < (ssize_t)numtowrite) {
END_PROFILE(SMBwriteBmpx);
write_bmpx_struct *wbms;
BOOL send_response = False;
files_struct *fsp = file_fsp(inbuf,smb_vwv0);
+ NTSTATUS status;
START_PROFILE(SMBwriteBs);
CHECK_FSP(fsp,conn);
nwritten = write_file(fsp,data,startpos,numtowrite);
- sync_file(conn, fsp, write_through);
+ status = sync_file(conn, fsp, write_through);
- if (nwritten < (ssize_t)numtowrite) {
+ if (nwritten < (ssize_t)numtowrite || !NT_STATUS_IS_OK(status)) {
if(write_through) {
/* We are returning an error - we can delete the aux struct */
if (wbms)