summaryrefslogtreecommitdiff
path: root/src/lib/eina/eina_file.c
diff options
context:
space:
mode:
authorGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-31 23:17:18 +0000
committerGustavo Sverzut Barbieri <barbieri@gmail.com>2012-12-31 23:17:18 +0000
commit6ae6f925a4871d1be22221dbd5b1f2b09b1a172d (patch)
tree2be8af37de02f22fc6e3cceb4ab6c1a80f852e91 /src/lib/eina/eina_file.c
parent678727aae4a274b0a8ab2d2df6692437fbdb3299 (diff)
efl: add eina_file_copy()
it's useful to copy file from one place to another and this will be used in eio' s implementation. NOTE: did not use mmap here as mmap faults may be cumbersome to handle (Eina_File itself does that, but in a nasty way) and the implementation would be severely different as there is no Eina_File from FD, and there is no way to inject custom memory/fd into the Eina_File's fault handling. The performance would not be that different anyways and the splice() is already in there for systems with good performance (read: Linux). SVN revision: 81942
Diffstat (limited to 'src/lib/eina/eina_file.c')
-rw-r--r--src/lib/eina/eina_file.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/src/lib/eina/eina_file.c b/src/lib/eina/eina_file.c
index ec83b7d..01b193a 100644
--- a/src/lib/eina/eina_file.c
+++ b/src/lib/eina/eina_file.c
@@ -54,6 +54,7 @@ void *alloca (size_t);
54#include <fcntl.h> 54#include <fcntl.h>
55 55
56#define PATH_DELIM '/' 56#define PATH_DELIM '/'
57#define COPY_BLOCKSIZE (4 * 1024 * 1024)
57 58
58#include "eina_config.h" 59#include "eina_config.h"
59#include "eina_private.h" 60#include "eina_private.h"
@@ -95,6 +96,11 @@ void *alloca (size_t);
95#endif 96#endif
96#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__) 97#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__)
97 98
99#ifdef INF
100#undef INF
101#endif
102#define INF(...) EINA_LOG_DOM_INFO(_eina_file_log_dom, __VA_ARGS__)
103
98#ifdef DBG 104#ifdef DBG
99#undef DBG 105#undef DBG
100#endif 106#endif
@@ -1518,3 +1524,256 @@ eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st)
1518#endif 1524#endif
1519 return 0; 1525 return 0;
1520} 1526}
1527
1528static Eina_Bool
1529_eina_file_copy_write_internal(int fd, char *buf, size_t size)
1530{
1531 size_t done = 0;
1532 while (done < size)
1533 {
1534 ssize_t w = write(fd, buf + done, size - done);
1535 if (w >= 0)
1536 done += w;
1537 else if ((errno != EAGAIN) && (errno != EINTR))
1538 {
1539 ERR("Error writing destination file during copy: %s",
1540 strerror(errno));
1541 return EINA_FALSE;
1542 }
1543 }
1544 return EINA_TRUE;
1545}
1546
1547static Eina_Bool
1548_eina_file_copy_read_internal(int fd, char *buf, off_t bufsize, ssize_t *readsize)
1549{
1550 while (1)
1551 {
1552 ssize_t r = read(fd, buf, bufsize);
1553 if (r == 0)
1554 {
1555 ERR("Premature end of source file during copy.");
1556 return EINA_FALSE;
1557 }
1558 else if (r < 0)
1559 {
1560 if ((errno != EAGAIN) && (errno != EINTR))
1561 {
1562 ERR("Error reading source file during copy: %s",
1563 strerror(errno));
1564 return EINA_FALSE;
1565 }
1566 }
1567 else
1568 {
1569 *readsize = r;
1570 return EINA_TRUE;
1571 }
1572 }
1573}
1574
1575static Eina_Bool
1576_eina_file_copy_write_splice_internal(int fd, int pipefd, size_t size)
1577{
1578 size_t done = 0;
1579 while (done < size)
1580 {
1581 ssize_t w = splice(pipefd, NULL, fd, NULL, size - done, SPLICE_F_MORE);
1582 if (w >= 0)
1583 done += w;
1584 else if (errno == EINVAL)
1585 {
1586 INF("Splicing is not supported for destination file");
1587 return EINA_FALSE;
1588 }
1589 else if ((errno != EAGAIN) && (errno != EINTR))
1590 {
1591 ERR("Error splicing to destination file during copy: %s",
1592 strerror(errno));
1593 return EINA_FALSE;
1594 }
1595 }
1596 return EINA_TRUE;
1597}
1598
1599static Eina_Bool
1600_eina_file_copy_read_splice_internal(int fd, int pipefd, off_t bufsize, ssize_t *readsize)
1601{
1602 while (1)
1603 {
1604 ssize_t r = splice(fd, NULL, pipefd, NULL, bufsize, SPLICE_F_MORE);
1605 if (r == 0)
1606 {
1607 ERR("Premature end of source file during splice.");
1608 return EINA_FALSE;
1609 }
1610 else if (r < 0)
1611 {
1612 if (errno == EINVAL)
1613 {
1614 INF("Splicing is not supported for source file");
1615 return EINA_FALSE;
1616 }
1617 else if ((errno != EAGAIN) && (errno != EINTR))
1618 {
1619 ERR("Error splicing from source file during copy: %s",
1620 strerror(errno));
1621 return EINA_FALSE;
1622 }
1623 }
1624 else
1625 {
1626 *readsize = r;
1627 return EINA_TRUE;
1628 }
1629 }
1630}
1631
1632static Eina_Bool
1633_eina_file_copy_splice_internal(int s, int d, off_t total, Eina_File_Copy_Progress cb, const void *cb_data, Eina_Bool *splice_unsupported)
1634{
1635#ifdef HAVE_SPLICE
1636 off_t bufsize = COPY_BLOCKSIZE;
1637 off_t done;
1638 Eina_Bool ret;
1639 int pipefd[2];
1640
1641 *splice_unsupported = EINA_TRUE;
1642
1643 if (pipe(pipefd) < 0) return EINA_FALSE;
1644
1645 done = 0;
1646 ret = EINA_TRUE;
1647 while (done < total)
1648 {
1649 size_t todo;
1650 ssize_t r;
1651
1652 if (done + bufsize < total)
1653 todo = bufsize;
1654 else
1655 todo = total - done;
1656
1657 printf("loop done=%lld, total=%lld, todo=%zd\n", done, total, todo);
1658
1659 ret = _eina_file_copy_read_splice_internal(s, pipefd[1], todo, &r);
1660 if (!ret) break;
1661
1662 ret = _eina_file_copy_write_splice_internal(d, pipefd[0], r);
1663 if (!ret) break;
1664
1665 *splice_unsupported = EINA_FALSE;
1666 done += r;
1667
1668 if (cb)
1669 {
1670 ret = cb((void *)cb_data, done, total);
1671 if (!ret) break;
1672 }
1673 }
1674
1675 close(pipefd[0]);
1676 close(pipefd[1]);
1677
1678 return ret;
1679#endif
1680 *splice_unsupported = EINA_TRUE;
1681 return EINA_FALSE;
1682 (void)s;
1683 (void)d;
1684 (void)total;
1685 (void)cb;
1686 (void)cb_data;
1687}
1688
1689static Eina_Bool
1690_eina_file_copy_internal(int s, int d, off_t total, Eina_File_Copy_Progress cb, const void *cb_data)
1691{
1692 void *buf = NULL;
1693 off_t bufsize = COPY_BLOCKSIZE;
1694 off_t done;
1695 Eina_Bool ret, splice_unsupported;
1696
1697 ret = _eina_file_copy_splice_internal(s, d, total, cb, cb_data,
1698 &splice_unsupported);
1699 if (ret)
1700 return EINA_TRUE;
1701 else if (!splice_unsupported) /* splice works, but copy failed anyway */
1702 return EINA_FALSE;
1703
1704 /* make sure splice didn't change the position */
1705 lseek(s, 0, SEEK_SET);
1706 lseek(d, 0, SEEK_SET);
1707
1708 while ((bufsize > 0) && ((buf = malloc(bufsize)) == NULL))
1709 bufsize /= 128;
1710
1711 EINA_SAFETY_ON_NULL_RETURN_VAL(buf, EINA_FALSE);
1712
1713 done = 0;
1714 ret = EINA_TRUE;
1715 while (done < total)
1716 {
1717 size_t todo;
1718 ssize_t r;
1719
1720 if (done + bufsize < total)
1721 todo = bufsize;
1722 else
1723 todo = total - done;
1724
1725 ret = _eina_file_copy_read_internal(s, buf, todo, &r);
1726 if (!ret) break;
1727
1728 ret = _eina_file_copy_write_internal(d, buf, r);
1729 if (!ret) break;
1730
1731 done += r;
1732
1733 if (cb)
1734 {
1735 ret = cb((void *)cb_data, done, total);
1736 if (!ret) break;
1737 }
1738 }
1739
1740 free(buf);
1741 return ret;
1742}
1743
1744EAPI Eina_Bool
1745eina_file_copy(const char *src, const char *dst, Eina_File_Copy_Flags flags, Eina_File_Copy_Progress cb, const void *cb_data)
1746{
1747 struct stat st;
1748 int s, d;
1749 Eina_Bool success;
1750
1751 EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
1752 EINA_SAFETY_ON_NULL_RETURN_VAL(dst, EINA_FALSE);
1753
1754 s = open(src, O_RDONLY);
1755 EINA_SAFETY_ON_TRUE_RETURN_VAL (s < 0, EINA_FALSE);
1756
1757 success = (fstat(s, &st) == 0);
1758 EINA_SAFETY_ON_FALSE_GOTO(success, end);
1759
1760 d = open(dst, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
1761 EINA_SAFETY_ON_TRUE_GOTO(d < 0, end);
1762
1763 success = _eina_file_copy_internal(s, d, st.st_size, cb, cb_data);
1764 if (success)
1765 {
1766 if (flags & EINA_FILE_COPY_PERMISSION)
1767 fchmod(d, st.st_mode);
1768 if (flags & EINA_FILE_COPY_XATTR)
1769 eina_xattr_fd_copy(s, d);
1770 }
1771
1772 end:
1773 close(s);
1774
1775 if (!success)
1776 unlink(dst);
1777
1778 return success;
1779}