summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/libsmb_internal.h2
-rw-r--r--source3/libsmb/clirap.c95
-rw-r--r--source3/libsmb/libsmb_cache.c2
-rw-r--r--source3/libsmb/libsmbclient.c231
4 files changed, 244 insertions, 86 deletions
diff --git a/source3/include/libsmb_internal.h b/source3/include/libsmb_internal.h
index 2eca879cbe..081bb415e5 100644
--- a/source3/include/libsmb_internal.h
+++ b/source3/include/libsmb_internal.h
@@ -12,9 +12,9 @@
struct _SMBCSRV {
struct cli_state cli;
dev_t dev;
+ BOOL no_pathinfo;
BOOL no_pathinfo2;
BOOL no_nt_session;
- int server_fd;
SMBCSRV *next, *prev;
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
index 06b683b038..4766811c8e 100644
--- a/source3/libsmb/clirap.c
+++ b/source3/libsmb/clirap.c
@@ -457,6 +457,101 @@ BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
return True;
}
+
+/****************************************************************************
+send a setpathinfo call
+****************************************************************************/
+BOOL cli_setpathinfo(struct cli_state *cli, const char *fname,
+ time_t c_time, time_t a_time, time_t m_time, uint16 mode)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ unsigned int rparam_len, rdata_len;
+ uint16 setup = TRANSACT2_SETPATHINFO;
+ pstring param;
+ pstring data;
+ char *rparam=NULL, *rdata=NULL;
+ int count=8;
+ BOOL ret;
+ void (*date_fn)(char *buf,int offset,time_t unixdate);
+ char *p;
+
+ memset(param, 0, sizeof(param));
+ memset(data, 0, sizeof(data));
+
+ p = param;
+
+ /* Add the information level */
+ SSVAL(p, 0, SMB_INFO_STANDARD);
+
+ /* Skip reserved */
+ p += 6;
+
+ /* Add the file name */
+ p += clistr_push(cli, p, fname, sizeof(pstring)-6, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ p = data;
+
+ if (cli->win95) {
+ date_fn = put_dos_date;
+ } else {
+ date_fn = put_dos_date2;
+ }
+
+ /* Add the create, last access, and modification times */
+ (*date_fn)(p, 0, c_time);
+ (*date_fn)(p, 4, a_time);
+ (*date_fn)(p, 8, m_time);
+ p += 12;
+
+ /* Skip DataSize and AllocationSize */
+ p += 8;
+
+ /* Add attributes */
+ SSVAL(p, 0, mode);
+ p += 2;
+
+ /* Add EA size (none) */
+ SIVAL(p, 0, 0);
+ p += 4;
+
+ data_len = PTR_DIFF(p, data);
+
+ do {
+ ret = (cli_send_trans(cli, SMBtrans2,
+ NULL, /* Name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, length, max */
+ param, param_len, 10, /* param, length, max */
+ data, data_len, cli->max_xmit /* data, length, max */
+ ) &&
+ cli_receive_trans(cli, SMBtrans2,
+ &rparam, &rparam_len,
+ &rdata, &rdata_len));
+ if (!cli_is_dos_error(cli)) break;
+ if (!ret) {
+ /* we need to work around a Win95 bug - sometimes
+ it gives ERRSRV/ERRerror temprarily */
+ uint8 eclass;
+ uint32 ecode;
+ cli_dos_error(cli, &eclass, &ecode);
+ if (eclass != ERRSRV || ecode != ERRerror) break;
+ smb_msleep(100);
+ }
+ } while (count-- && ret==False);
+
+ if (!ret) {
+ return False;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return True;
+}
+
+
/****************************************************************************
send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
****************************************************************************/
diff --git a/source3/libsmb/libsmb_cache.c b/source3/libsmb/libsmb_cache.c
index dabf5a527d..de9a1656d8 100644
--- a/source3/libsmb/libsmb_cache.c
+++ b/source3/libsmb/libsmb_cache.c
@@ -102,7 +102,7 @@ static int smbc_add_cached_server(SMBCCTX * context, SMBCSRV * new,
/*
* Search the server cache for a server
- * returns server_fd on success, -1 on error (not found)
+ * returns server handle on success, NULL on error (not found)
* This function is only used if the external cache is not enabled
*/
static SMBCSRV * smbc_get_cached_server(SMBCCTX * context, const char * server,
diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c
index 296dbc7f5b..404d9def69 100644
--- a/source3/libsmb/libsmbclient.c
+++ b/source3/libsmb/libsmbclient.c
@@ -420,7 +420,7 @@ static int smbc_errno(SMBCCTX *context, struct cli_state *c)
}
/*
- * Check a server_fd.
+ * Check a server for being alive and well.
* returns 0 if the server is in shape. Returns 1 on error
*
* Also useable outside libsmbclient to enable external cache
@@ -745,7 +745,7 @@ SMBCSRV *smbc_server(SMBCCTX *context,
/*
* Ok, we have got a nice connection
- * Let's find a free server_fd
+ * Let's allocate a server structure.
*/
srv = SMB_MALLOC_P(SMBCSRV);
@@ -757,6 +757,9 @@ SMBCSRV *smbc_server(SMBCCTX *context,
ZERO_STRUCTP(srv);
srv->cli = c;
srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
+ srv->no_pathinfo = False;
+ srv->no_pathinfo2 = False;
+ srv->no_nt_session = False;
/* now add it to the cache (internal or external) */
/* Let the cache function set errno if it wants to */
@@ -1259,10 +1262,133 @@ static BOOL smbc_getatr(SMBCCTX * context, SMBCSRV *srv, char *path,
}
/*
- * Routine to unlink() a file
+ * Set file info on an SMB server. Use setpathinfo call first. If that
+ * fails, use setattrE..
+ *
+ * Time parameters are always used and must be provided.
+ * "mode" (attributes) parameter may be set to -1 if it is not to be set.
*/
+static BOOL smbc_setatr(SMBCCTX * context, SMBCSRV *srv, char *path,
+ time_t c_time, time_t a_time, time_t m_time,
+ uint16 mode)
+{
+ int fd;
+ int ret;
+
+ /*
+ * Get the create time of the file (if not provided); we'll need it in
+ * the set call.
+ */
+ if (! srv->no_pathinfo && c_time != 0) {
+ if (! cli_qpathinfo(&srv->cli, path,
+ &c_time, NULL, NULL, NULL, NULL)) {
+ /* qpathinfo not available */
+ srv->no_pathinfo = True;
+ } else {
+ /*
+ * We got a creation time. For sanity sake, since
+ * there is no POSIX function to set the create time
+ * of a file, if the existing create time is greater
+ * than either of access time or modification time,
+ * set create time to the smallest of those. This
+ * ensure that the create time of a file is never
+ * greater than its last access or modification time.
+ */
+ if (c_time > a_time) c_time = a_time;
+ if (c_time > m_time) c_time = m_time;
+ }
+ }
+
+ /*
+ * First, try setpathinfo (if qpathinfo succeeded), for it is the
+ * modern function for "new code" to be using, and it works given a
+ * filename rather than requiring that the file be opened to have its
+ * attributes manipulated.
+ */
+ if (srv->no_pathinfo ||
+ ! cli_setpathinfo(&srv->cli, path, c_time, a_time, m_time, mode)) {
+
+ /*
+ * setpathinfo is not supported; go to plan B.
+ *
+ * cli_setatr() does not work on win98, and it also doesn't
+ * support setting the access time (only the modification
+ * time), so in all cases, we open the specified file and use
+ * cli_setattrE() which should work on all OS versions, and
+ * supports both times.
+ */
-static int smbc_unlink_ctx(SMBCCTX *context, const char *fname)
+ /* Don't try {q,set}pathinfo() again, with this server */
+ srv->no_pathinfo = True;
+
+ /* Open the file */
+ if ((fd = cli_open(&srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
+
+ errno = smbc_errno(context, &srv->cli);
+ return -1;
+ }
+
+ /*
+ * Get the creat time of the file (if it wasn't provided).
+ * We'll need it in the set call
+ */
+ if (c_time == 0) {
+ ret = cli_getattrE(&srv->cli, fd,
+ NULL, NULL,
+ &c_time, NULL, NULL);
+ } else {
+ ret = True;
+ }
+
+ /* If we got create time, set times */
+ if (ret) {
+ /* Some OS versions don't support create time */
+ if (c_time == 0) {
+ c_time = time(NULL);
+ }
+
+ /*
+ * For sanity sake, since there is no POSIX function
+ * to set the create time of a file, if the existing
+ * create time is greater than either of access time
+ * or modification time, set create time to the
+ * smallest of those. This ensure that the create
+ * time of a file is never greater than its last
+ * access or modification time.
+ */
+ if (c_time > a_time) c_time = a_time;
+ if (c_time > m_time) c_time = m_time;
+
+ /* Set the new attributes */
+ ret = cli_setattrE(&srv->cli, fd,
+ c_time, a_time, m_time);
+ cli_close(&srv->cli, fd);
+ }
+
+ /*
+ * Unfortunately, setattrE() doesn't have a provision for
+ * setting the access mode (attributes). We'll have to try
+ * cli_setatr() for that, and with only this parameter, it
+ * seems to work on win98.
+ */
+ if (ret && mode != (uint16) -1) {
+ ret = cli_setatr(&srv->cli, path, mode, 0);
+ }
+
+ if (! ret) {
+ errno = smbc_errno(context, &srv->cli);
+ return False;
+ }
+ }
+
+ return True;
+}
+
+ /*
+ * Routine to unlink() a file
+ */
+
+ static int smbc_unlink_ctx(SMBCCTX *context, const char *fname)
{
fstring server, share, user, password, workgroup;
pstring path;
@@ -2851,12 +2977,9 @@ int smbc_chmod_ctx(SMBCCTX *context, const char *fname, mode_t newmode)
int smbc_utimes_ctx(SMBCCTX *context, const char *fname, struct timeval *tbuf)
{
- int fd;
- int ret;
SMBCSRV *srv;
fstring server, share, user, password, workgroup;
pstring path;
- time_t c_time;
time_t a_time;
time_t m_time;
@@ -2910,49 +3033,14 @@ int smbc_utimes_ctx(SMBCCTX *context, const char *fname, struct timeval *tbuf)
srv = smbc_server(context, server, share, workgroup, user, password);
if (!srv) {
- return -1; /* errno set by smbc_server */
+ return -1; /* errno set by smbc_server */
}
- /*
- * cli_setatr() does not work on win98, and it also doesn't support
- * setting the access time (only the modification time), so in all
- * cases, we open the specified file and use cli_setattrE() which
- * should work on all OS versions, and supports both times.
- */
- if ((fd = cli_open(&srv->cli, path, O_RDWR, DENY_NONE)) < 0) {
-
- errno = smbc_errno(context, &srv->cli);
- return -1;
-
+ if (!smbc_setatr(context, srv, path, 0, a_time, m_time, 0)) {
+ return -1; /* errno set by smbc_setatr */
}
- /* Get the creat time of the file; we'll need it in the set call */
- ret = cli_getattrE(&srv->cli, fd, NULL, NULL, &c_time, NULL, NULL);
-
- /* Some OS versions don't support create time */
- if (c_time == 0) {
- c_time = time(NULL);
- }
-
- /*
- * For sanity sake, since there is no POSIX function to set the create
- * time of a file, if the existing create time is greater than either
- * of access time or modification time, set create time to the
- * smallest of those. This ensure that the create time of a file is
- * never greater than its last access or modification time.
- */
- if (c_time > a_time) c_time = a_time;
- if (c_time > m_time) c_time = m_time;
-
- /* If we sucessfully retrieved the create time... */
- if (ret) {
- /* ... then set the new attributes */
- ret = cli_setattrE(&srv->cli, fd, c_time, a_time, m_time);
- }
-
- cli_close(&srv->cli, fd);
-
- return ret;
+ return 0;
}
@@ -4334,23 +4422,15 @@ int smbc_setxattr_ctx(SMBCCTX *context,
dos_attr_parse(context, dad, srv, namevalue);
/* Set the new DOS attributes */
-#if 0 /* not yet implemented */
- if (! cli_setpathinfo(&srv->cli, path,
- dad->c_time,
- dad->a_time,
- dad->m_time,
- dad->mode)) {
- if (!cli_setatr(&srv->cli, path,
- dad->mode, dad->m_time)) {
- errno = smbc_errno(context, &srv->cli);
- }
+ if (! smbc_setatr(context, srv, path,
+ dad->c_time,
+ dad->a_time,
+ dad->m_time,
+ dad->mode)) {
+
+ /* cause failure if NT failed too */
+ dad = NULL;
}
-#else
- if (!cli_setatr(&srv->cli, path,
- dad->mode, dad->m_time)) {
- errno = smbc_errno(context, &srv->cli);
- }
-#endif
}
/* we only fail if both NT and DOS sets failed */
@@ -4472,28 +4552,11 @@ int smbc_setxattr_ctx(SMBCCTX *context,
dos_attr_parse(context, dad, srv, namevalue);
/* Set the new DOS attributes */
-#if 0 /* not yet implemented */
- ret2 = cli_setpathinfo(&srv->cli, path,
- dad->c_time,
- dad->a_time,
- dad->m_time,
- dad->mode);
- if (! ret2) {
- ret2 = cli_setatr(&srv->cli, path,
- dad->mode,
- dad->m_time);
- if (! ret2) {
- errno = smbc_errno(context,
- &srv->cli);
- }
- }
-#else
- ret2 = cli_setatr(&srv->cli, path,
- dad->mode, dad->m_time);
- if (! ret2) {
- errno = smbc_errno(context, &srv->cli);
- }
-#endif
+ ret2 = smbc_setatr(context, srv, path,
+ dad->c_time,
+ dad->a_time,
+ dad->m_time,
+ dad->mode);
/* ret2 has True (success) / False (failure) */
if (ret2) {