Convert all uint8/16/32 to _t in all modules.
[kamenim/samba-autobuild/.git] / source3 / modules / vfs_streams_xattr.c
index b68fa02a354af98e4980108bd269e13e71327011..d149fc83a7a351f0a46dc2304cf0971e76e8b2ba 100644 (file)
  */
 
 #include "includes.h"
+#include "smbd/smbd.h"
+#include "system/filesys.h"
+#include "../lib/crypto/md5.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_VFS
 
+struct streams_xattr_config {
+       const char *prefix;
+       size_t prefix_len;
+       bool store_stream_type;
+};
+
 struct stream_io {
        char *base;
        char *xattr_name;
@@ -36,7 +45,7 @@ struct stream_io {
 
 static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
 {
-       struct MD5Context ctx;
+       MD5_CTX ctx;
         unsigned char hash[16];
        SMB_INO_T result;
        char *upper_sname;
@@ -49,9 +58,9 @@ static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
        SMB_ASSERT(upper_sname != NULL);
 
         MD5Init(&ctx);
-        MD5Update(&ctx, (unsigned char *)&(sbuf->st_ex_dev),
+        MD5Update(&ctx, (const unsigned char *)&(sbuf->st_ex_dev),
                  sizeof(sbuf->st_ex_dev));
-        MD5Update(&ctx, (unsigned char *)&(sbuf->st_ex_ino),
+        MD5Update(&ctx, (const unsigned char *)&(sbuf->st_ex_ino),
                  sizeof(sbuf->st_ex_ino));
         MD5Update(&ctx, (unsigned char *)upper_sname,
                  talloc_get_size(upper_sname)-1);
@@ -92,31 +101,47 @@ static ssize_t get_xattr_size(connection_struct *conn,
  * Given a stream name, populate xattr_name with the xattr name to use for
  * accessing the stream.
  */
-static NTSTATUS streams_xattr_get_name(TALLOC_CTX *ctx,
+static NTSTATUS streams_xattr_get_name(vfs_handle_struct *handle,
+                                      TALLOC_CTX *ctx,
                                       const char *stream_name,
                                       char **xattr_name)
 {
        char *stype;
+       struct streams_xattr_config *config;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
+                               return NT_STATUS_UNSUCCESSFUL);
 
        stype = strchr_m(stream_name + 1, ':');
 
+       if (stype) {
+               if (strcasecmp_m(stype, ":$DATA") != 0) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       }
+
        *xattr_name = talloc_asprintf(ctx, "%s%s",
-                                     SAMBA_XATTR_DOSSTREAM_PREFIX,
+                                     config->prefix,
                                      stream_name + 1);
        if (*xattr_name == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       if (stype == NULL) {
-               /* Append an explicit stream type if one wasn't specified. */
-               *xattr_name = talloc_asprintf(ctx, "%s:$DATA",
-                                              *xattr_name);
+       if (stype != NULL) {
+               /* Normalize the stream type to upercase. */
+               if (!strupper_m(strrchr_m(*xattr_name, ':') + 1)) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+       } else if (config->store_stream_type) {
+               /*
+                * Append an explicit stream type if one wasn't
+                * specified.
+                */
+               *xattr_name = talloc_asprintf(ctx, "%s%s",
+                                             *xattr_name, ":$DATA");
                if (*xattr_name == NULL) {
                        return NT_STATUS_NO_MEMORY;
                }
-       } else {
-               /* Normalize the stream type to upercase. */
-               strupper_m(strrchr_m(*xattr_name, ':') + 1);
        }
 
        DEBUG(10, ("xattr_name: %s, stream_name: %s\n", *xattr_name,
@@ -140,7 +165,7 @@ static bool streams_xattr_recheck(struct stream_io *sio)
                return false;
        }
 
-       status = streams_xattr_get_name(talloc_tos(),
+       status = streams_xattr_get_name(sio->handle, talloc_tos(),
                                        sio->fsp->fsp_name->stream_name,
                                        &xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
@@ -189,7 +214,6 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
                               SMB_STRUCT_STAT *sbuf)
 {
        struct smb_filename *smb_fname_base = NULL;
-       NTSTATUS status;
        int ret = -1;
        struct stream_io *io = (struct stream_io *)
                VFS_FETCH_FSP_EXTENSION(handle, fsp);
@@ -205,12 +229,10 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
        }
 
        /* Create an smb_filename with stream_name == NULL. */
-       status = create_synthetic_smb_fname(talloc_tos(),
-                                           io->base,
-                                           NULL, NULL,
-                                           &smb_fname_base);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
+       smb_fname_base = synthetic_smb_fname(talloc_tos(), io->base,
+                                            NULL, NULL);
+       if (smb_fname_base == NULL) {
+               errno = ENOMEM;
                return -1;
        }
 
@@ -237,7 +259,7 @@ static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
        sbuf->st_ex_ino = stream_inode(sbuf, io->xattr_name);
        sbuf->st_ex_mode &= ~S_IFMT;
         sbuf->st_ex_mode |= S_IFREG;
-        sbuf->st_ex_blocks = sbuf->st_ex_size % STAT_ST_BLOCKSIZE + 1;
+        sbuf->st_ex_blocks = sbuf->st_ex_size / STAT_ST_BLOCKSIZE + 1;
 
        return 0;
 }
@@ -253,6 +275,11 @@ static int streams_xattr_stat(vfs_handle_struct *handle,
                return SMB_VFS_NEXT_STAT(handle, smb_fname);
        }
 
+       /* Note if lp_posix_paths() is true, we can never
+        * get here as is_ntfs_stream_smb_fname() is
+        * always false. So we never need worry about
+        * not following links here. */
+
        /* If the default stream is requested, just stat the base file. */
        if (is_ntfs_default_stream_smb_fname(smb_fname)) {
                return streams_xattr_stat_base(handle, smb_fname, true);
@@ -264,8 +291,8 @@ static int streams_xattr_stat(vfs_handle_struct *handle,
        }
 
        /* Derive the xattr name to lookup. */
-       status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
-                                       &xattr_name);
+       status = streams_xattr_get_name(handle, talloc_tos(),
+                                       smb_fname->stream_name, &xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                return -1;
@@ -285,7 +312,7 @@ static int streams_xattr_stat(vfs_handle_struct *handle,
        smb_fname->st.st_ex_mode &= ~S_IFMT;
         smb_fname->st.st_ex_mode |= S_IFREG;
         smb_fname->st.st_ex_blocks =
-           smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1;
+           smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
 
        result = 0;
  fail:
@@ -304,7 +331,7 @@ static int streams_xattr_lstat(vfs_handle_struct *handle,
                return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
        }
 
-               /* If the default stream is requested, just stat the base file. */
+       /* If the default stream is requested, just stat the base file. */
        if (is_ntfs_default_stream_smb_fname(smb_fname)) {
                return streams_xattr_stat_base(handle, smb_fname, false);
        }
@@ -315,8 +342,8 @@ static int streams_xattr_lstat(vfs_handle_struct *handle,
        }
 
        /* Derive the xattr name to lookup. */
-       status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
-                                       &xattr_name);
+       status = streams_xattr_get_name(handle, talloc_tos(),
+                                       smb_fname->stream_name, &xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                return -1;
@@ -336,7 +363,7 @@ static int streams_xattr_lstat(vfs_handle_struct *handle,
        smb_fname->st.st_ex_mode &= ~S_IFMT;
         smb_fname->st.st_ex_mode |= S_IFREG;
         smb_fname->st.st_ex_blocks =
-           smb_fname->st.st_ex_size % STAT_ST_BLOCKSIZE + 1;
+           smb_fname->st.st_ex_size / STAT_ST_BLOCKSIZE + 1;
 
        result = 0;
 
@@ -357,8 +384,8 @@ static int streams_xattr_open(vfs_handle_struct *handle,
        int baseflags;
        int hostfd = -1;
 
-       DEBUG(10, ("streams_xattr_open called for %s\n",
-                  smb_fname_str_dbg(smb_fname)));
+       DEBUG(10, ("streams_xattr_open called for %s with flags 0x%x\n",
+                  smb_fname_str_dbg(smb_fname), flags));
 
        if (!is_ntfs_stream_smb_fname(smb_fname)) {
                return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
@@ -379,20 +406,18 @@ static int streams_xattr_open(vfs_handle_struct *handle,
                return ret;
        }
 
-       status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
-                                       &xattr_name);
+       status = streams_xattr_get_name(handle, talloc_tos(),
+                                       smb_fname->stream_name, &xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                goto fail;
        }
 
        /* Create an smb_filename with stream_name == NULL. */
-       status = create_synthetic_smb_fname(talloc_tos(),
-                                           smb_fname->base_name,
-                                           NULL, NULL,
-                                           &smb_fname_base);
-       if (!NT_STATUS_IS_OK(status)) {
-               errno = map_errno_from_nt_status(status);
+       smb_fname_base = synthetic_smb_fname(
+               talloc_tos(), smb_fname->base_name, NULL, NULL);
+       if (smb_fname_base == NULL) {
+               errno = ENOMEM;
                goto fail;
        }
 
@@ -442,40 +467,20 @@ static int streams_xattr_open(vfs_handle_struct *handle,
                goto fail;
        }
 
-       if (!NT_STATUS_IS_OK(status)) {
+       if ((!NT_STATUS_IS_OK(status) && (flags & O_CREAT)) ||
+           (flags & O_TRUNC)) {
                /*
-                * The attribute does not exist
+                * The attribute does not exist or needs to be truncated
                 */
 
-                if (flags & O_CREAT) {
-                       /*
-                        * Darn, xattrs need at least 1 byte
-                        */
-                        char null = '\0';
-
-                       DEBUG(10, ("creating attribute %s on file %s\n",
-                                  xattr_name, smb_fname->base_name));
+               /*
+                * Darn, xattrs need at least 1 byte
+                */
+               char null = '\0';
 
-                       if (fsp->base_fsp->fh->fd != -1) {
-                               if (SMB_VFS_FSETXATTR(
-                                       fsp->base_fsp, xattr_name,
-                                       &null, sizeof(null),
-                                       flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
-                                       goto fail;
-                               }
-                       } else {
-                               if (SMB_VFS_SETXATTR(
-                                       handle->conn, smb_fname->base_name,
-                                       xattr_name, &null, sizeof(null),
-                                       flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
-                                       goto fail;
-                               }
-                       }
-               }
-       }
+               DEBUG(10, ("creating or truncating attribute %s on file %s\n",
+                          xattr_name, smb_fname->base_name));
 
-       if (flags & O_TRUNC) {
-               char null = '\0';
                if (fsp->base_fsp->fh->fd != -1) {
                        if (SMB_VFS_FSETXATTR(
                                        fsp->base_fsp, xattr_name,
@@ -522,6 +527,7 @@ static int streams_xattr_open(vfs_handle_struct *handle,
                 * BUGBUGBUG -- we would need to call fd_close_posix here, but
                 * we don't have a full fsp yet
                 */
+               fsp->fh->fd = hostfd;
                SMB_VFS_CLOSE(fsp);
        }
 
@@ -533,7 +539,7 @@ static int streams_xattr_unlink(vfs_handle_struct *handle,
 {
        NTSTATUS status;
        int ret = -1;
-       char *xattr_name;
+       char *xattr_name = NULL;
 
        if (!is_ntfs_stream_smb_fname(smb_fname)) {
                return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
@@ -543,10 +549,9 @@ static int streams_xattr_unlink(vfs_handle_struct *handle,
        if (is_ntfs_default_stream_smb_fname(smb_fname)) {
                struct smb_filename *smb_fname_base = NULL;
 
-               status = copy_smb_filename(talloc_tos(), smb_fname,
-                                           &smb_fname_base);
-               if (!NT_STATUS_IS_OK(status)) {
-                       errno = map_errno_from_nt_status(status);
+               smb_fname_base = cp_smb_filename(talloc_tos(), smb_fname);
+               if (smb_fname_base == NULL) {
+                       errno = ENOMEM;
                        return -1;
                }
 
@@ -556,8 +561,8 @@ static int streams_xattr_unlink(vfs_handle_struct *handle,
                return ret;
        }
 
-       status = streams_xattr_get_name(talloc_tos(), smb_fname->stream_name,
-                                       &xattr_name);
+       status = streams_xattr_get_name(handle, talloc_tos(),
+                                       smb_fname->stream_name, &xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                goto fail;
@@ -606,20 +611,20 @@ static int streams_xattr_rename(vfs_handle_struct *handle,
        }
 
        /* Don't rename if the streams are identical. */
-       if (StrCaseCmp(smb_fname_src->stream_name,
+       if (strcasecmp_m(smb_fname_src->stream_name,
                       smb_fname_dst->stream_name) == 0) {
                goto done;
        }
 
        /* Get the xattr names. */
-       status = streams_xattr_get_name(talloc_tos(),
+       status = streams_xattr_get_name(handle, talloc_tos(),
                                        smb_fname_src->stream_name,
                                        &src_xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
                errno = map_errno_from_nt_status(status);
                goto fail;
        }
-       status = streams_xattr_get_name(talloc_tos(),
+       status = streams_xattr_get_name(handle, talloc_tos(),
                                        smb_fname_dst->stream_name,
                                        &dst_xattr_name);
        if (!NT_STATUS_IS_OK(status)) {
@@ -665,7 +670,7 @@ static int streams_xattr_rename(vfs_handle_struct *handle,
        return ret;
 }
 
-static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
+static NTSTATUS walk_xattr_streams(vfs_handle_struct *handle, files_struct *fsp,
                                   const char *fname,
                                   bool (*fn)(struct ea_struct *ea,
                                              void *private_data),
@@ -674,9 +679,12 @@ static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
        NTSTATUS status;
        char **names;
        size_t i, num_names;
-       size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
+       struct streams_xattr_config *config;
+
+       SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
+                               return NT_STATUS_UNSUCCESSFUL);
 
-       status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+       status = get_ea_names_from_file(talloc_tos(), handle->conn, fsp, fname,
                                        &names, &num_names);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
@@ -685,20 +693,41 @@ static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
        for (i=0; i<num_names; i++) {
                struct ea_struct ea;
 
-               if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
-                           prefix_len) != 0) {
+               /*
+                * We want to check with samba_private_attr_name()
+                * whether the xattr name is a private one,
+                * unfortunately it flags xattrs that begin with the
+                * default streams prefix as private.
+                *
+                * By only calling samba_private_attr_name() in case
+                * the xattr does NOT begin with the default prefix,
+                * we know that if it returns 'true' it definitely one
+                * of our internal xattr like "user.DOSATTRIB".
+                */
+               if (strncasecmp_m(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
+                                 strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) != 0) {
+                       if (samba_private_attr_name(names[i])) {
+                               continue;
+                       }
+               }
+
+               if (strncmp(names[i], config->prefix,
+                           config->prefix_len) != 0) {
                        continue;
                }
 
-               status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
+               status = get_ea_value(names, handle->conn, fsp, fname,
+                                     names[i], &ea);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(10, ("Could not get ea %s for file %s: %s\n",
                                   names[i], fname, nt_errstr(status)));
                        continue;
                }
 
-               ea.name = talloc_asprintf(ea.value.data, ":%s",
-                                         names[i] + prefix_len);
+               ea.name = talloc_asprintf(
+                       ea.value.data, ":%s%s",
+                       names[i] + config->prefix_len,
+                       config->store_stream_type ? "" : ":$DATA");
                if (ea.name == NULL) {
                        DEBUG(0, ("talloc failed\n"));
                        continue;
@@ -718,12 +747,12 @@ static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
 
 static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
                           struct stream_struct **streams,
-                          const char *name, SMB_OFF_T size,
-                          SMB_OFF_T alloc_size)
+                          const char *name, off_t size,
+                          off_t alloc_size)
 {
        struct stream_struct *tmp;
 
-       tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+       tmp = talloc_realloc(mem_ctx, *streams, struct stream_struct,
                                   (*num_streams)+1);
        if (tmp == NULL) {
                return false;
@@ -784,10 +813,10 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
        }
        else {
                struct smb_filename *smb_fname = NULL;
-               status = create_synthetic_smb_fname(talloc_tos(), fname, NULL,
-                                                   NULL, &smb_fname);
-               if (!NT_STATUS_IS_OK(status)) {
-                       return status;
+               smb_fname = synthetic_smb_fname(talloc_tos(), fname, NULL,
+                                               NULL);
+               if (smb_fname == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
                if (lp_posix_pathnames()) {
                        ret = SMB_VFS_LSTAT(handle->conn, smb_fname);
@@ -802,25 +831,25 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
                return map_nt_error_from_unix(errno);
        }
 
-       state.streams = NULL;
-       state.num_streams = 0;
-
-       if (!S_ISDIR(sbuf.st_ex_mode)) {
-               if (!add_one_stream(mem_ctx,
-                                   &state.num_streams, &state.streams,
-                                   "::$DATA", sbuf.st_ex_size,
-                                   SMB_VFS_GET_ALLOC_SIZE(handle->conn, fsp,
-                                                          &sbuf))) {
-                       return NT_STATUS_NO_MEMORY;
-               }
-       }
-
+       state.streams = *pstreams;
+       state.num_streams = *pnum_streams;
        state.mem_ctx = mem_ctx;
        state.handle = handle;
        state.status = NT_STATUS_OK;
 
-       status = walk_xattr_streams(handle->conn, fsp, fname,
+       if (S_ISLNK(sbuf.st_ex_mode)) {
+               /*
+                * Currently we do't have SMB_VFS_LLISTXATTR
+                * inside the VFS which means there's no way
+                * to cope with a symlink when lp_posix_pathnames().
+                * returns true. For now ignore links.
+                * FIXME - by adding SMB_VFS_LLISTXATTR. JRA.
+                */
+               status = NT_STATUS_OK;
+       } else {
+               status = walk_xattr_streams(handle, fsp, fname,
                                    collect_one_stream, &state);
+       }
 
        if (!NT_STATUS_IS_OK(status)) {
                TALLOC_FREE(state.streams);
@@ -834,7 +863,8 @@ static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
 
        *pnum_streams = state.num_streams;
        *pstreams = state.streams;
-       return NT_STATUS_OK;
+
+       return SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, pnum_streams, pstreams);
 }
 
 static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle,
@@ -843,9 +873,53 @@ static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle,
        return SMB_VFS_NEXT_FS_CAPABILITIES(handle, p_ts_res) | FILE_NAMED_STREAMS;
 }
 
+static int streams_xattr_connect(vfs_handle_struct *handle,
+                                const char *service, const char *user)
+{
+       struct streams_xattr_config *config;
+       const char *default_prefix = SAMBA_XATTR_DOSSTREAM_PREFIX;
+       const char *prefix;
+       int rc;
+
+       rc = SMB_VFS_NEXT_CONNECT(handle, service, user);
+       if (rc != 0) {
+               return rc;
+       }
+
+       config = talloc_zero(handle->conn, struct streams_xattr_config);
+       if (config == NULL) {
+               DEBUG(1, ("talloc_zero() failed\n"));
+               errno = ENOMEM;
+               return -1;
+       }
+
+       prefix = lp_parm_const_string(SNUM(handle->conn),
+                                     "streams_xattr", "prefix",
+                                     default_prefix);
+       config->prefix = talloc_strdup(config, prefix);
+       if (config->prefix == NULL) {
+               DEBUG(1, ("talloc_strdup() failed\n"));
+               errno = ENOMEM;
+               return -1;
+       }
+       config->prefix_len = strlen(config->prefix);
+       DEBUG(10, ("streams_xattr using stream prefix: %s\n", config->prefix));
+
+       config->store_stream_type = lp_parm_bool(SNUM(handle->conn),
+                                                "streams_xattr",
+                                                "store_stream_type",
+                                                true);
+
+       SMB_VFS_HANDLE_SET_DATA(handle, config,
+                               NULL, struct stream_xattr_config,
+                               return -1);
+
+       return 0;
+}
+
 static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
                                    files_struct *fsp, const void *data,
-                                   size_t n, SMB_OFF_T offset)
+                                   size_t n, off_t offset)
 {
         struct stream_io *sio =
                (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
@@ -870,9 +944,9 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
        }
 
         if ((offset + n) > ea.value.length-1) {
-               uint8 *tmp;
+               uint8_t *tmp;
 
-               tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
+               tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
                                           offset + n + 1);
 
                if (tmp == NULL) {
@@ -908,7 +982,7 @@ static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
 
 static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
                                   files_struct *fsp, void *data,
-                                  size_t n, SMB_OFF_T offset)
+                                  size_t n, off_t offset)
 {
         struct stream_io *sio =
                (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
@@ -952,10 +1026,10 @@ static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
 
 static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
                                        struct files_struct *fsp,
-                                       SMB_OFF_T offset)
+                                       off_t offset)
 {
        int ret;
-       uint8 *tmp;
+       uint8_t *tmp;
        struct ea_struct ea;
        NTSTATUS status;
         struct stream_io *sio =
@@ -978,7 +1052,7 @@ static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
+       tmp = talloc_realloc(talloc_tos(), ea.value.data, uint8_t,
                                   offset + 1);
 
        if (tmp == NULL) {
@@ -1017,18 +1091,47 @@ static int streams_xattr_ftruncate(struct vfs_handle_struct *handle,
        return 0;
 }
 
+static int streams_xattr_fallocate(struct vfs_handle_struct *handle,
+                                       struct files_struct *fsp,
+                                       uint32_t mode,
+                                       off_t offset,
+                                       off_t len)
+{
+        struct stream_io *sio =
+               (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+       DEBUG(10, ("streams_xattr_fallocate called for file %s offset %.0f"
+               "len = %.0f\n",
+               fsp_str_dbg(fsp), (double)offset, (double)len));
+
+       if (sio == NULL) {
+               return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
+       }
+
+       if (!streams_xattr_recheck(sio)) {
+               return -1;
+       }
+
+       /* Let the pwrite code path handle it. */
+       errno = ENOSYS;
+       return -1;
+}
+
+
 static struct vfs_fn_pointers vfs_streams_xattr_fns = {
-       .fs_capabilities = streams_xattr_fs_capabilities,
-       .open = streams_xattr_open,
-       .stat = streams_xattr_stat,
-       .fstat = streams_xattr_fstat,
-       .lstat = streams_xattr_lstat,
-       .pread = streams_xattr_pread,
-       .pwrite = streams_xattr_pwrite,
-       .unlink = streams_xattr_unlink,
-       .rename = streams_xattr_rename,
-        .ftruncate = streams_xattr_ftruncate,
-       .streaminfo = streams_xattr_streaminfo,
+       .fs_capabilities_fn = streams_xattr_fs_capabilities,
+       .connect_fn = streams_xattr_connect,
+       .open_fn = streams_xattr_open,
+       .stat_fn = streams_xattr_stat,
+       .fstat_fn = streams_xattr_fstat,
+       .lstat_fn = streams_xattr_lstat,
+       .pread_fn = streams_xattr_pread,
+       .pwrite_fn = streams_xattr_pwrite,
+       .unlink_fn = streams_xattr_unlink,
+       .rename_fn = streams_xattr_rename,
+       .ftruncate_fn = streams_xattr_ftruncate,
+       .fallocate_fn = streams_xattr_fallocate,
+       .streaminfo_fn = streams_xattr_streaminfo,
 };
 
 NTSTATUS vfs_streams_xattr_init(void);