diff options
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) { |