smbd: add twrp arg to synthetic_smb_fname()
[amitay/samba.git] / source3 / modules / vfs_fruit.c
index 892e2cbd3c18cc988898a21ce39c1cbffed75741..5579988217a7f22864a30f1c24106b81885ce956 100644 (file)
@@ -377,11 +377,7 @@ static bool filter_empty_rsrc_stream(unsigned int *num_streams,
        }
 
        TALLOC_FREE(tmp[i].name);
-       if (*num_streams - 1 > i) {
-               memmove(&tmp[i], &tmp[i+1],
-                       (*num_streams - i - 1) * sizeof(struct stream_struct));
-       }
-
+       ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
        *num_streams -= 1;
        return true;
 }
@@ -408,11 +404,7 @@ static bool del_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
        }
 
        TALLOC_FREE(tmp[i].name);
-       if (*num_streams - 1 > i) {
-               memmove(&tmp[i], &tmp[i+1],
-                       (*num_streams - i - 1) * sizeof(struct stream_struct));
-       }
-
+       ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
        *num_streams -= 1;
        return true;
 }
@@ -891,7 +883,9 @@ static bool readdir_attr_meta_finderi_stream(
        stream_name = synthetic_smb_fname(talloc_tos(),
                                          smb_fname->base_name,
                                          AFPINFO_STREAM_NAME,
-                                         NULL, smb_fname->flags);
+                                         NULL,
+                                         smb_fname->twrp,
+                                         smb_fname->flags);
        if (stream_name == NULL) {
                return false;
        }
@@ -1065,7 +1059,9 @@ static uint64_t readdir_attr_rfork_size_stream(
        stream_name = synthetic_smb_fname(talloc_tos(),
                                          smb_fname->base_name,
                                          AFPRESOURCE_STREAM_NAME,
-                                         NULL, 0);
+                                         NULL,
+                                         smb_fname->twrp,
+                                         0);
        if (stream_name == NULL) {
                return 0;
        }
@@ -1254,6 +1250,8 @@ static int fruit_connect(vfs_handle_struct *handle,
        int rc;
        char *list = NULL, *newlist = NULL;
        struct fruit_config_data *config;
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
 
        DEBUG(10, ("fruit_connect\n"));
 
@@ -1271,7 +1269,7 @@ static int fruit_connect(vfs_handle_struct *handle,
                                struct fruit_config_data, return -1);
 
        if (config->veto_appledouble) {
-               list = lp_veto_files(talloc_tos(), SNUM(handle->conn));
+               list = lp_veto_files(talloc_tos(), lp_sub, SNUM(handle->conn));
 
                if (list) {
                        if (strstr(list, "/" ADOUBLE_NAME_PREFIX "*/") == NULL) {
@@ -1613,7 +1611,7 @@ static int fruit_open(vfs_handle_struct *handle,
 
        DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
 
-       if (!is_ntfs_stream_smb_fname(smb_fname)) {
+       if (!is_named_stream(smb_fname)) {
                return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
        }
 
@@ -1696,7 +1694,7 @@ static int fruit_close(vfs_handle_struct *handle,
 
        DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(fsp->fsp_name), fd);
 
-       if (!is_ntfs_stream_smb_fname(fsp->fsp_name)) {
+       if (!is_named_stream(fsp->fsp_name)) {
                return SMB_VFS_NEXT_CLOSE(handle, fsp);
        }
 
@@ -1776,9 +1774,13 @@ done:
 }
 
 static int fruit_unlink_meta_stream(vfs_handle_struct *handle,
-                                   const struct smb_filename *smb_fname)
+                               struct files_struct *dirfsp,
+                               const struct smb_filename *smb_fname)
 {
-       return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+       return SMB_VFS_NEXT_UNLINKAT(handle,
+                               dirfsp,
+                               smb_fname,
+                               0);
 }
 
 static int fruit_unlink_meta_netatalk(vfs_handle_struct *handle,
@@ -1801,7 +1803,9 @@ static int fruit_unlink_meta(vfs_handle_struct *handle,
 
        switch (config->meta) {
        case FRUIT_META_STREAM:
-               rc = fruit_unlink_meta_stream(handle, smb_fname);
+               rc = fruit_unlink_meta_stream(handle,
+                               dirfsp,
+                               smb_fname);
                break;
 
        case FRUIT_META_NETATALK:
@@ -1817,8 +1821,9 @@ static int fruit_unlink_meta(vfs_handle_struct *handle,
 }
 
 static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
-                                   const struct smb_filename *smb_fname,
-                                   bool force_unlink)
+                               struct files_struct *dirfsp,
+                               const struct smb_filename *smb_fname,
+                               bool force_unlink)
 {
        int ret;
 
@@ -1854,7 +1859,10 @@ static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
                }
        }
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                       dirfsp,
+                       smb_fname,
+                       0);
        if ((ret != 0) && (errno == ENOENT) && force_unlink) {
                ret = 0;
        }
@@ -1863,8 +1871,9 @@ static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
 }
 
 static int fruit_unlink_rsrc_adouble(vfs_handle_struct *handle,
-                                    const struct smb_filename *smb_fname,
-                                    bool force_unlink)
+                               struct files_struct *dirfsp,
+                               const struct smb_filename *smb_fname,
+                               bool force_unlink)
 {
        int rc;
        struct adouble *ad = NULL;
@@ -1899,7 +1908,10 @@ static int fruit_unlink_rsrc_adouble(vfs_handle_struct *handle,
                return -1;
        }
 
-       rc = SMB_VFS_NEXT_UNLINK(handle, adp_smb_fname);
+       rc = SMB_VFS_NEXT_UNLINKAT(handle,
+                       dirfsp,
+                       adp_smb_fname,
+                       0);
        TALLOC_FREE(adp_smb_fname);
        if ((rc != 0) && (errno == ENOENT) && force_unlink) {
                rc = 0;
@@ -1922,8 +1934,9 @@ static int fruit_unlink_rsrc_xattr(vfs_handle_struct *handle,
 }
 
 static int fruit_unlink_rsrc(vfs_handle_struct *handle,
-                            const struct smb_filename *smb_fname,
-                            bool force_unlink)
+                       struct files_struct *dirfsp,
+                       const struct smb_filename *smb_fname,
+                       bool force_unlink)
 {
        struct fruit_config_data *config = NULL;
        int rc;
@@ -1933,11 +1946,17 @@ static int fruit_unlink_rsrc(vfs_handle_struct *handle,
 
        switch (config->rsrc) {
        case FRUIT_RSRC_STREAM:
-               rc = fruit_unlink_rsrc_stream(handle, smb_fname, force_unlink);
+               rc = fruit_unlink_rsrc_stream(handle,
+                               dirfsp,
+                               smb_fname,
+                               force_unlink);
                break;
 
        case FRUIT_RSRC_ADFILE:
-               rc = fruit_unlink_rsrc_adouble(handle, smb_fname, force_unlink);
+               rc = fruit_unlink_rsrc_adouble(handle,
+                               dirfsp,
+                               smb_fname,
+                               force_unlink);
                break;
 
        case FRUIT_RSRC_XATTR:
@@ -1952,65 +1971,6 @@ static int fruit_unlink_rsrc(vfs_handle_struct *handle,
        return rc;
 }
 
-static int fruit_unlink_internal(vfs_handle_struct *handle,
-                       struct files_struct *dirfsp,
-                       const struct smb_filename *smb_fname)
-{
-       int rc;
-       struct fruit_config_data *config = NULL;
-       struct smb_filename *rsrc_smb_fname = NULL;
-
-       SMB_VFS_HANDLE_GET_DATA(handle, config,
-                               struct fruit_config_data, return -1);
-
-       if (is_afpinfo_stream(smb_fname->stream_name)) {
-               return fruit_unlink_meta(handle,
-                               dirfsp,
-                               smb_fname);
-       } else if (is_afpresource_stream(smb_fname->stream_name)) {
-               return fruit_unlink_rsrc(handle, smb_fname, false);
-       } else if (is_ntfs_stream_smb_fname(smb_fname)) {
-               return SMB_VFS_NEXT_UNLINKAT(handle,
-                               dirfsp,
-                               smb_fname,
-                               0);
-       } else if (is_adouble_file(smb_fname->base_name)) {
-               return SMB_VFS_NEXT_UNLINKAT(handle,
-                               dirfsp,
-                               smb_fname,
-                               0);
-       }
-
-       /*
-        * A request to delete the base file. Because 0 byte resource
-        * fork streams are not listed by fruit_streaminfo,
-        * delete_all_streams() can't remove 0 byte resource fork
-        * streams, so we have to cleanup this here.
-        */
-       rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
-                                            smb_fname->base_name,
-                                            AFPRESOURCE_STREAM_NAME,
-                                            NULL,
-                                            smb_fname->flags);
-       if (rsrc_smb_fname == NULL) {
-               return -1;
-       }
-
-       rc = fruit_unlink_rsrc(handle, rsrc_smb_fname, true);
-       if ((rc != 0) && (errno != ENOENT)) {
-               DBG_ERR("Forced unlink of [%s] failed [%s]\n",
-                       smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
-               TALLOC_FREE(rsrc_smb_fname);
-               return -1;
-       }
-       TALLOC_FREE(rsrc_smb_fname);
-
-       return SMB_VFS_NEXT_UNLINKAT(handle,
-                       dirfsp,
-                       smb_fname,
-                       0);
-}
-
 static int fruit_chmod(vfs_handle_struct *handle,
                       const struct smb_filename *smb_fname,
                       mode_t mode)
@@ -2055,167 +2015,77 @@ static int fruit_chmod(vfs_handle_struct *handle,
        return rc;
 }
 
-static int fruit_chown(vfs_handle_struct *handle,
-                      const struct smb_filename *smb_fname,
-                      uid_t uid,
-                      gid_t gid)
+static int fruit_unlinkat(vfs_handle_struct *handle,
+                       struct files_struct *dirfsp,
+                       const struct smb_filename *smb_fname,
+                       int flags)
 {
-       int rc = -1;
        struct fruit_config_data *config = NULL;
-       struct smb_filename *adp_smb_fname = NULL;
-
-       rc = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
-       if (rc != 0) {
-               return rc;
-       }
-
-       SMB_VFS_HANDLE_GET_DATA(handle, config,
-                               struct fruit_config_data, return -1);
-
-       if (config->rsrc != FRUIT_RSRC_ADFILE) {
-               return 0;
-       }
-
-       if (!VALID_STAT(smb_fname->st)) {
-               return 0;
-       }
-
-       if (!S_ISREG(smb_fname->st.st_ex_mode)) {
-               return 0;
-       }
-
-       rc = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
-       if (rc != 0) {
-               goto done;
-       }
+       struct smb_filename *rsrc_smb_fname = NULL;
+       int ret;
 
-       DEBUG(10, ("fruit_chown: %s\n", adp_smb_fname->base_name));
+       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
 
-       rc = SMB_VFS_NEXT_CHOWN(handle, adp_smb_fname, uid, gid);
-       if (errno == ENOENT) {
-               rc = 0;
+       if (flags & AT_REMOVEDIR) {
+               return SMB_VFS_NEXT_UNLINKAT(handle,
+                                            dirfsp,
+                                            smb_fname,
+                                            AT_REMOVEDIR);
        }
 
- done:
-       TALLOC_FREE(adp_smb_fname);
-       return rc;
-}
-
-static int fruit_rmdir_internal(struct vfs_handle_struct *handle,
-                       struct files_struct *dirfsp,
-                       const struct smb_filename *smb_fname)
-{
-       DIR *dh = NULL;
-       struct dirent *de;
-       struct fruit_config_data *config;
-
        SMB_VFS_HANDLE_GET_DATA(handle, config,
                                struct fruit_config_data, return -1);
 
-       if (config->rsrc != FRUIT_RSRC_ADFILE) {
-               goto exit_rmdir;
+       if (is_afpinfo_stream(smb_fname->stream_name)) {
+               return fruit_unlink_meta(handle,
+                               dirfsp,
+                               smb_fname);
+       } else if (is_afpresource_stream(smb_fname->stream_name)) {
+               return fruit_unlink_rsrc(handle,
+                               dirfsp,
+                               smb_fname,
+                               false);
+       } else if (is_named_stream(smb_fname)) {
+               return SMB_VFS_NEXT_UNLINKAT(handle,
+                               dirfsp,
+                               smb_fname,
+                               0);
+       } else if (is_adouble_file(smb_fname->base_name)) {
+               return SMB_VFS_NEXT_UNLINKAT(handle,
+                               dirfsp,
+                               smb_fname,
+                               0);
        }
 
        /*
-        * Due to there is no way to change bDeleteVetoFiles variable
-        * from this module, need to clean up ourselves
+        * A request to delete the base file. Because 0 byte resource
+        * fork streams are not listed by fruit_streaminfo,
+        * delete_all_streams() can't remove 0 byte resource fork
+        * streams, so we have to cleanup this here.
         */
-
-       dh = SMB_VFS_OPENDIR(handle->conn, smb_fname, NULL, 0);
-       if (dh == NULL) {
-               goto exit_rmdir;
-       }
-
-       while ((de = SMB_VFS_READDIR(handle->conn, dh, NULL)) != NULL) {
-               struct adouble *ad = NULL;
-               char *p = NULL;
-               struct smb_filename *ad_smb_fname = NULL;
-               int ret;
-
-               if (!is_adouble_file(de->d_name)) {
-                       continue;
-               }
-
-               p = talloc_asprintf(talloc_tos(), "%s/%s",
-                                   smb_fname->base_name, de->d_name);
-               if (p == NULL) {
-                       DBG_ERR("talloc_asprintf failed\n");
-                       return -1;
-               }
-
-               ad_smb_fname = synthetic_smb_fname(talloc_tos(), p,
-                                                   NULL, NULL,
-                                                   smb_fname->flags);
-               TALLOC_FREE(p);
-               if (ad_smb_fname == NULL) {
-                       DBG_ERR("synthetic_smb_fname failed\n");
-                       return -1;
-               }
-
-               /*
-                * Check whether it's a valid AppleDouble file, if
-                * yes, delete it, ignore it otherwise.
-                */
-               ad = ad_get(talloc_tos(), handle, ad_smb_fname, ADOUBLE_RSRC);
-               if (ad == NULL) {
-                       TALLOC_FREE(ad_smb_fname);
-                       TALLOC_FREE(p);
-                       continue;
-               }
-               TALLOC_FREE(ad);
-
-               ret = SMB_VFS_NEXT_UNLINKAT(handle,
-                               dirfsp,
-                               ad_smb_fname,
-                               0);
-               if (ret != 0) {
-                       DBG_ERR("Deleting [%s] failed\n",
-                               smb_fname_str_dbg(ad_smb_fname));
-               }
-               TALLOC_FREE(ad_smb_fname);
+       rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                            smb_fname->base_name,
+                                            AFPRESOURCE_STREAM_NAME,
+                                            NULL,
+                                            smb_fname->twrp,
+                                            smb_fname->flags);
+       if (rsrc_smb_fname == NULL) {
+               return -1;
        }
 
-exit_rmdir:
-       if (dh) {
-               SMB_VFS_CLOSEDIR(handle->conn, dh);
+       ret = fruit_unlink_rsrc(handle, dirfsp, rsrc_smb_fname, true);
+       if ((ret != 0) && (errno != ENOENT)) {
+               DBG_ERR("Forced unlink of [%s] failed [%s]\n",
+                       smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
+               TALLOC_FREE(rsrc_smb_fname);
+               return -1;
        }
-       return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
-}
-
-static int fruit_rmdir(struct vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname)
-{
-       return fruit_rmdir_internal(handle,
-                               handle->conn->cwd_fsp,
-                               smb_fname);
-}
-
-static int fruit_unlink(vfs_handle_struct *handle,
-                       const struct smb_filename *smb_fname)
-{
-       return fruit_unlink_internal(handle,
-                               handle->conn->cwd_fsp,
-                               smb_fname);
-}
-
-static int fruit_unlinkat(vfs_handle_struct *handle,
-                       struct files_struct *dirfsp,
-                       const struct smb_filename *smb_fname,
-                       int flags)
-{
-       int ret;
+       TALLOC_FREE(rsrc_smb_fname);
 
-       SMB_ASSERT(dirfsp == dirfsp->conn->cwd_fsp);
-       if (flags & AT_REMOVEDIR) {
-               ret = fruit_rmdir_internal(handle,
-                               dirfsp,
-                               smb_fname);
-       } else {
-               ret = fruit_unlink_internal(handle,
-                               dirfsp,
-                               smb_fname);
-       }
-       return ret;
+       return SMB_VFS_NEXT_UNLINKAT(handle,
+                       dirfsp,
+                       smb_fname,
+                       0);
 }
 
 static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle,
@@ -2233,7 +2103,10 @@ static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle,
        DBG_ERR("Removing [%s] after short read [%zd]\n",
                fsp_str_dbg(fsp), nread);
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name);
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                       fsp->conn->cwd_fsp,
+                       fsp->fsp_name,
+                       0);
        if (ret != 0) {
                DBG_ERR("Removing [%s] failed\n", fsp_str_dbg(fsp));
                return -1;
@@ -3183,8 +3056,7 @@ static int fruit_stat(vfs_handle_struct *handle,
        DEBUG(10, ("fruit_stat called for %s\n",
                   smb_fname_str_dbg(smb_fname)));
 
-       if (!is_ntfs_stream_smb_fname(smb_fname)
-           || is_ntfs_default_stream_smb_fname(smb_fname)) {
+       if (!is_named_stream(smb_fname)) {
                rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
                if (rc == 0) {
                        update_btime(handle, smb_fname);
@@ -3225,8 +3097,7 @@ static int fruit_lstat(vfs_handle_struct *handle,
        DEBUG(10, ("fruit_lstat called for %s\n",
                   smb_fname_str_dbg(smb_fname)));
 
-       if (!is_ntfs_stream_smb_fname(smb_fname)
-           || is_ntfs_default_stream_smb_fname(smb_fname)) {
+       if (!is_named_stream(smb_fname)) {
                rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
                if (rc == 0) {
                        update_btime(handle, smb_fname);
@@ -3466,12 +3337,17 @@ static NTSTATUS delete_invalid_meta_stream(
        sname = synthetic_smb_fname(talloc_tos(),
                                    smb_fname->base_name,
                                    AFPINFO_STREAM_NAME,
-                                   NULL, 0);
+                                   NULL,
+                                   smb_fname->twrp,
+                                   0);
        if (sname == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, sname);
+       ret = SMB_VFS_NEXT_UNLINKAT(handle,
+                       handle->conn->cwd_fsp,
+                       sname,
+                       0);
        TALLOC_FREE(sname);
        if (ret != 0) {
                DBG_ERR("Removing [%s] failed\n", smb_fname_str_dbg(sname));
@@ -3830,7 +3706,7 @@ static int fruit_ntimes(vfs_handle_struct *handle,
                                return -1);
 
        if ((config->meta != FRUIT_META_NETATALK) ||
-           null_timespec(ft->create_time))
+           is_omit_timespec(&ft->create_time))
        {
                return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
        }
@@ -4051,6 +3927,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
                }
 
                ret = ad_convert(handle,
+                                handle->conn->cwd_fsp,
                                 smb_fname,
                                 macos_string_replace_map,
                                 conv_flags);
@@ -4076,7 +3953,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
        fsp = *result;
 
        if (global_fruit_config.nego_aapl) {
-               if (config->posix_rename && fsp->is_directory) {
+               if (config->posix_rename && fsp->fsp_flags.is_directory) {
                        /*
                         * Enable POSIX directory rename behaviour
                         */
@@ -4094,8 +3971,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
        if (global_fruit_config.nego_aapl &&
            create_disposition == FILE_OPEN &&
            smb_fname->st.st_ex_size == 0 &&
-           is_ntfs_stream_smb_fname(smb_fname) &&
-           !(is_ntfs_default_stream_smb_fname(smb_fname)))
+           is_named_stream(smb_fname))
        {
                status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
                goto fail;
@@ -4106,8 +3982,7 @@ static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
                fio->created = true;
        }
 
-       if (is_ntfs_stream_smb_fname(smb_fname)
-           || fsp->is_directory) {
+       if (is_named_stream(smb_fname) || fsp->fsp_flags.is_directory) {
                return status;
        }
 
@@ -4164,7 +4039,11 @@ static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
                conv_flags |= AD_CONV_DELETE;
        }
 
-       ret = ad_convert(handle, fname, macos_string_replace_map, conv_flags);
+       ret = ad_convert(handle,
+                       handle->conn->cwd_fsp,
+                       fname,
+                       macos_string_replace_map,
+                       conv_flags);
        if (ret != 0) {
                DBG_ERR("ad_convert() failed\n");
                return NT_STATUS_UNSUCCESSFUL;
@@ -4209,6 +4088,7 @@ static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
        } else {
                status = smbd_calculate_access_mask(
                        handle->conn,
+                       handle->conn->cwd_fsp,
                        fname,
                        false,
                        SEC_FLAG_MAXIMUM_ALLOWED,
@@ -4618,6 +4498,7 @@ static void fruit_offload_write_done(struct tevent_req *subreq)
                        state->src_fsp->fsp_name->base_name,
                        streams[i].name,
                        NULL,
+                       state->src_fsp->fsp_name->twrp,
                        state->src_fsp->fsp_name->flags);
                if (tevent_req_nomem(src_fname_tmp, req)) {
                        return;
@@ -4633,6 +4514,7 @@ static void fruit_offload_write_done(struct tevent_req *subreq)
                        state->dst_fsp->fsp_name->base_name,
                        streams[i].name,
                        NULL,
+                       state->dst_fsp->fsp_name->twrp,
                        state->dst_fsp->fsp_name->flags);
                if (tevent_req_nomem(dst_fname_tmp, req)) {
                        TALLOC_FREE(src_fname_tmp);
@@ -4792,7 +4674,12 @@ static bool fruit_get_bandsize(vfs_handle_struct *handle,
                goto out;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(), plist, NULL, NULL, 0);
+       smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       plist,
+                                       NULL,
+                                       NULL,
+                                       0,
+                                       0);
        if (smb_fname == NULL) {
                ok = false;
                goto out;
@@ -4907,15 +4794,16 @@ struct fruit_disk_free_state {
 };
 
 static bool fruit_get_num_bands(vfs_handle_struct *handle,
-                               char *bundle,
+                               const char *bundle,
                                size_t *_nbands)
 {
        char *path = NULL;
        struct smb_filename *bands_dir = NULL;
-       DIR *d = NULL;
-       struct dirent *e = NULL;
+       struct smb_Dir *dir_hnd = NULL;
+       const char *dname = NULL;
+       char *talloced = NULL;
+       long offset = 0;
        size_t nbands;
-       int ret;
 
        path = talloc_asprintf(talloc_tos(),
                               "%s/%s/bands",
@@ -4929,35 +4817,30 @@ static bool fruit_get_num_bands(vfs_handle_struct *handle,
                                        path,
                                        NULL,
                                        NULL,
+                                       0,
                                        0);
        TALLOC_FREE(path);
        if (bands_dir == NULL) {
                return false;
        }
 
-       d = SMB_VFS_NEXT_OPENDIR(handle, bands_dir, NULL, 0);
-       if (d == NULL) {
+       dir_hnd = OpenDir(talloc_tos(), handle->conn, bands_dir, NULL, 0);
+       if (dir_hnd == NULL) {
                TALLOC_FREE(bands_dir);
                return false;
        }
 
        nbands = 0;
 
-       for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
-            e != NULL;
-            e = SMB_VFS_NEXT_READDIR(handle, d, NULL))
+        while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
+              != NULL)
        {
-               if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) {
+               if (ISDOT(dname) || ISDOTDOT(dname)) {
                        continue;
                }
                nbands++;
        }
-
-       ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
-       if (ret != 0) {
-               TALLOC_FREE(bands_dir);
-               return false;
-       }
+       TALLOC_FREE(dir_hnd);
 
        DBG_DEBUG("%zu bands in [%s]\n", nbands, smb_fname_str_dbg(bands_dir));
 
@@ -4969,7 +4852,7 @@ static bool fruit_get_num_bands(vfs_handle_struct *handle,
 
 static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
                                   struct fruit_disk_free_state *state,
-                                  struct dirent *e)
+                                  const char *name)
 {
        bool ok;
        char *p = NULL;
@@ -4978,7 +4861,7 @@ static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
        size_t nbands;
        off_t tm_size;
 
-       p = strstr(e->d_name, "sparsebundle");
+       p = strstr(name, "sparsebundle");
        if (p == NULL) {
                return true;
        }
@@ -4987,39 +4870,45 @@ static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
                return true;
        }
 
-       DBG_DEBUG("Processing sparsebundle [%s]\n", e->d_name);
+       DBG_DEBUG("Processing sparsebundle [%s]\n", name);
 
-       ok = fruit_get_bandsize(handle, e->d_name, &bandsize);
+       ok = fruit_get_bandsize(handle, name, &bandsize);
        if (!ok) {
                /*
                 * Beware of race conditions: this may be an uninitialized
                 * Info.plist that a client is just creating. We don't want let
                 * this to trigger complete failure.
                 */
-               DBG_ERR("Processing sparsebundle [%s] failed\n", e->d_name);
+               DBG_ERR("Processing sparsebundle [%s] failed\n", name);
                return true;
        }
 
-       ok = fruit_get_num_bands(handle, e->d_name, &nbands);
+       ok = fruit_get_num_bands(handle, name, &nbands);
        if (!ok) {
                /*
                 * Beware of race conditions: this may be a backup sparsebundle
                 * in an early stage lacking a bands subdirectory. We don't want
                 * let this to trigger complete failure.
                 */
-               DBG_ERR("Processing sparsebundle [%s] failed\n", e->d_name);
+               DBG_ERR("Processing sparsebundle [%s] failed\n", name);
                return true;
        }
 
+       /*
+        * Arithmetic on 32-bit systems may cause overflow, depending on
+        * size_t precision. First we check its unlikely, then we
+        * force the precision into target off_t, then we check that
+        * the total did not overflow either.
+        */
        if (bandsize > SIZE_MAX/nbands) {
-               DBG_ERR("tmsize overflow: bandsize [%zu] nbands [%zu]\n",
+               DBG_ERR("tmsize potential overflow: bandsize [%zu] nbands [%zu]\n",
                        bandsize, nbands);
                return false;
        }
-       tm_size = bandsize * nbands;
+       tm_size = (off_t)bandsize * (off_t)nbands;
 
        if (state->total_size + tm_size < state->total_size) {
-               DBG_ERR("tmsize overflow: bandsize [%zu] nbands [%zu]\n",
+               DBG_ERR("tm total size overflow: bandsize [%zu] nbands [%zu]\n",
                        bandsize, nbands);
                return false;
        }
@@ -5027,7 +4916,7 @@ static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
        state->total_size += tm_size;
 
        DBG_DEBUG("[%s] tm_size [%jd] total_size [%jd]\n",
-                 e->d_name, (intmax_t)tm_size, (intmax_t)state->total_size);
+                 name, (intmax_t)tm_size, (intmax_t)state->total_size);
 
        return true;
 }
@@ -5051,11 +4940,12 @@ static uint64_t fruit_disk_free(vfs_handle_struct *handle,
 {
        struct fruit_config_data *config = NULL;
        struct fruit_disk_free_state state = {0};
-       DIR *d = NULL;
-       struct dirent *e = NULL;
+       struct smb_Dir *dir_hnd = NULL;
+       const char *dname = NULL;
+       char *talloced = NULL;
+       long offset = 0;
        uint64_t dfree;
        uint64_t dsize;
-       int ret;
        bool ok;
 
        SMB_VFS_HANDLE_GET_DATA(handle, config,
@@ -5072,26 +4962,24 @@ static uint64_t fruit_disk_free(vfs_handle_struct *handle,
                                              _dsize);
        }
 
-       d = SMB_VFS_NEXT_OPENDIR(handle, smb_fname, NULL, 0);
-       if (d == NULL) {
+       dir_hnd = OpenDir(talloc_tos(), handle->conn, smb_fname, NULL, 0);
+       if (dir_hnd == NULL) {
                return UINT64_MAX;
        }
 
-       for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
-            e != NULL;
-            e = SMB_VFS_NEXT_READDIR(handle, d, NULL))
+        while ((dname = ReadDirName(dir_hnd, &offset, NULL, &talloced))
+              != NULL)
        {
-               ok = fruit_tmsize_do_dirent(handle, &state, e);
+               ok = fruit_tmsize_do_dirent(handle, &state, dname);
                if (!ok) {
-                       SMB_VFS_NEXT_CLOSEDIR(handle, d);
+                       TALLOC_FREE(talloced);
+                       TALLOC_FREE(dir_hnd);
                        return UINT64_MAX;
                }
+               TALLOC_FREE(talloced);
        }
 
-       ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
-       if (ret != 0) {
-               return UINT64_MAX;
-       }
+       TALLOC_FREE(dir_hnd);
 
        dsize = config->time_machine_max_size / 512;
        dfree = dsize - (state.total_size / 512);
@@ -5129,11 +5017,8 @@ static struct vfs_fn_pointers vfs_fruit_fns = {
 
        /* File operations */
        .chmod_fn = fruit_chmod,
-       .chown_fn = fruit_chown,
-       .unlink_fn = fruit_unlink,
        .unlinkat_fn = fruit_unlinkat,
        .renameat_fn = fruit_renameat,
-       .rmdir_fn = fruit_rmdir,
        .open_fn = fruit_open,
        .close_fn = fruit_close,
        .pread_fn = fruit_pread,