1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 
22 #include "../my_config.h"
23 
24 extern "C"
25 {
26 } // end extern "C"
27 
28 #include "cat_tools.hpp"
29 #include "cat_all_entrees.hpp"
30 #include "deci.hpp"
31 
32 using namespace std;
33 
34 namespace libdar
35 {
36 
37 	// local sub routines
38 
39     static string local_fsa_fam_to_string(const cat_inode & ref);
40 
41 	// exported routine implementation
42 
local_perm(const cat_inode & ref,bool hard)43     string local_perm(const cat_inode &ref, bool hard)
44     {
45 	saved_status st;
46 	char type;
47 
48 	U_32 perm = ref.get_perm();
49 	if(!extract_base_and_status(ref.signature(), (unsigned char &)type, st))
50 	    throw SRC_BUG;
51 
52 	return tools_get_permission_string(type, perm, hard);
53     }
54 
local_uid(const cat_inode & ref)55     string local_uid(const cat_inode & ref)
56     {
57 	return tools_name_of_uid(ref.get_uid());
58     }
59 
local_gid(const cat_inode & ref)60     string local_gid(const cat_inode & ref)
61     {
62 	return tools_name_of_gid(ref.get_gid());
63     }
64 
local_size(const cat_inode & ref,bool sizes_in_bytes)65     string local_size(const cat_inode & ref, bool sizes_in_bytes)
66     {
67 	string ret;
68 
69 	const cat_file *fic = dynamic_cast<const cat_file *>(&ref);
70 	const cat_directory *dir = dynamic_cast<const cat_directory *>(&ref);
71 	if(fic != nullptr)
72 	    if(sizes_in_bytes)
73 		ret = deci(fic->get_size()).human();
74 	    else
75 		ret = tools_display_integer_in_metric_system(fic->get_size(), "o", true);
76 	else
77 	    if(dir != nullptr)
78 		if(sizes_in_bytes)
79 		    ret = deci(dir->get_size()).human();
80 		else
81 		    ret = tools_display_integer_in_metric_system(dir->get_size(), "o", true);
82 	    else
83 		ret = "0";
84 
85 	return ret;
86     }
87 
local_storage_size(const cat_inode & ref)88     string local_storage_size(const cat_inode & ref)
89     {
90 	string ret;
91 
92 	const cat_file *fic = dynamic_cast<const cat_file*>(&ref);
93 	if(fic != nullptr)
94 	{
95 	    deci d = fic->get_storage_size();
96 	    ret = d.human();
97 	}
98 	else
99 	    ret = "0";
100 
101 	return ret;
102     }
103 
local_date(const cat_inode & ref)104     string local_date(const cat_inode & ref)
105     {
106 	return tools_display_date(ref.get_last_modif());
107     }
108 
local_flag(const cat_inode & ref,bool isolated,bool dirty_seq)109     string local_flag(const cat_inode & ref, bool isolated, bool dirty_seq)
110     {
111 	string ret;
112 	const cat_file *ref_f = dynamic_cast<const cat_file *>(&ref);
113 	bool dirty = dirty_seq || (ref_f != nullptr ? ref_f->is_dirty() : false);
114 	saved_status st = ref.get_saved_status();
115 	cat_inode::ea_status ea_st = ref.ea_get_saved_status();
116 
117 	if(isolated && st == s_saved && !dirty)
118 	    st = s_fake;
119 
120 	if(isolated && ea_st == cat_inode::ea_full)
121 	    ea_st = cat_inode::ea_fake;
122 
123 	switch(st)
124 	{
125 	case s_saved:
126 	    if(dirty)
127 		ret = gettext("[DIRTY]");
128 	    else
129 		ret = gettext("[Saved]");
130 	    break;
131 	case s_fake:
132 	    ret = gettext("[InRef]");
133 	    break;
134 	case s_not_saved:
135 	    ret = "[     ]";
136 	    break;
137 	default:
138 	    throw SRC_BUG;
139 	}
140 
141 
142 	switch(ea_st)
143 	{
144 	case cat_inode::ea_full:
145 	    ret += gettext("[Saved]");
146 	    break;
147 	case cat_inode::ea_fake:
148 	    ret += gettext("[InRef]");
149 	    break;
150 	case cat_inode::ea_partial:
151 	    ret += "[     ]";
152 	    break;
153 	case cat_inode::ea_none:
154 	    ret += "       ";
155 	    break;
156 	case cat_inode::ea_removed:
157 	    ret += "[Suppr]";
158 	    break;
159 	default:
160 	    throw SRC_BUG;
161 	}
162 
163 	ret += "[" + local_fsa_fam_to_string(ref) + "]";
164 	const cat_file *fic = dynamic_cast<const cat_file *>(&ref);
165 	const cat_directory *dir = dynamic_cast<const cat_directory *>(&ref);
166 	if(fic != nullptr && fic->get_saved_status() == s_saved)
167 	    ret += string("[")
168 		+ tools_get_compression_ratio(fic->get_storage_size(),
169 					      fic->get_size(),
170 					      fic->get_compression_algo_read() != none || fic->get_sparse_file_detection_read())
171 		+ "]";
172 
173 	else if(dir != nullptr)
174 	    ret += string("[")
175 		+ tools_get_compression_ratio(dir->get_storage_size(),
176 					      dir->get_size(),
177 					      true)
178 		+ "]";
179 	else
180 	    ret += "[-----]";
181 
182 	if(fic != nullptr && fic->get_sparse_file_detection_read())
183 	    ret += "[X]";
184 	else
185 	    ret += "[ ]";
186 
187 	return ret;
188     }
189 
xml_listing_attributes(user_interaction & dialog,const string & beginning,const string & data,const string & metadata,const cat_entree * obj,bool list_ea)190     void xml_listing_attributes(user_interaction & dialog,
191 				const string & beginning,
192 				const string & data,
193 				const string & metadata,
194 				const cat_entree * obj,
195 				bool list_ea)
196     {
197 	string user;
198 	string group;
199 	string permissions;
200 	string atime;
201 	string mtime;
202 	string ctime;
203 	const cat_inode *e_ino = dynamic_cast<const cat_inode *>(obj);
204 	const cat_mirage *e_hard = dynamic_cast<const cat_mirage *>(obj);
205 
206 	if(e_hard != nullptr)
207 	    e_ino = e_hard->get_inode();
208 
209 	if(e_ino != nullptr)
210 	{
211 	    user = local_uid(*e_ino);
212 	    group = local_gid(*e_ino);
213 	    permissions = local_perm(*e_ino, e_hard != nullptr);
214 	    atime = deci(e_ino->get_last_access().get_second_value()).human();
215 	    mtime = deci(e_ino->get_last_modif().get_second_value()).human();
216 	    if(e_ino->has_last_change())
217 	    {
218 		ctime = deci(e_ino->get_last_change().get_second_value()).human();
219 		if(ctime == "0")
220 		    ctime = "";
221 	    }
222 	    else
223 		ctime = "";
224 	}
225 	else
226 	{
227 	    user = "";
228 	    group = "";
229 	    permissions = "";
230 	    atime = "";
231 	    mtime = "";
232 	    ctime = "";
233 	}
234 
235 	bool go_ea = list_ea && e_ino != nullptr && e_ino->ea_get_saved_status() == cat_inode::ea_full;
236 	string end_tag = go_ea ? ">" : " />";
237 
238 	dialog.printf("%S<Attributes data=\"%S\" metadata=\"%S\" user=\"%S\" group=\"%S\" permissions=\"%S\" atime=\"%S\" mtime=\"%S\" ctime=\"%S\"%S\n",
239 		      &beginning, &data, &metadata, &user, &group, &permissions, &atime, &mtime, &ctime, &end_tag);
240 	if(go_ea)
241 	{
242 	    string new_begin = beginning + "\t";
243 	    local_display_ea(dialog, e_ino, new_begin + "<EA_entry ea_name=\"", "\" />", true);
244 	    dialog.printf("%S</Attributes>", &beginning);
245 	}
246     }
247 
248 
extract_base_and_status(unsigned char signature,unsigned char & base,saved_status & saved)249     bool extract_base_and_status(unsigned char signature, unsigned char & base, saved_status & saved)
250     {
251 	bool fake = (signature & SAVED_FAKE_BIT) != 0;
252 
253 	signature &= ~SAVED_FAKE_BIT;
254 	if(!isalpha(signature))
255 	    return false;
256 	base = tolower(signature);
257 
258 	if(fake)
259 	    if(base == signature)
260 		saved = s_fake;
261 	    else
262 		return false;
263 	else
264 	    if(signature == base)
265 		saved = s_saved;
266 	    else
267 		saved = s_not_saved;
268 	return true;
269     }
270 
271 
local_display_ea(user_interaction & dialog,const cat_inode * ino,const string & prefix,const string & suffix,bool xml_output)272     void local_display_ea(user_interaction & dialog,
273 			  const cat_inode * ino,
274 			  const string &prefix,
275 			  const string &suffix,
276 			  bool xml_output)
277     {
278 	if(ino == nullptr)
279 	    return;
280 
281 	if(ino->ea_get_saved_status() == cat_inode::ea_full)
282 	{
283 	    const ea_attributs *owned = ino->get_ea();
284 	    string key, val;
285 
286 	    if(owned == nullptr)
287 		throw SRC_BUG;
288 
289 	    owned->reset_read();
290 	    while(owned->read(key, val))
291 	    {
292 		if(xml_output)
293 		    key = tools_output2xml(key);
294 		dialog.warning(prefix + key + suffix);
295 	    }
296 	}
297     }
298 
mk_signature(unsigned char base,saved_status state)299     unsigned char mk_signature(unsigned char base, saved_status state)
300     {
301         if(! islower(base))
302             throw SRC_BUG;
303         switch(state)
304         {
305         case s_saved:
306             return base;
307         case s_fake:
308             return base | SAVED_FAKE_BIT;
309         case s_not_saved:
310             return toupper(base);
311         default:
312             throw SRC_BUG;
313         }
314     }
315 
unmk_signature(unsigned char sig,unsigned char & base,saved_status & state,bool isolated)316     void unmk_signature(unsigned char sig, unsigned char & base, saved_status & state, bool isolated)
317     {
318         if((sig & SAVED_FAKE_BIT) == 0 && !isolated)
319             if(islower(sig))
320                 state = s_saved;
321             else
322                 state = s_not_saved;
323         else
324             state = s_fake;
325 
326         base = tolower(sig & ~SAVED_FAKE_BIT);
327     }
328 
compatible_signature(unsigned char a,unsigned char b)329     bool compatible_signature(unsigned char a, unsigned char b)
330     {
331         a = tolower(a & ~SAVED_FAKE_BIT);
332         b = tolower(b & ~SAVED_FAKE_BIT);
333 
334         switch(a)
335         {
336         case 'e':
337         case 'f':
338             return b == 'e' || b == 'f';
339         default:
340             return b == a;
341         }
342     }
343 
get_base_signature(unsigned char a)344     unsigned char get_base_signature(unsigned char a)
345     {
346 	unsigned char ret;
347 	saved_status st;
348 	unmk_signature(a, ret, st, false);
349 	if(ret == 'e')
350 	    ret = 'f';
351 
352 	return ret;
353     }
354 
entree_to_string(const cat_entree * obj)355     string entree_to_string(const cat_entree *obj)
356     {
357 	string ret;
358 	if(obj == nullptr)
359 	    throw SRC_BUG;
360 
361 	switch(get_base_signature(obj->signature()))
362 	{
363 	case 'j':
364 	    ret = gettext("ignored directory");
365 	    break;
366 	case 'd':
367 	    ret = gettext("folder");
368 	    break;
369 	case 'x':
370 	    ret = gettext("deleted file");
371 	    break;
372 	case 'o':
373 	    ret = gettext("door");
374 	    break;
375 	case 'f':
376 	    ret = gettext("file");
377 	    break;
378 	case 'l':
379 	    ret = gettext("symlink");
380 	    break;
381 	case 'c':
382 	    ret = gettext("char device");
383 	    break;
384 	case 'b':
385 	    ret = gettext("block device");
386 	    break;
387 	case 'p':
388 	    ret = gettext("pipe");
389 	    break;
390 	case 's':
391 	    ret = gettext("socket");
392 	    break;
393 	case 'i':
394 	    ret = gettext("ignored entry");
395 	    break;
396 	case 'm':
397 	    ret = gettext("hard linked inode");
398 	    break;
399 	case 'z':
400 	    ret = gettext("end of directory");
401 	    break;
402 	default:
403 	    throw SRC_BUG; // missing inode type
404 	}
405 
406 	return ret;
407     }
408 
409 	// local routine implementation
410 
local_fsa_fam_to_string(const cat_inode & ref)411     static string local_fsa_fam_to_string(const cat_inode & ref)
412     {
413 	string ret = "";
414 
415 	if(ref.fsa_get_saved_status() != cat_inode::fsa_none)
416 	{
417 	    fsa_scope sc = ref.fsa_get_families();
418 	    bool upper = ref.fsa_get_saved_status() == cat_inode::fsa_full;
419 	    ret = fsa_scope_to_string(upper, sc);
420 	    if(ret.size() < 3)
421 		ret += "-";
422 	}
423 	else
424 	    ret = "---";
425 
426 	return ret;
427     }
428 
429 } // end of namespace
430 
431