diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/build.sh timeshift-1.7.4~178~ubuntu14.04.1/build.sh --- timeshift-1.7.3~177~ubuntu14.04.1/build.sh 1970-01-01 00:00:00.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/build.sh 2015-09-08 01:01:52.000000000 +0000 @@ -0,0 +1,2 @@ + +make 2>&1 | grep -E --color=never 'error:|.vala:.*warning:' | grep -E --color=always "error:|$" diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/debian/bzr-builder.manifest timeshift-1.7.4~178~ubuntu14.04.1/debian/bzr-builder.manifest --- timeshift-1.7.3~177~ubuntu14.04.1/debian/bzr-builder.manifest 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/debian/bzr-builder.manifest 2015-09-08 01:01:52.000000000 +0000 @@ -1,2 +1,2 @@ -# bzr-builder format 0.3 deb-version {debupstream}~177 -lp:timeshift revid:tony.george.kol@gmail.com-20150814223043-fk0s54fxftkxwloj +# bzr-builder format 0.3 deb-version {debupstream}~178 +lp:timeshift revid:tony.george.kol@gmail.com-20150908005349-uo1hm0rf7u3jkj60 diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/debian/changelog timeshift-1.7.4~178~ubuntu14.04.1/debian/changelog --- timeshift-1.7.3~177~ubuntu14.04.1/debian/changelog 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/debian/changelog 2015-09-08 01:01:52.000000000 +0000 @@ -1,13 +1,11 @@ -timeshift (1.7.3~177~ubuntu14.04.1) trusty; urgency=low +timeshift (1.7.4~178~ubuntu14.04.1) trusty; urgency=low * Auto build. - -- Tony George Fri, 14 Aug 2015 22:34:06 +0000 + -- Tony George Tue, 08 Sep 2015 01:01:52 +0000 -timeshift (1.7.3) trusty; urgency=low +timeshift (1.7.4) trusty; urgency=low - * Updated build dependency to valac-0.26, libgee-0.8 - - * Fixed ambiguous references to Gtk.ListStore + * Fixed minor issues - -- Tony George Fri, 14 Aug 2015 10:00:00 +0530 + -- Tony George Mon, 09 Sep 2015 10:00:00 +0530 diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/AboutWindow.vala timeshift-1.7.4~178~ubuntu14.04.1/src/AboutWindow.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/AboutWindow.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/AboutWindow.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,26 +1,26 @@ /* * AboutWindow.vala - * + * * Copyright 2012 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ - + using Gtk; using TeeJee.Logging; @@ -39,7 +39,7 @@ private Box hbox_action; private Button btn_credits; private Button btn_close; - + private Gtk.Image img_logo; private Label lbl_program_name; private Label lbl_version; @@ -106,7 +106,7 @@ _donations = value; } } - + private string _license = ""; public string license{ get{ @@ -116,7 +116,7 @@ _license = value; } } - + private Gdk.Pixbuf _logo; public Gdk.Pixbuf logo{ get{ @@ -146,7 +146,7 @@ _translators = value; } } - + private string[] _third_party; public string[] third_party{ get{ @@ -156,7 +156,7 @@ _third_party = value; } } - + private string _version = ""; public string version{ get{ @@ -186,21 +186,21 @@ _website_label = value; } } - + public AboutWindow() { window_position = WindowPosition.CENTER_ON_PARENT; set_destroy_with_parent (true); set_modal (true); skip_taskbar_hint = false; - set_default_size (450, 400); + set_default_size (450, 400); vbox_main = get_content_area(); vbox_main.margin = 6; vbox_main.spacing = 6; - + vbox_logo = new Box(Orientation.VERTICAL,0); vbox_main.add(vbox_logo); - + vbox_credits = new Box(Orientation.VERTICAL,0); vbox_credits.no_show_all = true; vbox_main.add(vbox_credits); @@ -213,7 +213,7 @@ img_logo.margin_top = 6; img_logo.margin_bottom = 6; vbox_logo.add(img_logo); - + //program_name lbl_program_name = new Label(""); lbl_program_name.set_use_markup(true); @@ -230,7 +230,7 @@ lbl_comments.set_use_markup(true); lbl_comments.margin_top = 10; vbox_logo.add(lbl_comments); - + //website lbtn_website = new LinkButton(""); lbtn_website.margin_top = 5; @@ -238,13 +238,13 @@ lbtn_website.activate_link.connect(()=>{ try{ - return Gtk.show_uri(null, lbtn_website.uri, Gdk.CURRENT_TIME); + return Gtk.show_uri(null, lbtn_website.uri, Gdk.CURRENT_TIME); } catch(Error e){ return false; } }); - + //copyright lbl_copyright = new Label(""); lbl_copyright.set_use_markup(true); @@ -260,27 +260,27 @@ var sw_credits = new ScrolledWindow(null, null); sw_credits.set_shadow_type(ShadowType.ETCHED_IN); sw_credits.expand = true; - + vbox_credits.add(sw_credits); sw_credits.add(vbox_lines); - + //hbox_commands -------------------------------------------------- - + hbox_action = (Box) get_action_area(); - + //btn_credits btn_credits = new Button.with_label(" " + _("Credits")); btn_credits.set_image (new Image.from_stock ("gtk-about", IconSize.MENU)); - hbox_action.add(btn_credits); - + hbox_action.add(btn_credits); + btn_credits.clicked.connect(()=>{ vbox_logo.visible = !(vbox_logo.visible); vbox_credits.visible = !(vbox_credits.visible); - + if ((vbox_credits.visible)&&(!sw_credits.visible)){ sw_credits.show_all(); } - + if (vbox_credits.visible){ btn_credits.label = " " + _("Back"); btn_credits.set_image (new Image.from_stock ("gtk-go-back", IconSize.MENU)); @@ -295,10 +295,10 @@ btn_close = new Button.with_label(" " + _("Close")); btn_close.set_image (new Image.from_stock ("gtk-close", IconSize.MENU)); hbox_action.add(btn_close); - + btn_close.clicked.connect(()=>{ this.destroy(); }); } - + public void initialize() { title = program_name; img_logo.pixbuf = logo; @@ -309,7 +309,7 @@ lbtn_website.label = website_label; //lbl_copyright.label = "%s".printf(copyright); lbl_copyright.label = "%s".printf(copyright); - + if (authors.length > 0){ add_line("%s\n".printf(_("Authors"))); foreach(string name in authors){ @@ -317,7 +317,7 @@ } add_line("\n"); } - + if (third_party.length > 0){ add_line("%s\n".printf(_("Third Party Tools"))); foreach(string name in third_party){ @@ -325,7 +325,7 @@ } add_line("\n"); } - + if (artists.length > 0){ add_line("%s\n".printf(_("Artists"))); foreach(string name in artists){ @@ -362,12 +362,12 @@ btn_credits.visible = false; } } - + public void add_line(string text){ if (text.split(":").length >= 2){ var link = new LinkButton(text.split(":")[0]); vbox_lines.add(link); - + string val = text[text.index_of(":") + 1:text.length]; if (val.contains("@")){ link.uri = "mailto:" + val; @@ -381,7 +381,7 @@ link.activate_link.connect(()=>{ try{ - return Gtk.show_uri(null, link.uri, Gdk.CURRENT_TIME); + return Gtk.show_uri(null, link.uri, Gdk.CURRENT_TIME); } catch(Error e){ return false; diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/DonationWindow.vala timeshift-1.7.4~178~ubuntu14.04.1/src/DonationWindow.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/DonationWindow.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/DonationWindow.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,26 +1,26 @@ /* * DonationWindow.vala - * + * * Copyright 2012 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ - + using Gtk; using TeeJee.Logging; @@ -33,30 +33,31 @@ public class DonationWindow : Dialog { public DonationWindow() { - title = _("Donate"); - window_position = WindowPosition.CENTER_ON_PARENT; + set_title(_("Donate")); + window_position = WindowPosition.CENTER_ON_PARENT; set_destroy_with_parent (true); set_modal (true); - skip_taskbar_hint = false; - set_default_size (400, 20); + set_deletable(true); + set_skip_taskbar_hint(false); + set_default_size (400, 20); icon = get_app_icon(16); - + //vbox_main - Box vbox_main = get_content_area(); + Box vbox_main = get_content_area(); vbox_main.margin = 6; vbox_main.homogeneous = false; - + get_action_area().visible = false; - + //lbl_message Label lbl_message = new Gtk.Label(""); string msg = _("Did you find this software useful?\n\nYou can buy me a coffee or make a donation via PayPal to show your support. Or just drop me an email and say Hi.\n\nThis application is completely free and will continue to remain that way. Your contributions will help in keeping this project alive and to develop it further.\n\nFeel free to drop me an email if you find any issues or if you have suggestions for improvement.\n\nRegards,\nTony George\nteejeetech@gmail.com"); lbl_message.label = msg; lbl_message.wrap = true; vbox_main.pack_start(lbl_message,true,true,0); - + //vbox_actions - Box vbox_actions = new Box (Orientation.VERTICAL, 6); + Box vbox_actions = new Box (Orientation.VERTICAL, 6); vbox_actions.margin_left = 50; vbox_actions.margin_right = 50; vbox_actions.margin_top = 20; @@ -66,7 +67,7 @@ Button btn_donate = new Button.with_label(" " + _("Donate via PayPal") + " "); vbox_actions.add(btn_donate); btn_donate.clicked.connect(()=>{ - xdg_open("https://www.paypal.com/cgi-bin/webscr?business=teejee2009@gmail.com&cmd=_xclick¤cy_code=USD&amount=10&item_name=Timeshift%20Donation"); + xdg_open("https://www.paypal.com/cgi-bin/webscr?business=teejee2009@gmail.com&cmd=_xclick¤cy_code=USD&amount=10&item_name=Selene%20Donation"); }); //btn_send_email @@ -75,13 +76,19 @@ btn_send_email.clicked.connect(()=>{ xdg_open("mailto:teejeetech@gmail.com"); }); - + //btn_visit Button btn_visit = new Button.with_label(" " + _("Visit Website") + " "); vbox_actions.add(btn_visit); btn_visit.clicked.connect(()=>{ xdg_open("http://www.teejeetech.in"); }); - } + //btn_exit + Button btn_exit = new Button.with_label(" " + _("OK") + " "); + vbox_actions.add(btn_exit); + btn_exit.clicked.connect(() => { + this.destroy(); + }); + } } diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/ExcludeMessageWindow.vala timeshift-1.7.4~178~ubuntu14.04.1/src/ExcludeMessageWindow.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/ExcludeMessageWindow.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/ExcludeMessageWindow.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,24 +1,24 @@ /* * ExcludeMessageWindow.vala - * + * * Copyright 2013 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ using Gtk; @@ -46,7 +46,7 @@ private Label lbl_exclude; private Label lbl_header_home; private Label lbl_home; - + //actions private Button btn_ok; @@ -64,20 +64,20 @@ catch(Error e){ log_error (e.message); } - + string msg; - + //vbox_main vbox_main = get_content_area (); vbox_main.margin = 3; vbox_main.spacing = 3; - + //lbl_header_exclude lbl_header_exclude = new Gtk.Label("" + _("Exclude List") + ":"); lbl_header_exclude.xalign = (float) 0.0; lbl_header_exclude.set_use_markup(true); vbox_main.add(lbl_header_exclude); - + //lbl_exclude lbl_exclude = new Gtk.Label(_("Files matching the following patterns will be excluded") + ":"); lbl_exclude.xalign = (float) 0.0; @@ -85,7 +85,7 @@ vbox_main.add(lbl_exclude); //tv_exclude----------------------------------------------- - + //tv_exclude tv_exclude = new TreeView(); tv_exclude.get_selection().mode = SelectionMode.MULTIPLE; @@ -103,15 +103,15 @@ col_exclude = new TreeViewColumn(); col_exclude.title = _("File Pattern"); col_exclude.expand = true; - + CellRendererText cell_exclude_margin = new CellRendererText (); cell_exclude_margin.text = ""; col_exclude.pack_start (cell_exclude_margin, false); - + CellRendererPixbuf cell_exclude_icon = new CellRendererPixbuf (); col_exclude.pack_start (cell_exclude_icon, false); col_exclude.set_attributes(cell_exclude_icon, "pixbuf", 1); - + CellRendererText cell_exclude_text = new CellRendererText (); col_exclude.pack_start (cell_exclude_text, false); col_exclude.set_cell_data_func (cell_exclude_text, cell_exclude_text_render); @@ -131,13 +131,13 @@ lbl_home.set_use_markup(true); lbl_home.wrap = true; vbox_main.add(lbl_home); - + msg = _("Hidden files and folders are included by default since they contain user-specific configuration files.") + "\n"; msg += _("All other files and folders are excluded.") + "\n"; lbl_home.label =msg; - + //Actions ---------------------------------------------- - + //hbox_action hbox_action = (Box) get_action_area (); @@ -150,7 +150,7 @@ var model = new Gtk.ListStore(2, typeof(string), typeof(Gdk.Pixbuf)); tv_exclude.model = model; - + foreach(string path in App.exclude_list_default){ tv_exclude_add_item(path); } @@ -161,7 +161,7 @@ model.get (iter, 0, out pattern, -1); (cell as Gtk.CellRendererText).text = pattern.has_prefix("+ ") ? pattern[2:pattern.length] : pattern; } - + private void tv_exclude_add_item(string path){ Gdk.Pixbuf pix_exclude = null; Gdk.Pixbuf pix_include = null; @@ -178,22 +178,22 @@ TreeIter iter; var model = (Gtk.ListStore) tv_exclude.model; model.append(out iter); - + if (path.has_prefix("+ ")){ pix_selected = pix_include; } else{ pix_selected = pix_exclude; } - + model.set (iter, 0, path, 1, pix_selected); - + Adjustment adj = tv_exclude.get_hadjustment(); adj.value = adj.upper; } - + private void btn_ok_clicked(){ this.response(Gtk.ResponseType.OK); - return; + return; } } diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/Main.vala timeshift-1.7.4~178~ubuntu14.04.1/src/Main.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/Main.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/Main.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,24 +1,24 @@ /* * Main.vala - * + * * Copyright 2012 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ using GLib; @@ -39,7 +39,7 @@ public Main App; public const string AppName = "Timeshift RSYNC"; public const string AppShortName = "timeshift"; -public const string AppVersion = "1.7.3"; +public const string AppVersion = "1.7.4"; public const string AppAuthor = "Tony George"; public const string AppAuthorEmail = "teejee2008@gmail.com"; @@ -64,21 +64,21 @@ public Gee.ArrayList exclude_list_restore; public Gee.ArrayList exclude_list_apps; public Gee.ArrayList mount_list; - + //temp private Gee.ArrayList grub_device_list; - + public Device root_device; public Device home_device; public Device snapshot_device; - + public string mount_point_backup = ""; public string mount_point_restore = ""; public string mount_point_app = "/mnt/timeshift"; - + public DistInfo current_distro; public bool mirror_system = false; - + public bool _is_scheduled = false; public bool schedule_monthly = false; public bool schedule_weekly = false; @@ -92,7 +92,7 @@ public int count_boot = 5; public string app_mode = ""; - + //global vars for controlling threads public bool thr_success = false; public bool thr_running = false; @@ -100,23 +100,23 @@ public string thr_arg1 = ""; public bool thr_timeout_active = false; public string thr_timeout_cmd = ""; - + public int startup_delay_interval_mins = 10; public int retain_snapshots_max_days = 200; public int minimum_free_disk_space_mb = 2048; public long first_snapshot_size = 0; - + public string log_dir = ""; public string log_file = ""; public string lock_dir = ""; public string lock_file = ""; - + public TimeShiftBackup snapshot_to_delete; public TimeShiftBackup snapshot_to_restore; public Device restore_target; public bool reinstall_grub2 = false; public string grub_device = ""; - + public bool cmd_skip_grub = false; public string cmd_grub_device = ""; public string cmd_target_device = ""; @@ -124,7 +124,7 @@ public string cmd_snapshot = ""; public bool cmd_confirm = false; public bool cmd_verbose = true; - + public string progress_text = ""; public int snapshot_list_start_index = 0; @@ -142,18 +142,18 @@ return 0; } } - + //init TMP LOG_ENABLE = false; init_tmp(); LOG_ENABLE = true; - + /* * Note: * init_tmp() will fail if timeshift is run as normal user * logging will be disabled temporarily so that the error is not displayed to user */ - + /* var map = Device.get_mounted_filesystems_using_mtab(); foreach(Device pi in map.values){ @@ -161,40 +161,40 @@ } exit(0); */ - + LOG_TIMESTAMP = true; - + App = new Main(args); bool success = App.start_application(args); App.exit_app(); - + return (success) ? 0 : 1; } - + private static void set_locale(){ Intl.setlocale(GLib.LocaleCategory.MESSAGES, "timeshift"); Intl.textdomain(GETTEXT_PACKAGE); Intl.bind_textdomain_codeset(GETTEXT_PACKAGE, "utf-8"); Intl.bindtextdomain(GETTEXT_PACKAGE, LOCALE_DIR); } - + public Main(string[] args){ string msg = ""; //parse arguments (initial) ------------ - + parse_arguments(args); //check for admin access before logging is initialized //since writing to log directory requires admin access - + if (!user_is_admin()){ msg = _("TimeShift needs admin access to backup and restore system files.") + "\n"; msg += _("Please run the application as admin (using 'sudo' or 'su')"); log_error(msg); - + if (app_mode == ""){ string title = _("Admin Access Required"); gtk_messagebox(title, msg, null, true); @@ -204,12 +204,12 @@ } //init log ------------------ - + try { DateTime now = new DateTime.now_local(); log_dir = "/var/log/timeshift"; log_file = log_dir + "/" + now.format("%Y-%m-%d_%H-%M-%S") + ".log"; - + var file = File.new_for_path (log_dir); if (!file.query_exists ()) { file.make_directory_with_parents(); @@ -219,25 +219,25 @@ if (file.query_exists ()) { file.delete (); } - + dos_log = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION)); if ((app_mode == "")||(LOG_DEBUG)){ log_msg(_("Session log file") + ": %s".printf(log_file)); } - } + } catch (Error e) { log_error (e.message); } //get Linux distribution info ----------------------- - + this.current_distro = DistInfo.get_dist_info("/"); if ((app_mode == "")||(LOG_DEBUG)){ log_msg(_("Distribution") + ": " + current_distro.full_name(),true); } - + //check dependencies --------------------- - + string message; if (!check_dependencies(out message)){ if (app_mode == ""){ @@ -248,7 +248,7 @@ } //check and create lock ------------------ - + lock_dir = "/var/run/lock/timeshift"; lock_file = lock_dir + "/lock"; if (!create_lock()){ @@ -256,7 +256,7 @@ string txt = read_file(lock_file); //string pid = txt.split(";")[0].strip(); string mode = txt.split(";")[1].strip(); - + if (mode == "backup"){ msg = _("A scheduled job is currently taking a system snapshot.") + "\n"; msg += _("Please wait for a few minutes and try again."); @@ -265,7 +265,7 @@ msg = _("Another instance of timeshift is currently running!") + "\n"; msg += _("Please check if you have multiple windows open.") + "\n"; } - + string title = _("Error"); gtk_messagebox(title, msg, null, true); } @@ -276,26 +276,26 @@ } //initialize variables ------------------ - + this.app_path = (File.new_for_path (args[0])).get_parent().get_path (); this.share_folder = "/usr/share"; this.app_conf_path = "/etc/timeshift.json"; //root_device and home_device will be initalized by update_partition_list() - + //check if running locally ------------- - + string local_exec = args[0]; string local_conf = app_path + "/timeshift.json"; string local_share = app_path + "/share"; var f_local_exec = File.new_for_path(local_exec); if (f_local_exec.query_exists()){ - + var f_local_conf = File.new_for_path(local_conf); if (f_local_conf.query_exists()){ this.app_conf_path = local_conf; } - + var f_local_share = File.new_for_path(local_share); if (f_local_share.query_exists()){ this.share_folder = local_share; @@ -307,7 +307,7 @@ } //initialize lists ------------------------- - + snapshot_list = new Gee.ArrayList(); exclude_list_user = new Gee.ArrayList(); exclude_list_default = new Gee.ArrayList(); @@ -320,16 +320,16 @@ add_default_exclude_entries(); //add_app_exclude_entries(); - + //initialize app -------------------- - + update_partition_list(); detect_system_devices(); //finish initialization -------------- - + load_app_config(); - update_snapshot_list(); + update_snapshot_list(); } public bool start_application(string[] args){ @@ -365,11 +365,11 @@ case "delete-all": is_success = delete_all_snapshots(); return is_success; - + case "ondemand": is_success = take_snapshot(true,"",null); return is_success; - + case "list-snapshots": LOG_ENABLE = true; if (snapshot_list.size > 0){ @@ -387,13 +387,13 @@ log_msg(_("Devices with Linux file systems") + ":\n"); list_devices(); return true; - + default: //Initialize main window var window = new MainWindow (); window.destroy.connect(Gtk.main_quit); window.show_all(); - + //start event loop Gtk.main(); @@ -403,8 +403,8 @@ public bool check_dependencies(out string msg){ msg = ""; - - string[] dependencies = { "rsync","/sbin/blkid","df","mount","umount","fuser","crontab","cp","rm","touch","ln","sync"}; //"shutdown","chroot", + + string[] dependencies = { "rsync","/sbin/blkid","df","mount","umount","fuser","crontab","cp","rm","touch","ln","sync"}; //"shutdown","chroot", string path; foreach(string cmd_tool in dependencies){ @@ -413,7 +413,7 @@ msg += " * " + cmd_tool + "\n"; } } - + if (msg.length > 0){ msg = _("Commands listed below are not available on this system") + ":\n\n" + msg + "\n"; msg += _("Please install required packages and try running TimeShift again"); @@ -424,8 +424,8 @@ return true; } } - - public bool check_btrfs_root_layout(){ + + public bool check_btrfs_root_layout(){ //check if root device is a BTRFS volume if ((root_device != null) && (root_device.type == "btrfs")){ //check subvolume layout @@ -434,7 +434,7 @@ msg += _("Only ubuntu-type layouts with @ and @home subvolumes are currently supported.") + "\n\n"; msg += _("Application will exit.") + "\n\n"; string title = _("Not Supported"); - + if (app_mode == ""){ gtk_messagebox(title, msg, null, true); } @@ -444,15 +444,15 @@ return false; } } - + return true; } - + public void add_default_exclude_entries(){ - + exclude_list_default.clear(); exclude_list_home.clear(); - + //default exclude entries ------------------- exclude_list_default.add("/dev/*"); @@ -468,17 +468,17 @@ exclude_list_default.add("/timeshift/*"); exclude_list_default.add("/data/*"); exclude_list_default.add("/cdrom/*"); - + exclude_list_default.add("/root/.thumbnails"); exclude_list_default.add("/root/.cache"); exclude_list_default.add("/root/.gvfs"); exclude_list_default.add("/root/.local/share/Trash"); - + exclude_list_default.add("/home/*/.thumbnails"); exclude_list_default.add("/home/*/.cache"); exclude_list_default.add("/home/*/.gvfs"); exclude_list_default.add("/home/*/.local/share/Trash"); - + //default extra ------------------ exclude_list_default_extra.add("/root/.mozilla/firefox/*.default/Cache"); @@ -486,41 +486,41 @@ exclude_list_default_extra.add("/root/.opera/cache"); exclude_list_default_extra.add("/root/.kde/share/apps/kio_http/cache"); exclude_list_default_extra.add("/root/.kde/share/cache/http"); - + exclude_list_default_extra.add("/home/*/.mozilla/firefox/*.default/Cache"); exclude_list_default_extra.add("/home/*/.mozilla/firefox/*.default/OfflineCache"); exclude_list_default_extra.add("/home/*/.opera/cache"); exclude_list_default_extra.add("/home/*/.kde/share/apps/kio_http/cache"); exclude_list_default_extra.add("/home/*/.kde/share/cache/http"); - + //default home ---------------- - + exclude_list_home.add("+ /root/.**"); exclude_list_home.add("/root/**"); - + exclude_list_home.add("+ /home/*/.**"); exclude_list_home.add("/home/*/**"); - + /* Most web browsers store their cache under ~/.cache and /tmp These files will be excluded by the entries for ~/.cache and /tmp There is no need to add special entries. - + ~/.cache/google-chrome -- Google Chrome ~/.cache/chromium -- Chromium ~/.cache/epiphany-browser -- Epiphany ~/.cache/midori/web -- Midori /var/tmp/kdecache-$USER/http -- Rekonq */ - + } - + public void add_app_exclude_entries(){ exclude_list_apps.clear(); - + string home; string user_name; - + string cmd = "echo ${SUDO_USER:-$(whoami)}"; string std_out; string std_err; @@ -535,11 +535,11 @@ user_name = std_out.strip(); home = "/home/%s".printf(user_name); } - + if ((root_device == null) || ((restore_target.device != root_device.device) && (restore_target.uuid != root_device.uuid))){ home = mount_point_restore + home; } - + try { File f_home = File.new_for_path (home); @@ -553,7 +553,7 @@ if (name == ".local"){ continue; } if (name == ".gvfs"){ continue; } if (name.has_suffix(".lock")){ continue; } - + if (dir_exists(item)) { AppExcludeEntry entry = new AppExcludeEntry("~/" + name, false); exclude_list_apps.add(entry); @@ -563,14 +563,14 @@ exclude_list_apps.add(entry); } } - + File f_home_config = File.new_for_path (home + "/.config"); enumerator = f_home_config.enumerate_children ("standard::*", 0); while ((file = enumerator.next_file ()) != null) { string name = file.get_name(); string item = home + "/.config/" + name; if (name.has_suffix(".lock")){ continue; } - + if (dir_exists(item)) { AppExcludeEntry entry = new AppExcludeEntry("~/.config/" + name, false); exclude_list_apps.add(entry); @@ -580,14 +580,14 @@ exclude_list_apps.add(entry); } } - + File f_home_local = File.new_for_path (home + "/.local/share"); enumerator = f_home_local.enumerate_children ("standard::*", 0); while ((file = enumerator.next_file ()) != null) { string name = file.get_name(); string item = home + "/.local/share/" + name; if (name.has_suffix(".lock")){ continue; } - + if (dir_exists(item)) { AppExcludeEntry entry = new AppExcludeEntry("~/.local/share/" + name, false); exclude_list_apps.add(entry); @@ -608,25 +608,25 @@ }; exclude_list_apps.sort((owned) entry_compare); } - + public bool create_lock(){ try{ - + string current_pid = ((long)Posix.getpid()).to_string(); var file = File.new_for_path (lock_dir); if (!file.query_exists()) { file.make_directory_with_parents(); } - + file = File.new_for_path (lock_file); if (file.query_exists()) { - + string txt = read_file(lock_file); string process_id = txt.split(";")[0].strip(); //string mode = txt.split(";")[1].strip(); long pid = long.parse(process_id); - + if (process_is_running(pid)){ log_msg(_("Another instance of timeshift is currently running") + " (PID=%ld)".printf(pid)); return false; @@ -645,12 +645,12 @@ return true; } } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); return false; } } - + public void remove_lock(){ try{ var file = File.new_for_path (lock_file); @@ -658,13 +658,13 @@ file.delete(); } } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); } } - + //console functions - + public static string help_message (){ string msg = "\n" + AppName + " v" + AppVersion + " by Tony George (teejee2008@gmail.com)" + "\n"; msg += "\n"; @@ -705,7 +705,7 @@ msg += " --quiet " + _("Hide rsync output") + "\n"; msg += " --help " + _("Show all options") + "\n"; msg += "\n"; - + msg += _("Examples") + ":\n"; msg += "\n"; msg += "timeshift --list\n"; @@ -716,7 +716,7 @@ msg += "timeshift --delete --snapshot '2014-10-12_16-29-08'\n"; msg += "timeshift --delete-all \n"; msg += "\n"; - + msg += _("Notes") + ":\n"; msg += "\n"; msg += " 1) --backup will take a snapshot only if a scheduled snapshot is due\n"; @@ -729,7 +729,7 @@ } private void parse_arguments(string[] args){ - for (int k = 1; k < args.length; k++) // Oth arg is app path + for (int k = 1; k < args.length; k++) // Oth arg is app path { switch (args[k].down()){ case "--backup": @@ -737,7 +737,7 @@ LOG_DEBUG = false; app_mode = "backup"; break; - + case "--delete": LOG_TIMESTAMP = false; LOG_DEBUG = false; @@ -749,14 +749,14 @@ LOG_DEBUG = false; app_mode = "delete-all"; break; - + case "--restore": LOG_TIMESTAMP = false; LOG_DEBUG = false; mirror_system = false; app_mode = "restore"; break; - + case "--clone": LOG_TIMESTAMP = false; LOG_DEBUG = false; @@ -773,7 +773,7 @@ case "--skip-grub": cmd_skip_grub = true; break; - + case "--verbose": cmd_verbose = true; break; @@ -781,7 +781,7 @@ case "--quiet": cmd_verbose = false; break; - + case "--yes": cmd_confirm = true; break; @@ -791,7 +791,7 @@ reinstall_grub2 = true; cmd_grub_device = args[++k]; break; - + case "--target": case "--target-device": cmd_target_device = args[++k]; @@ -800,17 +800,17 @@ case "--backup-device": cmd_backup_device = args[++k]; break; - + case "--snapshot": case "--snapshot-name": cmd_snapshot = args[++k]; break; - + case "--debug": LOG_COMMANDS = true; LOG_DEBUG = true; break; - + case "--list": case "--list-snapshots": app_mode = "list-snapshots"; @@ -823,7 +823,7 @@ LOG_TIMESTAMP = false; LOG_DEBUG = false; break; - + default: LOG_TIMESTAMP = false; log_error(_("Invalid command line arguments") + ": %s".printf(args[k]), true); @@ -832,19 +832,19 @@ break; } } - + /* LOG_ENABLE = false; disables all console output * LOG_TIMESTAMP = false; disables the timestamp prepended to every line in terminal output * LOG_DEBUG = false; disables additional console messages * LOG_COMMANDS = true; enables printing of all commands on terminal * */ - + if (app_mode == ""){ //Initialize GTK LOG_TIMESTAMP = true; Gtk.init(ref args); } - + } public void list_snapshots(bool paginate){ @@ -854,10 +854,10 @@ count++; } } - + string[,] grid = new string[count+1,5]; bool[] right_align = { false, false, false, false, false}; - + int row = 0; int col = -1; grid[row, ++col] = _("Num"); @@ -879,20 +879,20 @@ row++; } } - + print_grid(grid, right_align); } - + public void list_devices(){ int count = 0; foreach(Device pi in partition_list) { if (!pi.has_linux_filesystem()) { continue; } count++; } - + string[,] grid = new string[count+1,6]; bool[] right_align = { false, false, false, true, true, false}; - + int row = 0; int col = -1; grid[row, ++col] = _("Num"); @@ -903,7 +903,7 @@ grid[row, ++col] = _("Type"); grid[row, ++col] = _("Label"); row++; - + foreach(Device pi in partition_list) { if (!pi.has_linux_filesystem()) { continue; } @@ -917,13 +917,13 @@ grid[row, ++col] = "%s".printf(pi.label); row++; } - + print_grid(grid, right_align); } - + public void print_grid(string[,] grid, bool[] right_align, bool has_header = true){ int[] col_width = new int[grid.length[1]]; - + for(int col=0; col col_width[col]){ @@ -938,14 +938,14 @@ stdout.printf(fmt.printf(grid[row,col])); } stdout.printf("\n"); - + if (has_header && (row == 0)){ stdout.printf(string.nfill(78, '-')); stdout.printf("\n"); } } } - + public void list_grub_devices(bool print_to_console = true){ //add devices grub_device_list = new Gee.ArrayList(); @@ -960,12 +960,12 @@ if (pi.device.has_prefix("/dev/dm-")) { continue; } grub_device_list.add(pi); } - + /*Note: Lists are already sorted. No need to sort again */ - + string[,] grid = new string[grub_device_list.size+1,4]; bool[] right_align = { false, false, false, false }; - + int row = 0; int col = -1; grid[row, ++col] = _("Num"); @@ -973,7 +973,7 @@ grid[row, ++col] = _("Device"); grid[row, ++col] = _("Description"); row++; - + string desc = ""; foreach(Device pi in grub_device_list) { col = -1; @@ -992,59 +992,59 @@ grid[row, ++col] = "%s".printf(desc); row++; } - + print_grid(grid, right_align); } //input prompt timeout - + public void start_timeout_counter(string kill_cmd = ""){ try { thr_timeout_cmd = kill_cmd; thr_timeout_active = true; Thread.create (start_timeout_counter_thread, true); - } + } catch (Error e) { log_error (e.message); } } - + public void start_timeout_counter_thread(){ int count = 20 * 1000; while (thr_timeout_active && (count > 0)){ Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 500); count -= 500; } - + if (thr_timeout_active){ thr_timeout_active = false; stdout.printf("\n"); - + if (thr_timeout_cmd.length > 0){ Posix.system("killall " + thr_timeout_cmd); } - + log_error(_("No response from user")); log_msg(_("Aborted.")); exit(0); } } - + public void stop_timeout_counter(){ thr_timeout_active = false; } - + //prompt for input - + public Device? read_stdin_device(Gee.ArrayList device_list){ start_timeout_counter(); string? line = stdin.read_line(); stop_timeout_counter(); - + line = (line != null) ? line.strip() : line; - + Device selected_device = null; - + if (line.down() == "a"){ log_msg(_("Aborted.")); exit_app(); @@ -1065,19 +1065,19 @@ log_error("Invalid input"); } } - + return selected_device; } - + public Device? read_stdin_device_mounts(Gee.ArrayList device_list, MountEntry mnt){ start_timeout_counter(); string? line = stdin.read_line(); stop_timeout_counter(); - + line = (line != null) ? line.strip() : line; - + Device selected_device = null; - + if ((line == null)||(line.length == 0)||(line.down() == "c")||(line.down() == "d")){ //set default if (mirror_system){ @@ -1107,10 +1107,10 @@ log_error("Invalid input"); } } - + return selected_device; } - + public Device? get_device_from_index(Gee.ArrayList device_list, string index_string){ int64 index; if (int64.try_parse(index_string, out index)){ @@ -1125,7 +1125,7 @@ return null; } - + public Device? get_device_from_name(Gee.ArrayList device_list, string device_name){ foreach(Device pi in device_list) { if (!pi.has_linux_filesystem()) { continue; } @@ -1143,16 +1143,16 @@ return null; } - + public TimeShiftBackup read_stdin_snapshot(){ start_timeout_counter(); string? line = stdin.read_line(); stop_timeout_counter(); - + line = (line != null) ? line.strip() : line; - + TimeShiftBackup selected_snapshot = null; - + if (line.down() == "a"){ log_msg("Aborted."); exit_app(); @@ -1196,17 +1196,17 @@ log_error("Invalid input"); } } - + return selected_snapshot; } - + public bool read_stdin_grub_install(){ start_timeout_counter(); string? line = stdin.read_line(); stop_timeout_counter(); - + line = (line != null) ? line.strip() : line; - + if ((line == null)||(line.length == 0)){ log_error("Invalid input"); return false; @@ -1241,9 +1241,9 @@ start_timeout_counter(); string? line = stdin.read_line(); stop_timeout_counter(); - + line = (line != null) ? line.strip() : line; - + if ((line.down() == "a")||(line.down() == "n")){ log_msg("Aborted."); exit_app(); @@ -1267,9 +1267,9 @@ return false; } } - + //properties - + public string snapshot_dir { owned get{ if (mount_point_backup == "/"){ @@ -1283,7 +1283,7 @@ } } } - + public bool is_scheduled{ get{ return _is_scheduled; @@ -1292,18 +1292,18 @@ _is_scheduled = value; } } - + public bool live_system(){ return (root_device == null); } - + //backup - + public bool take_snapshot (bool is_ondemand, string snapshot_comments, Gtk.Window? parent_win){ if (check_btrfs_root_layout() == false){ return false; } - + bool status; bool update_symlinks = false; @@ -1316,11 +1316,11 @@ if (!mount_backup_device(parent_win)){ return false; } - + //check backup device string msg; int status_code = check_backup_device(out msg); - + if (!is_ondemand){ //check if first snapshot was taken if (status_code == 2){ @@ -1329,7 +1329,7 @@ return false; } } - + //check space if ((status_code == 1) || (status_code == 2)){ is_scheduled = false; @@ -1359,12 +1359,12 @@ TimeShiftBackup last_snapshot_daily = get_latest_snapshot("daily"); TimeShiftBackup last_snapshot_weekly = get_latest_snapshot("weekly"); TimeShiftBackup last_snapshot_monthly = get_latest_snapshot("monthly"); - + DateTime dt_sys_boot = now.add_seconds((-1) * get_system_uptime_seconds()); bool take_new = false; if (schedule_boot){ - + log_msg(_("Boot snapshots are enabled")); if (last_snapshot_boot == null){ @@ -1380,7 +1380,7 @@ log_msg(_("Last boot snapshot is %d hours old").printf(hours)); take_new = false; } - + if (take_new){ status = backup_and_rotate ("boot",now); if(!status){ @@ -1392,9 +1392,9 @@ } } } - + if (schedule_hourly){ - + log_msg(_("Hourly snapshots are enabled")); if (last_snapshot_hourly == null){ @@ -1410,7 +1410,7 @@ log_msg(_("Last hourly snapshot is %d minutes old").printf(mins)); take_new = false; } - + if (take_new){ status = backup_and_rotate ("hourly",now); if(!status){ @@ -1422,9 +1422,9 @@ } } } - + if (schedule_daily){ - + log_msg(_("Daily snapshots are enabled")); if (last_snapshot_daily == null){ @@ -1440,7 +1440,7 @@ log_msg(_("Last daily snapshot is %d hours old").printf(hours)); take_new = false; } - + if (take_new){ status = backup_and_rotate ("daily",now); if(!status){ @@ -1452,9 +1452,9 @@ } } } - + if (schedule_weekly){ - + log_msg(_("Weekly snapshots are enabled")); if (last_snapshot_weekly == null){ @@ -1470,7 +1470,7 @@ log_msg(_("Last weekly snapshot is %d days old").printf(days)); take_new = false; } - + if (take_new){ status = backup_and_rotate ("weekly",now); if(!status){ @@ -1482,9 +1482,9 @@ } } } - + if (schedule_monthly){ - + log_msg(_("Monthly snapshot are enabled")); if (last_snapshot_monthly == null){ @@ -1500,7 +1500,7 @@ log_msg(_("Last monthly snapshot is %d days old").printf(days)); take_new = false; } - + if (take_new){ status = backup_and_rotate ("monthly",now); if(!status){ @@ -1519,7 +1519,7 @@ } auto_delete_backups(); - + if (update_symlinks){ update_snapshot_list(); create_symlinks(); @@ -1532,7 +1532,7 @@ return true; } - + public bool backup_and_rotate(string tag, DateTime dt_created){ string cmd = ""; string std_out; @@ -1544,23 +1544,23 @@ string time_stamp = dt_created.format("%Y-%m-%d_%H-%M-%S"); DateTime now = new DateTime.now_local(); bool backup_taken = false; - - string sync_name = ".sync"; - string sync_path = snapshot_dir + "/" + sync_name; - + + string sync_name = ".sync"; + string sync_path = snapshot_dir + "/" + sync_name; + try{ //delete the existing .sync snapshot if invalid -------- - + f = File.new_for_path(sync_path); if(f.query_exists()){ - + f = File.new_for_path(sync_path + "/info.json"); if(!f.query_exists()){ progress_text = _("Cleaning up..."); log_msg(progress_text); - + if (!delete_directory(sync_path)){ return false; } @@ -1568,12 +1568,12 @@ } DateTime dt_sys_boot = now.add_seconds((-1) * get_system_uptime_seconds()); - + //check if we can rotate an existing backup ------------- - + TimeShiftBackup last_snapshot = get_latest_snapshot(); DateTime dt_filter = null; - + if ((tag != "ondemand") && (last_snapshot != null)){ switch(tag){ case "boot": @@ -1589,7 +1589,7 @@ log_error(_("Unknown snapshot type") + ": %s".printf(tag)); return false; } - + TimeShiftBackup backup_to_rotate = null; foreach(TimeShiftBackup bak in snapshot_list){ if (bak.date.compare(dt_filter) > 0){ @@ -1609,7 +1609,7 @@ if (!backup_taken){ //take new backup --------------------------------- - + DateTime dt_begin = new DateTime.now_local(); //log_msg("Taking system snapshot..."); @@ -1617,32 +1617,32 @@ f = File.new_for_path(sync_path); if (!f.query_exists()){ - + //create .sync directory -------- - + f = File.new_for_path(sync_path + "/localhost"); f.make_directory_with_parents(); TimeShiftBackup bak_restore = null; - + //check if a control file was written after restore ------- - + string ctl_path = snapshot_dir + "/.sync-restore"; - + f = File.new_for_path(ctl_path); if(f.query_exists()){ string snapshot_path = read_file(ctl_path); - + foreach(TimeShiftBackup bak in snapshot_list){ if (bak.path == snapshot_path){ bak_restore = bak; break; } } - + f.delete(); } - + if (bak_restore == null){ //select latest snapshot for hard-linking for(int k = snapshot_list.size -1; k >= 0; k--){ @@ -1651,14 +1651,14 @@ break; } } - + //hard-link selected snapshot if (bak_restore != null){ progress_text = _("Hard-linking files from previous snapshot..."); log_msg(progress_text); - + cmd = "cp -alp \"%s\" \"%s\"".printf(bak_restore.path + "/localhost/.", sync_path + "/localhost/"); - + if (LOG_COMMANDS) { log_debug(cmd); } Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); @@ -1669,23 +1669,23 @@ } } } - + //delete existing control file -------------- - + f = File.new_for_path(sync_path + "/info.json"); if (f.query_exists()){ f.delete(); } - + //save exclude list ------------ - + save_exclude_list(sync_path); - + //update modification date of .sync directory --------- - + cmd = "touch \"%s\"".printf(sync_path); Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - + if (LOG_COMMANDS) { log_debug(cmd); } if (ret_val != 0){ @@ -1693,18 +1693,18 @@ log_error(_("Failed to update modification date")); return false; } - + //rsync file system with .sync ------------------ - + progress_text = _("Synching files..."); log_msg(progress_text); - + var log_path = sync_path + "/rsync-log"; f = File.new_for_path(log_path); if (f.query_exists()){ f.delete(); } - + cmd = "rsync -ai %s --delete --numeric-ids --stats --relative --delete-excluded".printf(cmd_verbose ? "--verbose" : "--quiet"); cmd += " --log-file=\"%s\"".printf(log_path); cmd += " --exclude-from=\"%s\"".printf(list_file); @@ -1719,19 +1719,19 @@ } //write control file ---------- - + write_snapshot_control_file(sync_path, dt_created, tag); //rotate .sync to required level ---------- - + progress_text = _("Saving new snapshot..."); log_msg(progress_text); - - string new_name = time_stamp; - string new_path = snapshot_dir + "/" + new_name; + + string new_name = time_stamp; + string new_path = snapshot_dir + "/" + new_name; cmd = "cp -alp \"%s\" \"%s\"".printf(sync_path, new_path); - + if (LOG_COMMANDS) { log_debug(cmd); } Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); @@ -1747,9 +1747,9 @@ msg = _("Snapshot saved successfully") + " (%lds)".printf(seconds); log_msg(msg); notify_send("TimeShift",msg,10000,"low"); - + log_msg(_("Snapshot") + " '%s' ".printf(new_name) + _("tagged") + " '%s'".printf(tag)); - + update_snapshot_list(); } } @@ -1763,7 +1763,7 @@ public int run_rsync(string cmd){ thr_arg1 = cmd; - + try { thr_running = true; Thread.create (run_rsync_thread, true); @@ -1782,7 +1782,7 @@ public void run_rsync_thread(){ if (LOG_COMMANDS) { log_debug(thr_arg1); } - + int ret_val = -1; try{ @@ -1808,11 +1808,11 @@ int count = 0; bool show_msg = false; DateTime dt_limit; - + //delete older backups - boot --------------- var list = get_snapshot_list("boot"); - + if (list.size > count_boot){ log_msg(_("Maximum backups exceeded for backup level") + " '%s'".printf("boot")); while (list.size > count_boot){ @@ -1821,16 +1821,16 @@ list = get_snapshot_list("boot"); } } - + //delete older backups - hourly, daily, weekly, monthly --------- - + string[] levels = { "hourly","daily","weekly","monthly" }; - + foreach(string level in levels){ list = get_snapshot_list(level); - + if (list.size == 0) { continue; } - + switch (level){ case "hourly": dt_limit = now.add_hours(-1 * count_hourly); @@ -1850,9 +1850,9 @@ } if (list[0].date.compare(dt_limit) < 0){ - + log_msg(_("Maximum backups exceeded for backup level") + " '%s'".printf(level)); - + while (list[0].date.compare(dt_limit) < 0){ list[0].remove_tag(level); log_msg(_("Snapshot") + " '%s' ".printf(list[0].name) + _("un-tagged") + " '%s'".printf(level)); @@ -1862,18 +1862,18 @@ } //delete older backups - max days ------- - + show_msg = true; count = 0; foreach(TimeShiftBackup bak in snapshot_list){ if (bak.date.compare(now.add_days(-1 * retain_snapshots_max_days)) < 0){ if (!bak.has_tag("ondemand")){ - + if (show_msg){ log_msg(_("Removing backups older than") + " %d ".printf(retain_snapshots_max_days) + _("days...")); show_msg = false; } - + log_msg(_("Snapshot") + " '%s' ".printf(bak.name) + _("un-tagged")); bak.tags.clear(); count++; @@ -1884,7 +1884,7 @@ delete_untagged_snapshots(); //delete older backups - minimum space ------- - + update_partition_list(); show_msg = true; @@ -1893,7 +1893,7 @@ list = get_snapshot_list(); if (list.size > 0){ if (!list[0].has_tag("ondemand")){ - + if (show_msg){ log_msg(_("Free space is less than") + " %d GB".printf(minimum_free_disk_space_mb)); log_msg(_("Removing older backups to free disk space")); @@ -1906,29 +1906,29 @@ update_partition_list(); //TODO: update snapshot_device only } } - + public void delete_untagged_snapshots(){ bool show_msg = true; foreach(TimeShiftBackup bak in snapshot_list){ if (bak.tags.size == 0){ - + if (show_msg){ log_msg(_("Removing un-tagged snapshots...")); show_msg = false; } - + delete_snapshot(bak); } } } - + public void create_symlinks(){ string cmd = ""; string std_out; string std_err; int ret_val; - + try{ cleanup_symlink_dir("boot"); cleanup_symlink_dir("hourly"); @@ -1936,16 +1936,16 @@ cleanup_symlink_dir("weekly"); cleanup_symlink_dir("monthly"); cleanup_symlink_dir("ondemand"); - + string path; - + foreach(TimeShiftBackup bak in snapshot_list){ foreach(string tag in bak.tags){ path = mount_point_backup + "/timeshift/snapshots-%s".printf(tag); - cmd = "ln --symbolic \"../snapshots/%s\" -t \"%s\"".printf(bak.name, path); - + cmd = "ln --symbolic \"../snapshots/%s\" -t \"%s\"".printf(bak.name, path); + if (LOG_COMMANDS) { log_debug(cmd); } - + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); if (ret_val != 0){ log_error (std_err); @@ -1954,28 +1954,28 @@ } } } - + log_debug (_("Symlinks updated")); - } + } catch (Error e) { log_error (e.message); } } - + public void cleanup_symlink_dir(string tag){ string cmd = ""; string std_out; string std_err; int ret_val; - + try{ string path = mount_point_backup + "/timeshift/snapshots-%s".printf(tag); var f = File.new_for_path(path); if (f.query_exists()){ - cmd = "rm -rf \"%s\"".printf(path + "/"); - + cmd = "rm -rf \"%s\"".printf(path + "/"); + if (LOG_COMMANDS) { log_debug(cmd); } - + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); if (ret_val != 0){ log_error (std_err); @@ -1983,69 +1983,69 @@ return; } } - + f.make_directory_with_parents(); - } + } catch (Error e) { log_error (e.message); } } public void save_exclude_list(string snapshot_path){ - + try{ - + Gee.ArrayList combined_list = new Gee.ArrayList(); - + //add default entries foreach(string path in exclude_list_default){ if (!combined_list.contains(path)){ combined_list.add(path); } } - + //add default extra entries foreach(string path in exclude_list_default_extra){ if (!combined_list.contains(path)){ combined_list.add(path); } } - + //add user entries from current settings foreach(string path in exclude_list_user){ if (!combined_list.contains(path)){ combined_list.add(path); } } - + //add home entries foreach(string path in exclude_list_home){ if (!combined_list.contains(path)){ combined_list.add(path); } } - + string timeshift_path = "/timeshift/*"; if (!combined_list.contains(timeshift_path)){ combined_list.add(timeshift_path); } - + //write file ----------- - + string list_file = snapshot_path + "/exclude.list"; string file_text = ""; - + var f = File.new_for_path(list_file); if (f.query_exists()){ f.delete(); } - + foreach(string path in combined_list){ file_text += path + "\n"; } - + write_file(list_file,file_text); - } + } catch (Error e) { log_error (e.message); } @@ -2068,13 +2068,13 @@ var node = new Json.Node(NodeType.OBJECT); node.set_object(config); json.set_root(node); - + try{ var f = File.new_for_path(ctl_path); if (f.query_exists()){ f.delete(); } - + json.to_file(ctl_path); } catch (Error e) { log_error (e.message); @@ -2084,7 +2084,7 @@ } //restore - + public void get_backup_device_from_cmd(bool prompt_if_empty, Gtk.Window? parent_win){ if (cmd_backup_device.length > 0){ //set backup device from command line argument @@ -2107,18 +2107,18 @@ if ((snapshot_device == null) || (prompt_if_empty && (snapshot_list.size == 0))){ //prompt user for backup device log_msg(""); - + log_msg(TERM_COLOR_YELLOW + _("Select backup device") + ":\n" + TERM_COLOR_RESET); list_devices(); log_msg(""); - + snapshot_device = null; while (snapshot_device == null){ stdout.printf(TERM_COLOR_YELLOW + _("Enter device name or number (a=Abort)") + ": " + TERM_COLOR_RESET); stdout.flush(); snapshot_device = read_stdin_device(partition_list); } - + log_msg(""); if (snapshot_device != null){ @@ -2128,13 +2128,13 @@ } } } - + public bool restore_snapshot(Gtk.Window? parent_win){ bool found = false; - + //set snapshot device ----------------------------------------------- - - if (!mirror_system){ + + if (!mirror_system){ if (snapshot_device != null){ //print snapshot_device name log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET); @@ -2149,15 +2149,15 @@ return false; } } - + //set snapshot ----------------------------------------------- - + if (!mirror_system){ - + if (app_mode != ""){ //command-line mode - - if (cmd_snapshot.length > 0){ - + + if (cmd_snapshot.length > 0){ + //check command line arguments found = false; foreach(TimeShiftBackup bak in snapshot_list) { @@ -2167,22 +2167,22 @@ break; } } - + //check if found if (!found){ log_error(_("Could not find snapshot") + ": '%s'".printf(cmd_snapshot)); return false; } } - + //prompt user for snapshot if (snapshot_to_restore == null){ - + if (snapshot_list.size == 0){ log_error(_("No snapshots found on device") + ": '%s'".printf(snapshot_device.device)); return false; } - + log_msg(""); log_msg(TERM_COLOR_YELLOW + _("Select snapshot to restore") + ":\n" + TERM_COLOR_RESET); list_snapshots(true); @@ -2196,7 +2196,7 @@ log_msg(""); } } - + if (snapshot_to_restore != null){ //print snapshot name log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET); @@ -2209,13 +2209,13 @@ return false; } } - + //set target device ----------------------------------------------- - + if (app_mode != ""){ //command line mode - if (cmd_target_device.length > 0){ - + if (cmd_target_device.length > 0){ + //check command line arguments found = false; foreach(Device pi in partition_list) { @@ -2236,7 +2236,7 @@ if (found){ break; } } } - + //check if found if (!found){ log_error(_("Could not find device") + ": '%s'".printf(cmd_target_device)); @@ -2245,7 +2245,7 @@ return false; } } - + //prompt user for target device if (restore_target == null){ log_msg(""); @@ -2261,7 +2261,7 @@ log_msg(""); } } - + if (restore_target != null){ string symlink = ""; foreach(string sym in restore_target.symlinks){ @@ -2269,7 +2269,7 @@ symlink = sym; } } - + //print target device name log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET); log_msg(_("Target Device") + ": %s".printf(restore_target.full_name_with_alias), true); @@ -2280,9 +2280,9 @@ log_error(_("Target device not specified!")); return false; } - + //select other devices in mount_list -------------------- - + if (app_mode != ""){ //command line mode init_mount_list(); @@ -2290,16 +2290,16 @@ MountEntry mnt = mount_list[i]; Device dev = null; string default_device = ""; - + if (mnt.mount_point == "/"){ continue; } - + if (mirror_system){ default_device = restore_target.device; } else{ default_device = mnt.device.device; } - + //prompt user for device if (dev == null){ log_msg(""); @@ -2315,13 +2315,13 @@ } log_msg(""); } - + if (dev != null){ mnt.device = dev; if (dev.device == restore_target.device){ mount_list.remove_at(i); } - + log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET); if (dev.device == restore_target.device){ log_msg(_("'%s' will be on root device").printf(mnt.mount_point), true); @@ -2333,9 +2333,9 @@ } } } - + //mount selected devices --------------------------------------- - + if (restore_target != null){ if (app_mode != ""){ //commandline mode //mount target device and other devices @@ -2353,13 +2353,13 @@ log_error(_("Target device not specified!")); return false; } - + //set grub device ----------------------------------------------- if (app_mode != ""){ //command line mode - - if (cmd_grub_device.length > 0){ - + + if (cmd_grub_device.length > 0){ + //check command line arguments found = false; list_grub_devices(false); @@ -2383,7 +2383,7 @@ } } } - + //check if found if (!found){ log_error(_("Could not find device") + ": '%s'".printf(cmd_grub_device)); @@ -2392,7 +2392,7 @@ return false; } } - + if ((cmd_skip_grub == false) && (reinstall_grub2 == false)){ log_msg(""); @@ -2401,8 +2401,8 @@ stdout.flush(); read_stdin_grub_install(); } - } - + } + if ((reinstall_grub2) && (grub_device.length == 0)){ log_msg(""); log_msg(TERM_COLOR_YELLOW + _("Select GRUB device") + ":\n" + TERM_COLOR_RESET); @@ -2417,7 +2417,7 @@ } log_msg(""); } - + if ((reinstall_grub2) && (grub_device.length > 0)){ log_msg(TERM_COLOR_YELLOW + string.nfill(78, '*') + TERM_COLOR_RESET); log_msg(_("GRUB Device") + ": %s".printf(grub_device), true); @@ -2435,7 +2435,7 @@ msg += "\n"; msg = msg.replace("",TERM_COLOR_RED).replace("",TERM_COLOR_RESET); log_msg(msg); - + while (cmd_confirm == false){ stdout.printf(TERM_COLOR_YELLOW + _("Continue with restore? (y/n): ") + TERM_COLOR_RESET); stdout.flush(); @@ -2447,26 +2447,26 @@ thr_running = true; thr_success = false; Thread.create (restore_snapshot_thread, true); - } + } catch (ThreadError e) { thr_running = false; thr_success = false; log_error (e.message); } - + while (thr_running){ gtk_do_events (); Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 100); } - + snapshot_to_restore = null; - + return thr_success; } - + public void init_mount_list(){ mount_list.clear(); - + Gee.ArrayList fstab_list = null; if (mirror_system){ string fstab_path = "/etc/fstab"; @@ -2476,7 +2476,7 @@ string fstab_path = snapshot_to_restore.path + "/localhost/etc/fstab"; fstab_list = FsTabEntry.read_fstab_file(fstab_path); } - + foreach(FsTabEntry mnt in fstab_list){ switch(mnt.mount_point){ case "/": @@ -2505,7 +2505,7 @@ if (mnt_dev != null) { break; } } } - } + } if (mnt_dev != null){ mount_list.add(new MountEntry(mnt_dev, mnt.mount_point)); } @@ -2517,13 +2517,13 @@ log_msg("Entry:%s -> %s".printf(mnt.device.device,mnt.mount_point)); }*/ } - + public string unlock_encrypted_device(Device dev, Gtk.Window? parent_win){ string mapped_name = "%s_unlocked".printf(dev.name); string[] name_list = { "%s_unlocked".printf(dev.name), "%s_crypt".printf(dev.name), "luks-%s".printf(dev.uuid)}; - + if ((parent_win == null)&&(app_mode != "")){ - + //check if unlocked foreach(string name in name_list){ if (device_exists("/dev/mapper/%s".printf(name))){ @@ -2533,7 +2533,7 @@ return name; } } - + start_timeout_counter("cryptsetup"); //prompt user to unlock @@ -2541,7 +2541,7 @@ int retval = Posix.system(cmd); stop_timeout_counter(); log_msg(""); - + switch (retval){ case 512: //invalid passphrase log_error(_("Wrong Passphrase") + ": " + _("Failed to unlock device")); @@ -2569,13 +2569,13 @@ return name; } } - + //prompt user to unlock string passphrase = gtk_inputbox(_("Encrypted Device"), _("Enter passphrase to unlock '%s'").printf(dev.name), parent_win, true); string cmd = "echo '%s' | cryptsetup luksOpen '%s' '%s'".printf(passphrase, dev.device, mapped_name); int retval = execute_script_sync(cmd, false); log_debug("cryptsetup:" + retval.to_string()); - + switch(retval){ case 512: //invalid passphrase gtk_messagebox(_("Wrong Passphrase"),_("Wrong Passphrase") + ": " + _("Failed to unlock device"), parent_win); @@ -2595,14 +2595,14 @@ return mapped_name; } } - + public Device? unlock_and_find_device(Device enc_dev, Gtk.Window? parent_win){ if (enc_dev.type == "luks"){ string mapped_name = unlock_encrypted_device(enc_dev, parent_win); string mapped_device = "/dev/mapper/%s".printf(mapped_name); if (mapped_name.length == 0) { return null; } enc_dev = null; - + //find unlocked device if (mapped_name.length > 0){ foreach(Device dev in partition_list){ @@ -2613,41 +2613,41 @@ } } } - + return null; } else{ return enc_dev; } } - + public string disclaimer_pre_restore(){ string msg = ""; msg += "" + _("WARNING") + ":\n\n"; msg += _("Files will be overwritten on the target device!") + "\n"; msg += _("If restore fails and you are unable to boot the system, \nthen boot from the Ubuntu Live CD, install Timeshift, and try again.") + "\n"; - + if ((root_device != null) && (restore_target.device == root_device.device)){ msg += "\n" + _("Please save your work and close all applications.") + "\n"; msg += _("System will reboot to complete the restore process.") + "\n"; } - + msg += "\n"; msg += "" + _("DISCLAIMER") + ":\n\n"; msg += _("This software comes without absolutely NO warranty and the author takes\nno responsibility for any damage arising from the use of this program."); msg += "\n" + _("If these terms are not acceptable to you, please do not proceed\nbeyond this point!"); return msg; } - + public void restore_snapshot_thread(){ string sh = ""; int ret_val = -1; string temp_script; try{ - + string source_path = ""; - + if (snapshot_to_restore != null){ source_path = snapshot_to_restore.path; } @@ -2657,12 +2657,12 @@ create_dir(source_path); } } - + //set target path ---------------- - + bool restore_current_system; string target_path; - + if ((root_device != null) && ((restore_target.device == root_device.device) || (restore_target.uuid == root_device.uuid))){ restore_current_system = true; target_path = "/"; @@ -2670,7 +2670,7 @@ else{ restore_current_system = false; target_path = mount_point_restore + "/"; - + if (mount_point_restore.strip().length == 0){ log_error(_("Target device is not mounted")); thr_success = false; @@ -2680,11 +2680,11 @@ } //save exclude list for restore -------------- - + save_exclude_list_for_restore(source_path); - + //create script ------------- - + sh = ""; sh += "echo ''\n"; if (restore_current_system){ @@ -2693,20 +2693,20 @@ } sh += "echo ''\n"; sh += "sleep 3s\n"; - + //log file var log_path = source_path + "/rsync-log-restore"; var f = File.new_for_path(log_path); if (f.query_exists()){ f.delete(); } - + //run rsync ---------- - + sh += "rsync -avir --force --delete-after"; sh += " --log-file=\"%s\"".printf(log_path); sh += " --exclude-from=\"%s\"".printf(source_path + "/exclude-restore.list"); - + if (mirror_system){ sh += " \"%s\" \"%s\" \n".printf("/", target_path); } @@ -2716,9 +2716,9 @@ //sync file system sh += "sync \n"; - + //chroot and re-install grub2 -------- - + if (reinstall_grub2 && (grub_device != null) && (grub_device.length > 0)){ sh += "echo '' \n"; sh += "echo '" + _("Re-installing GRUB2 bootloader...") + "' \n"; @@ -2730,16 +2730,16 @@ sh += "echo '' \n"; sh += "echo '" + _("Synching file systems...") + "' \n"; sh += "sync \n"; - + sh += "echo '' \n"; sh += "echo '" + _("Cleaning up...") + "' \n"; sh += "sync \n"; sh += "for i in /dev /proc /run /sys; do umount -f \"%s$i\"; done \n".printf(target_path); sh += "sync \n"; } - + //reboot if required -------- - + if (restore_current_system){ sh += "echo '' \n"; sh += "echo '" + _("Rebooting system...") + "' \n"; @@ -2748,53 +2748,53 @@ } //check if current system is being restored and do some housekeeping --------- - + if (restore_current_system){ - + //invalidate the .sync snapshot ------- - - string sync_name = ".sync"; - string sync_path = snapshot_dir + "/" + sync_name; + + string sync_name = ".sync"; + string sync_path = snapshot_dir + "/" + sync_name; string control_file_path = sync_path + "/info.json"; - + f = File.new_for_path(control_file_path); if(f.query_exists()){ f.delete(); //delete the control file } - + //save a control file for updating the .sync snapshot ----- - + control_file_path = snapshot_dir + "/.sync-restore"; - + f = File.new_for_path(control_file_path); if(f.query_exists()){ f.delete(); //delete existing file } - + write_file(control_file_path, snapshot_to_restore.path); //save snapshot name } - + //run the script -------------------- - + if (snapshot_to_restore != null){ log_msg(_("Restoring snapshot...")); } else{ log_msg(_("Cloning system...")); } - + if (app_mode == ""){ //gui if (restore_current_system){ //current system, gui, fullscreen temp_script = create_temp_bash_script(sh); ret_val = execute_bash_script_fullscreen_sync(temp_script); - + if (ret_val == -1){ string msg = _("Failed to find a terminal emulator on this system!") + "\n"; msg += _("Please install one of the following terminal emulators and try again") + ":\n"; msg += "xfce4-terminal gnome-terminal xterm konsole\n\n"; msg += _("No changes were made to system."); - + log_error(msg); string title = _("Error"); @@ -2829,7 +2829,7 @@ } //check for errors ---------------------- - + if (ret_val != 0){ log_error(_("Restore failed with exit code") + ": %d".printf(ret_val)); thr_success = false; @@ -2840,9 +2840,9 @@ thr_success = true; thr_running = false; } - + //update /etc/fstab when restoring to another device -------------------- - + if (!restore_current_system){ string fstab_path = target_path + "etc/fstab"; var fstab_list = FsTabEntry.read_fstab_file(fstab_path); @@ -2855,7 +2855,7 @@ //update fstab entry fstab_entry.device = "UUID=%s".printf(mount_entry.device.uuid); fstab_entry.type = mount_entry.device.type; - + //fix mount options for / and /home if (restore_target.type != "btrfs"){ if ((fstab_entry.mount_point == "/") && fstab_entry.options.contains("subvol=@")){ @@ -2873,7 +2873,7 @@ } } } - + if (!found){ //add new fstab entry FsTabEntry fstab_entry = new FsTabEntry(); @@ -2883,15 +2883,15 @@ fstab_list.add(fstab_entry); } } - - /* + + /* * If user has not mounted /home, and /home is mounted on another device (according to the fstab file) * then remove the /home mount entry from the fstab. * This is required - otherwise when the user boots the restored system they will continue to see * the existing device as /home and instead of seeing the files restored to /home on the *root* device. * We will do this fix only for /home and leave all other mount points untouched. * */ - + bool found_home_in_fstab = false; FsTabEntry fstab_home_entry = null; foreach(FsTabEntry fstab_entry in fstab_list){ @@ -2901,7 +2901,7 @@ break; } } - + bool found_home_in_mount_list = false; foreach(MountEntry mount_entry in mount_list){ if (mount_entry.mount_point == "/home"){ @@ -2916,18 +2916,18 @@ } //write the updated file -------------- - + string text = "# \n\n"; text += FsTabEntry.create_fstab_file(fstab_list.to_array(), false); if (file_exists(fstab_path)){ file_delete(fstab_path); } write_file(fstab_path, text); - + log_msg(_("Updated /etc/fstab on target device") + ": %s".printf(fstab_path)); - + //create folders for mount points in /etc/fstab to prevent mount errors during boot --------- - + foreach(FsTabEntry fstab_entry in fstab_list){ if (fstab_entry.mount_point.length == 0){ continue; } @@ -2951,19 +2951,19 @@ } public void save_exclude_list_for_restore(string file_path){ - + try{ string pattern; - + if (exclude_list_restore.size == 0){ - + //add default entries foreach(string path in exclude_list_default){ if (!exclude_list_restore.contains(path)){ exclude_list_restore.add(path); } } - + if (!mirror_system){ //add default_extra entries foreach(string path in exclude_list_default_extra){ @@ -2972,7 +2972,7 @@ } } } - + //add app entries foreach(AppExcludeEntry entry in exclude_list_apps){ if (entry.enabled){ @@ -2980,21 +2980,21 @@ if (!exclude_list_restore.contains(pattern)){ exclude_list_restore.add(pattern); } - + pattern = entry.pattern(true); if (!exclude_list_restore.contains(pattern)){ exclude_list_restore.add(pattern); } } } - + //add user entries from current settings foreach(string path in exclude_list_user){ if (!exclude_list_restore.contains(path) && !exclude_list_home.contains(path)){ exclude_list_restore.add(path); } } - + //add user entries from snapshot exclude list string list_file = file_path + "/exclude.list"; if (file_exists(list_file)){ @@ -3004,19 +3004,19 @@ } } } - + //add home entries foreach(string path in exclude_list_home){ if (!exclude_list_restore.contains(path)){ exclude_list_restore.add(path); } } - + string timeshift_path = "/timeshift/*"; if (!exclude_list_restore.contains(timeshift_path)){ exclude_list_restore.add(timeshift_path); } - + log_msg(_("Using the default exclude-list")); } else{ @@ -3027,40 +3027,40 @@ if (!exclude_list_restore.contains(timeshift_path)){ exclude_list_restore.add(timeshift_path); } - + //write file ----------- string file_text = ""; string list_file_restore = file_path + "/exclude-restore.list"; - + var f = File.new_for_path(list_file_restore); if (f.query_exists()){ f.delete(); } - + foreach(string path in exclude_list_restore){ file_text += path + "\n"; } write_file(list_file_restore,file_text); - } + } catch (Error e) { log_error (e.message); } } //delete - + public bool delete_snapshot(TimeShiftBackup? snapshot = null){ bool found = false; snapshot_to_delete = snapshot; - + //set snapshot ----------------------------------------------- if (app_mode != ""){ //command-line mode - - if (cmd_snapshot.length > 0){ - + + if (cmd_snapshot.length > 0){ + //check command line arguments found = false; foreach(TimeShiftBackup bak in snapshot_list) { @@ -3070,22 +3070,22 @@ break; } } - + //check if found if (!found){ log_error(_("Could not find snapshot") + ": '%s'".printf(cmd_snapshot)); return false; } } - + //prompt user for snapshot if (snapshot_to_delete == null){ - + if (snapshot_list.size == 0){ log_msg(_("No snapshots found on device") + " '%s'".printf(snapshot_device.device)); return false; } - + log_msg(""); log_msg(TERM_COLOR_YELLOW + _("Select snapshot to delete") + ":\n" + TERM_COLOR_RESET); list_snapshots(true); @@ -3099,7 +3099,7 @@ log_msg(""); } } - + if (snapshot_to_delete == null){ //print error log_error(_("Snapshot to delete not specified!")); @@ -3115,17 +3115,17 @@ thr_success = false; log_error (e.message); } - + while (thr_running){ gtk_do_events (); Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 100); } - + snapshot_to_delete = null; - + return thr_success; } - + public void delete_snapshot_thread(){ string cmd = ""; string std_out; @@ -3133,16 +3133,16 @@ int ret_val; log_msg(_("Removing snapshot") + " '%s'...".printf(snapshot_to_delete.name)); - + try{ var f = File.new_for_path(snapshot_to_delete.path); if(f.query_exists()){ cmd = "rm -rf \"%s\"".printf(snapshot_to_delete.path); - + if (LOG_COMMANDS) { log_debug(cmd); } - + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - + if (ret_val != 0){ log_error(_("Failed to remove") + ": '%s'".printf(snapshot_to_delete.path)); thr_success = false; @@ -3173,34 +3173,34 @@ public bool delete_all_snapshots(){ string timeshift_dir = mount_point_backup + "/timeshift"; string sync_dir = mount_point_backup + "/timeshift/snapshots/.sync"; - - if (dir_exists(timeshift_dir)){ + + if (dir_exists(timeshift_dir)){ //delete snapshots foreach(TimeShiftBackup bak in snapshot_list){ - if (!delete_snapshot(bak)){ - return false; + if (!delete_snapshot(bak)){ + return false; } } - + //delete .sync if (dir_exists(sync_dir)){ - if (!delete_directory(sync_dir)){ - return false; + if (!delete_directory(sync_dir)){ + return false; } } - + //delete /timeshift return delete_directory(timeshift_dir); } else{ log_msg(_("No snapshots found on device") + " '%s'".printf(snapshot_device.device)); - return true; + return true; } } public bool delete_directory(string dir_path){ thr_arg1 = dir_path; - + try { thr_running = true; thr_success = false; @@ -3210,17 +3210,17 @@ thr_success = false; log_error (e.message); } - + while (thr_running){ gtk_do_events (); Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 100); } - + thr_arg1 = null; - + return thr_success; } - + public void delete_directory_thread(){ string cmd = ""; string std_out; @@ -3231,11 +3231,11 @@ var f = File.new_for_path(thr_arg1); if(f.query_exists()){ cmd = "rm -rf \"%s\"".printf(thr_arg1); - + if (LOG_COMMANDS) { log_debug(cmd); } - + Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - + if (ret_val != 0){ log_error(_("Failed to remove") + ": '%s'".printf(thr_arg1)); thr_success = false; @@ -3265,27 +3265,27 @@ //app config - + public void save_app_config(){ var config = new Json.Object(); //config.set_string_member("enabled", is_scheduled.to_string()); - + config.set_string_member("backup_device_uuid", (snapshot_device == null) ? "" : snapshot_device.uuid); - + config.set_string_member("is_scheduled", is_scheduled.to_string()); - + config.set_string_member("schedule_monthly", schedule_monthly.to_string()); config.set_string_member("schedule_weekly", schedule_weekly.to_string()); config.set_string_member("schedule_daily", schedule_daily.to_string()); config.set_string_member("schedule_hourly", schedule_hourly.to_string()); config.set_string_member("schedule_boot", schedule_boot.to_string()); - + config.set_string_member("count_monthly", count_monthly.to_string()); config.set_string_member("count_weekly", count_weekly.to_string()); config.set_string_member("count_daily", count_daily.to_string()); config.set_string_member("count_hourly", count_hourly.to_string()); config.set_string_member("count_boot", count_boot.to_string()); - + config.set_string_member("max_days", retain_snapshots_max_days.to_string()); config.set_string_member("min_space", minimum_free_disk_space_mb.to_string()); @@ -3294,29 +3294,29 @@ arr.add_string_element(path); } config.set_array_member("exclude",arr); - + var json = new Json.Generator(); json.pretty = true; json.indent = 2; var node = new Json.Node(NodeType.OBJECT); node.set_object(config); json.set_root(node); - + try{ json.to_file(this.app_conf_path); } catch (Error e) { log_error (e.message); } - + if ((app_mode == "")||(LOG_DEBUG)){ log_msg(_("App config saved") + ": '%s'".printf(this.app_conf_path)); } } - + public void load_app_config(){ var f = File.new_for_path(this.app_conf_path); if (!f.query_exists()) { return; } - + var parser = new Json.Parser(); try{ parser.load_from_file(this.app_conf_path); @@ -3325,9 +3325,9 @@ } var node = parser.get_root(); var config = node.get_object(); - + string uuid = json_get_string(config,"backup_device_uuid",""); - + foreach(Device pi in partition_list){ if (pi.uuid == uuid){ snapshot_device = pi; @@ -3346,7 +3346,7 @@ exit(1); } } - + if (snapshot_device == null){ if ((root_device != null) && (app_mode == "")){ log_msg (_("Backup device not set! Defaulting to system device") + " '%s'".printf(root_device.device)); @@ -3354,12 +3354,12 @@ } } /* Note: In commandline mode, user will be prompted for backup device instead of defaulting to system device */ - + /* The backup device specified in config file will be mounted at this point if: * 1) app is running in GUI mode, OR * 2) app is running command mode without backup device argument * */ - + if (snapshot_device != null){ if ((app_mode == "") || (cmd_backup_device.length == 0)){ if (mount_backup_device(null)){ @@ -3378,13 +3378,13 @@ this.schedule_daily = json_get_bool(config,"schedule_daily",schedule_daily); this.schedule_hourly = json_get_bool(config,"schedule_hourly",schedule_hourly); this.schedule_boot = json_get_bool(config,"schedule_boot",schedule_boot); - + this.count_monthly = json_get_int(config,"count_monthly",count_monthly); this.count_weekly = json_get_int(config,"count_weekly",count_weekly); this.count_daily = json_get_int(config,"count_daily",count_daily); this.count_hourly = json_get_int(config,"count_hourly",count_hourly); this.count_boot = json_get_int(config,"count_boot",count_boot); - + this.retain_snapshots_max_days = json_get_int(config,"max_days",retain_snapshots_max_days); this.minimum_free_disk_space_mb = json_get_int(config,"min_space",minimum_free_disk_space_mb); @@ -3397,16 +3397,16 @@ } } } - + if ((app_mode == "")||(LOG_DEBUG)){ log_msg(_("App config loaded") + ": '%s'".printf(this.app_conf_path)); } } //core functions - + public bool update_snapshot_list(){ - + snapshot_list.clear(); string path = mount_point_backup + "/timeshift/snapshots"; @@ -3418,7 +3418,7 @@ try{ var dir = File.new_for_path (path); var enumerator = dir.enumerate_children ("*", 0); - + var info = enumerator.next_file (); while (info != null) { if (info.get_file_type() == FileType.DIRECTORY) { @@ -3437,7 +3437,7 @@ return false; } - snapshot_list.sort((a,b) => { + snapshot_list.sort((a,b) => { TimeShiftBackup t1 = (TimeShiftBackup) a; TimeShiftBackup t2 = (TimeShiftBackup) b; return t1.date.compare(t2.date); @@ -3445,17 +3445,17 @@ return true; } - + public Gee.ArrayList partition_list { owned get{ var list = new Gee.ArrayList(); foreach(Device pi in partition_map.values) { list.add(pi); } - list.sort((a,b) => { + list.sort((a,b) => { Device p1 = (Device) a; Device p2 = (Device) b; - + int index = 0; while (index < p1.device.length){ if (Posix.isdigit(p1.device[index])){ @@ -3470,13 +3470,13 @@ } index++; } - + return strcmp(p1.device,p2.device); }); return list; } } - + public void update_partition_list(){ partition_map.clear(); partition_map = Device.get_filesystems(); @@ -3505,15 +3505,15 @@ list.add(bak); } } - list.sort((a,b) => { + list.sort((a,b) => { TimeShiftBackup t1 = (TimeShiftBackup) a; TimeShiftBackup t2 = (TimeShiftBackup) b; - return (t1.date.compare(t2.date)); + return (t1.date.compare(t2.date)); }); return list; } - + public void detect_system_devices(){ foreach(Device pi in partition_list){ if (pi.mount_points.contains("/")){ @@ -3522,7 +3522,7 @@ log_msg(_("/ is mapped to device: %s, UUID=%s").printf(pi.device,pi.uuid)); } } - + if (pi.mount_points.contains("/home")){ home_device = pi; if ((app_mode == "")||(LOG_DEBUG)){ @@ -3531,7 +3531,7 @@ } } } - + public TimeShiftBackup? get_latest_snapshot(string tag = ""){ var list = get_snapshot_list(tag); @@ -3540,10 +3540,10 @@ else return null; } - + public TimeShiftBackup? get_oldest_snapshot(string tag = ""){ var list = get_snapshot_list(tag); - + if (list.size > 0) return list[0]; else @@ -3556,13 +3556,13 @@ * Otherwise existing mount point will be used. * This is required since we need to mount the root subvolume of the BTRFS filesystem * */ - + if (snapshot_device == null){ log_error(_("Backup device not set!")); return false; } else{ - + //unlock if required snapshot_device = unlock_and_find_device(snapshot_device, parent_win); if (snapshot_device == null){ @@ -3615,24 +3615,24 @@ } } } - + public bool mount_target_device(Gtk.Window? parent_win){ /* Note: * Target device will be mounted explicitly to /mnt/timeshift/restore * Existing mount points are not used since we need to mount other devices in sub-directories * */ - + if (restore_target == null){ return false; } else{ //unmount unmount_target_device(); - + //check and create restore mount point for restore mount_point_restore = mount_point_app + "/restore"; check_and_create_dir_with_parents(mount_point_restore); - + //unlock encrypted device if (restore_target.type == "luks"){ restore_target = unlock_and_find_device(restore_target, parent_win); @@ -3642,16 +3642,16 @@ log_error(_("Target device not specified!")); return false; } - + //update mount entry foreach (MountEntry mnt in mount_list) { if (mnt.mount_point == "/"){ - mnt.device = restore_target; - break; + mnt.device = restore_target; + break; } } } - + //mount root device if (restore_target.type == "btrfs"){ @@ -3667,17 +3667,17 @@ else{ log_error("\n" + msg); } - + return false; } - //mount @ + //mount @ if (!mount(restore_target.uuid, mount_point_restore, "subvol=@")){ log_error(_("Failed to mount BTRFS subvolume") + ": @"); return false; } - //mount @home + //mount @home if (!mount(restore_target.uuid, mount_point_restore + "/home", "subvol=@home")){ log_error(_("Failed to mount BTRFS subvolume") + ": @home"); return false; @@ -3688,7 +3688,7 @@ return false; } } - + //mount remaining devices foreach (MountEntry mnt in mount_list) { if (mnt.mount_point != "/"){ @@ -3704,12 +3704,12 @@ } if (!mount(mnt.device.uuid, mount_point_restore + mnt.mount_point)){ - return false; - } + return false; + } } } } - + return true; } @@ -3730,7 +3730,7 @@ //don't unmount } } - + public void unmount_target_device(bool exit_on_error = true){ //unmount the target device only if it was mounted by application if (mount_point_restore.has_prefix(mount_point_app)){ //always true @@ -3740,7 +3740,7 @@ //don't unmount } } - + public bool unmount_device(string mount_point, bool exit_on_error = true){ bool is_unmounted = unmount(mount_point); if (!is_unmounted){ @@ -3758,17 +3758,17 @@ } public int check_backup_device(out string message){ - - /* + + /* -1 - device un-available - 0 - first snapshot taken, disk space sufficient + 0 - first snapshot taken, disk space sufficient 1 - first snapshot taken, disk space not sufficient 2 - first snapshot not taken, disk space not sufficient 3 - first snapshot not taken, disk space sufficient */ int status_code = 0; - + //free space message if ((snapshot_device != null) && (snapshot_device.free.length > 0)){ message = "%s ".printf(snapshot_device.free) + _("free"); @@ -3777,17 +3777,17 @@ else{ message = ""; } - + if (!live_system()){ if (!backup_device_online()){ - + if (snapshot_device == null){ message = _("Please select the backup device"); } else{ message = _("Backup device not available"); } - + status_code = -1; } else{ @@ -3820,29 +3820,29 @@ } log_debug("Checked backup device (status=%d)".printf(status_code)); - + return status_code; } - + public bool check_btrfs_volume(Device dev){ string mnt_btrfs = mount_point_app + "/btrfs"; check_and_create_dir_with_parents(mnt_btrfs); - + unmount(mnt_btrfs); mount(dev.uuid, mnt_btrfs); - + bool is_supported = dir_exists(mnt_btrfs + "/@") && dir_exists(mnt_btrfs + "/@home"); - + if (unmount(mnt_btrfs)){ if (dir_exists(mnt_btrfs) && (get_file_count(mnt_btrfs) == 0)){ file_delete(mnt_btrfs); log_debug(_("Removed mount directory: '%s'").printf(mnt_btrfs)); } } - + return is_supported; } - + public bool backup_device_online(){ if (snapshot_device != null){ mount_backup_device(null); @@ -3854,14 +3854,14 @@ } public long calculate_size_of_first_snapshot(){ - + if (this.first_snapshot_size > 0){ return this.first_snapshot_size; } else if (live_system()){ return 0; } - + try { thr_running = true; thr_success = false; @@ -3871,7 +3871,7 @@ thr_success = false; log_error (e.message); } - + while (thr_running){ gtk_do_events (); Thread.usleep((ulong) GLib.TimeSpan.MILLISECOND * 100); @@ -3879,10 +3879,10 @@ return this.first_snapshot_size; } - + public void calculate_size_of_first_snapshot_thread(){ thr_running = true; - + string cmd = ""; string std_out; string std_err; @@ -3890,26 +3890,26 @@ long required_space = 0; try{ - + var f = File.new_for_path("/tmp/exclude.list"); if (f.query_exists()){ f.delete(); } - + f = File.new_for_path("/tmp/rsync.log"); if (f.query_exists()){ f.delete(); } - + f = File.new_for_path("/tmp/empty"); if (!f.query_exists()){ create_dir("/tmp/empty"); } - + save_exclude_list("/tmp"); - + cmd = "LC_ALL=C ; rsync -ai --delete --numeric-ids --relative --stats --dry-run --delete-excluded --exclude-from=/tmp/exclude.list /. /tmp/empty/ &> /tmp/rsync.log"; - + ret_val = execute_command_script_sync(cmd, out std_out, out std_err); if (ret_val == 0){ cmd = "cat /tmp/rsync.log | awk '/Total file size/ {print $4}'"; @@ -3935,53 +3935,53 @@ log_error (e.message); thr_success = false; } - + if ((required_space == 0) && (root_device != null)){ required_space = root_device.used_mb; } - + this.first_snapshot_size = required_space; - + log_debug("First snapshot size: %ld MB".printf(required_space)); - + thr_running = false; } //cron jobs - + public void cron_job_update(){ - + if (live_system()) { return; } - + string current_entry = ""; string new_entry = ""; bool new_entry_exists = false; string search_string = ""; - + //scheduled job ---------------------------------- - + new_entry = get_crontab_entry_scheduled(); new_entry_exists = false; - + //check and remove crontab entries created by previous versions of timeshift - + search_string = "*/30 * * * * timeshift --backup"; current_entry = crontab_read_entry(search_string); if (current_entry.length > 0) { //remove entry crontab_remove_job(current_entry); - } - + } + //check for regular entries foreach(string interval in new string[] {"@monthly","@weekly","@daily","@hourly"}){ - + search_string = "%s timeshift --backup".printf(interval); - + //read current_entry = crontab_read_entry(search_string); - + if (current_entry.length == 0) { continue; } //not found - + //check if (current_entry == new_entry){ //keep entry @@ -3992,22 +3992,22 @@ crontab_remove_job(current_entry); } } - + //add new entry if missing if (!new_entry_exists && new_entry.length > 0){ crontab_add_job(new_entry); } - + //boot job ---------------------------------- - + search_string = """@reboot sleep [0-9]*m && timeshift --backup"""; - + new_entry = get_crontab_entry_boot(); new_entry_exists = false; - + //read current_entry = crontab_read_entry(search_string, true); - + if (current_entry.length > 0) { //check if (current_entry == new_entry){ @@ -4019,7 +4019,7 @@ crontab_remove_job(current_entry); } } - + //add new entry if missing if (!new_entry_exists && new_entry.length > 0){ crontab_add_job(new_entry); @@ -4029,7 +4029,7 @@ private string get_crontab_entry_scheduled(){ if (is_scheduled && (snapshot_list.size > 0)){ if (schedule_hourly){ - return "@hourly timeshift --backup"; + return "@hourly timeshift --backup"; } else if (schedule_daily){ return "@daily timeshift --backup"; @@ -4041,7 +4041,7 @@ return "@monthly timeshift --backup"; } } - + return ""; } @@ -4051,13 +4051,13 @@ return "@reboot sleep %dm && timeshift --backup".printf(startup_delay_interval_mins); } } - + return ""; } - + private bool crontab_add_job(string entry){ if (live_system()) { return false; } - + if (crontab_add(entry)){ log_msg(_("Cron job added") + ": %s".printf(entry)); return true; @@ -4067,10 +4067,10 @@ return false; } } - + private bool crontab_remove_job(string search_string){ if (live_system()) { return false; } - + if (crontab_remove(search_string)){ log_msg(_("Cron job removed") + ": %s".printf(search_string)); return true; @@ -4082,18 +4082,18 @@ } //cleanup - + public void clean_logs(){ - + Gee.ArrayList list = new Gee.ArrayList(); - + try{ var dir = File.new_for_path (log_dir); var enumerator = dir.enumerate_children ("*", 0); - + var info = enumerator.next_file (); string path; - + while (info != null) { if (info.get_file_type() == FileType.REGULAR) { path = log_dir + "/" + info.get_name(); @@ -4107,9 +4107,9 @@ CompareDataFunc compare_func = (a, b) => { return strcmp(a,b); }; - + list.sort((owned) compare_func); - + if (list.size > 500){ for(int k=0; k<100; k++){ var file = File.new_for_path (list[k]); @@ -4124,25 +4124,25 @@ log_error (e.message); } } - + public void exit_app (){ - + if (app_mode == ""){ //update app config only in GUI mode save_app_config(); } - + cron_job_update(); - + unmount_backup_device(false); unmount_target_device(false); - + clean_logs(); remove_lock(); //Gtk.main_quit (); } - + public bool is_rsync_running(){ string cmd = "rsync -ai --delete --numeric-ids --relative --delete-excluded"; string txt = execute_command_sync_get_output ("ps w -C rsync"); @@ -4153,7 +4153,7 @@ } return false; } - + public void kill_rsync(){ string cmd = "rsync -ai --delete --numeric-ids --relative --delete-excluded"; string txt = execute_command_sync_get_output ("ps w -C rsync"); @@ -4181,22 +4181,22 @@ public Gee.ArrayList exclude_list; public Gee.ArrayList fstab_list; public bool is_valid = true; - + public TimeShiftBackup(string dir_path){ - + try{ var f = File.new_for_path(dir_path); var info = f.query_info("*", FileQueryInfoFlags.NONE); - + path = dir_path; name = info.get_name(); description = ""; - + date = new DateTime.from_unix_utc(0); tags = new Gee.ArrayList(); exclude_list = new Gee.ArrayList(); fstab_list = new Gee.ArrayList(); - + read_control_file(); read_exclude_list(); read_fstab_file(); @@ -4205,7 +4205,7 @@ log_error (e.message); } } - + public string taglist{ owned get{ string str = ""; @@ -4223,7 +4223,7 @@ } } } - + public string taglist_short{ owned get{ string str = ""; @@ -4233,28 +4233,28 @@ return str.strip(); } } - + public void add_tag(string tag){ if (!tags.contains(tag.strip())){ tags.add(tag.strip()); update_control_file(); } } - + public void remove_tag(string tag){ if (tags.contains(tag.strip())){ tags.remove(tag.strip()); update_control_file(); } } - + public bool has_tag(string tag){ return tags.contains(tag.strip()); } - + public void read_control_file(){ string ctl_file = path + "/info.json"; - + var f = File.new_for_path(ctl_file); if (f.query_exists()) { var parser = new Json.Parser(); @@ -4265,15 +4265,15 @@ } var node = parser.get_root(); var config = node.get_object(); - - + + if ((node == null)||(config == null)){ is_valid = false; return; } - + string val = json_get_string(config,"created",""); - if (val.length > 0) { + if (val.length > 0) { DateTime date_utc = new DateTime.from_unix_utc(int64.parse(val)); date = date_utc.to_local(); } @@ -4291,9 +4291,9 @@ public void read_exclude_list(){ string list_file = path + "/exclude.list"; - + exclude_list.clear(); - + var f = File.new_for_path(list_file); if (f.query_exists()) { foreach(string path in read_file(list_file).split("\n")){ @@ -4307,12 +4307,12 @@ is_valid = false; } } - + public void read_fstab_file(){ string fstab_path = path + "/localhost/etc/fstab"; - fstab_list = FsTabEntry.read_fstab_file(fstab_path); + fstab_list = FsTabEntry.read_fstab_file(fstab_path); } - + public bool has_subvolumes(){ foreach(FsTabEntry en in fstab_list){ if (en.options.contains("subvol=@")){ @@ -4321,14 +4321,14 @@ } return false; } - + public void update_control_file(){ try{ string ctl_file = path + "/info.json"; var f = File.new_for_path(ctl_file); - + if (f.query_exists()) { - + var parser = new Json.Parser(); try{ parser.load_from_file(ctl_file); @@ -4340,7 +4340,7 @@ config.set_string_member("tags", taglist); config.set_string_member("comments", description); - + var json = new Json.Generator(); json.pretty = true; json.indent = 2; @@ -4360,20 +4360,19 @@ public bool is_include = false; public bool is_file = false; public bool enabled = false; - + public AppExcludeEntry(string _relpath, bool _is_file, bool _is_include = false){ relpath = _relpath; is_file = _is_file; is_include = _is_include; } - + public string pattern(bool root_home = false){ string str = (is_include) ? "+ " : ""; str += (root_home) ? "/root" : "/home/*"; str += relpath[1:relpath.length]; str += (is_file) ? "" : "/**"; - return str.strip(); + return str.strip(); } - -} +} diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/MainWindow.vala timeshift-1.7.4~178~ubuntu14.04.1/src/MainWindow.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/MainWindow.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/MainWindow.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,26 +1,26 @@ /* * MainWindow.vala - * + * * Copyright 2013 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ - + using Gtk; using Gee; @@ -35,9 +35,9 @@ using TeeJee.Misc; class MainWindow : Gtk.Window{ - + private Box vbox_main; - + //snapshots private Toolbar toolbar; private ToolButton btn_backup; @@ -51,14 +51,14 @@ private ToolButton btn_view_app_logs; private ToolButton btn_about; private ToolButton btn_donate; - + //backup device private Box hbox_device; private Label lbl_backup_device; private ComboBox cmb_backup_device; private Button btn_refresh_backup_device_list; private Label lbl_backup_device_warning; - + //snapshots private ScrolledWindow sw_backups; private TreeView tv_backups; @@ -68,7 +68,7 @@ private TreeViewColumn col_desc; private int tv_backups_sort_column_index = 0; private bool tv_backups_sort_column_desc = true; - + //statusbar private Box hbox_statusbar; private Gtk.Image img_status_spinner; @@ -81,12 +81,12 @@ private Label lbl_status_device; private Gtk.Image img_status_device; private Gtk.Image img_status_progress; - + //timers private uint timer_status_message; private uint timer_progress; private uint timer_backup_device_init; - + //other private Device snapshot_device_original; @@ -97,14 +97,14 @@ this.set_default_size (700, 500); this.delete_event.connect(on_delete_event); this.icon = get_app_icon(16); - + //vboxMain vbox_main = new Box (Orientation.VERTICAL, 0); vbox_main.margin = 0; add (vbox_main); - + //toolbar --------------------------------------------------- - + //toolbar toolbar = new Gtk.Toolbar (); toolbar.toolbar_style = ToolbarStyle.BOTH_HORIZ; @@ -129,7 +129,7 @@ toolbar.add(btn_restore); btn_restore.clicked.connect (btn_restore_clicked); - + //btn_browse_snapshot btn_browse_snapshot = new Gtk.ToolButton.from_stock ("gtk-directory"); btn_browse_snapshot.is_important = true; @@ -138,7 +138,7 @@ toolbar.add(btn_browse_snapshot); btn_browse_snapshot.clicked.connect (btn_browse_snapshot_clicked); - + //btn_delete_snapshot btn_delete_snapshot = new Gtk.ToolButton.from_stock ("gtk-delete"); btn_delete_snapshot.is_important = true; @@ -156,7 +156,7 @@ toolbar.add(btn_settings); btn_settings.clicked.connect (btn_settings_clicked); - + //separator var separator = new Gtk.SeparatorToolItem(); separator.set_draw (false); @@ -171,7 +171,7 @@ toolbar.add(btn_clone); btn_clone.clicked.connect (btn_clone_clicked); - + //btn_refresh_snapshots btn_refresh_snapshots = new Gtk.ToolButton.from_stock ("gtk-refresh"); btn_refresh_snapshots.label = _("Refresh"); @@ -191,7 +191,7 @@ toolbar.add(btn_view_snapshot_log); btn_view_snapshot_log.clicked.connect (btn_view_snapshot_log_clicked); - + //btn_view_app_logs btn_view_app_logs = new Gtk.ToolButton.from_stock ("gtk-file"); btn_view_app_logs.label = _("TimeShift Logs"); @@ -199,14 +199,14 @@ toolbar.add(btn_view_app_logs); btn_view_app_logs.clicked.connect (btn_view_app_logs_clicked); - + //btn_donate btn_donate = new Gtk.ToolButton.from_stock ("gtk-missing-image"); btn_donate.label = _("Donate"); btn_donate.set_tooltip_text (_("Donate")); btn_donate.icon_widget = get_shared_icon("donate","donate.svg",24); toolbar.add(btn_donate); - + btn_donate.clicked.connect(btn_donate_clicked); //btn_about @@ -219,7 +219,7 @@ btn_about.clicked.connect (btn_about_clicked); //backup device ------------------------------------------------ - + //hbox_device hbox_device = new Box (Orientation.HORIZONTAL, 6); hbox_device.margin_top = 6; @@ -231,39 +231,39 @@ lbl_backup_device = new Gtk.Label(_("Backup Device")); lbl_backup_device.xalign = (float) 0.0; hbox_device.add(lbl_backup_device); - + //cmb_backup_device cmb_backup_device = new ComboBox (); cmb_backup_device.hexpand = true; cmb_backup_device.set_tooltip_markup(_("Snapshots will be saved in path /timeshift on selected device")); hbox_device.add(cmb_backup_device); - + CellRendererText cell_backup_dev_margin = new CellRendererText (); cell_backup_dev_margin.text = ""; cmb_backup_device.pack_start (cell_backup_dev_margin, false); - + CellRendererPixbuf cell_backup_dev_icon = new CellRendererPixbuf (); cell_backup_dev_icon.xpad = 1; cmb_backup_device.pack_start (cell_backup_dev_icon, false); cmb_backup_device.set_attributes(cell_backup_dev_icon, "pixbuf", 1); - + CellRendererText cell_backup_device = new CellRendererText(); cmb_backup_device.pack_start( cell_backup_device, false ); cmb_backup_device.set_cell_data_func (cell_backup_device, cell_backup_device_render); cmb_backup_device.changed.connect(cmb_backup_device_changed); - + //btn_refresh_backup_device_list btn_refresh_backup_device_list = new Gtk.Button.with_label (" " + _("Refresh") + " "); btn_refresh_backup_device_list.set_size_request(50,-1); btn_refresh_backup_device_list.set_tooltip_text(_("Refresh Devices")); - btn_refresh_backup_device_list.clicked.connect(()=>{ + btn_refresh_backup_device_list.clicked.connect(()=>{ App.update_partition_list(); - refresh_cmb_backup_device(); + refresh_cmb_backup_device(); refresh_tv_backups(); }); hbox_device.add(btn_refresh_backup_device_list); - + //lbl_backup_device_warning lbl_backup_device_warning = new Gtk.Label(""); lbl_backup_device_warning.set_use_markup(true); @@ -275,14 +275,14 @@ vbox_main.add(lbl_backup_device_warning); //snapshot list ---------------------------------------------- - + //tv_backups tv_backups = new TreeView(); tv_backups.get_selection().mode = SelectionMode.MULTIPLE; tv_backups.headers_clickable = true; tv_backups.has_tooltip = true; tv_backups.set_rules_hint (true); - + //sw_backups sw_backups = new ScrolledWindow(null, null); sw_backups.set_shadow_type (ShadowType.ETCHED_IN); @@ -300,18 +300,18 @@ col_date.clickable = true; col_date.resizable = true; col_date.spacing = 1; - + CellRendererPixbuf cell_backup_icon = new CellRendererPixbuf (); cell_backup_icon.stock_id = "gtk-floppy"; cell_backup_icon.xpad = 1; col_date.pack_start (cell_backup_icon, false); - + CellRendererText cell_date = new CellRendererText (); col_date.pack_start (cell_date, false); col_date.set_cell_data_func (cell_date, cell_date_render); - + tv_backups.append_column(col_date); - + col_date.clicked.connect(() => { if(tv_backups_sort_column_index == 0){ tv_backups_sort_column_desc = !tv_backups_sort_column_desc; @@ -322,20 +322,20 @@ } refresh_tv_backups(); }); - + //col_system col_system = new TreeViewColumn(); col_system.title = _("System"); col_system.resizable = true; col_system.clickable = true; col_system.min_width = 150; - + CellRendererText cell_system = new CellRendererText (); cell_system.ellipsize = Pango.EllipsizeMode.END; col_system.pack_start (cell_system, false); col_system.set_cell_data_func (cell_system, cell_system_render); tv_backups.append_column(col_system); - + col_system.clicked.connect(() => { if(tv_backups_sort_column_index == 1){ tv_backups_sort_column_desc = !tv_backups_sort_column_desc; @@ -346,7 +346,7 @@ } refresh_tv_backups(); }); - + //col_tags col_tags = new TreeViewColumn(); col_tags.title = _("Tags"); @@ -358,7 +358,7 @@ col_tags.pack_start (cell_tags, false); col_tags.set_cell_data_func (cell_tags, cell_tags_render); tv_backups.append_column(col_tags); - + col_tags.clicked.connect(() => { if(tv_backups_sort_column_index == 2){ tv_backups_sort_column_desc = !tv_backups_sort_column_desc; @@ -381,9 +381,9 @@ col_desc.set_cell_data_func (cell_desc, cell_desc_render); tv_backups.append_column(col_desc); cell_desc.editable = true; - + cell_desc.edited.connect (cell_desc_edited); - + //tooltips tv_backups.query_tooltip.connect ((x, y, keyboard_tooltip, tooltip) => { TreeModel model; @@ -415,7 +415,7 @@ return false; }); - + //hbox_statusbar hbox_statusbar = new Box (Orientation.HORIZONTAL, 6); hbox_statusbar.margin_bottom = 1; @@ -428,13 +428,13 @@ img_status_spinner.file = App.share_folder + "/timeshift/images/spinner.gif"; img_status_spinner.no_show_all = true; hbox_statusbar.add(img_status_spinner); - + //img_status_dot img_status_dot = new Gtk.Image(); img_status_dot.file = App.share_folder + "/timeshift/images/item-green.gif"; img_status_dot.no_show_all = true; hbox_statusbar.add(img_status_dot); - + //lbl_status lbl_status = new Gtk.Label(""); lbl_status.no_show_all = true; @@ -444,77 +444,77 @@ img_status_device = new Gtk.Image(); img_status_device.no_show_all = true; hbox_statusbar.add(img_status_device); - + //lbl_status_device lbl_status_device = new Gtk.Label(""); lbl_status_device.set_use_markup(true); lbl_status_device.no_show_all = true; hbox_statusbar.add(lbl_status_device); - + //img_status_scheduled img_status_scheduled = new Gtk.Image(); img_status_scheduled.no_show_all = true; hbox_statusbar.add(img_status_scheduled); - + //lbl_status_scheduled lbl_status_scheduled = new Gtk.Label(""); lbl_status_scheduled.set_use_markup(true); lbl_status_scheduled.no_show_all = true; hbox_statusbar.add(lbl_status_scheduled); - + //img_status_latest img_status_latest = new Gtk.Image(); img_status_latest.no_show_all = true; hbox_statusbar.add(img_status_latest); - + //lbl_status_latest lbl_status_latest = new Gtk.Label(""); lbl_status_latest.set_use_markup(true); lbl_status_latest.no_show_all = true; hbox_statusbar.add(lbl_status_latest); - + //lbl_status_separator Label lbl_status_separator = new Gtk.Label(""); hbox_statusbar.hexpand = true; hbox_statusbar.pack_start(lbl_status_separator,true,true,0); - + //img_status_progress img_status_progress = new Gtk.Image(); img_status_progress.file = App.share_folder + "/timeshift/images/progress.gif"; img_status_progress.no_show_all = true; hbox_statusbar.add(img_status_progress); - + snapshot_device_original = App.snapshot_device; - + if (App.live_system()){ btn_backup.sensitive = false; btn_clone.sensitive = false; btn_settings.sensitive = false; btn_view_app_logs.sensitive = false; } - + refresh_cmb_backup_device(); timer_backup_device_init = Timeout.add(100, init_backup_device); } private bool init_backup_device(){ - + /* updates statusbar messages and snapshot list after backup device is changed */ - + if (timer_backup_device_init > 0){ Source.remove(timer_backup_device_init); - timer_backup_device_init = -1; + timer_backup_device_init = 0; } - + update_ui(false); - + if (App.live_system()){ statusbar_message(_("Checking backup device...")); } else{ statusbar_message(_("Estimating system size...")); } - + //refresh_cmb_backup_device(); refresh_tv_backups(); update_statusbar(); @@ -522,9 +522,9 @@ return false; } - + private bool on_delete_event(Gdk.EventAny event){ - + this.delete_event.disconnect(on_delete_event); //disconnect this handler if (App.is_rsync_running()){ @@ -535,9 +535,9 @@ if (!App.is_scheduled){ return false; //close window } - + //else - check backup device ------------------------------- - + string message; int status_code = App.check_backup_device(out message); @@ -553,7 +553,7 @@ dialog.set_modal(true); int response = dialog.run(); dialog.destroy(); - + if (response == Gtk.ResponseType.OK){ App.is_scheduled = false; return false; //close window @@ -567,7 +567,7 @@ string msg = _("Selected device does not have enough space.") + "\n"; msg += _("Scheduled snapshots will be disabled till another device is selected.") + "\n"; msg += _("Do you want to select another device now?") + "\n"; - + var dialog = new Gtk.MessageDialog.with_markup(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO, msg); dialog.set_title(_("Disable Scheduled Snapshots")); dialog.set_default_size (300, -1); @@ -575,7 +575,7 @@ dialog.set_modal(true); int response = dialog.run(); dialog.destroy(); - + if (response == Gtk.ResponseType.YES){ this.delete_event.connect(on_delete_event); //reconnect this handler return true; //keep window open @@ -584,12 +584,12 @@ App.is_scheduled = false; return false; //close window } - + case 3: string msg = _("Scheduled jobs will be enabled only after the first snapshot is taken.") + "\n"; msg += message + (" space and 10 minutes to complete.") + "\n"; msg += _("Do you want to take the first snapshot now?") + "\n"; - + var dialog = new Gtk.MessageDialog.with_markup(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO, msg); dialog.set_title(_("First Snapshot")); dialog.set_default_size (300, -1); @@ -597,7 +597,7 @@ dialog.set_modal(true); int response = dialog.run(); dialog.destroy(); - + if (response == Gtk.ResponseType.YES){ btn_backup_clicked(); this.delete_event.connect(on_delete_event); //reconnect this handler @@ -607,14 +607,14 @@ App.is_scheduled = false; return false; //close window } - + case 0: if (App.snapshot_device.uuid != snapshot_device_original.uuid){ log_debug(_("snapshot device changed")); - + string msg = _("Scheduled snapshots will be saved to ") + "%s\n".printf(App.snapshot_device.device); msg += _("Click 'OK' to confirm") + "\n"; - + var dialog = new Gtk.MessageDialog.with_markup(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO, Gtk.ButtonsType.OK_CANCEL, msg); dialog.set_title(_("Backup Device Changed")); dialog.set_default_size (300, -1); @@ -622,14 +622,14 @@ dialog.set_modal(true); int response = dialog.run(); dialog.destroy(); - + if (response == Gtk.ResponseType.CANCEL){ this.delete_event.connect(on_delete_event); //reconnect this handler return true; //keep window open } } break; - + case -1: string msg = _("The backup device is not set or unavailable.") + "\n"; msg += _("Scheduled snapshots will be disabled.") + "\n"; @@ -642,7 +642,7 @@ dialog.set_modal(true); int response = dialog.run(); dialog.destroy(); - + if (response == Gtk.ResponseType.YES){ this.delete_event.connect(on_delete_event); //reconnect this handler return true; //keep window open @@ -651,18 +651,18 @@ App.is_scheduled = false; return false; //close window } - + } return false; } - + private void cell_date_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ TimeShiftBackup bak; model.get (iter, 0, out bak, -1); (cell as Gtk.CellRendererText).text = bak.date.format ("%Y-%m-%d %I:%M %p"); } - + private void cell_tags_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ TimeShiftBackup bak; model.get (iter, 0, out bak, -1); @@ -674,13 +674,13 @@ model.get (iter, 0, out bak, -1); (cell as Gtk.CellRendererText).text = bak.sys_distro; } - + private void cell_desc_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ TimeShiftBackup bak; model.get (iter, 0, out bak, -1); (cell as Gtk.CellRendererText).text = bak.description; } - + private void cell_desc_edited (string path, string new_text) { TimeShiftBackup bak; @@ -700,29 +700,29 @@ } private void refresh_tv_backups(){ - + App.update_snapshot_list(); - + var model = new Gtk.ListStore(1, typeof(TimeShiftBackup)); - + var list = App.snapshot_list; - + if (tv_backups_sort_column_index == 0){ - + if (tv_backups_sort_column_desc) { - list.sort((a,b) => { + list.sort((a,b) => { TimeShiftBackup t1 = (TimeShiftBackup) a; TimeShiftBackup t2 = (TimeShiftBackup) b; - + return (t1.date.compare(t2.date)); }); } else{ - list.sort((a,b) => { + list.sort((a,b) => { TimeShiftBackup t1 = (TimeShiftBackup) a; TimeShiftBackup t2 = (TimeShiftBackup) b; - + return -1 * (t1.date.compare(t2.date)); }); } @@ -730,18 +730,18 @@ else{ if (tv_backups_sort_column_desc) { - list.sort((a,b) => { + list.sort((a,b) => { TimeShiftBackup t1 = (TimeShiftBackup) a; TimeShiftBackup t2 = (TimeShiftBackup) b; - + return strcmp(t1.taglist,t2.taglist); }); } else{ - list.sort((a,b) => { + list.sort((a,b) => { TimeShiftBackup t1 = (TimeShiftBackup) a; TimeShiftBackup t2 = (TimeShiftBackup) b; - + return -1 * strcmp(t1.taglist,t2.taglist); }); } @@ -752,7 +752,7 @@ model.append(out iter); model.set (iter, 0, bak); } - + tv_backups.set_model (model); tv_backups.columns_autosize (); } @@ -767,29 +767,29 @@ int index_root_device = -1; foreach(Device pi in App.partition_list) { - + if (!pi.has_linux_filesystem()) { continue; } store.append(out iter); store.set (iter, 0, pi); - + //set icon ---------------- - + Gdk.Pixbuf pix_selected = null; Gdk.Pixbuf pix_device = get_shared_icon("disk","disk.png",16).pixbuf; Gdk.Pixbuf pix_locked = get_shared_icon("locked","locked.svg",16).pixbuf; - + if (pi.type == "luks"){ pix_selected = pix_locked; } else{ pix_selected = pix_device; } - + store.set (iter, 1, pix_selected, -1); - + //get device index ---------- - + index++; if ((App.root_device != null) && (pi.uuid == App.root_device.uuid)){ index_root_device = index; @@ -798,9 +798,9 @@ index_snapshot_device = index; } } - + cmb_backup_device.set_model (store); - + if (index_snapshot_device > -1){ cmb_backup_device.active = index_snapshot_device; } @@ -811,40 +811,40 @@ cmb_backup_device.active = -1; } } - + private void cmb_backup_device_changed(){ ComboBox combo = cmb_backup_device; if (combo.model == null) { return; } - + string txt; - if (combo.active < 0) { + if (combo.active < 0) { txt = "" + _("WARNING:") + "\n"; txt += "Ø " + _("Please select a device for saving snapshots.") + "\n"; txt = "" + txt + ""; lbl_backup_device_warning.label = txt; App.snapshot_device = null; - return; + return; } - + //get new device reference TreeIter iter; Device pi; combo.get_active_iter (out iter); TreeModel model = (TreeModel) combo.model; model.get(iter, 0, out pi); - + change_backup_device(pi); } - + private void change_backup_device(Device pi){ //return if device has not changed if ((App.snapshot_device != null) && (pi.uuid == App.snapshot_device.uuid)){ return; } gtk_set_busy(true, this); - + Device previous_device = App.snapshot_device; App.snapshot_device = pi; - + //try mounting the device if (App.mount_backup_device(this)){ App.update_partition_list(); @@ -860,18 +860,18 @@ } private void btn_backup_clicked(){ - + //check root device -------------- - + if (App.check_btrfs_root_layout() == false){ return; } - + //check snapshot device ----------- - + string msg; int status_code = App.check_backup_device(out msg); - + switch(status_code){ case -1: check_backup_device_online(); @@ -884,33 +884,33 @@ } //update UI ------------------ - + update_ui(false); statusbar_message(_("Taking snapshot...")); - + update_progress_start(); - + //take snapshot ---------------- - - bool is_success = App.take_snapshot(true,"",this); + + bool is_success = App.take_snapshot(true,"",this); update_progress_stop(); - + if (is_success){ statusbar_message_with_timeout(_("Snapshot saved successfully"), true); } else{ statusbar_message_with_timeout(_("Error: Unable to save snapshot"), false); } - + //update UI ------------------- - + App.update_partition_list(); refresh_cmb_backup_device(); refresh_tv_backups(); update_statusbar(); - + update_ui(true); } @@ -919,31 +919,31 @@ TreeIter iter_delete; TreeSelection sel; bool is_success = true; - + //check if device is online if (!check_backup_device_online()) { return; } - + //check selected count ---------------- - + sel = tv_backups.get_selection (); - if (sel.count_selected_rows() == 0){ + if (sel.count_selected_rows() == 0){ gtk_messagebox(_("No Snapshots Selected"),_("Please select the snapshots to delete"),null,false); - return; + return; } - + //update UI ------------------ - + update_ui(false); - + statusbar_message(_("Removing selected snapshots...")); - + //get list of snapshots to delete -------------------- var list_of_snapshots_to_delete = new Gee.ArrayList(); var store = (Gtk.ListStore) tv_backups.model; - + bool iterExists = store.get_iter_first (out iter); - while (iterExists && is_success) { + while (iterExists && is_success) { if (sel.iter_is_selected (iter)){ TimeShiftBackup bak; store.get (iter, 0, out bak); @@ -951,18 +951,18 @@ } iterExists = store.iter_next (ref iter); } - + //clear selection --------------- - + tv_backups.get_selection().unselect_all(); - + //delete snapshots -------------------------- - + foreach(TimeShiftBackup bak in list_of_snapshots_to_delete){ - + //find the iter being deleted iterExists = store.get_iter_first (out iter_delete); - while (iterExists) { + while (iterExists) { TimeShiftBackup bak_current; store.get (iter_delete, 0, out bak_current); if (bak_current.path == bak.path){ @@ -970,35 +970,35 @@ } iterExists = store.iter_next (ref iter_delete); } - + //select the iter being deleted tv_backups.get_selection().select_iter(iter_delete); - + statusbar_message(_("Deleting snapshot") + ": '%s'...".printf(bak.name)); - - is_success = App.delete_snapshot(bak); - + + is_success = App.delete_snapshot(bak); + if (!is_success){ statusbar_message_with_timeout(_("Error: Unable to delete snapshot") + ": '%s'".printf(bak.name), false); break; } - + //remove iter from tv_backups store.remove(iter_delete); } - + App.update_snapshot_list(); if (App.snapshot_list.size == 0){ statusbar_message(_("Deleting snapshot") + ": '.sync'..."); App.delete_all_snapshots(); } - + if (is_success){ statusbar_message_with_timeout(_("Snapshots deleted successfully"), true); } - + //update UI ------------------- - + App.update_partition_list(); refresh_cmb_backup_device(); refresh_tv_backups(); @@ -1006,55 +1006,55 @@ update_ui(true); } - + private void btn_restore_clicked(){ App.mirror_system = false; restore(); } - + private void btn_clone_clicked(){ App.mirror_system = true; restore(); } - + private void restore(){ TreeIter iter; TreeSelection sel; - + if (!App.mirror_system){ //check if backup device is online (check #1) if (!check_backup_device_online()) { return; } } - + if (!App.mirror_system){ //check if single snapshot is selected ------------- - + sel = tv_backups.get_selection (); - if (sel.count_selected_rows() == 0){ + if (sel.count_selected_rows() == 0){ gtk_messagebox(_("No Snapshots Selected"), _("Please select the snapshot to restore"),null,false); - return; + return; } - else if (sel.count_selected_rows() > 1){ + else if (sel.count_selected_rows() > 1){ gtk_messagebox(_("Multiple Snapshots Selected"), _("Please select a single snapshot"),null,false); - return; + return; } - + //get selected snapshot ------------------ - + TimeShiftBackup snapshot_to_restore = null; - + var store = (Gtk.ListStore) tv_backups.model; sel = tv_backups.get_selection(); bool iterExists = store.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { if (sel.iter_is_selected (iter)){ store.get (iter, 0, out snapshot_to_restore); break; } iterExists = store.iter_next (ref iter); } - + App.snapshot_to_restore = snapshot_to_restore; App.restore_target = App.root_device; } @@ -1062,7 +1062,7 @@ App.snapshot_to_restore = null; App.restore_target = null; } - + //show restore window ----------------- var dialog = new RestoreWindow(); @@ -1070,27 +1070,27 @@ dialog.show_all(); int response = dialog.run(); dialog.destroy(); - + if (response != Gtk.ResponseType.OK){ App.unmount_target_device(); return; //cancel } - + if (!App.mirror_system){ //check if backup device is online (check #2) if (!check_backup_device_online()) { return; } } - + //update UI ---------------- - + update_ui(false); - + //take a snapshot if current system is being restored ----------------- - + if (!App.live_system() && (App.restore_target.device == App.root_device.device) && (App.restore_target.uuid == App.root_device.uuid)){ string msg = _("Do you want to take a snapshot of the current system before restoring the selected snapshot?"); - + var dlg = new Gtk.MessageDialog.with_markup(this, Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, msg); dlg.set_title(_("Take Snapshot")); dlg.set_default_size (200, -1); @@ -1101,13 +1101,13 @@ if (response == Gtk.ResponseType.YES){ statusbar_message(_("Taking snapshot...")); - + update_progress_start(); - - bool is_success = App.take_snapshot(true,"",this); - + + bool is_success = App.take_snapshot(true,"",this); + update_progress_stop(); - + if (is_success){ App.update_snapshot_list(); var latest = App.get_latest_snapshot("ondemand"); @@ -1121,7 +1121,7 @@ //check if backup device is online (check #3) if (!check_backup_device_online()) { return; } } - + //restore the snapshot -------------------- if (App.snapshot_to_restore != null){ @@ -1132,13 +1132,13 @@ log_msg("Cloning current system to device '%s'".printf(App.restore_target.device),true); statusbar_message(_("Cloning system...")); } - + if (App.reinstall_grub2){ log_msg("GRUB will be installed on '%s'".printf(App.grub_device),true); } - bool is_success = App.restore_snapshot(this); - + bool is_success = App.restore_snapshot(this); + string msg; if (is_success){ if (App.mirror_system){ @@ -1148,7 +1148,7 @@ msg = _("Snapshot was restored successfully on target device"); } statusbar_message_with_timeout(msg, true); - + var dlg = new Gtk.MessageDialog.with_markup(this,Gtk.DialogFlags.MODAL, Gtk.MessageType.INFO, Gtk.ButtonsType.OK, msg); dlg.set_title(_("Finished")); dlg.set_modal(true); @@ -1173,9 +1173,9 @@ dlg.run(); dlg.destroy(); } - + //update UI ---------------- - + update_ui(true); } @@ -1187,19 +1187,19 @@ dialog.hide_on_delete (); } }); - + dialog.show_all(); dialog.run(); update_statusbar(); } - + private void btn_browse_snapshot_clicked(){ - + //check if device is online - if (!check_backup_device_online()) { - return; + if (!check_backup_device_online()) { + return; } - + TreeSelection sel = tv_backups.get_selection (); if (sel.count_selected_rows() == 0){ var f = File.new_for_path(App.snapshot_dir); @@ -1211,12 +1211,12 @@ } return; } - + TreeIter iter; var store = (Gtk.ListStore)tv_backups.model; - + bool iterExists = store.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { if (sel.iter_is_selected (iter)){ TimeShiftBackup bak; store.get (iter, 0, out bak); @@ -1234,12 +1234,12 @@ gtk_messagebox(_("Select Snapshot"),_("Please select a snapshot to view the log!"),null,false); return; } - + TreeIter iter; var store = (Gtk.ListStore)tv_backups.model; - + bool iterExists = store.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { if (sel.iter_is_selected (iter)){ TimeShiftBackup bak; store.get (iter, 0, out bak); @@ -1250,7 +1250,7 @@ iterExists = store.iter_next (ref iter); } } - + private void btn_view_app_logs_clicked(){ exo_open_folder(App.log_dir); } @@ -1262,27 +1262,27 @@ dialog.run(); dialog.destroy(); } - + private void btn_about_clicked (){ var dialog = new AboutWindow(); dialog.set_transient_for (this); - dialog.authors = { - "Tony George:teejeetech@gmail.com" + dialog.authors = { + "Tony George:teejeetech@gmail.com" }; - + dialog.translators = { "Debaru, Nikos, alienus (French):launchpad.net/~lp-l10n-fr", "tomberry88 (Italian):launchpad.net/~tomberry", "ë°•ì •ê·œ(Jung-Kyu Park) (Korean):bagjunggyu@gmail.com" - }; - + }; + dialog.third_party = { "Timeshift is powered by the following tools and components. Please visit the links for more information.", "rsync by Andrew Tridgell, Wayne Davison, and others.:http://rsync.samba.org/" - }; - - dialog.documenters = null; + }; + + dialog.documenters = null; dialog.artists = null; dialog.donations = null; @@ -1307,14 +1307,14 @@ img_status_progress.visible = !visible; lbl_status.visible = !visible; lbl_status.label = ""; - + img_status_device.visible = visible; lbl_status_device.visible = visible; - + //if (App.is_live_system()){ //visible = false; //} - + img_status_scheduled.visible = visible; lbl_status_scheduled.visible = visible; img_status_latest.visible = visible; @@ -1324,44 +1324,44 @@ private void statusbar_message (string message){ if (timer_status_message > 0){ Source.remove (timer_status_message); - timer_status_message = -1; + timer_status_message = 0; } lbl_status.label = message; } - + private void statusbar_message_with_timeout (string message, bool success){ if (timer_status_message > 0){ Source.remove (timer_status_message); - timer_status_message = -1; + timer_status_message = 0; } lbl_status.label = message; - + img_status_spinner.visible = false; img_status_progress.visible = false; img_status_dot.visible = true; - + if (success){ img_status_dot.file = App.share_folder + "/timeshift/images/item-green.png"; } else{ img_status_dot.file = App.share_folder + "/timeshift/images/item-red.png"; } - + timer_status_message = Timeout.add_seconds (5, statusbar_clear); } - + private bool statusbar_clear (){ if (timer_status_message > 0){ Source.remove (timer_status_message); - timer_status_message = -1; + timer_status_message = 0; } lbl_status.label = ""; show_statusbar_icons(true); return true; } - + private void update_ui(bool enable){ toolbar.sensitive = enable; hbox_device.sensitive = enable; @@ -1369,19 +1369,19 @@ show_statusbar_icons(enable); gtk_set_busy(!enable, this); } - + private void update_progress_start(){ timer_progress = Timeout.add_seconds(1, update_progress); } - + private bool update_progress (){ if (timer_progress > 0){ Source.remove(timer_progress); timer_progress = 0; } - + lbl_status.label = App.progress_text; - + timer_progress = Timeout.add_seconds(1, update_progress); return true; } @@ -1392,7 +1392,7 @@ timer_progress = 0; } } - + private bool check_backup_device_online(){ if (!App.backup_device_online()){ gtk_messagebox(_("Device Offline"),_("Backup device is not available"), null, true); @@ -1407,9 +1407,9 @@ private void update_statusbar(){ string img_dot_red = App.share_folder + "/timeshift/images/item-red.png"; string img_dot_green = App.share_folder + "/timeshift/images/item-green.png"; - + //check free space on backup device --------------------------- - + string message = ""; int status_code = App.check_backup_device(out message); string txt; @@ -1426,14 +1426,14 @@ lbl_backup_device_warning.label = txt; lbl_backup_device_warning.visible = true; break; - + case 1: txt = _("Backup device does not have enough space!"); txt = "" + txt + ""; lbl_backup_device_warning.label = txt; lbl_backup_device_warning.visible = true; break; - + case 2: long required = App.calculate_size_of_first_snapshot(); txt = _("Backup device does not have enough space!") + " "; @@ -1442,13 +1442,13 @@ lbl_backup_device_warning.label = txt; lbl_backup_device_warning.visible = true; break; - + default: lbl_backup_device_warning.label = ""; lbl_backup_device_warning.visible = false; break; } - + if ((status_code == 0)||(status_code == 3)){ img_status_device.file = img_dot_green; } @@ -1456,14 +1456,14 @@ img_status_device.file = img_dot_red; } lbl_status_device.label = message; - + img_status_device.visible = (message.strip().length > 0); lbl_status_device.visible = (message.strip().length > 0); - + // statusbar icons --------------------------------------------------------- - + //status - scheduled snapshots ----------- - + if (App.live_system()){ img_status_scheduled.file = img_dot_green; lbl_status_scheduled.label = _("Running from Live CD/USB"); @@ -1482,12 +1482,12 @@ } //status - last snapshot ----------- - + if (status_code >= 0){ DateTime now = new DateTime.now_local(); TimeShiftBackup last_snapshot = App.get_latest_snapshot(); DateTime last_snapshot_date = (last_snapshot == null) ? null : last_snapshot.date; - + if (last_snapshot == null){ img_status_latest.file = img_dot_red; lbl_status_latest.label = _("No snapshots on device"); @@ -1495,7 +1495,7 @@ else{ float days = ((float) now.difference(last_snapshot_date) / TimeSpan.DAY); float hours = ((float) now.difference(last_snapshot_date) / TimeSpan.HOUR); - + if (days > 1){ img_status_latest.file = img_dot_red; lbl_status_latest.label = _("Last snapshot is") + " %.0f ".printf(days) + _("days old") + "!"; @@ -1515,5 +1515,5 @@ lbl_status_latest.visible = false; } } - + } diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/makefile timeshift-1.7.4~178~ubuntu14.04.1/src/makefile --- timeshift-1.7.3~177~ubuntu14.04.1/src/makefile 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/makefile 2015-09-08 01:01:52.000000000 +0000 @@ -12,7 +12,7 @@ all: #build binaries valac -X -D'GETTEXT_PACKAGE="${app_name}"' --Xcc="-lm" -X -Wl,-rpath,/usr/share/${app_name}/libs --thread "Main.vala" "Utility.vala" "MainWindow.vala" "SettingsWindow.vala" "RestoreWindow.vala" "ExcludeMessageWindow.vala" "AboutWindow.vala" "DonationWindow.vala" -o ${app_name} --pkg glib-2.0 --pkg gio-unix-2.0 --pkg posix --pkg gtk+-3.0 --pkg gee-0.8 --pkg json-glib-1.0 --pkg gudev-1.0 - + #update translation template xgettext --language=C --keyword=_ --copyright-holder='Tony George (teejee2008@gmail.com)' --package-name="${app_name}" --package-version='1.6' --msgid-bugs-address='teejee2008@gmail.com' --escape --sort-output -o ../${app_name}.pot *.vala @@ -30,42 +30,42 @@ mkdir -p "$(DESTDIR)$(localedir)/it_IT/LC_MESSAGES" mkdir -p "$(DESTDIR)$(localedir)/ko_KR/LC_MESSAGES" mkdir -p "$(DESTDIR)$(localedir)/fr_FR/LC_MESSAGES" - + #binary install -m 0755 ${app_name} "$(DESTDIR)$(bindir)" install -m 0755 ${app_name}-uninstall "$(DESTDIR)$(bindir)" install -m 0755 ${app_name}-launcher "$(DESTDIR)$(bindir)" - + #shared files cp -dpr --no-preserve=ownership -t "$(DESTDIR)$(sharedir)/${app_name}" ./share/${app_name}/* chmod --recursive 0755 $(DESTDIR)$(sharedir)/${app_name}/* - + #launcher install -m 0755 ${app_name}.desktop "$(DESTDIR)$(launcherdir)" - + #app icon install -m 0755 ./share/pixmaps/${app_name}.png "$(DESTDIR)$(sharedir)/pixmaps/" - + #translations msgfmt --check --verbose -o "$(DESTDIR)$(localedir)/it_IT/LC_MESSAGES/${app_name}.mo" ../po/${app_name}-it.po msgfmt --check --verbose -o "$(DESTDIR)$(localedir)/ko_KR/LC_MESSAGES/${app_name}.mo" ../po/${app_name}-ko.po msgfmt --check --verbose -o "$(DESTDIR)$(localedir)/fr_FR/LC_MESSAGES/${app_name}.mo" ../po/${app_name}-fr.po - + uninstall: #binary rm -f "$(DESTDIR)$(bindir)/${app_name}" rm -f "$(DESTDIR)$(bindir)/${app_name}-uninstall" rm -f "$(DESTDIR)$(bindir)/${app_name}-launcher" - + #shared files rm -rf "$(DESTDIR)$(sharedir)/${app_name}" - + #launcher rm -f "$(DESTDIR)$(launcherdir)/${app_name}.desktop" - + #app icon rm -f "$(DESTDIR)$(sharedir)/pixmaps/${app_name}.png" - + #translations rm -f $(DESTDIR)$(localedir)/*/LC_MESSAGES/${app_name}.mo diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/RestoreWindow.vala timeshift-1.7.4~178~ubuntu14.04.1/src/RestoreWindow.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/RestoreWindow.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/RestoreWindow.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,24 +1,24 @@ /* * MainWindow.vala - * + * * Copyright 2013 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ using Gtk; @@ -51,12 +51,12 @@ private TreeViewColumn col_size; private TreeViewColumn col_dist; private CellRendererCombo cell_mount; - + //bootloader private Label lbl_header_bootloader; private ComboBox cmb_boot_device; private CheckButton chk_skip_grub_install; - + //apps private Label lbl_app; private Box vbox_app; @@ -76,26 +76,26 @@ private ToolButton btn_remove; private ToolButton btn_warning; private ToolButton btn_reset_exclude_list; - + private MenuToolButton btn_exclude; private Gtk.Menu menu_exclude; private ImageMenuItem menu_exclude_add_file; private ImageMenuItem menu_exclude_add_folder; private ImageMenuItem menu_exclude_add_folder_contents; - + private MenuToolButton btn_include; private Gtk.Menu menu_include; private ImageMenuItem menu_include_add_file; private ImageMenuItem menu_include_add_folder; - + private Gee.ArrayList temp_exclude_list; - + //actions private Button btn_cancel; private Button btn_restore; - + private Device selected_target = null; - + public RestoreWindow () { this.title = _("Restore"); this.window_position = WindowPosition.CENTER_ON_PARENT; @@ -104,7 +104,7 @@ this.set_default_size (550, 500); this.skip_taskbar_hint = true; this.icon = get_app_icon(16); - + //vbox_main vbox_main = get_content_area (); @@ -114,7 +114,7 @@ vbox_main.pack_start (notebook, true, true, 0); //target device tab ------------------------------------------------- - + //lbl_exclude lbl_exclude = new Label (_("Target")); @@ -122,7 +122,7 @@ Box vbox_target = new Box (Orientation.VERTICAL, 6); vbox_target.margin = 6; notebook.append_page (vbox_target, lbl_exclude); - + //hbox_device Box hbox_device = new Box (Orientation.HORIZONTAL, 6); //hbox_device.margin = 6; @@ -137,7 +137,7 @@ radio_sys = new RadioButton(null); hbox_device.add(radio_sys); radio_sys.label = "Current System"; - + radio_other = new RadioButton.from_widget(radio_sys); hbox_device.add(radio_other); radio_other.label = "Other Device"; @@ -150,12 +150,12 @@ radio_sys.sensitive = true; radio_sys.active = true; } - + radio_sys.toggled.connect(() => { sw_partitions.sensitive = radio_other.active; - + refresh_tv_partitions(); - + if (radio_sys.active){ App.restore_target = App.root_device; } @@ -163,29 +163,29 @@ init_mounts(); } - //tv_partitions_select_target(); + //tv_partitions_select_target(); cmb_boot_device_select_default(); }); - + //tv_partitions tv_partitions = new TreeView(); tv_partitions.get_selection().mode = SelectionMode.SINGLE; tv_partitions.set_rules_hint (true); tv_partitions.button_release_event.connect(tv_partitions_button_press_event); - + //sw_partitions sw_partitions = new ScrolledWindow(null, null); sw_partitions.set_shadow_type (ShadowType.ETCHED_IN); sw_partitions.add (tv_partitions); sw_partitions.expand = true; vbox_target.add(sw_partitions); - + //col_device col_device_target = new TreeViewColumn(); col_device_target.title = _("Device"); col_device_target.spacing = 1; tv_partitions.append_column(col_device_target); - + CellRendererPixbuf cell_device_icon = new CellRendererPixbuf(); cell_device_icon.xpad = 1; col_device_target.pack_start (cell_device_icon, false); @@ -214,14 +214,14 @@ col_mount.pack_start (cell_mount, false); col_mount.set_cell_data_func (cell_mount, cell_mount_render); tv_partitions.append_column(col_mount); - + cell_mount.set_property ("text-column", 0); col_mount.add_attribute (cell_mount, "text", 1); //populate combo var model = new Gtk.ListStore(1, typeof(string)); cell_mount.model = model; - + TreeIter iter; model.append(out iter); model.set (iter, 0, "/"); @@ -237,7 +237,7 @@ model.get_iter_from_string (out iter, path); model.set (iter, 1, val); }); - + cell_mount.edited.connect((path, new_text) => { model = (Gtk.ListStore) tv_partitions.model; model.get_iter_from_string (out iter, path); @@ -252,7 +252,7 @@ col_size.pack_start (cell_size, false); col_size.set_cell_data_func (cell_size, cell_size_render); tv_partitions.append_column(col_size); - + //col_dist col_dist = new TreeViewColumn(); col_dist.title = _("System"); @@ -262,15 +262,15 @@ tv_partitions.append_column(col_dist); tv_partitions.set_tooltip_column(2); - + //bootloader options ------------------------------------------- - + //lbl_header_bootloader lbl_header_bootloader = new Gtk.Label(_("Device for Bootloader Installation") + ":"); lbl_header_bootloader.set_use_markup(true); lbl_header_bootloader.xalign = (float) 0.0; vbox_target.add(lbl_header_bootloader); - + //hbox_grub Box hbox_grub = new Box (Orientation.HORIZONTAL, 6); hbox_grub.margin_right = 6; @@ -281,33 +281,33 @@ cmb_boot_device = new ComboBox (); cmb_boot_device.hexpand = true; hbox_grub.add(cmb_boot_device); - + CellRendererText cell_dev_margin = new CellRendererText (); cell_dev_margin.text = ""; cmb_boot_device.pack_start (cell_dev_margin, false); - + CellRendererPixbuf cell_dev_icon = new CellRendererPixbuf (); cell_dev_icon.stock_id = "gtk-harddisk"; cmb_boot_device.pack_start (cell_dev_icon, false); - + CellRendererText cell_device_grub = new CellRendererText(); cmb_boot_device.pack_start(cell_device_grub, false ); cmb_boot_device.set_cell_data_func (cell_device_grub, cell_device_grub_render); - + string tt = "" + _("** Advanced Users **") + "\n\n"+ _("Skips bootloader (re)installation on target device.\nFiles in /boot directory on target partition will remain untouched.\n\nIf you are restoring a system that was bootable previously then it should boot successfully.\nOtherwise the system may fail to boot."); - + //chk_skip_grub_install chk_skip_grub_install = new CheckButton.with_label(_("Skip bootloader installation (not recommended)")); chk_skip_grub_install.active = false; chk_skip_grub_install.set_tooltip_markup(tt); vbox_target.add (chk_skip_grub_install); - + chk_skip_grub_install.toggled.connect(()=>{ cmb_boot_device.sensitive = !chk_skip_grub_install.active; }); - + //Exclude Apps tab --------------------------------------------- - + //lbl_apps lbl_app = new Label (_("Exclude")); @@ -315,14 +315,14 @@ vbox_app = new Box(Gtk.Orientation.VERTICAL, 6); vbox_app.margin = 6; notebook.append_page (vbox_app, lbl_app); - + //lbl_app_message string msg = _("Select the applications for which current settings should be kept.") + "\n"; msg += _("For all other applications, settings will be restored from selected snapshot."); lbl_app_message = new Label (msg); lbl_app_message.xalign = (float) 0.0; vbox_app.add(lbl_app_message); - + //tv_app----------------------------------------------- //tv_app @@ -343,25 +343,25 @@ col_app.title = _("Application"); col_app.expand = true; tv_app.append_column(col_app); - + CellRendererText cell_app_margin = new CellRendererText (); cell_app_margin.text = ""; col_app.pack_start (cell_app_margin, false); - + CellRendererToggle cell_app_enabled = new CellRendererToggle (); cell_app_enabled.radio = false; cell_app_enabled.activatable = true; col_app.pack_start (cell_app_enabled, false); col_app.set_cell_data_func (cell_app_enabled, cell_app_enabled_render); - + cell_app_enabled.toggled.connect (cell_app_enabled_toggled); - + CellRendererText cell_app_text = new CellRendererText (); col_app.pack_start (cell_app_text, false); col_app.set_cell_data_func (cell_app_text, cell_app_text_render); //Advanced tab --------------------------------------------- - + //lbl_exclude lbl_exclude = new Label (_("Advanced")); @@ -371,37 +371,37 @@ notebook.append_page (vbox_exclude, lbl_exclude); //toolbar_exclude --------------------------------------------------- - + //toolbar_exclude toolbar_exclude = new Gtk.Toolbar (); toolbar_exclude.toolbar_style = ToolbarStyle.BOTH_HORIZ; vbox_exclude.add(toolbar_exclude); - + string png_exclude = App.share_folder + "/timeshift/images/item-gray.png"; string png_include = App.share_folder + "/timeshift/images/item-blue.png"; - + //btn_exclude btn_exclude = new Gtk.MenuToolButton(null,""); toolbar_exclude.add(btn_exclude); - + btn_exclude.is_important = true; btn_exclude.label = _("Exclude"); btn_exclude.set_tooltip_text (_("Exclude")); btn_exclude.set_icon_widget(new Gtk.Image.from_file (png_exclude)); - + //btn_include btn_include = new Gtk.MenuToolButton(null,""); toolbar_exclude.add(btn_include); - + btn_include.is_important = true; btn_include.label = _("Include"); btn_include.set_tooltip_text (_("Include")); btn_include.set_icon_widget(new Gtk.Image.from_file (png_include)); - + //btn_remove btn_remove = new Gtk.ToolButton.from_stock("gtk-remove"); toolbar_exclude.add(btn_remove); - + btn_remove.is_important = true; btn_remove.label = _("Remove"); btn_remove.set_tooltip_text (_("Remove selected items")); @@ -411,7 +411,7 @@ //btn_warning btn_warning = new Gtk.ToolButton.from_stock("gtk-dialog-warning"); toolbar_exclude.add(btn_warning); - + btn_warning.is_important = true; btn_warning.label = _("Warning"); btn_warning.set_tooltip_text (_("Warning")); @@ -423,29 +423,29 @@ separator.set_draw (false); separator.set_expand (true); toolbar_exclude.add(separator); - + //btn_reset_exclude_list btn_reset_exclude_list = new Gtk.ToolButton.from_stock("gtk-refresh"); toolbar_exclude.add(btn_reset_exclude_list); - + btn_reset_exclude_list.is_important = false; btn_reset_exclude_list.label = _("Reset"); btn_reset_exclude_list.set_tooltip_text (_("Reset this list to default state")); btn_reset_exclude_list.clicked.connect (btn_reset_exclude_list_clicked); - + //menu -------------------------------------------------- - + //menu_exclude menu_exclude = new Gtk.Menu(); btn_exclude.set_menu(menu_exclude); - + //menu_exclude_add_file menu_exclude_add_file = new ImageMenuItem.with_label (""); menu_exclude_add_file.label = _("Exclude File(s)"); menu_exclude_add_file.set_image(new Gtk.Image.from_file (png_exclude)); menu_exclude.append(menu_exclude_add_file); - + menu_exclude_add_file.activate.connect (menu_exclude_add_files_clicked); //menu_exclude_add_folder @@ -453,7 +453,7 @@ menu_exclude_add_folder.label = _("Exclude Directory"); menu_exclude_add_folder.set_image(new Gtk.Image.from_file (png_exclude)); menu_exclude.append(menu_exclude_add_folder); - + menu_exclude_add_folder.activate.connect (menu_exclude_add_folder_clicked); //menu_exclude_add_folder_contents @@ -461,19 +461,19 @@ menu_exclude_add_folder_contents.label = _("Exclude Directory Contents"); menu_exclude_add_folder_contents.set_image(new Gtk.Image.from_file (png_exclude)); menu_exclude.append(menu_exclude_add_folder_contents); - + menu_exclude_add_folder_contents.activate.connect (menu_exclude_add_folder_contents_clicked); - + //menu_include menu_include = new Gtk.Menu(); btn_include.set_menu(menu_include); - + //menu_include_add_file menu_include_add_file = new ImageMenuItem.with_label (""); menu_include_add_file.label = _("Include File(s)"); menu_include_add_file.set_image(new Gtk.Image.from_file (png_include)); menu_include.append(menu_include_add_file); - + menu_include_add_file.activate.connect (menu_include_add_files_clicked); //menu_include_add_folder @@ -481,21 +481,21 @@ menu_include_add_folder.label = _("Include Directory"); menu_include_add_folder.set_image(new Gtk.Image.from_file (png_include)); menu_include.append(menu_include_add_folder); - + menu_include_add_folder.activate.connect (menu_include_add_folder_clicked); - + menu_exclude.show_all(); menu_include.show_all(); - + //tv_exclude----------------------------------------------- - + //tv_exclude tv_exclude = new TreeView(); tv_exclude.get_selection().mode = SelectionMode.MULTIPLE; tv_exclude.headers_visible = true; tv_exclude.set_rules_hint (true); //tv_exclude.row_activated.connect(tv_exclude_row_activated); - + //sw_exclude sw_exclude = new ScrolledWindow(null, null); sw_exclude.set_shadow_type (ShadowType.ETCHED_IN); @@ -507,38 +507,38 @@ col_exclude = new TreeViewColumn(); col_exclude.title = _("File Pattern"); col_exclude.expand = true; - + CellRendererText cell_exclude_margin = new CellRendererText (); cell_exclude_margin.text = ""; col_exclude.pack_start (cell_exclude_margin, false); - + CellRendererPixbuf cell_exclude_icon = new CellRendererPixbuf (); col_exclude.pack_start (cell_exclude_icon, false); col_exclude.set_attributes(cell_exclude_icon, "pixbuf", 1); - + CellRendererText cell_exclude_text = new CellRendererText (); col_exclude.pack_start (cell_exclude_text, false); col_exclude.set_cell_data_func (cell_exclude_text, cell_exclude_text_render); cell_exclude_text.editable = true; tv_exclude.append_column(col_exclude); - + cell_exclude_text.edited.connect (cell_exclude_text_edited); - + //lnk_default_list lnk_default_list = new LinkButton.with_label("",_("Some locations are excluded by default")); lnk_default_list.xalign = (float) 0.0; lnk_default_list.activate_link.connect(lnk_default_list_activate); vbox_exclude.add(lnk_default_list); - + //Actions ---------------------------------------------- - + //hbox_action hbox_action = (Box) get_action_area (); //btn_restore btn_restore = new Button(); hbox_action.add(btn_restore); - + btn_restore.set_label (" " + _("Restore")); btn_restore.set_tooltip_text (_("Restore")); Gtk.Image img_restore = new Image.from_stock("gtk-go-forward", Gtk.IconSize.BUTTON); @@ -548,7 +548,7 @@ //btn_cancel btn_cancel = new Button(); hbox_action.add(btn_cancel); - + btn_cancel.set_label (" " + _("Cancel")); btn_cancel.set_tooltip_text (_("Cancel")); Gtk.Image img_cancel = new Image.from_stock("gtk-cancel", Gtk.IconSize.BUTTON); @@ -565,7 +565,7 @@ refresh_tv_apps(); sw_partitions.sensitive = radio_other.active; - + notebook.switch_page.connect_after((page, new_page_index) => { if (new_page_index == 1){ bool ok = check_and_mount_devices(); @@ -582,28 +582,28 @@ selected_app_list.add(entry.relpath); } } - + //refresh the list App.add_app_exclude_entries(); - + //restore app selections foreach(AppExcludeEntry entry in App.exclude_list_apps){ if (selected_app_list.contains(entry.relpath)){ entry.enabled = true; } } - + //refresh treeview refresh_tv_apps(); } }); - + set_app_page_state(); - + init_mounts(); - + } - + private void init_mounts(){ TreeIter iter; Gtk.ListStore store; @@ -618,8 +618,8 @@ App.mount_list.remove_at(i); } } - - /* Note: + + /* Note: * While cloning the system, /boot is the only mount point that we will leave unchanged (to avoid encrypted systems from breaking) * All other mounts like /home will be defaulted to target device (to prevent the "cloned" system from using the original device) * */ @@ -640,7 +640,7 @@ } } } - + private void set_app_page_state(){ if (App.restore_target == null){ lbl_app.sensitive = false; @@ -651,11 +651,11 @@ vbox_app.sensitive = true; } } - + private void cell_device_target_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ Device pi; model.get (iter, 0, out pi, -1); - + string symlink = ""; foreach(string sym in pi.symlinks){ if (sym.has_prefix("/dev/mapper/")){ @@ -669,11 +669,11 @@ else{ (cell as Gtk.CellRendererText).text = pi.device + ((symlink.length > 0) ? " → " + symlink : ""); } - + Gtk.CellRendererText ctxt = (cell as Gtk.CellRendererText); set_cell_text_color(ref ctxt); } - + private void set_cell_text_color(ref CellRendererText cell){ string span = ""; if (!sw_partitions.sensitive){ @@ -681,7 +681,7 @@ } cell.markup = span + cell.text + ""; } - + private void cell_fs_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ Device pi; model.get (iter, 0, out pi, -1); @@ -689,7 +689,7 @@ Gtk.CellRendererText ctxt = (cell as Gtk.CellRendererText); set_cell_text_color(ref ctxt); } - + private void cell_size_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ Device pi; model.get (iter, 0, out pi, -1); @@ -697,11 +697,11 @@ Gtk.CellRendererText ctxt = (cell as Gtk.CellRendererText); set_cell_text_color(ref ctxt); } - + private void cell_mount_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ (cell as Gtk.CellRendererCombo).background = "#F2F5A9"; } - + private void cell_dist_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ Device pi; model.get (iter, 0, out pi, -1); @@ -709,8 +709,8 @@ Gtk.CellRendererText ctxt = (cell as Gtk.CellRendererText); set_cell_text_color(ref ctxt); } - - + + private void cell_device_grub_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ Device dev; model.get (iter, 0, out dev, -1); @@ -731,12 +731,12 @@ private void cell_exclude_text_edited (string path, string new_text) { string old_pattern; string new_pattern; - + TreeIter iter; var model = (Gtk.ListStore) tv_exclude.model; model.get_iter_from_string (out iter, path); model.get (iter, 0, out old_pattern, -1); - + if (old_pattern.has_prefix("+ ")){ new_pattern = "+ " + new_text; } @@ -744,7 +744,7 @@ new_pattern = new_text; } model.set (iter, 0, new_pattern); - + int index = temp_exclude_list.index_of(old_pattern); temp_exclude_list.insert(index, new_pattern); temp_exclude_list.remove(old_pattern); @@ -755,7 +755,7 @@ model.get (iter, 0, out entry, -1); (cell as Gtk.CellRendererToggle).active = entry.enabled; } - + private void cell_app_text_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ AppExcludeEntry entry; model.get (iter, 0, out entry, -1); @@ -773,13 +773,13 @@ private void refresh_cmb_boot_device(){ var store = new Gtk.ListStore(1, typeof(Device)); - + //add devices Gee.ArrayList device_list = new Gee.ArrayList(); foreach(Device di in get_block_devices()) { device_list.add(di); } - + //add partitions var list = App.partition_list; foreach(Device pi in list) { @@ -787,15 +787,15 @@ if (pi.device.has_prefix("/dev/dm-")) { continue; } device_list.add(pi); } - + //sort - device_list.sort((a,b) => { + device_list.sort((a,b) => { Device p1 = (Device) a; Device p2 = (Device) b; - + return strcmp(p1.device,p2.device); }); - + TreeIter iter; foreach(Device entry in device_list) { store.append(out iter); @@ -807,42 +807,42 @@ } private void cmb_boot_device_select_default(){ - if (App.restore_target == null){ + if (App.restore_target == null){ cmb_boot_device.active = -1; - return; + return; } - + TreeIter iter; var store = (Gtk.ListStore) cmb_boot_device.model; int index = -1; - + int first_mbr_device_index = -1; for (bool next = store.get_iter_first (out iter); next; next = store.iter_next (ref iter)) { Device dev; store.get(iter, 0, out dev); - + index++; - + if (dev.device == App.restore_target.device[0:8]){ cmb_boot_device.active = index; break; } - + if ((first_mbr_device_index == -1) && (dev.device.length == "/dev/sdX".length)){ first_mbr_device_index = index; } } - + //select first MBR device if not found if (cmb_boot_device.active == -1){ cmb_boot_device.active = first_mbr_device_index; } } - + private void refresh_tv_partitions(){ - + App.update_partition_list(); - + var model = new Gtk.ListStore(4, typeof(Device), typeof(string), typeof(string), typeof(Gdk.Pixbuf)); tv_partitions.set_model (model); @@ -850,7 +850,7 @@ foreach(Device pi in App.partition_list) { if (!pi.has_linux_filesystem()) { continue; } if (!radio_sys.sensitive && (App.root_device != null) && ((pi.device == App.root_device.device)||(pi.uuid == App.root_device.uuid))) { continue; } - + string tt = ""; tt += "%-7s".printf(_("Device")) + "\t: %s\n".printf(pi.full_name_with_alias); tt += "%-7s".printf(_("UUID")) + "\t: %s\n".printf(pi.uuid); @@ -859,39 +859,39 @@ tt += "%-7s".printf(_("Size")) + "\t: %s\n".printf((pi.size_mb > 0) ? "%s GB".printf(pi.size) : ""); tt += "%-7s".printf(_("Used")) + "\t: %s\n".printf((pi.used_mb > 0) ? "%s GB".printf(pi.used) : ""); tt += "%-7s".printf(_("System")) + "\t: %s".printf(pi.dist_info); - + model.append(out iter); model.set (iter,0,pi,1,"",2,tt); - + //set icon ---------------- - + Gdk.Pixbuf pix_selected = null; Gdk.Pixbuf pix_device = get_shared_icon("disk","disk.png",16).pixbuf; Gdk.Pixbuf pix_locked = get_shared_icon("locked","locked.svg",16).pixbuf; - + if (pi.type == "luks"){ pix_selected = pix_locked; } else{ pix_selected = pix_device; } - + model.set (iter, 3, pix_selected, -1); } - + tv_partitions_select_target(); } - + private void tv_partitions_select_target(){ - - if (App.restore_target == null){ + + if (App.restore_target == null){ tv_partitions.get_selection().unselect_all(); - return; + return; } - + TreeIter iter; var store = (Gtk.ListStore) tv_partitions.model; - + for (bool next = store.get_iter_first (out iter); next; next = store.iter_next (ref iter)) { Device pi; string mount_point; @@ -903,11 +903,11 @@ } } } - + private void refresh_tv_exclude(){ var model = new Gtk.ListStore(2, typeof(string), typeof(Gdk.Pixbuf)); tv_exclude.model = model; - + foreach(string path in temp_exclude_list){ tv_exclude_add_item(path); } @@ -916,7 +916,7 @@ private void refresh_tv_apps(){ var model = new Gtk.ListStore(1, typeof(AppExcludeEntry)); tv_app.model = model; - + foreach(AppExcludeEntry entry in App.exclude_list_apps){ TreeIter iter; model.append(out iter); @@ -940,20 +940,20 @@ TreeIter iter; var model = (Gtk.ListStore) tv_exclude.model; model.append(out iter); - + if (path.has_prefix("+ ")){ pix_selected = pix_include; } else{ pix_selected = pix_exclude; } - + model.set (iter, 0, path, 1, pix_selected, -1); - + Adjustment adj = tv_exclude.get_hadjustment(); adj.value = adj.upper; } - + private bool lnk_default_list_activate(){ //show message window ----------------- var dialog = new ExcludeMessageWindow(); @@ -969,13 +969,13 @@ Gtk.ListStore store; TreeSelection sel; bool iterExists; - + //get selected target device Device restore_target = null; sel = tv_partitions.get_selection (); store = (Gtk.ListStore) tv_partitions.model; iterExists = store.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { if (sel.iter_is_selected (iter)){ store.get (iter, 0, out restore_target); break; @@ -983,29 +983,29 @@ iterExists = store.iter_next (ref iter); } App.restore_target = restore_target; - + //select grub device if (selected_target == null){ cmb_boot_device_select_default(); } else if (selected_target.device != restore_target.device){ - cmb_boot_device_select_default(); + cmb_boot_device_select_default(); } else{ //target device has not changed - do not reset to default boot device } selected_target = restore_target; - + set_app_page_state(); - + return false; } private void menu_exclude_add_files_clicked(){ - + var list = browse_files(); - + if (list.length() > 0){ foreach(string path in list){ if (!temp_exclude_list.contains(path)){ @@ -1018,14 +1018,14 @@ } private void menu_exclude_add_folder_clicked(){ - + var list = browse_folder(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path + "/"; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -1036,14 +1036,14 @@ } private void menu_exclude_add_folder_contents_clicked(){ - + var list = browse_folder(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path + "/*"; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -1054,14 +1054,14 @@ } private void menu_include_add_files_clicked(){ - + var list = browse_files(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path.has_prefix("+ ") ? path : "+ " + path; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -1072,15 +1072,15 @@ } private void menu_include_add_folder_clicked(){ - + var list = browse_folder(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path.has_prefix("+ ") ? path : "+ " + path; path = path + "/***"; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -1103,7 +1103,7 @@ dialog.run(); var list = dialog.get_filenames(); dialog.destroy (); - + return list; } @@ -1116,11 +1116,11 @@ dialog.set_transient_for(this); dialog.set_modal (true); dialog.set_select_multiple (false); - + dialog.run(); var list = dialog.get_filenames(); dialog.destroy (); - + return list; } @@ -1129,7 +1129,7 @@ TreeSelection sel = tv_exclude.get_selection (); TreeIter iter; bool iterExists = tv_exclude.model.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { if (sel.iter_is_selected (iter)){ string path; tv_exclude.model.get (iter, 0, out path); @@ -1147,7 +1147,7 @@ msg += _("By default, any item that was included/excluded at the time of taking the snapshot will be included/excluded.") + " "; msg += _("Any exclude patterns in the current exclude list will also be excluded.") + " "; msg += _("To see which files are included in the snapshot use the 'Browse' button on the main window."); - + var dialog = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg); dialog.set_title("Warning"); dialog.set_default_size (200, -1); @@ -1156,11 +1156,11 @@ dialog.run(); dialog.destroy(); } - + private void btn_reset_exclude_list_clicked(){ //create a temp exclude list temp_exclude_list = new Gee.ArrayList(); - + //add all include/exclude items from snapshot list if (App.snapshot_to_restore != null){ foreach(string path in App.snapshot_to_restore.exclude_list){ @@ -1169,17 +1169,17 @@ } } } - + //add all exclude items from current list foreach(string path in App.exclude_list_user){ if (!temp_exclude_list.contains(path) && !App.exclude_list_default.contains(path) && !App.exclude_list_home.contains(path)){ - + if (!path.has_prefix("+ ")){ //don't add include entries from current exclude list temp_exclude_list.add(path); } } - } - + } + //refresh treeview refresh_tv_exclude(); } @@ -1187,16 +1187,16 @@ private void btn_restore_clicked(){ //check if backup device is online if (!check_backup_device_online()) { return; } - + //Note: A successful restore will reboot the system if target device is same as system device - + bool ok = check_and_mount_devices(); if (!ok){ return; } //save grub install options ---------------------- - + App.reinstall_grub2 = !chk_skip_grub_install.active; TreeIter iter; @@ -1210,18 +1210,18 @@ else{ App.grub_device = ""; } - + //save modified exclude list ---------------------- - + App.exclude_list_restore.clear(); - + //add default entries foreach(string path in App.exclude_list_default){ if (!App.exclude_list_restore.contains(path)){ App.exclude_list_restore.add(path); } } - + //add app entries foreach(AppExcludeEntry entry in App.exclude_list_apps){ if (entry.enabled){ @@ -1229,14 +1229,14 @@ if (!App.exclude_list_restore.contains(pattern)){ App.exclude_list_restore.add(pattern); } - + pattern = entry.pattern(true); if (!App.exclude_list_restore.contains(pattern)){ App.exclude_list_restore.add(pattern); } } } - + //add modified user entries foreach(string path in temp_exclude_list){ if (!App.exclude_list_restore.contains(path) && !App.exclude_list_home.contains(path)){ @@ -1250,20 +1250,20 @@ App.exclude_list_restore.add(path); } } - + //exclude timeshift backups string timeshift_path = "/timeshift/*"; if (!App.exclude_list_restore.contains(timeshift_path)){ App.exclude_list_restore.add(timeshift_path); } - + //exclude boot directory if grub install is skipped if (!App.reinstall_grub2){ App.exclude_list_restore.add("/boot/*"); } - + //display and confirm mount points ------------ - + if (!radio_sys.active){ if (show_mount_list() != Gtk.ResponseType.OK){ return; @@ -1271,7 +1271,7 @@ } //last option to quit - show disclaimer ------------ - + if (show_disclaimer() == Gtk.ResponseType.YES){ this.response(Gtk.ResponseType.OK); } @@ -1289,12 +1289,12 @@ return true; } } - + private bool check_and_mount_devices(){ TreeIter iter; Gtk.ListStore store; TreeSelection sel; - + //check if target device selected --------------- if (radio_sys.active){ @@ -1304,7 +1304,7 @@ } else{ //we are restoring to another disk - mount selected devices - + App.restore_target = null; App.mount_list.clear(); bool no_mount_points_set_by_user = true; @@ -1320,24 +1320,24 @@ if ((mount_point != null) && (mount_point.length > 0)){ mount_point = mount_point.strip(); no_mount_points_set_by_user = false; - + App.mount_list.add(new MountEntry(pi,mount_point)); if (mount_point == "/"){ App.restore_target = pi; - } + } } } if (App.restore_target == null){ //no root mount point was set by user - + if (no_mount_points_set_by_user){ //user has not set any mount points - + //check if a device is selected in treeview sel = tv_partitions.get_selection (); - if (sel.count_selected_rows() == 1){ + if (sel.count_selected_rows() == 1){ //use selected device as the root mount point for (bool next = store.get_iter_first (out iter); next; next = store.iter_next (ref iter)) { if (sel.iter_is_selected (iter)){ @@ -1354,7 +1354,7 @@ string title = _("Select Target Device"); string msg = _("Please select the target device from the list"); gtk_messagebox(title, msg, this, true); - return false; + return false; } } else{ @@ -1362,50 +1362,50 @@ string title = _("Select Root Device"); string msg = _("Please select the root device (/)"); gtk_messagebox(title, msg, this, true); - return false; + return false; } } - + //check BTRFS subvolume layout -------------- - + if (App.restore_target.type == "btrfs"){ if (App.check_btrfs_volume(App.restore_target) == false){ string title = _("Unsupported Subvolume Layout"); string msg = _("The target partition has an unsupported subvolume layout.") + " "; msg += _("Only ubuntu-type layouts with @ and @home subvolumes are currently supported.") + "\n\n"; gtk_messagebox(title, msg, this, true); - return false; + return false; } } //mount target device ------------- - + bool status = App.mount_target_device(this); if (status == false){ string title = _("Error"); string msg = _("Failed to mount device") + ": %s".printf(App.restore_target.device); gtk_messagebox(title, msg, this, true); - return false; + return false; } } - + //check if grub device selected --------------- - if (!chk_skip_grub_install.active && cmb_boot_device.active < 0){ + if (!chk_skip_grub_install.active && cmb_boot_device.active < 0){ string title =_("Boot device not selected"); string msg = _("Please select the boot device"); gtk_messagebox(title, msg, this, true); - return false; + return false; } - + return true; } - + private int show_disclaimer(){ string msg = App.disclaimer_pre_restore(); msg += "\n\n"; msg += "" + _("Continue with restore?") + "\n"; - + var dialog = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.YES_NO, msg); dialog.set_title(_("DISCLAIMER")); dialog.set_default_size (200, -1); @@ -1421,7 +1421,7 @@ int max_mount = _("Mount").length; int max_dev = _("Device").length; - + foreach(MountEntry mnt in App.mount_list){ string dev_name = mnt.device.short_name_with_alias; if (dev_name.length > max_dev){ max_dev = dev_name.length; } @@ -1437,7 +1437,7 @@ } msg += ""; msg += "\n" + _("Click OK to continue") + "\n"; - + var dialog = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK_CANCEL, msg); dialog.set_title(_("Confirm Mounts")); dialog.set_default_size (200, -1); @@ -1447,11 +1447,11 @@ dialog.destroy(); return response; } - + private void btn_cancel_clicked(){ App.unmount_target_device(); this.response(Gtk.ResponseType.CANCEL); - return; + return; } } diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/SettingsWindow.vala timeshift-1.7.4~178~ubuntu14.04.1/src/SettingsWindow.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/SettingsWindow.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/SettingsWindow.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,24 +1,24 @@ /* * SettingsWindow.vala - * + * * Copyright 2013 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ using Gtk; @@ -70,43 +70,43 @@ private ToolButton btn_remove; private ToolButton btn_warning; private ToolButton btn_reset_exclude_list; - + private MenuToolButton btn_exclude; private Gtk.Menu menu_exclude; private ImageMenuItem menu_exclude_add_file; private ImageMenuItem menu_exclude_add_folder; private ImageMenuItem menu_exclude_add_folder_contents; - + private MenuToolButton btn_include; private Gtk.Menu menu_include; private ImageMenuItem menu_include_add_file; private ImageMenuItem menu_include_add_folder; - + //actions private Button btn_save; private Button btn_cancel; - + private Gee.ArrayList temp_exclude_list; - + public SettingsWindow () { this.deletable = false; this.title = _("Settings"); this.window_position = WindowPosition.CENTER_ON_PARENT; this.set_destroy_with_parent (true); this.set_modal (true); - this.set_default_size (450, 500); + this.set_default_size (450, 500); this.icon = get_app_icon(16); - + //vboxMain vbox_main = get_content_area (); - + //notebook notebook = new Notebook (); notebook.margin = 6; vbox_main.pack_start (notebook, true, true, 0); //schedule tab --------------------------------------------- - + //lbl_schedule lbl_schedule = new Label (_("Schedule")); @@ -114,13 +114,13 @@ vbox_schedule = new Box (Gtk.Orientation.VERTICAL, 6); vbox_schedule.margin = 6; notebook.append_page (vbox_schedule, lbl_schedule); - + //automatic snapshots ------------------------------ - + //hbox_auto_snapshots hbox_auto_snapshots = new Box (Gtk.Orientation.HORIZONTAL, 6); vbox_schedule.add (hbox_auto_snapshots); - + //lbl_header_schedule lbl_header_schedule = new Gtk.Label("" + _("Scheduled Snapshots") + ""); lbl_header_schedule.set_use_markup(true); @@ -128,25 +128,25 @@ lbl_header_schedule.xalign = (float) 0.0; lbl_header_schedule.valign = Align.CENTER; hbox_auto_snapshots.add(lbl_header_schedule); - + Box hbox_schedule = new Box(Orientation.HORIZONTAL,0); hbox_auto_snapshots.add(hbox_schedule); - + //switch_schedule switch_schedule = new Gtk.Switch(); switch_schedule.set_size_request(100,20); switch_schedule.active = App.is_scheduled; hbox_auto_snapshots.pack_end(switch_schedule,false,false,0); - + switch_schedule.notify["active"].connect(switch_schedule_changed); - + //tv_schedule ----------------------------------------------- //tv_schedule tv_schedule = new TreeView(); tv_schedule.get_selection().mode = SelectionMode.MULTIPLE; tv_schedule.set_rules_hint (true); - + //sw_schedule sw_schedule = new ScrolledWindow(null, null); sw_schedule.set_shadow_type (ShadowType.ETCHED_IN); @@ -171,7 +171,7 @@ col_sched_level.pack_start (cell_sched_level, false); col_sched_level.set_cell_data_func (cell_sched_level, cell_sched_level_render); tv_schedule.append_column(col_sched_level); - + //col_sched_desc col_sched_desc = new TreeViewColumn(); col_sched_desc.title = " " + _("Description") + " "; @@ -180,9 +180,9 @@ col_sched_desc.pack_start (cell_sched_desc, false); col_sched_desc.set_cell_data_func (cell_sched_desc, cell_sched_desc_render); tv_schedule.append_column(col_sched_desc); - + //auto-remove tab ------------------------------------------------------ - + //lbl_auto_remove lbl_auto_remove = new Label (_("Auto-Remove")); @@ -200,7 +200,7 @@ tv_remove = new TreeView(); tv_remove.get_selection().mode = SelectionMode.MULTIPLE; tv_remove.set_rules_hint (true); - + //sw_remove sw_remove = new ScrolledWindow(null, null); sw_remove.set_shadow_type (ShadowType.ETCHED_IN); @@ -215,7 +215,7 @@ col_remove_rule.pack_start (cell_remove_rule, false); col_remove_rule.set_cell_data_func (cell_remove_rule, cell_remove_rule_render); tv_remove.append_column(col_remove_rule); - + //col_sched_desc col_remove_limit = new TreeViewColumn(); col_remove_limit.title = " " + _("Limit") + " "; @@ -226,7 +226,7 @@ col_remove_limit.pack_start (cell_remove_limit, false); col_remove_limit.set_cell_data_func (cell_remove_limit, cell_remove_limit_render); tv_remove.append_column(col_remove_limit); - + //col_remove_rule col_remove_units = new TreeViewColumn(); col_remove_units.title = ""; @@ -238,7 +238,7 @@ tv_schedule.sensitive = switch_schedule.active; //Exclude tab --------------------------------------------- - + //lbl_exclude lbl_exclude = new Label (_("Advanced")); @@ -248,39 +248,39 @@ notebook.append_page (vbox_exclude, lbl_exclude); //toolbar_exclude --------------------------------------------------- - + //toolbar_exclude toolbar_exclude = new Gtk.Toolbar (); toolbar_exclude.toolbar_style = ToolbarStyle.BOTH_HORIZ; //toolbar_exclude.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR); //toolbar.set_size_request(-1,48); vbox_exclude.add(toolbar_exclude); - + string png_exclude = App.share_folder + "/timeshift/images/item-gray.png"; string png_include = App.share_folder + "/timeshift/images/item-blue.png"; - + //btn_exclude btn_exclude = new Gtk.MenuToolButton(null,""); toolbar_exclude.add(btn_exclude); - + btn_exclude.is_important = true; btn_exclude.label = _("Exclude"); btn_exclude.set_tooltip_text (_("Exclude")); btn_exclude.set_icon_widget(new Gtk.Image.from_file (png_exclude)); - + //btn_include btn_include = new Gtk.MenuToolButton(null,""); toolbar_exclude.add(btn_include); - + btn_include.is_important = true; btn_include.label = _("Include"); btn_include.set_tooltip_text (_("Include")); btn_include.set_icon_widget(new Gtk.Image.from_file (png_include)); - + //btn_remove btn_remove = new Gtk.ToolButton.from_stock("gtk-remove"); toolbar_exclude.add(btn_remove); - + btn_remove.is_important = true; btn_remove.label = _("Remove"); btn_remove.set_tooltip_text (_("Remove selected items")); @@ -290,7 +290,7 @@ //btn_warning btn_warning = new Gtk.ToolButton.from_stock("gtk-dialog-warning"); toolbar_exclude.add(btn_warning); - + btn_warning.is_important = true; btn_warning.label = _("Warning"); btn_warning.set_tooltip_text (_("Warning")); @@ -302,27 +302,27 @@ separator.set_draw (false); separator.set_expand (true); toolbar_exclude.add(separator); - + //btn_reset_exclude_list btn_reset_exclude_list = new Gtk.ToolButton.from_stock("gtk-refresh"); toolbar_exclude.add(btn_reset_exclude_list); - + btn_reset_exclude_list.is_important = false; btn_reset_exclude_list.label = _("Reset"); btn_reset_exclude_list.set_tooltip_text (_("Clear the list")); btn_reset_exclude_list.clicked.connect (btn_reset_exclude_list_clicked); - + //menu_exclude menu_exclude = new Gtk.Menu(); btn_exclude.set_menu(menu_exclude); - + //menu_exclude_add_file menu_exclude_add_file = new ImageMenuItem.with_label (""); menu_exclude_add_file.label = _("Exclude File(s)"); menu_exclude_add_file.set_image(new Gtk.Image.from_file (png_exclude)); menu_exclude.append(menu_exclude_add_file); - + menu_exclude_add_file.activate.connect (menu_exclude_add_files_clicked); //menu_exclude_add_folder @@ -330,7 +330,7 @@ menu_exclude_add_folder.label = _("Exclude Directory"); menu_exclude_add_folder.set_image(new Gtk.Image.from_file (png_exclude)); menu_exclude.append(menu_exclude_add_folder); - + menu_exclude_add_folder.activate.connect (menu_exclude_add_folder_clicked); //menu_exclude_add_folder_contents @@ -338,19 +338,19 @@ menu_exclude_add_folder_contents.label = _("Exclude Directory Contents"); menu_exclude_add_folder_contents.set_image(new Gtk.Image.from_file (png_exclude)); menu_exclude.append(menu_exclude_add_folder_contents); - + menu_exclude_add_folder_contents.activate.connect (menu_exclude_add_folder_contents_clicked); - + //menu_include menu_include = new Gtk.Menu(); btn_include.set_menu(menu_include); - + //menu_include_add_file menu_include_add_file = new ImageMenuItem.with_label (""); menu_include_add_file.label = _("Include File(s)"); menu_include_add_file.set_image(new Gtk.Image.from_file (png_include)); menu_include.append(menu_include_add_file); - + menu_include_add_file.activate.connect (menu_include_add_files_clicked); //menu_include_add_folder @@ -358,21 +358,21 @@ menu_include_add_folder.label = _("Include Directory"); menu_include_add_folder.set_image(new Gtk.Image.from_file (png_include)); menu_include.append(menu_include_add_folder); - + menu_include_add_folder.activate.connect (menu_include_add_folder_clicked); - + menu_exclude.show_all(); menu_include.show_all(); //tv_exclude----------------------------------------------- - + //tv_exclude tv_exclude = new TreeView(); tv_exclude.get_selection().mode = SelectionMode.MULTIPLE; tv_exclude.headers_visible = true; tv_exclude.set_rules_hint (true); //tv_exclude.row_activated.connect(tv_exclude_row_activated); - + //sw_exclude sw_exclude = new ScrolledWindow(null, null); sw_exclude.set_shadow_type (ShadowType.ETCHED_IN); @@ -384,23 +384,23 @@ col_exclude = new TreeViewColumn(); col_exclude.title = _("File Pattern"); col_exclude.expand = true; - + CellRendererText cell_exclude_margin = new CellRendererText (); cell_exclude_margin.text = ""; col_exclude.pack_start (cell_exclude_margin, false); - + CellRendererPixbuf cell_exclude_icon = new CellRendererPixbuf (); col_exclude.pack_start (cell_exclude_icon, false); col_exclude.set_attributes(cell_exclude_icon, "pixbuf", 1); - + CellRendererText cell_exclude_text = new CellRendererText (); col_exclude.pack_start (cell_exclude_text, false); col_exclude.set_cell_data_func (cell_exclude_text, cell_exclude_text_render); cell_exclude_text.editable = true; tv_exclude.append_column(col_exclude); - + cell_exclude_text.edited.connect (cell_exclude_text_edited); - + //lnk_default_list lnk_default_list = new LinkButton.with_label("",_("Some locations are excluded by default")); lnk_default_list.xalign = (float) 0.0; @@ -408,25 +408,25 @@ vbox_exclude.add(lnk_default_list); //initialize ------------------ - + temp_exclude_list = new Gee.ArrayList(); - + foreach(string path in App.exclude_list_user){ if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); } } - + refresh_tv_exclude(); refresh_tv_schedule(); refresh_tv_remove(); // Actions ---------------------------------------------- - + //btn_save btn_save = (Button) add_button ("gtk-save", Gtk.ResponseType.ACCEPT); btn_save.clicked.connect (btn_save_clicked); - + //btn_cancel btn_cancel = (Button) add_button ("gtk-cancel", Gtk.ResponseType.CANCEL); btn_cancel.clicked.connect (btn_cancel_clicked); @@ -438,13 +438,13 @@ model.get (iter, 0, out val, -1); (cell as Gtk.CellRendererToggle).active = val; } - + private void cell_sched_level_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ string val; model.get (iter, 1, out val, -1); (cell as Gtk.CellRendererText).text = val; } - + private void cell_sched_desc_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ string val; model.get (iter, 2, out val, -1); @@ -456,7 +456,7 @@ model.get (iter, 0, out val, -1); (cell as Gtk.CellRendererText).markup = val; } - + private void cell_remove_limit_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ int val; string units; @@ -464,19 +464,19 @@ (cell as Gtk.CellRendererText).text = (units == "GB") ? "%.0f".printf(val/1024.0) : val.to_string(); (cell as Gtk.CellRendererText).background = "#F2F5A9"; } - + private void cell_remove_units_render (CellLayout cell_layout, CellRenderer cell, TreeModel model, TreeIter iter){ string val; model.get (iter, 2, out val, -1); (cell as Gtk.CellRendererText).text = val; } - + private void cell_sched_enable_toggled (string path){ TreeIter iter; var model = (Gtk.ListStore)tv_schedule.model; bool enabled; int count; - + model.get_iter_from_string (out iter, path); model.get (iter, 0, out enabled, 2, out count,-1); model.set (iter, 0, !enabled); @@ -486,19 +486,19 @@ for(int k = 0; k<5; k++){ model.get_iter_from_string (out iter, k.to_string()); model.get (iter, 0, out enabled, -1); - if (enabled){ - atleast_one_enabled = true; - break; + if (enabled){ + atleast_one_enabled = true; + break; } } - + switch_schedule.active = atleast_one_enabled; } - + private void cell_remove_limit_edited (string path, string new_text) { int count = 0; string units; - + TreeIter iter; var model = (Gtk.ListStore)tv_remove.model; model.get_iter_from_string (out iter, path); @@ -515,16 +515,16 @@ model.get (iter, 0, out pattern, -1); (cell as Gtk.CellRendererText).text = pattern.has_prefix("+ ") ? pattern[2:pattern.length] : pattern; } - + private void cell_exclude_text_edited (string path, string new_text) { string old_pattern; string new_pattern; - + TreeIter iter; var model = (Gtk.ListStore) tv_exclude.model; model.get_iter_from_string (out iter, path); model.get (iter, 0, out old_pattern, -1); - + if (old_pattern.has_prefix("+ ")){ new_pattern = "+ " + new_text; } @@ -532,7 +532,7 @@ new_pattern = new_text; } model.set (iter, 0, new_pattern); - + int index = temp_exclude_list.index_of(old_pattern); temp_exclude_list.insert(index, new_pattern); temp_exclude_list.remove(old_pattern); @@ -552,22 +552,22 @@ model.set (iter, 0, App.schedule_weekly); model.set (iter, 1, _("Weekly")); model.set (iter, 2, _("Keep one snapshot per week")); - + model.append(out iter); model.set (iter, 0, App.schedule_daily); model.set (iter, 1, _("Daily")); model.set (iter, 2, _("Keep one snapshot per day")); - + model.append(out iter); model.set (iter, 0, App.schedule_hourly); model.set (iter, 1, _("Hourly")); model.set (iter, 2, _("Keep one snapshot per hour")); - + model.append(out iter); model.set (iter, 0, App.schedule_boot); model.set (iter, 1, _("Boot")); model.set (iter, 2, _("Keep one snapshot per reboot")); - + tv_schedule.set_model (model); tv_schedule.columns_autosize (); } @@ -575,7 +575,7 @@ private void refresh_tv_remove(){ var model = new Gtk.ListStore(3, typeof(string), typeof(int), typeof(string)); - + string span = ""; if (switch_schedule.active){ span = ""; @@ -583,7 +583,7 @@ else{ span = ""; } - + TreeIter iter; model.append(out iter); model.set (iter, 0, span + _("Monthly") + " " + _("snapshots older than")); @@ -594,45 +594,45 @@ model.set (iter, 0, span + _("Weekly") + " " + _("snapshots older than")); model.set (iter, 1, App.count_weekly); model.set (iter, 2, "weeks"); - + model.append(out iter); model.set (iter, 0, span + _("Daily") + " " + _("snapshots older than")); model.set (iter, 1, App.count_daily); model.set (iter, 2, "days"); - + model.append(out iter); model.set (iter, 0, span + _("Hourly") + " " + _("snapshots older than")); model.set (iter, 1, App.count_hourly); model.set (iter, 2, "hours"); - + model.append(out iter); model.set (iter, 0, span + _("Boot") + " " + _("snapshots older than")); model.set (iter, 1, App.count_boot); model.set (iter, 2, "reboots"); - + model.append(out iter); model.set (iter, 0, _("All snapshots older than")); model.set (iter, 1, App.retain_snapshots_max_days); model.set (iter, 2, "days"); - + model.append(out iter); model.set (iter, 0, _("When free space less than")); model.set (iter, 1, App.minimum_free_disk_space_mb); model.set (iter, 2, "GB"); - + tv_remove.set_model (model); //tv_remove.columns_autosize (); } - + private void refresh_tv_exclude(){ var model = new Gtk.ListStore(2, typeof(string), typeof(Gdk.Pixbuf)); tv_exclude.model = model; - + foreach(string path in temp_exclude_list){ tv_exclude_add_item(path); } } - + private void tv_exclude_add_item(string path){ Gdk.Pixbuf pix_exclude = null; Gdk.Pixbuf pix_include = null; @@ -649,7 +649,7 @@ TreeIter iter; var model = (Gtk.ListStore) tv_exclude.model; model.append(out iter); - + if (path.has_prefix("+ ")){ pix_selected = pix_include; } @@ -658,31 +658,31 @@ } model.set (iter, 0, path, 1, pix_selected, -1); - + Adjustment adj = tv_exclude.get_hadjustment(); adj.value = adj.upper; } - - + + private void switch_schedule_changed(){ tv_schedule.sensitive = switch_schedule.active; if (switch_schedule.active){ - bool atleast_one_enabled = App.schedule_boot + bool atleast_one_enabled = App.schedule_boot || App.schedule_hourly || App.schedule_daily || App.schedule_weekly || App.schedule_monthly; - + if(!atleast_one_enabled){ TreeIter iter; var store = (Gtk.ListStore) tv_schedule.model; - bool enabled; + bool enabled; int index = -1; - + bool iterExists = store.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { store.get (iter, 0, out enabled,-1); switch(++index){ case 4: @@ -697,10 +697,10 @@ tv_schedule.get_selection().unselect_all(); tv_remove.get_selection().unselect_all(); } - + refresh_tv_remove(); //refresh the item colors } - + private bool lnk_default_list_activate(){ //show message window ----------------- var dialog = new ExcludeMessageWindow(); @@ -713,9 +713,9 @@ private void menu_exclude_add_files_clicked(){ - + var list = browse_files(); - + if (list.length() > 0){ foreach(string path in list){ if (!temp_exclude_list.contains(path)){ @@ -728,14 +728,14 @@ } private void menu_exclude_add_folder_clicked(){ - + var list = browse_folder(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path + "/"; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -746,14 +746,14 @@ } private void menu_exclude_add_folder_contents_clicked(){ - + var list = browse_folder(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path + "/*"; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -762,18 +762,18 @@ } } } - + private void menu_include_add_files_clicked(){ - + var list = browse_files(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path.has_prefix("+ ") ? path : "+ " + path; if (!temp_exclude_list.contains(path)){ - temp_exclude_list.add(path); + temp_exclude_list.add(path); tv_exclude_add_item(path); App.first_snapshot_size = 0; //re-calculate } @@ -782,15 +782,15 @@ } private void menu_include_add_folder_clicked(){ - + var list = browse_folder(); - + if (list.length() > 0){ foreach(string path in list){ - + path = path.has_prefix("+ ") ? path : "+ " + path; path = path + "/***"; - + if (!temp_exclude_list.contains(path)){ temp_exclude_list.add(path); tv_exclude_add_item(path); @@ -813,7 +813,7 @@ dialog.run(); var list = dialog.get_filenames(); dialog.destroy (); - + return list; } @@ -826,20 +826,20 @@ dialog.set_transient_for(this); dialog.set_modal (true); dialog.set_select_multiple (false); - + dialog.run(); var list = dialog.get_filenames(); dialog.destroy (); - + return list; } - - + + private void btn_remove_clicked(){ TreeSelection sel = tv_exclude.get_selection (); TreeIter iter; bool iterExists = tv_exclude.model.get_iter_first (out iter); - while (iterExists) { + while (iterExists) { if (sel.iter_is_selected (iter)){ string path; tv_exclude.model.get (iter, 0, out path); @@ -848,16 +848,16 @@ } iterExists = tv_exclude.model.iter_next (ref iter); } - + refresh_tv_exclude(); } - + private void btn_warning_clicked(){ string msg = ""; msg += _("Documents, music and other folders in your home directory are excluded by default.") + " "; msg += _("Please do NOT include these folders in your snapshot unless you have a very good reason for doing so.") + " "; msg += _("If you include any specific folders then these folders will get overwritten with previous contents when you restore a snapshot."); - + var dialog = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, Gtk.MessageType.WARNING, Gtk.ButtonsType.OK, msg); dialog.set_title("Warning"); dialog.set_default_size (200, -1); @@ -866,18 +866,18 @@ dialog.run(); dialog.destroy(); } - + private void btn_reset_exclude_list_clicked(){ //create a temp exclude list ---------------------------- - + temp_exclude_list = new Gee.ArrayList(); - + //refresh treeview -------------------------- - + refresh_tv_exclude(); } - - + + private void btn_save_clicked(){ tv_schedule_save_changes(); tv_remove_save_changes(); @@ -885,7 +885,7 @@ App.save_app_config(); App.cron_job_update(); - + this.destroy(); } @@ -894,13 +894,13 @@ TreeModel store = tv_schedule.model; bool enabled; int index = -1; - + bool iterExists = store.get_iter_first (out iter); - - while (iterExists) { - + + while (iterExists) { + store.get (iter, 0, out enabled,-1); - + switch(++index){ case 0: App.schedule_monthly = enabled; @@ -920,24 +920,24 @@ } iterExists = store.iter_next (ref iter); } - + if (!App.live_system()){ App.is_scheduled = switch_schedule.active; } } - + private void tv_remove_save_changes(){ TreeIter iter; TreeModel store = tv_remove.model; int count = -1; int index = -1; - + bool iterExists = store.get_iter_first (out iter); - - while (iterExists) { - + + while (iterExists) { + store.get (iter, 1, out count, -1); - + switch(++index){ case 0: App.count_monthly = count; @@ -973,7 +973,7 @@ } } } - + private void btn_cancel_clicked(){ this.destroy(); } diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/timeshift-uninstall timeshift-1.7.4~178~ubuntu14.04.1/src/timeshift-uninstall --- timeshift-1.7.3~177~ubuntu14.04.1/src/timeshift-uninstall 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/timeshift-uninstall 2015-09-08 01:01:52.000000000 +0000 @@ -35,7 +35,7 @@ if [ "$2" == 0 ]; then add_newline='-n' fi - + if [ $COLORS_SUPPORTED -eq 0 ]; then echo -e ${add_newline} "[${Red}!${Reset}] ${Yellow}$1${Reset}" else @@ -48,7 +48,7 @@ if [ "$2" == 0 ]; then add_newline='-n' fi - + if [ $COLORS_SUPPORTED -eq 0 ]; then echo -e ${add_newline} "[${Red}X${Reset}] ${Yellow}$1${Reset}" else @@ -112,7 +112,7 @@ rm -rf "/usr/share/${app_name}" rm -rf "/usr/share/doc/${app_name}" rm -f /usr/share/locale/*/LC_MESSAGES/${app_name}.mo - + if [ -d /timeshift ]; then remove_backups=n MSG_INFO "Remove backups on system partition? (y/n):" "0" @@ -120,7 +120,7 @@ if [ "$remove_backups" == "" ]; then remove_backups=n fi - + if [ "$remove_backups" == "y" ]; then MSG_INFO "Freeing disk space..." echo "" diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/src/Utility.vala timeshift-1.7.4~178~ubuntu14.04.1/src/Utility.vala --- timeshift-1.7.3~177~ubuntu14.04.1/src/Utility.vala 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/src/Utility.vala 2015-09-08 01:01:52.000000000 +0000 @@ -1,24 +1,24 @@ /* * Utility.vala - * + * * Copyright 2012 Tony George - * + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. - * - * + * + * */ using Gtk; @@ -46,19 +46,19 @@ public double GiB = 1024 * 1024 * 1024; namespace TeeJee.Logging{ - + /* Functions for logging messages to console and log files */ using TeeJee.Misc; - + public DataOutputStream dos_log; - + public bool LOG_ENABLE = true; public bool LOG_TIMESTAMP = true; public bool LOG_COLORS = true; public bool LOG_DEBUG = false; public bool LOG_COMMANDS = false; - + public const string TERM_COLOR_YELLOW = "\033[" + "1;33" + "m"; public const string TERM_COLOR_GREEN = "\033[" + "1;32" + "m"; public const string TERM_COLOR_RED = "\033[" + "1;31" + "m"; @@ -67,78 +67,78 @@ public void log_msg (string message, bool highlight = false){ if (!LOG_ENABLE) { return; } - + string msg = ""; - + if (highlight && LOG_COLORS){ msg += "\033[1;38;5;34m"; } - + if (LOG_TIMESTAMP){ msg += "[" + timestamp() + "] "; } - + msg += message; - + if (highlight && LOG_COLORS){ msg += "\033[0m"; } - + msg += "\n"; - + stdout.printf (msg); try { if (dos_log != null){ dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); } - } + } catch (Error e) { stdout.printf (e.message); } } - + public void log_msg_to_file (string message, bool highlight = false){ try { if (dos_log != null){ dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); } - } + } catch (Error e) { stdout.printf (e.message); } } - + public void log_error (string message, bool highlight = true, bool is_warning = false){ if (!LOG_ENABLE) { return; } - + string msg = ""; - + if (highlight && LOG_COLORS){ msg += "\033[1;38;5;9m"; } - + if (LOG_TIMESTAMP){ msg += "[" + timestamp() + "] "; } - + string prefix = (is_warning) ? _("Warning") : _("Error"); - + msg += prefix + ": " + message; - + if (highlight && LOG_COLORS){ msg += "\033[0m"; } - + msg += "\n"; - + stdout.printf (msg); - + try { if (dos_log != null){ dos_log.put_string ("[%s] %s: %s\n".printf(timestamp(), prefix, message)); } - } + } catch (Error e) { stdout.printf (e.message); } @@ -146,7 +146,7 @@ public void log_debug (string message){ if (!LOG_ENABLE) { return; } - + if (LOG_DEBUG){ //display output and write to log log_msg (message); @@ -157,16 +157,16 @@ if (dos_log != null){ dos_log.put_string ("[%s] %s\n".printf(timestamp(), message)); } - } + } catch (Error e) { stdout.printf (e.message); } } } - + public void log_empty_line(){ if (!LOG_ENABLE) { return; } - + stdout.printf ("\n"); stdout.flush(); @@ -174,7 +174,7 @@ if (dos_log != null){ dos_log.put_string ("\n"); } - } + } catch (Error e) { stdout.printf (e.message); } @@ -182,42 +182,42 @@ } namespace TeeJee.FileSystem{ - + /* Convenience functions for handling files and directories */ - + using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.ProcessManagement; using TeeJee.Misc; - + public void file_delete(string filePath){ - + /* Check and delete file */ - + try { var file = File.new_for_path (filePath); - if (file.query_exists ()) { - file.delete (); + if (file.query_exists ()) { + file.delete (); } } catch (Error e) { log_error (e.message); } } - + public bool file_exists (string filePath){ /* Check if file exists */ return ( FileUtils.test(filePath, GLib.FileTest.EXISTS) && FileUtils.test(filePath, GLib.FileTest.IS_REGULAR)); } - + public bool device_exists (string filePath){ /* Check if device exists */ return (FileUtils.test(filePath, GLib.FileTest.EXISTS)); } - + public void file_copy (string src_file, string dest_file){ try{ var file_src = File.new_for_path (src_file); - if (file_src.query_exists()) { + if (file_src.query_exists()) { var file_dest = File.new_for_path (dest_file); file_src.copy(file_dest,FileCopyFlags.OVERWRITE,null,null); } @@ -226,18 +226,18 @@ log_error (e.message); } } - + public bool dir_exists (string filePath){ - + /* Check if directory exists */ - + return ( FileUtils.test(filePath, GLib.FileTest.EXISTS) && FileUtils.test(filePath, GLib.FileTest.IS_DIR)); } - + public bool create_dir (string filePath){ - + /* Creates a directory along with parents */ - + try{ var dir = File.parse_name (filePath); if (dir.query_exists () == false) { @@ -245,16 +245,16 @@ } return true; } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); return false; } } public bool check_and_create_dir_with_parents (string filePath){ - + /* Creates a directory along with parents */ - + try{ var dir = File.parse_name (filePath); if (dir.query_exists () == false) { @@ -262,66 +262,66 @@ } return true; } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); return false; } } - + public bool move_file (string sourcePath, string destPath){ - + /* Move file from one location to another */ - + try{ File fromFile = File.new_for_path (sourcePath); File toFile = File.new_for_path (destPath); fromFile.move (toFile, FileCopyFlags.NONE); return true; } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); return false; } } - + public bool copy_file (string sourcePath, string destPath){ - + /* Copy file from one location to another */ - + try{ File fromFile = File.new_for_path (sourcePath); File toFile = File.new_for_path (destPath); fromFile.copy (toFile, FileCopyFlags.NONE); return true; } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); return false; } } - + public string? read_file (string file_path){ - + /* Reads text from file */ - + string txt; size_t size; - + try{ GLib.FileUtils.get_contents (file_path, out txt, out size); - return txt; + return txt; } catch (Error e){ log_error (e.message); } - + return null; } - + public bool write_file (string file_path, string contents){ - + /* Write text to file */ - + try{ var file = File.new_for_path (file_path); if (file.query_exists ()) { file.delete (); } @@ -334,63 +334,63 @@ catch (Error e) { log_error (e.message); return false; - } + } } - + public long get_file_count(string path){ - + /* Return total count of files and directories */ - + string cmd = ""; string std_out; string std_err; int ret_val; - + cmd = "find \"%s\" | wc -l".printf(path); ret_val = execute_command_script_sync(cmd, out std_out, out std_err); return long.parse(std_out); } public long get_file_size(string path){ - + /* Returns size of files and directories in KB*/ - + string cmd = ""; string output = ""; - + cmd = "du -s \"%s\"".printf(path); output = execute_command_sync_get_output(cmd); return long.parse(output.split("\t")[0]); } public string get_file_size_formatted(string path){ - + /* Returns size of files and directories in KB*/ - + string cmd = ""; string output = ""; - + cmd = "du -s -h \"%s\"".printf(path); output = execute_command_sync_get_output(cmd); return output.split("\t")[0].strip(); } - + public int chmod (string file, string permission){ - + /* Change file permissions */ - + return execute_command_sync ("chmod " + permission + " \"%s\"".printf(file)); } - + public string resolve_relative_path (string filePath){ - + /* Resolve the full path of given file using 'realpath' command */ - + string filePath2 = filePath; if (filePath2.has_prefix ("~")){ filePath2 = Environment.get_home_dir () + "/" + filePath2[2:filePath2.length]; } - + try { string output = ""; Process.spawn_command_line_sync("realpath \"%s\"".printf(filePath2), out output); @@ -402,14 +402,14 @@ catch(Error e){ log_error (e.message); } - + return filePath2; } - + public int rsync (string sourceDirectory, string destDirectory, bool updateExisting, bool deleteExtra){ - + /* Sync files with rsync */ - + string cmd = "rsync --recursive --perms --chmod=a=rwx"; cmd += updateExisting ? "" : " --ignore-existing"; cmd += deleteExtra ? " --delete" : ""; @@ -420,17 +420,17 @@ } namespace TeeJee.Devices{ - + /* Functions and classes for handling disk partitions */ - + using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.ProcessManagement; public class Device : GLib.Object{ - + /* Class for storing disk information */ - + GUdev.Device udev_device; public string device = ""; public string type = ""; @@ -441,7 +441,7 @@ public string model = ""; public bool removable = false; public string devtype = ""; //disk or partition - + public long size_mb = 0; public long used_mb = 0; @@ -451,48 +451,48 @@ public Gee.ArrayList mount_points; public Gee.ArrayList symlinks; public string mount_options = ""; - + public static Gee.HashMap device_list_master; - + public Device(){ mount_points = new Gee.ArrayList(); symlinks = new Gee.ArrayList(); } - + public Device.from_udev(GUdev.Device d){ mount_points = new Gee.ArrayList(); symlinks = new Gee.ArrayList(); - + udev_device = d; - + device = d.get_device_file(); - + devtype = d.get_devtype(); //change devtype to 'partition' for device mapper disks if (device.has_prefix("/dev/dm-")){ devtype = "partition"; } - + label = d.get_property("ID_FS_LABEL"); label = (label == null) ? "" : label; - + uuid = d.get_property("ID_FS_UUID"); uuid = (uuid == null) ? "" : uuid.down(); - + type = d.get_property("ID_FS_TYPE"); type = (type == null) ? "" : type.down(); type = type.contains("luks") ? "luks" : type; - + foreach (string symlink in d.get_device_file_symlinks()){ symlinks.add(symlink); } } - - /* Returns: + + /* Returns: * 'sda3' for '/dev/sda3' * 'luks' for '/dev/mapper/luks' * */ - + public string name{ owned get{ if (devtype == "partition"){ @@ -522,7 +522,7 @@ } } } - + public string short_name_with_alias{ owned get{ string text = ""; @@ -532,7 +532,7 @@ symlink = sym.replace("/dev/mapper/","").replace("/dev/",""); } } - + if (symlink.length > 15){ symlink = symlink[0:14] + "..."; } @@ -548,14 +548,14 @@ } } } - + public string description(){ return description_formatted().replace("","").replace("",""); } public string description_formatted(){ string s = ""; - + if (devtype == "disk"){ s += "" + short_name_with_alias + ""; s += ((vendor.length > 0)||(model.length > 0)) ? (" ~ " + vendor + " " + model) : ""; @@ -566,10 +566,10 @@ s += (type.length > 0) ? " ~ " + type : ""; s += (used.length > 0) ? " ~ " + used + " / " + size + " GB used (" + used_percent + ")" : ""; } - + return s; } - + public string description_full(){ string s = ""; s += device; @@ -577,16 +577,16 @@ s += (uuid.length > 0) ? " ~ " + uuid : ""; s += (type.length > 0) ? " ~ " + type : ""; s += (used.length > 0) ? " ~ " + used + " / " + size + " GB used (" + used_percent + ")" : ""; - + string mps = ""; foreach(string mp in mount_points){ mps += mp + " "; } s += (mps.length > 0) ? " ~ " + mps.strip() : ""; - + return s; } - + public string description_usage(){ if (used.length > 0){ return used + " / " + size + " used (" + used_percent + ")"; @@ -595,31 +595,31 @@ return ""; } } - + public string size{ owned get{ return (size_mb == 0) ? "" : "%.1f".printf(size_mb/1024.0); } } - + public string used{ owned get{ return (used_mb == 0) ? "" : "%.1f".printf(used_mb/1024.0); } } - + public long free_mb{ get{ return (size_mb - used_mb); } } - + public bool is_mounted{ get{ return (mount_points.size > 0); } } - + public string free{ owned get{ return (free_mb == 0) ? "" : "%.1f GB".printf(free_mb/1024.0); @@ -654,15 +654,15 @@ map.set(dev.uuid, dev); } } - + device_list_master = map; - + return map; } - + public static Gee.HashMap get_block_devices_using_blkid(string device_file){ - /* Returns list of mounted partitions using 'blkid' command + /* Returns list of mounted partitions using 'blkid' command Populates device, type, uuid, label */ var map = new Gee.HashMap(); @@ -673,40 +673,40 @@ int ret_val; Regex rex; MatchInfo match; - + cmd = "/sbin/blkid" + ((device_file.length > 0) ? " " + device_file: ""); ret_val = execute_command_script_sync(cmd, out std_out, out std_err); if (ret_val != 0){ log_error ("blkid: " + _("Failed to get partition list") + ((device_file.length > 0) ? ": " + device_file : "")); return map; //return empty map } - + /* sample output ----------------- - /dev/sda1: LABEL="System Reserved" UUID="F476B08076B04560" TYPE="ntfs" - /dev/sda2: LABEL="windows" UUID="BE00B6DB00B69A3B" TYPE="ntfs" + /dev/sda1: LABEL="System Reserved" UUID="F476B08076B04560" TYPE="ntfs" + /dev/sda2: LABEL="windows" UUID="BE00B6DB00B69A3B" TYPE="ntfs" /dev/sda3: UUID="03f3f35d-71fa-4dff-b740-9cca19e7555f" TYPE="ext4" */ - + //parse output and build filesystem map ------------- foreach(string line in std_out.split("\n")){ if (line.strip().length == 0) { continue; } - + Device pi = new Device(); - + pi.device = line.split(":")[0].strip(); - + if (pi.device.length == 0) { continue; } - + //exclude non-standard devices -------------------- if (!pi.device.has_prefix("/dev/")){ continue; } - - if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { + + if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { //ok } else if (pi.device.has_prefix("/dev/disk/by-uuid/")){ @@ -718,18 +718,18 @@ } //parse & populate fields ------------------ - + try{ rex = new Regex("""LABEL=\"([^\"]*)\""""); if (rex.match (line, 0, out match)){ pi.label = match.fetch(1).strip(); } - + rex = new Regex("""UUID=\"([^\"]*)\""""); if (rex.match (line, 0, out match)){ pi.uuid = match.fetch(1).strip(); } - + rex = new Regex("""TYPE=\"([^\"]*)\""""); if (rex.match (line, 0, out match)){ pi.type = match.fetch(1).strip(); @@ -738,33 +738,33 @@ catch(Error e){ log_error (e.message); } - + //add to map ------------------------- - + if ((pi.uuid.length > 0) && !map.has_key(pi.uuid)){ map.set(pi.uuid, pi); } } - + return map; } public static Gee.HashMap get_disk_space_using_df(string device_or_mount_point = ""){ - - /* Returns list of mounted partitions using 'df' command + + /* Returns list of mounted partitions using 'df' command Populates device, type, size, used and mount_point_list */ - + var map = new Gee.HashMap(); - + string std_out; string std_err; string cmd; int ret_val; - + cmd = "df -T -BM" + ((device_or_mount_point.length > 0) ? " \"%s\"".printf(device_or_mount_point): ""); ret_val = execute_command_script_sync(cmd, out std_out, out std_err); //ret_val is not reliable, no need to check - + /* sample output ----------------- @@ -776,7 +776,7 @@ none tmpfs 5M 0M 5M 0% /run/lock /dev/sda3 ext4 25070M 19508M 4282M 83% /mnt/timeshift */ - + string[] lines = std_out.split("\n"); int line_num = 0; @@ -784,14 +784,14 @@ if (++line_num == 1) { continue; } if (line.strip().length == 0) { continue; } - + Device pi = new Device(); - + //parse & populate fields ------------------ - + int k = 1; foreach(string val in line.split(" ")){ - + if (val.strip().length == 0){ continue; } switch(k++){ @@ -821,21 +821,21 @@ break; } } - - /* Note: + + /* Note: * The mount points displayed by 'df' are not reliable. * For example, if same device is mounted at 2 locations, 'df' displays only the first location. * Hence, we will not populate the 'mount_points' field in Device object * Use get_mounted_filesystems_using_mtab() if mount info is required * */ - + //exclude non-standard devices -------------------- - + if (!pi.device.has_prefix("/dev/")){ continue; } - - if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { + + if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { //ok } else if (pi.device.has_prefix("/dev/disk/by-uuid/")){ @@ -847,11 +847,11 @@ } //get uuid --------------------------- - + pi.uuid = get_device_uuid(pi.device); //add to map ------------------------- - + if ((pi.uuid.length > 0) && !map.has_key(pi.uuid)){ map.set(pi.uuid, pi); } @@ -861,19 +861,19 @@ } public static Gee.HashMap get_mounted_filesystems_using_mtab(){ - + /* Returns list of mounted partitions by reading /proc/mounts Populates device, type and mount_point_list */ var map = new Gee.HashMap(); - + string mtab_path = "/etc/mtab"; string mtab_lines = ""; - + File f; - + //find mtab file ----------- - + mtab_path = "/proc/mounts"; f = File.new_for_path(mtab_path); if(!f.query_exists()){ @@ -887,17 +887,17 @@ } } } - + /* Note: - * /etc/mtab represents what 'mount' passed to the kernel + * /etc/mtab represents what 'mount' passed to the kernel * whereas /proc/mounts shows the data as seen inside the kernel * Hence /proc/mounts is always up-to-date whereas /etc/mtab might not be * */ - + //read ----------- - + mtab_lines = read_file(mtab_path); - + /* sample mtab ----------------- @@ -915,28 +915,28 @@ filesystemtype - the type of filesystem mounted. options - the mount options for the filesystem dump - used by dump to decide if the filesystem needs dumping. - fsckorder - used by fsck to detrmine the fsck pass to use. + fsckorder - used by fsck to detrmine the fsck pass to use. */ - + /* Note: * We are interested only in the last device that was mounted at a given mount point * Hence the lines must be parsed in reverse order (from last to first) * */ - + //parse ------------ - + string[] lines = mtab_lines.split("\n"); var mount_list = new Gee.ArrayList(); - + for (int i = lines.length - 1; i >= 0; i--){ - + string line = lines[i].strip(); if (line.length == 0) { continue; } - + Device pi = new Device(); //parse & populate fields ------------------ - + int k = 1; foreach(string val in line.split(" ")){ if (val.strip().length == 0){ continue; } @@ -964,14 +964,14 @@ break; } } - + //exclude unknown device names ---------------- if (!pi.device.has_prefix("/dev/")){ continue; } - - if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { + + if (pi.device.has_prefix("/dev/sd") || pi.device.has_prefix("/dev/hd") || pi.device.has_prefix("/dev/mapper/") || pi.device.has_prefix("/dev/dm")) { //ok } else if (pi.device.has_prefix("/dev/disk/by-uuid/")){ @@ -983,11 +983,11 @@ } //get uuid --------------------------- - + pi.uuid = get_device_uuid(pi.device); //add to map ------------------------- - + if (pi.uuid.length > 0){ if (!map.has_key(pi.uuid)){ map.set(pi.uuid, pi); @@ -1004,12 +1004,12 @@ return map; } - + public static Gee.HashMap get_filesystems(bool get_space = true, bool get_mounts = true){ - + /* Returns list of block devices Populates all fields in Device class */ - + var map = get_block_devices_using_udev(); if (get_space){ @@ -1023,9 +1023,9 @@ pi.used_mb = pi_df.used_mb; pi.available = pi_df.available; pi.used_percent = pi_df.used_percent; - + if (pi.device.has_prefix("/dev/disk/by-uuid/") || pi.device.length > 25){ - //check if df has a more friendly device name + //check if df has a more friendly device name if (pi_df.device.has_prefix("/dev/hd") || pi_df.device.has_prefix("/dev/sd") || pi_df.device.has_prefix("/dev/mapper/") || pi_df.device.has_prefix("/dev/dm")){ //get device name from df pi.device = pi_df.device; @@ -1034,7 +1034,7 @@ } } } - + if (get_mounts){ //get mount points var map_mt = get_mounted_filesystems_using_mtab(); @@ -1049,11 +1049,11 @@ return map; } - + public static Device refresh_partition_usage_info(Device pi){ - + /* Updates disk space info and returns the given Device object */ - + var map_df = get_disk_space_using_df(pi.device); if (map_df.has_key(pi.uuid)){ var pi_df = map_df.get(pi.uuid); @@ -1065,12 +1065,12 @@ return pi; } - + public static string get_device_uuid(string device){ if (device_list_master == null){ get_block_devices_using_udev(); } - + foreach(Device dev in device_list_master.values){ if (dev.device == device){ return dev.uuid; @@ -1083,14 +1083,14 @@ } } } - + return ""; } public static Gee.ArrayList get_mount_points(string device_or_uuid){ string device = ""; string uuid = ""; - + if (device_or_uuid.has_prefix("/dev")){ device = device_or_uuid; uuid = get_device_uuid(device_or_uuid); @@ -1099,13 +1099,13 @@ uuid = device_or_uuid; device = "/dev/disk/by-uuid/%s".printf(uuid); } - + var map = get_mounted_filesystems_using_mtab(); if (map.has_key(uuid)){ var pi = map.get(uuid); return pi.mount_points; } - + return (new Gee.ArrayList()); } @@ -1121,21 +1121,21 @@ public string dump = "0"; public string pass = "0"; public string line = ""; - + public static Gee.ArrayList read_fstab_file(string fstab_file_path){ Gee.ArrayList list = new Gee.ArrayList(); - + if (!file_exists(fstab_file_path)){ return list; } - + string text = read_file(fstab_file_path); string[] lines = text.split("\n"); foreach(string line in lines){ FsTabEntry entry = new FsTabEntry(); list.add(entry); - + entry.is_comment = line.strip().has_prefix("#"); entry.is_empty_line = (line.strip().length == 0); - + if (entry.is_comment){ entry.line = line; } @@ -1144,7 +1144,7 @@ } else{ entry.line = line; - + string[] parts = line.replace("\t"," ").split(" "); int part_num = -1; foreach(string part in parts){ @@ -1172,7 +1172,7 @@ } } } - + return list; } @@ -1191,11 +1191,11 @@ return text; } } - + public class MountEntry : GLib.Object{ public Device device = null; public string mount_point = ""; - + public MountEntry(Device device, string mount_point){ this.device = device; this.mount_point = mount_point; @@ -1203,10 +1203,10 @@ } public bool mount(string device_or_uuid, string mount_point, string mount_options = ""){ - + /* Mounts specified device at specified mount point. * */ - + string cmd = ""; string std_out; string std_err; @@ -1215,7 +1215,7 @@ string uuid = ""; //get uuid ----------------------------- - + if (device_or_uuid.has_prefix("/dev")){ device = device_or_uuid; uuid = Device.get_device_uuid(device_or_uuid); @@ -1226,7 +1226,7 @@ } //check if already mounted ------------- - + var map = Device.get_mounted_filesystems_using_mtab(); if (map.has_key(uuid)){ var pi = map.get(uuid); @@ -1237,7 +1237,7 @@ try{ //check and create mount point ------------------- - + File file = File.new_for_path(mount_point); if (!file.query_exists()){ file.make_directory_with_parents(); @@ -1247,7 +1247,7 @@ if (mount_options.length > 0){ cmd = "mount -o %s \"%s\" \"%s\"".printf(mount_options, device, mount_point); - } + } else{ cmd = "mount \"%s\" \"%s\"".printf(device, mount_point); } @@ -1267,9 +1267,9 @@ log_error (e.message); return false; } - + //check if mounted successfully ------------- - + map = Device.get_mounted_filesystems_using_mtab(); if (map.has_key(uuid)){ var pi = map.get(uuid); @@ -1279,18 +1279,18 @@ } return false; } - + public string automount(string device_or_uuid, string mount_options = "", string mount_prefix = "/mnt"){ - + /* Returns the mount point of specified device. * If unmounted, mounts the device to /mnt/ and returns the mount point. * */ - + string device = ""; string uuid = ""; - + //get uuid ----------------------------- - + if (device_or_uuid.has_prefix("/dev")){ device = device_or_uuid; uuid = Device.get_device_uuid(device_or_uuid); @@ -1299,9 +1299,9 @@ uuid = device_or_uuid; device = "/dev/disk/by-uuid/%s".printf(uuid); } - + //check if already mounted and return mount point ------------- - + var map = Device.get_filesystems(); if (map.has_key(uuid)){ var pi = map.get(uuid); @@ -1309,11 +1309,11 @@ return pi.mount_points[0]; } } - + //check and create mount point ------------------- - + string mount_point = "%s/%s".printf(mount_prefix, uuid); - + try{ File file = File.new_for_path(mount_point); if (!file.query_exists()){ @@ -1324,7 +1324,7 @@ log_error (e.message); return ""; } - + //mount the device and return mount_point -------------------- if (mount(uuid, mount_point, mount_options)){ @@ -1334,9 +1334,9 @@ return ""; } } - + public bool unmount(string mount_point){ - + /* Recursively unmounts all devices at given mount_point and subdirectories * */ @@ -1346,7 +1346,7 @@ int ret_val; //check if mounted ------------- - + bool mounted = false; var map = Device.get_mounted_filesystems_using_mtab(); foreach (Device pi in map.values){ @@ -1357,23 +1357,23 @@ } } if (!mounted) { return true; } - + //try to unmount ------------------ - + try{ - + string cmd_unmount = "cat /proc/mounts | awk '{print $2}' | grep '%s' | sort -r | xargs umount".printf(mount_point); - + log_debug(_("Unmounting from") + ": '%s'".printf(mount_point)); - + //sync before unmount cmd = "sync"; Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); //ignore success/failure - + //unmount ret_val = execute_command_script_sync(cmd_unmount, out std_out, out std_err); - + if (ret_val != 0){ log_error (_("Failed to unmount")); log_error (std_err); @@ -1383,9 +1383,9 @@ log_error (e.message); return false; } - + //check if unmounted -------------------------- - + mounted = false; map = Device.get_mounted_filesystems_using_mtab(); foreach (Device pi in map.values){ @@ -1395,20 +1395,20 @@ } } } - + return !mounted; } - + public string get_device_mount_point(string device_or_uuid){ /* Returns the mount point of specified device. * If unmounted, mounts the device to /mnt/ and returns the mount point. * */ - + string device = ""; string uuid = ""; - + //get uuid ----------------------------- - + if (device_or_uuid.has_prefix("/dev")){ device = device_or_uuid; uuid = Device.get_device_uuid(device_or_uuid); @@ -1417,9 +1417,9 @@ uuid = device_or_uuid; device = "/dev/disk/by-uuid/%s".printf(uuid); } - + //check if already mounted and return mount point ------------- - + var map = Device.get_mounted_filesystems_using_mtab(); if (map.has_key(uuid)){ var pi = map.get(uuid); @@ -1429,13 +1429,13 @@ } return ""; } - + public Gee.ArrayList get_block_devices(){ - + /* Returns a list of all storage devices including vendor and model number */ - + var device_list = new Gee.ArrayList(); - + string letters = "abcdefghijklmnopqrstuvwxyz"; string letter = ""; string path = ""; @@ -1444,29 +1444,29 @@ string vendor = ""; string removable = ""; File f; - + for(int i=0; i<26; i++){ letter = letters[i:i+1]; path = "/sys/block/sd%s".printf(letter); - f = File.new_for_path(path); + f = File.new_for_path(path); if (f.query_exists()){ - + device = ""; model = ""; removable = "0"; - - f = File.new_for_path(path + "/device/vendor"); + + f = File.new_for_path(path + "/device/vendor"); if (f.query_exists()){ vendor = read_file(path + "/device/vendor"); } - - f = File.new_for_path(path + "/device/model"); + + f = File.new_for_path(path + "/device/model"); if (f.query_exists()){ model = read_file(path + "/device/model"); } - - f = File.new_for_path(path + "/removable"); + + f = File.new_for_path(path + "/removable"); if (f.query_exists()){ removable = read_file(path + "/removable"); } @@ -1482,18 +1482,18 @@ } } } - + return device_list; } - + } namespace TeeJee.JSON{ - + using TeeJee.Logging; /* Convenience functions for reading and writing JSON files */ - + public string json_get_string(Json.Object jobj, string member, string def_value){ if (jobj.has_member(member)){ return jobj.get_string_member(member); @@ -1503,7 +1503,7 @@ return def_value; } } - + public bool json_get_bool(Json.Object jobj, string member, bool def_value){ if (jobj.has_member(member)){ return bool.parse(jobj.get_string_member(member)); @@ -1513,7 +1513,7 @@ return def_value; } } - + public int json_get_int(Json.Object jobj, string member, int def_value){ if (jobj.has_member(member)){ return int.parse(jobj.get_string_member(member)); @@ -1523,21 +1523,21 @@ return def_value; } } - + } namespace TeeJee.ProcessManagement{ using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.Misc; - + public string TEMP_DIR; /* Convenience functions for executing commands and managing processes */ - + public static void init_tmp(){ string std_out, std_err; - + TEMP_DIR = Environment.get_tmp_dir() + "/" + AppShortName; create_dir(TEMP_DIR); @@ -1550,10 +1550,10 @@ } public int execute_command_sync (string cmd){ - - /* Executes single command synchronously and returns exit code + + /* Executes single command synchronously and returns exit code * Pipes and multiple commands are not supported */ - + try { int exitCode; Process.spawn_command_line_sync(cmd, null, null, out exitCode); @@ -1564,12 +1564,12 @@ return -1; } } - + public string execute_command_sync_get_output (string cmd){ - + /* Executes single command synchronously and returns std_out * Pipes and multiple commands are not supported */ - + try { int exitCode; string std_out; @@ -1583,17 +1583,17 @@ } public bool execute_command_script_async (string cmd){ - - /* Creates a temporary bash script with given commands and executes it asynchronously + + /* Creates a temporary bash script with given commands and executes it asynchronously * Return value indicates if script was started successfully */ - + try { - + string scriptfile = create_temp_bash_script (cmd); - + string[] argv = new string[1]; argv[0] = scriptfile; - + Pid child_pid; Process.spawn_async_with_pipes( null, //working dir @@ -1609,12 +1609,12 @@ return false; } } - + public string? create_temp_bash_script (string script_text){ - - /* Creates a temporary bash script with given commands + + /* Creates a temporary bash script with given commands * Returns the script file path */ - + var sh = ""; sh += "#!/bin/bash\n"; sh += script_text; @@ -1629,29 +1629,29 @@ return null; } } - + public string get_temp_file_path(){ - + /* Generates temporary file path */ - + return TEMP_DIR + "/" + timestamp2() + (new Rand()).next_int().to_string(); } - + public int execute_command_script_sync (string script, out string std_out, out string std_err){ - + /* Executes commands synchronously * Returns exit code, output messages and error messages. * Commands are written to a temporary bash script and executed. */ - + string path = create_temp_bash_script(script); try { - + string[] argv = new string[1]; argv[0] = path; - + int exit_code; - + Process.spawn_sync ( TEMP_DIR, //working dir argv, //argv @@ -1662,7 +1662,7 @@ out std_err, out exit_code ); - + return exit_code; } catch (Error e){ @@ -1672,20 +1672,20 @@ } public int execute_script_sync_get_output (string script, out string std_out, out string std_err){ - + /* Executes commands synchronously * Returns exit code, output messages and error messages. * Commands are written to a temporary bash script and executed. */ - + string path = create_temp_bash_script(script); try { - + string[] argv = new string[1]; argv[0] = path; - + int exit_code; - + Process.spawn_sync ( TEMP_DIR, //working dir argv, //argv @@ -1696,7 +1696,7 @@ out std_err, out exit_code ); - + return exit_code; } catch (Error e){ @@ -1704,23 +1704,23 @@ return -1; } } - + public int execute_script_sync(string script, bool suppress_output){ - + /* Executes commands synchronously * Returns exit code, output messages and error messages. * Commands are written to a temporary bash script and executed. */ - + string path = create_temp_bash_script(script); try { - + string[] argv = new string[1]; argv[0] = path; - + int exit_code; string std_out, std_err; - + if (suppress_output){ //output will be suppressed Process.spawn_sync ( @@ -1755,19 +1755,19 @@ return -1; } } - + public bool execute_command_script_in_terminal_sync (string script){ - + /* Executes a command script in a terminal window */ //TODO: Remove this - + try { - + string[] argv = new string[3]; argv[0] = "x-terminal-emulator"; argv[1] = "-e"; argv[2] = script; - + Process.spawn_sync ( TEMP_DIR, //working dir argv, //argv @@ -1775,7 +1775,7 @@ SpawnFlags.SEARCH_PATH, null // child_setup ); - + return true; } catch (Error e){ @@ -1785,54 +1785,54 @@ } public int execute_bash_script_fullscreen_sync (string script_file){ - + /* Executes a bash script synchronously. * Script is executed in a fullscreen terminal window */ - + string path; - + path = get_cmd_path ("xfce4-terminal"); if ((path != null)&&(path != "")){ return execute_command_sync ("xfce4-terminal --fullscreen -e \"%s\"".printf(script_file)); } - + path = get_cmd_path ("gnome-terminal"); if ((path != null)&&(path != "")){ return execute_command_sync ("gnome-terminal --full-screen -e \"%s\"".printf(script_file)); } - + path = get_cmd_path ("xterm"); if ((path != null)&&(path != "")){ return execute_command_sync ("xterm -fullscreen -e \"%s\"".printf(script_file)); } - + //default terminal - unknown, normal window path = get_cmd_path ("x-terminal-emulator"); if ((path != null)&&(path != "")){ return execute_command_sync ("x-terminal-emulator -e \"%s\"".printf(script_file)); } - + return -1; } - + public int execute_bash_script_sync (string script_file){ - + /* Executes a bash script synchronously in the default terminal window */ - + string path = get_cmd_path ("x-terminal-emulator"); if ((path != null)&&(path != "")){ return execute_command_sync ("x-terminal-emulator -e \"%s\"".printf(script_file)); } - + return -1; } - + public string get_cmd_path (string cmd){ - + /* Returns the full path to a command */ - + try { - int exitCode; + int exitCode; string stdout, stderr; Process.spawn_command_line_sync("which " + cmd, out stdout, out stderr, out exitCode); return stdout; @@ -1844,9 +1844,9 @@ } public int get_pid_by_name (string name){ - + /* Get the process ID for a process with given name */ - + try{ string output = ""; Process.spawn_command_line_sync("pidof \"%s\"".printf(name), out output); @@ -1856,29 +1856,29 @@ return int.parse (arr[0]); } } - } - catch (Error e) { - log_error (e.message); } - + catch (Error e) { + log_error (e.message); + } + return -1; } - + public int[] get_pid_by_command (string proc_name, string command){ - + /* Get the process IDs for given process name and command string */ - + int[] proc_list = {}; - + //'ps' output strips double and single quotes so we will remove it too for matching with output - string cmd = command.replace("\"","").replace("'",""); + string cmd = command.replace("\"","").replace("'",""); try{ Regex rex = new Regex("""^[ \t]*([0-9]*)[ \t]*"""); MatchInfo match; - - string txt = execute_command_sync_get_output ("ps ew -C " + proc_name); //ew = all users - + + string txt = execute_command_sync_get_output ("ps ew -C " + proc_name); //ew = all users + log_msg(txt); foreach(string line in txt.split("\n")){ if (line.index_of(cmd) != -1){ @@ -1887,74 +1887,74 @@ } } } - } - catch (Error e) { - log_error (e.message); } - + catch (Error e) { + log_error (e.message); + } + return proc_list; } - + public bool process_is_running(long pid){ - + /* Checks if given process is running */ - + string cmd = ""; string std_out; string std_err; int ret_val; - + try{ cmd = "ps --pid %ld".printf(pid); Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); } - catch (Error e) { - log_error (e.message); + catch (Error e) { + log_error (e.message); return false; } - + return (ret_val == 0); } public int[] get_process_children (Pid parentPid){ - + /* Returns the list of child processes spawned by given process */ - + string output; - + try { Process.spawn_command_line_sync("ps --ppid %d".printf(parentPid), out output); } catch(Error e){ log_error (e.message); } - + int pid; int[] procList = {}; string[] arr; - + foreach (string line in output.split ("\n")){ arr = line.strip().split (" "); if (arr.length < 1) { continue; } - + pid = 0; pid = int.parse (arr[0]); - + if (pid != 0){ procList += pid; } } return procList; } - - + + public void process_kill(Pid process_pid, bool killChildren = true){ - + /* Kills specified process and its children (optional) */ - + int[] child_pids = get_process_children (process_pid); Posix.kill (process_pid, 15); - + if (killChildren){ Pid childPid; foreach (long pid in child_pids){ @@ -1963,28 +1963,28 @@ } } } - + public int process_pause (Pid procID){ - + /* Pause/Freeze a process */ - + return execute_command_sync ("kill -STOP %d".printf(procID)); } - + public int process_resume (Pid procID){ - + /* Resume/Un-freeze a process*/ - + return execute_command_sync ("kill -CONT %d".printf(procID)); } public void command_kill(string cmd_name, string cmd){ - + /* Kills a specific command */ string txt = execute_command_sync_get_output ("ps w -C %s".printf(cmd_name)); //use 'ps ew -C conky' for all users - + string pid = ""; foreach(string line in txt.split("\n")){ if (line.index_of(cmd) != -1){ @@ -1994,65 +1994,65 @@ } } } - - + + public void process_set_priority (Pid procID, int prio){ - + /* Set process priority */ - + if (Posix.getpriority (Posix.PRIO_PROCESS, procID) != prio) Posix.setpriority (Posix.PRIO_PROCESS, procID, prio); } - + public int process_get_priority (Pid procID){ - + /* Get process priority */ - + return Posix.getpriority (Posix.PRIO_PROCESS, procID); } - + public void process_set_priority_normal (Pid procID){ - + /* Set normal priority for process */ - + process_set_priority (procID, 0); } - + public void process_set_priority_low (Pid procID){ - + /* Set low priority for process */ - + process_set_priority (procID, 5); } - + public bool user_is_admin (){ - + /* Check if current application is running with admin priviledges */ - + try{ // create a process string[] argv = { "sleep", "10" }; Pid procId; - Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); - + Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); + // try changing the priority Posix.setpriority (Posix.PRIO_PROCESS, procId, -5); - + // check if priority was changed successfully if (Posix.getpriority (Posix.PRIO_PROCESS, procId) == -5) return true; else return false; - } - catch (Error e) { - //log_error (e.message); + } + catch (Error e) { + //log_error (e.message); return false; } } public string get_user_login(){ - /* + /* Returns Login ID of current user. If running as 'sudo' it will return Login ID of the actual user. */ @@ -2062,7 +2062,7 @@ string std_err; int ret_val; ret_val = execute_command_script_sync(cmd, out std_out, out std_err); - + string user_name; if ((std_out == null) || (std_out.length == 0)){ user_name = "root"; @@ -2070,45 +2070,45 @@ else{ user_name = std_out.strip(); } - + return user_name; } public int get_user_id(string user_login){ - /* + /* Returns UID of specified user. */ - + int uid = -1; string cmd = "id %s -u".printf(user_login); string txt = execute_command_sync_get_output(cmd); if ((txt != null) && (txt.length > 0)){ uid = int.parse(txt); } - + return uid; } - - + + public string get_app_path (){ - + /* Get path of current process */ - + try{ - return GLib.FileUtils.read_link ("/proc/self/exe"); + return GLib.FileUtils.read_link ("/proc/self/exe"); } catch (Error e){ log_error (e.message); return ""; } } - + public string get_app_dir (){ - + /* Get parent directory of current process */ - + try{ - return (File.new_for_path (GLib.FileUtils.read_link ("/proc/self/exe"))).get_parent ().get_path (); + return (File.new_for_path (GLib.FileUtils.read_link ("/proc/self/exe"))).get_parent ().get_path (); } catch (Error e){ log_error (e.message); @@ -2119,21 +2119,21 @@ } namespace TeeJee.GtkHelper{ - + using Gtk; - + public void gtk_do_events (){ - + /* Do pending events */ - + while(Gtk.events_pending ()) Gtk.main_iteration (); } public void gtk_set_busy (bool busy, Gtk.Window win) { - + /* Show or hide busy cursor on window */ - + Gdk.Cursor? cursor = null; if (busy){ @@ -2142,18 +2142,18 @@ else{ cursor = new Gdk.Cursor(Gdk.CursorType.ARROW); } - + var window = win.get_window (); - + if (window != null) { window.set_cursor (cursor); } - + gtk_do_events (); } - + public void gtk_messagebox(string title, string message, Gtk.Window? parent_win, bool is_error = false){ - + /* Shows a simple message box */ Gtk.MessageType type = Gtk.MessageType.INFO; @@ -2163,7 +2163,7 @@ else{ type = Gtk.MessageType.INFO; } - + var dlg = new Gtk.MessageDialog.with_markup(null, Gtk.DialogFlags.MODAL, type, Gtk.ButtonsType.OK, message); dlg.title = title; dlg.set_default_size (300, -1); @@ -2176,23 +2176,23 @@ } public string gtk_inputbox(string title, string message, Gtk.Window? parent_win, bool mask_password = false){ - + /* Shows a simple input prompt */ - + //vbox_main Gtk.Box vbox_main = new Box (Orientation.VERTICAL, 0); vbox_main.margin = 6; - + //lbl_input Gtk.Label lbl_input = new Gtk.Label(title); lbl_input.xalign = (float) 0.0; lbl_input.label = message; - + //txt_input Gtk.Entry txt_input = new Gtk.Entry(); txt_input.margin_top = 3; txt_input.set_visibility(false); - + //create dialog var dlg = new Gtk.Dialog.with_buttons(title, parent_win, DialogFlags.MODAL); dlg.title = title; @@ -2201,17 +2201,17 @@ dlg.set_transient_for(parent_win); dlg.set_modal(true); } - + //add widgets Gtk.Box content = (Box) dlg.get_content_area (); vbox_main.pack_start (lbl_input, false, true, 0); vbox_main.pack_start (txt_input, false, true, 0); content.add(vbox_main); - + //add buttons dlg.add_button(_("OK"),Gtk.ResponseType.OK); dlg.add_button(_("Cancel"),Gtk.ResponseType.CANCEL); - + //keyboard shortcuts txt_input.key_press_event.connect ((w, event) => { if (event.keyval == 65293) { @@ -2220,12 +2220,12 @@ } return false; }); - + dlg.show_all(); int response = dlg.run(); string input_text = txt_input.text; dlg.destroy(); - + if (response == Gtk.ResponseType.CANCEL){ return ""; } @@ -2233,15 +2233,15 @@ return input_text; } } - + public bool gtk_combobox_set_value (ComboBox combo, int index, string val){ - + /* Conveniance function to set combobox value */ - + TreeIter iter; string comboVal; TreeModel model = (TreeModel) combo.model; - + bool iterExists = model.get_iter_first (out iter); while (iterExists){ model.get(iter, 1, out comboVal); @@ -2250,45 +2250,45 @@ return true; } iterExists = model.iter_next (ref iter); - } - + } + return false; } - + public string gtk_combobox_get_value (ComboBox combo, int index, string default_value){ - + /* Conveniance function to get combobox value */ - + if (combo.model == null) { return default_value; } if (combo.active < 0) { return default_value; } - + TreeIter iter; string val = ""; combo.get_active_iter (out iter); TreeModel model = (TreeModel) combo.model; model.get(iter, index, out val); - + return val; } public class CellRendererProgress2 : Gtk.CellRendererProgress{ public override void render (Cairo.Context cr, Gtk.Widget widget, Gdk.Rectangle background_area, Gdk.Rectangle cell_area, Gtk.CellRendererState flags) { - if (text == "--") + if (text == "--") return; - + int diff = (int) ((cell_area.height - height)/2); - + // Apply the new height into the bar, and center vertically: Gdk.Rectangle new_area = Gdk.Rectangle() ; new_area.x = cell_area.x; new_area.y = cell_area.y + diff; new_area.width = width - 5; new_area.height = height; - + base.render(cr, widget, background_area, new_area, flags); } - } - + } + public Gdk.Pixbuf? get_app_icon(int icon_size, string format = ".png"){ var img_icon = get_shared_icon(AppShortName, AppShortName + format,icon_size,"pixmaps"); if (img_icon != null){ @@ -2298,94 +2298,94 @@ return null; } } - + public Gtk.Image? get_shared_icon(string icon_name, string fallback_icon_file_name, int icon_size, string icon_directory = AppShortName + "/images"){ Gdk.Pixbuf pix_icon = null; Gtk.Image img_icon = null; - + try { Gtk.IconTheme icon_theme = Gtk.IconTheme.get_default(); pix_icon = icon_theme.load_icon (icon_name, icon_size, 0); } catch (Error e) { //log_error (e.message); } - + string fallback_icon_file_path = "/usr/share/%s/%s".printf(icon_directory, fallback_icon_file_name); - - if (pix_icon == null){ + + if (pix_icon == null){ try { pix_icon = new Gdk.Pixbuf.from_file_at_size (fallback_icon_file_path, icon_size, icon_size); } catch (Error e) { log_error (e.message); } } - - if (pix_icon == null){ + + if (pix_icon == null){ log_error (_("Missing Icon") + ": '%s', '%s'".printf(icon_name, fallback_icon_file_path)); } else{ img_icon = new Gtk.Image.from_pixbuf(pix_icon); } - return img_icon; + return img_icon; } } namespace TeeJee.Multimedia{ - + using TeeJee.Logging; - + /* Functions for working with audio/video files */ - + public long get_file_duration(string filePath){ - + /* Returns the duration of an audio/video file using MediaInfo */ - + string output = "0"; - + try { Process.spawn_command_line_sync("mediainfo \"--Inform=General;%Duration%\" \"" + filePath + "\"", out output); } catch(Error e){ log_error (e.message); } - + return long.parse(output); } - + public string get_file_crop_params (string filePath){ - + /* Returns cropping parameters for a video file using avconv */ - + string output = ""; string error = ""; - + try { Process.spawn_command_line_sync("avconv -i \"%s\" -vf cropdetect=30 -ss 5 -t 5 -f matroska -an -y /dev/null".printf(filePath), out output, out error); } catch(Error e){ log_error (e.message); } - + int w=0,h=0,x=10000,y=10000; int num=0; string key,val; string[] arr; - + foreach (string line in error.split ("\n")){ if (line == null) { continue; } if (line.index_of ("crop=") == -1) { continue; } foreach (string part in line.split (" ")){ if (part == null || part.length == 0) { continue; } - + arr = part.split (":"); if (arr.length != 2) { continue; } - + key = arr[0].strip (); val = arr[1].strip (); - + switch (key){ case "x": num = int.parse (arr[1]); @@ -2406,47 +2406,47 @@ } } } - + if (x == 10000 || y == 10000) return "%i:%i:%i:%i".printf(0,0,0,0); - else + else return "%i:%i:%i:%i".printf(w,h,x,y); } - + public string get_mediainfo (string filePath){ - + /* Returns the multimedia properties of an audio/video file using MediaInfo */ - + string output = ""; - + try { Process.spawn_command_line_sync("mediainfo \"%s\"".printf(filePath), out output); } catch(Error e){ log_error (e.message); } - + return output; } - - + + } namespace TeeJee.System{ - + using TeeJee.ProcessManagement; using TeeJee.Logging; public double get_system_uptime_seconds(){ - + /* Returns the system up-time in seconds */ - + string cmd = ""; string std_out; string std_err; int ret_val; - + try{ cmd = "cat /proc/uptime"; Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); @@ -2459,18 +2459,18 @@ return 0; } } - + public string get_desktop_name(){ - + /* Return the names of the current Desktop environment */ - + int pid = -1; - + pid = get_pid_by_name("cinnamon"); if (pid > 0){ return "Cinnamon"; } - + pid = get_pid_by_name("xfdesktop"); if (pid > 0){ return "Xfce"; @@ -2485,12 +2485,12 @@ if (pid > 0){ return "Gnome"; } - + pid = get_pid_by_name("wingpanel"); if (pid > 0){ return "Elementary"; } - + pid = get_pid_by_name("unity-panel-service"); if (pid > 0){ return "Unity"; @@ -2500,7 +2500,7 @@ if (pid > 0){ return "KDE"; } - + return "Unknown"; } @@ -2516,42 +2516,42 @@ catch (Error e){ log_error (e.message); } - + return (exit_code == 0); } - + public bool shutdown (){ - + /* Shutdown the system immediately */ - + try{ string[] argv = { "shutdown", "-h", "now" }; Pid procId; - Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); + Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); return true; - } - catch (Error e) { - log_error (e.message); + } + catch (Error e) { + log_error (e.message); return false; } } - + public bool reboot(){ - + /* Reboot the system immediately */ try{ string[] argv = { "shutdown", "-r", "now" }; Pid procId; - Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); + Process.spawn_async(null, argv, null, SpawnFlags.SEARCH_PATH, null, out procId); return true; - } - catch (Error e) { - log_error (e.message); + } + catch (Error e) { + log_error (e.message); return false; } } - + public bool xdg_open (string file){ string path; path = get_cmd_path ("xdg-open"); @@ -2560,20 +2560,20 @@ } return false; } - + public bool exo_open_folder (string dir_path, bool xdg_open_try_first = true){ - + /* Tries to open the given directory in a file manager */ /* xdg-open is a desktop-independent tool for configuring the default applications of a user. - Inside a desktop environment (e.g. GNOME, KDE, Xfce), xdg-open simply passes the arguments + Inside a desktop environment (e.g. GNOME, KDE, Xfce), xdg-open simply passes the arguments to that desktop environment's file-opener application (gvfs-open, kde-open, exo-open, respectively). - We will first try using xdg-open and then check for specific file managers if it fails. + We will first try using xdg-open and then check for specific file managers if it fails. */ - + string path; - + if (xdg_open_try_first){ //try using xdg-open path = get_cmd_path ("xdg-open"); @@ -2581,17 +2581,17 @@ return execute_command_script_async ("xdg-open \"" + dir_path + "\""); } } - + path = get_cmd_path ("nemo"); if ((path != null)&&(path != "")){ return execute_command_script_async ("nemo \"" + dir_path + "\""); } - + path = get_cmd_path ("nautilus"); if ((path != null)&&(path != "")){ return execute_command_script_async ("nautilus \"" + dir_path + "\""); } - + path = get_cmd_path ("thunar"); if ((path != null)&&(path != "")){ return execute_command_script_async ("thunar \"" + dir_path + "\""); @@ -2601,7 +2601,7 @@ if ((path != null)&&(path != "")){ return execute_command_script_async ("pantheon-files \"" + dir_path + "\""); } - + path = get_cmd_path ("marlin"); if ((path != null)&&(path != "")){ return execute_command_script_async ("marlin \"" + dir_path + "\""); @@ -2614,16 +2614,16 @@ return execute_command_script_async ("xdg-open \"" + dir_path + "\""); } } - + return false; } public bool exo_open_textfile (string txt){ - + /* Tries to open the given text file in a text editor */ - + string path; - + path = get_cmd_path ("exo-open"); if ((path != null)&&(path != "")){ return execute_command_script_async ("exo-open \"" + txt + "\""); @@ -2638,11 +2638,11 @@ } public bool exo_open_url (string url){ - + /* Tries to open the given text file in a text editor */ - + string path; - + path = get_cmd_path ("exo-open"); if ((path != null)&&(path != "")){ return execute_command_script_async ("exo-open \"" + url + "\""); @@ -2657,19 +2657,19 @@ if ((path != null)&&(path != "")){ return execute_command_script_async ("chromium-browser \"" + url + "\""); } - + return false; } - + private DateTime dt_last_notification = null; private const int NOTIFICATION_INTERVAL = 3; - + public int notify_send (string title, string message, int durationMillis, string urgency, string dialog_type = "info"){ - + /* Displays notification bubble on the desktop */ int retVal = 0; - + switch (dialog_type){ case "error": case "info": @@ -2680,14 +2680,14 @@ dialog_type = "info"; break; } - + long seconds = 9999; if (dt_last_notification != null){ DateTime dt_end = new DateTime.now_local(); TimeSpan elapsed = dt_end.difference(dt_last_notification); seconds = (long)(elapsed * 1.0 / TimeSpan.SECOND); } - + if (seconds > NOTIFICATION_INTERVAL){ string s = "notify-send -t %d -u %s -i %s \"%s\" \"%s\"".printf(durationMillis, urgency, "gtk-dialog-" + dialog_type, title, message); retVal = execute_command_sync (s); @@ -2696,13 +2696,13 @@ return retVal; } - + public bool set_directory_ownership(string dir_name, string login_name){ try { string cmd = "chown %s -R %s".printf(login_name, dir_name); int exit_code; Process.spawn_command_line_sync(cmd, null, null, out exit_code); - + if (exit_code == 0){ //log_msg(_("Ownership changed to '%s' for files in directory '%s'").printf(login_name, dir_name)); return true; @@ -2717,16 +2717,16 @@ return false; } } - + public bool crontab_remove(string line){ string cmd = ""; string std_out; string std_err; int ret_val; - + cmd = "crontab -l | sed '/%s/d' | crontab -".printf(line); ret_val = execute_command_script_sync(cmd, out std_out, out std_err); - + if (ret_val != 0){ log_error(std_err); return false; @@ -2735,28 +2735,28 @@ return true; } } - + public bool crontab_add(string entry){ string cmd = ""; string std_out; string std_err; int ret_val; - + try{ string crontab = crontab_read_all(); crontab += crontab.has_suffix("\n") ? "" : "\n"; crontab += entry + "\n"; - + //remove empty lines crontab = crontab.replace("\n\n","\n"); //remove empty lines in middle crontab = crontab.has_prefix("\n") ? crontab[1:crontab.length] : crontab; //remove empty lines in beginning - + string temp_file = get_temp_file_path(); write_file(temp_file, crontab); cmd = "crontab \"%s\"".printf(temp_file); Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); - + if (ret_val != 0){ log_error(std_err); return false; @@ -2776,7 +2776,7 @@ string std_out; string std_err; int ret_val; - + try { cmd = "crontab -l"; Process.spawn_command_line_sync(cmd, out std_out, out std_err, out ret_val); @@ -2793,13 +2793,13 @@ return ""; } } - + public string crontab_read_entry(string search_string, bool use_regex_matching = false){ string cmd = ""; string std_out; string std_err; int ret_val; - + try{ Regex rex = null; MatchInfo match; @@ -2837,30 +2837,30 @@ } namespace TeeJee.Misc { - + /* Various utility functions */ - + using Gtk; using TeeJee.Logging; using TeeJee.FileSystem; using TeeJee.ProcessManagement; - + public class DistInfo : GLib.Object{ - + /* Class for storing information about linux distribution */ - + public string dist_id = ""; public string description = ""; public string release = ""; public string codename = ""; - + public DistInfo(){ dist_id = ""; description = ""; release = ""; codename = ""; } - + public string full_name(){ if (dist_id == ""){ return ""; @@ -2873,14 +2873,14 @@ return val; } } - + public static DistInfo get_dist_info(string root_path){ - - /* Returns information about the Linux distribution + + /* Returns information about the Linux distribution * installed at the given root path */ - + DistInfo info = new DistInfo(); - + string dist_file = root_path + "/etc/lsb-release"; var f = File.new_for_path(dist_file); if (f.query_exists()){ @@ -2891,22 +2891,22 @@ DISTRIB_CODENAME=raring DISTRIB_DESCRIPTION="Ubuntu 13.04" */ - + foreach(string line in read_file(dist_file).split("\n")){ - + if (line.split("=").length != 2){ continue; } - + string key = line.split("=")[0].strip(); string val = line.split("=")[1].strip(); - + if (val.has_prefix("\"")){ val = val[1:val.length]; } - + if (val.has_suffix("\"")){ val = val[0:val.length-1]; } - + switch (key){ case "DISTRIB_ID": info.dist_id = val; @@ -2924,11 +2924,11 @@ } } else{ - + dist_file = root_path + "/etc/os-release"; f = File.new_for_path(dist_file); if (f.query_exists()){ - + /* NAME="Ubuntu" VERSION="13.04, Raring Ringtail" @@ -2940,14 +2940,14 @@ SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/" */ - + foreach(string line in read_file(dist_file).split("\n")){ - + if (line.split("=").length != 2){ continue; } - + string key = line.split("=")[0].strip(); string val = line.split("=")[1].strip(); - + switch (key){ case "ID": info.dist_id = val; @@ -2968,33 +2968,33 @@ return info; } - + } public static Gdk.RGBA hex_to_rgba (string hex_color){ - + /* Converts the color in hex to RGBA */ - + string hex = hex_color.strip().down(); if (hex.has_prefix("#") == false){ hex = "#" + hex; } - + Gdk.RGBA color = Gdk.RGBA(); if(color.parse(hex) == false){ color.parse("#000000"); } color.alpha = 255; - + return color; } - + public static string rgba_to_hex (Gdk.RGBA color, bool alpha = false, bool prefix_hash = true){ - + /* Converts the color in RGBA to hex */ - + string hex = ""; - + if (alpha){ hex = "%02x%02x%02x%02x".printf((uint)(Math.round(color.red*255)), (uint)(Math.round(color.green*255)), @@ -3002,54 +3002,54 @@ (uint)(Math.round(color.alpha*255))) .up(); } - else { + else { hex = "%02x%02x%02x".printf((uint)(Math.round(color.red*255)), (uint)(Math.round(color.green*255)), (uint)(Math.round(color.blue*255))) .up(); - } - + } + if (prefix_hash){ hex = "#" + hex; - } - - return hex; + } + + return hex; } public string timestamp2 (){ - + /* Returns a numeric timestamp string */ - + return "%ld".printf((long) time_t ()); } - - public string timestamp (){ - + + public string timestamp (){ + /* Returns a formatted timestamp string */ - + Time t = Time.local (time_t ()); return t.format ("%H:%M:%S"); } - public string timestamp3 (){ - + public string timestamp3 (){ + /* Returns a formatted timestamp string */ - + Time t = Time.local (time_t ()); return t.format ("%Y-%d-%m_%H-%M-%S"); } - + public string format_file_size (int64 size){ - + /* Format file size in MB */ - + return "%0.1f MB".printf (size / (1024.0 * 1024)); } public string format_file_size_auto (int64 size, bool binary_base = false){ - + /* Format file size in human readable format */ - + if (binary_base){ if (size > 1 * GiB){ return "%0.1f GiB".printf (size / GiB); @@ -3079,11 +3079,11 @@ } } } - + public string format_duration (long millis){ - + /* Converts time in milliseconds to format '00:00:00.0' */ - + double time = millis / 1000.0; // time in seconds double hr = Math.floor(time / (60.0 * 60)); @@ -3091,14 +3091,14 @@ double min = Math.floor(time / 60.0); time = time - (min * 60); double sec = Math.floor(time); - + return "%02.0lf:%02.0lf:%02.0lf".printf (hr, min, sec); } - + public double parse_time (string time){ - + /* Converts time in format '00:00:00.0' to milliseconds */ - + string[] arr = time.split (":"); double millis = 0; if (arr.length >= 3){ @@ -3108,7 +3108,7 @@ } return millis; } - + public string escape_html(string html){ return html .replace("&","&") @@ -3118,7 +3118,7 @@ .replace(">",">") ; } - + public string unescape_html(string html){ return html .replace("&","&") @@ -3129,4 +3129,3 @@ ; } } - diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/timeshift.geany timeshift-1.7.4~178~ubuntu14.04.1/timeshift.geany --- timeshift-1.7.3~177~ubuntu14.04.1/timeshift.geany 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/timeshift.geany 2015-09-08 01:01:52.000000000 +0000 @@ -17,8 +17,21 @@ long_line_column=80 [files] -current_page=0 -FILE_NAME_0=0;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMain.vala;0;4 +current_page=13 +FILE_NAME_0=1223;Vala;0;EUTF-8;1;1;0;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMain.vala;0;4 +FILE_NAME_1=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FAboutWindow.vala;0;4 +FILE_NAME_2=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FDonationWindow.vala;0;4 +FILE_NAME_3=5557;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FExcludeMessageWindow.vala;0;4 +FILE_NAME_4=23055;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FMainWindow.vala;0;4 +FILE_NAME_5=171;Make;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2Fmakefile;0;4 +FILE_NAME_6=39594;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FRestoreWindow.vala;0;4 +FILE_NAME_7=21194;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FSettingsWindow.vala;0;4 +FILE_NAME_8=0;Conf;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2Ftimeshift.desktop;0;4 +FILE_NAME_9=0;Sh;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2Ftimeshift-launcher;0;4 +FILE_NAME_10=0;Sh;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2Ftimeshift-uninstall;0;4 +FILE_NAME_11=0;Vala;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fsrc%2FUtility.vala;0;4 +FILE_NAME_12=163;Conf;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fdebian%2Fcontrol;0;4 +FILE_NAME_13=223;None;0;EUTF-8;1;1;1;%2Fhome%2Fteejee%2Fprojects%2Flinux%2Ftimeshift%2Fdebian%2Fchangelog;0;4 [VTE] last_dir=/home/teejee diff -Nru timeshift-1.7.3~177~ubuntu14.04.1/timeshift.pot timeshift-1.7.4~178~ubuntu14.04.1/timeshift.pot --- timeshift-1.7.3~177~ubuntu14.04.1/timeshift.pot 2015-08-14 22:34:06.000000000 +0000 +++ timeshift-1.7.4~178~ubuntu14.04.1/timeshift.pot 2015-09-08 01:01:52.000000000 +0000 @@ -8,7 +8,7 @@ msgstr "" "Project-Id-Version: timeshift 1.6\n" "Report-Msgid-Bugs-To: teejee2008@gmail.com\n" -"POT-Creation-Date: 2015-08-14 18:24-0400\n" +"POT-Creation-Date: 2015-09-07 20:49-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -409,7 +409,7 @@ msgid "Devices with Linux file systems" msgstr "" -#: DonationWindow.vala:53 +#: DonationWindow.vala:54 msgid "" "Did you find this software useful?\n" "\n" @@ -477,7 +477,7 @@ msgid "Donate" msgstr "" -#: DonationWindow.vala:66 +#: DonationWindow.vala:67 msgid "Donate via PayPal" msgstr "" @@ -965,7 +965,7 @@ msgid "Num" msgstr "" -#: Utility.vala:2212 +#: DonationWindow.vala:88 Utility.vala:2212 msgid "OK" msgstr "" @@ -1252,7 +1252,7 @@ msgid "Selected device does not have enough space." msgstr "" -#: DonationWindow.vala:73 +#: DonationWindow.vala:74 msgid "Send Email" msgstr "" @@ -1549,7 +1549,7 @@ msgid "View rsync log for selected snapshot" msgstr "" -#: DonationWindow.vala:80 +#: DonationWindow.vala:81 msgid "Visit Website" msgstr ""