From 951329e07d92afacdebfb85bfc950c760a7bd524 Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Fri, 21 Oct 2011 15:57:32 +0200 Subject: [PATCH] Rewrite atalk_build_paths() to make use of struct smb_filename instead of plain char *. Rewrite all callers of atalk_build_paths() to accomodate this. Also fixed: Implement rename() VFS function. Instead of using individual TALLOC contexts, use talloc_tos() context. atalk_lchown() called SMB_VFS_NEXT_CHOWN instead of SMB_VFS_NEXT_LCHOWN. Avoid excessive gotos. --- source3/modules/vfs_netatalk.c | 411 ++++++++++++++++++++++----------------- 1 files changed, 232 insertions(+), 179 deletions(-) diff --git a/source3/modules/vfs_netatalk.c b/source3/modules/vfs_netatalk.c index 8d2c9b7..1a0a1d0 100644 --- a/source3/modules/vfs_netatalk.c +++ b/source3/modules/vfs_netatalk.c @@ -22,89 +22,126 @@ #include "smbd/smbd.h" #include "system/filesys.h" +#include + #undef DBGC_CLASS #define DBGC_CLASS DBGC_VFS #define APPLEDOUBLE ".AppleDouble" +#define ADOUBLEPARENT ".Parent" #define ADOUBLEMODE 0777 -/* atalk functions */ - -static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, - const char *fname, - char **adbl_path, char **orig_path, - SMB_STRUCT_STAT *adbl_info, - SMB_STRUCT_STAT *orig_info, - bool fake_dir_create_times); +/* atalk_build_paths() flags */ +#define ADOUBLE_PATH_STAT (1 << 0) +#define ADOUBLE_PATH_FILE (1 << 1) +#define ADOUBLE_PATH_DIR (1 << 2) +#define ADOUBLE_PATH_DIR_FOR_FILE (1 << 3) +#define ADOUBLE_PATH_PARENT (1 << 4) -static int atalk_unlink_file(const char *path); -static int atalk_get_path_ptr(char *path) +/** + * Construct path to AppleDouble file or directory + * + * The path to the AppleDouble object is constructed according to the + * parameter "adflags". Example given "example/path": + * + * ADOUBLE_PATH_STAT: + * stat() the object in order to determine whether it is a file or directory, + * then build path accordingly: + * file: example/.AppleDouble/path + * directory: example/path/.AppleDouble/ + * + * ADOUBLE_PATH_STAT | ADOUBLE_PATH_PARENT: + * stat() the object in order to determine whether it is a file or directory, + * then build path accordingly: + * file: example/.AppleDouble/path + * directory: example/path/.AppleDouble/.Parent + * + * ADOUBLE_DIR_FOR_FILE: + * Assume object is a file, build path to AppleDouble directory which contains + * it's AppleDouble file: + * example/.AppleDouble/ + * + * ADOUBLE_PATH_FILE: + * Assume object is a file, build path for a file: + * example/.AppleDouble/path + * + * ADOUBLE_PATH_DIR: + * Assume object is a directory, uild AppleDouble directory path for a directory: + * example/path/.AppleDouble/ + * + * ADOUBLE_PATH_DIR | ADOUBLE_PATH_PARENT: + * Build path to AppleDouble file of the directory itself: + * example/path/.AppleDouble/.Parent + * + * @param handle (r) VFS handle + * @param ctx (rw) TALLOC_CTX + * @param path (r) pathname to filesystem object + * @param adflags (r) Conversion flags, see above + * + * @return AppleDouble path on sucess, NULL on error + **/ +static struct smb_filename * +atalk_build_paths(const struct vfs_handle_struct *handle, + TALLOC_CTX *ctx, + const struct smb_filename *path, + unsigned int adflags) { - int i = 0; - int ptr = 0; - - for (i = 0; path[i]; i ++) { - if (path[i] == '/') - ptr = i; - /* get out some 'spam';) from win32's file name */ - else if (path[i] == ':') { - path[i] = '\0'; - break; - } - } - - return ptr; -} + NTSTATUS status; + struct smb_filename *adpath = NULL; + char *dname; + char *bname; + SMB_STRUCT_STAT *st; -static int atalk_build_paths(TALLOC_CTX *ctx, const char *path, - const char *fname, - char **adbl_path, char **orig_path, - SMB_STRUCT_STAT *adbl_info, - SMB_STRUCT_STAT *orig_info, - bool fake_dir_create_times) -{ - int ptr0 = 0; - int ptr1 = 0; - char *dname = 0; - char *name = 0; - - 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)); - return -1; - } + if (!handle || !ctx || !path) + return NULL; - if (fname[0] == '.') ptr0 ++; - if (fname[1] == '/') ptr0 ++; + if ((st = talloc_zero(ctx, SMB_STRUCT_STAT)) == NULL) + return NULL; - *orig_path = talloc_asprintf(ctx, "%s/%s", path, &fname[ptr0]); + if (!NT_STATUS_IS_OK(status = create_synthetic_smb_fname(ctx, NULL, NULL, st, &adpath))) + return NULL; - /* get pointer to last '/' */ - ptr1 = atalk_get_path_ptr(*orig_path); + if ((dname = dirname(talloc_strdup(ctx, path->base_name))) == NULL) + return NULL; + if (dname[0] == '.' && dname[1] == 0) + dname = NULL; - sys_lstat(*orig_path, orig_info, fake_dir_create_times); + if ((bname = basename(talloc_strdup(ctx, path->base_name))) == NULL) + return NULL; - if (S_ISDIR(orig_info->st_ex_mode)) { - *adbl_path = talloc_asprintf(ctx, "%s/%s/%s/", - path, &fname[ptr0], APPLEDOUBLE); - } else { - dname = talloc_strdup(ctx, *orig_path); - dname[ptr1] = '\0'; - name = *orig_path; - *adbl_path = talloc_asprintf(ctx, "%s/%s/%s", - dname, APPLEDOUBLE, &name[ptr1 + 1]); + if ((adflags & ADOUBLE_PATH_STAT) && (!VALID_STAT(path->st))) { + DEBUG(0, ("invalid stat: %s\n", path->base_name)); + return NULL; } -#if 0 - DEBUG(3, ("ATALK: DEBUG:\n%s\n%s\n", *orig_path, *adbl_path)); -#endif - sys_lstat(*adbl_path, adbl_info, fake_dir_create_times); - return 0; + + if (((adflags & ADOUBLE_PATH_STAT) && S_ISDIR(path->st.st_ex_mode)) + || (adflags & ADOUBLE_PATH_DIR)) { + if (adflags & ADOUBLE_PATH_PARENT) { + adpath->base_name = talloc_asprintf(ctx, "%s%s%s/%s/%s", + dname ? dname : "", dname ? "/" : "", + bname, APPLEDOUBLE, ADOUBLEPARENT); + } else { + adpath->base_name = talloc_asprintf(ctx, "%s%s%s/%s/", + dname ? dname : "", dname ? "/" : "", + bname, + APPLEDOUBLE); + } + } else if ((adflags & ADOUBLE_PATH_STAT) || (adflags & ADOUBLE_PATH_FILE)) { + adpath->base_name = talloc_asprintf(ctx, "%s%s%s/%s", + dname ? dname : "", dname ? "/" : "", + APPLEDOUBLE, bname); + } else if (adflags & ADOUBLE_PATH_DIR_FOR_FILE) { + adpath->base_name = talloc_asprintf(ctx, "%s%s%s/", + dname ? dname : "", dname ? "/" : "", + APPLEDOUBLE); + } + + (void)SMB_VFS_STAT(handle->conn, adpath); + + DEBUG(3, ("in: \"%s\"\nout: \"%s\"\n", path->base_name, adpath->base_name)); + + return adpath; } static int atalk_unlink_file(const char *path) @@ -228,7 +265,6 @@ static SMB_STRUCT_DIR *atalk_fdopendir(struct vfs_handle_struct *handle, files_s static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path) { bool add = False; - TALLOC_CTX *ctx = 0; char *dpath; if (!handle->conn->origpath || !path) goto exit_rmdir; @@ -239,17 +275,13 @@ static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path) strstr(path, APPLEDOUBLE) ? (add = False) : (add = True); - if (!(ctx = talloc_init("remove_directory"))) - goto exit_rmdir; - - if (!(dpath = talloc_asprintf(ctx, "%s/%s%s", + if (!(dpath = talloc_asprintf(talloc_tos(), "%s/%s%s", handle->conn->origpath, path, add ? "/"APPLEDOUBLE : ""))) goto exit_rmdir; - atalk_rrmdir(ctx, dpath); + atalk_rrmdir(talloc_tos(), dpath); exit_rmdir: - talloc_destroy(ctx); return SMB_VFS_NEXT_RMDIR(handle, path); } @@ -260,36 +292,73 @@ 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; - NTSTATUS status; + + /* src */ + struct smb_filename *src_adpath; + + /* dst */ + struct smb_filename *dst_adpath; + struct smb_filename *dst_addirpath; ret = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst); - status = get_full_smb_filename(talloc_tos(), smb_fname_src, &oldname); - if (!NT_STATUS_IS_OK(status)) { - return ret; + if (is_ntfs_stream_smb_fname(smb_fname_src) + || is_ntfs_stream_smb_fname(smb_fname_dst)) { + DEBUG(3, ("stream detected, ignoring\n")); + return 0; } - if (atalk_build_paths(talloc_tos(), handle->conn->origpath, oldname, - &adbl_path, &orig_path, &adbl_info, - &orig_info, false) != 0) - goto exit_rename; + DEBUG(3, ("src: \"%s/%s\"\ndst: \"%s\"\n", + handle->conn->origpath, smb_fname_src->base_name, + smb_fname_dst->base_name)); - 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 (strstr_m(smb_fname_src->base_name, APPLEDOUBLE) + || strstr_m(smb_fname_dst->base_name, APPLEDOUBLE)) + return ret; + + if ((src_adpath = atalk_build_paths(handle, + talloc_tos(), + smb_fname_src, + ADOUBLE_PATH_STAT)) == NULL) + return ret; - atalk_unlink_file(adbl_path); + if ((ret == 0) && S_ISREG(smb_fname_src->st.st_ex_mode)) { + /* Only rename AppleDouble files of files */ + if (!VALID_STAT(src_adpath->st)) { + DEBUG(1, ("can't stat: \"%s\"\n", src_adpath->base_name)); + return ret; + } -exit_rename: - TALLOC_FREE(oldname); - TALLOC_FREE(adbl_path); - TALLOC_FREE(orig_path); + /* build path for destination adouble file */ + if ((dst_adpath = atalk_build_paths(handle, + talloc_tos(), + smb_fname_dst, + ADOUBLE_PATH_FILE)) == NULL) + return ret; + + /* Check .AppleDouble directory exists, create if necessary */ + if ((dst_addirpath = atalk_build_paths(handle, + talloc_tos(), + smb_fname_dst, + ADOUBLE_PATH_DIR_FOR_FILE) + ) == NULL) + return ret; + + if (!VALID_STAT(dst_addirpath->st) && (errno == ENOENT)) { + DEBUG(3, ("creating adouble dir: \"%s\"\n", + dst_addirpath->base_name)); + if ((ret = SMB_VFS_MKDIR(handle->conn, dst_addirpath->base_name, 02777)) != 0) + goto exit; + + } + + DEBUG(3, ("src: \"%s\"\ndst: \"%s\"\n", + src_adpath->base_name, dst_adpath->base_name)); + + ret = rename(src_adpath->base_name, dst_adpath->base_name); + } + +exit: return ret; } @@ -297,19 +366,12 @@ static int atalk_unlink(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname) { int ret = 0, i; - char *path = NULL; - char *adbl_path = NULL; - char *orig_path = NULL; - SMB_STRUCT_STAT adbl_info; - SMB_STRUCT_STAT orig_info; - NTSTATUS status; + struct smb_filename *adpath; ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname); - status = get_full_smb_filename(talloc_tos(), smb_fname, &path); - if (!NT_STATUS_IS_OK(status)) { + if (!smb_fname || strstr_m(smb_fname->base_name, APPLEDOUBLE)) return ret; - } /* no .AppleDouble sync if veto or hide list is empty, * otherwise "Cannot find the specified file" error will be caused @@ -330,130 +392,121 @@ static int atalk_unlink(struct vfs_handle_struct *handle, else { DEBUG(3, ("ATALK: %s is not hidden, skipped..\n", APPLEDOUBLE)); - goto exit_unlink; + return ret; } } } - if (atalk_build_paths(talloc_tos(), handle->conn->origpath, path, - &adbl_path, &orig_path, - &adbl_info, &orig_info, false) != 0) - goto exit_unlink; - - 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_unlink; - } + if ((adpath = atalk_build_paths(handle, talloc_tos(), smb_fname, + ADOUBLE_PATH_STAT)) == NULL) + return ret; + if (!VALID_STAT(adpath->st)) + return ret; - atalk_unlink_file(adbl_path); + (void)atalk_unlink_file(adpath->base_name); -exit_unlink: - TALLOC_FREE(path); - TALLOC_FREE(adbl_path); - TALLOC_FREE(orig_path); return ret; } static int atalk_chmod(struct vfs_handle_struct *handle, const char *path, mode_t mode) { - int ret = 0; - char *adbl_path = 0; - char *orig_path = 0; - SMB_STRUCT_STAT adbl_info; - SMB_STRUCT_STAT orig_info; - TALLOC_CTX *ctx; + NTSTATUS status; + int ret; + struct smb_filename *srcpath; + struct smb_filename *adpath; + SMB_STRUCT_STAT st; ret = SMB_VFS_NEXT_CHMOD(handle, path, mode); - if (!path) return ret; + if (!path || strstr_m(path, APPLEDOUBLE)) + return ret; + + if (!NT_STATUS_IS_OK(status = create_synthetic_smb_fname(handle, talloc_tos(), + NULL, &st, &srcpath))) + return ret; - if (!(ctx = talloc_init("chmod_file"))) + if ((adpath = atalk_build_paths(handle, talloc_tos(), srcpath, ADOUBLE_PATH_STAT)) == NULL) return ret; - if (atalk_build_paths(ctx, handle->conn->origpath, path, &adbl_path, - &orig_path, &adbl_info, &orig_info, - false) != 0) - goto exit_chmod; + if (!VALID_STAT(adpath->st)) + return ret; - if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) { - DEBUG(3, ("ATALK: %s has passed..\n", orig_path)); - goto exit_chmod; + if (!S_ISDIR(adpath->st.st_ex_mode) && !S_ISREG(adpath->st.st_ex_mode)) { + DEBUG(3, ("ATALK: %s has passed..\n", adpath->base_name)); + return ret; } - chmod(adbl_path, ADOUBLEMODE); + if (chmod(adpath->base_name, ADOUBLEMODE) != 0) + DEBUG(3, ("chmod(\"%s\"): %s\n", adpath->base_name, strerror(errno))); -exit_chmod: - talloc_destroy(ctx); return ret; } static int atalk_chown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) { - int ret = 0; - char *adbl_path = 0; - char *orig_path = 0; - SMB_STRUCT_STAT adbl_info; - SMB_STRUCT_STAT orig_info; - TALLOC_CTX *ctx; + NTSTATUS status; + int ret; + struct smb_filename *srcpath; + struct smb_filename *adpath; + SMB_STRUCT_STAT st; ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid); - if (!path) return ret; + if (!path || strstr_m(path, APPLEDOUBLE)) + return ret; - if (!(ctx = talloc_init("chown_file"))) + if (!NT_STATUS_IS_OK(status = create_synthetic_smb_fname(handle, talloc_tos(), + NULL, &st, &srcpath))) return ret; - if (atalk_build_paths(ctx, handle->conn->origpath, path, - &adbl_path, &orig_path, - &adbl_info, &orig_info, false) != 0) - goto exit_chown; + if ((adpath = atalk_build_paths(handle, talloc_tos(), srcpath, ADOUBLE_PATH_STAT)) == NULL) + return ret; - if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) { - DEBUG(3, ("ATALK: %s has passed..\n", orig_path)); - goto exit_chown; - } + if (!VALID_STAT(adpath->st)) + return ret; - if (chown(adbl_path, uid, gid) == -1) { - DEBUG(3, ("ATALK: chown error %s\n", strerror(errno))); + if (!S_ISDIR(adpath->st.st_ex_mode) && !S_ISREG(adpath->st.st_ex_mode)) { + DEBUG(3, ("ATALK: %s has passed..\n", path)); + return ret; } -exit_chown: - talloc_destroy(ctx); + if (chown(adpath->base_name, uid, gid) == -1) + DEBUG(3, ("chown(\"%s\"): %s\n", adpath->base_name, strerror(errno))); + return ret; } static int atalk_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) { - int ret = 0; - char *adbl_path = 0; - char *orig_path = 0; - SMB_STRUCT_STAT adbl_info; - SMB_STRUCT_STAT orig_info; - TALLOC_CTX *ctx; + NTSTATUS status; + int ret; + struct smb_filename *srcpath; + struct smb_filename *adpath; + SMB_STRUCT_STAT st; - ret = SMB_VFS_NEXT_CHOWN(handle, path, uid, gid); + ret = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); - if (!path) return ret; + if (!path || strstr_m(path, APPLEDOUBLE)) + return ret; - if (!(ctx = talloc_init("lchown_file"))) + if (!NT_STATUS_IS_OK(status = create_synthetic_smb_fname(handle, talloc_tos(), + NULL, &st, &srcpath))) return ret; - if (atalk_build_paths(ctx, handle->conn->origpath, path, - &adbl_path, &orig_path, - &adbl_info, &orig_info, false) != 0) - goto exit_lchown; + if ((adpath = atalk_build_paths(handle, talloc_tos(), srcpath, ADOUBLE_PATH_STAT)) == NULL) + return ret; - if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) { - DEBUG(3, ("ATALK: %s has passed..\n", orig_path)); - goto exit_lchown; - } + if (!VALID_STAT(adpath->st)) + return ret; - if (lchown(adbl_path, uid, gid) == -1) { - DEBUG(3, ("ATALK: lchown error %s\n", strerror(errno))); + if (!S_ISDIR(adpath->st.st_ex_mode) && !S_ISREG(adpath->st.st_ex_mode)) { + DEBUG(3, ("ATALK: %s has passed..\n", path)); + return ret; } -exit_lchown: - talloc_destroy(ctx); + if (lchown(adpath->base_name, uid, gid) != 0) + DEBUG(3, ("lchown(\"%s\"): %s\n", adpath->base_name, strerror(errno))); + return ret; } -- 1.7.0.5