an initial fix for handling sparse files in smbd
authorAndrew Tridgell <tridge@samba.org>
Mon, 29 Jul 2002 11:14:05 +0000 (11:14 +0000)
committerAndrew Tridgell <tridge@samba.org>
Mon, 29 Jul 2002 11:14:05 +0000 (11:14 +0000)
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.

source/include/includes.h
source/include/ntioctl.h [new file with mode: 0644]
source/smbd/dosmode.c
source/smbd/nttrans.c
source/smbd/trans2.c

index 04d11afafb9648e02783059acfa0f89d9f68e221..6084d583ed6aa5b5235f520f16a76ce39bc81188 100644 (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"
diff --git a/source/include/ntioctl.h b/source/include/ntioctl.h
new file mode 100644 (file)
index 0000000..4749842
--- /dev/null
@@ -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
index dcffe3aa90a4b98051a95f3e5697149336b28692..77d8c9cc920ffcf64e06c8dd3ede4d46f919ac6f 100644 (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;
-    }
-
-  /* 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);
 }
 
 /*******************************************************************
index 8f6b4ab374e85121c4253d1f1dc1330499ea0dec..cf69dfddb049fa6044c56634d47a19ddaeb278dc 100644 (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:
index 7da1758decc2fee8b96c191d36efb78ffa6eb17b..3a8e41c654618d72d43e27790f61c0c462bf9601 100644 (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;
                        }