diff --git a/ggatessh/ggatessh.c b/ggatessh/ggatessh.c index 06c766d..6bb0b17 100644 --- a/ggatessh/ggatessh.c +++ b/ggatessh/ggatessh.c @@ -387,11 +387,11 @@ req_thread(void *arg __unused) buf = NULL; break; + case BIO_DELETE: case BIO_FLUSH: greq->r_ggio.gctl_data = NULL; break; - case BIO_DELETE: default: greq->r_ggio.gctl_error = EOPNOTSUPP; g_gate_ioctl(G_GATE_CMD_DONE, &greq->r_ggio); @@ -426,6 +426,27 @@ req_thread(void *arg __unused) return (NULL); } +static const char * +sftperrno_str(int err) +{ + const char *strs[] = { + [0] = "ok", + [1] = "eof", + [2] = "no such file", + [3] = "permission denied", + [4] = "failure", + [5] = "bad message", + [6] = "no connection", + [7] = "connection lost", + [8] = "op unsupported", + }; + + if (err < 0 || err >= (int)nitems(strs)) + return "invalid errno"; + + return strs[err]; +} + static int process_pending(struct ggs_reqqueue *req_pending, struct ggs_sessqueue *sessqueue) @@ -433,6 +454,7 @@ process_pending(struct ggs_reqqueue *req_pending, struct ggs_req *greq, *greq2; char *errmsg; int rc; + int sftperrno; int didwork; didwork = 0; @@ -505,6 +527,38 @@ again: /* NOTREACHABLE */ break; + case BIO_DELETE: + g_gate_log(LOG_DEBUG, "sftp_punchhole(%p)", greq); + rc = libssh2_sftp_punchhole(greq->r_handle, + greq->r_ggio.gctl_offset, greq->r_ggio.gctl_length); + + didwork = 1; /* assume this always does work */ + switch (rc) { + case LIBSSH2_ERROR_SFTP_PROTOCOL: + greq->r_ggio.gctl_error = EOPNOTSUPP; + sftperrno = libssh2_sftp_last_error( + greq->r_session); + g_gate_log(LOG_DEBUG, "sftp_punchhole(%p) errno: %s(%d)", greq, + sftperrno_str(sftperrno), sftperrno); + goto completeio; + + case LIBSSH2_ERROR_EAGAIN: + continue; + + case 0: /* success */ + goto completeio; + + default: + libssh2_session_last_error(greq->r_ssh_session, + &errmsg, NULL, 0); + g_gate_log(LOG_ERR, "sftp_punchhole(%p) ret %d: %s", + greq, rc, errmsg); + greq->r_ggio.gctl_error = EIO; + goto completeio; + } + /* NOTREACHABLE */ + break; + default: rc = 0; g_gate_log(LOG_ERR, "unhandled op: %d",