Ancient
view release on metacpan or search on metacpan
xs/file/file.c view on Meta::CPAN
static int file_copy_internal(pTHX_ const char *src, const char *dst) {
int fd_src, fd_dst;
char *buffer;
ssize_t n_read, n_written, written;
struct stat st;
int result = 0;
#ifdef _WIN32
int open_flags_r = O_RDONLY | O_BINARY;
int open_flags_w = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
#else
int open_flags_r = O_RDONLY;
int open_flags_w = O_WRONLY | O_CREAT | O_TRUNC;
#endif
fd_src = open(src, open_flags_r);
if (fd_src < 0) return 0;
if (fstat(fd_src, &st) < 0) {
close(fd_src);
return 0;
}
fd_dst = open(dst, open_flags_w, st.st_mode & 07777);
if (fd_dst < 0) {
close(fd_src);
return 0;
}
Newx(buffer, FILE_BULK_BUFFER_SIZE, char);
while (1) {
n_read = read(fd_src, buffer, FILE_BULK_BUFFER_SIZE);
if (n_read < 0) {
if (errno == EINTR) continue;
goto cleanup;
}
if (n_read == 0) break;
written = 0;
while (written < n_read) {
n_written = write(fd_dst, buffer + written, n_read - written);
if (n_written < 0) {
if (errno == EINTR) continue;
goto cleanup;
}
written += n_written;
}
}
result = 1;
cleanup:
Safefree(buffer);
close(fd_src);
close(fd_dst);
return result;
}
static int file_move_internal(pTHX_ const char *src, const char *dst) {
/* Try rename first (fast path for same filesystem) */
if (rename(src, dst) == 0) {
return 1;
}
/* If EXDEV, copy then delete (cross-device move) */
if (errno == EXDEV) {
if (file_copy_internal(aTHX_ src, dst)) {
return file_unlink_internal(src);
}
}
return 0;
}
static int file_touch_internal(const char *path) {
#ifdef _WIN32
HANDLE h;
FILETIME ft;
SYSTEMTIME st;
int result = 0;
/* Try to open existing file */
h = CreateFileA(path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (h == INVALID_HANDLE_VALUE) {
return 0;
}
GetSystemTime(&st);
SystemTimeToFileTime(&st, &ft);
result = SetFileTime(h, NULL, &ft, &ft) != 0;
CloseHandle(h);
return result;
#else
int fd;
/* Try to update times on existing file - utime(path, NULL) sets to current time */
if (utime(path, NULL) == 0) {
return 1;
}
/* File doesn't exist, create it */
fd = open(path, O_WRONLY | O_CREAT, 0644);
if (fd < 0) return 0;
close(fd);
return 1;
#endif
}
static int file_chmod_internal(const char *path, int mode) {
#ifdef _WIN32
return _chmod(path, mode) == 0;
#else
return chmod(path, mode) == 0;
#endif
}
static int file_mkdir_internal(const char *path, int mode) {
#ifdef _WIN32
PERL_UNUSED_VAR(mode);
return _mkdir(path) == 0;
#else
xs/file/file.c view on Meta::CPAN
static AV* file_head_internal(pTHX_ const char *path, IV n) {
AV *result = newAV();
IV idx;
SV *line;
IV count = 0;
if (n <= 0) return result;
idx = file_lines_open(aTHX_ path);
if (idx < 0) return result;
while (count < n && (line = file_lines_next(aTHX_ idx)) != &PL_sv_undef) {
av_push(result, line);
count++;
}
file_lines_close(idx);
return result;
}
static AV* file_tail_internal(pTHX_ const char *path, IV n) {
AV *result = newAV();
AV *buffer;
SV *line;
IV idx;
SSize_t i, buf_len;
if (n <= 0) return result;
idx = file_lines_open(aTHX_ path);
if (idx < 0) return result;
/* Use circular buffer to keep last N lines */
buffer = newAV();
av_extend(buffer, n - 1);
while ((line = file_lines_next(aTHX_ idx)) != &PL_sv_undef) {
if (av_len(buffer) + 1 >= n) {
SV *old = av_shift(buffer);
SvREFCNT_dec(old);
}
av_push(buffer, line);
}
file_lines_close(idx);
/* Copy buffer to result */
buf_len = av_len(buffer) + 1;
for (i = 0; i < buf_len; i++) {
SV **sv = av_fetch(buffer, i, 0);
if (sv) {
av_push(result, newSVsv(*sv));
}
}
SvREFCNT_dec((SV*)buffer);
return result;
}
/* ============================================
Atomic spew - write to temp file then rename
============================================ */
static int file_atomic_spew_internal(pTHX_ const char *path, SV *data) {
char temp_path[4096];
int fd;
const char *buf;
STRLEN len;
ssize_t written = 0, n;
static int counter = 0;
#ifdef _WIN32
int open_flags = O_WRONLY | O_CREAT | O_TRUNC | O_BINARY;
int pid = (int)GetCurrentProcessId();
#else
int open_flags = O_WRONLY | O_CREAT | O_TRUNC;
int pid = (int)getpid();
#endif
/* Create temp file name in same directory */
snprintf(temp_path, sizeof(temp_path), "%s.tmp.%d.%d", path, pid, counter++);
buf = SvPV(data, len);
fd = open(temp_path, open_flags, 0644);
if (fd < 0) {
return 0;
}
while ((size_t)written < len) {
n = write(fd, buf + written, len - written);
if (n < 0) {
if (errno == EINTR) continue;
close(fd);
file_unlink_internal(temp_path);
return 0;
}
written += n;
}
#ifdef _WIN32
/* Sync to disk on Windows */
_commit(fd);
#else
/* Sync to disk on POSIX */
fsync(fd);
#endif
close(fd);
/* Atomic rename */
if (rename(temp_path, path) != 0) {
file_unlink_internal(temp_path);
return 0;
}
return 1;
}
/* ============================================
Split lines utility
============================================ */
static AV* file_split_lines(pTHX_ SV *content) {
AV *lines;
const char *start, *end, *p;
STRLEN len;
start = SvPV(content, len);
end = start + len;
lines = newAV();
while (start < end) {
p = memchr(start, '\n', end - start);
if (p) {
av_push(lines, newSVpvn(start, p - start));
start = p + 1;
} else {
if (start < end) {
av_push(lines, newSVpvn(start, end - start));
}
break;
}
}
return lines;
}
/* ============================================
XS Functions
============================================ */
static XS(xs_slurp) {
dXSARGS;
const char *path;
if (items != 1) croak("Usage: file::slurp(path)");
path = SvPV_nolen(ST(0));
ST(0) = sv_2mortal(file_slurp_internal(aTHX_ path));
XSRETURN(1);
}
static XS(xs_slurp_raw) {
dXSARGS;
const char *path;
if (items != 1) croak("Usage: file::slurp_raw(path)");
path = SvPV_nolen(ST(0));
ST(0) = sv_2mortal(file_slurp_raw(aTHX_ path));
XSRETURN(1);
( run in 0.965 second using v1.01-cache-2.11-cpan-0b5f733616e )