diff options
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/config.h.in | 1 | ||||
-rw-r--r-- | source3/include/smb.h | 1 | ||||
-rw-r--r-- | source3/include/smb_macros.h | 3 | ||||
-rw-r--r-- | source3/smbd/nttrans.c | 40 | ||||
-rw-r--r-- | source3/smbd/trans2.c | 47 |
5 files changed, 66 insertions, 26 deletions
diff --git a/source3/include/config.h.in b/source3/include/config.h.in index 4a138b6db6..8c06e25396 100644 --- a/source3/include/config.h.in +++ b/source3/include/config.h.in @@ -252,6 +252,7 @@ #undef HAVE_LDAP #undef HAVE_STAT_ST_BLOCKS #undef STAT_ST_BLOCKSIZE +#undef HAVE_STAT_ST_BLKSIZE #undef HAVE_DEVICE_MAJOR_FN #undef HAVE_DEVICE_MINOR_FN #undef HAVE_PASSWD_PW_COMMENT diff --git a/source3/include/smb.h b/source3/include/smb.h index 9101e947a7..958a563642 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -391,6 +391,7 @@ typedef struct files_struct BOOL delete_on_close; SMB_OFF_T pos; SMB_OFF_T size; + SMB_OFF_T initial_allocation_size; /* Faked up initial allocation on disk. */ mode_t mode; uint16 vuid; write_bmpx_struct *wbmpx_ptr; diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h index a2351c705e..ccf151fab2 100644 --- a/source3/include/smb_macros.h +++ b/source3/include/smb_macros.h @@ -165,8 +165,7 @@ /* this is how errors are generated */ #define UNIXERROR(defclass,deferror) unix_error_packet(outbuf,defclass,deferror,__LINE__,__FILE__) -#define SMB_ROUNDUP(x,g) (((x)+((g)-1))&~((g)-1)) -#define SMB_ROUNDUP_ALLOCATION(s) ((s) ? (SMB_ROUNDUP((SMB_OFF_T)((s)+1), ((SMB_OFF_T)SMB_ROUNDUP_ALLOCATION_SIZE))) : 0 ) +#define SMB_ROUNDUP(x,r) ( ((x)%(r)) ? ( (((x)+(r))/(r))*(r) ) : (x)) /* Extra macros added by Ying Chen at IBM - speed increase by inlining. */ #define smb_buf(buf) (((char *)(buf)) + smb_size + CVAL(buf,smb_wct)*2) diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index 722a7ff8bf..ff35771644 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -548,6 +548,7 @@ int reply_ntcreate_and_X(connection_struct *conn, uint32 create_disposition = IVAL(inbuf,smb_ntcreate_CreateDisposition); uint32 create_options = IVAL(inbuf,smb_ntcreate_CreateOptions); uint16 root_dir_fid = (uint16)IVAL(inbuf,smb_ntcreate_RootDirectoryFid); + SMB_OFF_T allocation_size = 0; int smb_ofun; int smb_open_mode; int smb_attr = (file_attributes & SAMBA_ATTRIBUTES_MASK); @@ -571,7 +572,7 @@ int reply_ntcreate_and_X(connection_struct *conn, file_attributes = 0x%x, share_access = 0x%x, create_disposition = 0x%x \ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attributes, share_access, create_disposition, - root_dir_fid, create_options )); + create_options, root_dir_fid )); /* If it's an IPC, use the pipe handler. */ @@ -805,6 +806,22 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib return ERROR_DOS(ERRDOS,ERRnoaccess); } + /* Save the requested allocation size. */ + allocation_size = IVAL(inbuf,smb_ntcreate_AllocationSize); +#ifdef LARGE_SMB_OFF_T + allocation_size |= (((SMB_OFF_T)IVAL(inbuf,smb_ntcreate_AllocationSize + 4)) << 32); +#endif + if (allocation_size && (allocation_size > file_len)) { + fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); + if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { + close_file(fsp,False); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + } else { + fsp->initial_allocation_size = SMB_ROUNDUP(file_len,SMB_ROUNDUP_ALLOCATION_SIZE); + } + /* * If the caller set the extended oplock request bit * and we granted one (by whatever means) - set the @@ -869,7 +886,7 @@ create_options = 0x%x root_dir_fid = 0x%x\n", flags, desired_access, file_attrib p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, get_allocation_size(&sbuf)); + SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); p += 12; @@ -1045,6 +1062,7 @@ static int call_nt_transact_create(connection_struct *conn, uint32 create_options; uint32 sd_len; uint16 root_dir_fid; + SMB_OFF_T allocation_size = 0; int smb_ofun; int smb_open_mode; int smb_attr; @@ -1282,6 +1300,22 @@ static int call_nt_transact_create(connection_struct *conn, restore_case_semantics(file_attributes); + /* Save the requested allocation size. */ + allocation_size = IVAL(params,12); +#ifdef LARGE_SMB_OFF_T + allocation_size |= (((SMB_OFF_T)IVAL(params,16)) << 32); +#endif + if (allocation_size && (allocation_size > file_len)) { + fsp->initial_allocation_size = SMB_ROUNDUP(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); + if (vfs_allocate_file_space(fsp, fsp->initial_allocation_size) == -1) { + close_file(fsp,False); + END_PROFILE(SMBntcreateX); + return ERROR_NT(NT_STATUS_DISK_FULL); + } + } else { + fsp->initial_allocation_size = SMB_ROUNDUP(file_len,SMB_ROUNDUP_ALLOCATION_SIZE); + } + /* Realloc the size of parameters and data we will return */ params = Realloc(*ppparams, 69); if(params == NULL) @@ -1325,7 +1359,7 @@ static int call_nt_transact_create(connection_struct *conn, p += 8; SIVAL(p,0,fmode); /* File Attributes. */ p += 4; - SOFF_T(p, 0, get_allocation_size(&sbuf)); + SOFF_T(p, 0, get_allocation_size(fsp,&sbuf)); p += 8; SOFF_T(p,0,file_len); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 91e76012e6..8def7c0250 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -30,19 +30,26 @@ extern int global_oplock_break; extern uint32 global_client_caps; extern pstring global_myname; +#define get_file_size(sbuf) (sbuf.st_size) + /* given a stat buffer return the allocated size on disk, taking into account sparse files */ -SMB_OFF_T get_allocation_size(SMB_STRUCT_STAT *sbuf) +SMB_OFF_T get_allocation_size(files_struct *fsp, SMB_STRUCT_STAT *sbuf) { SMB_OFF_T ret; +#if defined(HAVE_STAT_ST_BLKSIZE) && defined(HAVE_STAT_ST_BLOCKS) ret = sbuf->st_blksize * (SMB_OFF_T)sbuf->st_blocks; - ret = SMB_ROUNDUP_ALLOCATION(ret); +#elif defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) + ret = (SMB_OFF_T)STAT_ST_BLOCKSIZE * (SMB_OFF_T)sbuf->st_blocks; +#else + ret = get_file_size(*sbuf); +#endif + if (!ret && fsp && fsp->initial_allocation_size) + ret = fsp->initial_allocation_size; + ret = SMB_ROUNDUP(ret,SMB_ROUNDUP_ALLOCATION_SIZE); return ret; } -#define get_file_size(sbuf) (sbuf.st_size) - - /**************************************************************************** Send the required number of replies back. We assume all fields other than the data fields are @@ -579,7 +586,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, } file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(&sbuf); + allocation_size = get_allocation_size(NULL,&sbuf); mdate = sbuf.st_mtime; adate = sbuf.st_atime; cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn))); @@ -756,12 +763,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn, SOFF_T(p,0,get_file_size(sbuf)); /* File size 64 Bit */ p+= 8; -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - SOFF_T(p,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ -#else - /* Can't get the value - fake it using size. */ - SOFF_T(p,0,get_file_size(sbuf)); /* Number of bytes used on disk - 64 Bit */ -#endif + SOFF_T(p,0,get_allocation_size(NULL,&sbuf)); /* Number of bytes used on disk - 64 Bit */ p+= 8; put_long_date(p,sbuf.st_ctime); /* Creation Time 64 Bit */ @@ -1559,12 +1561,16 @@ static int call_trans2qfilepathinfo(connection_struct *conn, BOOL delete_pending = False; int len; time_t c_time; + files_struct *fsp = NULL; if (!params) return ERROR_NT(NT_STATUS_INVALID_PARAMETER); if (tran_call == TRANSACT2_QFILEINFO) { - files_struct *fsp = file_fsp(params,0); + if (total_params < 4) + return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + + fsp = file_fsp(params,0); info_level = SVAL(params,2); DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QFILEINFO: level = %d\n", info_level)); @@ -1662,7 +1668,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, mode = dos_mode(conn,fname,&sbuf); fullpathname = fname; file_size = get_file_size(sbuf); - allocation_size = get_allocation_size(&sbuf); + allocation_size = get_allocation_size(fsp,&sbuf); if (mode & aDIR) file_size = 0; @@ -1982,12 +1988,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn, SOFF_T(pdata,0,get_file_size(sbuf)); /* File size 64 Bit */ pdata += 8; -#if defined(HAVE_STAT_ST_BLOCKS) && defined(STAT_ST_BLOCKSIZE) - SOFF_T(pdata,0,sbuf.st_blocks*STAT_ST_BLOCKSIZE); /* Number of bytes used on disk - 64 Bit */ -#else - /* Can't get the value - fake it using size. */ - SOFF_T(pdata,0,get_file_size(sbuf)); /* Number of bytes used on disk - 64 Bit */ -#endif + SOFF_T(pdata,0,get_allocation_size(fsp,&sbuf)); /* Number of bytes used on disk - 64 Bit */ pdata += 8; put_long_date(pdata,sbuf.st_ctime); /* Creation Time 64 Bit */ @@ -2422,11 +2423,12 @@ static int call_trans2setfilepathinfo(connection_struct *conn, case SMB_SET_FILE_ALLOCATION_INFO: { int ret = -1; - SMB_OFF_T allocation_size = IVAL(pdata,0); + SMB_OFF_T allocation_size; if (total_data < 8) return(ERROR_DOS(ERRDOS,ERRinvalidparam)); + allocation_size = IVAL(pdata,0); #ifdef LARGE_SMB_OFF_T allocation_size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32); #else /* LARGE_SMB_OFF_T */ @@ -2436,6 +2438,9 @@ static int call_trans2setfilepathinfo(connection_struct *conn, 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(allocation_size,SMB_ROUNDUP_ALLOCATION_SIZE); + if(allocation_size != get_file_size(sbuf)) { SMB_STRUCT_STAT new_sbuf; |