Grafx2 now disables safety backups (and warns the user on startup) if another instance is running or if its configuration directory is read-only. Implemented separately on Linux and Windows, tested only on Windows

git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@1343 416bcca6-2ee7-4201-b75f-2eb2f807beb1
This commit is contained in:
Yves Rizoud 2010-02-14 00:28:42 +00:00
parent 7076e8e06d
commit 4c3a0b6f68
4 changed files with 165 additions and 54 deletions

69
io.c
View File

@ -284,3 +284,72 @@ void Get_full_filename(char * output_name, char * file_name, char * directory_na
} }
strcat(output_name,file_name); strcat(output_name,file_name);
} }
/// Lock file used to prevent several instances of grafx2 from harming each others' backups
#ifdef __WIN32__
HANDLE Lock_file_handle = INVALID_HANDLE_VALUE;
#else
int Lock_file_handle = -1;
#endif
byte Create_lock_file(const char *file_directory)
{
char lock_filename[MAX_PATH_CHARACTERS];
strcpy(lock_filename,file_directory);
strcat(lock_filename,"gfx2.lck");
#ifdef __WIN32__
// Windowzy method for creating a lock file
Lock_file_handle = CreateFile(
lock_filename,
GENERIC_WRITE,
0, // No sharing
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (Lock_file_handle == INVALID_HANDLE_VALUE)
{
return -1;
}
#else
// Unixy method for lock file
Lock_file_handle = open(lock_filename,O_WRONLY|O_CREAT);
if (Lock_file_handle == -1)
{
// Usually write-protected media
return -1;
}
if (lockf(Lock_file_handle, F_TLOCK, 0)==-1)
{
close(Lock_file_handle);
// Usually write-protected media
return -1;
}
#endif
return 0;
}
void Release_lock_file(const char *file_directory)
{
char lock_filename[MAX_PATH_CHARACTERS];
#ifdef __WIN32__
if (Lock_file_handle != INVALID_HANDLE_VALUE)
{
CloseHandle(Lock_file_handle);
}
#else
if (Lock_file_handle != -1)
{
close(Lock_file_handle);
Lock_file_handle = -1;
}
#endif
// Actual deletion
strcpy(lock_filename,file_directory);
strcat(lock_filename,"gfx2.lck");
remove(lock_filename);
}

9
io.h
View File

@ -94,3 +94,12 @@ void For_each_file(const char * directory_name, void Callback(const char *));
/// Creates a fully qualified name from a directory and filename. /// Creates a fully qualified name from a directory and filename.
/// The point is simply to insert a PATH_SEPARATOR when needed. /// The point is simply to insert a PATH_SEPARATOR when needed.
void Get_full_filename(char * output_name, char * file_name, char * directory_name); void Get_full_filename(char * output_name, char * file_name, char * directory_name);
///
/// Creates a lock file, to check if an other instance of Grafx2 is running.
/// @return 0 on success (first instance), -1 on failure (others are running)
byte Create_lock_file(const char *file_directory);
///
/// Release a lock file created by ::Create_Lock_file
void Release_lock_file(const char *file_directory);

View File

@ -1162,6 +1162,7 @@ T_String_list *Backups_main = NULL;
/// A list of files, used for scanning a directory /// A list of files, used for scanning a directory
T_String_list *Backups_spare = NULL; T_String_list *Backups_spare = NULL;
// Settings for safety backup (frequency, numbers, etc) // Settings for safety backup (frequency, numbers, etc)
const int Rotation_safety_backup = 8; const int Rotation_safety_backup = 8;
@ -1187,9 +1188,9 @@ void Add_backup_file(const char *name)
Extract_filename(file_name, name); Extract_filename(file_name, name);
// Check first character // Check first character
if (file_name[0]=='a') if (file_name[0]==Main_safety_backup_prefix)
list = &Backups_main; list = &Backups_main;
else if (file_name[0]=='b') else if (file_name[0]==Spare_safety_backup_prefix)
list = &Backups_spare; list = &Backups_spare;
else { else {
// Not a good file // Not a good file
@ -1291,13 +1292,22 @@ byte Process_backups(T_String_list **list)
} }
/// Global indicator that tells if the safety backup system is active
byte Safety_backup_active = 0;
/// ///
/// Checks if there are any pending safety backups, and then opens them. /// Checks if there are any pending safety backups, and then opens them.
/// /// @return 0 if no problem, -1 if the backup system cannot be activated, >=1 if some backups are restored
int Check_recovery(void) int Check_recovery(void)
{ {
int restored_spare; int restored_spare;
int restored_main; int restored_main;
// First check if can write backups
if (Create_lock_file(Config_directory))
return -1;
Safety_backup_active=1;
Backups_main = NULL; Backups_main = NULL;
Backups_spare = NULL; Backups_spare = NULL;
@ -1327,13 +1337,7 @@ int Check_recovery(void)
Compute_paintbrush_coordinates(); Compute_paintbrush_coordinates();
Redraw_layered_image(); Redraw_layered_image();
} }
/* return restored_main + restored_spare;
if (restored_main||restored_spare)
{
Display_all_screen();
return 1;
}*/
return restored_main || restored_spare;
} }
void Rotate_safety_backups(void) void Rotate_safety_backups(void)
@ -1343,6 +1347,9 @@ void Rotate_safety_backups(void)
char file_name[12+1]; char file_name[12+1];
char deleted_file[MAX_PATH_CHARACTERS]; char deleted_file[MAX_PATH_CHARACTERS];
if (!Safety_backup_active)
return;
now = SDL_GetTicks(); now = SDL_GetTicks();
// It's time to save if either: // It's time to save if either:
// - Many edits have taken place // - Many edits have taken place
@ -1384,6 +1391,9 @@ void Delete_safety_backups(void)
{ {
T_String_list *element; T_String_list *element;
if (!Safety_backup_active)
return;
Backups_main = NULL; Backups_main = NULL;
Backups_spare = NULL; Backups_spare = NULL;
@ -1401,4 +1411,7 @@ void Delete_safety_backups(void)
printf("Failed to delete %s\n",element->String); printf("Failed to delete %s\n",element->String);
} }
// Release lock file
Release_lock_file(Config_directory);
} }

108
main.c
View File

@ -760,54 +760,74 @@ int Init_program(int argc,char * argv[])
*Brush=MC_White; *Brush=MC_White;
// Test de recuperation de fichiers sauvés // Test de recuperation de fichiers sauvés
if (Check_recovery()) switch (Check_recovery())
{
// Some files were loaded from last crash-exit.
// Do not load files from command-line, nor show splash screen.
Compute_optimal_menu_colors(Main_palette);
Display_all_screen();
Display_menu();
Display_cursor();
}
else
{ {
T_IO_Context context; T_IO_Context context;
switch (file_in_command_line)
{
case 0:
if (Config.Opening_message)
Button_Message_initial();
break;
case 2: default:
// Load this file // Some files were loaded from last crash-exit.
Init_context_layered_image(&context, spare_filename, spare_directory); // Do not load files from command-line, nor show splash screen.
Load_image(&context); Compute_optimal_menu_colors(Main_palette);
Destroy_context(&context); Display_all_screen();
End_of_modification(); Display_menu();
Redraw_layered_image(); Display_cursor();
Verbose_message("Images recovered",
Button_Page(); "Grafx2 has recovered images from\n"
// no break ! proceed with the other file now "last session, before a crash or\n"
case 1: "shutdown. Browse the history using\n"
Init_context_layered_image(&context, main_filename, main_directory); "the Undo/Redo button, and when\n"
Load_image(&context); "you find a state that you want to\n"
Destroy_context(&context); "save, use the 'Save as' button to\n"
End_of_modification(); "save the image.\n"
Redraw_layered_image(); "Some backups can be present in\n"
"the spare page too.\n");
Hide_cursor(); break;
Compute_optimal_menu_colors(Main_palette);
Display_all_screen();
Display_menu();
Display_cursor();
Resolution_in_command_line = 0;
break;
default: case -1: // Unable to write lock file
break; Verbose_message("Warning",
} "Safety backups (every minute) are\n"
"disabled because Grafx2 is running\n"
"from a read-only device, or other\n"
"instances are running.");
break;
case 0:
switch (file_in_command_line)
{
case 0:
if (Config.Opening_message)
Button_Message_initial();
break;
case 2:
// Load this file
Init_context_layered_image(&context, spare_filename, spare_directory);
Load_image(&context);
Destroy_context(&context);
End_of_modification();
Redraw_layered_image();
Button_Page();
// no break ! proceed with the other file now
case 1:
Init_context_layered_image(&context, main_filename, main_directory);
Load_image(&context);
Destroy_context(&context);
End_of_modification();
Redraw_layered_image();
Hide_cursor();
Compute_optimal_menu_colors(Main_palette);
Display_all_screen();
Display_menu();
Display_cursor();
Resolution_in_command_line = 0;
break;
default:
break;
}
} }
return(1); return(1);
} }