Files
dvdisaster/file.c
2012-03-06 20:10:48 +09:00

255 lines
6.4 KiB
C

/* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2011 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#include "dvdisaster.h"
/***
*** Open the image file and fill in the respective Info struct.
***/
ImageInfo* OpenImageFile(EccHeader *eh, int mode)
{ ImageInfo *ii = NULL;
gint64 img_size;
int n,file_flags;
gint64 fp_sector;
unsigned char buf[2048];
struct MD5Context md5ctxt;
ii = g_malloc0(sizeof(ImageInfo));
if(!(mode & PRINT_MODE))
PrintLog(_("\nOpening %s"), Closure->imageName);
if(!LargeStat(Closure->imageName, &img_size))
{ if(mode & PRINT_MODE) /* no error in print mode */
{ FreeImageInfo(ii);
return NULL;
}
PrintLog(": %s.\n", strerror(errno));
g_free(ii);
Stop(_("Image file %s: %s."), Closure->imageName, strerror(errno));
return NULL;
}
file_flags = mode & WRITEABLE_IMAGE ? O_RDWR : O_RDONLY;
if(!(ii->file = LargeOpen(Closure->imageName, file_flags, IMG_PERMS)))
{ if(!(mode & PRINT_MODE))
PrintLog(": %s.\n", strerror(errno));
if(Closure->guiMode)
{ g_free(ii);
Stop(_("Can't open %s:\n%s"),Closure->imageName,strerror(errno));
}
else Stop(_("Image file %s: %s."), Closure->imageName, strerror(errno));
return NULL;
}
ii->size = img_size;
CalcSectors(img_size, &ii->sectors, &ii->inLast);
if(!(mode & PRINT_MODE))
{ if(ii->inLast == 2048)
PrintLog(_(": %lld medium sectors.\n"), ii->sectors);
else PrintLog(_(": %lld medium sectors and %d bytes.\n"),
ii->sectors-1, ii->inLast);
}
/*** Calculate md5sum of the fingerprint sector.
Use sector specified by .ecc file if possible,
else use built-in default */
if(!eh)
fp_sector = FINGERPRINT_SECTOR;
else fp_sector = eh->fpSector;
LargeSeek(ii->file, fp_sector*2048);
MD5Init(&md5ctxt);
n = LargeRead(ii->file, buf, 2048);
if(n != 2048)
Stop(_("could not read image sector %lld (only %d bytes):\n%s"),
fp_sector,n,strerror(errno));
MD5Update(&md5ctxt, buf, n);
MD5Final(ii->mediumFP, &md5ctxt);
if(CheckForMissingSector(buf, fp_sector, NULL, 0) != SECTOR_PRESENT) /* No sector, no md5sum */
{ memset(ii->mediumFP, 0 ,16);
ii->fpValid=FALSE;
}
else ii->fpValid=TRUE;
LargeSeek(ii->file, 0); /* rewind */
return ii;
}
void FreeImageInfo(ImageInfo *ii)
{
if(ii->file)
if(!LargeClose(ii->file))
Stop(_("Error closing image file:\n%s"), strerror(errno));
g_free(ii);
}
/***
*** Open the ecc file and fill in the info stuff
***/
EccInfo* OpenEccFile(int mode)
{ EccInfo *ei = NULL;
int file_flags;
/*** Sanity check for ecc file reads */
if(!(mode & WRITEABLE_ECC))
{ gint64 ecc_size;
if(!LargeStat(Closure->eccName, &ecc_size))
{ if(!(mode & PRINT_MODE))
Stop(_("Can't open %s:\n%s"),Closure->eccName,strerror(errno));
return NULL;
}
if(ecc_size < 4096)
Stop(_("Invalid or damaged ecc file"));
}
/*** Open the ecc file */
ei = g_malloc0(sizeof(EccInfo));
ei->eh = g_malloc0(sizeof(EccHeader));
file_flags = mode & WRITEABLE_ECC ? O_RDWR | O_CREAT : O_RDONLY;
if(!(ei->file = LargeOpen(Closure->eccName, file_flags, IMG_PERMS)))
{ FreeEccInfo(ei);
ei = NULL;
if(!(mode & PRINT_MODE)) /* missing ecc file no problem in print mode */
Stop(_("Can't open %s:\n%s"),Closure->eccName,strerror(errno));
return NULL;
}
if(!(mode & WRITEABLE_ECC))
{ int n = LargeRead(ei->file, ei->eh, sizeof(EccHeader));
if(n != sizeof(EccHeader))
{ FreeEccInfo(ei);
Stop(_("Can't read ecc header:\n%s"),strerror(errno));
}
/*** Endian annoyance */
#ifdef HAVE_BIG_ENDIAN
SwapEccHeaderBytes(ei->eh);
#endif
/*** See if we can use the ecc file */
if(strncmp((char*)ei->eh->cookie, "*dvdisaster*", 12))
{ FreeEccInfo(ei);
Stop(_("Invalid or damaged ecc file"));
}
VerifyVersion(ei->eh,1);
ei->sectors = uchar_to_gint64(ei->eh->sectors);
LargeSeek(ei->file, 0);
}
return ei;
}
void FreeEccInfo(EccInfo *ei)
{
if(ei->file)
if(!LargeClose(ei->file))
Stop(_("Error closing error correction file:\n%s"), strerror(errno));
if(ei->eh) g_free(ei->eh);
g_free(ei);
}
/***
*** Auxiliary functions
***/
/*
* Append the given file suffix if none is already present
*/
char *ApplyAutoSuffix(char *filename, char *suffix)
{ char *out;
if(!filename || !*filename || strrchr(filename, '.'))
return filename;
out = g_strdup_printf("%s.%s",filename,suffix);
g_free(filename);
return out;
}
/*
* See if we can handle the specified .ecc file
*/
int VerifyVersion(EccHeader *eh, int fatal)
{
if(Closure->version < eh->neededVersion)
{ if(fatal)
Stop(_("This .ecc file requires dvdisaster V%d.%d.%d or higher.\n"
"Please visit http://www.dvdisaster.com for an upgrade."),
eh->neededVersion/10000,
(eh->neededVersion%10000)/100,
eh->neededVersion%100);
return 1;
}
return 0;
}
/* Remove the image file */
void UnlinkImage(GtkWidget *label)
{
if(LargeUnlink(Closure->imageName))
{ PrintLog(_("\nImage file %s deleted.\n"),Closure->imageName);
if(Closure->guiMode)
SetLabelText(GTK_LABEL(label),
_("\nImage file %s deleted.\n"), Closure->imageName);
}
else
{ if(!Closure->guiMode)
PrintLog("\n");
ModalWarning(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, NULL,
_("Image file %s not deleted: %s\n"),
Closure->imageName, strerror(errno));
}
}