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:
parent
8c85675b07
commit
1ea873e0a0
@ -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
26
source3/include/ntioctl.h
Normal 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
|
@ -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);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
|
@ -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, ¶ms, &data);
|
||||
length, bufsize,
|
||||
&setup, setup_count,
|
||||
¶ms, parameter_count,
|
||||
&data, data_count);
|
||||
END_PROFILE_NESTED(NT_transact_ioctl);
|
||||
break;
|
||||
case NT_TRANSACT_SET_SECURITY_DESC:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user