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