#! /usr/bin/ruby module RbLocate class Indexer attr_accessor :mutex def initialize(path) puts "Setting up indexer for #{path}" @path = path @backend = Backend::SqLite.new end def walk require "find" Find.find(@path) do |file| mutex.synchronize do puts "Adding #{file}" @backend.put(file) end end end end class IndexThreadFactory def initialize(path) @backend = Backend::SqLite.new @threads = [] @path = path end def populate_threads require "thread" mutex = Mutex.new Dir.open(@path).each do |item| item = @path+item if File.ftype(item) == "directory" and not item.match(/^\/\.+/) @threads.push( Thread.new { indexer = Indexer.new(item) indexer.mutex = mutex indexer.walk puts "Thread for #{item} ready" }) else puts "File: #{item}" @backend.put(item) unless item.match(/^\/\.+$/) end end end def wait @threads.each do |t| t.join end end end class Search def initialize @backend = Backend::SqLite.new end def search(string) @backend.search(string) do |file| puts file end end end module Backend module Generic def self.is_uid?(path, uid) return true if uid == 0 File::Stat.new(path).uid == uid end def self.is_gid?(path, gid) return true if gid == 0 File::Stat.new(path).gid == gid end end class SqLite def initialize require "sqlite3" @database = SQLite3::Database.new("files.db") end def put(path) retry_counter = 0 begin @database.execute("INSERT INTO files VALUES (NULL, ?)", path) rescue SQLite3::SQLException => error puts "Error: #{error.to_s}" rescue SQLite3::BusyException => error if retry_counter <= 1000 puts "Database is locked. Waiting ..." sleep 0.1 retry else puts "Tried too often. Giving up" end end end def search(string, &block) string = quote string begin @database.execute("SELECT id, path FROM files WHERE path LIKE '%#{string}%'") do |id,path| unless File.exists?(path) delete_by_id id next end yield path if Generic.is_uid?(path, Process.euid) and Generic.is_gid?(path, Process.gid) end rescue SQLite3::BusyException => error retry end end def delete_by_id(id) @database.execute("DELETE FROM files WHERE id = ?", id) end def quote(string) string.gsub(/'/, "''") end end end end case ARGV[0] when "--search" search = RbLocate::Search.new search.search(ARGV[1]) when "--index" factory = RbLocate::IndexThreadFactory.new(ARGV[1]) factory.populate_threads factory.wait else puts "Invalid option" end