| 486 | // ── MOVE ───────────────────────────────────────────────────────────────────── |
| 487 | |
| 488 | void WebDAVHandler::handleMove(WebServer& s) { |
| 489 | String srcPath = getRequestPath(s); |
| 490 | String dstPath = getDestinationPath(s); |
| 491 | bool overwrite = getOverwrite(s); |
| 492 | |
| 493 | LOG_DBG("DAV", "MOVE %s -> %s (overwrite=%d)", srcPath.c_str(), dstPath.c_str(), overwrite); |
| 494 | |
| 495 | if (srcPath == "/" || srcPath.isEmpty()) { |
| 496 | s.send(403, "text/plain", "Cannot move root"); |
| 497 | return; |
| 498 | } |
| 499 | |
| 500 | if (isProtectedPath(srcPath) || isProtectedPath(dstPath)) { |
| 501 | s.send(403, "text/plain", "Forbidden"); |
| 502 | return; |
| 503 | } |
| 504 | |
| 505 | if (dstPath.isEmpty()) { |
| 506 | s.send(400, "text/plain", "Missing Destination header"); |
| 507 | return; |
| 508 | } |
| 509 | |
| 510 | if (srcPath == dstPath) { |
| 511 | s.send(204); |
| 512 | return; |
| 513 | } |
| 514 | |
| 515 | if (!Storage.exists(srcPath.c_str())) { |
| 516 | s.send(404, "text/plain", "Source not found"); |
| 517 | return; |
| 518 | } |
| 519 | |
| 520 | // Check destination parent exists |
| 521 | int lastSlash = dstPath.lastIndexOf('/'); |
| 522 | if (lastSlash > 0) { |
| 523 | String parentPath = dstPath.substring(0, lastSlash); |
| 524 | if (!parentPath.isEmpty() && !Storage.exists(parentPath.c_str())) { |
| 525 | s.send(409, "text/plain", "Destination parent does not exist"); |
| 526 | return; |
| 527 | } |
| 528 | } |
| 529 | |
| 530 | bool dstExists = Storage.exists(dstPath.c_str()); |
| 531 | if (dstExists && !overwrite) { |
| 532 | s.send(412, "text/plain", "Destination exists and Overwrite is F"); |
| 533 | return; |
| 534 | } |
| 535 | |
| 536 | if (dstExists) { |
| 537 | Storage.remove(dstPath.c_str()); |
| 538 | } |
| 539 | |
| 540 | HalFile file = Storage.open(srcPath.c_str()); |
| 541 | if (!file) { |
| 542 | s.send(500, "text/plain", "Failed to open source"); |
| 543 | return; |
| 544 | } |
| 545 | |