class EL_FILE_SYSTEM_ROUTINES_I
OS file system routines
note
description: "OS file system routines"
author: "Finnian Reilly"
copyright: "Copyright (c) 2001-2017 Finnian Reilly"
contact: "finnian at eiffel hyphen loop dot com"
license: "MIT license (See: en.wikipedia.org/wiki/MIT_License)"
date: "2019-12-26 13:31:14 GMT (Thursday 26th December 2019)"
revision: "20"
deferred class
EL_FILE_SYSTEM_ROUTINES_I
inherit
EL_SHARED_DIRECTORY
rename
copy as copy_object
end
EL_MODULE_CHECKSUM
rename
copy as copy_object
end
feature {NONE} -- Initialization
make
do
create internal_info_file.make
end
feature -- Access
closed_none_plain_text: PLAIN_TEXT_FILE
do
create Result.make_with_name ("None.txt")
end
escaped_path (path: EL_PATH): ZSTRING
deferred
end
file_data (a_file_path: EL_FILE_PATH): MANAGED_POINTER
require
file_exists: a_file_path.exists
local
l_file: RAW_FILE
do
create l_file.make_open_read (a_file_path)
create Result.make (l_file.count)
l_file.read_to_managed_pointer (Result, 0, l_file.count)
l_file.close
end
line_one (a_file_path: EL_FILE_PATH): STRING
--
require
file_exists: a_file_path.exists
local
text_file: PLAIN_TEXT_FILE
do
create text_file.make_open_read (a_file_path)
create Result.make_empty
if not text_file.is_empty then
text_file.read_line
Result := text_file.last_string
end
text_file.close
end
plain_text (a_file_path: EL_FILE_PATH): STRING
--
require
file_exists: a_file_path.exists
local
text_file: PLAIN_TEXT_FILE; count: INTEGER; line: STRING
do
create text_file.make_open_read (a_file_path)
create Result.make (text_file.count)
if not text_file.is_empty then
from until text_file.end_of_file loop
text_file.read_line
line := text_file.last_string
count := count + line.count + 1
line.prune_all_trailing ('%R')
Result.append (line)
if count < text_file.count then
Result.append_character ('%N')
end
end
end
text_file.close
end
plain_text_bomless (a_file_path: EL_FILE_PATH): STRING
-- file text without byte-order mark
do
Result := plain_text (a_file_path)
if Result.starts_with ({UTF_CONVERTER}.Utf_8_bom_to_string_8) then
Result.remove_head (3)
end
end
feature -- File lists
files (a_dir_path: EL_DIR_PATH): like Directory.files
--
do
Result := Directory.named (a_dir_path).recursive_files
end
files_with_extension (a_dir_path: EL_DIR_PATH; extension: READABLE_STRING_GENERAL): like Directory.files
--
do
Result := Directory.named (a_dir_path).files_with_extension (extension)
end
recursive_files (a_dir_path: EL_DIR_PATH): like Directory.recursive_files
--
do
Result := Directory.named (a_dir_path).recursive_files
end
recursive_files_with_extension (a_dir_path: EL_DIR_PATH; extension: READABLE_STRING_GENERAL): like Directory.recursive_files
--
do
Result := Directory.named (a_dir_path).recursive_files_with_extension (extension)
end
feature -- Measurement
file_access_time (file_path: EL_FILE_PATH): INTEGER
do
Result := info_file (file_path).access_date
end
file_byte_count (a_file_path: EL_FILE_PATH): INTEGER
--
do
Result := info_file (a_file_path).count
end
file_checksum (a_file_path: EL_FILE_PATH): NATURAL
do
Result := Checksum.file_content (a_file_path)
end
file_megabyte_count (a_file_path: EL_FILE_PATH): DOUBLE
--
do
Result := file_byte_count (a_file_path) / 1000000
end
file_modification_time (file_path: EL_FILE_PATH): INTEGER
do
Result := info_file (file_path).date
end
feature -- File property change
add_permission (path: EL_FILE_PATH; who, what: STRING)
-- Add read, write, execute or setuid permission
-- for `who' ('u', 'g' or 'o') to `what'.
require
file_exists: path.exists
valid_who: valid_who (who)
valid_what: valid_what (what)
do
change_permission (path, who, what, agent {FILE}.add_permission)
end
remove_permission (path: EL_FILE_PATH; who, what: STRING)
-- remove read, write, execute or setuid permission
-- for `who' ('u', 'g' or 'o') to `what'.
require
file_exists: path.exists
valid_who: valid_who (who)
valid_what: valid_what (what)
do
change_permission (path, who, what, agent {FILE}.remove_permission)
end
set_file_modification_time (file_path: EL_FILE_PATH; date_time: INTEGER)
-- set modification time with date_time as secs since Unix epoch
deferred
ensure
modification_time_set: file_modification_time (file_path) = date_time
end
set_file_stamp (file_path: EL_FILE_PATH; date_time: INTEGER)
-- Stamp file with `time' (for both access and modification).
deferred
ensure
file_access_time_set: file_access_time (file_path) = date_time
modification_time_set: file_modification_time (file_path) = date_time
end
feature -- Basic operations
copy_file_contents (source_file: FILE; destination_path: EL_FILE_PATH)
require
exists_and_closed: source_file.is_closed and source_file.exists
local
destination_file: FILE; data: MANAGED_POINTER
byte_count: INTEGER
do
make_directory (destination_path.parent)
destination_file := source_file.twin
source_file.open_read
byte_count := source_file.count
-- Read
create data.make (byte_count)
source_file.read_to_managed_pointer (data, 0, byte_count)
notify_progress (source_file, False)
source_file.close
-- Write
destination_file.make_open_write (destination_path)
destination_file.put_managed_pointer (data, 0, byte_count)
notify_progress (destination_file, True)
destination_file.close
end
copy_file_contents_to_dir (source_file: FILE; destination_dir: EL_DIR_PATH)
local
destination_path: EL_FILE_PATH
do
destination_path := source_file.path
destination_path.set_parent_path (destination_dir)
copy_file_contents (source_file, destination_path)
end
delete_empty_branch (dir_path: EL_DIR_PATH)
--
require
path_exists: dir_path.exists
local
dir_steps: EL_PATH_STEPS
dir: like Directory.named
do
dir_steps := dir_path
from dir := Directory.named (dir_path) until dir_steps.is_empty or else not dir.is_empty loop
dir.delete
dir_steps.remove_tail (1)
dir.make_with_name (dir_steps.to_string_32)
end
end
delete_if_empty (dir_path: EL_DIR_PATH)
--
require
path_exists: dir_path.exists
local
dir: like Directory.named
do
dir := Directory.named (dir_path)
if dir.is_empty then
dir.delete
end
end
make_directory (a_dir_path: EL_DIR_PATH)
-- recursively create directory
local
dir_parent: EL_DIR_PATH
do
if not (a_dir_path.is_empty or else a_dir_path.exists) then
dir_parent := a_dir_path.parent
make_directory (dir_parent)
if dir_parent.exists_and_is_writeable then
Directory.named (a_dir_path).create_dir
end
end
end
remove_file, remove_directory, remove_path (a_path: EL_PATH)
--
require
exists: a_path.exists
do
info_file (a_path).delete
end
rename_file (a_file_path, new_file_path: EL_FILE_PATH)
-- change name of file to new_name. If preserve_extension is true, the original extension is preserved
require
file_exists: a_file_path.exists
do
info_file (a_file_path).rename_file (new_file_path)
end
write_plain_text (a_file_path: EL_FILE_PATH; text: STRING)
--
local
text_file: PLAIN_TEXT_FILE
do
create text_file.make_open_write (a_file_path)
text_file.put_string (text)
text_file.close
end
feature -- Status query
directory_exists, file_exists, path_exists (a_path: EL_PATH): BOOLEAN
do
Result := info_file (a_path).exists
end
has_content (a_file_path: EL_FILE_PATH): BOOLEAN
-- True if file not empty
local
l_file: RAW_FILE
do
create l_file.make_open_read (a_file_path)
Result := not l_file.is_empty
l_file.close
end
is_file_newer (path_1, path_2: EL_FILE_PATH): BOOLEAN
-- `True' if either A or B is true
-- A. `path_1' modification time is greater than `path_2' modification time
-- B. `path_2' does not exist
require
path_1_exists: path_1.exists
do
Result := not path_2.exists or else file_modification_time (path_1) > file_modification_time (path_2)
end
is_writeable_directory (dir_path: EL_DIR_PATH): BOOLEAN
do
Result := Directory.named (dir_path).is_writable
end
feature -- Contract Support
valid_what (what: STRING): BOOLEAN
do
Result := across what as c all ("rwxs").has (c.item) end
end
valid_who (who: STRING): BOOLEAN
do
Result := across who as c all ("uog").has (c.item) end
end
feature {NONE} -- Implementation
change_permission (path: EL_PATH; who, what: STRING; change: PROCEDURE [FILE, STRING, STRING])
-- Add/remove permissions to file or directory specified by `path' using `change' action
-- Add read, write, execute or setuid permission
-- for `who' ('u', 'g' or 'o') to `what'.
local
file: FILE; l_who: STRING
do
file := info_file (path)
create l_who.make (1)
across who as c loop
l_who.wipe_out
l_who.append_character (c.item)
change (file, l_who, what)
end
end
info_file (a_path: EL_PATH): EL_INFO_RAW_FILE
--
do
Result := internal_info_file
Result.set_path (a_path)
end
notify_progress (file: FILE; final: BOOLEAN)
do
if attached {EL_NOTIFYING_FILE} file as l_file then
if final then
l_file.notify_final
else
l_file.notify
end
end
end
feature {NONE} -- Internal attributes
internal_info_file: EL_INFO_RAW_FILE
end