lib/PublicInbox/SpawnPP.pm
lib/PublicInbox/Syscall.pm
lib/PublicInbox/TLS.pm
+lib/PublicInbox/Tmpfile.pm
lib/PublicInbox/Unsubscribe.pm
lib/PublicInbox/UserContent.pm
lib/PublicInbox/V2Writable.pm
use POSIX qw(dup2);
require IO::Handle;
use PublicInbox::Spawn qw(spawn popen_rd);
+use PublicInbox::Tmpfile;
use base qw(Exporter);
our @EXPORT_OK = qw(git_unquote git_quote);
qw(-c core.abbrev=40 cat-file), $batch);
my $redir = { 0 => fileno($out_r), 1 => fileno($in_w) };
if ($err) {
- open(my $fh, '+>', undef) or fail($self, "open.err failed: $!");
+ my $id = "git.$self->{git_dir}$batch.err";
+ my $fh = tmpfile($id) or fail($self, "tmpfile($id): $!");
$self->{$err} = $fh;
$redir->{2} = fileno($fh);
}
use HTTP::Status qw(status_message);
use Plack::Util;
use PublicInbox::Qspawn;
+use PublicInbox::Tmpfile;
# 32 is same as the git-daemon connection limit
my $default_limiter = PublicInbox::Qspawn::Limiter->new(32);
if (defined $fd && $fd >= 0) {
return { 0 => $fd };
}
- open(my $in, '+>', undef);
+ my $id = "git-http.input.$env->{REMOTE_HOST}:$env->{REMOTE_PORT}";
+ my $in = tmpfile($id);
unless (defined $in) {
err($env, "could not open temporary file: $!");
return;
require PublicInbox::EvCleanup;
use PublicInbox::DS qw(msg_more);
use PublicInbox::Syscall qw(EPOLLIN EPOLLONESHOT);
+use PublicInbox::Tmpfile;
use constant {
CHUNK_START => -1, # [a-f0-9]+\r\n
CHUNK_END => -2, # \r\n
}
sub input_tmpfile ($) {
- open($_[0], '+>', undef);
- $_[0]->autoflush(1);
+ my $input = tmpfile('http.input', $_[0]->{sock}) or return;
+ $input->autoflush(1);
+ $input;
}
sub input_prepare {
quit($self, 413);
return;
}
- input_tmpfile($input);
+ $input = input_tmpfile($self);
} elsif (env_chunked($env)) {
$len = CHUNK_START;
- input_tmpfile($input);
+ $input = input_tmpfile($self);
} else {
$input = $null_io;
}
use PublicInbox::Git qw(git_unquote git_quote);
use PublicInbox::MsgIter qw(msg_iter msg_part_text);
use PublicInbox::Qspawn;
+use PublicInbox::Tmpfile;
use URI::Escape qw(uri_escape_utf8);
# POSIX requires _POSIX_ARG_MAX >= 4096, and xargs is required to
my $path_a = $di->{path_a} or die "BUG: path_a missing for $oid_full";
my $mode_a = $di->{mode_a} || extract_old_mode($di);
- open my $in, '+>', undef or die "open: $!";
+ my $in = tmpfile("update-index.$oid_full") or die "tmpfile: $!";
print $in "$mode_a $oid_full\t$path_a\0" or die "print: $!";
$in->flush or die "flush: $!";
sysseek($in, 0, 0) or die "seek: $!";
--- /dev/null
+# Copyright (C) 2019 all contributors <meta@public-inbox.org>
+# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
+package PublicInbox::Tmpfile;
+use strict;
+use warnings;
+use base qw(Exporter);
+our @EXPORT = qw(tmpfile);
+use Fcntl qw(:DEFAULT);
+use Errno qw(EEXIST);
+require File::Spec;
+
+# use tmpfile instead of open(..., '+>', undef) so we can get an
+# unlinked filename which makes sense when viewed with lsof
+# (at least on Linux)
+# TODO: O_APPEND support (this is the reason I'm not using File::Temp)
+# And if we ever stop caring to have debuggable filenames, O_TMPFILE :)
+sub tmpfile ($;$) {
+ my ($id, $sock) = @_;
+ if (defined $sock) {
+ # add the socket inode number so we can figure out which
+ # socket it belongs to
+ my @st = stat($sock);
+ $id .= '-ino:'.$st[1];
+ }
+ $id =~ tr!/!^!;
+
+ my $fl = O_RDWR | O_CREAT | O_EXCL;
+ do {
+ my $fn = File::Spec->tmpdir . "/$id-".time.'-'.rand;
+ if (sysopen(my $fh, $fn, $fl, 0600)) { # likely
+ unlink($fn) or die "unlink($fn): $!"; # FS broken
+ return $fh; # success
+ }
+ } while ($! == EEXIST);
+ undef # EMFILE/ENFILE/ENOSPC/ENOMEM
+}
+
+1;
use PublicInbox::SolverGit;
use PublicInbox::WwwStream;
use PublicInbox::Linkify;
+use PublicInbox::Tmpfile;
use PublicInbox::Hval qw(ascii_html to_filename);
my $hl = eval {
require PublicInbox::HlMod;
$hints->{$to} = $v;
}
- open my $log, '+>', undef or die "open: $!";
+ my $log = tmpfile("solve.$oid_b");
my $solver = PublicInbox::SolverGit->new($ctx->{-inbox}, sub {
solve_result($ctx, $_[0], $log, $hints, $fn);
});