diff options
Diffstat (limited to '')
-rw-r--r-- | source4/libcli/clifile.c | 767 |
1 files changed, 767 insertions, 0 deletions
diff --git a/source4/libcli/clifile.c b/source4/libcli/clifile.c new file mode 100644 index 0000000..c6a5cd5 --- /dev/null +++ b/source4/libcli/clifile.c @@ -0,0 +1,767 @@ +/* + Unix SMB/CIFS implementation. + client file operations + Copyright (C) Andrew Tridgell 1994-1998 + Copyright (C) Jeremy Allison 2001-2002 + Copyright (C) James Myers 2003 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "system/filesys.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/libcli.h" +#include "system/dir.h" + +/**************************************************************************** + Hard/Symlink a file (UNIX extensions). +****************************************************************************/ + +static NTSTATUS smbcli_link_internal(struct smbcli_tree *tree, + const char *fname_src, + const char *fname_dst, bool hard_link) +{ + union smb_setfileinfo parms; + NTSTATUS status; + + if (hard_link) { + parms.generic.level = RAW_SFILEINFO_UNIX_HLINK; + parms.unix_hlink.in.file.path = fname_src; + parms.unix_hlink.in.link_dest = fname_dst; + } else { + parms.generic.level = RAW_SFILEINFO_UNIX_LINK; + parms.unix_link.in.file.path = fname_src; + parms.unix_link.in.link_dest = fname_dst; + } + + status = smb_raw_setpathinfo(tree, &parms); + + return status; +} + +/**************************************************************************** + Symlink a file (UNIX extensions). +****************************************************************************/ +NTSTATUS smbcli_unix_symlink(struct smbcli_tree *tree, const char *fname_src, + const char *fname_dst) +{ + return smbcli_link_internal(tree, fname_src, fname_dst, false); +} + +/**************************************************************************** + Hard a file (UNIX extensions). +****************************************************************************/ +NTSTATUS smbcli_unix_hardlink(struct smbcli_tree *tree, const char *fname_src, + const char *fname_dst) +{ + return smbcli_link_internal(tree, fname_src, fname_dst, true); +} + + +/**************************************************************************** + Chmod or chown a file internal (UNIX extensions). +****************************************************************************/ +static NTSTATUS smbcli_unix_chmod_chown_internal(struct smbcli_tree *tree, + const char *fname, + uint32_t mode, uint32_t uid, + uint32_t gid) +{ + union smb_setfileinfo parms; + NTSTATUS status; + + parms.generic.level = SMB_SFILEINFO_UNIX_BASIC; + parms.unix_basic.in.file.path = fname; + parms.unix_basic.in.uid = uid; + parms.unix_basic.in.gid = gid; + parms.unix_basic.in.mode = mode; + + status = smb_raw_setpathinfo(tree, &parms); + + return status; +} + +/**************************************************************************** + chmod a file (UNIX extensions). +****************************************************************************/ + +NTSTATUS smbcli_unix_chmod(struct smbcli_tree *tree, const char *fname, mode_t mode) +{ + return smbcli_unix_chmod_chown_internal(tree, fname, + unix_perms_to_wire(mode), + SMB_UID_NO_CHANGE, + SMB_GID_NO_CHANGE); +} + +/**************************************************************************** + chown a file (UNIX extensions). +****************************************************************************/ +NTSTATUS smbcli_unix_chown(struct smbcli_tree *tree, const char *fname, uid_t uid, + gid_t gid) +{ + return smbcli_unix_chmod_chown_internal(tree, fname, SMB_MODE_NO_CHANGE, + (uint32_t)uid, (uint32_t)gid); +} + + +/**************************************************************************** + Rename a file. +****************************************************************************/ +NTSTATUS smbcli_rename(struct smbcli_tree *tree, const char *fname_src, + const char *fname_dst) +{ + union smb_rename parms; + + parms.generic.level = RAW_RENAME_RENAME; + parms.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY; + parms.rename.in.pattern1 = fname_src; + parms.rename.in.pattern2 = fname_dst; + + return smb_raw_rename(tree, &parms); +} + + +/**************************************************************************** + Delete a file. +****************************************************************************/ +NTSTATUS smbcli_unlink(struct smbcli_tree *tree, const char *fname) +{ + union smb_unlink parms; + + parms.unlink.in.pattern = fname; + parms.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY; + + return smb_raw_unlink(tree, &parms); +} + +struct wcard_delete_state { + struct smbcli_tree *tree; + NTSTATUS status; + char *error_name; /* To help debugging. */ +}; + +static void del_fn(struct clilist_file_info *finfo, + const char *pattern, + void *priv) +{ + NTSTATUS status; + union smb_unlink parms; + char *filename = NULL; + char *dirname = NULL; + char *p = NULL; + struct wcard_delete_state *state = (struct wcard_delete_state *)priv; + + if (ISDOT(finfo->name) || ISDOTDOT(finfo->name)) { + return; + } + dirname = talloc_strdup(state, pattern); + if (dirname == NULL) { + TALLOC_FREE(state->error_name); + state->status = NT_STATUS_NO_MEMORY; + return; + } + p = strrchr_m(dirname, '\\'); + if (p != NULL) { + /* Remove the terminating '\' */ + *p = '\0'; + } + if (dirname[0] != '\0') { + filename = talloc_asprintf(dirname, + "%s\\%s", + dirname, + finfo->name); + } else { + filename = talloc_asprintf(dirname, + "%s", + finfo->name); + } + if (filename == NULL) { + TALLOC_FREE(dirname); + TALLOC_FREE(state->error_name); + state->status = NT_STATUS_NO_MEMORY; + return; + } + parms.unlink.in.pattern = filename; + parms.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | + FILE_ATTRIBUTE_HIDDEN; + status = smb_raw_unlink(state->tree, &parms); + if (NT_STATUS_IS_OK(state->status)) { + state->status = status; + if (!NT_STATUS_IS_OK(status)) { + /* + * Save off the name we failed to + * delete to help debugging. + */ + state->error_name = talloc_move(state, &filename); + } + } + TALLOC_FREE(dirname); +} + +/**************************************************************************** + Delete a file, possibly with a wildcard pattern. +****************************************************************************/ +NTSTATUS smbcli_unlink_wcard(struct smbcli_tree *tree, const char *pattern) +{ + NTSTATUS status; + int ret; + struct wcard_delete_state *state = NULL; + + if (strchr(pattern, '*') == NULL) { + /* No wildcard, just call smbcli_unlink(). */ + return smbcli_unlink(tree, pattern); + } + state = talloc_zero(tree, struct wcard_delete_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + state->tree = tree; + ret = smbcli_list(tree, + pattern, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN, + del_fn, + state); + status = state->status; + TALLOC_FREE(state); + if (ret < 0) { + return NT_STATUS_UNSUCCESSFUL; + } + return status; +} + +/**************************************************************************** + Create a directory. +****************************************************************************/ +NTSTATUS smbcli_mkdir(struct smbcli_tree *tree, const char *dname) +{ + union smb_mkdir parms; + + parms.mkdir.level = RAW_MKDIR_MKDIR; + parms.mkdir.in.path = dname; + + return smb_raw_mkdir(tree, &parms); +} + + +/**************************************************************************** + Remove a directory. +****************************************************************************/ +NTSTATUS smbcli_rmdir(struct smbcli_tree *tree, const char *dname) +{ + struct smb_rmdir parms; + + parms.in.path = dname; + + return smb_raw_rmdir(tree, &parms); +} + + +/**************************************************************************** + Set or clear the delete on close flag. +****************************************************************************/ +NTSTATUS smbcli_nt_delete_on_close(struct smbcli_tree *tree, int fnum, + bool flag) +{ + union smb_setfileinfo parms; + NTSTATUS status; + + parms.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO; + parms.disposition_info.in.file.fnum = fnum; + parms.disposition_info.in.delete_on_close = flag; + + status = smb_raw_setfileinfo(tree, &parms); + + return status; +} + + +/**************************************************************************** + Create/open a file - exposing the full horror of the NT API :-). + Used in CIFS-on-CIFS NTVFS. +****************************************************************************/ +int smbcli_nt_create_full(struct smbcli_tree *tree, const char *fname, + uint32_t CreatFlags, uint32_t DesiredAccess, + uint32_t FileAttributes, uint32_t ShareAccess, + uint32_t CreateDisposition, uint32_t CreateOptions, + uint8_t SecurityFlags) +{ + union smb_open open_parms; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + + mem_ctx = talloc_init("raw_open"); + if (!mem_ctx) return -1; + + open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX; + open_parms.ntcreatex.in.flags = CreatFlags; + open_parms.ntcreatex.in.root_fid.fnum = 0; + open_parms.ntcreatex.in.access_mask = DesiredAccess; + open_parms.ntcreatex.in.file_attr = FileAttributes; + open_parms.ntcreatex.in.alloc_size = 0; + open_parms.ntcreatex.in.share_access = ShareAccess; + open_parms.ntcreatex.in.open_disposition = CreateDisposition; + open_parms.ntcreatex.in.create_options = CreateOptions; + open_parms.ntcreatex.in.impersonation = 0; + open_parms.ntcreatex.in.security_flags = SecurityFlags; + open_parms.ntcreatex.in.fname = fname; + + status = smb_raw_open(tree, mem_ctx, &open_parms); + talloc_free(mem_ctx); + + if (NT_STATUS_IS_OK(status)) { + return open_parms.ntcreatex.out.file.fnum; + } + + return -1; +} + + +/**************************************************************************** + Open a file (using SMBopenx) + WARNING: if you open with O_WRONLY then getattrE won't work! +****************************************************************************/ +int smbcli_open(struct smbcli_tree *tree, const char *fname, int flags, + int share_mode) +{ + union smb_open open_parms; + unsigned int openfn=0; + unsigned int accessmode=0; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + + mem_ctx = talloc_init("raw_open"); + if (!mem_ctx) return -1; + + if (flags & O_CREAT) { + openfn |= OPENX_OPEN_FUNC_CREATE; + } + if (!(flags & O_EXCL)) { + if (flags & O_TRUNC) { + openfn |= OPENX_OPEN_FUNC_TRUNC; + } else { + openfn |= OPENX_OPEN_FUNC_OPEN; + } + } + + accessmode = (share_mode<<OPENX_MODE_DENY_SHIFT); + + if ((flags & O_ACCMODE) == O_RDWR) { + accessmode |= OPENX_MODE_ACCESS_RDWR; + } else if ((flags & O_ACCMODE) == O_WRONLY) { + accessmode |= OPENX_MODE_ACCESS_WRITE; + } + +#if defined(O_SYNC) + if ((flags & O_SYNC) == O_SYNC) { + accessmode |= OPENX_MODE_WRITE_THRU; + } +#endif + + if (share_mode == DENY_FCB) { + accessmode = OPENX_MODE_ACCESS_FCB | OPENX_MODE_DENY_FCB; + } + + open_parms.openx.level = RAW_OPEN_OPENX; + open_parms.openx.in.flags = 0; + open_parms.openx.in.open_mode = accessmode; + open_parms.openx.in.search_attrs = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN; + open_parms.openx.in.file_attrs = 0; + open_parms.openx.in.write_time = 0; + open_parms.openx.in.open_func = openfn; + open_parms.openx.in.size = 0; + open_parms.openx.in.timeout = 0; + open_parms.openx.in.fname = fname; + + status = smb_raw_open(tree, mem_ctx, &open_parms); + talloc_free(mem_ctx); + + if (NT_STATUS_IS_OK(status)) { + return open_parms.openx.out.file.fnum; + } + + return -1; +} + + +/**************************************************************************** + Close a file. +****************************************************************************/ +NTSTATUS smbcli_close(struct smbcli_tree *tree, int fnum) +{ + union smb_close close_parms; + NTSTATUS status; + + close_parms.close.level = RAW_CLOSE_CLOSE; + close_parms.close.in.file.fnum = fnum; + close_parms.close.in.write_time = 0; + status = smb_raw_close(tree, &close_parms); + return status; +} + +/**************************************************************************** + send a lock with a specified locktype + this is used for testing LOCKING_ANDX_CANCEL_LOCK +****************************************************************************/ +NTSTATUS smbcli_locktype(struct smbcli_tree *tree, int fnum, + uint32_t offset, uint32_t len, int timeout, + uint8_t locktype) +{ + union smb_lock parms; + struct smb_lock_entry lock[1]; + NTSTATUS status; + + parms.lockx.level = RAW_LOCK_LOCKX; + parms.lockx.in.file.fnum = fnum; + parms.lockx.in.mode = locktype; + parms.lockx.in.timeout = timeout; + parms.lockx.in.ulock_cnt = 0; + parms.lockx.in.lock_cnt = 1; + lock[0].pid = tree->session->pid; + lock[0].offset = offset; + lock[0].count = len; + parms.lockx.in.locks = &lock[0]; + + status = smb_raw_lock(tree, &parms); + + return status; +} + + +/**************************************************************************** + Lock a file. +****************************************************************************/ +NTSTATUS smbcli_lock(struct smbcli_tree *tree, int fnum, + uint32_t offset, uint32_t len, int timeout, + enum brl_type lock_type) +{ + union smb_lock parms; + struct smb_lock_entry lock[1]; + NTSTATUS status; + + parms.lockx.level = RAW_LOCK_LOCKX; + parms.lockx.in.file.fnum = fnum; + parms.lockx.in.mode = (lock_type == READ_LOCK? 1 : 0); + parms.lockx.in.timeout = timeout; + parms.lockx.in.ulock_cnt = 0; + parms.lockx.in.lock_cnt = 1; + lock[0].pid = tree->session->pid; + lock[0].offset = offset; + lock[0].count = len; + parms.lockx.in.locks = &lock[0]; + + status = smb_raw_lock(tree, &parms); + + return status; +} + + +/**************************************************************************** + Unlock a file. +****************************************************************************/ +NTSTATUS smbcli_unlock(struct smbcli_tree *tree, int fnum, uint32_t offset, uint32_t len) +{ + union smb_lock parms; + struct smb_lock_entry lock[1]; + NTSTATUS status; + + parms.lockx.level = RAW_LOCK_LOCKX; + parms.lockx.in.file.fnum = fnum; + parms.lockx.in.mode = 0; + parms.lockx.in.timeout = 0; + parms.lockx.in.ulock_cnt = 1; + parms.lockx.in.lock_cnt = 0; + lock[0].pid = tree->session->pid; + lock[0].offset = offset; + lock[0].count = len; + parms.lockx.in.locks = &lock[0]; + + status = smb_raw_lock(tree, &parms); + return status; +} + + +/**************************************************************************** + Lock a file with 64 bit offsets. +****************************************************************************/ +NTSTATUS smbcli_lock64(struct smbcli_tree *tree, int fnum, + off_t offset, off_t len, int timeout, + enum brl_type lock_type) +{ + union smb_lock parms; + int ltype; + struct smb_lock_entry lock[1]; + NTSTATUS status; + + if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) { + return smbcli_lock(tree, fnum, offset, len, timeout, lock_type); + } + + parms.lockx.level = RAW_LOCK_LOCKX; + parms.lockx.in.file.fnum = fnum; + + ltype = (lock_type == READ_LOCK? 1 : 0); + ltype |= LOCKING_ANDX_LARGE_FILES; + parms.lockx.in.mode = ltype; + parms.lockx.in.timeout = timeout; + parms.lockx.in.ulock_cnt = 0; + parms.lockx.in.lock_cnt = 1; + lock[0].pid = tree->session->pid; + lock[0].offset = offset; + lock[0].count = len; + parms.lockx.in.locks = &lock[0]; + + status = smb_raw_lock(tree, &parms); + + return status; +} + + +/**************************************************************************** + Unlock a file with 64 bit offsets. +****************************************************************************/ +NTSTATUS smbcli_unlock64(struct smbcli_tree *tree, int fnum, off_t offset, + off_t len) +{ + union smb_lock parms; + struct smb_lock_entry lock[1]; + NTSTATUS status; + + if (!(tree->session->transport->negotiate.capabilities & CAP_LARGE_FILES)) { + return smbcli_unlock(tree, fnum, offset, len); + } + + parms.lockx.level = RAW_LOCK_LOCKX; + parms.lockx.in.file.fnum = fnum; + parms.lockx.in.mode = LOCKING_ANDX_LARGE_FILES; + parms.lockx.in.timeout = 0; + parms.lockx.in.ulock_cnt = 1; + parms.lockx.in.lock_cnt = 0; + lock[0].pid = tree->session->pid; + lock[0].offset = offset; + lock[0].count = len; + parms.lockx.in.locks = &lock[0]; + + status = smb_raw_lock(tree, &parms); + + return status; +} + + +/**************************************************************************** + Do a SMBgetattrE call. +****************************************************************************/ +NTSTATUS smbcli_getattrE(struct smbcli_tree *tree, int fnum, + uint16_t *attr, size_t *size, + time_t *c_time, time_t *a_time, time_t *m_time) +{ + union smb_fileinfo parms; + NTSTATUS status; + + parms.getattre.level = RAW_FILEINFO_GETATTRE; + parms.getattre.in.file.fnum = fnum; + + status = smb_raw_fileinfo(tree, NULL, &parms); + + if (!NT_STATUS_IS_OK(status)) + return status; + + if (size) { + *size = parms.getattre.out.size; + } + + if (attr) { + *attr = parms.getattre.out.attrib; + } + + if (c_time) { + *c_time = parms.getattre.out.create_time; + } + + if (a_time) { + *a_time = parms.getattre.out.access_time; + } + + if (m_time) { + *m_time = parms.getattre.out.write_time; + } + + return status; +} + +/**************************************************************************** + Do a SMBgetatr call +****************************************************************************/ +NTSTATUS smbcli_getatr(struct smbcli_tree *tree, const char *fname, + uint16_t *attr, size_t *size, time_t *t) +{ + union smb_fileinfo parms; + NTSTATUS status; + + parms.getattr.level = RAW_FILEINFO_GETATTR; + parms.getattr.in.file.path = fname; + + status = smb_raw_pathinfo(tree, NULL, &parms); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (size) { + *size = parms.getattr.out.size; + } + + if (t) { + *t = parms.getattr.out.write_time; + } + + if (attr) { + *attr = parms.getattr.out.attrib; + } + + return status; +} + + +/**************************************************************************** + Do a SMBsetatr call. +****************************************************************************/ +NTSTATUS smbcli_setatr(struct smbcli_tree *tree, const char *fname, uint16_t mode, + time_t t) +{ + union smb_setfileinfo parms; + + parms.setattr.level = RAW_SFILEINFO_SETATTR; + parms.setattr.in.file.path = fname; + parms.setattr.in.attrib = mode; + parms.setattr.in.write_time = t; + + return smb_raw_setpathinfo(tree, &parms); +} + +/**************************************************************************** + Do a setfileinfo basic_info call. +****************************************************************************/ +NTSTATUS smbcli_fsetatr(struct smbcli_tree *tree, int fnum, uint16_t mode, + NTTIME create_time, NTTIME access_time, + NTTIME write_time, NTTIME change_time) +{ + union smb_setfileinfo parms; + + parms.basic_info.level = RAW_SFILEINFO_BASIC_INFO; + parms.basic_info.in.file.fnum = fnum; + parms.basic_info.in.attrib = mode; + parms.basic_info.in.create_time = create_time; + parms.basic_info.in.access_time = access_time; + parms.basic_info.in.write_time = write_time; + parms.basic_info.in.change_time = change_time; + + return smb_raw_setfileinfo(tree, &parms); +} + + +/**************************************************************************** + truncate a file to a given size +****************************************************************************/ +NTSTATUS smbcli_ftruncate(struct smbcli_tree *tree, int fnum, uint64_t size) +{ + union smb_setfileinfo parms; + + parms.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFO; + parms.end_of_file_info.in.file.fnum = fnum; + parms.end_of_file_info.in.size = size; + + return smb_raw_setfileinfo(tree, &parms); +} + + +/**************************************************************************** + Check for existence of a dir. +****************************************************************************/ +NTSTATUS smbcli_chkpath(struct smbcli_tree *tree, const char *path) +{ + union smb_chkpath parms; + char *path2; + NTSTATUS status; + + path2 = strdup(path); + trim_string(path2,NULL,"\\"); + if (!*path2) { + free(path2); + path2 = strdup("\\"); + } + + parms.chkpath.in.path = path2; + + status = smb_raw_chkpath(tree, &parms); + + free(path2); + + return status; +} + + +/**************************************************************************** + Query disk space. +****************************************************************************/ +NTSTATUS smbcli_dskattr(struct smbcli_tree *tree, uint32_t *bsize, + uint64_t *total, uint64_t *avail) +{ + union smb_fsinfo fsinfo_parms; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + + mem_ctx = talloc_init("smbcli_dskattr"); + + fsinfo_parms.dskattr.level = RAW_QFS_SIZE_INFO; + status = smb_raw_fsinfo(tree, mem_ctx, &fsinfo_parms); + if (NT_STATUS_IS_OK(status)) { + *bsize = fsinfo_parms.size_info.out.bytes_per_sector * fsinfo_parms.size_info.out.sectors_per_unit; + *total = fsinfo_parms.size_info.out.total_alloc_units; + *avail = fsinfo_parms.size_info.out.avail_alloc_units; + } + + talloc_free(mem_ctx); + + return status; +} + + +/**************************************************************************** + Create and open a temporary file. +****************************************************************************/ +int smbcli_ctemp(struct smbcli_tree *tree, const char *path, char **tmp_path) +{ + union smb_open open_parms; + TALLOC_CTX *mem_ctx; + NTSTATUS status; + int ret = -1; + + mem_ctx = talloc_init("raw_open"); + if (!mem_ctx) return ret; + + open_parms.openx.level = RAW_OPEN_CTEMP; + open_parms.ctemp.in.attrib = 0; + open_parms.ctemp.in.directory = path; + open_parms.ctemp.in.write_time = 0; + + status = smb_raw_open(tree, mem_ctx, &open_parms); + if (NT_STATUS_IS_OK(status)) { + if (tmp_path) { + *tmp_path = strdup(open_parms.ctemp.out.name); + } + ret = open_parms.ctemp.out.file.fnum; + } + talloc_free(mem_ctx); + return ret; +} |