|
|
c8d21a |
/*******************************************************************/
|
|
|
c8d21a |
/* slibtool: a skinny libtool implementation, written in C */
|
|
|
c8d21a |
/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
|
|
|
c8d21a |
/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
|
|
|
c8d21a |
/*******************************************************************/
|
|
|
c8d21a |
|
|
|
c8d21a |
#include <time.h>
|
|
|
c8d21a |
#include <fcntl.h>
|
|
|
c8d21a |
#include <stdio.h>
|
|
|
c8d21a |
#include <stddef.h>
|
|
|
c8d21a |
#include <limits.h>
|
|
|
c8d21a |
#include <string.h>
|
|
|
c8d21a |
#include <stdlib.h>
|
|
|
c8d21a |
#include <unistd.h>
|
|
|
c8d21a |
#include <inttypes.h>
|
|
|
c8d21a |
#include <sys/stat.h>
|
|
|
c8d21a |
|
|
|
c8d21a |
#include <slibtool/slibtool.h>
|
|
|
c8d21a |
#include <slibtool/slibtool_arbits.h>
|
|
|
c8d21a |
#include "slibtool_ar_impl.h"
|
|
|
c8d21a |
#include "slibtool_driver_impl.h"
|
|
|
c8d21a |
#include "slibtool_errinfo_impl.h"
|
|
|
c8d21a |
|
|
|
c8d21a |
/****************************************************/
|
|
|
c8d21a |
/* As elsewhere in slibtool, file-system operations */
|
|
|
c8d21a |
/* utilizie the _at variants of the relevant posix */
|
|
|
c8d21a |
/* interfaces. In the case of archives, that means */
|
|
|
c8d21a |
/* passing dctx->fdctx->fdcwd as the _fdat_ param, */
|
|
|
c8d21a |
/* where dctx is the driver context which was used */
|
|
|
c8d21a |
/* with slbt_get_archive_ctx(). */
|
|
|
c8d21a |
/************************************************** */
|
|
|
c8d21a |
|
|
|
c8d21a |
#define PPRIX64 "%"PRIx64
|
|
|
c8d21a |
|
|
|
c8d21a |
int slbt_store_archive(
|
|
|
c8d21a |
struct slbt_archive_ctx * arctx,
|
|
|
c8d21a |
const char * path,
|
|
|
c8d21a |
mode_t mode)
|
|
|
c8d21a |
{
|
|
|
c8d21a |
const struct slbt_driver_ctx * dctx;
|
|
|
c8d21a |
struct stat st;
|
|
|
c8d21a |
int fdat;
|
|
|
c8d21a |
int fdtmp;
|
|
|
c8d21a |
char * mark;
|
|
|
c8d21a |
char * slash;
|
|
|
c8d21a |
size_t buflen;
|
|
|
c8d21a |
size_t nbytes;
|
|
|
c8d21a |
ssize_t written;
|
|
|
c8d21a |
char buf[PATH_MAX];
|
|
|
c8d21a |
|
|
|
c8d21a |
/* init dctx */
|
|
|
c8d21a |
if (!(dctx = slbt_get_archive_ictx(arctx)->dctx))
|
|
|
c8d21a |
return -1;
|
|
|
c8d21a |
|
|
|
c8d21a |
/* validation */
|
|
|
c8d21a |
if (strlen(path) >= PATH_MAX)
|
|
|
c8d21a |
return SLBT_CUSTOM_ERROR(
|
|
|
c8d21a |
dctx,
|
|
|
c8d21a |
SLBT_ERR_FLOW_ERROR);
|
|
|
c8d21a |
|
|
|
c8d21a |
/**************************************************/
|
|
|
c8d21a |
/* create temporary file in the target directory */
|
|
|
c8d21a |
/* */
|
|
|
c8d21a |
/* the tmpfile name pattern involes the inode */
|
|
|
c8d21a |
/* of the target directory, a local stack address */
|
|
|
c8d21a |
/* in the calling thread, the current time, and */
|
|
|
c8d21a |
/* finally the pid of the current process. */
|
|
|
c8d21a |
/**************************************************/
|
|
|
c8d21a |
|
|
|
c8d21a |
memset(buf,0,sizeof(buf));
|
|
|
c8d21a |
strcpy(buf,path);
|
|
|
c8d21a |
|
|
|
c8d21a |
fdat = slbt_driver_fdcwd(dctx);
|
|
|
c8d21a |
|
|
|
c8d21a |
mark = (slash = strrchr(buf,'/'))
|
|
|
c8d21a |
? slash : buf;
|
|
|
c8d21a |
|
|
|
c8d21a |
if (slash) {
|
|
|
c8d21a |
*++mark = '\0';
|
|
|
c8d21a |
|
|
|
c8d21a |
if (fstatat(fdat,buf,&st,0) < 0)
|
|
|
c8d21a |
return SLBT_SYSTEM_ERROR(
|
|
|
c8d21a |
dctx,0);
|
|
|
c8d21a |
} else {
|
|
|
c8d21a |
if (fstatat(fdat,".",&st,0) < 0)
|
|
|
c8d21a |
return SLBT_SYSTEM_ERROR(
|
|
|
c8d21a |
dctx,0);
|
|
|
c8d21a |
}
|
|
|
c8d21a |
|
|
|
c8d21a |
buflen = sizeof(buf) - (mark - buf);
|
|
|
c8d21a |
nbytes = snprintf(
|
|
|
c8d21a |
mark,
|
|
|
c8d21a |
buflen,
|
|
|
c8d21a |
".slibtool.tmpfile"
|
|
|
c8d21a |
".inode."PPRIX64
|
|
|
c8d21a |
".time."PPRIX64
|
|
|
c8d21a |
".salt.%p"
|
|
|
c8d21a |
".pid.%d"
|
|
|
c8d21a |
".tmp",
|
|
|
c8d21a |
st.st_ino,
|
|
|
c8d21a |
time(0),&buf,
|
|
|
c8d21a |
getpid());
|
|
|
c8d21a |
|
|
|
c8d21a |
if (nbytes >= buflen)
|
|
|
c8d21a |
return SLBT_CUSTOM_ERROR(
|
|
|
c8d21a |
dctx,
|
|
|
c8d21a |
SLBT_ERR_FLOW_ERROR);
|
|
|
c8d21a |
|
|
|
c8d21a |
if ((fdtmp = openat(fdat,buf,O_WRONLY|O_CREAT|O_EXCL,mode)) < 0)
|
|
|
c8d21a |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
c8d21a |
|
|
|
c8d21a |
/* set archive size */
|
|
|
c8d21a |
if (ftruncate(fdtmp,arctx->map->map_size) < 0)
|
|
|
c8d21a |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
c8d21a |
|
|
|
c8d21a |
/* write archive */
|
|
|
c8d21a |
mark = arctx->map->map_addr;
|
|
|
c8d21a |
nbytes = arctx->map->map_size;
|
|
|
c8d21a |
|
|
|
c8d21a |
for (; nbytes; ) {
|
|
|
c8d21a |
written = write(fdtmp,mark,nbytes);
|
|
|
c8d21a |
|
|
|
c8d21a |
while ((written < 0) && (errno == EINTR))
|
|
|
c8d21a |
written = write(fdtmp,mark,nbytes);
|
|
|
c8d21a |
|
|
|
c8d21a |
if (written < 0) {
|
|
|
c8d21a |
unlinkat(fdat,buf,0);
|
|
|
c8d21a |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
c8d21a |
};
|
|
|
c8d21a |
|
|
|
c8d21a |
nbytes -= written;
|
|
|
c8d21a |
mark += written;
|
|
|
c8d21a |
}
|
|
|
c8d21a |
|
|
|
c8d21a |
/* finalize (atomically) */
|
|
|
c8d21a |
if (renameat(fdat,buf,fdat,path) < 0) {
|
|
|
c8d21a |
unlinkat(fdat,buf,0);
|
|
|
c8d21a |
return SLBT_SYSTEM_ERROR(dctx,0);
|
|
|
c8d21a |
}
|
|
|
c8d21a |
|
|
|
c8d21a |
/* yay */
|
|
|
c8d21a |
return 0;
|
|
|
c8d21a |
}
|