Imported Upstream version 0.72.3

This commit is contained in:
TANIGUCHI Takaki
2012-03-06 11:08:15 +09:00
parent 205701b3de
commit 30255c97b3
713 changed files with 13953 additions and 28840 deletions

View File

@@ -1,5 +1,5 @@
/* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2010 Carsten Gnoerlich.
* Copyright (C) 2004-2011 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
*
@@ -25,16 +25,22 @@
*** Wrappers around the standard low level file system interface.
***
* This is pointless for Linux, but gives us the possibility to
* hide differences in Linux/Windows semantics.
* hide differences in Linux/Windows semantics and to
* do split image files on VFAT in a transparent way.
*
* Note the different return value semantics from standard functions:
* - LargeOpen() returns a LargeFile pointer on success and NULL otherwise;
* - LargeRead() and LargeWrite() return the number of bytes read/written;
* - the remaining functions return True on success or False on failure.
*
* Also, individual behaviour may deviate from standard functions.
* Also, individual behaviour may deviate from standard functions especially
* when in split file mode.
*/
//#define MAX_FILE_SIZE (128*1024*1024)
//#define MAX_FILE_SIZE (8*1024*1024)
#define MAX_FILE_SIZE (2048LL*1024LL*1024LL)
#ifdef SYS_MINGW
#include <windows.h>
@@ -68,7 +74,7 @@ int large_ftruncate(int fd, gint64 size)
*/
static gchar* os_path(char *path_in)
{ gchar *cp_path = g_filename_from_utf8(path_in, -1, NULL, NULL, NULL);
{ gchar *cp_path = g_locale_from_utf8(path_in, -1, NULL, NULL, NULL);
if(cp_path == NULL)
{ errno = EINVAL;
@@ -79,26 +85,92 @@ static gchar* os_path(char *path_in)
return cp_path;
}
/*
* local aux function: opens the given segment of a large file.
*/
static int open_segment(LargeFile *lf, int n)
{ char name[lf->namelen];
gchar *cp_path;
if(!lf->suffix) g_sprintf(name, "%s%02d", lf->basename, n);
else g_sprintf(name, "%s%02d.%s", lf->basename, n, lf->suffix);
cp_path = os_path(name);
if(!cp_path) return FALSE;
lf->fileSegment[n] = open(cp_path, lf->flags, lf->mode);
g_free(cp_path);
if(lf->fileSegment[n] == -1)
{ PrintLog("open_segment(\"%s*\", %d) failed\n", lf->basename, n);
return FALSE;
}
return TRUE;
}
/*
* Large stat replacement (queries only file size)
*/
int LargeStat(char *path, gint64 *length_return)
{ struct stat mystat;
gchar *cp_path = os_path(path);
char name[strlen(path)+3];
char prefix[strlen(path)+1];
char *suffix = NULL, *c;
int i;
if(!cp_path) return FALSE;
/* Unsplit file case */
if(!Closure->splitFiles)
{ gchar *cp_path = os_path(path);
if(stat(cp_path, &mystat) == -1)
{ g_free(cp_path);
return FALSE;
if(!cp_path) return FALSE;
if(stat(cp_path, &mystat) == -1)
{ g_free(cp_path);
return FALSE;
}
g_free(cp_path);
if(!S_ISREG(mystat.st_mode))
return FALSE;
*length_return = mystat.st_size;
return TRUE;
}
g_free(cp_path);
if(!S_ISREG(mystat.st_mode))
return FALSE;
/* stat() all segments and add up their sizes */
*length_return = 0;
strcpy(prefix, path);
c = strrchr(prefix, '.');
if(c)
{ suffix = c+1;
*c = 0;
}
for(i=0; i<MAX_FILE_SEGMENTS; i++)
{ gchar *cp_path;
int result;
if(!suffix) g_sprintf(name, "%s%02d", prefix, i);
else g_sprintf(name, "%s%02d.%s", prefix,i,suffix);
cp_path = os_path(name);
if(!cp_path) return FALSE;
result = stat(cp_path, &mystat);
g_free(cp_path);
if( result == -1)
return i != 0;
else if(!S_ISREG(mystat.st_mode))
return FALSE;
else *length_return += mystat.st_size;
}
*length_return = mystat.st_size;
return TRUE;
}
@@ -132,6 +204,7 @@ LargeFile* LargeOpen(char *name, int flags, mode_t mode)
{ LargeFile *lf = g_malloc0(sizeof(LargeFile));
struct stat mystat;
gchar *cp_path;
char *c;
#ifdef HAVE_O_LARGEFILE
flags |= O_LARGEFILE;
@@ -140,25 +213,63 @@ LargeFile* LargeOpen(char *name, int flags, mode_t mode)
flags |= O_BINARY;
#endif
cp_path = os_path(name);
if(!cp_path) return FALSE;
/* Unsplit file case */
/* Do not try to open directories etc. */
if(!Closure->splitFiles)
{ cp_path = os_path(name);
if(!cp_path) return FALSE;
/* Do not try to open directories etc. */
if( (stat(cp_path, &mystat) == 0)
&& !S_ISREG(mystat.st_mode))
{ g_free(cp_path), g_free(lf); return NULL;
}
lf->fileSegment[0] = open(cp_path, flags, mode);
g_free(cp_path);
if(lf->fileSegment[0] == -1)
{ g_free(lf); return NULL;
}
LargeStat(name, &lf->size); /* Do NOT use cp_path! */
return lf;
}
/* Prepare for using split files.
* Note that we're only trying to open the first segment,
* so a failure condition of LargeOpen() is weaker for segmented
* files than for the single file case.
*/
lf->flags = flags;
if(lf->flags & (O_RDWR | O_WRONLY)) /* these imply O_CREAT here to create */
lf->flags |= O_CREAT; /* the additional file segments */
lf->mode = mode;
lf->namelen = strlen(name+3);
lf->basename = g_strdup(name);
c = strrchr(lf->basename, '.');
if(c)
{ lf->suffix = c+1;
*c = 0;
}
cp_path = os_path(name);
if(!cp_path) return NULL;
if( (stat(cp_path, &mystat) == 0)
&& !S_ISREG(mystat.st_mode))
{ g_free(cp_path), g_free(lf); return NULL;
{ g_free(cp_path); g_free(lf); return NULL;
}
lf->fileHandle = open(cp_path, flags, mode);
g_free(cp_path);
if(lf->fileHandle == -1)
if(!open_segment(lf, 0))
{ g_free(lf); return NULL;
}
lf->path = g_strdup(name);
LargeStat(name, &lf->size); /* Do NOT use cp_path! */
LargeStat(name, &lf->size);
return lf;
}
@@ -170,9 +281,48 @@ LargeFile* LargeOpen(char *name, int flags, mode_t mode)
int LargeSeek(LargeFile *lf, gint64 pos)
{
lf->offset = pos;
if(lseek(lf->fileHandle, pos, SEEK_SET) != pos)
return FALSE;
/* Unsplit file case */
if(!Closure->splitFiles)
{ lf->offset = pos;
if(lseek(lf->fileSegment[0], pos, SEEK_SET) != pos)
return FALSE;
}
/* Split file case */
else
{ gint64 seg = pos / MAX_FILE_SIZE;
gint64 segpos = pos - seg * MAX_FILE_SIZE;
if(seg >= MAX_FILE_SEGMENTS) /* Hit the maximum segment limit? */
{ PrintLog("LargeSeek(\"%s*\", %lld [%d:%d]) out of file descriptors\n",
lf->basename, pos, seg, segpos);
return FALSE;
}
/* Open the respective segment */
if(!lf->fileSegment[seg])
if(!open_segment(lf, seg))
{ PrintLog("LargeSeek(\"%s*\", %lld [%d:%d]) failed opening segment\n",
lf->basename, pos, seg, segpos);
return FALSE;
}
/* lseek() within the segment */
if(lseek(lf->fileSegment[seg], segpos, SEEK_SET) != segpos)
{ PrintLog("LargeSeek(\"%s*\", %lld [%d:%d]) failed seeking in segment\n",
lf->basename, pos, seg, segpos);
return FALSE;
}
/* remember segment and offset within */
lf->segment = seg;
lf->offset = segpos;
}
return TRUE;
}
@@ -184,25 +334,124 @@ int LargeSeek(LargeFile *lf, gint64 pos)
*/
int LargeEOF(LargeFile *lf)
{
return lf->offset >= lf->size;
{ gint64 filepos;
if(!Closure->splitFiles)
filepos = lf->offset;
else filepos = MAX_FILE_SIZE * lf->segment + lf->offset;
return filepos >= lf->size;
}
/*
* Reading large files
* Reading in segmented files
*/
ssize_t LargeRead(LargeFile *lf, void *buf, size_t count)
{ ssize_t n;
n = read(lf->fileHandle, buf, count);
lf->offset += n;
/* Simple unsegmented case */
return n;
if(!Closure->splitFiles)
{ n = read(lf->fileSegment[0], buf, count);
lf->offset += n;
return n;
}
/* Segmented file case; open first segment if necessary */
if(!lf->fileSegment[lf->segment])
if(!open_segment(lf, lf->segment))
return -1;
/* If buffer does not cross a segment boundary,
simply read from the current segment and return */
if(lf->offset + count <= MAX_FILE_SIZE)
{ n = read(lf->fileSegment[lf->segment], buf, count);
lf->offset += n;
/* If the segment boundary was touched,
wrap to next segment */
if(lf->offset >= MAX_FILE_SIZE)
{ lf->offset = 0;
lf->segment++;
if(lf->fileSegment[lf->segment] && lseek(lf->fileSegment[lf->segment], 0, SEEK_SET) != 0)
{ PrintLog("LargeRead(\"%s*\", ...) failed wrapping to next segment\n",
lf->segment);
return -1;
}
}
return n;
}
/* Read is spread over two or more segments */
else
{ /* Handle portion coming from current segment */
size_t first = MAX_FILE_SIZE - lf->offset;
size_t chunk = 0;
size_t read_in = 0;
n = read(lf->fileSegment[lf->segment], buf, first);
lf->offset += n;
if(n != first) return n;
count -= n;
/* Handle remainder which comes from the next segments */
while(count > 0)
{
/* Open next segment */
lf->segment++;
if(!lf->fileSegment[lf->segment])
{ if(!open_segment(lf, lf->segment))
return -1;
}
else
{ if(lseek(lf->fileSegment[lf->segment], 0, SEEK_SET) != 0)
{ PrintLog("LargeRead(\"%s*\", ...) failed switching to next segment\n",
lf->segment);
return n;
}
}
chunk = count > MAX_FILE_SIZE ? MAX_FILE_SIZE : count;
read_in = read(lf->fileSegment[lf->segment], buf+n, chunk);
n += read_in;
count -= read_in;
if(read_in != chunk) return n;
}
/* If the segment boundary was touched, wrap to next segment */
lf->offset = read_in;
if(lf->offset >= MAX_FILE_SIZE)
{ lf->offset = 0;
lf->segment++;
if(lf->fileSegment[lf->segment] && lseek(lf->fileSegment[lf->segment], 0, SEEK_SET) != 0)
{ PrintLog("LargeRead(\"%s*\", ...) failed wrapping to next segment\n",
lf->segment);
return -1;
}
}
return n;
}
}
/*
* Writing large files
* Writing in segmented files
*/
static void insert_buttons(GtkDialog *dialog)
@@ -267,10 +516,104 @@ static ssize_t xwrite(int fdes, void *buf_base, size_t count)
ssize_t LargeWrite(LargeFile *lf, void *buf, size_t count)
{ ssize_t n;
n = xwrite(lf->fileHandle, buf, count);
lf->offset += n;
/* Simple unsegmented case */
return n;
if(!Closure->splitFiles)
{ n = xwrite(lf->fileSegment[0], buf, count);
lf->offset += n;
return n;
}
/* Segmented file case; open first segment if necessary */
if(!lf->fileSegment[lf->segment])
if(!open_segment(lf, lf->segment))
return -1;
/* If buffer does not cross a segment boundary,
simply write it to the current segment and return */
if(lf->offset + count <= MAX_FILE_SIZE)
{ n = xwrite(lf->fileSegment[lf->segment], buf, count);
lf->offset += n;
/* If the segment boundary was touched,
wrap to next segment */
if(lf->offset >= MAX_FILE_SIZE)
{ lf->offset = 0;
lf->segment++;
if(lf->fileSegment[lf->segment] && lseek(lf->fileSegment[lf->segment], 0, SEEK_SET) != 0)
{ PrintLog("LargeWrite(\"%s*\", ...) failed wrapping to next segment\n",
lf->segment);
return -1;
}
}
return n;
}
/* Write is spread over two or more segments */
else
{ /* Handle portion going to current segment */
size_t first = MAX_FILE_SIZE - lf->offset;
size_t chunk = 0;
size_t written = 0;
n = xwrite(lf->fileSegment[lf->segment], buf, first);
lf->offset += n;
if(n != first) return n;
count -= n;
/* Handle remainder which goes into the next segments */
while(count > 0)
{
/* Open next segment */
lf->segment++;
if(!lf->fileSegment[lf->segment])
{ if(!open_segment(lf, lf->segment))
return -1;
}
else
{ if(lseek(lf->fileSegment[lf->segment], 0, SEEK_SET) != 0)
{ PrintLog("LargeWrite(\"%s*\", ...) failed switching to next segment\n",
lf->segment);
return n;
}
}
chunk = count > MAX_FILE_SIZE ? MAX_FILE_SIZE : count;
written = xwrite(lf->fileSegment[lf->segment], buf+n, chunk);
n += written;
count -= written;
if(written != chunk) return n;
}
/* If the segment boundary was touched, wrap to next segment */
lf->offset = written;
if(lf->offset >= MAX_FILE_SIZE)
{ lf->offset = 0;
lf->segment++;
if(lf->fileSegment[lf->segment] && lseek(lf->fileSegment[lf->segment], 0, SEEK_SET) != 0)
{ PrintLog("LargeWrite(\"%s*\", ...) failed wrapping to next segment\n",
lf->segment);
return -1;
}
}
return n;
}
}
/*
@@ -280,11 +623,26 @@ ssize_t LargeWrite(LargeFile *lf, void *buf, size_t count)
int LargeClose(LargeFile *lf)
{ int result = TRUE;
result = (close(lf->fileHandle) == 0);
/* Simple unsegmented case */
if(!Closure->splitFiles)
result = (close(lf->fileSegment[0]) == 0);
/* Segmented case */
else
{ int i;
for(i=0; i<MAX_FILE_SEGMENTS; i++)
{ if(lf->fileSegment[i] && close(lf->fileSegment[i]) != 0)
{ result = FALSE;
PrintLog("LargeClose(\"%s*\") failed closing segment %d\n", lf->basename, i);
}
}
}
/* Free the LargeFile struct and return results */
if(lf->path) g_free(lf->path);
if(lf->basename) g_free(lf->basename);
g_free(lf);
return result;
@@ -296,7 +654,42 @@ int LargeClose(LargeFile *lf)
int LargeTruncate(LargeFile *lf, gint64 length)
{
return large_ftruncate(lf->fileHandle, length) == 0;
/* Simple unsegmented case */
if(!Closure->splitFiles)
return large_ftruncate(lf->fileSegment[0], length) == 0;
/* Segmented case; first truncate the last segment */
else
{ gint64 seg = length / MAX_FILE_SIZE;
gint64 seglen = length - seg * MAX_FILE_SIZE;
int i;
if(!lf->fileSegment[seg])
{ if(!open_segment(lf, seg))
return FALSE;
}
if(large_ftruncate(lf->fileSegment[seg], seglen) != 0)
return FALSE;
/* In case of large truncation, close and delete excess segments */
for(i=seg+1; i<MAX_FILE_SEGMENTS; i++)
{ char name[lf->namelen];
gchar *cp_path;
close(lf->fileSegment[i]); /* no need for error testing */
if(!lf->suffix) g_sprintf(name, "%s%02d", lf->basename, i);
else g_sprintf(name, "%s%02d.%s", lf->basename, i, lf->suffix);
cp_path = os_path(name);
unlink(cp_path);
g_free(cp_path);
}
}
return TRUE;
}
/*
@@ -304,16 +697,49 @@ int LargeTruncate(LargeFile *lf, gint64 length)
*/
int LargeUnlink(char *path)
{ gchar *cp_path;
int result;
{ char name[strlen(path)+3];
char prefix[strlen(path)+1];
char *suffix = NULL, *c;
gchar *cp_path;
int i;
cp_path = os_path(path);
if(!cp_path) return FALSE;
/* Simple unsegmented case */
result = unlink(cp_path);
g_free(cp_path);
if(!Closure->splitFiles)
{ int result;
return result == 0;
cp_path = os_path(path);
if(!cp_path) return FALSE;
result = unlink(cp_path);
g_free(cp_path);
return result == 0;
}
/* Segmented case. This will unlink name00..name99 */
strcpy(prefix, path);
c = strrchr(prefix, '.');
if(c)
{ suffix = c+1;
*c = 0;
}
for(i=0; i<MAX_FILE_SEGMENTS; i++)
{ int result;
if(!suffix) g_sprintf(name, "%s%02d", prefix, i);
else g_sprintf(name, "%s%02d.%s", prefix, i, suffix);
cp_path = os_path(name);
if(!cp_path) return FALSE;
result = unlink(cp_path);
g_free(cp_path);
if(result == -1)
return i != 0;
}
return TRUE;
}
/***