| 557 | // ── COPY ───────────────────────────────────────────────────────────────────── |
| 558 | |
| 559 | void WebDAVHandler::handleCopy(WebServer& s) { |
| 560 | String srcPath = getRequestPath(s); |
| 561 | String dstPath = getDestinationPath(s); |
| 562 | bool overwrite = getOverwrite(s); |
| 563 | |
| 564 | LOG_DBG("DAV", "COPY %s -> %s (overwrite=%d)", srcPath.c_str(), dstPath.c_str(), overwrite); |
| 565 | |
| 566 | if (isProtectedPath(srcPath) || isProtectedPath(dstPath)) { |
| 567 | s.send(403, "text/plain", "Forbidden"); |
| 568 | return; |
| 569 | } |
| 570 | |
| 571 | if (dstPath.isEmpty()) { |
| 572 | s.send(400, "text/plain", "Missing Destination header"); |
| 573 | return; |
| 574 | } |
| 575 | |
| 576 | if (srcPath == dstPath) { |
| 577 | s.send(204); |
| 578 | return; |
| 579 | } |
| 580 | |
| 581 | if (!Storage.exists(srcPath.c_str())) { |
| 582 | s.send(404, "text/plain", "Source not found"); |
| 583 | return; |
| 584 | } |
| 585 | |
| 586 | HalFile srcFile = Storage.open(srcPath.c_str()); |
| 587 | if (!srcFile) { |
| 588 | s.send(500, "text/plain", "Failed to open source"); |
| 589 | return; |
| 590 | } |
| 591 | |
| 592 | if (srcFile.isDirectory()) { |
| 593 | srcFile.close(); |
| 594 | s.send(403, "text/plain", "Cannot copy directories"); |
| 595 | return; |
| 596 | } |
| 597 | |
| 598 | // Check destination parent exists |
| 599 | int lastSlash = dstPath.lastIndexOf('/'); |
| 600 | if (lastSlash > 0) { |
| 601 | String parentPath = dstPath.substring(0, lastSlash); |
| 602 | if (!parentPath.isEmpty() && !Storage.exists(parentPath.c_str())) { |
| 603 | srcFile.close(); |
| 604 | s.send(409, "text/plain", "Destination parent does not exist"); |
| 605 | return; |
| 606 | } |
| 607 | } |
| 608 | |
| 609 | bool dstExists = Storage.exists(dstPath.c_str()); |
| 610 | if (dstExists && !overwrite) { |
| 611 | srcFile.close(); |
| 612 | s.send(412, "text/plain", "Destination exists and Overwrite is F"); |
| 613 | return; |
| 614 | } |
| 615 | |
| 616 | if (dstExists) { |
nothing calls this directly
no test coverage detected