diff options
-rw-r--r-- | source3/smbd/trans2.c | 168 |
1 files changed, 99 insertions, 69 deletions
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 4bbef4dc45..063eca17e0 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -1,7 +1,7 @@ /* Unix SMB/CIFS implementation. SMB transaction2 handling - Copyright (C) Jeremy Allison 1994-2003 + Copyright (C) Jeremy Allison 1994-2007 Copyright (C) Stefan (metze) Metzmacher 2003 Copyright (C) Volker Lendecke 2005 Copyright (C) Steve French 2005 @@ -4346,6 +4346,92 @@ static NTSTATUS smb_set_file_basic_info(const char *pdata, int total_data, struc } /**************************************************************************** + Deal with SMB_SET_FILE_ALLOCATION_INFO. +****************************************************************************/ + +static NTSTATUS smb_set_file_allocation_info(connection_struct *conn, + const char *pdata, + int total_data, + files_struct *fsp, + const char *fname, + SMB_STRUCT_STAT *psbuf, + SMB_OFF_T *p_size) +{ + int ret = -1; + SMB_BIG_UINT allocation_size; + + if (total_data < 8) { + return NT_STATUS_INVALID_PARAMETER; + } + + allocation_size = (SMB_BIG_UINT)IVAL(pdata,0); +#ifdef LARGE_SMB_OFF_T + allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32); +#else /* LARGE_SMB_OFF_T */ + if (IVAL(pdata,4) != 0) { + /* more than 32 bits? */ + return NT_STATUS_INVALID_PARAMETER; + } +#endif /* LARGE_SMB_OFF_T */ + + DEBUG(10,("smb_set_file_allocation_info: Set file allocation info for file %s to %.0f\n", + fname, (double)allocation_size )); + + if (allocation_size) { + allocation_size = smb_roundup(conn, allocation_size); + } + + if(allocation_size != get_file_size(*psbuf)) { + SMB_STRUCT_STAT new_sbuf; + + DEBUG(10,("smb_set_file_allocation_info: file %s : setting new allocation size to %.0f\n", + fname, (double)allocation_size )); + + if (fsp && fsp->fh->fd != -1) { + /* Open file. */ + ret = vfs_allocate_file_space(fsp, allocation_size); + if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&new_sbuf) != 0) { + DEBUG(3,("smb_set_file_allocation_info: fstat of fnum %d failed (%s)\n", + fsp->fnum, strerror(errno))); + ret = -1; + } + } else { + /* Pathname or stat or directory file. */ + files_struct *new_fsp = NULL; + NTSTATUS status; + + status = open_file_ntcreate(conn, fname, psbuf, + FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN, + 0, + FILE_ATTRIBUTE_NORMAL, + FORCE_OPLOCK_BREAK_TO_NONE, + NULL, &new_fsp); + + if (!NT_STATUS_IS_OK(status)) { + /* NB. We check for open_was_deferred in the caller. */ + return status; + } + ret = vfs_allocate_file_space(new_fsp, allocation_size); + if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) { + DEBUG(3,("smb_set_file_allocation_info: fstat of fnum %d failed (%s)\n", + new_fsp->fnum, strerror(errno))); + ret = -1; + } + close_file(new_fsp,NORMAL_CLOSE); + } + if (ret == -1) { + return NT_STATUS_DISK_FULL; + } + + /* Allocate can truncate size... */ + *p_size = get_file_size(new_sbuf); + } + return NT_STATUS_OK; +} + +/**************************************************************************** Reply to a TRANS2_SETFILEINFO (set file info by fileid or pathname). ****************************************************************************/ @@ -4527,76 +4613,20 @@ static int call_trans2setfilepathinfo(connection_struct *conn, char *inbuf, char case SMB_FILE_ALLOCATION_INFORMATION: case SMB_SET_FILE_ALLOCATION_INFO: { - int ret = -1; - SMB_BIG_UINT allocation_size; - - if (total_data < 8) { - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } - - allocation_size = (SMB_BIG_UINT)IVAL(pdata,0); -#ifdef LARGE_SMB_OFF_T - allocation_size |= (((SMB_BIG_UINT)IVAL(pdata,4)) << 32); -#else /* LARGE_SMB_OFF_T */ - if (IVAL(pdata,4) != 0) { - /* more than 32 bits? */ - return ERROR_NT(NT_STATUS_INVALID_PARAMETER); - } -#endif /* LARGE_SMB_OFF_T */ - DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", - fname, (double)allocation_size )); - - if (allocation_size) { - allocation_size = smb_roundup(conn, allocation_size); - } - - if(allocation_size != get_file_size(sbuf)) { - SMB_STRUCT_STAT new_sbuf; - - DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new allocation size to %.0f\n", - fname, (double)allocation_size )); - - if (fd == -1) { - files_struct *new_fsp = NULL; - - status = open_file_ntcreate(conn, fname, &sbuf, - FILE_WRITE_DATA, - FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, - FILE_OPEN, - 0, - FILE_ATTRIBUTE_NORMAL, - FORCE_OPLOCK_BREAK_TO_NONE, - NULL, &new_fsp); - - if (!NT_STATUS_IS_OK(status)) { - if (open_was_deferred(SVAL(inbuf,smb_mid))) { - /* We have re-scheduled this call. */ - return -1; - } - return(UNIXERROR(ERRDOS,ERRnoaccess)); - } - ret = vfs_allocate_file_space(new_fsp, allocation_size); - if (SMB_VFS_FSTAT(new_fsp,new_fsp->fh->fd,&new_sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", - new_fsp->fnum, strerror(errno))); - ret = -1; - } - close_file(new_fsp,NORMAL_CLOSE); - } else { - ret = vfs_allocate_file_space(fsp, allocation_size); - if (SMB_VFS_FSTAT(fsp,fd,&new_sbuf) != 0) { - DEBUG(3,("call_trans2setfilepathinfo: fstat of fnum %d failed (%s)\n", - fsp->fnum, strerror(errno))); - ret = -1; - } + status = smb_set_file_allocation_info(conn, + pdata, + total_data, + fsp, + fname, + &sbuf, + &size); + if (!NT_STATUS_IS_OK(status)) { + if (open_was_deferred(SVAL(inbuf,smb_mid))) { + /* We have re-scheduled this call. */ + return -1; } - if (ret == -1) - return ERROR_NT(NT_STATUS_DISK_FULL); - - /* Allocate can truncate size... */ - size = get_file_size(new_sbuf); + return ERROR_NT(status); } - break; } |