Use inode number

This commit is contained in:
Alex Ling 2021-01-27 03:19:58 +00:00
parent 2b079c652d
commit bf18a14016

View File

@ -6,31 +6,30 @@ class File
end end
# Returns the signature of the file at filename. # Returns the signature of the file at filename.
# When it is not a supported file, returns 0. Otherwise, calculate the # When it is not a supported file, returns 0. Otherwise, uses the inode
# signature by combining its inode value, file size and mtime. This # number as its signature. On most file systems, the inode number is
# ensures that moving (unless to another device) and renaming the file # preserved even when the file is renamed, moved or edited.
# preserves the signature, while copying or editing the file changes it. # Some cases that would cause the inode number to change:
# - Reboot/remount on some file systems
# - Replaced with a copied file
# - Moved to a different device
# Since we are also using the relative paths to match ids, we won't lose
# information as long as the above changes do not happen together with
# a file/folder rename, with no library scan in between.
def self.signature(filename) : UInt64 def self.signature(filename) : UInt64
return 0u64 unless %w(.zip .rar .cbz .cbr).includes? File.extname filename if %w(.zip .rar .cbz .cbr).includes? File.extname filename
info = File.info filename File.info(filename).inode
signatures = [ else
info.inode, 0u64
File.size(filename), end
info.modification_time.to_unix,
]
Digest::CRC32.checksum(signatures.sort.join).to_u64
end end
end end
class Dir class Dir
# Returns the signature of the directory at dirname. # Returns the signature of the directory at dirname. See the comments for
# The signature is calculated by combining its mtime and the signatures of # `File.signature` for more information.
# 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 def self.signature(dirname) : UInt64
signatures = [] of (UInt64 | Int64) signatures = [File.info(dirname).inode]
signatures << File.info(dirname).modification_time.to_unix
self.open dirname do |dir| self.open dirname do |dir|
dir.entries.each do |fn| dir.entries.each do |fn|
next if fn.starts_with? "." next if fn.starts_with? "."