| |
| |
| |
| |
| |
| |
| #include <time.h> |
| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <limits.h> |
| #include <string.h> |
| #include <stdlib.h> |
| #include <unistd.h> |
| #include <inttypes.h> |
| #include <sys/stat.h> |
| |
| #include <slibtool/slibtool.h> |
| #include <slibtool/slibtool_arbits.h> |
| #include "slibtool_ar_impl.h" |
| #include "slibtool_driver_impl.h" |
| #include "slibtool_errinfo_impl.h" |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define PPRIX64 "%"PRIx64 |
| |
| int slbt_ar_store_archive( |
| struct slbt_archive_ctx * arctx, |
| const char * path, |
| mode_t mode) |
| { |
| const struct slbt_driver_ctx * dctx; |
| struct stat st; |
| int fdat; |
| int fdtmp; |
| void * addr; |
| char * mark; |
| char * slash; |
| size_t buflen; |
| size_t nbytes; |
| ssize_t written; |
| char buf[PATH_MAX]; |
| |
| |
| if (!(dctx = slbt_get_archive_ictx(arctx)->dctx)) |
| return -1; |
| |
| |
| if (strlen(path) >= PATH_MAX) |
| return SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_FLOW_ERROR); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| memset(buf,0,sizeof(buf)); |
| strcpy(buf,path); |
| |
| fdat = slbt_driver_fdcwd(dctx); |
| |
| addr = buf; |
| mark = (slash = strrchr(buf,'/')) |
| ? slash : buf; |
| |
| if (slash) { |
| *++mark = '\0'; |
| |
| if (fstatat(fdat,buf,&st,0) < 0) |
| return SLBT_SYSTEM_ERROR( |
| dctx,0); |
| } else { |
| if (fstatat(fdat,".",&st,0) < 0) |
| return SLBT_SYSTEM_ERROR( |
| dctx,0); |
| } |
| |
| buflen = sizeof(buf) - (mark - buf); |
| nbytes = snprintf( |
| mark, |
| buflen, |
| ".slibtool.tmpfile" |
| ".inode."PPRIX64 |
| ".time."PPRIX64 |
| ".salt.%p" |
| ".pid.%d" |
| ".tmp", |
| st.st_ino, |
| time(0),addr, |
| getpid()); |
| |
| if (nbytes >= buflen) |
| return SLBT_CUSTOM_ERROR( |
| dctx, |
| SLBT_ERR_FLOW_ERROR); |
| |
| if ((fdtmp = openat(fdat,buf,O_WRONLY|O_CREAT|O_EXCL,mode)) < 0) |
| return SLBT_SYSTEM_ERROR(dctx,0); |
| |
| |
| if (ftruncate(fdtmp,arctx->map->map_size) < 0) |
| return SLBT_SYSTEM_ERROR(dctx,0); |
| |
| |
| mark = arctx->map->map_addr; |
| nbytes = arctx->map->map_size; |
| |
| for (; nbytes; ) { |
| written = write(fdtmp,mark,nbytes); |
| |
| while ((written < 0) && (errno == EINTR)) |
| written = write(fdtmp,mark,nbytes); |
| |
| if (written < 0) { |
| unlinkat(fdat,buf,0); |
| return SLBT_SYSTEM_ERROR(dctx,0); |
| }; |
| |
| nbytes -= written; |
| mark += written; |
| } |
| |
| |
| if (renameat(fdat,buf,fdat,path) < 0) { |
| unlinkat(fdat,buf,0); |
| return SLBT_SYSTEM_ERROR(dctx,0); |
| } |
| |
| |
| return 0; |
| } |