diff -ruN misc/ctm.OLD/files/patch-r01-fix_warnings_in_mkCTM_mkctm.c misc/ctm/files/patch-r01-fix_warnings_in_mkCTM_mkctm.c --- misc/ctm.OLD/files/patch-r01-fix_warnings_in_mkCTM_mkctm.c 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r01-fix_warnings_in_mkCTM_mkctm.c 2023-12-29 09:49:35.963059000 +0100 @@ -0,0 +1,20 @@ +--- mkCTM/mkctm.c.ORI 2023-12-24 08:11:59.287756000 +0100 ++++ mkCTM/mkctm.c 2023-12-24 08:14:49.514747000 +0100 +@@ -113,7 +113,7 @@ + } + + int +-dirselect(struct dirent *de) ++dirselect(const struct dirent *de) + { + if (!strcmp(de->d_name, ".")) return 0; + if (!strcmp(de->d_name, "..")) return 0; +@@ -221,7 +221,7 @@ + + { + u_long l = s2.st_size + 2; +- u_char *cmd = alloca(strlen(buf1)+strlen(buf2)+100); ++ char *cmd = alloca(strlen(buf1)+strlen(buf2)+100); + u_char *ob = malloc(l), *p; + int j; + FILE *F; diff -ruN misc/ctm.OLD/files/patch-r02-fix_logf_name_clash_in_mkCTM_mkctm.c misc/ctm/files/patch-r02-fix_logf_name_clash_in_mkCTM_mkctm.c --- misc/ctm.OLD/files/patch-r02-fix_logf_name_clash_in_mkCTM_mkctm.c 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r02-fix_logf_name_clash_in_mkCTM_mkctm.c 2023-12-29 09:49:35.963595000 +0100 @@ -0,0 +1,120 @@ +--- mkCTM/mkctm.c.ORI 2023-12-24 08:03:42.335824000 +0100 ++++ mkCTM/mkctm.c 2023-12-24 08:04:21.959999000 +0100 +@@ -42,7 +42,7 @@ + int damage, damage_limit; + int change; + +-FILE *logf; ++FILE *logfile; + + u_long s1_ignored, s2_ignored; + u_long s1_bogus, s2_bogus; +@@ -134,7 +134,7 @@ + printf("%s %s%s %u %u %o", + pfx, name, de->d_name, + st->st_uid, st->st_gid, st->st_mode & ~S_IFMT); +- fprintf(logf, "%s %s%s\n", pfx, name, de->d_name); ++ fprintf(logfile, "%s %s%s\n", pfx, name, de->d_name); + if (verbose > 1) { + fprintf(stderr, "%s %s%s\n", pfx, name, de->d_name); + } +@@ -362,7 +362,7 @@ + strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); + DoDir(dir1, dir2, p); + printf("CTMDR %s%s\n", name, de->d_name); +- fprintf(logf, "CTMDR %s%s\n", name, de->d_name); ++ fprintf(logfile, "CTMDR %s%s\n", name, de->d_name); + if (verbose > 1) { + fprintf(stderr, "CTMDR %s%s\n", name, de->d_name); + } +@@ -376,7 +376,7 @@ + strcat(buf1, "/"); strcat(buf1, de->d_name); + m1 = MD5File(buf1, md5_1); + printf("CTMFR %s%s %s\n", name, de->d_name, m1); +- fprintf(logf, "CTMFR %s%s %s\n", name, de->d_name, m1); ++ fprintf(logfile, "CTMFR %s%s %s\n", name, de->d_name, m1); + if (verbose > 1) { + fprintf(stderr, "CTMFR %s%s\n", name, de->d_name); + } +@@ -403,14 +403,14 @@ + if (flag_ignore && + !regexec(®_ignore, buf1, 0, 0, 0)) { + (*ignored)++; +- fprintf(logf, "Ignore %s\n", buf1); ++ fprintf(logfile, "Ignore %s\n", buf1); + if (verbose > 2) { + fprintf(stderr, "Ignore %s\n", buf1); + } + } else if (flag_bogus && + !regexec(®_bogus, buf1, 0, 0, 0)) { + (*bogus)++; +- fprintf(logf, "Bogus %s\n", buf1); ++ fprintf(logfile, "Bogus %s\n", buf1); + fprintf(stderr, "Bogus %s\n", buf1); + damage++; + } else { +@@ -524,8 +524,8 @@ + strcpy(tmpfilename, tmpdir); strcat(tmpfilename, tmpfilebase); + mktemp(tmpfilename); + +- snprintf(command,command_size,"tar -C %s -cvf %s %s 2>&%d\n",dir2,tmpfilename,de->d_name,fileno(logf)); +- fflush(logf); ++ snprintf(command,command_size,"tar -C %s -cvf %s %s 2>&%d\n",dir2,tmpfilename,de->d_name,fileno(logfile)); ++ fflush(logfile); + ret_val = system(command); + if (ret_val!=0) errx(1,"The command \"%s\" failed with return value %d",command,ret_val); + printf("CTMTR "); +@@ -576,8 +576,8 @@ + errx(1,"No db/release in %s",buf2); + + if (release2 > release1) { +- snprintf(command,command_size,"svnadmin dump %s/%s -r %ld:%ld --incremental --deltas 2>&%d > %s\n",dir2,de->d_name,release1+1,release2,fileno(logf),tmpfilename); +- fflush(logf); ++ snprintf(command,command_size,"svnadmin dump %s/%s -r %ld:%ld --incremental --deltas 2>&%d > %s\n",dir2,de->d_name,release1+1,release2,fileno(logfile),tmpfilename); ++ fflush(logfile); + ret_val = system(command); + if (ret_val!=0) errx(1,"The command \"%s\" failed with return value %d",command,ret_val); + printf("CTMSV %s %ld ", de->d_name, release1); +@@ -723,10 +723,10 @@ + flag_bogus = 1; + break; + case 'l': +- logf = fopen(optarg, "w"); +- if (!logf) ++ logfile = fopen(optarg, "w"); ++ if (!logfile) + err(1, "%s", optarg); +- setlinebuf(logf); ++ setlinebuf(logfile); + break; + case 'q': + verbose--; +@@ -742,8 +742,8 @@ + argc -= optind; + argv += optind; + +- if (!logf) +- logf = fopen(_PATH_DEVNULL, "w"); ++ if (!logfile) ++ logfile = fopen(_PATH_DEVNULL, "w"); + + setbuf(stdout, 0); + +@@ -756,7 +756,7 @@ + + fprintf(stderr, "CTM_BEGIN 2.0 %s %s %s %s\n", + argv[0], argv[1], argv[2], argv[3]); +- fprintf(logf, "CTM_BEGIN 2.0 %s %s %s %s\n", ++ fprintf(logfile, "CTM_BEGIN 2.0 %s %s %s %s\n", + argv[0], argv[1], argv[2], argv[3]); + printf("CTM_BEGIN 2.0 %s %s %s %s\n", + argv[0], argv[1], argv[2], argv[3]); +@@ -773,7 +773,7 @@ + errx(4, "no changes"); + } else { + printf("CTM_END "); +- fprintf(logf, "CTM_END\n"); ++ fprintf(logfile, "CTM_END\n"); + if (strncmp(argv[0],"svn",3) != 0) + print_stat(stderr, "END: "); + } diff -ruN misc/ctm.OLD/files/patch-r03-fix_recreating_failure_in_ctm_ctm__pass2.c misc/ctm/files/patch-r03-fix_recreating_failure_in_ctm_ctm__pass2.c --- misc/ctm.OLD/files/patch-r03-fix_recreating_failure_in_ctm_ctm__pass2.c 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r03-fix_recreating_failure_in_ctm_ctm__pass2.c 2023-12-29 09:49:35.964007000 +0100 @@ -0,0 +1,35 @@ +--- ctm/ctm_pass2.c.ORI 2023-12-29 08:41:10.082775000 +0100 ++++ ctm/ctm_pass2.c 2023-12-29 08:43:18.156987000 +0100 +@@ -15,6 +15,8 @@ + #include "ctm.h" + #define BADREAD 32 + ++char LastRemoved[ PATH_MAX + 1 ] = ""; ++ + /*---------------------------------------------------------------------------*/ + /* Pass2 -- Validate the incoming CTM-file. + */ +@@ -86,6 +88,11 @@ + switch (j & CTM_F_MASK) { + case CTM_F_Name: + GETNAMECOPY(name,sep,j,0); ++ ++ /* If we remove anything, record its name */ ++ if( strcmp(sp->Key,"FR") == 0 || strcmp(sp->Key,"DR") == 0 || strcmp(sp->Key,"LR") == 0 ) ++ strncpy( LastRemoved, name, sizeof LastRemoved -1 ); ++ + /* If `keep' was specified, we won't remove any files, + so don't check if the file exists */ + if (KeepIt && +@@ -104,6 +111,11 @@ + + /* XXX Check DR DM rec's for parent-dir */ + if(j & CTM_Q_Name_New) { ++ ++ /* Don't check for existence of the new item if it had ++ been removed just before. */ ++ if( strcmp( LastRemoved, name ) != 0 ) ++ + /* XXX Check DR FR rec's for item */ + if(-1 != stat(name,&st)) { + fprintf(stderr," %s: %s exists.\n", diff -ruN misc/ctm.OLD/files/patch-r04-fix_ignoring_to_few_changes_in_mkCTM_mkctm.c misc/ctm/files/patch-r04-fix_ignoring_to_few_changes_in_mkCTM_mkctm.c --- misc/ctm.OLD/files/patch-r04-fix_ignoring_to_few_changes_in_mkCTM_mkctm.c 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r04-fix_ignoring_to_few_changes_in_mkCTM_mkctm.c 2023-12-29 09:49:35.964561000 +0100 @@ -0,0 +1,38 @@ +--- mkCTM/mkctm.c.ORI 2023-12-29 08:47:22.656993000 +0100 ++++ mkCTM/mkctm.c 2023-12-29 08:48:29.101390000 +0100 +@@ -32,6 +32,7 @@ + #include + #include + #include ++#include + + #define DEFAULT_IGNORE "/CVS$|/\\.#|00_TRANS\\.TBL$" + #define DEFAULT_BOGUS "\\.core$|\\.orig$|\\.rej$|\\.o$" +@@ -41,6 +42,7 @@ + int verbose; + int damage, damage_limit; + int change; ++int Have_ctm_status, Have_svn_revision; + + FILE *logfile; + +@@ -138,6 +140,10 @@ + if (verbose > 1) { + fprintf(stderr, "%s %s%s\n", pfx, name, de->d_name); + } ++ if( strcmp( de->d_name, ".ctm_status" ) == 0 ) ++ Have_ctm_status = 1; ++ if( strcmp( de->d_name, ".svn_revision" ) == 0 ) ++ Have_svn_revision = 1; + } + + void +@@ -769,7 +839,7 @@ + errx(1, "damage of %d would exceed %d files", + damage, damage_limit); + /* change <= 2 means no change because of .ctm_status and .svn_revision */ +- } else if (change < 3) { ++ } else if (change < 1 + Have_ctm_status + Have_svn_revision ) { + errx(4, "no changes"); + } else { + printf("CTM_END "); diff -ruN misc/ctm.OLD/files/patch-r10-add_symlink_handling_to_mkCTM_mkctm.c misc/ctm/files/patch-r10-add_symlink_handling_to_mkCTM_mkctm.c --- misc/ctm.OLD/files/patch-r10-add_symlink_handling_to_mkCTM_mkctm.c 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r10-add_symlink_handling_to_mkCTM_mkctm.c 2023-12-29 09:49:35.965207000 +0100 @@ -0,0 +1,94 @@ +--- mkCTM/mkctm.c.ORI 2023-12-29 09:07:16.210417000 +0100 ++++ mkCTM/mkctm.c 2023-12-29 09:07:16.211918000 +0100 +@@ -155,6 +155,39 @@ + strcpy(p, name); strcat(p, de->d_name); strcat(p, "/"); + DoDir(dir1, dir2, p); + s_same_dirs++; ++ ++ } else if( de->d_type == DT_LNK ) { ++ ++ char lbuf1[ PATH_MAX ]; ++ char lbuf2[ PATH_MAX ]; ++ char* buf1; ++ char* buf2; ++ ssize_t ret1, ret2; ++ ++ if( asprintf( &buf1, "%s/%s/%s", dir1, name, de->d_name ) <= 0 ) ++ err( 3, "asprintf: %s", dir2 ); ++ if( asprintf( &buf2, "%s/%s/%s", dir2, name, de->d_name ) <= 0 ) ++ err( 3, "asprintf: %s", dir2 ); ++ ++ if( (ret1 = readlink( buf1, lbuf1, sizeof lbuf1 - 1 )) == -1 ) ++ err( 3, "readlink: %s", buf1 ); ++ lbuf1[ ret1 ] = '\0'; ++ if( (ret2 = readlink( buf2, lbuf2, sizeof lbuf2 - 1 )) == -1 ) ++ err( 3, "readlink: %s", buf2 ); ++ lbuf2[ ret2 ] = '\0'; ++ ++ if( strcmp( lbuf1, lbuf2 ) == 0 ) ++ return; ++ ++ change++; ++ ++ printf( "CTMLR %s%s\n", name, de->d_name ); ++ name_stat("CTMLM", dir2, name, de); ++ printf( " %s\n", lbuf2 ); ++ ++ free( buf1 ); ++ free( buf2 ); ++ + } else { + char *buf1 = alloca(strlen(dir1) + strlen(name) + + strlen(de->d_name) + 3); +@@ -326,6 +359,25 @@ + putchar('\n'); + s_new_dirs++; + DoDir(dir1, dir2, p); ++ ++ } else if( de->d_type == DT_LNK ) { ++ ++ char* buf2; ++ char lbuf[ PATH_MAX ]; ++ ssize_t ret; ++ ++ if( asprintf( &buf2, "%s/%s/%s", dir2, name, de->d_name ) <= 0 ) ++ err( 3, "asprintf: %s", dir2 ); ++ ++ if( (ret = readlink( buf2, lbuf, sizeof lbuf - 1 )) == -1 ) ++ err( 3, "readlink: %s", buf2 ); ++ lbuf[ ret ] = '\0'; ++ ++ name_stat( "CTMLM", dir2, name, de ); ++ printf( " %s\n", lbuf ); ++ ++ free( buf2 ); ++ + } else if (de->d_type == DT_REG) { + char *buf2 = alloca(strlen(dir2) + strlen(name) + + strlen(de->d_name) + 3); +@@ -373,6 +425,14 @@ + fprintf(stderr, "CTMDR %s%s\n", name, de->d_name); + } + s_del_dirs++; ++ ++ } else if( de->d_type == DT_LNK ) { ++ ++ printf( "CTMLR %s%s\n", name, de->d_name ); ++ fprintf( logfile, "CTMLR %s%s\n", name, de->d_name ); ++ if( verbose > 1 ) ++ fprintf( stderr, "CTMLR %s%s\n", name, de->d_name ); ++ + } else if (de->d_type == DT_REG) { + char *buf1 = alloca(strlen(dir1) + strlen(name) + + strlen(de->d_name) + 3); +@@ -436,6 +496,10 @@ + nl[*i]->d_type = IFTODT(StatFile(buf)->st_mode); + if (nl[*i]->d_type == DT_REG || nl[*i]->d_type == DT_DIR) + break; ++ ++ if( nl[*i]->d_type == DT_LNK ) ++ break; ++ + (*wrong)++; + if (verbose > 0) + fprintf(stderr, "Wrong %s\n", buf); diff -ruN misc/ctm.OLD/files/patch-r11-add_symlink_handling_to_ctm misc/ctm/files/patch-r11-add_symlink_handling_to_ctm --- misc/ctm.OLD/files/patch-r11-add_symlink_handling_to_ctm 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r11-add_symlink_handling_to_ctm 2023-12-29 09:49:35.965830000 +0100 @@ -0,0 +1,286 @@ +--- ctm/ctm.h.ORI 2023-12-29 08:53:14.808809000 +0100 ++++ ctm/ctm.h 2023-12-29 08:53:14.827122000 +0100 +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + + #define VERSION "2.0" + +@@ -43,6 +44,7 @@ + #define CTM_F_Bytes 0x07 + #define CTM_F_Release 0x08 + #define CTM_F_Forward 0x09 ++#define CTM_F_Targetname 0x0a + + /* The qualifiers... */ + #define CTM_Q_MASK 0xff00 +@@ -51,6 +53,7 @@ + #define CTM_Q_Name_New 0x0400 + #define CTM_Q_Name_Subst 0x0800 + #define CTM_Q_Name_Svnbase 0x1000 ++#define CTM_Q_Name_Link 0x2000 + #define CTM_Q_MD5_After 0x0100 + #define CTM_Q_MD5_Before 0x0200 + #define CTM_Q_MD5_Chunk 0x0400 +--- ctm/ctm_syntax.c.ORI 2023-12-29 08:53:14.816487000 +0100 ++++ ctm/ctm_syntax.c 2023-12-29 08:59:53.103142000 +0100 +@@ -68,6 +68,13 @@ + static int ctmSV[] = /* Forward to svnadmin load */ + { Name|Dir|Svnbase, Release, Count, Forward|SVN, 0 }; + ++static int ctmLM[] = /* Link Make */ ++ { Name|CTM_Q_Name_Link|New, Uid, Gid, Mode, CTM_F_Targetname, 0 }; ++ ++static int ctmLR[] = /* Link Remove */ ++ { Name|CTM_Q_Name_Link, 0 }; ++ ++ + struct CTM_Syntax Syntax[] = { + { "FM", ctmFM }, + { "FS", ctmFS }, +@@ -79,4 +86,6 @@ + { "DR", ctmDR }, + { "TR", ctmTR }, + { "SV", ctmSV }, ++ { "LM", ctmLM }, ++ { "LR", ctmLR }, + { 0, 0} }; +--- ctm/ctm_pass1.c.ORI 2023-12-29 08:53:14.811803000 +0100 ++++ ctm/ctm_pass1.c 2023-12-29 08:53:14.827382000 +0100 +@@ -27,6 +27,7 @@ + int i,j,sep; + intmax_t cnt, rel; + u_char *md5=0,*name=0,*trash=0; ++ u_char* targetname = NULL; + struct CTM_Syntax *sp; + int slashwarn=0, match=0, total_matches=0; + unsigned current; +@@ -71,6 +72,7 @@ + Delete(md5); + Delete(name); + Delete(trash); ++ Delete( targetname ); + cnt = -1; + /* if a filter list is defined we assume that all pathnames require + an action opposite to that requested by the first filter in the +@@ -224,6 +226,9 @@ + return Exit_Garbage; + } + GETFORWARD(cnt,NULL); ++ break; ++ case CTM_F_Targetname: ++ GETFIELDCOPY( targetname, sep ); + break; + default: + fprintf(stderr,"List = 0x%x\n",j); +--- ctm/ctm_pass2.c.ORI 2023-12-29 08:53:14.823718000 +0100 ++++ ctm/ctm_pass2.c 2023-12-29 08:53:14.827299000 +0100 +@@ -117,14 +117,14 @@ + if( strcmp( LastRemoved, name ) != 0 ) + + /* XXX Check DR FR rec's for item */ +- if(-1 != stat(name,&st)) { ++ if(-1 != lstat(name,&st)) { + fprintf(stderr," %s: %s exists.\n", + sp->Key,name); + ret |= Exit_Forcible; + } + break; + } +- if(-1 == stat(name,&st)) { ++ if(-1 == lstat(name,&st)) { + fprintf(stderr," %s: %s doesn't exist.\n", + sp->Key,name); + if (sp->Key[1] == 'R') +@@ -173,10 +173,18 @@ + } + break; + } ++ if( j & CTM_Q_Name_Link ) { ++ if( ( st.st_mode & S_IFMT ) != S_IFLNK ) { ++ fprintf( stderr, " %s: %s exist, but isn't link.\n", sp->Key,name ); ++ ret |= Exit_NotOK; ++ } ++ break; ++ } + break; + case CTM_F_Uid: + case CTM_F_Gid: + case CTM_F_Mode: ++ case CTM_F_Targetname: + GETFIELD(p,sep); + break; + case CTM_F_MD5: +--- ctm/ctm_pass3.c.ORI 2023-12-29 08:53:14.814984000 +0100 ++++ ctm/ctm_pass3.c 2023-12-29 08:59:08.227903000 +0100 +@@ -23,7 +23,7 @@ + settime(const char *name, const struct timeval *times) + { + if (SetTime) +- if (utimes(name,times)) { ++ if (lutimes(name,times)) { + warn("utimes(): %s", name); + return -1; + } +@@ -33,7 +33,7 @@ + int + setmodefromchar(const char *name, const u_char *mode) + { +- return chmod(name, strtol(mode, NULL, 8)); ++ return lchmod(name, strtol(mode, NULL, 8)); + } + + int +@@ -45,6 +45,7 @@ + intmax_t cnt,rel; + char *svn_command = NULL; + u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0; ++ u_char* targetname = NULL; + struct CTM_Syntax *sp; + FILE *ed=0, *fd_to; + struct stat st; +@@ -124,6 +125,7 @@ + Delete(md5before); + Delete(trash); + Delete(name); ++ Delete( targetname ); + cnt = -1; + + GETFIELD(p,' '); +@@ -198,6 +200,10 @@ + } + } + break; ++ case CTM_F_Targetname: ++ //GETNAMECOPY( targetname, sep, j, Verbose ); ++ GETFIELDCOPY( targetname, sep ); ++ break; + default: WRONG + } + } +@@ -337,6 +343,70 @@ + } + if(!strcmp(sp->Key,"TR") || !strcmp(sp->Key,"SV")) + continue; ++ ++ ++ if( strcmp( sp->Key, "LR" ) == 0 ) { ++ ++ if( KeepIt ) { ++ if( Verbose > 1 ) ++ printf( " <%s> not removed\n", name ); ++ ++ } else { ++ if( unlink( name )) { ++ fprintf( stderr, "unlink %s: %s\n", name, strerror( errno )); ++ WRONG ++ } ++ } ++ ++ continue; ++ } ++ ++ ++ if( strcmp( sp->Key, "LM" ) == 0 ) { ++ ++ char* bn; // basename ++ char cwd[ PATH_MAX ]; ++ ++ if( getcwd( cwd, sizeof cwd ) == NULL ) { ++ fprintf( stderr, "getcwd: %s\n", strerror( errno ) ); ++ WRONG ++ } ++ ++ if( (bn = strrchr( name, '/' )) == NULL ) // no path component ++ bn = name; // basename ++ ++ else { // have path component ++ *bn++ = '\0'; // terminate path component ++ if( chdir( name )) { ++ fprintf( stderr, "chdir %s: %s\n", name, strerror( errno )); ++ WRONG ++ } ++ } ++ ++ if( symlink( targetname, bn )) { ++ fprintf( stderr, "symlink %s to %s: %s\n", targetname, bn, strerror( errno )); ++ WRONG ++ } ++ ++ if( chdir( cwd )) { // go back ++ fprintf( stderr, "chdir %s: %s\n", cwd, strerror( errno )); ++ WRONG ++ } ++ ++ *--bn = '/'; // restore name with path ++ if( lstat( name, &st )) { ++ fprintf( stderr, "stat %s: %s\n", name, strerror( errno )); ++ WRONG ++ } else if( (st.st_mode & S_IFMT) != S_IFLNK ) { ++ fprintf( stderr, "%s: no link\n", name ); ++ WRONG ++ } ++ ++ if( settime( name, times )) WRONG ++ if( setmodefromchar( name, mode )) WRONG ++ continue; ++ } ++ + WRONG + } + +--- ctm/ctm_passb.c.ORI 2023-04-25 21:04:20.000000000 +0200 ++++ ctm/ctm_passb.c 2023-12-29 09:03:07.551061000 +0100 +@@ -26,6 +26,7 @@ + MD5_CTX ctx; + int i,j,sep,cnt; + u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0; ++ u_char* targetname = NULL; + struct CTM_Syntax *sp; + FILE *b = 0; /* backup command */ + u_char buf[BUFSIZ]; +@@ -57,6 +58,7 @@ + Delete(md5before); + Delete(trash); + Delete(name); ++ Delete( targetname ); + cnt = -1; + + GETFIELD(p,' '); +@@ -90,6 +92,7 @@ + break; + case CTM_F_Count: GETBYTECNT(cnt,sep); break; + case CTM_F_Bytes: GETDATA(trash,cnt); break; ++ case CTM_F_Targetname: GETFIELDCOPY( targetname, sep ); break; + default: WRONG + } + } +@@ -98,7 +101,7 @@ + if(name[j] == '/') name[j] = '\0'; + + if (KeepIt && +- (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) ++ (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"LR") || !strcmp(sp->Key,"FR"))) + continue; + + /* match the name against the elements of the filter list. The +@@ -113,7 +116,9 @@ + if (CTM_FILTER_DISABLE == match) + continue; + ++ // Do we have to backup symlinks??? + if (!strcmp(sp->Key,"FS") || !strcmp(sp->Key,"FN") || ++ !strcmp(sp->Key,"LR") || + !strcmp(sp->Key,"AS") || !strcmp(sp->Key,"DR") || + !strcmp(sp->Key,"FR")) { + /* send name to the archiver for a backup */ +@@ -135,6 +140,7 @@ + Delete(md5before); + Delete(trash); + Delete(name); ++ Delete( targetname ); + + q = MD5End (&ctx,md5_1); + GETFIELD(p,'\n'); /* */ diff -ruN misc/ctm.OLD/files/patch-r20-add_ownermail_to_ctm__smail_ctm__smail.c misc/ctm/files/patch-r20-add_ownermail_to_ctm__smail_ctm__smail.c --- misc/ctm.OLD/files/patch-r20-add_ownermail_to_ctm__smail_ctm__smail.c 1970-01-01 01:00:00.000000000 +0100 +++ misc/ctm/files/patch-r20-add_ownermail_to_ctm__smail_ctm__smail.c 2023-12-29 09:49:35.966569000 +0100 @@ -0,0 +1,156 @@ +--- ctm_smail/ctm_smail.c.ORI 2023-04-25 21:04:20.000000000 +0200 ++++ ctm_smail/ctm_smail.c 2019-07-29 03:53:20.090358000 +0200 +@@ -32,18 +32,18 @@ + #define LINE_LENGTH 72 /* Chars per encoded line. Divisible by 4. */ + + int chop_and_send_or_queue(FILE *dfp, char *delta, off_t ctm_size, +- long max_msg_size, char *mail_alias, char *queue_dir); ++ long max_msg_size, char *mail_alias, char *owner_alias, char *queue_dir); + int chop_and_send(FILE *dfp, char *delta, long msg_size, int npieces, +- char *mail_alias); ++ char *mail_alias, char *owner_alias); + int chop_and_queue(FILE *dfp, char *delta, long msg_size, int npieces, +- char *mail_alias, char *queue_dir); ++ char *mail_alias, char *owner_alias, char *queue_dir); + void clean_up_queue(char *queue_dir); + int encode_body(FILE *sm_fp, FILE *delta_fp, long msg_size, unsigned *sum); +-void write_header(FILE *sfp, char *mail_alias, char *delta, int pce, ++void write_header(FILE *sfp, char *mail_alias, char *owner_alias, char *delta, int pce, + int npieces); + void write_trailer(FILE *sfp, unsigned sum); + int apologise(char *delta, off_t ctm_size, long max_ctm_size, +- char *mail_alias, char *queue_dir); ++ char *mail_alias, char *owner_alias, char *queue_dir); + FILE *open_sendmail(void); + int close_sendmail(FILE *fp); + +@@ -53,6 +53,7 @@ + int status = 0; + char *delta_file; + char *mail_alias; ++ char *owner_alias = NULL; + long max_msg_size = DEF_MAX_MSG; + long max_ctm_size = 0; + char *log_file = NULL; +@@ -63,11 +64,12 @@ + + err_prog_name(argv[0]); + +- OPTIONS("[-l log] [-m maxmsgsize] [-c maxctmsize] [-q queuedir] ctm-delta mail-alias") ++ OPTIONS("[-l log] [-m maxmsgsize] [-c maxctmsize] [-q queuedir] [-o owner_alias] ctm-delta mail-alias") + NUMBER('m', max_msg_size) + NUMBER('c', max_ctm_size) + STRING('l', log_file) + STRING('q', queue_dir) ++ STRING('o', owner_alias) + ENDOPTS + + if (argc != 3) +@@ -91,11 +93,11 @@ + } + + if (max_ctm_size != 0 && sb.st_size > max_ctm_size) +- status = apologise(delta, sb.st_size, max_ctm_size, mail_alias, ++ status = apologise(delta, sb.st_size, max_ctm_size, mail_alias, owner_alias, + queue_dir); + else + status = chop_and_send_or_queue(dfp, delta, sb.st_size, max_msg_size, +- mail_alias, queue_dir); ++ mail_alias, owner_alias, queue_dir); + + fclose(dfp); + +@@ -109,7 +111,7 @@ + */ + int + chop_and_send_or_queue(FILE *dfp, char *delta, off_t ctm_size, +- long max_msg_size, char *mail_alias, char *queue_dir) ++ long max_msg_size, char *mail_alias, char *owner_alias, char *queue_dir) + { + int npieces; + long msg_size; +@@ -133,10 +135,10 @@ + #undef howmany + + if (queue_dir == NULL) +- status = chop_and_send(dfp, delta, msg_size, npieces, mail_alias); ++ status = chop_and_send(dfp, delta, msg_size, npieces, mail_alias, owner_alias); + else + { +- status = chop_and_queue(dfp, delta, msg_size, npieces, mail_alias, ++ status = chop_and_queue(dfp, delta, msg_size, npieces, mail_alias, owner_alias, + queue_dir); + if (status) + clean_up_queue(queue_dir); +@@ -152,7 +154,7 @@ + */ + int + chop_and_send(FILE *dfp, char *delta, long msg_size, int npieces, +- char *mail_alias) ++ char *mail_alias, char *owner_alias) + { + int pce; + FILE *sfp; +@@ -171,7 +173,7 @@ + if ((sfp = open_sendmail()) == NULL) + return 1; + +- write_header(sfp, mail_alias, delta, pce, npieces); ++ write_header(sfp, mail_alias, owner_alias, delta, pce, npieces); + read_error = encode_body(sfp, dfp, msg_size, &sum); + if (!read_error) + write_trailer(sfp, sum); +@@ -204,7 +206,7 @@ + */ + int + chop_and_queue(FILE *dfp, char *delta, long msg_size, int npieces, +- char *mail_alias, char *queue_dir) ++ char *mail_alias, char *owner_alias, char *queue_dir) + { + int pce; + FILE *qfp; +@@ -228,7 +230,7 @@ + return 1; + } + +- write_header(qfp, mail_alias, delta, pce, npieces); ++ write_header(qfp, mail_alias, owner_alias, delta, pce, npieces); + if (encode_body(qfp, dfp, msg_size, &sum)) + return 1; + write_trailer(qfp, sum); +@@ -381,9 +383,12 @@ + * Write the mail header and data header. + */ + void +-write_header(FILE *sfp, char *mail_alias, char *delta, int pce, int npieces) ++write_header(FILE *sfp, char *mail_alias, char *owner_alias, char *delta, int pce, int npieces) + { +- fprintf(sfp, "From: owner-%s\n", mail_alias); ++ if (owner_alias == NULL) ++ fprintf(sfp, "From: owner-%s\n", mail_alias); ++ else ++ fprintf(sfp, "From: %s\n", owner_alias); + fprintf(sfp, "To: %s\n", mail_alias); + fprintf(sfp, "Subject: ctm-mail %s %d/%d\n\n", delta, pce, npieces); + +@@ -406,7 +411,7 @@ + * Returns 0 on success, 1 on failure. + */ + int +-apologise(char *delta, off_t ctm_size, long max_ctm_size, char *mail_alias, ++apologise(char *delta, off_t ctm_size, long max_ctm_size, char *mail_alias, char *owner_alias, + char *queue_dir) + { + FILE *sfp; +@@ -430,7 +435,10 @@ + } + + +- fprintf(sfp, "From: owner-%s\n", mail_alias); ++ if (owner_alias == NULL) ++ fprintf(sfp, "From: owner-%s\n", mail_alias); ++ else ++ fprintf(sfp, "From: %s\n", owner_alias); + fprintf(sfp, "To: %s\n", mail_alias); + fprintf(sfp, "Subject: ctm-notice %s\n\n", delta); +