=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sftp-server.c,v retrieving revision 1.43 retrieving revision 1.43.2.2 diff -u -r1.43 -r1.43.2.2 --- src/usr.bin/ssh/sftp-server.c 2003/06/25 22:39:36 1.43 +++ src/usr.bin/ssh/sftp-server.c 2004/08/19 22:37:32 1.43.2.2 @@ -1,28 +1,20 @@ /* - * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. + * Copyright (c) 2000-2004 Markus Friedl. All rights reserved. * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" -RCSID("$OpenBSD: sftp-server.c,v 1.43 2003/06/25 22:39:36 miod Exp $"); +RCSID("$OpenBSD: sftp-server.c,v 1.43.2.2 2004/08/19 22:37:32 brad Exp $"); #include "buffer.h" #include "bufaux.h" @@ -143,7 +135,7 @@ } static int -handle_new(int use, char *name, int fd, DIR *dirp) +handle_new(int use, const char *name, int fd, DIR *dirp) { int i; @@ -178,7 +170,7 @@ } static int -handle_from_string(char *handle, u_int hlen) +handle_from_string(const char *handle, u_int hlen) { int val; @@ -262,7 +254,7 @@ } static void -send_status(u_int32_t id, u_int32_t error) +send_status(u_int32_t id, u_int32_t status) { Buffer msg; const char *status_messages[] = { @@ -278,21 +270,21 @@ "Unknown error" /* Others */ }; - TRACE("sent status id %u error %u", id, error); + TRACE("sent status id %u error %u", id, status); buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_STATUS); buffer_put_int(&msg, id); - buffer_put_int(&msg, error); + buffer_put_int(&msg, status); if (version >= 3) { buffer_put_cstring(&msg, - status_messages[MIN(error,SSH2_FX_MAX)]); + status_messages[MIN(status,SSH2_FX_MAX)]); buffer_put_cstring(&msg, ""); } send_msg(&msg); buffer_free(&msg); } static void -send_data_or_handle(char type, u_int32_t id, char *data, int dlen) +send_data_or_handle(char type, u_int32_t id, const char *data, int dlen) { Buffer msg; @@ -305,7 +297,7 @@ } static void -send_data(u_int32_t id, char *data, int dlen) +send_data(u_int32_t id, const char *data, int dlen) { TRACE("sent data id %u len %d", id, dlen); send_data_or_handle(SSH2_FXP_DATA, id, data, dlen); @@ -324,7 +316,7 @@ } static void -send_names(u_int32_t id, int count, Stat *stats) +send_names(u_int32_t id, int count, const Stat *stats) { Buffer msg; int i; @@ -344,7 +336,7 @@ } static void -send_attrib(u_int32_t id, Attrib *a) +send_attrib(u_int32_t id, const Attrib *a) { Buffer msg; @@ -561,7 +553,7 @@ } static struct timeval * -attrib_to_tv(Attrib *a) +attrib_to_tv(const Attrib *a) { static struct timeval tv[2]; @@ -827,10 +819,26 @@ status = errno_to_portable(errno); else if (S_ISREG(sb.st_mode)) { /* Race-free rename of regular files */ - if (link(oldpath, newpath) == -1) + if (link(oldpath, newpath) == -1) { + if (errno == EOPNOTSUPP) { + struct stat st; + + /* + * fs doesn't support links, so fall back to + * stat+rename. This is racy. + */ + if (stat(newpath, &st) == -1) { + if (rename(oldpath, newpath) == -1) + status = + errno_to_portable(errno); + else + status = SSH2_FX_OK; + } + } else { + status = errno_to_portable(errno); + } + } else if (unlink(oldpath) == -1) { status = errno_to_portable(errno); - else if (unlink(oldpath) == -1) { - status = errno_to_portable(errno); /* clean spare link */ unlink(newpath); } else @@ -851,20 +859,20 @@ { u_int32_t id; int len; - char link[MAXPATHLEN]; + char buf[MAXPATHLEN]; char *path; id = get_int(); path = get_string(NULL); TRACE("readlink id %u path %s", id, path); - if ((len = readlink(path, link, sizeof(link) - 1)) == -1) + if ((len = readlink(path, buf, sizeof(buf) - 1)) == -1) send_status(id, errno_to_portable(errno)); else { Stat s; - link[len] = '\0'; + buf[len] = '\0'; attrib_clear(&s.attrib); - s.name = s.long_name = link; + s.name = s.long_name = buf; send_names(id, 1, &s); } xfree(path);