From db35e3eca9c6cbb3459556955b2ee991fcda8515 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Thu, 22 Sep 2011 11:00:19 +0200 Subject: [PATCH] Enhance VFS rename op to rename AppleDouble file --- source3/modules/vfs_netatalk.c | 136 +++++++++++++++++++++++++++++++--------- 1 files changed, 107 insertions(+), 29 deletions(-) diff --git a/source3/modules/vfs_netatalk.c b/source3/modules/vfs_netatalk.c index 8d2c9b7..f187cb6 100644 --- a/source3/modules/vfs_netatalk.c +++ b/source3/modules/vfs_netatalk.c @@ -26,6 +26,7 @@ #define DBGC_CLASS DBGC_VFS #define APPLEDOUBLE ".AppleDouble" +#define ADOUBLEPARENT ".Parent" #define ADOUBLEMODE 0777 /* atalk functions */ @@ -57,6 +58,48 @@ static int atalk_get_path_ptr(char *path) return ptr; } +/* + * Build AppleDouble path, "isdir" gives type: + * true: "some/path" -> "some/path/.AppeDouble/.Parent" + * false: "some/path" -> "some/.AppleDouble/path" + */ +static int atalk_path(TALLOC_CTX *ctx, const char *path, char **adbl_path, bool isdir) +{ + int ret = 0; + TALLOC_CTX *myctx = NULL; + char *mypath = NULL; + char *p1 = NULL; + + if (!ctx || !path || !adbl_path) + return -1; + + mypath = talloc_strdup(ctx, path); + + if (isdir) { + /* just append "/.AppeDouble/.Parent" */ + *adbl_path = talloc_asprintf(ctx, "/%s/%s", + APPLEDOUBLE, ADOUBLEPARENT); + } else { + p1 = strrchr(mypath, '/'); + if (p1) { + /* path contains a slash, first print dirname */ + *p1 = '\0'; + p1++; /* p1 now points to basename */ + *adbl_path = talloc_asprintf(ctx, "%s/%s/%s", + mypath, APPLEDOUBLE, p1); + } else { + *adbl_path = talloc_asprintf(*adbl_path, "%s/%s", + APPLEDOUBLE, mypath); + } + } + + DEBUG(3, ("in: \"%s\"\nout: \"%s\"\n", + path, *adbl_path)); + + return ret; +} + +/* Builds AppleDouble path for _existing_ files and directories */ static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, const char *fname, char **adbl_path, char **orig_path, @@ -72,11 +115,9 @@ static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, if (!ctx || !path || !fname || !adbl_path || !orig_path || !adbl_info || !orig_info) return -1; -#if 0 - DEBUG(3, ("ATALK: PATH: %s[%s]\n", path, fname)); -#endif + if (strstr(path, APPLEDOUBLE) || strstr(fname, APPLEDOUBLE)) { - DEBUG(3, ("ATALK: path %s[%s] already contains %s\n", path, fname, APPLEDOUBLE)); + DEBUG(3, ("path %s[%s] already contains %s\n", path, fname, APPLEDOUBLE)); return -1; } @@ -100,9 +141,10 @@ static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, *adbl_path = talloc_asprintf(ctx, "%s/%s/%s", dname, APPLEDOUBLE, &name[ptr1 + 1]); } -#if 0 - DEBUG(3, ("ATALK: DEBUG:\n%s\n%s\n", *orig_path, *adbl_path)); -#endif + + DEBUG(3, ("in: \"%s\"\nout: \"%s\"\n", + *orig_path, *adbl_path)); + sys_lstat(*adbl_path, adbl_info, fake_dir_create_times); return 0; } @@ -260,36 +302,72 @@ static int atalk_rename(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname_dst) { int ret = 0; - char *oldname = NULL; - char *adbl_path = NULL; - char *orig_path = NULL; - SMB_STRUCT_STAT adbl_info; - SMB_STRUCT_STAT orig_info; + TALLOC_CTX *ctx = NULL; NTSTATUS status; + char *ptr1; - ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst); + /* src */ + char *src_orig_path = NULL; + char *src_adbl_path = NULL; + SMB_STRUCT_STAT src_orig_info; + SMB_STRUCT_STAT src_adbl_info; - status = get_full_smb_filename(talloc_tos(), smb_fname_src, &oldname); - if (!NT_STATUS_IS_OK(status)) { - return ret; - } + /* dst */ + char *dst_adbl_path = NULL; + char *dst_adbldir_path = NULL; + SMB_STRUCT_STAT dst_adbl_dir; - if (atalk_build_paths(talloc_tos(), handle->conn->origpath, oldname, - &adbl_path, &orig_path, &adbl_info, - &orig_info, false) != 0) - goto exit_rename; + if (!(ctx = talloc_init("atalk_rename"))) + goto exit; - if (S_ISDIR(orig_info.st_ex_mode) || S_ISREG(orig_info.st_ex_mode)) { - DEBUG(3, ("ATALK: %s has passed..\n", adbl_path)); - goto exit_rename; + if (smb_fname_src->stream_name || smb_fname_dst->stream_name) { + DEBUG(3, ("stream detected, ignoring\n")); + goto exit; } - atalk_unlink_file(adbl_path); + DEBUG(3, ("src: \"%s/%s\"\ndst: \"%s\"\n", + handle->conn->origpath, smb_fname_src->base_name, + smb_fname_dst->base_name)); -exit_rename: - TALLOC_FREE(oldname); - TALLOC_FREE(adbl_path); - TALLOC_FREE(orig_path); + if (atalk_build_paths(ctx, handle->conn->origpath, + smb_fname_src->base_name, + &src_adbl_path, &src_orig_path, &src_adbl_info, + &src_orig_info, false) != 0) + goto exit; + + ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst); + + if (!ret && S_ISREG(src_orig_info.st_ex_mode)) { + if (sys_lstat(src_adbl_path, &src_adbl_info, false) != 0) { + if (errno != ENOENT) + DEBUG(1, ("stat \"%s\": %s\n", + src_adbl_path, strerror(errno))); + goto exit; + } + + /* Build path for destination adouble file */ + if ((ret = atalk_path(ctx, smb_fname_dst->base_name, + &dst_adbl_path, false)) != 0) + goto exit; + + /* Check .AppleDouble directory exists, create if necessary */ + dst_adbldir_path = talloc_strdup(ctx, dst_adbl_path); + if ((ptr1 = strrchr(dst_adbldir_path, '/')) != NULL) + *ptr1 = '\0'; + if ((sys_lstat(dst_adbldir_path, &dst_adbl_dir, false) != 0) && + (errno == ENOENT)) { + DEBUG(3, ("creating adouble dir: \"%s\"\n", + dst_adbldir_path)); + mkdir(dst_adbldir_path, 0777); + } + + DEBUG(3, ("src: \"%s\"\ndst: \"%s\"\n", + src_adbl_path, dst_adbl_path)); + ret = rename(src_adbl_path, dst_adbl_path); + } + +exit: + talloc_destroy(ctx); return ret; } -- 1.7.0.5