--- /dev/null
+#!/usr/bin/env ruby
+
+require 'getopt/long'
+include Getopt
+$opt = Long.getopts(
+ ["--debug", "-d", BOOLEAN],
+ ["--port", "-p", OPTIONAL],
+ ["--root-dir", "-r", OPTIONAL]
+ )
+default_opt = {
+ 'port' => 25107,
+ 'root-dir' => '/'
+}
+$opt = default_opt.merge $opt
+
+ARGV.reject! { |x| true } # prevent sinatra from trying to parse it
+require 'sinatra'
+
+# Configure sinatra server
+set :port, $opt['port'].to_i
+configure do
+ mime_type :binary, 'application/octet-stream'
+end
+
+def debuglog(loglevel, msg)
+ if $opt['debug'] or loglevel < 2
+ $stderr.puts "[keepd/#{$$} #{Time.now}] #{msg}"
+ end
+end
+
+# Configure backing store directories
+keepdirs = []
+rootdir = $opt['root-dir'].sub(/\/+$/, '')
+`mount`.split("\n").each do |mountline|
+ dev, on_txt, mountpoint, type_txt, fstype, opts = mountline.split
+ if on_txt == 'on' and type_txt == 'type'
+ debuglog 2, "dir #{mountpoint} is mounted"
+ if mountpoint[0..(rootdir.length)] == rootdir + '/'
+ debuglog 2, "dir #{mountpoint} is in #{rootdir}"
+ keepdir = "#{mountpoint.sub /\/$/, ''}/keep"
+ if File.exists? "#{keepdir}/."
+ keepdirs << { :root => "#{keepdir}", :readonly => false }
+ if opts.gsub(/[\(\)]/, '').split(',').index('ro')
+ keepdirs[-1][:readonly] = true
+ end
+ debuglog 1, "keepdir #{keepdirs[-1].inspect}"
+ end
+ end
+ end
+end
+
+get '/:locator' do |locator|
+ regs = locator.match /^([0-9a-f]{32,})/
+ if regs
+ hash = regs[1]
+ subdir = hash[0..2]
+ found = false
+ keepdirs.each do |keepdir|
+ backfile = "#{keepdir[:root]}/#{subdir}/#{hash}"
+ if File.exists? backfile
+ data = nil
+ File.open("#{keepdir[:root]}/lock", "a+") do |f|
+ if f.flock File::LOCK_EX
+ data = File.read backfile
+ end
+ end
+ if data
+ found = true
+ content_type :binary
+ body data
+ break
+ end
+ end
+ end
+ if not found
+ status 404
+ body 'not found'
+ end
+ else
+ pass
+ end
+end