~nabijaczleweli/voreutils

4d1b3a286e37f090e27032fcd6a1ace5ab957255 — наб a month ago fa4bb2a
Also bump/splice/c_f_r for head -c: common (well I hit it yesterday) usecase for subslicing files
3 files changed, 41 insertions(+), 3 deletions(-)

M README.md
M cmd/cat.cpp
M cmd/head.cpp
M README.md => README.md +1 -1
@@ 56,7 56,7 @@ GNU coreutils provide the following 106 binaries, according to `dpkg -L coreutil
  * ☐ /usr/bin/fmt
  * ☑ /usr/bin/fold
  * ☑ /usr/bin/groups
  * ☑ /usr/bin/head
  * ☑ /usr/bin/head – same deal as cat for byte prefix (`-c128`)
  * ☑ /usr/bin/hostid
  * ☑ /usr/bin/id
  * ☐ /usr/bin/install

M cmd/cat.cpp => cmd/cat.cpp +2 -2
@@ 124,7 124,7 @@ int main(int argc, const char * const * argv) {


	bool was_empty{}, err{}, need_lineno = true;
#if __linux__
#if __linux__  // TODO: also in head.cpp
	bool should_alt = !squeeze && !numbering && !tx;
	if(struct stat sb; !fstat(1, &sb) && S_ISFIFO(sb.st_mode)) {
		// stdout is "our" pipe – bump the size as high as it can go to promote big splices


@@ 151,7 151,7 @@ int main(int argc, const char * const * argv) {
		}


#if __linux__
#if __linux__  // TODO? also in head.cpp
		// Only splice if no tx (obv), but also if we've never used stdio, so as not to interfere with buffers/not lose the flush errors/&c.
		// Realistically, I think this should cover 98% of spliceable cases and degrades gracefully.
		if(should_alt) {

M cmd/head.cpp => cmd/head.cpp +38 -0
@@ 9,12 9,15 @@
#include <vector>
#include <vore-file>
#include <vore-getopt>
#include <vore-int>
#include <vore-numeric>
#include <vore-optarg>
#include <vore-print>
#include <vore-size>
#include <vore-stdio>

using namespace std::literals;
using namespace vore::literals;


#define USAGE(self)                             \


@@ 90,6 93,22 @@ int main(int argc, const char * const * argv) {
	if(unit == unit_t::bytes)
		std::setvbuf(stdout, nullptr, _IONBF, 0);  // Cleanly intersperse fprintf(stdout) with write(1) without explicit fflush()es

#if __linux__  // TODO: also in cat.cpp
	if(struct stat sb; !fstat(1, &sb) && S_ISFIFO(sb.st_mode)) {
		// stdout is "our" pipe – bump the size as high as it can go to promote big splices
		// (even if we aren't splicing, this will, potentially drastically, lower the scheduler overhead)
		// TODO: rethink if we want to maybe bump input buffers too
		unsigned max = 1048576;  // fs/pipe.c default
		if(vore::file::fd<false> mps{"/proc/sys/fs/pipe-max-size", O_RDONLY | O_CLOEXEC}; mps != -1) {
			char buf[10 + 1]{};
			if(read(mps, buf, sizeof(buf) - 1) != -1)
				vore::parse_uint(buf, max);  // untouched if fails (but it won't)
		}
		if(static_cast<unsigned>(fcntl(1, F_GETPIPE_SZ)) < max)  // root can bump this past the limit: don't downgrade
			(void)fcntl(1, F_SETPIPE_SZ, max);
	}
#endif


	bool err{}, headered{};
	int err_e{};


@@ 166,6 185,25 @@ int main(int argc, const char * const * argv) {
				char buf[64 * 1024];
				if(!except) {
					auto left = count;

#if __linux__  // TODO? also in cat.cpp
					{
						ssize_t rd;
						while(left && (rd = splice(fd, NULL, 1, NULL, std::min(128_u64 * 1024_u64 * 1024_u64, left), SPLICE_F_MOVE | SPLICE_F_MORE)) > 0)
							left -= rd;
						if(rd != -1)  // All errors are better-served when detected by the read()/write() loop below
							continue;
					}

					{
						ssize_t rd;
						while(left && (rd = copy_file_range(fd, NULL, 1, NULL, std::min(128_u64 * 1024_u64 * 1024_u64, left), 0)) > 0)
							left -= rd;
						if(rd != -1)  // All errors are better-served when detected by the read()/write() loop below
							continue;
					}
#endif

					for(ssize_t rd; left && (rd = read_all(fd, buf, std::min(static_cast<std::uint64_t>(sizeof(buf)), left)));) {
						left -= rd;