Setting chattr "C" and "i" at their proper times during restoring to disk

This commit is contained in:
2024-08-06 21:32:41 +02:00
parent ce66b6a7e4
commit c0ec40c5d2
10 changed files with 417 additions and 174 deletions

View File

@ -303,6 +303,105 @@ ex:;
}
int Xorriso_report_chattr_outcome(struct XorrisO *xorriso, char *disk_path,
uint64_t lfa_flags, uint64_t lfa_mask,
int iso_ret, int os_errno, int flag)
{
int ret;
char msg[101], *lfa_text= NULL;
if(iso_ret == 1)
{ret= 1; goto ex;}
ret= iso_util_encode_lfa_flags(lfa_flags & lfa_mask, &lfa_text, 0);
if(lfa_text == NULL)
lfa_text= strdup("-unknown-attributes-");
if(iso_ret < 0) {
strcpy(msg, "Could not set chattr '");
if(lfa_text != NULL)
strcat(msg, lfa_text);
strcat(msg, "'");
Xorriso_report_iso_error(xorriso, disk_path, iso_ret, msg, os_errno,
"FAILURE", 2);
ret= 0; goto ex;
} else if(iso_ret == 2) {
sprintf(xorriso->info_text,
"Could not map all of chattr '%s' to local file attributes of ",
lfa_text);
} else if(iso_ret == 3) {
sprintf(xorriso->info_text, "Will not apply chattr '%s' to symbolic link ",
lfa_text);
} else {
sprintf(xorriso->info_text,
"Unknown return value %d from iso_local_set_lfa_flags() with chattr '%s' to ",
iso_ret, lfa_text);
}
Text_shellsafe(disk_path, xorriso->info_text, 1);
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE", 0);
ret= 0;
ex:;
if(lfa_text != NULL)
free(lfa_text);
return(ret);
}
uint64_t Xorriso__lfa_bits(char *lfa_text)
{
int ret;
uint64_t lfa_bits;
ret= iso_util_decode_lfa_flags(lfa_text, &lfa_bits, 0);
if(ret < 0)
lfa_bits= 0;
return(lfa_bits);
}
int Xorriso_set_local_chattr_i(struct XorrisO *xorriso, char *disk_path,
int flag)
{
int ret, max_bit= 31, os_errno;
static uint64_t lfa_i= 0xffffffff;
if(lfa_i == 0xffffffff)
lfa_i= Xorriso__lfa_bits("i");
ret= iso_local_set_lfa_flags(disk_path, lfa_i, max_bit, lfa_i, &os_errno, 0);
ret= Xorriso_report_chattr_outcome(xorriso, disk_path, lfa_i, lfa_i,
ret, os_errno, 0);
if(ret <= 0)
return(ret);
return(1);
}
/* If present and enabled: restore chattr i */
int Xorriso_restore_chattr_i(struct XorrisO *xorriso, IsoNode *node,
char *disk_path, int flag)
{
int ret, max_bit;
uint64_t lfa_flags;
static uint64_t lfa_i= 0xffffffff;
if(lfa_i == 0xffffffff)
lfa_i= Xorriso__lfa_bits("i");
if((xorriso->do_aaip & (1 << 12)) && !(xorriso->do_aaip & (1 << 13))) {
ret= iso_node_get_lfa_flags(node, &lfa_flags, &max_bit, 0);
if(ret > 0) {
if(lfa_flags & lfa_i & xorriso->lfa_restore_mask) {
ret= Xorriso_set_local_chattr_i(xorriso, disk_path, 0);
if(ret <= 0)
return(ret);
return(1);
}
}
}
return(2);
}
/* @param flag bit0= minimal transfer: access permissions only
bit1= keep directory open: keep owner, allow rwx for owner
and push directory onto xorriso->perm_stack
@ -319,8 +418,14 @@ int Xorriso_restore_properties(struct XorrisO *xorriso, char *disk_path,
size_t num_attrs= 0, *value_lengths= NULL;
char **names= NULL, **values= NULL;
int *errnos= NULL;
uint64_t lfa_flags;
uint64_t lfa_flags, mask;
int max_bit, os_errno;
static uint64_t lfa_C= 0xffffffff, lfa_i= 0xffffffff;
if(lfa_C == 0xffffffff) {
lfa_C= Xorriso__lfa_bits("C");
lfa_i= Xorriso__lfa_bits("i");
}
ret= lstat(disk_path, &stbuf);
if(ret==-1) {
@ -474,16 +579,25 @@ cannot_set_perm:;
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FAILURE", 0);
{ret= 0; goto ex;}
} else if(ret > 0) {
ret= iso_local_set_lfa_flags(disk_path, lfa_flags, max_bit,
xorriso->lfa_restore_mask, &os_errno,
(!!(xorriso->do_aaip & (1 << 13))) |
((!!(xorriso->do_aaip & (1 << 14))) << 1));
if(ret < 0) {
/* Do not set lfa_flag 'C' here. It would be too late. */
mask= xorriso->lfa_restore_mask & ~lfa_C;
/* Do not set lfa_flag 'i' of a directory here. It would be too early. */
if(is_dir)
mask&= ~lfa_i;
if(mask != 0) {
ret= iso_local_set_lfa_flags(disk_path, lfa_flags, max_bit, mask,
&os_errno,
(!!(xorriso->do_aaip & (1 << 13))) |
((!!(xorriso->do_aaip & (1 << 14))) << 1));
/* >>> Need adjustable graceful error handling */;
Xorriso_process_msg_queues(xorriso, 0);
{ret= 0; goto ex;}
ret= Xorriso_report_chattr_outcome(xorriso, disk_path,
lfa_flags,
xorriso->lfa_restore_mask & ~lfa_C,
ret, os_errno, 0);
if(ret <= 0)
goto ex;
}
}
}
@ -850,7 +964,7 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
int flag)
{
int ret= 0, write_fd= -1, wanted, wret, open_flags, l_errno= 0;
int target_deleted= 0, buf_size= 32 * 1024;
int target_deleted= 0, buf_size= 32 * 1024, new_empty= 0;
char *what= "[unknown filetype]";
char *buf= NULL, type_text[5], *temp_path= NULL, *buf_pt, *reason;
char *link_target, *open_path_pt= NULL;
@ -867,12 +981,17 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
off_t catsize, iso_node_size, wanted_size, cap;
char disk_md5[16], iso_md5[16];
void *ctx= NULL;
int use_md5= 0, i, sparse_ret= 3;
int use_md5= 0, i, sparse_ret= 3, max_bit, os_errno;
struct Xorriso_sparse_statE *sparse_state= NULL;
uint64_t lfa_flags;
static uint64_t lfa_C= 0xffffffff;
Xorriso_alloc_meM(buf, char, buf_size);
Xorriso_alloc_meM(temp_path, char, SfileadrL);
if(lfa_C == 0xffffffff)
lfa_C= Xorriso__lfa_bits("C");
if(!(flag & 2))
img_offset= bytes= 0;
if(LIBISO_ISDIR(node)) {
@ -911,8 +1030,11 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
}
open_path_pt= disk_path;
ret= stat(open_path_pt, &stbuf);
if(ret == -1 && errno == EACCES && (flag & 128))
{ret= 4; goto ex;}
if(ret == -1) {
if(errno == EACCES && (flag & 128))
{ret= 4; goto ex;}
new_empty= 1;
}
if(flag&2) {
if(ret != -1) {
wanted_size= disk_offset + bytes;
@ -959,6 +1081,7 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
if(ret <= 0 || ret == 4)
goto ex;
open_path_pt= temp_path;
new_empty= 1;
}
}
if(write_fd==-1) {
@ -972,6 +1095,25 @@ int Xorriso_tree_restore_node(struct XorrisO *xorriso, IsoNode *node,
if(write_fd==-1)
goto cannot_restore;
}
if(new_empty) {
/* If chattr 'C' "no copy-on-write" is present on node and enabled for
restoring, then set it as long as the file is empty, because man chattr
says so for btrfs.
*/
ret= iso_node_get_lfa_flags(node, &lfa_flags, &max_bit, 0);
if(ret > 0) {
if(lfa_flags & lfa_C & xorriso->lfa_restore_mask) {
ret= iso_local_set_lfa_flags(open_path_pt, lfa_C, max_bit, lfa_C,
&os_errno, 0);
ret= Xorriso_report_chattr_outcome(xorriso, open_path_pt,
lfa_C, lfa_C, ret, os_errno, 0);
if(ret <= 0)
goto cannot_restore;
}
}
}
if(ISO_NODE_IS_BOOTCAT(node)) {
ret= Xorriso_get_volume(xorriso, &volume, 0);
if(ret<=0)
@ -1479,6 +1621,8 @@ int Xorriso_restore_disk_object(struct XorrisO *xorriso,
goto restoring_failed;
if(ret == 4)
goto ex;
if(ret == 2)
{ret= 3; goto ex;}
}
if(first_part_node != NULL && !no_props)
Xorriso_restore_properties(xorriso, disk_path, first_part_node,
@ -1526,6 +1670,8 @@ int Xorriso_restore_disk_object(struct XorrisO *xorriso,
| (no_props << 3));
if(ret == 4)
goto ex;
if(ret == 2)
{ret= 3; goto ex;}
if(ret > 0 && (flag & 8) && !no_props)
ret= Xorriso_restore_properties(xorriso, disk_path, node, 2 | !!(flag&64));
if(ret<=0) {
@ -1537,8 +1683,6 @@ restoring_failed:;
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "SORRY", 0);
{ret= 0; goto ex;}
}
if(ret==2)
{ret= 3; goto ex;}
if(record_hl_path) { /* Start of a disk hardlink family */
ret= Xorriso_register_node_target(xorriso, node_idx, disk_path, 0);
if(ret < 0)
@ -1659,7 +1803,7 @@ int Xorriso_restore_tree(struct XorrisO *xorriso, IsoDir *dir,
IsoDirIter *iter= NULL;
IsoNode **node_array= NULL;
int node_count= 0, node_idx;
int ret, source_is_dir, fret, was_failure= 0;
int ret, source_is_dir, fret, was_failure= 0, sret;
int do_not_dive, source_is_split= 0, len_dp, len_ip, stbuf_ret, hflag, hret;
char *name, *disk_name, *leaf_name, *srcpt, *stbuf_src= "";
struct LinkiteM *own_link_stack;
@ -1667,8 +1811,9 @@ int Xorriso_restore_tree(struct XorrisO *xorriso, IsoDir *dir,
char *disk_path= NULL, *img_path= NULL, *link_target= NULL;
off_t mem;
struct PermiteM *perm_stack_mem;
struct stat stbuf;
struct stat stbuf, disk_stbuf;
int dir_create= 0, node_register= 0, do_node_count= 0, normal_mode= 0;
int target_was_no_dir, dir_is_new;
perm_stack_mem= xorriso->perm_stack;
switch((flag >> 7) & 3) {
@ -1759,6 +1904,8 @@ much_too_long:;
while(1) { /* loop over ISO directory content */
stbuf_src= "";
target_was_no_dir= 0;
dir_is_new= 0;
#ifdef Osirrox_not_yeT
@ -1862,26 +2009,49 @@ much_too_long:;
} else if(node_register || do_node_count) {
ret= 1;
} else {
if(source_is_dir) {
ret= lstat(disk_path, &disk_stbuf);
if(ret == -1) {
target_was_no_dir= 1;
} else {
if(!S_ISDIR(disk_stbuf.st_mode))
target_was_no_dir= 1;
}
}
ret= Xorriso_restore_disk_object(xorriso, img_path, node, disk_path,
(off_t) 0, (off_t) 0, hflag);
if(ret == 3) /* intentionally not restored */
do_not_dive= 1;
if(target_was_no_dir) {
sret= lstat(disk_path, &disk_stbuf);
if(sret != -1)
if(S_ISDIR(disk_stbuf.st_mode))
dir_is_new= 1;
}
}
if(ret<=0)
goto was_problem;
}
ret= 1;
if(source_is_dir && !do_not_dive) {
ret= Xorriso_restore_tree(xorriso, (IsoDir *) node,
img_path, disk_path, mem,
own_link_stack, 1 | (flag & (2 | (3 << 7))));
/* eventually restore exact access permissions of directory */
}
if(source_is_dir) {
/* Restore exact access permissions of directory */
hret= Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso,
!!(flag&64));
if(hret<=0 && hret<ret)
ret= hret;
if(ret<=0)
goto was_problem;
if(dir_is_new && !dir_create) {
hret= Xorriso_restore_chattr_i(xorriso, node, disk_path, 0);
if(hret <= 0 && hret < ret)
ret= hret;
}
}
if(ret <= 0)
goto was_problem;
continue; /* regular bottom of loop */
was_problem:;
@ -2115,9 +2285,10 @@ attach_source:;
if(hret < 0)
goto ex;
}
if(new_dir_made && !(flag&64))
/* set timestamps which Permstack_pop() will not set */
Xorriso_restore_properties(xorriso, disk_path, node, 2);
}
if(new_dir_made && !(flag&64)) {
/* set timestamps which Permstack_pop() will not set */
Xorriso_restore_properties(xorriso, disk_path, node, 2);
}
} else {
if(dir_create || node_count) {
@ -2137,9 +2308,27 @@ attach_source:;
}
}
}
} else
} else {
*npt= '/';
}
}
if(new_dir_made && !dir_create) {
ret= 1;
/* Need to set any properties before possibly setting immutable bit.
So pop earlier than normal.
*/
hret= Permstack_pop(&(xorriso->perm_stack), perm_stack_mem, xorriso,
2 | !!(flag&64));
if(hret <= 0 && hret < ret)
ret= hret;
hret= Xorriso_restore_chattr_i(xorriso, node, disk_path, 0);
if(hret <= 0 && hret < ret)
ret= hret;
if(ret <= 0)
goto ex;
}
Xorriso_process_msg_queues(xorriso,0);
ret= 1 + (is_dir && !leaf_is_split);
ex:;
@ -2419,6 +2608,8 @@ int Xorriso_extract_cut(struct XorrisO *xorriso,
eff_disk_path, (off_t) 0, bytes, 2 | 8);
if(ret<=0)
goto ex;
if(ret != 1)
{ret= 0; goto ex;}
}
ret= Xorriso_restore_properties(xorriso, eff_disk_path, node, 0);