| ... | @@ -1029,6 +1029,110 @@ Error os_write_file(Buf *full_path, Buf *contents) { | ... | @@ -1029,6 +1029,110 @@ Error os_write_file(Buf *full_path, Buf *contents) { |
| 1029 | return ErrorNone; | 1029 | return ErrorNone; |
| 1030 | } | 1030 | } |
| 1031 | | 1031 | |
| | 1032 | static Error copy_open_files(FILE *src_f, FILE *dest_f) { |
| | 1033 | static const size_t buf_size = 2048; |
| | 1034 | char buf[buf_size]; |
| | 1035 | for (;;) { |
| | 1036 | size_t amt_read = fread(buf, 1, buf_size, src_f); |
| | 1037 | if (amt_read != buf_size) { |
| | 1038 | if (ferror(src_f)) { |
| | 1039 | return ErrorFileSystem; |
| | 1040 | } |
| | 1041 | } |
| | 1042 | size_t amt_written = fwrite(buf, 1, amt_read, dest_f); |
| | 1043 | if (amt_written != amt_read) { |
| | 1044 | return ErrorFileSystem; |
| | 1045 | } |
| | 1046 | if (feof(src_f)) { |
| | 1047 | return ErrorNone; |
| | 1048 | } |
| | 1049 | } |
| | 1050 | } |
| | 1051 | |
| | 1052 | #if defined(ZIG_OS_WINDOWS) |
| | 1053 | static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { |
| | 1054 | mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; |
| | 1055 | mtime->nsec = 0; |
| | 1056 | } |
| | 1057 | static FILETIME windows_os_timestamp_to_filetime(OsTimeStamp mtime) { |
| | 1058 | FILETIME result; |
| | 1059 | result.dwHighDateTime = mtime.sec >> 32; |
| | 1060 | result.dwLowDateTime = mtime.sec; |
| | 1061 | return result; |
| | 1062 | } |
| | 1063 | #endif |
| | 1064 | |
| | 1065 | static Error set_file_times(OsFile file, OsTimeStamp ts) { |
| | 1066 | #if defined(ZIG_OS_WINDOWS) |
| | 1067 | const atime_ft = windows.nanoSecondsToFileTime(atime); |
| | 1068 | const mtime_ft = windows.nanoSecondsToFileTime(mtime); |
| | 1069 | return SetFileTime(file, null, &atime_ft, &mtime_ft); |
| | 1070 | #else |
| | 1071 | struct timespec times[2] = { |
| | 1072 | { ts.sec, ts.nsec }, |
| | 1073 | { ts.sec, ts.nsec }, |
| | 1074 | }; |
| | 1075 | if (futimens(file, times) == -1) { |
| | 1076 | switch (errno) { |
| | 1077 | case EBADF: |
| | 1078 | zig_panic("futimens EBADF"); |
| | 1079 | default: |
| | 1080 | return ErrorUnexpected; |
| | 1081 | } |
| | 1082 | } |
| | 1083 | return ErrorNone; |
| | 1084 | #endif |
| | 1085 | } |
| | 1086 | |
| | 1087 | Error os_update_file(Buf *src_path, Buf *dst_path) { |
| | 1088 | Error err; |
| | 1089 | |
| | 1090 | OsFile src_file; |
| | 1091 | OsFileAttr src_attr; |
| | 1092 | if ((err = os_file_open_r(src_path, &src_file, &src_attr))) { |
| | 1093 | return err; |
| | 1094 | } |
| | 1095 | |
| | 1096 | OsFile dst_file; |
| | 1097 | OsFileAttr dst_attr; |
| | 1098 | if ((err = os_file_open_w(dst_path, &dst_file, &dst_attr, src_attr.mode))) { |
| | 1099 | os_file_close(&src_file); |
| | 1100 | return err; |
| | 1101 | } |
| | 1102 | |
| | 1103 | if (src_attr.mtime.sec == dst_attr.mtime.sec && |
| | 1104 | src_attr.mtime.nsec == dst_attr.mtime.nsec && |
| | 1105 | src_attr.mode == dst_attr.mode) |
| | 1106 | { |
| | 1107 | os_file_close(&src_file); |
| | 1108 | os_file_close(&dst_file); |
| | 1109 | return ErrorNone; |
| | 1110 | } |
| | 1111 | |
| | 1112 | FILE *src_libc_file = fdopen(src_file, "rb"); |
| | 1113 | FILE *dst_libc_file = fdopen(dst_file, "wb"); |
| | 1114 | assert(src_libc_file); |
| | 1115 | assert(dst_libc_file); |
| | 1116 | if (ftruncate(dst_file, 0) == -1) { |
| | 1117 | return ErrorUnexpected; |
| | 1118 | } |
| | 1119 | if ((err = copy_open_files(src_libc_file, dst_libc_file))) { |
| | 1120 | fclose(src_libc_file); |
| | 1121 | fclose(dst_libc_file); |
| | 1122 | return err; |
| | 1123 | } |
| | 1124 | if (fflush(src_libc_file) == -1) { |
| | 1125 | return ErrorUnexpected; |
| | 1126 | } |
| | 1127 | if (fflush(dst_libc_file) == -1) { |
| | 1128 | return ErrorUnexpected; |
| | 1129 | } |
| | 1130 | err = set_file_times(dst_file, src_attr.mtime); |
| | 1131 | fclose(src_libc_file); |
| | 1132 | fclose(dst_libc_file); |
| | 1133 | return err; |
| | 1134 | } |
| | 1135 | |
| 1032 | Error os_copy_file(Buf *src_path, Buf *dest_path) { | 1136 | Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1033 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); | 1137 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); |
| 1034 | if (!src_f) { | 1138 | if (!src_f) { |
| ... | @@ -1055,30 +1159,10 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { | ... | @@ -1055,30 +1159,10 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1055 | return ErrorFileSystem; | 1159 | return ErrorFileSystem; |
| 1056 | } | 1160 | } |
| 1057 | } | 1161 | } |
| 1058 | | 1162 | Error err = copy_open_files(src_f, dest_f); |
| 1059 | static const size_t buf_size = 2048; | 1163 | fclose(src_f); |
| 1060 | char buf[buf_size]; | 1164 | fclose(dest_f); |
| 1061 | for (;;) { | 1165 | return err; |
| 1062 | size_t amt_read = fread(buf, 1, buf_size, src_f); | | |
| 1063 | if (amt_read != buf_size) { | | |
| 1064 | if (ferror(src_f)) { | | |
| 1065 | fclose(src_f); | | |
| 1066 | fclose(dest_f); | | |
| 1067 | return ErrorFileSystem; | | |
| 1068 | } | | |
| 1069 | } | | |
| 1070 | size_t amt_written = fwrite(buf, 1, amt_read, dest_f); | | |
| 1071 | if (amt_written != amt_read) { | | |
| 1072 | fclose(src_f); | | |
| 1073 | fclose(dest_f); | | |
| 1074 | return ErrorFileSystem; | | |
| 1075 | } | | |
| 1076 | if (feof(src_f)) { | | |
| 1077 | fclose(src_f); | | |
| 1078 | fclose(dest_f); | | |
| 1079 | return ErrorNone; | | |
| 1080 | } | | |
| 1081 | } | | |
| 1082 | } | 1166 | } |
| 1083 | | 1167 | |
| 1084 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { | 1168 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| ... | @@ -1218,13 +1302,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) { | ... | @@ -1218,13 +1302,6 @@ Error os_rename(Buf *src_path, Buf *dest_path) { |
| 1218 | return ErrorNone; | 1302 | return ErrorNone; |
| 1219 | } | 1303 | } |
| 1220 | | 1304 | |
| 1221 | #if defined(ZIG_OS_WINDOWS) | | |
| 1222 | static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) { | | |
| 1223 | mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime; | | |
| 1224 | mtime->nsec = 0; | | |
| 1225 | } | | |
| 1226 | #endif | | |
| 1227 | | | |
| 1228 | OsTimeStamp os_timestamp_calendar(void) { | 1305 | OsTimeStamp os_timestamp_calendar(void) { |
| 1229 | OsTimeStamp result; | 1306 | OsTimeStamp result; |
| 1230 | #if defined(ZIG_OS_WINDOWS) | 1307 | #if defined(ZIG_OS_WINDOWS) |
| ... | @@ -1733,10 +1810,15 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { | ... | @@ -1733,10 +1810,15 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { |
| 1733 | #endif | 1810 | #endif |
| 1734 | } | 1811 | } |
| 1735 | | 1812 | |
| 1736 | Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { | 1813 | Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) { |
| 1737 | #if defined(ZIG_OS_WINDOWS) | 1814 | #if defined(ZIG_OS_WINDOWS) |
| 1738 | // TODO use CreateFileW | 1815 | // TODO use CreateFileW |
| 1739 | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); | 1816 | HANDLE result = CreateFileA(buf_ptr(full_path), |
| | 1817 | need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ, |
| | 1818 | need_write ? 0 : FILE_SHARE_READ, |
| | 1819 | nullptr, |
| | 1820 | need_write ? OPEN_ALWAYS : OPEN_EXISTING, |
| | 1821 | FILE_ATTRIBUTE_NORMAL, nullptr); |
| 1740 | | 1822 | |
| 1741 | if (result == INVALID_HANDLE_VALUE) { | 1823 | if (result == INVALID_HANDLE_VALUE) { |
| 1742 | DWORD err = GetLastError(); | 1824 | DWORD err = GetLastError(); |
| ... | @@ -1769,12 +1851,14 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { | ... | @@ -1769,12 +1851,14 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { |
| 1769 | } | 1851 | } |
| 1770 | windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime); | 1852 | windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime); |
| 1771 | attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow; | 1853 | attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow; |
| | 1854 | attr->mode = 0; |
| 1772 | } | 1855 | } |
| 1773 | | 1856 | |
| 1774 | return ErrorNone; | 1857 | return ErrorNone; |
| 1775 | #else | 1858 | #else |
| 1776 | for (;;) { | 1859 | for (;;) { |
| 1777 | int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC); | 1860 | int fd = open(buf_ptr(full_path), |
| | 1861 | need_write ? (O_RDWR|O_CLOEXEC|O_CREAT) : (O_RDONLY|O_CLOEXEC), mode); |
| 1778 | if (fd == -1) { | 1862 | if (fd == -1) { |
| 1779 | switch (errno) { | 1863 | switch (errno) { |
| 1780 | case EINTR: | 1864 | case EINTR: |
| ... | @@ -1784,6 +1868,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { | ... | @@ -1784,6 +1868,7 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { |
| 1784 | case EFAULT: | 1868 | case EFAULT: |
| 1785 | zig_unreachable(); | 1869 | zig_unreachable(); |
| 1786 | case EACCES: | 1870 | case EACCES: |
| | 1871 | case EPERM: |
| 1787 | return ErrorAccess; | 1872 | return ErrorAccess; |
| 1788 | case EISDIR: | 1873 | case EISDIR: |
| 1789 | return ErrorIsDir; | 1874 | return ErrorIsDir; |
| ... | @@ -1813,12 +1898,21 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { | ... | @@ -1813,12 +1898,21 @@ Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { |
| 1813 | attr->mtime.sec = statbuf.st_mtim.tv_sec; | 1898 | attr->mtime.sec = statbuf.st_mtim.tv_sec; |
| 1814 | attr->mtime.nsec = statbuf.st_mtim.tv_nsec; | 1899 | attr->mtime.nsec = statbuf.st_mtim.tv_nsec; |
| 1815 | #endif | 1900 | #endif |
| | 1901 | attr->mode = statbuf.st_mode; |
| 1816 | } | 1902 | } |
| 1817 | return ErrorNone; | 1903 | return ErrorNone; |
| 1818 | } | 1904 | } |
| 1819 | #endif | 1905 | #endif |
| 1820 | } | 1906 | } |
| 1821 | | 1907 | |
| | 1908 | Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) { |
| | 1909 | return os_file_open_rw(full_path, out_file, attr, false, 0); |
| | 1910 | } |
| | 1911 | |
| | 1912 | Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_t mode) { |
| | 1913 | return os_file_open_rw(full_path, out_file, attr, true, mode); |
| | 1914 | } |
| | 1915 | |
| 1822 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | 1916 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1823 | #if defined(ZIG_OS_WINDOWS) | 1917 | #if defined(ZIG_OS_WINDOWS) |
| 1824 | for (;;) { | 1918 | for (;;) { |
| ... | @@ -1864,6 +1958,7 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { | ... | @@ -1864,6 +1958,7 @@ Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1864 | case EFAULT: | 1958 | case EFAULT: |
| 1865 | zig_unreachable(); | 1959 | zig_unreachable(); |
| 1866 | case EACCES: | 1960 | case EACCES: |
| | 1961 | case EPERM: |
| 1867 | return ErrorAccess; | 1962 | return ErrorAccess; |
| 1868 | case EISDIR: | 1963 | case EISDIR: |
| 1869 | return ErrorIsDir; | 1964 | return ErrorIsDir; |