neocities/models/site_file.rb
parkedhampster 25ca2a879b Increase filename limit to ext4 character limit
Purpose of this PR:
- ext4 filesystems permit a filename limit of 255 characters
- changes arbitrary 100-character limit to the above limit
- many site builders will create minified files with names over 100 characters in length
- adds the limit as part of the error return as well
  - this is hard-coded currently (I am not intimately familiar with ruby)
2024-03-26 11:21:50 -04:00

129 lines
3.7 KiB
Ruby

# frozen_string_literal: true
require 'sanitize'
class SiteFile < Sequel::Model
CLASSIFIER_LIMIT = 1_000_000
CLASSIFIER_WORD_LIMIT = 25
FILE_PATH_CHARACTER_LIMIT = 1200
FILE_NAME_CHARACTER_LIMIT = 255
unrestrict_primary_key
plugin :update_primary_key
many_to_one :site
def self.path_too_long?(filename)
return true if filename.length > FILE_PATH_CHARACTER_LIMIT
false
end
def self.name_too_long?(filename)
return true if filename.length > FILE_NAME_CHARACTER_LIMIT
false
end
def before_destroy
if is_directory
site.site_files_dataset.where(path: %r{^#{Regexp.quote path}/}, is_directory: true).all.each do |site_file|
site_file.destroy
rescue Sequel::NoExistingObject
end
site.site_files_dataset.where(path: %r{^#{Regexp.quote path}/}, is_directory: false).all.each do |site_file|
site_file.destroy
rescue Sequel::NoExistingObject
end
begin
FileUtils.remove_dir site.files_path(path)
rescue Errno::ENOENT
end
else
begin
FileUtils.rm site.files_path(path)
rescue Errno::ENOENT
end
ext = File.extname(path).gsub(/^./, '')
site.screenshots_delete(path) if ext.match Site::HTML_REGEX
site.thumbnails_delete(path) if ext.match Site::IMAGE_REGEX
end
super
end
def rename(new_path)
current_path = path
new_path = site.scrubbed_path new_path
return false, 'new path too long' if new_path.length > FILE_PATH_CHARACTER_LIMIT
return false, 'new filename too long' if File.basename(new_path).length > FILE_NAME_CHARACTER_LIMIT
return false, 'cannot rename to empty path' if new_path == ''
return false, 'cannot rename or move root index.html' if current_path == 'index.html'
if site.site_files.select { |sf| sf.path == new_path }.length > 0
return false, "#{is_directory ? 'directory' : 'file'} already exists"
end
if is_directory
return false, 'directory name cannot end with .htm or .html' if new_path.match(/\.html?$/)
else # a file
mime_type = Magic.guess_file_mime_type site.files_path(path)
extname = File.extname new_path
unless site.supporter? || site.class.valid_file_mime_type_and_ext?(mime_type, extname)
return false, 'unsupported file type'
end
end
begin
FileUtils.mv site.files_path(path), site.files_path(new_path)
site.delete_thumbnail_or_screenshot current_path
site.generate_thumbnail_or_screenshot new_path
rescue Errno::ENOENT => e
return false, 'destination directory does not exist' if e.message =~ /No such file or directory/i
raise e
rescue ArgumentError => e
raise e unless e.message =~ /same file/
end
DB.transaction do
self.path = new_path
save_changes
if is_directory
site_files_in_dir = site.site_files.select { |sf| sf.path =~ %r{^#{current_path}/} }
site_files_in_dir.each do |site_file|
original_site_file_path = site_file.path
site_file.path = site_file.path.gsub(%r{^#{current_path}/}, "#{new_path}\/")
site_file.save_changes
site.delete_thumbnail_or_screenshot original_site_file_path
site.generate_thumbnail_or_screenshot site_file.path
site.purge_cache site_file.path
site.purge_cache original_site_file_path
end
else
site.purge_cache new_path
site.purge_cache current_path
end
end
[true, nil]
end
def after_destroy
super
DB['update sites set space_used=space_used-? where id=?', size, site_id].first unless is_directory
site.purge_cache site.files_path(path)
SiteChangeFile.filter(site_id: site_id, filename: path).delete
end
end