about summary refs log tree commit homepage
path: root/lib/PublicInbox/Tmpfile.pm
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2019-09-12 08:34:20 +0000
committerEric Wong <e@80x24.org>2019-09-14 09:24:23 +0000
commite5631087d3862823d0d4854a8dfc1258f91cb115 (patch)
treecbb6b7bf2c117fc8550f20c12116582933351131 /lib/PublicInbox/Tmpfile.pm
parentbb20bc29a831d8f84613d48af729ffaede9d43e2 (diff)
downloadpublic-inbox-e5631087d3862823d0d4854a8dfc1258f91cb115.tar.gz
Although we always unlink temporary files, give them a
meaningful name so that we can we can still make sense
of the pre-unlink name when using lsof(8) or similar
tools on Linux.
Diffstat (limited to 'lib/PublicInbox/Tmpfile.pm')
-rw-r--r--lib/PublicInbox/Tmpfile.pm38
1 files changed, 38 insertions, 0 deletions
diff --git a/lib/PublicInbox/Tmpfile.pm b/lib/PublicInbox/Tmpfile.pm
new file mode 100644
index 00000000..7fda100e
--- /dev/null
+++ b/lib/PublicInbox/Tmpfile.pm
@@ -0,0 +1,38 @@
+# 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;