From: Andrew Tridgell Date: Mon, 29 Jul 2002 11:14:05 +0000 (+0000) Subject: an initial fix for handling sparse files in smbd X-Git-Tag: release-19~142 X-Git-Url: http://git.samba.org/?p=import%2Fsamba-cvsimport.git;a=commitdiff_plain;h=7dfdb456d4c9bcf6ecb1f7e5c5e79989f95e5627 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. --- diff --git a/source/include/includes.h b/source/include/includes.h index 04d11afaf..6084d583e 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -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" diff --git a/source/include/ntioctl.h b/source/include/ntioctl.h new file mode 100644 index 000000000..4749842dd --- /dev/null +++ b/source/include/ntioctl.h @@ -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 diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index dcffe3aa9..77d8c9cc9 100644 --- a/source/smbd/dosmode.c +++ b/source/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/source/smbd/nttrans.c b/source/smbd/nttrans.c index 8f6b4ab37..cf69dfddb 100644 --- a/source/smbd/nttrans.c +++ b/source/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, ¶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: diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 7da1758de..3a8e41c65 100644 --- a/source/smbd/trans2.c +++ b/source/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; }