Data-Stack-Shared
view release on metacpan or search on metacpan
eg/str_undo.pl view on Meta::CPAN
use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../blib/lib", "$FindBin::Bin/../blib/arch";
use Data::Stack::Shared;
$| = 1;
my $undo = Data::Stack::Shared::Str->new(undef, 50, 128);
# simulate operations
for my $op ("create file.txt", "write 100 bytes", "chmod 644", "rename to file.bak") {
$undo->push($op);
printf "do: %s\n", $op;
}
printf "\nstack size: %d\n\n", $undo->size;
# undo last 2
for (1..2) {
my $op = $undo->pop;
printf "undo: %s\n", $op;
}
return 1;
}
/* Securely obtain a fd: create exclusively (O_CREAT|O_EXCL|O_NOFOLLOW at mode,
* default 0600), or attach an existing file (O_RDWR|O_NOFOLLOW, no O_CREAT).
* O_EXCL blocks a pre-seeded/hard-linked file and O_NOFOLLOW a symlink swap,
* so a local peer cannot redirect or pre-own the backing segment. */
static int stk_secure_open(const char *path, mode_t mode, char *errbuf) {
for (int attempt = 0; attempt < 100; attempt++) {
int fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC, mode);
if (fd >= 0) { (void)fchmod(fd, mode); return fd; } /* exact mode: umask narrowed the O_EXCL create */
if (errno != EEXIST) { STK_ERR("create %s: %s", path, strerror(errno)); return -1; }
fd = open(path, O_RDWR|O_NOFOLLOW|O_CLOEXEC);
if (fd >= 0) return fd;
if (errno == ENOENT) continue; /* creator unlinked between our two opens; retry */
STK_ERR("open %s: %s", path, strerror(errno)); /* ELOOP => symlink rejected */
return -1;
}
STK_ERR("open %s: create/attach kept racing", path);
return -1;
}
struct stat st;
if (fstat(fd, &st) < 0) {
STK_ERR("fstat: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL;
}
int is_new = (st.st_size == 0);
if (!is_new && (uint64_t)st.st_size < sizeof(StkHeader)) {
STK_ERR("%s: file too small (%lld)", path, (long long)st.st_size);
flock(fd, LOCK_UN); close(fd); return NULL;
}
if (is_new && (st.st_uid != geteuid() || fchmod(fd, mode) < 0)) {
STK_ERR("%s: refusing to initialize file not owned by us", path);
flock(fd, LOCK_UN); close(fd); return NULL;
}
if (is_new) {
if (ftruncate(fd, (off_t)total) < 0) {
STK_ERR("ftruncate: %s", strerror(errno));
flock(fd, LOCK_UN); close(fd); return NULL;
}
}
map_size = is_new ? (size_t)total : (size_t)st.st_size;
memcpy(&snap, base, sizeof snap);
if (!stk_validate_header(&snap, (uint64_t)st.st_size, variant_id)) {
/* Recover an abandoned mid-init file: a creator killed
* between the ftruncate and the header init leaves a
* full-size, all-zero (magic==0) file that would brick every
* future open of this path. Re-initialize ONLY when it is
* exactly our size, still uninitialized, and owned by us;
* anything else still errors. */
if (snap.magic == 0 && (uint64_t)st.st_size == total
&& st.st_uid == geteuid() && stk_region_is_zero(base, map_size)) {
if (fchmod(fd, mode) < 0) {
STK_ERR("%s: fchmod: %s", path, strerror(errno));
munmap(base, map_size); flock(fd, LOCK_UN); close(fd); return NULL;
}
stk_init_header(base, total, elem_size, variant_id, capacity);
flock(fd, LOCK_UN); close(fd);
return stk_setup(base, map_size, path, -1,
sizeof(StkHeader), stk_ctl_offset(elem_size, capacity),
elem_size, capacity);
}
if (snap.magic == 0 && (uint64_t)st.st_size == total
&& st.st_uid == geteuid())
( run in 1.273 second using v1.01-cache-2.11-cpan-f03e8824b8d )