summaryrefslogtreecommitdiff
path: root/source4/libcli/clifile.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/libcli/clifile.c')
-rw-r--r--source4/libcli/clifile.c647
1 files changed, 647 insertions, 0 deletions
diff --git a/source4/libcli/clifile.c b/source4/libcli/clifile.c
new file mode 100644
index 0000000000..c203e4633d
--- /dev/null
+++ b/source4/libcli/clifile.c
@@ -0,0 +1,647 @@
+/*
+ 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 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/****************************************************************************
+ Hard/Symlink a file (UNIX extensions).
+****************************************************************************/
+
+static BOOL cli_link_internal(struct cli_state *cli,
+ const char *fname_src,
+ const char *fname_dst, BOOL hard_link)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ if (hard_link) {
+ parms.generic.level = SMB_SFILEINFO_UNIX_HLINK;
+ parms.unix_hlink.file.fname = fname_src;
+ parms.unix_hlink.in.link_dest = fname_dst;
+ } else {
+ parms.generic.level = SMB_SFILEINFO_UNIX_LINK;
+ parms.unix_link.file.fname = fname_src;
+ parms.unix_link.in.link_dest = fname_dst;
+ }
+
+ status = smb_raw_setpathinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ Map standard UNIX permissions onto wire representations.
+****************************************************************************/
+static uint32 unix_perms_to_wire(mode_t perms)
+{
+ unsigned int ret = 0;
+
+ ret |= ((perms & S_IXOTH) ? UNIX_X_OTH : 0);
+ ret |= ((perms & S_IWOTH) ? UNIX_W_OTH : 0);
+ ret |= ((perms & S_IROTH) ? UNIX_R_OTH : 0);
+ ret |= ((perms & S_IXGRP) ? UNIX_X_GRP : 0);
+ ret |= ((perms & S_IWGRP) ? UNIX_W_GRP : 0);
+ ret |= ((perms & S_IRGRP) ? UNIX_R_GRP : 0);
+ ret |= ((perms & S_IXUSR) ? UNIX_X_USR : 0);
+ ret |= ((perms & S_IWUSR) ? UNIX_W_USR : 0);
+ ret |= ((perms & S_IRUSR) ? UNIX_R_USR : 0);
+#ifdef S_ISVTX
+ ret |= ((perms & S_ISVTX) ? UNIX_STICKY : 0);
+#endif
+#ifdef S_ISGID
+ ret |= ((perms & S_ISGID) ? UNIX_SET_GID : 0);
+#endif
+#ifdef S_ISUID
+ ret |= ((perms & S_ISUID) ? UNIX_SET_UID : 0);
+#endif
+ return ret;
+}
+
+/****************************************************************************
+ Symlink a file (UNIX extensions).
+****************************************************************************/
+BOOL cli_unix_symlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ return cli_link_internal(cli, fname_src, fname_dst, False);
+}
+
+/****************************************************************************
+ Hard a file (UNIX extensions).
+****************************************************************************/
+BOOL cli_unix_hardlink(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ return cli_link_internal(cli, fname_src, fname_dst, True);
+}
+
+
+/****************************************************************************
+ Chmod or chown a file internal (UNIX extensions).
+****************************************************************************/
+static BOOL cli_unix_chmod_chown_internal(struct cli_state *cli, const char *fname,
+ uint32 mode, uint32 uid, uint32 gid)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ parms.generic.level = SMB_SFILEINFO_UNIX_BASIC;
+ parms.unix_basic.file.fname = fname;
+ parms.unix_basic.in.uid = uid;
+ parms.unix_basic.in.gid = gid;
+ parms.unix_basic.in.mode = mode;
+
+ status = smb_raw_setpathinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ chmod a file (UNIX extensions).
+****************************************************************************/
+
+BOOL cli_unix_chmod(struct cli_state *cli, const char *fname, mode_t mode)
+{
+ return cli_unix_chmod_chown_internal(cli, fname,
+ unix_perms_to_wire(mode), SMB_UID_NO_CHANGE, SMB_GID_NO_CHANGE);
+}
+
+/****************************************************************************
+ chown a file (UNIX extensions).
+****************************************************************************/
+BOOL cli_unix_chown(struct cli_state *cli, const char *fname, uid_t uid, gid_t gid)
+{
+ return cli_unix_chmod_chown_internal(cli, fname, SMB_MODE_NO_CHANGE, (uint32)uid, (uint32)gid);
+}
+
+
+/****************************************************************************
+ Rename a file.
+****************************************************************************/
+BOOL cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst)
+{
+ struct smb_rename parms;
+
+ parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+ parms.in.pattern1 = fname_src;
+ parms.in.pattern2 = fname_dst;
+ return NT_STATUS_IS_OK(smb_raw_rename(cli->tree, &parms));
+}
+
+
+/****************************************************************************
+ Delete a file.
+****************************************************************************/
+BOOL cli_unlink(struct cli_state *cli, const char *fname)
+{
+ struct smb_unlink parms;
+
+ parms.in.pattern = fname;
+ if (strchr(fname, '*')) {
+ parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+ } else {
+ parms.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+ }
+ return NT_STATUS_IS_OK(smb_raw_unlink(cli->tree, &parms));
+}
+
+/****************************************************************************
+ Create a directory.
+****************************************************************************/
+BOOL cli_mkdir(struct cli_state *cli, const char *dname)
+{
+ union smb_mkdir parms;
+
+ parms.mkdir.level = RAW_MKDIR_MKDIR;
+ parms.mkdir.in.path = dname;
+
+ return NT_STATUS_IS_OK(smb_raw_mkdir(cli->tree, &parms));
+}
+
+
+/****************************************************************************
+ Remove a directory.
+****************************************************************************/
+BOOL cli_rmdir(struct cli_state *cli, const char *dname)
+{
+ struct smb_rmdir parms;
+
+ parms.in.path = dname;
+ return NT_STATUS_IS_OK(smb_raw_rmdir(cli->tree, &parms));
+}
+
+
+/****************************************************************************
+ Set or clear the delete on close flag.
+****************************************************************************/
+BOOL cli_nt_delete_on_close(struct cli_state *cli, int fnum, BOOL flag)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ parms.disposition_info.level = RAW_SFILEINFO_DISPOSITION_INFO;
+ parms.disposition_info.file.fnum = fnum;
+ parms.disposition_info.in.delete_on_close = flag;
+
+ status = smb_raw_setfileinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Create/open a file - exposing the full horror of the NT API :-).
+ Used in CIFS-on-CIFS NTVFS.
+****************************************************************************/
+int cli_nt_create_full(struct cli_state *cli, const char *fname,
+ uint32 CreatFlags, uint32 DesiredAccess,
+ uint32 FileAttributes, uint32 ShareAccess,
+ uint32 CreateDisposition, uint32 CreateOptions,
+ uint8 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 = 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(cli->tree, mem_ctx, &open_parms);
+ talloc_destroy(mem_ctx);
+
+ if (NT_STATUS_IS_OK(status)) {
+ return open_parms.ntcreatex.out.fnum;
+ }
+
+ return -1;
+}
+
+
+/****************************************************************************
+ Open a file (using SMBopenx)
+ WARNING: if you open with O_WRONLY then getattrE won't work!
+****************************************************************************/
+int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode)
+{
+ union smb_open open_parms;
+ unsigned openfn=0;
+ unsigned 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(cli->tree, mem_ctx, &open_parms);
+ talloc_destroy(mem_ctx);
+
+ if (NT_STATUS_IS_OK(status)) {
+ return open_parms.openx.out.fnum;
+ }
+
+ return -1;
+}
+
+
+/****************************************************************************
+ Close a file.
+****************************************************************************/
+BOOL cli_close(struct cli_state *cli, int fnum)
+{
+ union smb_close close_parms;
+ NTSTATUS status;
+
+ close_parms.close.level = RAW_CLOSE_CLOSE;
+ close_parms.close.in.fnum = fnum;
+ close_parms.close.in.write_time = 0;
+ status = smb_raw_close(cli->tree, &close_parms);
+ return NT_STATUS_IS_OK(status);
+}
+
+/****************************************************************************
+ send a lock with a specified locktype
+ this is used for testing LOCKING_ANDX_CANCEL_LOCK
+****************************************************************************/
+NTSTATUS cli_locktype(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 len, int timeout, unsigned char locktype)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.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 = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return status;
+}
+
+
+/****************************************************************************
+ Lock a file.
+****************************************************************************/
+BOOL cli_lock(struct cli_state *cli, int fnum,
+ uint32 offset, uint32 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.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 = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Unlock a file.
+****************************************************************************/
+BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.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 = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Lock a file with 64 bit offsets.
+****************************************************************************/
+BOOL cli_lock64(struct cli_state *cli, int fnum,
+ SMB_OFF_T offset, SMB_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 (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ return cli_lock(cli, fnum, offset, len, timeout, lock_type);
+ }
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.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 = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Unlock a file with 64 bit offsets.
+****************************************************************************/
+BOOL cli_unlock64(struct cli_state *cli, int fnum, SMB_OFF_T offset, SMB_OFF_T len)
+{
+ union smb_lock parms;
+ struct smb_lock_entry lock[1];
+ NTSTATUS status;
+
+ if (!(cli->transport->negotiate.capabilities & CAP_LARGE_FILES)) {
+ return cli_unlock(cli, fnum, offset, len);
+ }
+
+ parms.lockx.level = RAW_LOCK_LOCKX;
+ parms.lockx.in.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 = cli->session->pid;
+ lock[0].offset = offset;
+ lock[0].count = len;
+ parms.lockx.in.locks = &lock[0];
+
+ status = smb_raw_lock(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Do a SMBgetattrE call.
+****************************************************************************/
+BOOL cli_getattrE(struct cli_state *cli, int fd,
+ uint16 *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.fnum = fd;
+
+ status = smb_raw_fileinfo(cli->tree, NULL, &parms);
+
+ if (!NT_STATUS_IS_OK(status))
+ return False;
+
+ 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 True;
+}
+
+/****************************************************************************
+ Do a SMBgetatr call
+****************************************************************************/
+BOOL cli_getatr(struct cli_state *cli, const char *fname,
+ uint16 *attr, size_t *size, time_t *t)
+{
+ union smb_fileinfo parms;
+ NTSTATUS status;
+
+ parms.getattr.level = RAW_FILEINFO_GETATTR;
+ parms.getattr.in.fname = fname;
+
+ status = smb_raw_pathinfo(cli->tree, NULL, &parms);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return False;
+ }
+
+ if (size) {
+ *size = parms.getattr.out.size;
+ }
+
+ if (t) {
+ *t = parms.getattr.out.write_time;
+ }
+
+ if (attr) {
+ *attr = parms.getattr.out.attrib;
+ }
+
+ return True;
+}
+
+
+/****************************************************************************
+ Do a SMBsetatr call.
+****************************************************************************/
+BOOL cli_setatr(struct cli_state *cli, const char *fname, uint16 mode, time_t t)
+{
+ union smb_setfileinfo parms;
+ NTSTATUS status;
+
+ parms.setattr.level = RAW_SFILEINFO_SETATTR;
+ parms.setattr.in.attrib = mode;
+ parms.setattr.in.write_time = t;
+ parms.setattr.file.fname = fname;
+
+ status = smb_raw_setpathinfo(cli->tree, &parms);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Check for existence of a dir.
+****************************************************************************/
+BOOL cli_chkpath(struct cli_state *cli, const char *path)
+{
+ struct smb_chkpath parms;
+ char *path2;
+ NTSTATUS status;
+
+ path2 = strdup(path);
+ trim_string(path2,NULL,"\\");
+ if (!*path2) {
+ free(path2);
+ path2 = strdup("\\");
+ }
+
+ parms.in.path = path2;
+
+ status = smb_raw_chkpath(cli->tree, &parms);
+
+ free(path2);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Query disk space.
+****************************************************************************/
+BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
+{
+ union smb_fsinfo fsinfo_parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("cli_dskattr");
+
+ fsinfo_parms.dskattr.level = RAW_QFS_DSKATTR;
+ status = smb_raw_fsinfo(cli->tree, mem_ctx, &fsinfo_parms);
+ if (NT_STATUS_IS_OK(status)) {
+ *bsize = fsinfo_parms.dskattr.out.block_size;
+ *total = fsinfo_parms.dskattr.out.units_total;
+ *avail = fsinfo_parms.dskattr.out.units_free;
+ }
+
+ talloc_destroy(mem_ctx);
+
+ return NT_STATUS_IS_OK(status);
+}
+
+
+/****************************************************************************
+ Create and open a temporary file.
+****************************************************************************/
+int cli_ctemp(struct cli_state *cli, const char *path, char **tmp_path)
+{
+ union smb_open open_parms;
+ TALLOC_CTX *mem_ctx;
+ NTSTATUS status;
+
+ mem_ctx = talloc_init("raw_open");
+ if (!mem_ctx) return -1;
+
+ open_parms.openx.level = RAW_OPEN_CTEMP;
+ open_parms.ctemp.in.attrib = 0;
+ open_parms.ctemp.in.directory = path;
+
+ status = smb_raw_open(cli->tree, mem_ctx, &open_parms);
+ if (tmp_path) {
+ *tmp_path = strdup(open_parms.ctemp.out.name);
+ }
+ talloc_destroy(mem_ctx);
+ if (NT_STATUS_IS_OK(status)) {
+ return open_parms.ctemp.out.fnum;
+ }
+ return -1;
+}
+