2021-06-01 12:20:20 +00:00
|
|
|
# Copyright (C) 2012-2021 Zammad Foundation, http://zammad-foundation.org/
|
|
|
|
|
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)
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-05-06 12:56:12 +00:00
|
|
|
# install file
|
2016-02-29 11:58:21 +00:00
|
|
|
location = get_location(sha)
|
2015-05-06 12:56:12 +00:00
|
|
|
permission = '600'
|
2018-09-26 08:06:48 +00:00
|
|
|
|
|
|
|
# verify if file already is in file system and if it's not corrupt
|
|
|
|
if File.exist?(location)
|
|
|
|
begin
|
|
|
|
get(sha)
|
|
|
|
rescue
|
|
|
|
delete(sha)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# write file to file system
|
2016-02-29 11:58:21 +00:00
|
|
|
if !File.exist?(location)
|
2020-01-28 00:44:03 +00:00
|
|
|
Rails.logger.debug { "storage write '#{location}' (#{permission})" }
|
2016-02-29 11:58:21 +00:00
|
|
|
file = File.new(location, 'wb')
|
2016-02-02 12:50:49 +00:00
|
|
|
file.write(data)
|
2015-05-06 12:56:12 +00:00
|
|
|
file.close
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
2016-02-29 11:58:21 +00:00
|
|
|
File.chmod(permission.to_i(8), location)
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-05-06 12:56:12 +00:00
|
|
|
# check sha
|
2016-02-02 12:50:49 +00:00
|
|
|
local_sha = Digest::SHA256.hexdigest(get(sha))
|
2015-05-06 12:56:12 +00:00
|
|
|
if sha != local_sha
|
2020-03-12 08:23:19 +00:00
|
|
|
raise "Corrupt file in fs #{location}, sha should be #{sha} but is #{local_sha}"
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
2015-05-06 12:56:12 +00:00
|
|
|
|
|
|
|
true
|
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-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { "read from fs #{location}" }
|
2016-02-29 11:58:21 +00:00
|
|
|
if !File.exist?(location)
|
2020-03-12 08:23:19 +00:00
|
|
|
raise "No such file #{location}"
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-02-29 11:58:21 +00:00
|
|
|
data = File.open(location, 'rb')
|
2015-04-27 22:21:30 +00:00
|
|
|
content = data.read
|
2015-04-27 21:44:41 +00:00
|
|
|
|
2015-04-27 22:21:30 +00:00
|
|
|
# check sha
|
2016-02-02 12:50:49 +00:00
|
|
|
local_sha = Digest::SHA256.hexdigest(content)
|
2015-04-27 22:21:30 +00:00
|
|
|
if local_sha != sha
|
2020-03-12 08:23:19 +00:00
|
|
|
raise "Corrupt file in fs #{location}, sha should be #{sha} but is #{local_sha}"
|
2015-04-27 22:21:30 +00:00
|
|
|
end
|
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
|
|
|
|
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)
|
|
|
|
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
|
|
|
|
|
|
|
# check if dir need to be removed
|
|
|
|
locations = location.split('/')
|
2017-10-01 12:25:52 +00:00
|
|
|
(0..locations.count).reverse_each do |count|
|
2016-02-29 11:58:21 +00:00
|
|
|
local_location = locations[0, count].join('/')
|
2017-11-23 08:09:44 +00:00
|
|
|
break if local_location.match?(%r{storage/fs/{0,4}$})
|
|
|
|
break if Dir["#{local_location}/*"].present?
|
2019-06-27 18:26:28 +00:00
|
|
|
next if !Dir.exist?(local_location)
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-02-29 11:58:21 +00:00
|
|
|
FileUtils.rmdir(local_location)
|
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)
|
2015-04-27 22:21:30 +00:00
|
|
|
|
2015-05-06 12:56:12 +00:00
|
|
|
# generate directory
|
2020-02-18 19:51:31 +00:00
|
|
|
base = Rails.root.join('storage/fs').to_s
|
2017-11-23 08:09:44 +00:00
|
|
|
parts = []
|
2016-02-29 11:58:21 +00:00
|
|
|
length1 = 4
|
|
|
|
length2 = 5
|
|
|
|
length3 = 7
|
|
|
|
last_position = 0
|
2020-09-30 09:07:01 +00:00
|
|
|
|
|
|
|
# rubocop:disable Style/CombinableLoops
|
2017-10-01 12:25:52 +00:00
|
|
|
(0..1).each do |_count|
|
2016-02-29 11:58:21 +00:00
|
|
|
end_position = last_position + length1
|
|
|
|
parts.push sha[last_position, length1]
|
|
|
|
last_position = end_position
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
|
|
|
(0..1).each do |_count|
|
2016-02-29 11:58:21 +00:00
|
|
|
end_position = last_position + length2
|
|
|
|
parts.push sha[last_position, length2]
|
|
|
|
last_position = end_position
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
|
|
|
(0..1).each do |_count|
|
2016-02-29 11:58:21 +00:00
|
|
|
end_position = last_position + length3
|
|
|
|
parts.push sha[last_position, length3]
|
|
|
|
last_position = end_position
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2020-09-30 09:07:01 +00:00
|
|
|
# rubocop:enable Style/CombinableLoops
|
2019-09-02 11:52:11 +00:00
|
|
|
|
2020-09-30 09:07:01 +00:00
|
|
|
path = "#{parts[ 0..6 ].join('/')}/"
|
2016-02-29 11:58:21 +00:00
|
|
|
file = sha[last_position, sha.length]
|
2015-05-06 12:56:12 +00:00
|
|
|
location = "#{base}/#{path}"
|
|
|
|
|
|
|
|
# create directory if not exists
|
2016-02-02 12:50:49 +00:00
|
|
|
if !File.exist?(location)
|
|
|
|
FileUtils.mkdir_p(location)
|
2015-05-06 12:56:12 +00:00
|
|
|
end
|
2019-06-28 11:38:49 +00:00
|
|
|
full_path = location + file
|
2016-02-29 11:58:21 +00:00
|
|
|
full_path.gsub('//', '/')
|
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
|