מערכות קבצים ושינוי מבנה¶
נניח שכלי גיבוי רואה קובץ בגודל לוגי של עשרה גיגה־בתים. האם עליו לקרוא עשרה גיגה־בתים מן ההתקן, והאם העתקה פשוטה תשמר את כל המידע הקשור לקובץ? התשובה תלויה בתכונות כגון sparse ranges, streams, קישורים ומאפייני מערכת הקבצים.
נתייחס ל־filesystem כאל מערכת שמספקת חוזים ויכולות, ולא רק כאל מחרוזת "NTFS" או "ReFS". יכולת יכולה להשתנות לפי גרסת מערכת, תצורת volume וה־API שבו משתמשים. שם המערכת הוא נקודת התחלה לשאלה, לא תחליף לבדיקת תמיכה.
שאילתת יכולות על היעד שנפתח¶
התוכנית הבאה מדפיסה את שם מערכת הקבצים וכמה דגלי יכולת. היא אינה משנה קובץ או volume:
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <array>
#include <iostream>
int wmain(int argc, wchar_t** argv) {
if (argc != 2) return 2;
HANDLE file = CreateFileW(argv[1], FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
if (file == INVALID_HANDLE_VALUE) return 1;
std::array<wchar_t, 256> name{};
DWORD serial = 0, component = 0, flags = 0;
if (!GetVolumeInformationByHandleW(file, nullptr, 0, &serial,
&component, &flags, name.data(),
static_cast<DWORD>(name.size()))) {
std::cerr << GetLastError() << '\n';
CloseHandle(file);
return 1;
}
std::wcout << L"filesystem=" << name.data() << L'\n';
std::cout << "sparse=" << bool(flags & FILE_SUPPORTS_SPARSE_FILES)
<< " streams=" << bool(flags & FILE_NAMED_STREAMS)
<< " reparse=" << bool(flags & FILE_SUPPORTS_REPARSE_POINTS)
<< " hardlinks=" << bool(flags & FILE_SUPPORTS_HARD_LINKS)
<< '\n';
CloseHandle(file);
}
הדגל מתאר יכולת של היעד בהקשר השאילתה, ולא אישור שהפעולה הבאה תצליח. הרשאות, סוג אובייקט ומצב מערכת יכולים עדיין לגרום לכשל. המימוש צריך לבדוק גם את תוצאת הפעולה עצמה.
גודל לוגי מול אחסון מוקצה¶
קובץ sparse יכול לתאר טווחים לוגיים שאינם מחזיקים אחסון פיזי רגיל לכל בית. קריאה מטווח חור מחזירה אפסים לפי החוזה. כלי שמעתיק את כל האפסים ככתיבות רגילות יכול להפוך קובץ חסכוני לקובץ שמקצה הרבה יותר מקום.
הפיכת קובץ חדש ל־sparse נעשית באמצעות FSCTL_SET_SPARSE כאשר המערכת תומכת בכך. לאחר מכן אפשר להרחיב גודל לוגי ולכתוב רק טווחים מסוימים. אין להסיק מגודל הקובץ לבדו כמה מקום הוא צורך, ובדיקת טווחים מוקצים דורשת API מתאים ותשומת לב לשינוי מקביל.
ניסוי בטוח יוצר קובץ חדש באמצעות CREATE_NEW, מסמן אותו כ־sparse, כותב בלוק בתחילתו ובלוק בסופו ומשווה בין גודל לוגי לאחסון מדווח. אם שם המעבדה כבר קיים, הניסוי נעצר במקום לדרוס מידע.
שם נוסף או הפניה נוספת¶
קישור קשיח הוא שם נוסף לאותו קובץ בהקשר מערכת הקבצים. שינוי דרך אחד השמות משפיע על אותו תוכן. לעומתו, reparse point מפעיל מנגנון פרשנות שיכול להפנות ליעד או להשתתף בתכונה אחרת. אין להניח שכל reparse point הוא symlink רגיל.
כלי סריקה צריך להגדיר האם הוא עוקב אחרי קישורים, כיצד הוא מונע מעגלים ואיך הוא מזהה אובייקט שכבר נסרק. השוואת מחרוזות נתיב בלבד אינה מספיקה כדי לזהות שני שמות לאותו קובץ. גם "אל תעקוב אחרי קישורים" דורש בדיקה בכל מקום הרלוונטי לפרוטוקול הפתיחה.
זרם נתונים חלופי הוא עוד דרך שבה שם קובץ אחד יכול להכיל מידע שאינו בזרם הראשי. כלי שמעתיק רק את bytes הזרם הראשי לא בהכרח משמר את כל ה־streams וה־metadata. השאלה אם לשמר אותם היא חלק מחוזה הכלי, ולא פרט מקרי.
יומן מערכת קבצים אינו יומן היישום¶
מנגנון journal של filesystem מסייע לשמור או לשחזר עקביות של מבני המערכת לפי חוזהו. הוא אינו מבטיח שכל עסקה עסקית של היישום תופיע בשלמותה אחרי קריסה. אם עסקה משנה שני קבצים, מערכת הקבצים אינה יודעת בהכרח שהשינויים שייכים לפעולה אחת.
גם USN journal מתאר שינויים לצורכי מעקב, ולא משמש עותק מלא של תוכן ישן שממנו אפשר לשחזר כל עסקה. נמשיך להשתמש ב־WAL של היישום כאשר נדרשת משמעות עסקית מוגדרת.
שינוי שם והחלפת תוכן¶
שינוי שם בתוך אותו volume יכול להיות פעולה יעילה של metadata, אבל חוזי החלפה, handles פתוחים ועמידות דורשים בדיקה של ה־API וה־filesystem. מעבר בין volumes עשוי להפוך להעתקה ומחיקה, ולכן אין להציגו כפעולה אטומית אחת.
דפוס של כתיבה לקובץ זמני ואז החלפה יכול לצמצם חלון של תוכן חלקי, אך צריך להגדיר flush, שימור הרשאות ומצב שבו הכשל קורה בין השלבים. עצם השימוש ב־ReplaceFile או ב־MoveFileEx אינו הוכחה שכל metadata ותוכן שרדו כל סוג כשל.
הניסוי הבא ב־watcher יראה שגם הודעות שינוי אינן עסקה מלאה. אנחנו צריכים לשמור על ההפרדה בין פעולה לוגית, שינוי שם ותצפית על שינוי.
קריאה להעמקה¶
התיעוד של שאילתת מידע volume, של קבצים דלילים ושל נקודות reparse מגדיר את המנגנונים. השוו NTFS ו־ReFS לפי התכונות שנבדקו ביעד, בלי להניח רשימת תמיכה קבועה לכל גרסה.