FileSharer 개발 노트 9 — 프로그램을 다시 켰을 때 공유 목록을 되살리는 방법

FileSharer 개발 노트 · 09 / 10

세 개발자가 임시 파일, 정식 저장본과 백업을 구분해 저장·복구 흐름을 설명합니다.
AI 일러스트 · 세 개발자가 임시 파일, 정식 저장본과 백업을 구분해 저장·복구 흐름을 설명합니다.

공유 링크가 프로그램을 다시 켤 때마다 사라지면 전달한 주소를 믿고 쓰기 어렵습니다. 그래서 FileSharer는 메모리의 공유 항목을 shares_db.txt에 저장하고 시작할 때 다시 읽습니다. 파일 하나로 저장하는 작은 도구에서도, “쓰면 된다”와 “중단돼도 복구된다”는 다른 요구사항입니다.

원본 WriteFileAtomic을 샘플 파일에 두 번 실행한 결과와 저장 순서를 정리한 설명도. 실제 공유 DB나 PIN·키 파일은 사용하지 않았습니다.
원본 WriteFileAtomic을 샘플 파일에 두 번 실행한 결과와 저장 순서를 정리한 설명도. 실제 공유 DB나 PIN·키 파일은 사용하지 않았습니다.

아래 샘플 결과는 실제 공유 DB 대신 두 문자열을 사용해 저장·백업 경로를 확인한 것입니다.

최종 파일을 바로 덮어쓰지 않는다

WriteFileAtomic은 먼저 같은 경로 옆의 .tmp 파일에 새 내용을 씁니다. 기존 파일이 있으면 File.Replace로 교체하면서 .bak에 직전 파일을 남깁니다. 원본의 우선 경로는 다음과 같습니다.

File.WriteAllLines(tmp, lines, Encoding.UTF8);
if (File.Exists(path))
{
    try { File.Replace(tmp, path, bak); return; }
    catch { }
}

뒤에는 교체가 실패했을 때 기존 파일을 백업 이름으로 옮기고 임시 파일을 최종 위치로 이동하는 대체 경로가 이어집니다. Microsoft의 File.Replace 문서는 대상 교체와 백업 생성을 설명하며, 서로 다른 볼륨에서의 제약도 안내합니다.

메서드 이름에 Atomic이 있다고 모든 경로와 정전 상황까지 하나의 불가분 작업이 되는 것은 아닙니다. 특히 여러 번의 이동으로 처리하는 대체 경로에는 중간 상태가 있습니다. 파일 시스템에 기록이 영속화되는 시점까지 이번 시험에서 검증한 것은 아닙니다.

두 번 저장하면 무엇이 남는가

샘플에서는 새 폴더에 generation-one을 저장한 뒤, 같은 경로에 generation-two를 저장합니다. 두 번째 저장 뒤의 파일 내용은 다음과 같습니다.

확인 대상 실제 내용
최종 파일 generation-two
.bak 파일 generation-one

샘플 결과에서는 정상적인 두 번째 저장에서 직전 세대가 남았습니다. 이 결과는 성공 경로에 한정되며, 전원 차단·권한 오류·용량 부족 상황의 복구까지 검증한 것은 아닙니다.

‘비어 있음’과 ‘없음’은 다른 복구 조건이다

LoadStoreFromDisk는 본 파일이 없으면 곧바로 반환합니다. 파일이 존재하지만 비어 있고 백업에 내용이 있으면 백업을 읽습니다. 따라서 .bak만 남아 있는 상황까지 자동으로 복구한다고 소개하면 정확하지 않습니다.

또 각 행의 일부 값은 bool.Parse, long.Parse, DateTime.Parse로 변환하고, 큰 범위의 바깥쪽에서 예외를 잡습니다. 중간 행 하나가 잘못됐을 때 나머지 정상 행을 어디까지 읽는지 점검할 필요가 있습니다. 행별 검증과 오류 기록을 두면 손상된 항목 하나가 복구 전체를 가리는 일을 줄일 수 있습니다.

현재 로더는 다시 읽은 항목 중 IsActive()가 true인 것만 메모리 사전에 넣습니다. 즉 디스크에 행이 남아 있어도 해제·만료·횟수 제한 상태에 따라 복원되는 목록은 달라집니다.

저장 성공은 코드 밖에도 알려야 한다

상위 SaveStoreToDisk는 예외를 잡고 별도 실패 결과를 반환하지 않습니다. 메모리에서는 새 공유가 보이지만 디스크 저장은 실패하는 상태가 가능하다는 뜻입니다. 재시작 뒤에야 문제를 알게 되면 원인을 찾기 어렵습니다.

개선한다면 저장 성공 여부를 호출자에게 돌려주고, 사용자에게 “현재 세션에서만 유지됨” 같은 상태를 표시할 수 있습니다. 동시에 여러 저장이 발생할 때 고정된 .tmp 이름을 공유해도 되는지, 읽은 스냅숏의 순서가 뒤바뀌지 않는지도 검토 대상입니다.

복구 자료에는 비밀도 함께 남는다

공유 저장 행에는 파일 경로뿐 아니라 PIN과 공유 암호화 키 필드가 포함됩니다. 백업에도 같은 종류의 정보가 남을 수 있습니다. 반면 터널 인증 값에는 Windows DPAPI를 사용하는 별도 코드가 있습니다. 두 저장 경로를 섞어 “모든 비밀이 암호화돼 저장된다”고 표현하면 안 됩니다.

DPAPI의 CurrentUser 범위는 현재 사용자 계정에 묶이는 보호 범위입니다. 의미는 Microsoft의 DataProtectionScope 문서에서 확인할 수 있습니다. 이를 다른 PC·다른 계정으로의 자동 복구 보장과 동일하게 해석해서도 안 됩니다.

작은 설정 저장소에서도 보관과 복구는 함께 설계해야 합니다. 정상 저장 결과만 확인하는 대신 본 파일 없음, 빈 파일, 손상된 한 행, 비밀이 포함된 백업을 각각 다른 상태로 다루는 것이 이 코드에서 이어 갈 다음 단계입니다.

소스 근거
FileSharer.cs:2661–2694 SaveStoreToDisk · FileSharer.cs:2704–2723 WriteFileAtomic · FileSharer.cs:2725–2794 LoadStoreFromDisk · FileSharer.cs:TailscaleTunnel.SaveAuthKey / LoadAuthKey

 

댓글