]> git.ipfire.org Git - thirdparty/samba.git/commitdiff
Added "strict allocate" per share parameter. This causes actual on-disk allocation
authorJeremy Allison <jra@samba.org>
Wed, 1 Aug 2001 22:13:50 +0000 (22:13 +0000)
committerJeremy Allison <jra@samba.org>
Wed, 1 Aug 2001 22:13:50 +0000 (22:13 +0000)
to be done. Without it just does the ftruncate.
Jeremy.

source/param/loadparm.c
source/smbd/trans2.c
source/smbd/vfs.c

index a1871437ac30458482d546e77ab015766bb06e88..e4cd3a798289b36975c5481e8a94f229abc56a09 100644 (file)
@@ -363,6 +363,7 @@ typedef struct
        BOOL bWidelinks;
        BOOL bSymlinks;
        BOOL bSyncAlways;
+       BOOL bStrictAllocate;
        BOOL bStrictSync;
        char magic_char;
        BOOL *copymap;
@@ -476,6 +477,7 @@ static service sDefault = {
        True,                   /* bWidelinks */
        True,                   /* bSymlinks */
        False,                  /* bSyncAlways */
+       False,                  /* bStrictAllocate */
        False,                  /* bStrictSync */
        '~',                    /* magic char */
        NULL,                   /* copymap */
@@ -798,6 +800,7 @@ static struct parm_struct parm_table[] = {
        
        {"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL, NULL, 0},
        {"stat cache size", P_INTEGER, P_GLOBAL, &Globals.stat_cache_size, NULL, NULL, 0},
+       {"strict allocate", P_BOOL, P_LOCAL, &sDefault.bStrictAllocate, NULL, NULL, FLAG_SHARE},
        {"strict sync", P_BOOL, P_LOCAL, &sDefault.bStrictSync, NULL, NULL, FLAG_SHARE},
        {"sync always", P_BOOL, P_LOCAL, &sDefault.bSyncAlways, NULL, NULL, FLAG_SHARE},
        {"use mmap", P_BOOL, P_GLOBAL, &Globals.bUseMmap, NULL, NULL, 0},
@@ -1640,6 +1643,7 @@ FN_LOCAL_BOOL(lp_manglednames, bMangledNames)
 FN_LOCAL_BOOL(lp_widelinks, bWidelinks)
 FN_LOCAL_BOOL(lp_symlinks, bSymlinks)
 FN_LOCAL_BOOL(lp_syncalways, bSyncAlways)
+FN_LOCAL_BOOL(lp_strict_allocate, bStrictAllocate)
 FN_LOCAL_BOOL(lp_strict_sync, bStrictSync)
 FN_LOCAL_BOOL(lp_map_system, bMap_system)
 FN_LOCAL_BOOL(lp_delete_readonly, bDeleteReadonly)
index ae312cd5d23607c2b2cca8667d41569f4a13032c..bb7ca6e0f840e5ea09ea342acb79aa41a891c107 100644 (file)
@@ -1878,25 +1878,59 @@ static int call_trans2setfilepathinfo(connection_struct *conn,
       break;
     }
 
-    /*
-     * NT seems to use this call with a size of zero
-     * to mean truncate the file. JRA.
-     */
-
        case 1019:
        case 1020:
     case SMB_SET_FILE_ALLOCATION_INFO:
     {
-      SMB_OFF_T newsize = IVAL(pdata,0);
+      int ret = -1;
+      size = IVAL(pdata,0);
 #ifdef LARGE_SMB_OFF_T
-      newsize |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
+      size |= (((SMB_OFF_T)IVAL(pdata,4)) << 32);
 #else /* LARGE_SMB_OFF_T */
       if (IVAL(pdata,4) != 0)  /* more than 32 bits? */
          return(ERROR(ERRDOS,ERRunknownlevel));
 #endif /* LARGE_SMB_OFF_T */
-      DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n", fname, (double)newsize ));
-      if(newsize == 0)
-        size = 0;
+      DEBUG(10,("call_trans2setfilepathinfo: Set file allocation info for file %s to %.0f\n",
+                           fname, (double)size ));
+
+      if(size != sbuf.st_size) {
+        DEBUG(10,("call_trans2setfilepathinfo: file %s : setting new size to %.0f\n",
+            fname, (double)size ));
+        if (fd == -1) {
+          files_struct *new_fsp = NULL;
+          int access_mode = 0;
+          int action = 0;
+          if(global_oplock_break) {
+            /* Queue this file modify as we are the process of an oplock break.  */
+            DEBUG(2,("call_trans2setfilepathinfo: queueing message due to being "));
+            DEBUGADD(2,( "in oplock break state.\n"));
+            push_oplock_pending_smb_message(inbuf, length);
+            return -1;
+          }
+          new_fsp = open_file_shared(conn, fname, &sbuf,
+                             SET_OPEN_MODE(DOS_OPEN_RDWR),
+                             (FILE_FAIL_IF_NOT_EXIST|FILE_EXISTS_OPEN),
+                             0, 0, &access_mode, &action);
+          if (new_fsp == NULL)
+            return(UNIXERROR(ERRDOS,ERRbadpath));
+          ret = vfs_allocate_file_space(new_fsp, size);
+          close_file(new_fsp,True);
+        } else {
+          ret = vfs_allocate_file_space(fsp, size);
+        }
+      }
+
+      if (ret == -1)
+        return(UNIXERROR(ERRHRD,ERRdiskfull));
+
+      sbuf.st_size = size;
       break;
     }
 
index 50361564a5e173678877dd1e201a57078ddd95fc..834d75266e8b8320fa980dce1de878b8d4301202 100644 (file)
@@ -297,6 +297,84 @@ ssize_t vfs_write_data(files_struct *fsp,const char *buffer,size_t N)
   return (ssize_t)total;
 }
 
+/****************************************************************************
+ An allocate file space call using the vfs interface.
+ Allocates space for a file from a filedescriptor.
+ Returns 0 on success, -1 on failure.
+****************************************************************************/
+
+int vfs_allocate_file_space(files_struct *fsp, SMB_OFF_T len)
+{
+       int ret;
+       SMB_STRUCT_STAT st;
+       struct vfs_ops *vfs_ops = &fsp->conn->vfs_ops;
+
+       if (!lp_strict_allocate(SNUM(fsp->conn)))
+               return vfs_set_filelen(fsp, len);
+               
+       release_level_2_oplocks_on_change(fsp);
+
+       /*
+        * Actually try and commit the space on disk....
+        */
+
+       DEBUG(10,("vfs_allocate_file_space: file %s, len %.0f\n", fsp->fsp_name, (double)len ));
+
+       ret = vfs_fstat(fsp,fsp->fd,&st);
+       if (ret == -1)
+               return ret;
+
+       if (len == st.st_size)
+               return 0;
+
+       if (len < st.st_size) {
+               /* Shrink - use ftruncate. */
+
+               DEBUG(10,("vfs_allocate_file_space: file %s, shrink. Current size %.0f\n",
+                               fsp->fsp_name, (double)st.st_size ));
+
+               if ((ret = vfs_ops->ftruncate(fsp, fsp->fd, len)) != -1) {
+                       set_filelen_write_cache(fsp, len);
+               }
+               return ret;
+       }
+
+       /* Grow - we need to write out the space.... */
+       {
+               static unsigned char zero_space[65536];
+
+               SMB_OFF_T start_pos = st.st_size;
+               SMB_OFF_T len_to_write = len - st.st_size;
+               SMB_OFF_T retlen;
+
+               DEBUG(10,("vfs_allocate_file_space: file %s, grow. Current size %.0f\n",
+                               fsp->fsp_name, (double)st.st_size ));
+
+               if ((retlen = vfs_ops->lseek(fsp, fsp->fd, start_pos, SEEK_SET)) != start_pos)
+                       return -1;
+
+               while ( len_to_write > 0) {
+                       SMB_OFF_T current_len_to_write = MIN(sizeof(zero_space),len_to_write);
+
+                       retlen = vfs_ops->write(fsp,fsp->fd,zero_space,current_len_to_write);
+                       if (retlen != current_len_to_write) {
+                               /* Write fail - return to original size. */
+                               int save_errno = errno;
+                               fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, st.st_size);
+                               errno = save_errno;
+                               return -1;
+                       }
+
+                       DEBUG(10,("vfs_allocate_file_space: file %s, grow. wrote %.0f\n",
+                                       fsp->fsp_name, (double)current_len_to_write ));
+
+                       len_to_write -= current_len_to_write;
+               }
+               set_filelen_write_cache(fsp, len);
+       }
+       return 0;
+}
+
 /****************************************************************************
  A vfs set_filelen call.
  set the length of a file from a filedescriptor.
@@ -308,9 +386,8 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len)
        int ret;
 
        release_level_2_oplocks_on_change(fsp);
-       if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1) {
+       if ((ret = fsp->conn->vfs_ops.ftruncate(fsp, fsp->fd, len)) != -1)
                set_filelen_write_cache(fsp, len);
-       }
 
        return ret;
 }