summaryrefslogtreecommitdiffstats
path: root/source4/libcli/clifile.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source4/libcli/clifile.c767
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;
+}