/*
- * 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.41 2003/03/26 04:02:51 deraadt Exp $");
+RCSID("$OpenBSD: sftp-server.c,v 1.47 2004/06/25 05:38:48 dtucker Exp $");
#include "buffer.h"
#include "bufaux.h"
#define get_string(lenp) buffer_get_string(&iqueue, lenp);
#define TRACE debug
-#ifdef HAVE___PROGNAME
extern char *__progname;
-#else
-char *__progname;
-#endif
/* input and output queue */
Buffer iqueue;
/* Version of client */
int version;
-/* portable attibutes, etc. */
+/* portable attributes, etc. */
typedef struct Stat Stat;
}
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;
}
static int
-handle_from_string(char *handle, u_int hlen)
+handle_from_string(const char *handle, u_int hlen)
{
int val;
}
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[] = {
"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;
}
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);
}
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;
}
static void
-send_attrib(u_int32_t id, Attrib *a)
+send_attrib(u_int32_t id, const Attrib *a)
{
Buffer msg;
(u_int64_t)off, len);
if (len > sizeof buf) {
len = sizeof buf;
- log("read change len %d", len);
+ logit("read change len %d", len);
}
fd = handle_to_fd(handle);
if (fd >= 0) {
} else if (ret == len) {
status = SSH2_FX_OK;
} else {
- log("nothing at all written");
+ logit("nothing at all written");
}
}
}
}
static struct timeval *
-attrib_to_tv(Attrib *a)
+attrib_to_tv(const Attrib *a)
{
static struct timeval tv[2];
status = errno_to_portable(errno);
else if (S_ISREG(sb.st_mode)) {
/* Race-free rename of regular files */
- if (link(oldpath, newpath) == -1)
- status = errno_to_portable(errno);
- else if (unlink(oldpath) == -1) {
+ if (link(oldpath, newpath) == -1) {
+ if (errno == EOPNOTSUPP
+#ifdef LINK_OPNOTSUPP_ERRNO
+ || errno == LINK_OPNOTSUPP_ERRNO
+#endif
+ ) {
+ 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);
/* clean spare link */
unlink(newpath);
{
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);
/* XXX should use getopt */
- __progname = get_progname(av[0]);
+ __progname = ssh_get_progname(av[0]);
handle_init();
#ifdef DEBUG_SFTP_SERVER