Skip to content
API Documentation
BastionGuard™
TeeJee.FileSystem.vala
Go to the documentation of this file.
1
2/*
3 * TeeJee.FileSystem.vala
4 *
5 * Copyright 2012-2018 Tony George <teejeetech@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20 * MA 02110-1301, USA.
21 *
22 *
23 */
24
26
27 /* Convenience functions for handling files and directories */
28
29 using TeeJee.Logging;
31 using TeeJee.Misc;
32
33
34 public const int64 KB = 1000;
35 public const int64 MB = 1000 * KB;
36 public const int64 GB = 1000 * MB;
37 public const int64 TB = 1000 * GB;
38 public const int64 KiB = 1024;
39 public const int64 MiB = 1024 * KiB;
40 public const int64 GiB = 1024 * MiB;
41 public const int64 TiB = 1024 * GiB;
42
43 // path helpers ----------------------------
44
45 public string file_parent(string file_path){
46 return File.new_for_path(file_path).get_parent().get_path();
47 }
48
49 public string file_basename(string file_path){
50 return File.new_for_path(file_path).get_basename();
51 }
52
53 public string path_combine(string path1, string path2){
54 return GLib.Path.build_path("/", path1, path2);
55 }
56
57 public string remove_trailing_slash(string path){
58 if (path.has_suffix("/")){
59 return path[0:path.length - 1];
60 }
61 else{
62 return path;
63 }
64 }
65
66 // file helpers -----------------------------
67
68 public bool file_exists (string file_path){
69 /* Check if file exists */
70 return (FileUtils.test(file_path, GLib.FileTest.EXISTS)
71 && !FileUtils.test(file_path, GLib.FileTest.IS_DIR));
72 }
73
74 public bool file_delete(string file_path){
75
76 /* Check and delete file */
77
78 try {
79 var file = File.new_for_path (file_path);
80 if (file.query_exists ()) {
81 file.delete ();
82 }
83 return true;
84 } catch (Error e) {
85 log_error (e.message);
86 log_error(_("Failed to delete file") + ": %s".printf(file_path));
87 return false;
88 }
89 }
90
91 public int64? file_line_count (string file_path){
92 /* Count number of lines in text file returns null on error */
93
94 try {
95 long line_nums = 0;
96 char symbol;
97
98 File file = File.new_for_path(file_path);
99 FileInputStream inStream = file.read();
100 BufferedInputStream bis = new BufferedInputStream.sized(inStream, (size_t) (1 * MiB));
101 while((symbol = (char) bis.read_byte()) != -1) {
102 if(symbol == '\n') {
103 line_nums ++;
104 }
105 }
106 bis.close();
107 return line_nums;
108 } catch(Error e) {
109 log_error (e.message);
110 log_error(_("Failed to read file") + ": %s".printf(file_path));
111 }
112 return null;
113 }
114
115 public string? file_read (string file_path){
116
117 /* Reads text from file */
118
119 string txt;
120 size_t size;
121
122 try{
123 GLib.FileUtils.get_contents (file_path, out txt, out size);
124 return txt;
125 }
126 catch (Error e){
127 log_error (e.message);
128 log_error(_("Failed to read file") + ": %s".printf(file_path));
129 }
130
131 return null;
132 }
133
134 // read a file with a delimiter into an array
135 // this function is not very optimized so avoid using it for large files
136 public string[]? file_read_array(string file_path, char delimiter = '\n'){
137 try{
138 uint8[] content;
139 GLib.FileUtils.get_data(file_path, out content);
140
141 // count elements
142 string[] parsed = {""};
143 int element = 0;
144 foreach (uint8 byte in content) {
145 // create a new element
146 if(byte == delimiter) {
147 element ++;
148 parsed += "";
149 continue;
150 }
151
152 parsed[element] += ((char) byte).to_string();
153 }
154
155 return parsed;
156 }
157 catch (Error e){
158 log_error (e.message);
159 log_error(_("Failed to read file") + ": %s".printf(file_path));
160 }
161
162 return null;
163 }
164
165 public bool file_write (string file_path, string contents){
166
167 /* Write text to file */
168
169 try{
170
171 dir_create(file_parent(file_path));
172
173 var file = File.new_for_path (file_path);
174 if (file.query_exists ()) {
175 file.delete ();
176 }
177
178 var file_stream = file.create (FileCreateFlags.NONE);
179 var data_stream = new DataOutputStream (file_stream);
180 data_stream.put_string (contents);
181 data_stream.close();
182 return true;
183 }
184 catch (Error e) {
185 log_error (e.message);
186 log_error(_("Failed to write file") + ": %s".printf(file_path));
187 return false;
188 }
189 }
190
191 public bool file_copy (string src_file, string dest_file){
192 try{
193 var file_src = File.new_for_path (src_file);
194 if (file_src.query_exists()) {
195 var file_dest = File.new_for_path (dest_file);
196 file_src.copy(file_dest,FileCopyFlags.OVERWRITE,null,null);
197 return true;
198 }
199 }
200 catch(Error e){
201 log_error (e.message);
202 log_error(_("Failed to copy file") + ": '%s', '%s'".printf(src_file, dest_file));
203 }
204
205 return false;
206 }
207
208 public void file_move (string src_file, string dest_file){
209 try{
210 var file_src = File.new_for_path (src_file);
211 if (file_src.query_exists()) {
212 var file_dest = File.new_for_path (dest_file);
213 file_src.move(file_dest,FileCopyFlags.OVERWRITE,null,null);
214 }
215 else{
216 log_error(_("File not found") + ": '%s'".printf(src_file));
217 }
218 }
219 catch(Error e){
220 log_error (e.message);
221 log_error(_("Failed to move file") + ": '%s', '%s'".printf(src_file, dest_file));
222 }
223 }
224
225 public bool file_is_symlink(string file_path){
226
227 try {
228 var file = File.new_for_path (file_path);
229
230 if (file.query_exists()) {
231
232 var info = file.query_info("%s".printf(FileAttribute.STANDARD_TYPE), FileQueryInfoFlags.NOFOLLOW_SYMLINKS); // don't follow symlinks
233
234 var file_type = info.get_file_type();
235
236 return (file_type == FileType.SYMBOLIC_LINK);
237 }
238 }
239 catch (Error e) {
240 log_error (e.message);
241 }
242
243 return false;
244 }
245
246 public bool file_gzip (string src_file){
247
248 string dst_file = src_file + ".gz";
249 file_delete(dst_file);
250
251 string cmd = "gzip '%s'".printf(escape_single_quote(src_file));
252 string std_out, std_err;
253 exec_sync(cmd, out std_out, out std_err);
254
255 return file_exists(dst_file);
256 }
257
258 public string file_resolve_executable_path(string file_path){
259
260 if (file_path.has_prefix("/")){
261 return file_path;
262 }
263 else if (!file_path.contains("/")){
264 return GLib.Environment.find_program_in_path(file_path);
265 }
266 else if (file_path.has_prefix("./")){
267 return path_combine(GLib.Environment.get_current_dir(), file_path[2:file_path.length]);
268 }
269 else if (file_path.has_prefix("../")){
270 return path_combine(file_parent(GLib.Environment.get_current_dir()), file_path[3:file_path.length]);
271 }
272 else {
273 return path_combine(GLib.Environment.get_current_dir(), file_path);
274 }
275 }
276
277 // file info -----------------
278
279 public string file_get_symlink_target(string file_path){
280 try{
281 FileInfo info;
282 File file = File.parse_name (file_path);
283 if (file.query_exists()) {
284 info = file.query_info("%s".printf(FileAttribute.STANDARD_SYMLINK_TARGET), 0);
285 return info.get_symlink_target();
286 }
287 }
288 catch (Error e) {
289 log_error (e.message);
290 }
291
292 return "";
293 }
294
295 // directory helpers ----------------------
296
297 public bool dir_exists (string dir_path){
298 /* Check if directory exists */
299 return ( FileUtils.test(dir_path, GLib.FileTest.EXISTS) && FileUtils.test(dir_path, GLib.FileTest.IS_DIR));
300 }
301
302 public bool dir_create (string dir_path, bool show_message = false){
303
304 /* Creates a directory along with parents */
305
306 try{
307 var dir = File.parse_name (dir_path);
308
309 if (dir.query_exists () == false) {
310
311 bool ok = dir.make_directory_with_parents (null);
312
313 if (show_message){
314 if (ok){
315 log_msg(_("Created directory") + ": %s".printf(dir_path));
316 }
317 else{
318 log_error(_("Failed to create directory") + ": %s".printf(dir_path));
319 }
320 }
321 }
322
323 return true;
324 }
325 catch (Error e) {
326 log_error (e.message);
327 log_error(_("Failed to create directory") + ": %s".printf(dir_path));
328 return false;
329 }
330 }
331
332 // delete an empty directory
333 public static bool dir_empty_delete(string path) {
334 File dirf = File.new_for_path(path);
335 try {
336 if (dirf.query_file_type(FileQueryInfoFlags.NONE) == FileType.DIRECTORY) {
337 return dirf.delete(); // only succeeds, if the dir is empty
338 }
339 } catch(Error ioe) {
340 if(ioe.matches(IOError.quark(), IOError.NOT_FOUND)) {
341 // directory does not exist
342 return true;
343 }
344 }
345 return false;
346 }
347
348 public static bool dir_delete_recursive(string dir) {
349 File f = File.new_for_path(dir);
350 if(f.query_exists()) {
351 try {
352 FileEnumerator enumerator = f.enumerate_children(FileAttribute.STANDARD_NAME, FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
353 FileInfo info;
354 while ((info = enumerator.next_file()) != null) {
355 string name = info.get_name();
356 if(info.get_file_type() == FileType.DIRECTORY) {
357
358 // ignore . and ..
359 if(name == "." || name == "..") {
360 continue;
361 }
362
363 if(!dir_delete_recursive(dir + "/" + name)) {
364 return false;
365 }
366 } else {
367 File file = File.new_for_path(dir + "/" + name);
368 file.delete();
369 }
370 }
371 f.delete();
372 } catch(Error err) {
373 log_error("Can not enumerate folder %s".printf(dir));
374 return false;
375 }
376 }
377 return true;
378 }
379
380 public static bool dir_delete(string dir_path, bool show_message = false) {
381
382 /* Recursively deletes directory along with contents */
383
384 bool status = dir_delete_recursive(dir_path);
385
386 if (show_message){
387 if (status){
388 log_msg(_("Deleted directory") + ": %s".printf(dir_path));
389 }
390 else{
391 log_error(_("Failed to delete directory") + ": %s".printf(dir_path));
392 }
393 }
394
395 return status;
396 }
397
398 public bool dir_is_empty (string dir_path){
399
400 /* Check if directory is empty */
401
402 try{
403 bool is_empty = true;
404 var dir = File.parse_name (dir_path);
405 if (dir.query_exists()) {
406 FileInfo info;
407 var enu = dir.enumerate_children (FileAttribute.STANDARD_NAME, 0);
408 while ((info = enu.next_file()) != null) {
409 is_empty = false;
410 break;
411 }
412 }
413 return is_empty;
414 }
415 catch (Error e) {
416 log_error (e.message);
417 return false;
418 }
419 }
420
421 public Gee.ArrayList<string> dir_list_names(string path){
422
423 var list = new Gee.ArrayList<string>();
424
425 try
426 {
427 File f_home = File.new_for_path (path);
428 FileEnumerator enumerator = f_home.enumerate_children ("%s".printf(FileAttribute.STANDARD_NAME), 0);
429 FileInfo file;
430 while ((file = enumerator.next_file ()) != null) {
431 string name = file.get_name();
432 list.add(name);
433 }
434 }
435 catch (Error e) {
436 log_error (e.message);
437 }
438
439 //sort the list
440 CompareDataFunc<string> entry_compare = (a, b) => {
441 return strcmp(a,b);
442 };
443 list.sort((owned) entry_compare);
444
445 return list;
446 }
447
448 // misc --------------------
449
450 public string format_file_size (
451 uint64 size, bool binary_units = false,
452 string unit = "", bool show_units = true, int decimals = 1){
453
454 uint64 unit_k = binary_units ? 1024 : 1000;
455 uint64 unit_m = binary_units ? 1024 * unit_k : 1000 * unit_k;
456 uint64 unit_g = binary_units ? 1024 * unit_m : 1000 * unit_m;
457 uint64 unit_t = binary_units ? 1024 * unit_g : 1000 * unit_g;
458
459 //log_debug("size: %'lld".printf(size));
460
461 string txt = "";
462
463 if ((size > unit_t) && ((unit.length == 0) || (unit == "t"))){
464 txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_t));
465 if (show_units){
466 txt += " %sB".printf(binary_units ? "Ti" : "T");
467 }
468 }
469 else if ((size > unit_g) && ((unit.length == 0) || (unit == "g"))){
470 txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_g));
471 if (show_units){
472 txt += " %sB".printf(binary_units ? "Gi" : "G");
473 }
474 }
475 else if ((size > unit_m) && ((unit.length == 0) || (unit == "m"))){
476 txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_m));
477 if (show_units){
478 txt += " %sB".printf(binary_units ? "Mi" : "M");
479 }
480 }
481 else if ((size > unit_k) && ((unit.length == 0) || (unit == "k"))){
482 txt += ("%%'0.%df".printf(decimals)).printf(size / (1.0 * unit_k));
483 if (show_units){
484 txt += " %sB".printf(binary_units ? "Ki" : "K");
485 }
486 }
487 else{
488 txt += "%'0lu".printf(size);
489 if (show_units){
490 txt += " B";
491 }
492 }
493
494 //log_debug("converted: %s".printf(txt));
495
496 return txt;
497 }
498
499 public string escape_single_quote(string file_path){
500
501 return file_path.replace("'","'\\''");
502 }
503}
#define _(s)
Gee.ArrayList< string > dir_list_names(string path)
bool file_exists(string file_path)
string escape_single_quote(string file_path)
string remove_trailing_slash(string path)
string file_get_symlink_target(string file_path)
string? file_read(string file_path)
string file_basename(string file_path)
string file_parent(string file_path)
string?[] file_read_array(string file_path, char delimiter='\n')
bool file_write(string file_path, string contents)
string file_resolve_executable_path(string file_path)
bool file_is_symlink(string file_path)
string path_combine(string path1, string path2)
bool file_copy(string src_file, string dest_file)
string format_file_size(uint64 size, bool binary_units=false, string unit="", bool show_units=true, int decimals=1)
bool file_delete(string file_path)
static bool dir_delete(string dir_path, bool show_message=false)
int64? file_line_count(string file_path)
bool dir_is_empty(string dir_path)
bool dir_create(string dir_path, bool show_message=false)
static bool dir_empty_delete(string path)
bool dir_exists(string dir_path)
void file_move(string src_file, string dest_file)
static bool dir_delete_recursive(string dir)
bool file_gzip(string src_file)
void log_error(string message, bool highlight=false, bool is_warning=false)
void log_msg(string message, bool highlight=false)
int exec_sync(string cmd, out string? std_out=null, out string? std_err=null)