mirror of
https://github.com/hkalexling/Mango.git
synced 2025-08-02 10:55:30 -04:00
53 lines
1.7 KiB
Crystal
53 lines
1.7 KiB
Crystal
require "./util"
|
|
|
|
class File
|
|
abstract struct Info
|
|
def inode
|
|
@stat.st_ino
|
|
end
|
|
end
|
|
|
|
# Returns the signature of the file at filename.
|
|
# When it is not a supported file, returns 0. Otherwise, calculate the
|
|
# signature by combining its inode value, file size and mtime. This
|
|
# ensures that moving (unless to another device) and renaming the file
|
|
# preserves the signature, while copying or editing the file changes it.
|
|
def self.signature(filename) : UInt64
|
|
return 0u64 unless is_supported_file filename
|
|
info = File.info filename
|
|
signatures = [
|
|
info.inode,
|
|
File.size(filename),
|
|
info.modification_time.to_unix,
|
|
]
|
|
Digest::CRC32.checksum(signatures.sort.join).to_u64
|
|
end
|
|
end
|
|
|
|
class Dir
|
|
# Returns the signature of the directory at dirname.
|
|
# The signature is calculated by combining its mtime and the signatures of
|
|
# all directories and files in it. This ensures that moving (unless to
|
|
# another device) and renaming the directory preserves the signature,
|
|
# while copying or editing its content changes it.
|
|
def self.signature(dirname) : UInt64
|
|
signatures = [] of (UInt64 | Int64)
|
|
signatures << File.info(dirname).modification_time.to_unix
|
|
self.open dirname do |dir|
|
|
dir.entries.each do |fn|
|
|
next if fn.starts_with? "."
|
|
path = File.join dirname, fn
|
|
if File.directory? path
|
|
signatures << Dir.signature path
|
|
else
|
|
_sig = File.signature path
|
|
# Only add its signature value to `signatures` when it is a
|
|
# supported file
|
|
signatures << _sig if _sig > 0
|
|
end
|
|
end
|
|
end
|
|
Digest::CRC32.checksum(signatures.sort.join).to_u64
|
|
end
|
|
end
|