SilcStream silc_fd_stream_file2(const char *read_file, const char *write_file) { SilcStream stream; int fd1 = 0, fd2 = 0; SILC_LOG_DEBUG(("Creating new fd stream for reading `%s' and writing `%s'", read_file ? read_file : "(none)", write_file ? write_file : "(none)")); if (write_file) { fd2 = silc_file_open(write_file, O_CREAT | O_WRONLY); if (fd2 < 0) { silc_file_close(fd1); return NULL; } } if (read_file) { fd1 = silc_file_open(read_file, O_RDONLY); if (fd1 < 0) return NULL; } stream = silc_fd_stream_create2(fd1, fd2); if (!stream) { silc_file_close(fd1); silc_file_close(fd2); } return stream; }
int silc_file_writefile(const char *filename, const char *buffer, SilcUInt32 len) { int fd; int flags = O_CREAT | O_WRONLY | O_TRUNC; #if defined(O_BINARY) flags |= O_BINARY; #endif /* O_BINARY */ if ((fd = open(filename, flags, 0644)) == -1) { SILC_LOG_ERROR(("Cannot open file %s for writing: %s", filename, silc_errno_string(silc_errno))); return -1; } if (silc_file_write(fd, buffer, len) == -1) { SILC_LOG_ERROR(("Cannot write to file %s: %s", filename, silc_errno_string(silc_errno))); silc_file_close(fd); return -1; } #ifdef SILC_UNIX fsync(fd); #endif /* SILC_UNIX */ return silc_file_close(fd); }
char *silc_file_readfile(const char *filename, SilcUInt32 *return_len, SilcStack stack) { int fd; unsigned char *buffer; int filelen; fd = silc_file_open(filename, O_RDONLY); if (fd < 0) { if (silc_errno == SILC_ERR_NO_SUCH_FILE) return NULL; SILC_LOG_ERROR(("Cannot open file %s: %s", filename, silc_errno_string(silc_errno))); return NULL; } filelen = lseek(fd, (off_t)0L, SEEK_END); if (filelen < 0) { silc_set_errno_posix(errno); silc_file_close(fd); return NULL; } if (lseek(fd, (off_t)0L, SEEK_SET) < 0) { silc_set_errno_posix(errno); silc_file_close(fd); return NULL; } buffer = silc_calloc(filelen + 1, sizeof(*buffer)); if (!buffer) { silc_set_errno_posix(errno); silc_file_close(fd); return NULL; } if ((silc_file_read(fd, buffer, filelen)) == -1) { memset(buffer, 0, sizeof(buffer)); silc_file_close(fd); SILC_LOG_ERROR(("Cannot read from file %s: %s", filename, silc_errno_string(silc_errno))); return NULL; } silc_file_close(fd); buffer[filelen] = EOF; if (return_len) *return_len = filelen; return (char *)buffer; }
char *silc_file_readfile(const char *filename, SilcUInt32 *return_len) { int fd; char *buffer; int filelen; fd = silc_file_open(filename, O_RDONLY); if (fd < 0) { if (errno == ENOENT) return NULL; SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); return NULL; } filelen = lseek(fd, (off_t)0L, SEEK_END); if (filelen < 0) { silc_file_close(fd); return NULL; } if (lseek(fd, (off_t)0L, SEEK_SET) < 0) { silc_file_close(fd); return NULL; } if (filelen < 0) { SILC_LOG_ERROR(("Cannot open file %s: %s", filename, strerror(errno))); silc_file_close(fd); return NULL; } buffer = silc_calloc(filelen + 1, sizeof(char)); if ((silc_file_read(fd, buffer, filelen)) == -1) { memset(buffer, 0, sizeof(buffer)); silc_file_close(fd); SILC_LOG_ERROR(("Cannot read from file %s: %s", filename, strerror(errno))); return NULL; } silc_file_close(fd); buffer[filelen] = EOF; if (return_len) *return_len = filelen; return buffer; }
SilcBool silc_fd_stream_close(SilcStream stream) { SilcFDStream fd_stream = stream; if (fd_stream->fd1 > 0) { silc_file_close(fd_stream->fd1); if (fd_stream->schedule) { silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd1); silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd1); } } if (fd_stream->fd2 > 0 && fd_stream->fd2 != fd_stream->fd1) { silc_file_close(fd_stream->fd2); if (fd_stream->schedule) { silc_schedule_unset_listen_fd(fd_stream->schedule, fd_stream->fd2); silc_schedule_task_del_by_fd(fd_stream->schedule, fd_stream->fd2); } } return TRUE; }
static void silc_client_ftp_data(SilcSFTP sftp, SilcSFTPStatus status, const unsigned char *data, SilcUInt32 data_len, void *context) { SilcClientFtpSession session = (SilcClientFtpSession)context; SILC_LOG_DEBUG(("Start")); if (status == SILC_SFTP_STATUS_EOF) { /* EOF received */ /* Close the handle */ silc_sftp_close(sftp, session->read_handle, NULL, NULL); session->read_handle = NULL; /* Close the real file descriptor */ silc_file_close(session->fd); return; } if (status != SILC_SFTP_STATUS_OK) { /* Call monitor callback */ if (session->monitor) (*session->monitor)(session->client, session->conn, SILC_CLIENT_FILE_MONITOR_ERROR, (status == SILC_SFTP_STATUS_NO_SUCH_FILE ? SILC_CLIENT_FILE_NO_SUCH_FILE : status == SILC_SFTP_STATUS_PERMISSION_DENIED ? SILC_CLIENT_FILE_PERMISSION_DENIED : SILC_CLIENT_FILE_ERROR), 0, 0, session->client_entry, session->session_id, session->filepath, session->monitor_context); /* Close the handle */ silc_sftp_close(sftp, session->read_handle, NULL, NULL); session->read_handle = NULL; /* Close the real file descriptor */ silc_file_close(session->fd); return; } /* Read more, until EOF is received */ session->read_offset += data_len; silc_sftp_read(sftp, session->read_handle, session->read_offset, SILC_PACKET_MAX_LEN - 1024, silc_client_ftp_data, session); /* Write the read data to the real file */ silc_file_write(session->fd, data, data_len); /* Call monitor callback */ if (session->monitor) (*session->monitor)(session->client, session->conn, SILC_CLIENT_FILE_MONITOR_RECEIVE, SILC_CLIENT_FILE_OK, session->read_offset, session->filesize, session->client_entry, session->session_id, session->filepath, session->monitor_context); }
SilcClientFileError silc_client_file_send(SilcClient client, SilcClientConnection conn, SilcClientEntry client_entry, SilcClientConnectionParams *params, SilcPublicKey public_key, SilcPrivateKey private_key, SilcClientFileMonitor monitor, void *monitor_context, const char *filepath, SilcUInt32 *session_id) { SilcClientFtpSession session; SilcBuffer keyagr; char *filename, *path; int fd; SILC_LOG_DEBUG(("File send request (file: %s)", filepath)); if (!client || !client_entry || !filepath || !params || !public_key || !private_key) return SILC_CLIENT_FILE_ERROR; /* Check for existing session for `filepath'. */ silc_dlist_start(client->internal->ftp_sessions); while ((session = silc_dlist_get(client->internal->ftp_sessions))) { if (session->filepath && !strcmp(session->filepath, filepath) && session->client_entry == client_entry) return SILC_CLIENT_FILE_ALREADY_STARTED; } /* See whether the file exists and can be opened */ fd = silc_file_open(filepath, O_RDONLY); if (fd < 0) return SILC_CLIENT_FILE_NO_SUCH_FILE; silc_file_close(fd); /* Add new session */ session = silc_calloc(1, sizeof(*session)); if (!session) return SILC_CLIENT_FILE_ERROR; session->session_id = ++client->internal->next_session_id; session->client = client; session->server_conn = conn; session->initiator = TRUE; session->client_entry = silc_client_ref_client(client, conn, client_entry); session->monitor = monitor; session->monitor_context = monitor_context; session->filepath = strdup(filepath); session->params = *params; session->public_key = public_key; session->private_key = private_key; if (silc_asprintf(&path, "file://%s", filepath) < 0) { silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } /* Allocate memory filesystem and put the file to it */ if (strrchr(path, '/')) filename = strrchr(path, '/') + 1; else filename = (char *)path; session->fs = silc_sftp_fs_memory_alloc(SILC_SFTP_FS_PERM_READ | SILC_SFTP_FS_PERM_EXEC); silc_sftp_fs_memory_add_file(session->fs, NULL, SILC_SFTP_FS_PERM_READ, filename, path); session->filesize = silc_file_size(filepath); /* If local IP is provided, create listener for incoming key exchange */ if (params->local_ip || params->bind_ip) { session->listener = silc_client_listener_add(client, conn->internal->schedule, params, public_key, private_key, silc_client_ftp_connect_completion, session); if (!session->listener) { client->internal->ops->say(client, conn, SILC_CLIENT_MESSAGE_ERROR, "Cannot create listener for file transfer: " "%s", strerror(errno)); silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } session->hostname = (params->bind_ip ? strdup(params->bind_ip) : strdup(params->local_ip)); session->port = silc_client_listener_get_local_port(session->listener); } SILC_LOG_DEBUG(("Sending key agreement for file transfer")); /* Send the key agreement inside FTP packet */ keyagr = silc_key_agreement_payload_encode(session->hostname, 0, session->port); if (!keyagr) { if (session->listener) silc_client_listener_free(session->listener); silc_free(session); return SILC_CLIENT_FILE_NO_MEMORY; } silc_packet_send_va_ext(conn->stream, SILC_PACKET_FTP, 0, 0, NULL, SILC_ID_CLIENT, &client_entry->id, NULL, NULL, SILC_STR_UI_CHAR(1), SILC_STR_DATA(silc_buffer_data(keyagr), silc_buffer_len(keyagr)), SILC_STR_END); silc_buffer_free(keyagr); silc_free(path); silc_dlist_add(client->internal->ftp_sessions, session); if (session_id) *session_id = session->session_id; /* Add session request timeout */ if (params && params->timeout_secs) silc_schedule_task_add_timeout(client->schedule, silc_client_ftp_timeout, session, params->timeout_secs, 0); return SILC_CLIENT_FILE_OK; }