#define _GNU_SOURCE // gets us largefile64, among others #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include #include #include #include #include #include #include #include #ifndef O_NOATIME # if __i386__ || __ia64__ || __x86_64__ || __ppc__ # define O_NOATIME 01000000 # else # define O_NOATIME 0 # endif #endif MODULE = File::Defrag PACKAGE = File::Defrag PROTOTYPES: enable SV * direct_open (const char *pathname, int flags, int mode = 0666) CODE: { int fd = open (pathname, flags | O_DIRECT | O_LARGEFILE | O_NOATIME | O_NOFOLLOW, mode); if (fd < 0 && errno == EINVAL) fd = open (pathname, flags | O_LARGEFILE | O_NOATIME | O_NOFOLLOW, mode); if (fd < 0) XSRETURN_UNDEF; fcntl (fd, F_SETFD, 1); GV *gv = newGVgen ("File::Defrag"); IO *io = GvIOn (gv); IoIFP (io) = PerlIO_fdopen (fd, "r+"); RETVAL = newRV_noinc ((SV *)gv); } OUTPUT: RETVAL U32 direct_copy (PerlIO *f1, PerlIO *f2, U32 chunksize, U32 chunkindex) CODE: { int fd1 = PerlIO_fileno (f1); int fd2 = PerlIO_fileno (f2); void *buff = mmap (0, chunksize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_LOCKED | MAP_ANONYMOUS | MAP_POPULATE, 0, 0); if (buff == MAP_FAILED) croak ("unable to allocate %ld bytes of memory for copy buffer", (long)chunksize); off64_t offs = (off_t)chunksize * (off_t)chunkindex; ssize_t count = pread64 (fd1, buff, chunksize, offs); if (count == -1) { munmap (buff, chunksize); croak ("unable to read %ld bytes from source file", (long)chunksize); } ssize_t rounded = (count + 511) & ~511; ssize_t written = pwrite64 (fd2, buff, rounded, offs); munmap (buff, chunksize); if (written != rounded) croak ("unable to write %ld bytes to destination file", (long)rounded); RETVAL = count; } OUTPUT: RETVAL long file_extents (PerlIO *f, long max_gap = 0) CODE: { int fd = PerlIO_fileno (f); struct stat64 statdata; if (fstat64 (fd, &statdata)) croak ("unable to stat() file"); long blksize; if (ioctl (fd, FIGETBSZ, &blksize)) croak ("unable to detect file blocksize"); long fragments = 1; long next_blk = 0; if (ioctl (fd, FIBMAP, &next_blk)) XSRETURN_EMPTY; long count = (statdata.st_size + blksize - 1) / blksize; long i; for (i = 0; i < count; i++) { long blk = i; if (ioctl (fd, FIBMAP, &blk)) XSRETURN_EMPTY; if (blk < next_blk || next_blk + max_gap < blk) fragments++; next_blk = blk + 1; } RETVAL = fragments; } OUTPUT: RETVAL