2022-01-01 13:38:12 +00:00
|
|
|
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
|
2021-06-01 12:20:20 +00:00
|
|
|
|
2015-04-27 22:21:30 +00:00
|
|
|
class Store::Provider::File
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-05-06 12:56:12 +00:00
|
|
|
# write file to fs
|
2015-04-27 22:21:30 +00:00
|
|
|
def self.add(data, sha)
|
2016-02-29 11:58:21 +00:00
|
|
|
location = get_location(sha)
|
2018-09-26 08:06:48 +00:00
|
|
|
|
|
|
|
# write file to file system
|
2016-02-29 11:58:21 +00:00
|
|
|
if !File.exist?(location)
|
2021-07-09 16:38:23 +00:00
|
|
|
Rails.logger.debug { "storge write '#{location}' (600)" }
|
|
|
|
File.binwrite(location, data)
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2021-07-09 16:38:23 +00:00
|
|
|
File.chmod(0o600, location)
|
|
|
|
|
|
|
|
validate_file(sha)
|
|
|
|
rescue # .validate_file will raise an error if contents do not match SHA
|
|
|
|
delete(sha)
|
2015-05-06 12:56:12 +00:00
|
|
|
|
2021-07-09 16:38:23 +00:00
|
|
|
fail_count ||= 0
|
|
|
|
fail_count.zero? ? (fail_count += 1) && retry : raise
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-04-27 22:21:30 +00:00
|
|
|
# read file from fs
|
2015-05-06 12:56:12 +00:00
|
|
|
def self.get(sha)
|
2016-02-29 11:58:21 +00:00
|
|
|
location = get_location(sha)
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2021-07-09 16:38:23 +00:00
|
|
|
Rails.logger.debug { "read from fs #{location}" }
|
|
|
|
content = File.binread(location)
|
|
|
|
local_sha = Digest::SHA256.hexdigest(content)
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-04-27 22:21:30 +00:00
|
|
|
# check sha
|
2021-07-09 16:38:23 +00:00
|
|
|
raise "File corrupted: path #{location} does not match SHA digest (#{local_sha})" if local_sha != sha
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2015-04-27 22:21:30 +00:00
|
|
|
content
|
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2021-07-09 16:38:23 +00:00
|
|
|
class << self
|
|
|
|
alias validate_file get
|
|
|
|
end
|
|
|
|
|
2015-05-06 12:56:12 +00:00
|
|
|
# unlink file from fs
|
|
|
|
def self.delete(sha)
|
2016-02-29 11:58:21 +00:00
|
|
|
location = get_location(sha)
|
2021-07-09 16:38:23 +00:00
|
|
|
|
2016-02-29 11:58:21 +00:00
|
|
|
if File.exist?(location)
|
2020-01-28 00:44:03 +00:00
|
|
|
Rails.logger.info "storage remove '#{location}'"
|
2016-02-29 11:58:21 +00:00
|
|
|
File.delete(location)
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
2016-02-29 11:58:21 +00:00
|
|
|
|
2021-07-09 16:38:23 +00:00
|
|
|
# remove empty ancestor directories
|
|
|
|
storage_fs_path = Rails.root.join('storage/fs')
|
|
|
|
location.parent.ascend do |path|
|
|
|
|
break if !Dir.empty?(path)
|
|
|
|
break if path == storage_fs_path
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2021-07-09 16:38:23 +00:00
|
|
|
Dir.rmdir(path)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-05-06 12:56:12 +00:00
|
|
|
end
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-05-06 12:56:12 +00:00
|
|
|
# generate file location
|
2016-02-29 11:58:21 +00:00
|
|
|
def self.get_location(sha)
|
2021-07-09 16:38:23 +00:00
|
|
|
parts = sha.scan(%r{^(.{4})(.{4})(.{5})(.{5})(.{7})(.{7})(.*)}).first
|
|
|
|
Rails.root.join('storage/fs', *parts).tap { |path| FileUtils.mkdir_p(path.parent) }
|
2014-05-03 12:34:36 +00:00
|
|
|
end
|
2015-05-06 12:56:12 +00:00
|
|
|
|
2015-04-27 14:15:29 +00:00
|
|
|
end
|