New -osirrox option sparse= controls extraction into sparse files
This commit is contained in:
@ -533,6 +533,278 @@ ex:;
|
||||
}
|
||||
|
||||
|
||||
/* If defined the position accounting will be done by lseek() and used to
|
||||
* verify the position accounting in struct Xorriso_sparse_statE.
|
||||
* # def ine Xorriso_check_sparsE yes
|
||||
*/
|
||||
|
||||
struct Xorriso_sparse_statE {
|
||||
int use_lseek;
|
||||
off_t cur_pos;
|
||||
off_t after_last_written;
|
||||
int warnings;
|
||||
};
|
||||
|
||||
|
||||
#ifdef Xorriso_check_sparsE
|
||||
|
||||
static int Xorriso_sparse_warn(struct XorrisO *xorriso,
|
||||
struct Xorriso_sparse_statE *sparse_state,
|
||||
int occasion, char *msg, int flag)
|
||||
{
|
||||
if(sparse_state->warnings & (1 << occasion))
|
||||
return(1);
|
||||
sparse_state->warnings|= 1 << occasion;
|
||||
Xorriso_msgs_submit(xorriso, 0, msg, 0, "SORRY", 0);
|
||||
return(1);
|
||||
}
|
||||
|
||||
#endif /* Xorriso_check_sparsE */
|
||||
|
||||
|
||||
static int Xorriso_sparse_init(struct XorrisO *xorriso,
|
||||
struct Xorriso_sparse_statE **sparse_state,
|
||||
int write_fd, int flag)
|
||||
{
|
||||
struct Xorriso_sparse_statE *o= NULL;
|
||||
off_t cur_pos;
|
||||
struct stat stbuf;
|
||||
int ret;
|
||||
|
||||
*sparse_state= NULL;
|
||||
|
||||
/* Check whether sparse writing is disabled */
|
||||
if(xorriso->sparse_min_gap <= 0)
|
||||
{ret= 0; goto ex;}
|
||||
|
||||
/* Analyze write_fd */
|
||||
ret= fstat(write_fd, &stbuf);
|
||||
if(ret == -1)
|
||||
{ret= 0; goto ex;}
|
||||
if(!S_ISREG(stbuf.st_mode))
|
||||
{ret= 0; goto ex;}
|
||||
cur_pos= lseek(write_fd, (off_t) 0, SEEK_CUR);
|
||||
if(cur_pos < stbuf.st_size)
|
||||
{ret= 0; goto ex;}
|
||||
|
||||
Xorriso_alloc_meM(o, struct Xorriso_sparse_statE, 1);
|
||||
|
||||
/* Initialize sparse_state */
|
||||
o->use_lseek= 1;
|
||||
o->cur_pos= o->after_last_written= cur_pos;
|
||||
o->warnings= 0;
|
||||
|
||||
ret= 1;
|
||||
ex:;
|
||||
if(ret >= 1)
|
||||
*sparse_state= o;
|
||||
else
|
||||
Xorriso_free_meM(o);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
static int Xorriso_sparse_zeroize(struct XorrisO *xorriso,
|
||||
struct Xorriso_sparse_statE *sparse_state,
|
||||
int write_fd, off_t start, off_t count,
|
||||
int flag)
|
||||
{
|
||||
int ret, buf_size= 32 * 1024, buf_fill, wret;
|
||||
off_t todo, seek_ret;
|
||||
char *buf= NULL;
|
||||
|
||||
if(count <= 0)
|
||||
{ret= 2; goto ex;}
|
||||
Xorriso_alloc_meM(buf, char, buf_size);
|
||||
|
||||
seek_ret= lseek(write_fd, start, SEEK_SET);
|
||||
if(seek_ret == -1)
|
||||
{ret= -1; goto ex;}
|
||||
sparse_state->cur_pos= seek_ret;
|
||||
for(todo= count; todo > 0; ) {
|
||||
if(buf_size < todo)
|
||||
buf_fill= buf_size;
|
||||
else
|
||||
buf_fill= todo;
|
||||
wret= write(write_fd, buf, buf_fill);
|
||||
if(wret <= 0)
|
||||
{ret= wret; goto ex;}
|
||||
todo-= wret;
|
||||
sparse_state->cur_pos+= wret;
|
||||
}
|
||||
ret= 1;
|
||||
ex:;
|
||||
Xorriso_free_meM(buf);
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0= this is the last buffer of the stream
|
||||
*/
|
||||
static int Xorriso_sparse_write(struct XorrisO *xorriso,
|
||||
struct Xorriso_sparse_statE *sparse_state,
|
||||
int write_fd, char *buf, int count,
|
||||
int flag)
|
||||
{
|
||||
int wret, i, ret;
|
||||
off_t cur_pos= -1, seek_ret;
|
||||
static char zero[32]= {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
|
||||
0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
|
||||
|
||||
if(sparse_state == NULL)
|
||||
goto do_write;
|
||||
if(!sparse_state->use_lseek)
|
||||
goto do_write;
|
||||
if(flag & 1)
|
||||
goto do_write;
|
||||
|
||||
#ifdef Xorriso_check_sparsE
|
||||
|
||||
cur_pos= lseek(write_fd, (off_t) 0, SEEK_CUR);
|
||||
if(cur_pos == -1)
|
||||
goto do_write;
|
||||
if(cur_pos != sparse_state->cur_pos) {
|
||||
Xorriso_sparse_warn(xorriso, sparse_state, 0,
|
||||
"cur_pos deviation in Xorriso_sparse_write:intro", 0);
|
||||
sparse_state->cur_pos= cur_pos;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
cur_pos= sparse_state->cur_pos;
|
||||
|
||||
#endif
|
||||
|
||||
/* Check for all zeros */
|
||||
if(count % 32)
|
||||
goto do_write;
|
||||
for(i= 0; i < count; i+= 32)
|
||||
if(memcmp(buf + i, zero, 32))
|
||||
break;
|
||||
if(i < count)
|
||||
goto do_write;
|
||||
|
||||
/* Omit write() until next non-zero buffer or end of writing */
|
||||
|
||||
#ifdef Xorriso_check_sparsE
|
||||
|
||||
/* Only for debugging: Do real lseek() instead of write() */
|
||||
seek_ret= lseek(write_fd, cur_pos + count, SEEK_SET);
|
||||
if(seek_ret == -1)
|
||||
return(-1);
|
||||
|
||||
#endif
|
||||
|
||||
sparse_state->cur_pos= cur_pos + count;
|
||||
return(count);
|
||||
|
||||
do_write:
|
||||
if(sparse_state != NULL) {
|
||||
/* Check whether the gap since after_last_written is too small.
|
||||
If so: fill the whole gap by writing zeros.
|
||||
*/
|
||||
if(sparse_state->after_last_written < cur_pos) {
|
||||
if(xorriso->sparse_min_gap > cur_pos - sparse_state->after_last_written) {
|
||||
ret= Xorriso_sparse_zeroize(xorriso, sparse_state, write_fd,
|
||||
sparse_state->after_last_written,
|
||||
cur_pos - sparse_state->after_last_written, 0);
|
||||
if(ret < 0)
|
||||
return(ret);
|
||||
if(ret == 0) {
|
||||
seek_ret= lseek(write_fd, cur_pos, SEEK_SET);
|
||||
if(seek_ret == -1)
|
||||
return(-1);
|
||||
sparse_state->cur_pos= seek_ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(sparse_state != NULL) {
|
||||
|
||||
#ifdef Xorriso_check_sparsE
|
||||
|
||||
cur_pos= lseek(write_fd, (off_t) 0, SEEK_CUR);
|
||||
if(cur_pos != sparse_state->cur_pos) {
|
||||
Xorriso_sparse_warn(xorriso, sparse_state, 1,
|
||||
"cur_pos deviation in Xorriso_sparse_write:do_write", 0);
|
||||
sparse_state->cur_pos= cur_pos;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* lseek() has been delayed until now */
|
||||
if(sparse_state->after_last_written != sparse_state->cur_pos) {
|
||||
seek_ret= lseek(write_fd, sparse_state->cur_pos, SEEK_SET);
|
||||
if(seek_ret == -1)
|
||||
return(-1);
|
||||
}
|
||||
|
||||
#endif /* ! Xorriso_check_sparsE */
|
||||
|
||||
}
|
||||
wret= write(write_fd, buf, count);
|
||||
if(sparse_state != NULL && wret > 0 && cur_pos >= 0)
|
||||
sparse_state->cur_pos= sparse_state->after_last_written= cur_pos + wret;
|
||||
return(wret);
|
||||
}
|
||||
|
||||
|
||||
static int Xorriso_sparse_finish(struct XorrisO *xorriso,
|
||||
struct Xorriso_sparse_statE **sparse_state,
|
||||
int write_fd, int flag)
|
||||
{
|
||||
int ret;
|
||||
off_t cur_pos;
|
||||
struct Xorriso_sparse_statE *o;
|
||||
|
||||
if(sparse_state == NULL)
|
||||
return(0);
|
||||
o= *sparse_state;
|
||||
if(o == NULL)
|
||||
return(1);
|
||||
if(write_fd == -1)
|
||||
{ret= 1; goto ex;}
|
||||
|
||||
#ifdef Xorriso_check_sparsE
|
||||
|
||||
cur_pos= lseek(write_fd, (off_t) 0, SEEK_CUR);
|
||||
if(cur_pos == -1)
|
||||
{ret= -1; goto ex;}
|
||||
if(cur_pos != o->cur_pos) {
|
||||
Xorriso_sparse_warn(xorriso, o, 2,
|
||||
"cur_pos deviation in Xorriso_sparse_finish", 0);
|
||||
o->cur_pos= cur_pos;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
cur_pos= o->cur_pos;
|
||||
|
||||
#endif /* ! Xorriso_check_sparsE */
|
||||
|
||||
if(o->after_last_written < cur_pos) {
|
||||
/* Check whether the gap since after_last_written is too small.
|
||||
If so: fill the whole gap by writing zeros, else: write a last zero byte.
|
||||
*/
|
||||
if(xorriso->sparse_min_gap > cur_pos - o->after_last_written)
|
||||
ret= Xorriso_sparse_zeroize(xorriso, o, write_fd, o->after_last_written,
|
||||
cur_pos - o->after_last_written, 0);
|
||||
else
|
||||
ret= Xorriso_sparse_zeroize(xorriso, o, write_fd, cur_pos - 1, (off_t) 1,
|
||||
0);
|
||||
if(ret <= 0)
|
||||
goto ex;
|
||||
}
|
||||
ret= 1;
|
||||
ex:;
|
||||
Xorriso_free_meM(o);
|
||||
*sparse_state= NULL;
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* @param flag bit0= Minimal transfer: access permissions only
|
||||
bit1= *_offset and bytes are valid for writing to regular file
|
||||
bit2= This is not a parameter. Do not report if ignored
|
||||
@ -567,7 +839,8 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
|
||||
off_t catsize;
|
||||
char disk_md5[16], iso_md5[16];
|
||||
void *ctx= NULL;
|
||||
int use_md5= 0, i;
|
||||
int use_md5= 0, i, sparse_ret= 3;
|
||||
struct Xorriso_sparse_statE *sparse_state= NULL;
|
||||
|
||||
Xorriso_alloc_meM(buf, char, buf_size);
|
||||
Xorriso_alloc_meM(temp_path, char, SfileadrL);
|
||||
@ -679,6 +952,9 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
|
||||
goto cannot_restore;
|
||||
}
|
||||
}
|
||||
if(ISO_NODE_IS_FILE(node))
|
||||
Xorriso_sparse_init(xorriso, &sparse_state, write_fd, 0);
|
||||
|
||||
while(todo>0) {
|
||||
wanted= buf_size;
|
||||
if(wanted>todo)
|
||||
@ -731,7 +1007,11 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
|
||||
ret= read_count - img_offset;
|
||||
}
|
||||
|
||||
wret= write(write_fd, buf_pt, ret);
|
||||
if(sparse_state == NULL)
|
||||
wret= write(write_fd, buf_pt, ret);
|
||||
else
|
||||
wret= Xorriso_sparse_write(xorriso, sparse_state, write_fd, buf_pt, ret,
|
||||
0);
|
||||
if(wret>=0) {
|
||||
todo-= wret;
|
||||
xorriso->pacifier_byte_count+= wret;
|
||||
@ -774,8 +1054,11 @@ bad_md5:;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(write_fd != -1)
|
||||
|
||||
if(write_fd != -1) {
|
||||
sparse_ret= Xorriso_sparse_finish(xorriso, &sparse_state, write_fd, 0);
|
||||
close(write_fd);
|
||||
}
|
||||
write_fd= -1;
|
||||
if(todo > 0 && xorriso->extract_error_mode == 2) {
|
||||
unlink(open_path_pt);
|
||||
@ -798,6 +1081,12 @@ bad_md5:;
|
||||
}
|
||||
ret= -(todo > 0);
|
||||
l_errno= 0;
|
||||
if(sparse_ret <= 0) {
|
||||
strcpy(xorriso->info_text, "Could not finalize sparse extraction of ");
|
||||
Text_shellsafe(disk_path, xorriso->info_text, 1 | 2);
|
||||
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text,
|
||||
sparse_ret < 0 ? errno : 0, "FAILURE", 0);
|
||||
}
|
||||
|
||||
} else if(LIBISO_ISLNK(node)) {
|
||||
what= "symbolic link";
|
||||
@ -898,6 +1187,8 @@ ex:;
|
||||
Xorriso_iso_file_close(xorriso, &data_stream, 0);
|
||||
if(ctx != NULL)
|
||||
Xorriso_md5_end(xorriso, &ctx, disk_md5, 0);
|
||||
if(sparse_state != NULL)
|
||||
Xorriso_sparse_finish(xorriso, &sparse_state, -1, 0);
|
||||
Xorriso_process_msg_queues(xorriso,0);
|
||||
return(ret);
|
||||
}
|
||||
|
Reference in New Issue
Block a user