1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-23 17:34:34 +03:00

an initial fix for handling sparse files in smbd

This gets my test code working, where we previously failed with files
above 20G in size.

I'm still not completely happy with this. There are just too many
fields in trans2.c that we don't fill in.
(This used to be commit 7dfdb456d4)
This commit is contained in:
Andrew Tridgell 2002-07-29 11:14:05 +00:00
parent 8c85675b07
commit 1ea873e0a0
5 changed files with 138 additions and 72 deletions

View File

@ -707,6 +707,7 @@ extern int errno;
#include "hash.h"
#include "trans2.h"
#include "nterr.h"
#include "ntioctl.h"
#include "messages.h"
#include "charset.h"
#include "dynconfig.h"

26
source3/include/ntioctl.h Normal file
View File

@ -0,0 +1,26 @@
/*
Unix SMB/CIFS implementation.
NT ioctl code constants
Copyright (C) Andrew Tridgell 2002
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
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
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.
*/
/*
I'm guessing we will need to support a bunch of these eventually. For now
we only need the sparse flag
*/
#define NTIOCTL_SET_SPARSE 0x900c4

View File

@ -115,65 +115,67 @@ mode_t unix_mode(connection_struct *conn,int dosmode,const char *fname)
/****************************************************************************
change a unix mode to a dos mode
****************************************************************************/
int dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
uint32 dos_mode(connection_struct *conn,char *path,SMB_STRUCT_STAT *sbuf)
{
int result = 0;
int result = 0;
DEBUG(8,("dos_mode: %s\n", path));
DEBUG(8,("dos_mode: %s\n", path));
if ((sbuf->st_mode & S_IWUSR) == 0)
result |= aRONLY;
if ((sbuf->st_mode & S_IWUSR) == 0)
result |= aRONLY;
if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
result |= aARCH;
if (MAP_ARCHIVE(conn) && ((sbuf->st_mode & S_IXUSR) != 0))
result |= aARCH;
if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
result |= aSYSTEM;
if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
result |= aHIDDEN;
if (MAP_SYSTEM(conn) && ((sbuf->st_mode & S_IXGRP) != 0))
result |= aSYSTEM;
if (MAP_HIDDEN(conn) && ((sbuf->st_mode & S_IXOTH) != 0))
result |= aHIDDEN;
if (S_ISDIR(sbuf->st_mode))
result = aDIR | (result & aRONLY);
if (S_ISDIR(sbuf->st_mode))
result = aDIR | (result & aRONLY);
if (sbuf->st_size > sbuf->st_blocks * (SMB_OFF_T)sbuf->st_blksize) {
result |= FILE_ATTRIBUTE_SPARSE;
}
#ifdef S_ISLNK
#if LINKS_READ_ONLY
if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
result |= aRONLY;
if (S_ISLNK(sbuf->st_mode) && S_ISDIR(sbuf->st_mode))
result |= aRONLY;
#endif
#endif
/* hide files with a name starting with a . */
if (lp_hide_dot_files(SNUM(conn)))
{
char *p = strrchr_m(path,'/');
if (p)
p++;
else
p = path;
if (p[0] == '.' && p[1] != '.' && p[1] != 0)
result |= aHIDDEN;
}
/* hide files with a name starting with a . */
if (lp_hide_dot_files(SNUM(conn))) {
char *p = strrchr_m(path,'/');
if (p)
p++;
else
p = path;
if (p[0] == '.' && p[1] != '.' && p[1] != 0)
result |= aHIDDEN;
}
/* Optimization : Only call is_hidden_path if it's not already
hidden. */
if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path)) {
result |= aHIDDEN;
}
/* Optimization : Only call is_hidden_path if it's not already
hidden. */
if (!(result & aHIDDEN) && IS_HIDDEN_PATH(conn,path))
{
result |= aHIDDEN;
}
DEBUG(8,("dos_mode returning "));
DEBUG(8,("dos_mode returning "));
if (result & aHIDDEN) DEBUG(8, ("h"));
if (result & aRONLY ) DEBUG(8, ("r"));
if (result & aSYSTEM) DEBUG(8, ("s"));
if (result & aDIR ) DEBUG(8, ("d"));
if (result & aARCH ) DEBUG(8, ("a"));
DEBUG(8,("\n"));
if (result & aHIDDEN) DEBUG(8, ("h"));
if (result & aRONLY ) DEBUG(8, ("r"));
if (result & aSYSTEM) DEBUG(8, ("s"));
if (result & aDIR ) DEBUG(8, ("d"));
if (result & aARCH ) DEBUG(8, ("a"));
DEBUG(8,("\n"));
return(result);
return(result);
}
/*******************************************************************

View File

@ -851,7 +851,7 @@ int reply_ntcreate_and_X(connection_struct *conn,
p += 8;
SIVAL(p,0,fmode); /* File Attributes. */
p += 4;
SOFF_T(p, 0, SMB_ROUNDUP_ALLOCATION(file_len));
SOFF_T(p, 0, get_allocation_size(&sbuf));
p += 8;
SOFF_T(p,0,file_len);
p += 12;
@ -1295,7 +1295,7 @@ static int call_nt_transact_create(connection_struct *conn,
p += 8;
SIVAL(p,0,fmode); /* File Attributes. */
p += 4;
SOFF_T(p, 0, SMB_ROUNDUP_ALLOCATION(file_len));
SOFF_T(p, 0, get_allocation_size(&sbuf));
p += 8;
SOFF_T(p,0,file_len);
@ -1594,21 +1594,46 @@ static int call_nt_transact_set_security_desc(connection_struct *conn,
}
/****************************************************************************
Reply to IOCTL - not implemented - no plans.
Reply to NT IOCTL
****************************************************************************/
static int call_nt_transact_ioctl(connection_struct *conn,
char *inbuf, char *outbuf, int length,
int bufsize,
char **ppsetup, char **ppparams, char **ppdata)
char **ppsetup, int setup_count,
char **ppparams, int parameter_count,
char **ppdata, int data_count)
{
static BOOL logged_message = False;
unsigned fnum, control;
static BOOL logged_message;
if(!logged_message) {
DEBUG(3,("call_nt_transact_ioctl: Currently not implemented.\n"));
logged_message = True; /* Only print this once... */
if (setup_count != 8) {
DEBUG(3,("call_nt_transact_ioctl: invalid setup count %d\n", setup_count));
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
}
return ERROR_DOS(ERRSRV,ERRnosupport);
fnum = SVAL(*ppsetup, 4);
control = IVAL(*ppsetup, 0);
DEBUG(6,("call_nt_transact_ioctl: fnum=%d control=0x%x\n",
fnum, control));
switch (control) {
case NTIOCTL_SET_SPARSE:
/* pretend this succeeded - tho strictly we should
mark the file sparse (if the local fs supports it)
so we can know if we need to pre-allocate or not */
send_nt_replies(inbuf, outbuf, bufsize, NT_STATUS_OK, NULL, 0, NULL, 0);
return -1;
default:
if (!logged_message) {
logged_message = True; /* Only print this once... */
DEBUG(3,("call_nt_transact_ioctl(0x%x): Currently not implemented.\n",
control));
}
}
return ERROR_NT(NT_STATUS_NOT_SUPPORTED);
}
/****************************************************************************
@ -1769,8 +1794,10 @@ due to being in oplock break state.\n", (unsigned int)function_code ));
case NT_TRANSACT_IOCTL:
START_PROFILE_NESTED(NT_transact_ioctl);
outsize = call_nt_transact_ioctl(conn, inbuf, outbuf,
length, bufsize,
&setup, &params, &data);
length, bufsize,
&setup, setup_count,
&params, parameter_count,
&data, data_count);
END_PROFILE_NESTED(NT_transact_ioctl);
break;
case NT_TRANSACT_SET_SECURITY_DESC:

View File

@ -30,6 +30,17 @@ extern int global_oplock_break;
extern uint32 global_client_caps;
extern pstring global_myname;
/* 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 ret;
ret = sbuf->st_blksize * (SMB_OFF_T)sbuf->st_blocks;
ret = SMB_ROUNDUP_ALLOCATION(ret);
return ret;
}
/****************************************************************************
Send the required number of replies back.
We assume all fields other than the data fields are
@ -566,7 +577,7 @@ static BOOL get_lanman2_dir_entry(connection_struct *conn,
}
size = sbuf.st_size;
allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size);
allocation_size = get_allocation_size(&sbuf);
mdate = sbuf.st_mtime;
adate = sbuf.st_atime;
cdate = get_create_time(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
@ -1528,7 +1539,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
uint16 tran_call = SVAL(inbuf, smb_setup0);
uint16 info_level;
int mode=0;
SMB_OFF_T size=0;
SMB_OFF_T file_size=0;
SMB_OFF_T allocation_size=0;
unsigned int data_size;
SMB_STRUCT_STAT sbuf;
@ -1643,10 +1654,10 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
mode = dos_mode(conn,fname,&sbuf);
fullpathname = fname;
size = sbuf.st_size;
allocation_size = SMB_ROUNDUP_ALLOCATION(sbuf.st_size);
file_size = sbuf.st_size;
allocation_size = get_allocation_size(&sbuf);
if (mode & aDIR)
size = 0;
file_size = 0;
params = Realloc(*pparams,2);
if (params == NULL)
@ -1692,7 +1703,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_dos_date2(pdata,l1_fdateCreation,c_time);
put_dos_date2(pdata,l1_fdateLastAccess,sbuf.st_atime);
put_dos_date2(pdata,l1_fdateLastWrite,sbuf.st_mtime); /* write time */
SIVAL(pdata,l1_cbFile,(uint32)size);
SIVAL(pdata,l1_cbFile,(uint32)file_size);
SIVAL(pdata,l1_cbFileAlloc,(uint32)allocation_size);
SSVAL(pdata,l1_attrFile,mode);
SIVAL(pdata,l1_attrFile+2,4); /* this is what OS2 does */
@ -1703,7 +1714,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_dos_date2(pdata,0,c_time);
put_dos_date2(pdata,4,sbuf.st_atime);
put_dos_date2(pdata,8,sbuf.st_mtime);
SIVAL(pdata,12,(uint32)size);
SIVAL(pdata,12,(uint32)file_size);
SIVAL(pdata,16,(uint32)allocation_size);
SIVAL(pdata,20,mode);
break;
@ -1747,9 +1758,8 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
case SMB_QUERY_FILE_STANDARD_INFO:
data_size = 24;
/* Fake up allocation size. */
SOFF_T(pdata,0,allocation_size);
SOFF_T(pdata,8,size);
SOFF_T(pdata,8,file_size);
SIVAL(pdata,16,sbuf.st_nlink);
SCVAL(pdata,20,0);
SCVAL(pdata,21,(mode&aDIR)?1:0);
@ -1794,7 +1804,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
case SMB_FILE_END_OF_FILE_INFORMATION:
case SMB_QUERY_FILE_END_OF_FILEINFO:
data_size = 8;
SOFF_T(pdata,0,size);
SOFF_T(pdata,0,file_size);
break;
case SMB_QUERY_FILE_ALL_INFO:
@ -1805,7 +1815,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
SIVAL(pdata,32,mode);
pdata += 40;
SOFF_T(pdata,0,allocation_size);
SOFF_T(pdata,8,size);
SOFF_T(pdata,8,file_size);
SIVAL(pdata,16,sbuf.st_nlink);
SCVAL(pdata,20,delete_pending);
SCVAL(pdata,21,(mode&aDIR)?1:0);
@ -1917,7 +1927,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", 0xE, False);
SIVAL(pdata,0,0); /* ??? */
SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
SOFF_T(pdata,8,size);
SOFF_T(pdata,8,file_size);
SIVAL(pdata,16,allocation_size);
SIVAL(pdata,20,0); /* ??? */
data_size = 24 + byte_len;
@ -1925,7 +1935,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
break;
case SMB_FILE_COMPRESSION_INFORMATION:
SOFF_T(pdata,0,size);
SOFF_T(pdata,0,allocation_size);
SIVAL(pdata,8,0); /* ??? */
SIVAL(pdata,12,0); /* ??? */
data_size = 16;
@ -1937,7 +1947,7 @@ static int call_trans2qfilepathinfo(connection_struct *conn,
put_long_date(pdata+16,sbuf.st_mtime); /* write time */
put_long_date(pdata+24,sbuf.st_mtime); /* change time */
SIVAL(pdata,32,allocation_size);
SOFF_T(pdata,40,size);
SOFF_T(pdata,40,file_size);
SIVAL(pdata,48,mode);
SIVAL(pdata,52,0); /* ??? */
data_size = 56;
@ -2460,7 +2470,7 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
if (ret == -1)
return ERROR_NT(NT_STATUS_DISK_FULL);
/* Allocate can trucate size... */
/* Allocate can truncate size... */
size = new_sbuf.st_size;
}