diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index 792f728f83a..d5c468ebd99 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -476,8 +476,9 @@ static bool skel_getlock(vfs_handle_struct *handle, files_struct *fsp, return false; } -static int skel_symlink(vfs_handle_struct *handle, const char *oldpath, - const char *newpath) +static int skel_symlink(vfs_handle_struct *handle, + const char *link_contents, + const struct smb_filename *new_smb_fname) { errno = ENOSYS; return -1; diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index 11512e3815b..93872769422 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -570,10 +570,11 @@ static bool skel_getlock(vfs_handle_struct *handle, files_struct *fsp, return SMB_VFS_NEXT_GETLOCK(handle, fsp, poffset, pcount, ptype, ppid); } -static int skel_symlink(vfs_handle_struct *handle, const char *oldpath, - const char *newpath) +static int skel_symlink(vfs_handle_struct *handle, + const char *link_contents, + const struct smb_filename *new_smb_fname) { - return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath); + return SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname); } static int skel_vfs_readlink(vfs_handle_struct *handle, diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 115a9dc01c6..db555f2cc2b 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -226,6 +226,8 @@ to const struct smb_filename * */ /* Version 37 - Change readlink from const char * to const struct smb_filename * */ +/* Version 37 - Change symlink from const char * + to const struct smb_filename * */ #define SMB_VFS_INTERFACE_VERSION 37 @@ -745,7 +747,9 @@ struct vfs_fn_pointers { uint32_t share_mode, uint32_t access_mask); int (*linux_setlease_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, int leasetype); bool (*getlock_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid); - int (*symlink_fn)(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath); + int (*symlink_fn)(struct vfs_handle_struct *handle, + const char *link_contents, + const struct smb_filename *new_smb_fname); int (*readlink_fn)(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, char *buf, @@ -1251,8 +1255,9 @@ int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle, bool smb_vfs_call_getlock(struct vfs_handle_struct *handle, struct files_struct *fsp, off_t *poffset, off_t *pcount, int *ptype, pid_t *ppid); -int smb_vfs_call_symlink(struct vfs_handle_struct *handle, const char *oldpath, - const char *newpath); +int smb_vfs_call_symlink(struct vfs_handle_struct *handle, + const char *link_contents, + const struct smb_filename *new_smb_fname); int smb_vfs_call_readlink(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, char *buf, diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c index 2c21ab18c48..c07a05954c0 100644 --- a/source3/modules/vfs_cap.c +++ b/source3/modules/vfs_cap.c @@ -479,17 +479,44 @@ static int cap_ntimes(vfs_handle_struct *handle, } -static int cap_symlink(vfs_handle_struct *handle, const char *oldpath, - const char *newpath) +static int cap_symlink(vfs_handle_struct *handle, + const char *link_contents, + const struct smb_filename *new_smb_fname) { - char *capold = capencode(talloc_tos(), oldpath); - char *capnew = capencode(talloc_tos(), newpath); + char *capold = capencode(talloc_tos(), link_contents); + char *capnew = capencode(talloc_tos(), new_smb_fname->base_name); + struct smb_filename *new_cap_smb_fname = NULL; + int saved_errno = 0; + int ret; if (!capold || !capnew) { errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_SYMLINK(handle, capold, capnew); + new_cap_smb_fname = synthetic_smb_fname(talloc_tos(), + capnew, + NULL, + NULL, + new_smb_fname->flags); + if (new_cap_smb_fname == NULL) { + TALLOC_FREE(capold); + TALLOC_FREE(capnew); + errno = ENOMEM; + return -1; + } + ret = SMB_VFS_NEXT_SYMLINK(handle, + capold, + new_cap_smb_fname); + if (ret == -1) { + saved_errno = errno; + } + TALLOC_FREE(capold); + TALLOC_FREE(capnew); + TALLOC_FREE(new_cap_smb_fname); + if (saved_errno != 0) { + errno = saved_errno; + } + return ret; } static int cap_readlink(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index 3c38165b58f..7e2bd0e95d2 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -1125,11 +1125,17 @@ static int cephwrap_linux_setlease(struct vfs_handle_struct *handle, files_struc return result; } -static int cephwrap_symlink(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath) +static int cephwrap_symlink(struct vfs_handle_struct *handle, + const char *link_target, + const struct smb_filename *new_smb_fname) { int result = -1; - DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle, oldpath, newpath); - result = ceph_symlink(handle->data, oldpath, newpath); + DBG_DEBUG("[CEPH] symlink(%p, %s, %s)\n", handle, + link_target, + new_smb_fname->base_name); + result = ceph_symlink(handle->data, + link_target, + new_smb_fname->base_name); DBG_DEBUG("[CEPH] symlink(...) = %d\n", result); WRAP_RETURN(result); } diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 93ff6578553..d339f39aa06 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -2418,12 +2418,14 @@ static int vfswrap_linux_setlease(vfs_handle_struct *handle, files_struct *fsp, return result; } -static int vfswrap_symlink(vfs_handle_struct *handle, const char *oldpath, const char *newpath) +static int vfswrap_symlink(vfs_handle_struct *handle, + const char *link_target, + const struct smb_filename *new_smb_fname) { int result; START_PROFILE(syscall_symlink); - result = symlink(oldpath, newpath); + result = symlink(link_target, new_smb_fname->base_name); END_PROFILE(syscall_symlink); return result; } diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 408f834858c..1267ef3d226 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -1626,14 +1626,15 @@ static bool smb_full_audit_getlock(vfs_handle_struct *handle, files_struct *fsp, } static int smb_full_audit_symlink(vfs_handle_struct *handle, - const char *oldpath, const char *newpath) + const char *link_contents, + const struct smb_filename *new_smb_fname) { int result; - result = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath); + result = SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname); do_log(SMB_VFS_OP_SYMLINK, (result >= 0), handle, - "%s|%s", oldpath, newpath); + "%s|%s", link_contents, new_smb_fname->base_name); return result; } diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index bf19dd722a8..2528959d968 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -1234,9 +1234,12 @@ static bool vfs_gluster_getlock(struct vfs_handle_struct *handle, } static int vfs_gluster_symlink(struct vfs_handle_struct *handle, - const char *oldpath, const char *newpath) + const char *link_target, + const struct smb_filename *new_smb_fname) { - return glfs_symlink(handle->data, oldpath, newpath); + return glfs_symlink(handle->data, + link_target, + new_smb_fname->base_name); } static int vfs_gluster_readlink(struct vfs_handle_struct *handle, diff --git a/source3/modules/vfs_media_harmony.c b/source3/modules/vfs_media_harmony.c index 13604b36dcf..ca8d6ce1a6d 100644 --- a/source3/modules/vfs_media_harmony.c +++ b/source3/modules/vfs_media_harmony.c @@ -1719,47 +1719,41 @@ out: * Success: return 0 * Failure: set errno, return -1 */ + static int mh_symlink(vfs_handle_struct *handle, - const char *oldpath, - const char *newpath) + const char *link_contents, + const struct smb_filename *new_smb_fname) { - int status; - char *oldClientPath; - char *newClientPath; - TALLOC_CTX *ctx; + int status = -1; + char *client_link_contents = NULL; + struct smb_filename *newclientFname = NULL; DEBUG(MH_INFO_DEBUG, ("Entering mh_symlink\n")); - if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) - { - status = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath); + if (!is_in_media_files(link_contents) && + !is_in_media_files(new_smb_fname->base_name)) { + status = SMB_VFS_NEXT_SYMLINK(handle, + link_contents, + new_smb_fname); goto out; } - oldClientPath = NULL; - newClientPath = NULL; - ctx = talloc_tos(); - - if ((status = alloc_get_client_path(handle, ctx, - oldpath, - &oldClientPath))) - { + if ((status = alloc_get_client_path(handle, talloc_tos(), + link_contents, + &client_link_contents))) { goto err; } - - if ((status = alloc_get_client_path(handle, ctx, - newpath, - &newClientPath))) - { + if ((status = alloc_get_client_smb_fname(handle, talloc_tos(), + new_smb_fname, + &newclientFname))) { goto err; } status = SMB_VFS_NEXT_SYMLINK(handle, - oldClientPath, - newClientPath); - + client_link_contents, + newclientFname); err: - TALLOC_FREE(newClientPath); - TALLOC_FREE(oldClientPath); + TALLOC_FREE(client_link_contents); + TALLOC_FREE(newclientFname); out: return status; } diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 2c7fcaacef7..31ef499527e 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1150,19 +1150,28 @@ static int shadow_copy2_rename(vfs_handle_struct *handle, } static int shadow_copy2_symlink(vfs_handle_struct *handle, - const char *oldname, const char *newname) + const char *link_contents, + const struct smb_filename *new_smb_fname) { time_t timestamp_old = 0; time_t timestamp_new = 0; char *snappath_old = NULL; char *snappath_new = NULL; - if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, oldname, - ×tamp_old, NULL, &snappath_old)) { + if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), + handle, + link_contents, + ×tamp_old, + NULL, + &snappath_old)) { return -1; } - if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, newname, - ×tamp_new, NULL, &snappath_new)) { + if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), + handle, + new_smb_fname->base_name, + ×tamp_new, + NULL, + &snappath_new)) { return -1; } if ((timestamp_old != 0) || (timestamp_new != 0)) { @@ -1176,7 +1185,7 @@ static int shadow_copy2_symlink(vfs_handle_struct *handle, errno = EROFS; return -1; } - return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname); + return SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname); } static int shadow_copy2_link(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c index a41397427cc..4c814327feb 100644 --- a/source3/modules/vfs_snapper.c +++ b/source3/modules/vfs_snapper.c @@ -2037,23 +2037,31 @@ static int snapper_gmt_rename(vfs_handle_struct *handle, } static int snapper_gmt_symlink(vfs_handle_struct *handle, - const char *oldname, const char *newname) + const char *link_contents, + const struct smb_filename *new_smb_fname) { - time_t timestamp_old, timestamp_new; + time_t timestamp_old = 0; + time_t timestamp_new = 0; - if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, oldname, - ×tamp_old, NULL)) { + if (!snapper_gmt_strip_snapshot(talloc_tos(), + handle, + link_contents, + ×tamp_old, + NULL)) { return -1; } - if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, newname, - ×tamp_new, NULL)) { + if (!snapper_gmt_strip_snapshot(talloc_tos(), + handle, + new_smb_fname->base_name, + ×tamp_new, + NULL)) { return -1; } if ((timestamp_old != 0) || (timestamp_new != 0)) { errno = EROFS; return -1; } - return SMB_VFS_NEXT_SYMLINK(handle, oldname, newname); + return SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname); } static int snapper_gmt_link(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_syncops.c b/source3/modules/vfs_syncops.c index 725bd1072e4..f94588c60ed 100644 --- a/source3/modules/vfs_syncops.c +++ b/source3/modules/vfs_syncops.c @@ -108,19 +108,6 @@ static void syncops_two_names(const char *name1, const char *name2) talloc_free(tmp_ctx); } -/* - sync two meta data changes for 1 names - */ -static void syncops_name(const char *name) -{ - char *parent; - parent = parent_dir(NULL, name); - if (parent) { - syncops_sync_directory(parent); - talloc_free(parent); - } -} - /* sync two meta data changes for 1 names */ @@ -158,20 +145,6 @@ static int syncops_rename(vfs_handle_struct *handle, return ret; } -/* handle the rest with a macro */ -#define SYNCOPS_NEXT(op, fname, args) do { \ - int ret; \ - struct syncops_config_data *config; \ - SMB_VFS_HANDLE_GET_DATA(handle, config, \ - struct syncops_config_data, \ - return -1); \ - ret = SMB_VFS_NEXT_ ## op args; \ - if (ret == 0 \ - && config->onmeta && !config->disable \ - && fname) syncops_name(fname); \ - return ret; \ -} while (0) - #define SYNCOPS_NEXT_SMB_FNAME(op, fname, args) do { \ int ret; \ struct syncops_config_data *config; \ @@ -186,9 +159,22 @@ static int syncops_rename(vfs_handle_struct *handle, } while (0) static int syncops_symlink(vfs_handle_struct *handle, - const char *oldname, const char *newname) + const char *link_contents, + const struct smb_filename *new_smb_fname) { - SYNCOPS_NEXT(SYMLINK, newname, (handle, oldname, newname)); + int ret; + struct syncops_config_data *config; + + SMB_VFS_HANDLE_GET_DATA(handle, config, + struct syncops_config_data, + return -1); + + ret = SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname); + if (ret == 0 && config->onmeta && !config->disable) { + syncops_two_names(link_contents, + new_smb_fname->base_name); + } + return ret; } static int syncops_link(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 58c0f796a87..d3992018542 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1424,19 +1424,21 @@ static bool smb_time_audit_getlock(vfs_handle_struct *handle, } static int smb_time_audit_symlink(vfs_handle_struct *handle, - const char *oldpath, const char *newpath) + const char *link_contents, + const struct smb_filename *new_smb_fname) { int result; struct timespec ts1,ts2; double timediff; clock_gettime_mono(&ts1); - result = SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath); + result = SMB_VFS_NEXT_SYMLINK(handle, link_contents, new_smb_fname); clock_gettime_mono(&ts2); timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; if (timediff > audit_timeout) { - smb_time_audit_log_fname("symlink", timediff, newpath); + smb_time_audit_log_fname("symlink", timediff, + new_smb_fname->base_name); } return result; diff --git a/source3/modules/vfs_unityed_media.c b/source3/modules/vfs_unityed_media.c index c9ecc277408..45232e1781c 100644 --- a/source3/modules/vfs_unityed_media.c +++ b/source3/modules/vfs_unityed_media.c @@ -1318,38 +1318,40 @@ err: } static int um_symlink(vfs_handle_struct *handle, - const char *oldpath, - const char *newpath) + const char *link_contents, + const struct smb_filename *new_smb_fname) { int status; - char *old_client_path = NULL; - char *new_client_path = NULL; + char *client_link_contents = NULL; + struct smb_filename *new_client_fname = NULL; DEBUG(10, ("Entering um_symlink\n")); - if (!is_in_media_files(oldpath) && !is_in_media_files(newpath)) { - return SMB_VFS_NEXT_SYMLINK(handle, oldpath, newpath); + if (!is_in_media_files(link_contents) && + !is_in_media_files(new_smb_fname->base_name)) { + return SMB_VFS_NEXT_SYMLINK(handle, + link_contents, + new_smb_fname); } status = alloc_get_client_path(handle, talloc_tos(), - oldpath, &old_client_path); + link_contents, &client_link_contents); if (status != 0) { goto err; } - - status = alloc_get_client_path(handle, talloc_tos(), - newpath, &new_client_path); + status = alloc_get_client_smb_fname(handle, talloc_tos(), + new_smb_fname, &new_client_fname); if (status != 0) { goto err; } status = SMB_VFS_NEXT_SYMLINK(handle, - old_client_path, - new_client_path); + client_link_contents, + new_client_fname); err: - TALLOC_FREE(new_client_path); - TALLOC_FREE(old_client_path); + TALLOC_FREE(client_link_contents); + TALLOC_FREE(new_client_fname); return status; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index b88538c2ba1..9c25d8ba8fe 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -1297,6 +1297,7 @@ bool create_msdfs_link(const struct junction_map *jucn) int i=0; bool insert_comma = False; bool ret = False; + struct smb_filename *smb_fname = NULL; if(!junction_to_local_path(jucn, &path, &conn, &cwd)) { return False; @@ -1339,27 +1340,24 @@ bool create_msdfs_link(const struct junction_map *jucn) DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link)); - if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) { + smb_fname = synthetic_smb_fname(talloc_tos(), + path, + NULL, + NULL, + 0); + if (smb_fname == NULL) { + errno = ENOMEM; + goto out; + } + + if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) { if (errno == EEXIST) { - struct smb_filename *smb_fname; - - smb_fname = synthetic_smb_fname(talloc_tos(), - path, - NULL, - NULL, - 0); - if (smb_fname == NULL) { - errno = ENOMEM; - goto out; - } - if(SMB_VFS_UNLINK(conn, smb_fname)!=0) { TALLOC_FREE(smb_fname); goto out; } - TALLOC_FREE(smb_fname); } - if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) { + if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) { DEBUG(1,("create_msdfs_link: symlink failed " "%s -> %s\nError: %s\n", path, msdfs_link, strerror(errno))); @@ -1370,6 +1368,7 @@ bool create_msdfs_link(const struct junction_map *jucn) ret = True; out: + TALLOC_FREE(smb_fname); vfs_ChDir(conn, cwd); SMB_VFS_DISCONNECT(conn); conn_free(conn); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 8615a782f4a..de6073a973f 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -6607,10 +6607,9 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, struct smb_request *req, const char *pdata, int total_data, - const struct smb_filename *smb_fname) + const struct smb_filename *new_smb_fname) { char *link_target = NULL; - const char *newname = smb_fname->base_name; TALLOC_CTX *ctx = talloc_tos(); /* Set a symbolic link. */ @@ -6632,9 +6631,9 @@ static NTSTATUS smb_set_file_unix_link(connection_struct *conn, } DEBUG(10,("smb_set_file_unix_link: SMB_SET_FILE_UNIX_LINK doing symlink %s -> %s\n", - newname, link_target )); + new_smb_fname->base_name, link_target )); - if (SMB_VFS_SYMLINK(conn,link_target,newname) != 0) { + if (SMB_VFS_SYMLINK(conn,link_target,new_smb_fname) != 0) { return map_nt_error_from_unix(errno); } diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index bed3d2c1554..5acfb9af38a 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -2152,11 +2152,12 @@ int smb_vfs_call_linux_setlease(struct vfs_handle_struct *handle, return handle->fns->linux_setlease_fn(handle, fsp, leasetype); } -int smb_vfs_call_symlink(struct vfs_handle_struct *handle, const char *oldpath, - const char *newpath) +int smb_vfs_call_symlink(struct vfs_handle_struct *handle, + const char *link_target, + const struct smb_filename *new_smb_fname) { VFS_FIND(symlink); - return handle->fns->symlink_fn(handle, oldpath, newpath); + return handle->fns->symlink_fn(handle, link_target, new_smb_fname); } int smb_vfs_call_readlink(struct vfs_handle_struct *handle, diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c index 47e365a5dac..65a8e258d0d 100644 --- a/source3/torture/cmd_vfs.c +++ b/source3/torture/cmd_vfs.c @@ -1213,12 +1213,20 @@ static NTSTATUS cmd_lock(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, c static NTSTATUS cmd_symlink(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv) { + struct smb_filename *new_smb_fname = NULL; + if (argc != 3) { printf("Usage: symlink \n"); return NT_STATUS_OK; } - if (SMB_VFS_SYMLINK(vfs->conn, argv[1], argv[2]) == -1) { + new_smb_fname = synthetic_smb_fname_split(mem_ctx, + argv[2], + lp_posix_pathnames()); + if (new_smb_fname == NULL) { + return NT_STATUS_NO_MEMORY; + } + if (SMB_VFS_SYMLINK(vfs->conn, argv[1], new_smb_fname) == -1) { printf("symlink: error=%d (%s)\n", errno, strerror(errno)); return NT_STATUS_UNSUCCESSFUL; }