void sftp_handle_new_dir(struct handleid *id, DIR *dp, const char *path) { ferrcheck(pthread_mutex_lock(&sftp_handle_lock)); find_free_handle(id, SSH_FXP_OPENDIR); handles[id->id].u.dir = dp; handles[id->id].path = xstrdup(path); ferrcheck(pthread_mutex_unlock(&sftp_handle_lock)); }
uint32_t sftp_handle_close(const struct handleid *id) { uint32_t rc; ferrcheck(pthread_mutex_lock(&sftp_handle_lock)); if(id->id < nhandles && id->tag == handles[id->id].tag) { handles[id->id].tag = 0; /* free up */ switch(handles[id->id].type) { case SSH_FXP_OPEN: if(close(handles[id->id].u.fd) < 0) rc = HANDLER_ERRNO; else rc = 0; break; case SSH_FXP_OPENDIR: if(closedir(handles[id->id].u.dir) < 0) rc = HANDLER_ERRNO; else rc = 0; break; default: rc = SSH_FX_INVALID_HANDLE; } free(handles[id->id].path); } else rc = SSH_FX_INVALID_HANDLE; ferrcheck(pthread_mutex_unlock(&sftp_handle_lock)); return rc; }
void sftp_handle_new_file(struct handleid *id, int fd, const char *path, unsigned flags) { ferrcheck(pthread_mutex_lock(&sftp_handle_lock)); find_free_handle(id, SSH_FXP_OPEN); handles[id->id].u.fd = fd; handles[id->id].path = xstrdup(path); handles[id->id].flags = flags; ferrcheck(pthread_mutex_unlock(&sftp_handle_lock)); }
unsigned sftp_handle_flags(const struct handleid *id) { unsigned rc; ferrcheck(pthread_mutex_lock(&sftp_handle_lock)); if(id->id < nhandles && id->tag == handles[id->id].tag) rc = handles[id->id].flags; else rc = 0; ferrcheck(pthread_mutex_unlock(&sftp_handle_lock)); return rc; }
void serialize_remove_job(struct sftpjob *job) { struct sqnode *q, **qq; ferrcheck(pthread_mutex_lock(&sq_mutex)); for(qq = &newest; (q = *qq) && q->job != job; qq = &q->older) ; if(q) { *qq = q->older; free(q); /* Wake up anything that's waiting */ ferrcheck(pthread_cond_broadcast(&sq_cond)); } ferrcheck(pthread_mutex_unlock(&sq_mutex)); }
uint32_t sftp_handle_get_dir(const struct handleid *id, DIR **dp, const char **pathp) { uint32_t rc; ferrcheck(pthread_mutex_lock(&sftp_handle_lock)); if(id->id < nhandles && id->tag == handles[id->id].tag && handles[id->id].type == SSH_FXP_OPENDIR) { *dp = handles[id->id].u.dir; if(pathp) *pathp = handles[id->id].path; rc = 0; } else rc = SSH_FX_INVALID_HANDLE; ferrcheck(pthread_mutex_unlock(&sftp_handle_lock)); return rc; }
uint32_t sftp_handle_get_fd(const struct handleid *id, int *fd, unsigned *flagsp) { uint32_t rc; ferrcheck(pthread_mutex_lock(&sftp_handle_lock)); if(id->id < nhandles && id->tag == handles[id->id].tag && handles[id->id].type == SSH_FXP_OPEN) { *fd = handles[id->id].u.fd; if(flagsp) *flagsp = handles[id->id].flags; rc = 0; } else rc = SSH_FX_INVALID_HANDLE; ferrcheck(pthread_mutex_unlock(&sftp_handle_lock)); return rc; }
void queue_serializable_job(struct sftpjob *job) { uint8_t type; uint32_t id; uint64_t offset, len64; uint32_t len; struct handleid hid; unsigned handleflags; struct sqnode *q; job->ptr = job->data; job->left = job->len; if(!sftp_parse_uint8(job, &type) && (type == SSH_FXP_READ || type == SSH_FXP_WRITE) && sftp_parse_uint32(job, &id) == SSH_FX_OK && sftp_parse_handle(job, &hid) == SSH_FX_OK && sftp_parse_uint64(job, &offset) == SSH_FX_OK && sftp_parse_uint32(job, &len) == SSH_FX_OK) { /* This is a well-formed read or write operation */ len64 = len; handleflags = sftp_handle_flags(&hid); } else { /* Anything else has dummy values */ memset(&hid, 0, sizeof hid); offset = 0; len64 = ~(uint64_t)0; handleflags = 0; } ferrcheck(pthread_mutex_lock(&sq_mutex)); q = xmalloc(sizeof *q); q->older = newest; q->job = job; q->type = type; q->hid = hid; q->handleflags = handleflags; q->offset = offset; q->len = len64; newest = q; ferrcheck(pthread_mutex_unlock(&sq_mutex)); }
void serialize(struct sftpjob *job) { struct sqnode *q, *oq; ferrcheck(pthread_mutex_lock(&sq_mutex)); for(;;) { for(q = newest; q && q->job != job; q = q->older) ; /* If the job isn't in the queue then we process it straight away. This * shouldn't happen... */ if(!q) break; /* We've found our position in the queue. See if there is any request on * the same handle which blocks our request. */ for(oq = q->older; oq; oq = oq->older) if(!reorderable(q, oq, q->handleflags)) break; if(!oq) break; /* We found an blocking request. Wait for it to be removed. */ ferrcheck(pthread_cond_wait(&sq_cond, &sq_mutex)); } /* We did not find any blocking request. We proceed. */ ferrcheck(pthread_mutex_unlock(&sq_mutex)); }
void sftp_send_end(struct worker *w) { ssize_t n, written; assert(w->bufused < 0x80000000); /* Fill in length word. The malloc'd area is assumed to be aligned * suitably. */ *(uint32_t *)w->buffer = htonl(w->bufused - 4); /* Write the complete output, protecting stdout with a lock to avoid * interleaving different responses. */ ferrcheck(pthread_mutex_lock(&output_lock)); if(sftp_debugging) { D(("%s:", sendtype)); sftp_debug_hexdump(w->buffer + 4, w->bufused - 4); } /* Write the whole buffer, coping with short writes */ written = 0; while((size_t)written < w->bufused) if((n = write(sftpout, w->buffer + written, w->bufused - written)) > 0) written += n; else if(n < 0) fatal("error sending response: %s", strerror(errno)); ferrcheck(pthread_mutex_unlock(&output_lock)); w->bufused = 0x80000000; }