summaryrefslogtreecommitdiff
path: root/source3/libsmb/libsmbclient.c
diff options
context:
space:
mode:
authorDerrell Lipman <derrell@samba.org>2005-06-01 20:17:16 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 10:57:04 -0500
commitf3ad9323c62860107ad222a0014d6e661aee42f3 (patch)
treecd2af79cd9ad1f5502175add8526ca3c3c64cafc /source3/libsmb/libsmbclient.c
parente317034997bbeab447298070afdb1b78c60e0e69 (diff)
downloadsamba-f3ad9323c62860107ad222a0014d6e661aee42f3.tar.gz
samba-f3ad9323c62860107ad222a0014d6e661aee42f3.tar.bz2
samba-f3ad9323c62860107ad222a0014d6e661aee42f3.zip
r7172: This is the proper fix for setting file times from libsmbclient. We now
try setpathinfo, and if that doesn't work (e.g. on win98), revert to the previous slower method. (This used to be commit 6c05812bd90b0db69d974ee2758721dc2974a507)
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) {