diff --git a/runtime/lib/webdav-scan-diagnostic.php b/runtime/lib/webdav-scan-diagnostic.php new file mode 100644 index 0000000..3bc3cf5 --- /dev/null +++ b/runtime/lib/webdav-scan-diagnostic.php @@ -0,0 +1,152 @@ +#!/usr/bin/env php +$meta) + { + if (!is_array($meta) || (string)($meta['kind'] ?? '') !== 'file') continue; + $mapped_files[$normalize($path)] = $meta; + } + + $shadow_links = 0; + $matched = 0; + $broken = 0; + $unmapped = 0; + $duplicates = 0; + $seen = array(); + $examples = array(); + + $iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($gallery_root, FilesystemIterator::SKIP_DOTS), + RecursiveIteratorIterator::LEAVES_ONLY + ); + foreach ($iterator as $item) + { + $shadow = $item->getPathname(); + if (!is_link($shadow)) continue; + $shadow_links++; + $resolved = realpath($shadow); + if ($resolved === false || !is_file($resolved)) + { + $broken++; + if (count($examples) < 8) $examples[] = array('state'=>'broken','shadow'=>$shadow); + continue; + } + $resolved = $normalize($resolved); + if (!isset($mapped_files[$resolved])) + { + $unmapped++; + if (count($examples) < 8) $examples[] = array('state'=>'unmapped','shadow'=>$shadow,'target'=>$resolved); + continue; + } + if (isset($seen[$resolved])) + { + $duplicates++; + if (count($examples) < 8) $examples[] = array('state'=>'duplicate','shadow'=>$shadow,'target'=>$resolved); + continue; + } + $seen[$resolved] = true; + $matched++; + if (count($examples) < 8) + { + $meta = $mapped_files[$resolved]; + $examples[] = array( + 'state'=>'matched', + 'shadow'=>$shadow, + 'target'=>$resolved, + 'fileid'=>(int)($meta['fileid'] ?? 0), + 'webdav_path'=>(string)($meta['webdav_path'] ?? ''), + 'etag'=>(string)($meta['etag'] ?? ''), + ); + } + } + + $payload = array( + 'ok'=>($shadow_links > 0 && $matched === $shadow_links && $broken === 0 && $unmapped === 0 && $duplicates === 0), + 'connection_id'=>$connection_id, + 'state_dir'=>$state_dir, + 'gallery_root'=>$gallery_root, + 'mapping_file'=>$mapping_file, + 'mapping_files'=>count($mapped_files), + 'shadow_links'=>$shadow_links, + 'matched'=>$matched, + 'broken'=>$broken, + 'unmapped'=>$unmapped, + 'duplicates'=>$duplicates, + 'examples'=>$examples, + ); + echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)."\n"; + exit($payload['ok'] ? 0 : 4); +} +catch (Throwable $e) +{ + echo json_encode(array( + 'ok'=>false, + 'connection_id'=>$connection_id, + 'fatal'=>$e->getMessage(), + ), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)."\n"; + exit(1); +}