2
/* xorriso - creates, loads, manipulates and burns ISO 9660 filesystem images.
4
Copyright 2007-2010 Thomas Schmitt, <scdbackup@gmx.net>
6
Provided under GPL version 2 or later.
8
This file contains the implementations of classes:
10
- SplitparT which represents byte intervals of data files.
12
- DirseQ which crawls along a directory's content list.
14
- ExclusionS which manages the list of excluded file paths and
16
Because of its structural identity it is also used for disk address
17
oriented hiding at insert time as of mkisofs.
19
- Xorriso_lsT which provides a generic double-linked list.
21
- LinkiteM, PermiteM which temporarily record relations and states.
26
#include "../config.h"
30
#include <sys/types.h>
44
#include "xorriso_private.h"
47
/* ---------------------------- SplitparT ------------------------- */
59
static char Splitpart_wordS[][16]= {"part_", "_of_", "_at_", "_with_", "_of_"};
62
int Splitparts_new(struct SplitparT **o, int count, int flag)
66
(*o)= TSOB_FELD(struct SplitparT, count);
69
for(i= 0; i<count; i++) {
72
(*o)[i].total_parts= 0;
75
(*o)[i].total_bytes= 0;
81
int Splitparts_destroy(struct SplitparT **o, int count, int flag)
87
for(i= 0; i<count; i++) {
88
if((*o)[i].name!=NULL)
97
int Splitparts_set(struct SplitparT *o, int idx,
98
char *name, int partno, int total_parts,
99
off_t offset, off_t bytes, off_t total_bytes, int flag)
101
if(o[idx].name!=NULL)
103
o[idx].name= strdup(name);
104
if(o[idx].name==NULL)
106
o[idx].partno= partno;
107
o[idx].total_parts= total_parts;
108
o[idx].offset= offset;
110
o[idx].total_bytes= total_bytes;
115
int Splitparts_get(struct SplitparT *o, int idx, char **name, int *partno,
116
int *total_parts, off_t *offset, off_t *bytes,
117
off_t *total_bytes, int flag)
120
*partno= o[idx].partno;
121
*total_parts= o[idx].total_parts;
122
*offset= o[idx].offset;
123
*bytes= o[idx].bytes;
124
*total_bytes= o[idx].total_bytes;
129
int Splitpart__read_next_num(char *base_pt, char **next_pt, off_t *num,
132
char *cpt, *ept, scale[4];
136
for(cpt= base_pt; *cpt!=0 && !isdigit(*cpt); cpt++);
139
for(ept= cpt; *ept!=0 && isdigit(*ept); ept++)
140
*num= (*num)*10+(*ept)-'0';
144
sfak= Scanf_io_size(scale, 0);
145
*num *= (off_t) sfak;
153
int Splitpart__parse(char *name, int *partno, int *total_parts,
154
off_t *offset, off_t *bytes, off_t *total_bytes, int flag)
162
if(strncmp(cpt, Splitpart_wordS[0], strlen(Splitpart_wordS[0])) != 0)
164
ret= Splitpart__read_next_num(cpt, &ept, &num, 0);
169
if(strncmp(cpt, Splitpart_wordS[1], strlen(Splitpart_wordS[1])) != 0)
171
ret= Splitpart__read_next_num(cpt, &ept, &num, 0);
176
if(strncmp(cpt, Splitpart_wordS[2], strlen(Splitpart_wordS[2])) != 0)
178
ret= Splitpart__read_next_num(cpt, &ept, offset, 0);
182
if(strncmp(cpt, Splitpart_wordS[3], strlen(Splitpart_wordS[3])) != 0)
184
ret= Splitpart__read_next_num(cpt, &ept, bytes, 0);
188
if(strncmp(cpt, Splitpart_wordS[4], strlen(Splitpart_wordS[4])) != 0)
190
ret= Splitpart__read_next_num(cpt, &ept, total_bytes, 0);
199
int Splitpart__is_part_path(char *path, int flag)
201
int partno, total_parts, ret;
202
off_t offset, bytes, total_bytes;
205
name= strrchr(path, '/');
210
ret= Splitpart__parse(name, &partno, &total_parts, &offset, &bytes,
216
/* part_#_of_#_at_#_with_#_of_#
218
int Splitpart__compose(char *adr, int partno, int total_parts,
219
off_t offset, off_t bytes, off_t total_bytes, int flag)
221
sprintf(adr, "%s%d%s%d%s", Splitpart_wordS[0], partno, Splitpart_wordS[1],
222
total_parts, Splitpart_wordS[2]);
223
if((offset % (1024*1024))==0 && offset>0) {
224
Sfile_off_t_text(adr+strlen(adr), offset / (1024*1024), 0);
227
Sfile_off_t_text(adr+strlen(adr), offset, 0);
228
strcat(adr, Splitpart_wordS[3]);
229
if((bytes % (1024*1024))==0) {
230
Sfile_off_t_text(adr+strlen(adr), bytes / (1024*1024), 0);
233
Sfile_off_t_text(adr+strlen(adr), bytes, 0);
234
strcat(adr, Splitpart_wordS[4]);
235
Sfile_off_t_text(adr+strlen(adr), total_bytes, 0);
240
int Splitparts_cmp(const void *v1, const void *v2)
242
struct SplitparT *p1, *p2;
244
p1= (struct SplitparT *) v1;
245
p2= (struct SplitparT *) v2;
247
if(p1->partno>p2->partno)
249
if(p1->partno<p2->partno)
251
if(p1->offset>p2->offset)
253
if(p1->offset<p2->offset)
259
int Splitparts_sort(struct SplitparT *o, int count, int flag)
261
qsort(o, (size_t) count, sizeof(struct SplitparT), Splitparts_cmp);
266
/* ---------------------------- End SplitparT ------------------------- */
269
/* ------------------------------ DirseQ ------------------------------ */
272
static int Dirseq_buffer_sizE= 100;
286
int Dirseq_destroy(struct DirseQ **o, int flag);
287
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
288
int max_replies, int flag);
291
int Dirseq_new(struct DirseQ **o, char *adr, int flag)
293
bit0= with non-fatal errors do not complain about failed opendir()
296
int ret,i,severe_error;
299
m= *o= TSOB_FELD(struct DirseQ,1);
310
if(Sfile_str(m->adr, adr, 0)<=0)
311
{ret= 0; goto failed;}
312
m->buffer= TSOB_FELD(char *,Dirseq_buffer_sizE);
314
{ret= -1; goto failed;}
315
m->buffer_size= Dirseq_buffer_sizE;
316
for(i= 0;i<m->buffer_size;i++)
319
m->dirpt= opendir(".");
321
m->dirpt= opendir(adr);
323
severe_error= (errno && errno!=ENOENT && errno!=EACCES && errno!=ENOTDIR);
324
if(severe_error || !(flag&1))
325
fprintf(stderr,"opendir(%s) failed : %s\n",adr,strerror(errno));
336
int Dirseq_destroy(struct DirseQ **o, int flag)
342
if((*o)->dirpt!=NULL)
343
closedir((*o)->dirpt);
344
if((*o)->buffer!=NULL) {
345
for(i=0;i<(*o)->buffer_size;i++)
346
if((*o)->buffer[i]!=NULL)
347
free((*o)->buffer[i]);
348
free((char *) (*o)->buffer);
356
int Dirseq_set_next(struct DirseQ *o, struct DirseQ *next, int flag)
363
int Dirseq_get_next(struct DirseQ *o, struct DirseQ **next, int flag)
370
int Dirseq_get_adr(struct DirseQ *o, char **adrpt, int flag)
377
int Dirseq_rewind(struct DirseQ *o, int flag)
384
int Dirseq_next_adr(struct DirseQ *o, char reply[SfileadrL], int flag)
387
bit0= permission to use buffer
388
bit1= do not increment counter
389
bit2= ignore buffer in any case
390
bit3= do not exclude '.' and '..'
392
bit5= sort only incomplete last buffer
395
0= no more entries available
396
1= ok, reply is valid
400
struct dirent *entry;
403
static int override_flag_0= 0,override_flag_1= 32;
404
flag= (flag&~override_flag_0)|override_flag_1;
406
if((flag&1) && o->buffer_rpt>=o->buffer_fill) {
407
/* permission to buffer and buffer empty : load a buffer */
408
ret= Dirseq_next_adrblock(o,o->buffer,&(o->buffer_fill),
409
o->buffer_size,2|4|(flag&16));
413
if((flag&32) && o->buffer_fill<o->buffer_size && o->buffer_fill>0)
414
Sort_argv(o->buffer_fill,o->buffer,0);
416
if(o->buffer_rpt<o->buffer_fill && !(flag&4)) {
417
ret= Sfile_str(reply,o->buffer[o->buffer_rpt],0);
418
Sregex_string(&(o->buffer[o->buffer_rpt]),NULL,0);
427
entry= readdir(o->dirpt);
429
/* >>> how to distinguish error from EOF , do i need a (FILE *) ? */
432
if(strlen(entry->d_name)>=SfileadrL) {
433
fprintf(stderr,"--- oversized directory entry (number %d) :\n %s",
434
o->count+1,entry->d_name);
440
/* skip "." and ".." */
441
} while(name[0]=='.' && ((name[1]=='.' && name[2]==0) || name[1]==0));
442
if(Sfile_str(reply,name,0)<=0)
450
int Dirseq_next_adrblock(struct DirseQ *o, char *replies[], int *reply_count,
451
int max_replies, int flag)
452
/* @param replies A vector of Sregex_string pointers */
455
bit0= permission to use buffer
456
bit1= do not increment counter
457
bit2= ignore buffer in any case
461
0= no more entries available
462
1= ok, reply is valid
466
char reply[SfileadrL];
469
for(i=0;i<max_replies;i++) {
470
ret= Dirseq_next_adr(o,reply,flag&(1|2|4));
475
if(Sregex_string(&(replies[i]),reply,0)<=0)
479
if((*reply_count)==0)
482
Sort_argv(*reply_count,replies,0);
487
/* ---------------------------- End DirseQ ----------------------------- */
490
/* ---------------------------- Xorriso_lsT ----------------------------- */
494
@param flag Bitfield for control purposes
495
bit0= insert before link rather than after it
496
bit1= do not copy data (e.g. because *data is invalid)
497
bit2= attach data directly by pointer rather than by copying
499
int Xorriso_lst_new_binary(struct Xorriso_lsT **lstring, char *data,
500
int data_len, struct Xorriso_lsT *link, int flag)
503
struct Xorriso_lsT *s;
505
s= TSOB_FELD(struct Xorriso_lsT,1);
509
s->next= s->prev= NULL;
515
{ret= -1; goto failed;}
516
s->text= Smem_malloC(data_len);
518
{ret= -1; goto failed;}
520
memcpy(s->text,data,data_len);
542
Xorriso_lst_destroy(lstring,0);
548
@param flag Bitfield for control purposes
549
see Xorriso_lst_new_binary()
551
int Xorriso_lst_new(struct Xorriso_lsT **lstring, char *text,
552
struct Xorriso_lsT *link, int flag)
556
ret= Xorriso_lst_new_binary(lstring,text,strlen(text)+1,link,flag);
562
@param flag Bitfield for control purposes
563
bit0= do not set *lstring to NULL
565
int Xorriso_lst_destroy(struct Xorriso_lsT **lstring, int flag)
567
struct Xorriso_lsT *s;
573
s->prev->next= s->next;
575
s->next->prev= s->prev;
578
Smem_freE((char *) s);
585
int Xorriso_lst_destroy_all(struct Xorriso_lsT **lstring, int flag)
587
struct Xorriso_lsT *s,*next;
593
for(s= *lstring; s->prev!=NULL; s= s->prev);
594
for(;s!=NULL;s= next){
596
Xorriso_lst_destroy(&s,0);
603
int Xorriso_lst_append_binary(struct Xorriso_lsT **entry,
604
char *data, int data_len, int flag)
606
struct Xorriso_lsT *target= NULL,*newby;
609
for(target= *entry; target->next!=NULL; target= target->next);
610
if(Xorriso_lst_new_binary(&newby, data, data_len, target, flag & ~1)<=0)
612
if(*entry==NULL || (flag & 1))
618
struct Xorriso_lsT *Xorriso_lst_get_next(struct Xorriso_lsT *entry, int flag)
624
struct Xorriso_lsT *Xorriso_lst_get_prev(struct Xorriso_lsT *entry, int flag)
630
char *Xorriso_lst_get_text(struct Xorriso_lsT *entry, int flag)
636
int Xorriso_lst_detach_text(struct Xorriso_lsT *entry, int flag)
643
int Xorriso_lst_get_last(struct Xorriso_lsT *entry, struct Xorriso_lsT **last,
648
for((*last)= entry; (*last)->next != NULL; (*last)= (*last)->next);
653
/* --------------------------- End Xorriso_lsT ---------------------------- */
656
/* ------------------------------ ExclusionS ------------------------------ */
661
/* Absolute input patterns which lead to not_paths */
662
struct Xorriso_lsT *not_paths_descr;
664
/* Actually banned absolute paths */
665
struct Xorriso_lsT *not_paths;
667
/* Input patterns which lead to not_leafs */
668
struct Xorriso_lsT *not_leafs_descr;
670
/* Compiled not_leaf patterns. Caution: not char[] but regex_t */
671
struct Xorriso_lsT *not_leafs;
676
int Exclusions_new(struct ExclusionS **o, int flag)
678
struct ExclusionS *m;
680
m= *o= TSOB_FELD(struct ExclusionS, 1);
683
m->not_paths_descr= NULL;
685
m->not_leafs_descr= NULL;
691
int Exclusions_destroy(struct ExclusionS **o, int flag)
693
struct Xorriso_lsT *s,*next;
697
Xorriso_lst_destroy_all(&((*o)->not_paths_descr), 0);
698
Xorriso_lst_destroy_all(&((*o)->not_paths), 0);
699
Xorriso_lst_destroy_all(&((*o)->not_leafs_descr), 0);
700
for(s= (*o)->not_leafs; s!=NULL; s= next){
702
regfree((regex_t *) s->text);
703
Xorriso_lst_destroy(&s, 0);
711
int Exclusions_add_not_paths(struct ExclusionS *o, int descrc, char **descrs,
712
int pathc, char **paths, int flag)
714
struct Xorriso_lsT *s, *new_s;
718
if(o->not_paths_descr!=NULL)
719
for(s= o->not_paths_descr; s->next!=NULL; s= s->next);
720
for(i= 0; i<descrc; i++) {
721
ret= Xorriso_lst_new(&new_s, descrs[i], s, 0);
724
if(o->not_paths_descr==NULL)
725
o->not_paths_descr= new_s;
729
if(o->not_paths!=NULL)
730
for(s= o->not_paths; s->next!=NULL; s= s->next);
731
for(i= 0; i<pathc; i++) {
732
ret= Xorriso_lst_new(&new_s, paths[i], s, 0);
735
if(o->not_paths==NULL)
743
/* @return -1=cannot store , 0=cannot compile regex , 1=ok
745
int Exclusions_add_not_leafs(struct ExclusionS *o, char *not_leafs_descr,
746
regex_t *re, int flag)
750
ret= Xorriso_lst_append_binary(&(o->not_leafs_descr),
751
not_leafs_descr, strlen(not_leafs_descr)+1, 0);
754
ret= Xorriso_lst_append_binary(&(o->not_leafs), (char *) re, sizeof(regex_t), 0);
761
/* @param flag bit0= whole subtree is banned with -not_paths
762
@return 0=no match , 1=not_paths , 2=not_leafs, <0=error
764
int Exclusions_match(struct ExclusionS *o, char *abs_path, int flag)
766
struct Xorriso_lsT *s;
767
char leaf[SfileadrL], *leaf_pt;
769
int ret, was_non_slash, l;
773
for(s= o->not_paths; s!=NULL; s= s->next) {
775
if(strncmp(abs_path, s->text, l)==0)
776
if(abs_path[l]=='/' || abs_path[l]==0)
780
for(s= o->not_paths; s!=NULL; s= s->next)
781
if(strcmp(abs_path, s->text)==0)
785
/* determine leafname */
787
for(leaf_pt= abs_path+strlen(abs_path); leaf_pt >= abs_path; leaf_pt--) {
793
} else if(*leaf_pt!=0)
796
if(strlen(leaf_pt)>=SfileadrL)
798
strcpy(leaf, leaf_pt);
799
leaf_pt= strchr(leaf, '/');
803
/* test with leaf expressions */
804
for(s= o->not_leafs; s!=NULL; s= s->next) {
805
ret= regexec((regex_t *) s->text, leaf, 1, match, 0);
813
int Exclusions_get_descrs(struct ExclusionS *o,
814
struct Xorriso_lsT **not_paths_descr,
815
struct Xorriso_lsT **not_leafs_descr, int flag)
817
*not_paths_descr= o->not_paths_descr;
818
*not_leafs_descr= o->not_leafs_descr;
822
/* ---------------------------- End ExclusionS ---------------------------- */
825
/* ------------------------------ LinkiteM -------------------------------- */
832
struct LinkiteM *next;
836
int Linkitem_new(struct LinkiteM **o, char *link_path, dev_t target_dev,
837
ino_t target_ino, struct LinkiteM *next, int flag)
841
m= *o= TSOB_FELD(struct LinkiteM,1);
844
m->target_dev= target_dev;
845
m->target_ino= target_ino;
849
m->link_count= m->next->link_count+1;
850
m->link_path= strdup(link_path);
851
if(m->link_path==NULL)
855
Linkitem_destroy(o, 0);
860
int Linkitem_destroy(struct LinkiteM **o, int flag)
864
if((*o)->link_path!=NULL)
865
free((*o)->link_path);
872
int Linkitem_reset_stack(struct LinkiteM **o, struct LinkiteM *to, int flag)
874
struct LinkiteM *m, *m_next= NULL;
876
/* Prevent memory corruption */
877
for(m= *o; m!=to; m= m->next)
878
if(m==NULL) { /* this may actually not happen */
883
for(m= *o; m!=to; m= m_next) {
885
Linkitem_destroy(&m, 0);
892
int Linkitem_find(struct LinkiteM *stack, dev_t target_dev, ino_t target_ino,
893
struct LinkiteM **result, int flag)
897
for(m= stack; m!=NULL; m= m->next) {
898
if(target_dev == m->target_dev && target_ino == m->target_ino) {
907
int Linkitem_get_link_count(struct LinkiteM *item, int flag)
909
return(item->link_count);
913
/* ------------------------------ PermstacK ------------------------------- */
919
struct PermiteM *next;
923
int Permstack_push(struct PermiteM **o, char *disk_path, struct stat *stbuf,
928
m= TSOB_FELD(struct PermiteM,1);
932
memcpy(&(m->stbuf), stbuf, sizeof(struct stat));
935
m->disk_path= strdup(disk_path);
936
if(m->disk_path==NULL)
942
if(m->disk_path!=NULL)
949
/* @param flag bit0= minimal transfer: access permissions only
950
bit1= do not set timestamps
952
int Permstack_pop(struct PermiteM **o, struct PermiteM *stopper,
953
struct XorrisO *xorriso, int flag)
956
char sfe[5*SfileadrL];
957
struct utimbuf utime_buffer;
958
struct PermiteM *m, *m_next;
962
for(m= *o; m!=NULL; m= m->next)
966
sprintf(xorriso->info_text,
967
"Program error: Permstack_pop() : cannot find stopper");
968
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, 0, "FATAL", 0);
972
for(m= *o; m!=stopper; m= m_next) {
973
ret= chmod(m->disk_path, m->stbuf.st_mode);
976
sprintf(xorriso->info_text,
977
"Cannot change access permissions of disk directory: chmod %o %s",
978
(unsigned int) (m->stbuf.st_mode & 07777),
979
Text_shellsafe(m->disk_path, sfe, 0));
980
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",
985
ret= chown(m->disk_path, m->stbuf.st_uid, m->stbuf.st_gid);
986
/* don't complain if it fails */
988
utime_buffer.actime= m->stbuf.st_atime;
989
utime_buffer.modtime= m->stbuf.st_mtime;
990
ret= utime(m->disk_path,&utime_buffer);
991
if(ret==-1 && xorriso!=NULL) {
992
sprintf(xorriso->info_text,
993
"Cannot change timestamps of disk directory: %s",
994
Text_shellsafe(m->disk_path, sfe, 0));
995
Xorriso_msgs_submit(xorriso, 0, xorriso->info_text, errno, "FAILURE",
1009
/* ---------------------------- End PermstacK ----------------------------- */