summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2002-07-29 11:14:05 +0000
committerAndrew Tridgell <tridge@samba.org>2002-07-29 11:14:05 +0000
commit1ea873e0a07ed146ccfa61acd746de85df9ffb97 (patch)
treeaeac011a0b2be5a0b47b359d59e4a0c3bfd3293d /source3/smbd
parent8c85675b075404a333c8cc3d653b949e33ddc6a8 (diff)
downloadsamba-1ea873e0a07ed146ccfa61acd746de85df9ffb97.tar.gz
samba-1ea873e0a07ed146ccfa61acd746de85df9ffb97.tar.bz2
samba-1ea873e0a07ed146ccfa61acd746de85df9ffb97.zip
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 7dfdb456d4c9bcf6ecb1f7e5c5e79989f95e5627)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/dosmode.c92
-rw-r--r--source3/smbd/nttrans.c51
-rw-r--r--source3/smbd/trans2.c40
3 files changed, 111 insertions, 72 deletions
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index dcffe3aa90..77d8c9cc92 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -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;
- }
-
- /* 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 "));
+ /* 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;
+ }
- 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,("dos_mode returning "));
- 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);
}
/*******************************************************************
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 8f6b4ab374..cf69dfddb0 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -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:
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 7da1758dec..3a8e41c654 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -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;
}