diff options
-rw-r--r-- | src/logic/linkcmd/slbt_linkcmd_deps.c | 266 |
1 files changed, 265 insertions, 1 deletions
diff --git a/src/logic/linkcmd/slbt_linkcmd_deps.c b/src/logic/linkcmd/slbt_linkcmd_deps.c index 7e72dee..46b989f 100644 --- a/src/logic/linkcmd/slbt_linkcmd_deps.c +++ b/src/logic/linkcmd/slbt_linkcmd_deps.c @@ -17,6 +17,7 @@ #include "slibtool_linkcmd_impl.h" #include "slibtool_mapfile_impl.h" #include "slibtool_metafile_impl.h" +#include "slibtool_realpath_impl.h" #include "slibtool_snprintf_impl.h" #include "slibtool_visibility_impl.h" @@ -87,6 +88,254 @@ slbt_hidden int slbt_get_deps_meta( } +static int slbt_exec_link_normalize_dep_file( + const struct slbt_driver_ctx * dctx, + int deps, + char (*depfile)[PATH_MAX]) +{ + int ret; + int fdcwd; + int fdtgt; + char * dot; + char * slash; + const char * mark; + struct slbt_txtfile_ctx * tctx; + const char ** pline; + char * tgtmark; + char * depmark; + char * relmark; + char * tgtnext; + char * depnext; + char tgtdir [PATH_MAX]; + char tgtpath [PATH_MAX]; + char deppath [PATH_MAX]; + char pathbuf [PATH_MAX]; + char depsbuf [PATH_MAX]; + char relapath[PATH_MAX]; + + /* fdcwd */ + fdcwd = slbt_driver_fdcwd(dctx); + + /* first-pass dependency file */ + if (slbt_impl_get_txtfile_ctx(dctx,*depfile,deps,&tctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* second-pass dependency file */ + dot = strrchr(*depfile,'.'); + strcpy(dot,".tmp2"); + + if ((deps = openat(fdcwd,*depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0) { + slbt_lib_free_txtfile_ctx(tctx); + return SLBT_SYSTEM_ERROR(dctx,depfile); + } + + /* fdtgt */ + strcpy(tgtdir,*depfile); + + if (!(slash = strrchr(tgtdir,'/'))) + slash = tgtdir; + + slash[0] = '\0'; + + if ((slash = strrchr(tgtdir,'/'))) { + slash[0] = '\0'; + slash++; + } else { + slash = tgtdir; + slash[0] = '.'; + slash[1] = '/'; + slash[2] = '\0'; + } + + if ((slash > tgtdir) && strcmp(slash,".libs")) { + close(deps); + slbt_lib_free_txtfile_ctx(tctx); + + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + } + + if ((fdtgt = openat(fdcwd,tgtdir,O_DIRECTORY|O_CLOEXEC,0)) < 0) { + close(deps); + slbt_lib_free_txtfile_ctx(tctx); + + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + } + + if (slbt_realpath(fdcwd,tgtdir,0,tgtpath,sizeof(tgtpath)) < 0) { + close(fdtgt); + close(deps); + slbt_lib_free_txtfile_ctx(tctx); + + return SLBT_CUSTOM_ERROR( + dctx, + SLBT_ERR_FLOW_ERROR); + } + + strcpy(pathbuf,tgtpath); + + /* normalize dependency lines as needed */ + for (pline=tctx->txtlinev; *pline; pline++) { + if ((mark = *pline)) { + if ((mark[0] == '-') && (mark[1] == 'L')) + mark = &mark[2]; + + if ((mark > *pline) && (mark[0] == '/')) + mark = *pline; + } else { + mark = *pline; + } + + if (mark > *pline) { + if (slbt_realpath( + fdtgt,mark,0,deppath, + sizeof(deppath)) < 0) + mark = *pline; + + else if ((tgtpath[0] != '/') || (deppath[0] != '/')) + mark = 0; + + else + strcpy(depsbuf,deppath); + } + + if ((mark > *pline) && strcmp(tgtpath,deppath)) { + tgtmark = tgtpath; + depmark = deppath; + + tgtnext = strchr(tgtmark,'/'); + depnext = strchr(depmark,'/'); + + while (tgtnext && depnext) { + *tgtnext = '\0'; + *depnext = '\0'; + + if (strcmp(tgtmark,depmark)) { + tgtnext = 0; + depnext = 0; + } else { + tgtmark = &tgtnext[1]; + depmark = &depnext[1]; + + if (*tgtmark && *depmark) { + tgtnext = strchr(tgtmark,'/'); + depnext = strchr(depmark,'/'); + } else { + tgtnext = 0; + depnext = 0; + } + } + } + + strcpy(tgtmark,&pathbuf[tgtmark-tgtpath]); + strcpy(depmark,&depsbuf[depmark-deppath]); + + if ((tgtmark - tgtpath) == (depmark - deppath)) { + mark = &depmark[strlen(tgtmark)]; + + if ((mark[0] == '/') && !strncmp(tgtmark,depmark,mark-depmark)) + sprintf(relapath,"-L.%s",mark); + else + mark = relapath; + } else { + mark = relapath; + } + + if (mark == relapath) { + relmark = relapath; + relmark += sprintf(relapath,"-L../"); + + while ((tgtnext = strchr(tgtmark,'/'))) { + tgtmark = &tgtnext[1]; + relmark += sprintf(relmark,"../"); + } + + strcpy(relmark,depmark); + } + + mark = relapath; + + } else if (mark > *pline) { + strcpy(relapath,"-L."); + mark = relapath; + } + + ret = mark ? slbt_dprintf(deps,"%s\n",mark) : (-1); + + if (ret < 0) { + close(deps); + close(fdtgt); + slbt_lib_free_txtfile_ctx(tctx); + + return mark + ? SLBT_SYSTEM_ERROR(dctx,0) + : SLBT_NESTED_ERROR(dctx); + } + + if (mark == relapath) + strcpy(tgtpath,pathbuf); + } + + close(fdtgt); + slbt_lib_free_txtfile_ctx(tctx); + + return deps; +} + + +static int slbt_exec_link_compact_dep_file( + const struct slbt_driver_ctx * dctx, + int deps, + char (*depfile)[PATH_MAX]) +{ + int fdcwd; + struct slbt_txtfile_ctx * tctx; + const char ** pline; + const char ** pcomp; + const char * depline; + char * dot; + + /* fdcwd */ + fdcwd = slbt_driver_fdcwd(dctx); + + /* second-pass dependency file */ + if (slbt_impl_get_txtfile_ctx(dctx,*depfile,deps,&tctx) < 0) + return SLBT_NESTED_ERROR(dctx); + + /* second-pass dependency file */ + dot = strrchr(*depfile,'.'); + dot[0] = '\0'; + + if ((deps = openat(fdcwd,*depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0) { + slbt_lib_free_txtfile_ctx(tctx); + return SLBT_SYSTEM_ERROR(dctx,depfile); + } + + /* iterate, only write unique entries */ + for (pline=tctx->txtlinev; *pline; pline++) { + depline = *pline; + + if ((depline[0] == '-') && (depline[1] == 'L')) + for (pcomp=tctx->txtlinev; depline && pcomp<pline; pcomp++) + if (!strcmp(*pcomp,depline)) + depline = 0; + + if (depline && (slbt_dprintf(deps,"%s\n",depline) < 0)) { + close(deps); + slbt_lib_free_txtfile_ctx(tctx); + return SLBT_SYSTEM_ERROR(dctx,0); + } + } + + slbt_lib_free_txtfile_ctx(tctx); + + return deps; +} + + slbt_hidden int slbt_exec_link_create_dep_file( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, @@ -96,6 +345,7 @@ slbt_hidden int slbt_exec_link_create_dep_file( { int ret; int deps; + int fdtmp; int slen; int fdcwd; char ** parg; @@ -109,6 +359,7 @@ slbt_hidden int slbt_exec_link_create_dep_file( bool is_reladir; char reladir[PATH_MAX]; char depfile[PATH_MAX]; + char pathbuf[PATH_MAX]; struct stat st; int ldepth; int fdyndep; @@ -119,10 +370,12 @@ slbt_hidden int slbt_exec_link_create_dep_file( /* depfile */ if (slbt_snprintf(depfile,sizeof(depfile), - "%s.slibtool.deps", + "%s.slibtool.deps.tmp1", libfilename) < 0) return SLBT_BUFFER_ERROR(dctx); + strcpy(pathbuf,depfile); + /* deps */ if ((deps = openat(fdcwd,depfile,O_RDWR|O_CREAT|O_TRUNC,0644)) < 0) return SLBT_SYSTEM_ERROR(dctx,depfile); @@ -326,5 +579,16 @@ slbt_hidden int slbt_exec_link_create_dep_file( } } + if ((fdtmp = slbt_exec_link_normalize_dep_file(dctx,deps,&pathbuf)) < 0) + return SLBT_NESTED_ERROR(dctx); + + close(deps); + + if ((deps = slbt_exec_link_compact_dep_file(dctx,fdtmp,&pathbuf)) < 0) + return SLBT_NESTED_ERROR(dctx); + + close(deps); + close(fdtmp); + return 0; } |