summaryrefslogtreecommitdiff
path: root/source3/libsmb/libsmbclient.c
diff options
context:
space:
mode:
Diffstat (limited to 'source3/libsmb/libsmbclient.c')
-rw-r--r--source3/libsmb/libsmbclient.c231
1 files changed, 147 insertions, 84 deletions
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) {