void io_print(const io_chain_t &chain) { if (chain.empty()) { fprintf(stderr, "Empty chain %p\n", &chain); return; } fprintf(stderr, "Chain %p (%ld items):\n", &chain, (long)chain.size()); for (size_t i=0; i < chain.size(); i++) { const io_data_t *io = chain.at(i); fprintf(stderr, "\t%lu: fd:%d, input:%s, ", (unsigned long)i, io->fd, io->is_input ? "yes" : "no"); switch (io->io_mode) { case IO_FILE: fprintf(stderr, "file (%s)\n", io->filename_cstr); break; case IO_PIPE: fprintf(stderr, "pipe {%d, %d}\n", io->param1.pipe_fd[0], io->param1.pipe_fd[1]); break; case IO_FD: fprintf(stderr, "FD map %d -> %d\n", io->param1.old_fd, io->fd); break; case IO_BUFFER: fprintf(stderr, "buffer %p (size %lu)\n", io->out_buffer_ptr(), io->out_buffer_size()); break; case IO_CLOSE: fprintf(stderr, "close %d\n", io->fd); break; } } }
void io_print(const io_chain_t &chain) { if (chain.empty()) { fprintf(stderr, "Empty chain %p\n", &chain); return; } fprintf(stderr, "Chain %p (%ld items):\n", &chain, (long)chain.size()); for (size_t i=0; i < chain.size(); i++) { const shared_ptr<const io_data_t> &io = chain.at(i); fprintf(stderr, "\t%lu: fd:%d, ", (unsigned long)i, io->fd); io->print(); } }
// This isn't used so the lint tools were complaining about its presence. I'm keeping it in the // source because it could be useful for debugging. void io_print(const io_chain_t &chain) { if (chain.empty()) { std::fwprintf(stderr, L"Empty chain %p\n", &chain); return; } std::fwprintf(stderr, L"Chain %p (%ld items):\n", &chain, (long)chain.size()); for (size_t i=0; i < chain.size(); i++) { const shared_ptr<io_data_t> &io = chain.at(i); if (io.get() == NULL) { std::fwprintf(stderr, L"\t(null)\n"); } else { std::fwprintf(stderr, L"\t%lu: fd:%d, ", (unsigned long)i, io->fd); io->print(); } } }
/// Make a copy of the specified io redirection chain, but change file redirection into fd /// redirection. This makes the redirection chain suitable for use as block-level io, since the file /// won't be repeatedly reopened for every command in the block, which would reset the cursor /// position. /// /// \return true on success, false on failure. Returns the output chain and opened_fds by reference. static bool io_transmogrify(const io_chain_t &in_chain, io_chain_t *out_chain, std::vector<int> *out_opened_fds) { ASSERT_IS_MAIN_THREAD(); assert(out_chain != NULL && out_opened_fds != NULL); assert(out_chain->empty()); // Just to be clear what we do for an empty chain. if (in_chain.empty()) { return true; } bool success = true; // Make our chain of redirections. io_chain_t result_chain; // In the event we can't finish transmorgrifying, we'll have to close all the files we opened. std::vector<int> opened_fds; for (size_t idx = 0; idx < in_chain.size(); idx++) { const shared_ptr<io_data_t> &in = in_chain.at(idx); shared_ptr<io_data_t> out; // gets allocated via new switch (in->io_mode) { case IO_PIPE: case IO_FD: case IO_BUFFER: case IO_CLOSE: { // These redirections don't need transmogrification. They can be passed through. out = in; break; } case IO_FILE: { // Transmogrify file redirections. int fd; io_file_t *in_file = static_cast<io_file_t *>(in.get()); if ((fd = open(in_file->filename_cstr, in_file->flags, OPEN_MASK)) == -1) { debug(1, FILE_ERROR, in_file->filename_cstr); wperror(L"open"); success = false; break; } opened_fds.push_back(fd); out.reset(new io_fd_t(in->fd, fd, false)); break; } } if (out.get() != NULL) result_chain.push_back(out); // Don't go any further if we failed. if (!success) { break; } } // Now either return success, or clean up. if (success) { *out_chain = std::move(result_chain); *out_opened_fds = std::move(opened_fds); } else { result_chain.clear(); io_cleanup_fds(opened_fds); } return success; }