… | |
… | |
835 | } |
835 | } |
836 | |
836 | |
837 | /*****************************************************************************/ |
837 | /*****************************************************************************/ |
838 | /* work around various missing functions */ |
838 | /* work around various missing functions */ |
839 | |
839 | |
840 | #if _POSIX_VERSION < 200809L |
|
|
841 | # define realpath(path,resolved_path) (errno = ENOSYS, 0) |
|
|
842 | #endif |
|
|
843 | |
|
|
844 | #if !HAVE_PREADWRITE |
840 | #if !HAVE_PREADWRITE |
845 | # undef pread |
841 | # undef pread |
846 | # undef pwrite |
842 | # undef pwrite |
847 | # define pread eio__pread |
843 | # define pread eio__pread |
848 | # define pwrite eio__pwrite |
844 | # define pwrite eio__pwrite |
… | |
… | |
1119 | count -= cnt; |
1115 | count -= cnt; |
1120 | } |
1116 | } |
1121 | } |
1117 | } |
1122 | |
1118 | |
1123 | return res; |
1119 | return res; |
|
|
1120 | } |
|
|
1121 | |
|
|
1122 | #ifdef PAGESIZE |
|
|
1123 | # define eio_pagesize() PAGESIZE |
|
|
1124 | #else |
|
|
1125 | static intptr_t |
|
|
1126 | eio_pagesize (void) |
|
|
1127 | { |
|
|
1128 | static intptr_t page; |
|
|
1129 | |
|
|
1130 | if (!page) |
|
|
1131 | page = sysconf (_SC_PAGESIZE); |
|
|
1132 | |
|
|
1133 | return page; |
|
|
1134 | } |
|
|
1135 | #endif |
|
|
1136 | |
|
|
1137 | static void |
|
|
1138 | eio_page_align (void **addr, size_t *length) |
|
|
1139 | { |
|
|
1140 | intptr_t mask = eio_pagesize () - 1; |
|
|
1141 | |
|
|
1142 | /* round down addr */ |
|
|
1143 | intptr_t adj = mask & (intptr_t)*addr; |
|
|
1144 | |
|
|
1145 | *addr = (void *)((intptr_t)*addr - adj); |
|
|
1146 | *length += adj; |
|
|
1147 | |
|
|
1148 | /* round up length */ |
|
|
1149 | *length = (*length + mask) & ~mask; |
|
|
1150 | } |
|
|
1151 | |
|
|
1152 | #if !_POSIX_MEMLOCK |
|
|
1153 | # define eio__mlockall(a) ((errno = ENOSYS), -1) |
|
|
1154 | #else |
|
|
1155 | |
|
|
1156 | static int |
|
|
1157 | eio__mlockall (int flags) |
|
|
1158 | { |
|
|
1159 | #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7 |
|
|
1160 | extern int mallopt (int, int); |
|
|
1161 | mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */ |
|
|
1162 | #endif |
|
|
1163 | |
|
|
1164 | if (EIO_MCL_CURRENT != MCL_CURRENT |
|
|
1165 | || EIO_MCL_FUTURE != MCL_FUTURE) |
|
|
1166 | { |
|
|
1167 | flags = 0 |
|
|
1168 | | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0) |
|
|
1169 | | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0); |
|
|
1170 | } |
|
|
1171 | |
|
|
1172 | return mlockall (flags); |
|
|
1173 | } |
|
|
1174 | #endif |
|
|
1175 | |
|
|
1176 | #if !_POSIX_MEMLOCK_RANGE |
|
|
1177 | # define eio__mlock(a,b) ((errno = ENOSYS), -1) |
|
|
1178 | #else |
|
|
1179 | |
|
|
1180 | static int |
|
|
1181 | eio__mlock (void *addr, size_t length) |
|
|
1182 | { |
|
|
1183 | eio_page_align (&addr, &length); |
|
|
1184 | |
|
|
1185 | return mlock (addr, length); |
|
|
1186 | } |
|
|
1187 | |
|
|
1188 | #endif |
|
|
1189 | |
|
|
1190 | #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) |
|
|
1191 | # define eio__msync(a,b,c) ((errno = ENOSYS), -1) |
|
|
1192 | #else |
|
|
1193 | |
|
|
1194 | static int |
|
|
1195 | eio__msync (void *mem, size_t len, int flags) |
|
|
1196 | { |
|
|
1197 | eio_page_align (&mem, &len); |
|
|
1198 | |
|
|
1199 | if (EIO_MS_ASYNC != MS_SYNC |
|
|
1200 | || EIO_MS_INVALIDATE != MS_INVALIDATE |
|
|
1201 | || EIO_MS_SYNC != MS_SYNC) |
|
|
1202 | { |
|
|
1203 | flags = 0 |
|
|
1204 | | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0) |
|
|
1205 | | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0) |
|
|
1206 | | (flags & EIO_MS_SYNC ? MS_SYNC : 0); |
|
|
1207 | } |
|
|
1208 | |
|
|
1209 | return msync (mem, len, flags); |
|
|
1210 | } |
|
|
1211 | |
|
|
1212 | #endif |
|
|
1213 | |
|
|
1214 | static int |
|
|
1215 | eio__mtouch (eio_req *req) |
|
|
1216 | { |
|
|
1217 | void *mem = req->ptr2; |
|
|
1218 | size_t len = req->size; |
|
|
1219 | int flags = req->int1; |
|
|
1220 | |
|
|
1221 | eio_page_align (&mem, &len); |
|
|
1222 | |
|
|
1223 | { |
|
|
1224 | intptr_t addr = (intptr_t)mem; |
|
|
1225 | intptr_t end = addr + len; |
|
|
1226 | intptr_t page = eio_pagesize (); |
|
|
1227 | |
|
|
1228 | if (addr < end) |
|
|
1229 | if (flags & EIO_MT_MODIFY) /* modify */ |
|
|
1230 | do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req)); |
|
|
1231 | else |
|
|
1232 | do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req)); |
|
|
1233 | } |
|
|
1234 | |
|
|
1235 | return 0; |
|
|
1236 | } |
|
|
1237 | |
|
|
1238 | /*****************************************************************************/ |
|
|
1239 | /* requests implemented outside eio_execute, because they are so large */ |
|
|
1240 | |
|
|
1241 | static void |
|
|
1242 | eio__realpath (eio_req *req, etp_worker *self) |
|
|
1243 | { |
|
|
1244 | char *rel = req->ptr1; |
|
|
1245 | char *res; |
|
|
1246 | char *tmp1, *tmp2; |
|
|
1247 | #if SYMLOOP_MAX > 32 |
|
|
1248 | int links = SYMLOOP_MAX; |
|
|
1249 | #else |
|
|
1250 | int links = 32; |
|
|
1251 | #endif |
|
|
1252 | |
|
|
1253 | req->result = -1; |
|
|
1254 | |
|
|
1255 | errno = EINVAL; |
|
|
1256 | if (!rel) |
|
|
1257 | return; |
|
|
1258 | |
|
|
1259 | errno = ENOENT; |
|
|
1260 | if (!*rel) |
|
|
1261 | return; |
|
|
1262 | |
|
|
1263 | if (!req->ptr2) |
|
|
1264 | { |
|
|
1265 | X_LOCK (wrklock); |
|
|
1266 | req->flags |= EIO_FLAG_PTR2_FREE; |
|
|
1267 | X_UNLOCK (wrklock); |
|
|
1268 | req->ptr2 = malloc (PATH_MAX * 3); |
|
|
1269 | |
|
|
1270 | errno = ENOMEM; |
|
|
1271 | if (!req->ptr2) |
|
|
1272 | return; |
|
|
1273 | } |
|
|
1274 | |
|
|
1275 | res = req->ptr2; |
|
|
1276 | tmp1 = res + PATH_MAX; |
|
|
1277 | tmp2 = tmp1 + PATH_MAX; |
|
|
1278 | |
|
|
1279 | if (*rel != '/') |
|
|
1280 | { |
|
|
1281 | if (!getcwd (res, PATH_MAX)) |
|
|
1282 | return; |
|
|
1283 | |
|
|
1284 | if (res [1]) /* only use if not / */ |
|
|
1285 | res += strlen (res); |
|
|
1286 | } |
|
|
1287 | |
|
|
1288 | while (*rel) |
|
|
1289 | { |
|
|
1290 | ssize_t len, linklen; |
|
|
1291 | char *beg = rel; |
|
|
1292 | |
|
|
1293 | while (*rel && *rel != '/') |
|
|
1294 | ++rel; |
|
|
1295 | |
|
|
1296 | len = rel - beg; |
|
|
1297 | |
|
|
1298 | if (!len) /* skip slashes */ |
|
|
1299 | { |
|
|
1300 | ++rel; |
|
|
1301 | continue; |
|
|
1302 | } |
|
|
1303 | |
|
|
1304 | if (beg [0] == '.') |
|
|
1305 | { |
|
|
1306 | if (len == 1) |
|
|
1307 | continue; /* . - nop */ |
|
|
1308 | |
|
|
1309 | if (beg [1] == '.' && len == 2) |
|
|
1310 | { |
|
|
1311 | /* .. - back up one component, if possible */ |
|
|
1312 | |
|
|
1313 | while (res != req->ptr2) |
|
|
1314 | if (*--res == '/') |
|
|
1315 | break; |
|
|
1316 | |
|
|
1317 | continue; |
|
|
1318 | } |
|
|
1319 | } |
|
|
1320 | |
|
|
1321 | errno = ENAMETOOLONG; |
|
|
1322 | if (res + 1 + len + 1 >= tmp1) |
|
|
1323 | return; |
|
|
1324 | |
|
|
1325 | /* copy one component */ |
|
|
1326 | *res = '/'; |
|
|
1327 | memcpy (res + 1, beg, len); |
|
|
1328 | |
|
|
1329 | /* zero-terminate, for readlink */ |
|
|
1330 | res [len + 1] = 0; |
|
|
1331 | |
|
|
1332 | /* now check if it's a symlink */ |
|
|
1333 | linklen = readlink (req->ptr2, tmp1, PATH_MAX); |
|
|
1334 | |
|
|
1335 | if (linklen < 0) |
|
|
1336 | { |
|
|
1337 | if (errno != EINVAL) |
|
|
1338 | return; |
|
|
1339 | |
|
|
1340 | /* it's a normal directory. hopefully */ |
|
|
1341 | res += len + 1; |
|
|
1342 | } |
|
|
1343 | else |
|
|
1344 | { |
|
|
1345 | /* yay, it was a symlink - build new path in tmp2 */ |
|
|
1346 | int rellen = strlen (rel); |
|
|
1347 | |
|
|
1348 | errno = ENAMETOOLONG; |
|
|
1349 | if (linklen + 1 + rellen >= PATH_MAX) |
|
|
1350 | return; |
|
|
1351 | |
|
|
1352 | if (*tmp1 == '/') |
|
|
1353 | res = req->ptr2; /* symlink resolves to an absolute path */ |
|
|
1354 | |
|
|
1355 | /* we need to be careful, as rel might point into tmp2 already */ |
|
|
1356 | memmove (tmp2 + linklen + 1, rel, rellen + 1); |
|
|
1357 | tmp2 [linklen] = '/'; |
|
|
1358 | memcpy (tmp2, tmp1, linklen); |
|
|
1359 | |
|
|
1360 | rel = tmp2; |
|
|
1361 | } |
|
|
1362 | } |
|
|
1363 | |
|
|
1364 | /* special case for the lone root path */ |
|
|
1365 | if (res == req->ptr2) |
|
|
1366 | *res++ = '/'; |
|
|
1367 | |
|
|
1368 | req->result = res - (char *)req->ptr2; |
|
|
1369 | req->ptr2 = realloc (req->ptr2, req->result); /* trade time for space savings */ |
1124 | } |
1370 | } |
1125 | |
1371 | |
1126 | static signed char |
1372 | static signed char |
1127 | eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) |
1373 | eio_dent_cmp (const eio_dirent *a, const eio_dirent *b) |
1128 | { |
1374 | { |
… | |
… | |
1488 | break; |
1734 | break; |
1489 | } |
1735 | } |
1490 | } |
1736 | } |
1491 | } |
1737 | } |
1492 | |
1738 | |
1493 | #ifdef PAGESIZE |
|
|
1494 | # define eio_pagesize() PAGESIZE |
|
|
1495 | #else |
|
|
1496 | static intptr_t |
|
|
1497 | eio_pagesize (void) |
|
|
1498 | { |
|
|
1499 | static intptr_t page; |
|
|
1500 | |
|
|
1501 | if (!page) |
|
|
1502 | page = sysconf (_SC_PAGESIZE); |
|
|
1503 | |
|
|
1504 | return page; |
|
|
1505 | } |
|
|
1506 | #endif |
|
|
1507 | |
|
|
1508 | static void |
|
|
1509 | eio_page_align (void **addr, size_t *length) |
|
|
1510 | { |
|
|
1511 | intptr_t mask = eio_pagesize () - 1; |
|
|
1512 | |
|
|
1513 | /* round down addr */ |
|
|
1514 | intptr_t adj = mask & (intptr_t)*addr; |
|
|
1515 | |
|
|
1516 | *addr = (void *)((intptr_t)*addr - adj); |
|
|
1517 | *length += adj; |
|
|
1518 | |
|
|
1519 | /* round up length */ |
|
|
1520 | *length = (*length + mask) & ~mask; |
|
|
1521 | } |
|
|
1522 | |
|
|
1523 | #if !_POSIX_MEMLOCK |
|
|
1524 | # define eio__mlockall(a) ((errno = ENOSYS), -1) |
|
|
1525 | #else |
|
|
1526 | |
|
|
1527 | static int |
|
|
1528 | eio__mlockall (int flags) |
|
|
1529 | { |
|
|
1530 | #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 7 |
|
|
1531 | extern int mallopt (int, int); |
|
|
1532 | mallopt (-6, 238); /* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=473812 */ |
|
|
1533 | #endif |
|
|
1534 | |
|
|
1535 | if (EIO_MCL_CURRENT != MCL_CURRENT |
|
|
1536 | || EIO_MCL_FUTURE != MCL_FUTURE) |
|
|
1537 | { |
|
|
1538 | flags = 0 |
|
|
1539 | | (flags & EIO_MCL_CURRENT ? MCL_CURRENT : 0) |
|
|
1540 | | (flags & EIO_MCL_FUTURE ? MCL_FUTURE : 0); |
|
|
1541 | } |
|
|
1542 | |
|
|
1543 | return mlockall (flags); |
|
|
1544 | } |
|
|
1545 | #endif |
|
|
1546 | |
|
|
1547 | #if !_POSIX_MEMLOCK_RANGE |
|
|
1548 | # define eio__mlock(a,b) ((errno = ENOSYS), -1) |
|
|
1549 | #else |
|
|
1550 | |
|
|
1551 | static int |
|
|
1552 | eio__mlock (void *addr, size_t length) |
|
|
1553 | { |
|
|
1554 | eio_page_align (&addr, &length); |
|
|
1555 | |
|
|
1556 | return mlock (addr, length); |
|
|
1557 | } |
|
|
1558 | |
|
|
1559 | #endif |
|
|
1560 | |
|
|
1561 | #if !(_POSIX_MAPPED_FILES && _POSIX_SYNCHRONIZED_IO) |
|
|
1562 | # define eio__msync(a,b,c) ((errno = ENOSYS), -1) |
|
|
1563 | #else |
|
|
1564 | |
|
|
1565 | static int |
|
|
1566 | eio__msync (void *mem, size_t len, int flags) |
|
|
1567 | { |
|
|
1568 | eio_page_align (&mem, &len); |
|
|
1569 | |
|
|
1570 | if (EIO_MS_ASYNC != MS_SYNC |
|
|
1571 | || EIO_MS_INVALIDATE != MS_INVALIDATE |
|
|
1572 | || EIO_MS_SYNC != MS_SYNC) |
|
|
1573 | { |
|
|
1574 | flags = 0 |
|
|
1575 | | (flags & EIO_MS_ASYNC ? MS_ASYNC : 0) |
|
|
1576 | | (flags & EIO_MS_INVALIDATE ? MS_INVALIDATE : 0) |
|
|
1577 | | (flags & EIO_MS_SYNC ? MS_SYNC : 0); |
|
|
1578 | } |
|
|
1579 | |
|
|
1580 | return msync (mem, len, flags); |
|
|
1581 | } |
|
|
1582 | |
|
|
1583 | #endif |
|
|
1584 | |
|
|
1585 | static int |
|
|
1586 | eio__mtouch (eio_req *req) |
|
|
1587 | { |
|
|
1588 | void *mem = req->ptr2; |
|
|
1589 | size_t len = req->size; |
|
|
1590 | int flags = req->int1; |
|
|
1591 | |
|
|
1592 | eio_page_align (&mem, &len); |
|
|
1593 | |
|
|
1594 | { |
|
|
1595 | intptr_t addr = (intptr_t)mem; |
|
|
1596 | intptr_t end = addr + len; |
|
|
1597 | intptr_t page = eio_pagesize (); |
|
|
1598 | |
|
|
1599 | if (addr < end) |
|
|
1600 | if (flags & EIO_MT_MODIFY) /* modify */ |
|
|
1601 | do { *((volatile sig_atomic_t *)addr) |= 0; } while ((addr += page) < len && !EIO_CANCELLED (req)); |
|
|
1602 | else |
|
|
1603 | do { *((volatile sig_atomic_t *)addr) ; } while ((addr += page) < len && !EIO_CANCELLED (req)); |
|
|
1604 | } |
|
|
1605 | |
|
|
1606 | return 0; |
|
|
1607 | } |
|
|
1608 | |
|
|
1609 | /*****************************************************************************/ |
1739 | /*****************************************************************************/ |
1610 | |
1740 | |
1611 | #define ALLOC(len) \ |
1741 | #define ALLOC(len) \ |
1612 | if (!req->ptr2) \ |
1742 | if (!req->ptr2) \ |
1613 | { \ |
1743 | { \ |
… | |
… | |
1778 | case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break; |
1908 | case EIO_RENAME: req->result = rename (req->ptr1, req->ptr2); break; |
1779 | case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break; |
1909 | case EIO_LINK: req->result = link (req->ptr1, req->ptr2); break; |
1780 | case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break; |
1910 | case EIO_SYMLINK: req->result = symlink (req->ptr1, req->ptr2); break; |
1781 | case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break; |
1911 | case EIO_MKNOD: req->result = mknod (req->ptr1, (mode_t)req->int2, (dev_t)req->offs); break; |
1782 | |
1912 | |
1783 | case EIO_REALPATH: req->flags |= EIO_FLAG_PTR2_FREE; |
1913 | case EIO_REALPATH: eio__realpath (req, self); break; |
1784 | req->ptr2 = realpath (req->ptr1, 0); |
|
|
1785 | req->result = req->ptr2 ? strlen (req->ptr2) : -1; |
|
|
1786 | break; |
|
|
1787 | |
1914 | |
1788 | case EIO_READLINK: ALLOC (PATH_MAX); |
1915 | case EIO_READLINK: ALLOC (PATH_MAX); |
1789 | req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break; |
1916 | req->result = readlink (req->ptr1, req->ptr2, PATH_MAX); break; |
1790 | |
1917 | |
1791 | case EIO_SYNC: req->result = 0; sync (); break; |
1918 | case EIO_SYNC: req->result = 0; sync (); break; |