diff options
author | Derrell Lipman <derrell@samba.org> | 2005-06-01 20:17:16 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 10:57:04 -0500 |
commit | f3ad9323c62860107ad222a0014d6e661aee42f3 (patch) | |
tree | cd2af79cd9ad1f5502175add8526ca3c3c64cafc /source3/libsmb | |
parent | e317034997bbeab447298070afdb1b78c60e0e69 (diff) | |
download | samba-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')
-rw-r--r-- | source3/libsmb/clirap.c | 95 | ||||
-rw-r--r-- | source3/libsmb/libsmb_cache.c | 2 | ||||
-rw-r--r-- | source3/libsmb/libsmbclient.c | 231 |
3 files changed, 243 insertions, 85 deletions
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) { |