מעמקי ה-I/O ב-Windows (פרק 5) — המבנה הפנימי של NTFS: מערכת קבצים מתוך MFT

· עודכן בתאריך: · · Windows, NTFS, I/O, file system, MFT, kernel, .NET, troubleshooting

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 29 Jul 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI: 10.5281/zenodo.22175348)

מאמר זה מאוחסן בארכיון Zenodo. להלן גם ה-DOI שתמיד מפנה לגרסה האחרונה וגם ה-DOI המקובע לגרסה שאתם קוראים.

Go Komura (2026). מעמקי ה-I/O ב-Windows (פרק 5) — המבנה הפנימי של NTFS: מערכת קבצים מתוך MFT. KomuraSoft LLC. https://doi.org/10.5281/zenodo.22175348 https://comcomponent.com/he/blog/ntfs-internals-mft-structure/

DOI (הגרסה האחרונה)
10.5281/zenodo.22175348
DOI (הגרסה הזו)
10.5281/zenodo.22175349

בארבעת הפרקים עד כאן עקבנו אחרי איך בקשת I/O זורמת (פרקים 1–3) ואיך Cache Manager מקבל אותה (פרק 4). בסוף הבקשה מגיעה למערכת הקבצים. הפעם תור הדוגמה המובילה שלה, NTFS.

נקודת המבט משתנה. עד עכשיו הסיפור היה דינמי: זרימת בקשה. הפעם זה סיפור סטטי על איך נתונים מסודרים בדיסק. הזהות האמיתית של Zone.Identifier הבלתי נראה שמצורף לקובץ שהורד. למה העתקת עשרת אלפים קבצים קטנים איטית בהרבה מהעתקת קובץ אחד באותו גודל כולל. עד כמה באמת נכון ש”NTFS עם journal, אז זה בטוח”. הכול ניתן להסביר מהמבנה הזה.

זה פרק 5 בסדרה “מעמקי ה-I/O ב-Windows”.

רקע לקריאה של הפרק הזה: אם יש לכם את היסודות של IRP ומחסנית ההתקנים מפרק 1, הקריאה חלקה יותר. בכל זאת, כדי שאפשר יהיה לקרוא גם לבד, מגדירים קודם את המונחים מפרקים קודמים שמופיעים בגוף.

מונח בשורה אחת פירוט
IRP (I/O Request Packet) “תלוש בקשת I/O” שקריאת API כמו ReadFile הופכת אליו בתוך ה-kernel. נהגים מקבלים את התלוש ומעבדים פרק 1
I/O Manager ומחסנית התקנים רכיב ה-kernel שבונה IRP ומעביר אותו לפי הסדר לנהגים שערמו עד ההתקן היעד, והערמה עצמה פרק 1
Cache Manager רכיב שמחזיק תוכן קובץ בזיכרון, וכותב אחר כך לדיסק את מה ש-WriteFile כתב. הסיבה לכך ש”כתבתי עכשיו” לא אומר “כבר בדיסק” פרק 4

טבלה 1: מונחים מפרקים קודמים שהפרק הזה מניח

עוד דבר מפרק 1: שני השלבים cleanup (כשנסגר ה-handle האחרון) ו-close (כשכל הייחוסים בתוך ה-kernel נעלמו). נשתמש בהם בהסבר מחיקת קובץ בפרק 4.

1. קודם המסקנה

  • המרכז של NTFS הוא MFT (Master File Table). כל הקבצים מנוהלים כרשומות בפנקס שבתוך MFT, וכל המידע על קובץ נמצא “בתוך רשומת MFT” או “באזור מחוץ ל-MFT שהרשומה מצביעה עליו” (פרק 2).1
  • הישות של קובץ היא אוסף attributes. קובץ קטן נכנס כולו, כולל הנתונים, לתוך רשומת MFT (resident); קובץ גדול מחזיק רק הפניה לרצף clusters (non-resident). האיטיות בטיפול בהמון קבצים קטנים יוצאת מכאן (פרק 2).1
  • אפשר להחזיק כמה data streams. הנתונים הרגילים הם “stream בלי שם”, ואפשר stream נוסף בסינטקס filename:streamname. זו הזהות של Zone.Identifier (Mark of the Web) (פרק 3).2
  • גם שם הוא attribute. כמה שמות על אותה רשומה הם hard link. גם שם מקוצר 8.3 יושב שם כשם נוסף (פרק 4).34
  • reparse point הוא המנגנון הרשמי ל”פתחתי, ואז זה מקום אחר”. symbolic link, junction, ו-Files On-Demand של OneDrive כולם יישומים של נתונים עם tag (פרק 5).56
  • יש שני journals. $LogFile הוא לשחזור עקביות metadata (journal מקדים כדי לא להישבר), USN Journal הוא לתיעוד היסטוריית שינויים (פנקס של מה השתנה). התפקידים שונים לגמרי (פרק 6).78
  • “גודל” ו”גודל בדיסק” הם שני דברים. sparse ודחיסה מייצרים את הפער. גם הרקע ל”קובץ דחוס לא נהיה אסינכרוני” מפרק 2 נמצא כאן (פרק 7).910

ב-diagram, solid line מציינת relation שתמיד מתקיים ו-dashed line מציינת relation מותנה (התנאים מופיעים בהסבר של כל relation ב-detail page). הרשימה המלאה של ה-relations (סה”כ 35, כולל evidence ו-certainty) וההגדרות של ה-concepts המרכזיים נמצאות ב-detail page של ה-knowledge map (ביפנית). Data: JSON-LD / Turtle

2. הכול הוא רשומת MFT

2.1. הפנקס של ה-volume

כשמפרמטים volume של NTFS, נוצרים MFT (master file table) וסדרת קובצי metadata שמתחילים ב-$. ב-MFT יש לפחות רשומה אחת לכל קובץ ב-volume, וגם רשומה של MFT עצמה כלולה.1

volume של NTFSהרשומה מצביעה על המיקום$MFT: Master File Tableפנקס הרשומות של כל הקבצים (גם היא עצמה רשומה)אזור נתוני משתמש(איפה יושבים נתונים non-resident)$LogFile: journal טרנזקציות שלפעולות metadata (פרק 6)$Bitmap: מצב השימוש ב-clusters$Boot / $Secure / $UpCase וכו'קובצי metadata אחרים

איור 1: מבנה volume של NTFS. העיצוב הוא שגם מידע הניהול של מערכת הקבצים עצמה יושב כקבצים

מידע על קובץ (גודל, timestamps, הרשאות גישה, ואפילו תוכן הנתונים) נשמר בתוך רשומת MFT, או באזור מחוץ ל-MFT שהרשומה מתארת את מיקומו.1 כשמוחקים קובץ הרשומה מסומנת כפנויה וחוזרת לשימוש, אבל MFT עצמה לא מצטמצמת. בנוסף, כדי לשמור על MFT רציף שמור MFT zone; כשה-volume מתמלא מתחילה פרגמנטציה של MFT. גם סיפור תוחלת החיים הזה כתוב בתיעוד הרשמי.1

2.2. קובץ = אוסף attributes, resident ו-non-resident

תוכן file record הוא רשימת attributes. מידע סטנדרטי (timestamps וכו’), שם קובץ, אבטחה, ונתונים. כאן יש פיצול חשוב.

file record של MFT (פנקס של קובץ אחד)עד כמה מאות בתיםמעבר לזהattribute מידע סטנדרטיtimestamps ו-flagsattribute שם קובץ(אפשר כמה: פרק 4)attribute נתוניםהנתונים קטנים?residentגוף הנתונים נכנס לתוך הרשומהקריאה מסתיימת בגישה ל-MFT בלבדnon-residentברשומה רק הפניה לרצף clustersהנתונים עצמם באזור נתוני המשתמש

איור 2: file record הוא אוסף attributes. אם הנתונים קטנים הם resident בתוך הרשומה

קל יותר לראות איך תוכן אותה רשומה משתנה בין resident ל-non-resident אם שמים אותם זה מול זה.

non-resident: קובץ גדולמצביע על מיקוםמצביע על מיקוםfile record של MFT (אורך קבוע)מידע סטנדרטי / שם / אבטחה─────────────attribute נתונים = טבלת data runsרצף של מאיפה כמה clustersאזור נתוני משתמשrun 1: clusters רצופיםאזור נתוני משתמשrun 2: clusters רצופים במקום אחרresident: קובץ קטןfile record של MFT (אורך קבוע)מידע סטנדרטי / שם / אבטחה─────────────attribute נתונים = התוכן עצמוערך הגדרה=1 נכנס לכאן ישירותאין מקום נפרד בדיסקקריאה מסתיימת בגישה ל-MFT בלבד

איור 3: resident מול non-resident. ב-non-resident הרשומה מחזיקה רק טבלה של איפה יש כמה נתונים אמיתיים (data runs)

ככל שמספר ה-data runs גדל, קריאת קובץ אחד דורשת לעבור בין אזורים מפוזרים. זו הזהות של הפרגמנטציה בסעיף הבא.

מהמבנה הזה אפשר להסביר כמה תופעות שפוגשים בשטח.

  • למה העתקת 10,000 קבצים קטנים איטית. לכל קובץ יש יצירת רשומת MFT, רישום שם, והגדרת אבטחה. עבודת הפנקס שולטת יותר מהעברת הנתונים עצמה (וכל אחת מהן הופכת גם ליעד בדיקה של filters בפרק 6).
  • הזהות של פרגמנטציה. נתונים non-resident נרשמים כ”רצף של מקטעי clusters רצופים (runs)”. אם אין אזור רצוף, מספר ה-runs גדל, ומספר ה-seeks לקריאה גדל. זה פרגמנטציה. את סידור ה-runs אפשר לראות ב-fsutil file layout.
  • גם תיקייה לא מיוחדת. directory הוא “קובץ שמחזיק אינדקס משם קובץ למספר רשומת MFT”. על הפנקס, הכול יושב על אותו מנגנון.

3. נתונים הם רק stream אחד

3.1. קובץ אחד, כמה רצפי בתים

ב-NTFS קובץ אחד יכול להחזיק כמה data streams. מה שקוראים וכותבים בדרך כלל ב-ReadFile/WriteFile הוא default stream בלי שם, ובסינטקס filename:streamname אפשר ליצור alternate data stream (ADS).2

הקובץ report.docx (רשומת MFT אחת)default stream (בלי שם)= התוכן שרואים בדרך כלל:Zone.Identifierמידע מקור (Mark of the Web):שם כלשהומידע נוסף של האפליקציה

איור 4: כמה data streams. תצוגת הגודל ב-Explorer מראה רק את ה-default stream

ה-ADS הכי מוכר הוא Zone.Identifier. לקובץ שהורד בדפדפן נרשם ב-stream הזה המקור (למשל מהאינטרנט), וזה הופך לחומר לשיפוט של “Windows protected your PC” ב-SmartScreen ושל Protected View ב-Office. הצד הגלוי של המנגנון מכוסה ב”למה מופיע Windows protected your PC”. מאחור, זו פשוט NTFS stream.

3.2. מלכודות שמפתחים דורכים עליהן

  • לא רואים. לא בגודל ב-Explorer ולא ב-dir. בודקים ב-dir /r או ב-streams של Sysinternals.11
  • לא עוברים. ADS הוא יכולת של NTFS, ולכן בהעתקה ל-USB ב-FAT או דרך אחסון ענן הוא נוטה להיעלם. “האזהרה על הורדה נעלמה אחרי שהעתקתי” זה זה.
  • אפשר לפתוח גם מהאפליקציה שלכם. מספיק לכלול נקודתיים בנתיב, כמו CreateFile("data.txt:meta", ...) .2 זה נוח, אבל אתם מקבלים גם את תכונת “לא עובר”, ולכן זה לא מקום לגוף נתונים עסקיים.

באיור 2 כתבנו שאפשר כמה attributes של שם קובץ. בתוך אותו volume, כמה נתיבים מצביעים על קובץ אחד — זה hard link (CreateHardLink / mklink /H).3

אינדקס של C:\\backup\\אינדקס של C:\\app\\config-link.json → רשומה 1234config.json → רשומה 1234רשומת MFT 1234גוף הנתונים (או הפניה ל-runs)מספר קישורים: 2

איור 5: hard link. האינדקס של ה-directory מצביע על אותה רשומת MFT, ושניהם “אמיתיים”

שינוי דרך כל שם הוא אותו קובץ, ולכן התוכן מתיישר מיד.3 ומשמעות “מחיקה” משתנה: DeleteFile הוא “להוריד שם אחד”, והישות נעלמת רק כשהשם האחרון ירד, handles פתוחים נסגרו, וגם ייחוסים בתוך ה-kernel כמו section של memory map נעלמו כולם. שני השלבים מפרק 1, cleanup (ה-handle האחרון) ו-close (הייחוס האחרון), פועלים גם על תוחלת החיים של מחיקה. לתצוגת attributes יש גם מוזרות רשמית: שינוי attribute דרך קישור אחד לא בהכרח מעדכן את התצוגה הנראית דרך קישור אחר.3

4.2. שם 8.3: עוד שם מוסתר

בגלל תאימות היסטורית, NTFS יכולה לייצר אוטומטית שם מקוצר בפורמט 8.3 כמו REPORT~1.DOC לשם ארוך. גם זה יושב ברשומה כשם נוסף. בתיקייה עם הרבה קבצים, יצירת שם מקוצר והימנעות מהתנגשות עולות; אפשר לבטל יצירה ולהסיר שמות קיימים ב-fsutil 8dot3name (אם אפליקציה ישנה רשמה נתיב Registry בשם מקוצר זה נשבר, ולכן יש גם יכולת בדיקה לפני strip, וזה נקודה מעשית).4

חשוב: האם יש שם מקוצר תלוי בסביבה. ברירת המחדל נקבעת בערך Registry NtfsDisable8dot3NameCreation: 0 (מייצרים בכל ה-volumes), 1 (לא מייצרים באף volume), 2 (הגדרה לפי volume), 3 (לא מייצרים מחוץ ל-volume של המערכת).4 אם בוחרים 2 אפשר לעבור לפי volume, ולכן “ב-Windows תמיד יש שם מקוצר כמו PROGRA~1” לא נכון. לפני שכותבים קוד או נוהל שתלויים בשם מקוצר, בדקו את המצב הנוכחי ב-fsutil 8dot3name query C: (בלי volume זה ברירת המחדל המשותפת לכל ה-volumes).

מלכודות סביב נתיב ושם (MAX_PATH, שמות שמורים, נקודה בסוף) מכוסות ב”MAX_PATH ומלכודות של נתיבים ושמות קבצים ב-Windows”. אם מחברים את פתרון השמות מפרק 1 (Object Manager) לפרק הזה (שמות בתוך מערכת הקבצים), מתקבלת התמונה המלאה של “שם” ב-Windows.

5. reparse point: המנגנון של “פתחתי, ואז זה מקום אחר”

אפשר לשים reparse point על קובץ או directory. הישות היא attribute של “tag + נתונים שהמשתמש מגדיר”. כשמערכת הקבצים פותחת קובץ עם reparse point, הטיפול נחטף לפי ה-tag: filter driver שמבין את ה-tag לוקח את הטיפול, או שב-tag של החלפת שם פותרים מחדש לפי נתיב היעד.5

NTFSI/O ManagerאפליקציהNTFSI/O Managerאפליקציהמצא reparse point ביעדמחזיר tag ונתוניםfilter שמבין את ה-tagלוקח את הטיפול (פרק 6)alt[symbolic link / junction (החלפת שם)][tag שמנוהל בידי filter (קובץ ענן וכו')]CreateFile("C:\\data\\link.txt")IRP_MJ_CREATE (העולם של פרק 1)הנתיב האמיתי הוא כאןפותר מחדש לפי נתיב היעד

איור 6: פתרון reparse point. זה hook רשמי שמתערב בפעולת פתיחה

על המנגנון האחד הזה יושבות יכולות מוכרות.

  • symbolic link (mklink): שלט שמחזיק נתיב יעד. יכול להצביע גם ל-volume אחר או ל-UNC.6
  • junction / mount point: מנגנון ותיק שמחבר directory למיקום ב-volume מקומי אחר.3
  • Files On-Demand של OneDrive: קובץ בלי נתונים אמיתיים אצלכם מיוצג כ-reparse point, וברגע הפתיחה filter מוריד ומגיש את התוכן. זו הסיבה ל”רואים ב-Explorer, אבל בפתיחה רצה תקשורת” (מנגנון ה-filter עצמו בפרק 6).

נקודת זהירות אחת בפועל. “מה שמעבר לנתיב לא בהכרח המקום המקומי הזה”. כלי שעובר עץ רקורסיבית נכנס ללולאה ב-junction, סיכום גודל נספר פעמיים, גיבוי גורם להמון materialization בענן. קוד שלא מכיר reparse points דורך על אלה. נקודת הכניסה היא לבדוק את ה-attribute FILE_ATTRIBUTE_REPARSE_POINT ב-FindFirstFile.5

6. שני journals: $LogFile ו-USN

אומרים הרבה ש”NTFS היא journaling file system”, אבל ל-NTFS יש שני journals עם תפקידים שונים. אם מערבבים, קוראים לא נכון את מה שמובטח.

USN Journal: היסטוריית שינויים (כדי לדעת מה השתנה)בכל שינוי לקובץ / directoryרושמים תוכן השינוי ושםגיבוי, אינדקס חיפוש וכלי סנכרוןיודעים מה השתנה מאז הפעם הקודמת בלי סריקה מלאה$LogFile: journal מקדים (כדי לא להישבר)לפני פעולת metadata (עדכון רשומה, שינוי שם וכו')רושמים ל-logאחרי כשל מערכת, באתחול הבאמריצים את ה-log ומשחזרים עקביות מבנה

איור 7: שני journals. $LogFile כדי לא להישבר, USN כדי לדעת מה השתנה

ההבדל בטבלה:

זווית $LogFile (transaction log) USN Journal (change journal)
מטרה אחרי כשל להחזיר את מבנה מערכת הקבצים למצב עקבי7 לדעת אחר כך “מה השתנה מאז הפעם הקודמת”8
מה נרשם journal מקדים של פעולות metadata (עדכון רשומה, שינוי שם וכו’). תוכן הקובץ לא ביעד בכל שינוי, תוכן השינוי ושם הקובץ / directory היעד8
מי משתמש NTFS עצמה. לשחזור אוטומטי ב-mount הבא אפליקציות כמו גיבוי, אינדקס חיפוש, כלי סנכרון
כמה רחוק אפשר לחזור רק מה שצריך לשחזור. גודל קבוע שממחזרים, ולכן לא מתאים להיסטוריה ארוכה כשעוברים את MaximumSize, ברשומות ישנות נגזרות ב-checkpoint. טווח החזרה תלוי בהגדרת הגודל ובכמות העדכונים ב-volume12
איך מסתכלים אין אמצעי רשמי לקרוא את התוכן (אפשר לבדוק גודל ב-chkdsk /L) מצב ב-fsutil usn queryjournal, תוכן ב-fsutil usn readjournal. מתוכנית: FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL12
אפשר לעצור אי אפשר (חלק מ-NTFS) admin יכול למחוק / לכבות. אבל זה כופה סריקה מלאה על שירותים שמשתמשים בזה, וההשפעה גדולה12

טבלה 2: שני journals זה מול זה

  • $LogFile (transaction log) הוא journal מקדים של פעולות metadata. גם אחרי כשל מערכת, NTFS משחזרת עקביות מערכת הקבצים אוטומטית מה-log וממידע checkpoint באתחול הבא.7 מה שמוגן כאן הוא מבנה. כמו בפרק 4, תוכן נתונים dirty במטמון יכול להיעלם בניתוק חשמל. הקריאה הנכונה: “ה-volume לא נשבר. אבל הכתיבה האחרונה יכולה להיעלם”.
  • USN Journal (change journal) הוא פנקס שרושם בכל שינוי לקובץ או directory ב-volume את תוכן השינוי ושם היעד.8 גיבוי ו-indexer אוספים רק מה שהשתנה מאז הפעם הקודמת, בלי סריקה מלאה, וזה משמש גם כדי להימנע מבניית אינדקס מחדש אחרי כשל.8 בפועל שווה לזכור שאפשר להשתמש ב-fsutil usn readjournal כפנקס התאמה לחקירה של החמצות ב-FileSystemWatcher (“מדריך מעשי ל-FileSystemWatcher”).

7. sparse ודחיסה: יש שני “גדלים”

ב-NTFS, האורך הלוגי של קובץ והאזור שבאמת הוקצה מנוהלים בנפרד. במסך המאפיינים זה “גודל” ו”גודל בדיסק”. שני נציגים מייצרים את הפער.

קובץ sparse לא מקצה אזור אמיתי לטווחים שנמשכים כאפסים, ומנהל אותם כחורים.9 קובץ דיסק וירטואלי בגודל לוגי 42GB שעל הדיסק תופס 500MB קורה באופן רגיל. קריאת חור מחזירה אפסים; כתיבה מקצה רק את החלק הזה.

הקצאה בדיסק (15MB + מידע ניהול)קובץ לוגי (גודל: 1GB)run: הישות של R1run: הישות של R2נתונים 10MBחור (אפסים) 500MBנתונים 5MBחור (אפסים) השאר

איור 8: קובץ sparse. לחורים אין הקצאה, והגודל הלוגי נפרד מהגודל בדיסק

דחיסת NTFS דוחסת ומאחסנת לפי יחידת דחיסה.10 זה שקוף ונוח, אבל גם העלות שקופה: בכל קריאה וכתיבה רצים decompress ודחיסה מחדש, ופרגמנטציה מתקדמת בקלות. וכמו בפרק 2 פרק 5, גישה לקובץ דחוס לא נהיית אסינכרונית (מערכת הקבצים ממירה לסינכרוני). זה אחד המקומות לחשוד כש”הפכתי ל-I/O אסינכרוני והקובץ לא ממהר”.

את הגודל האמיתי לפי הקצאה לוקחים ב-GetCompressedFileSize. בחקירה ש“סכום גדלי הקבצים” לא מתאים ל”שימוש בדיסק”, חושדים לפי הסדר בארבעה: sparse, דחיסה, ADS (פרק 3), ועיגול ל-cluster.

8. לראות בעצמכם

גם הפעם אפשר לצפות בהכול ב-Windows אצלכם (חלק דורש הרשאות admin). לכל פקודה מצורף איפה להסתכל ומה זה אומר, כדי שתוכלו לשפוט לבד אם התוצאה נכונה.

:: לראות alternate data streams
dir /r C:\Users\%USERNAME%\Downloads

איפה להסתכל: מתחת לשורת קובץ רגילה מופיעות שורות מוזחות בצורה filename:Zone.Identifier:$DATA עם אורך. אם יש שורה כזו, לקובץ יש Mark of the Web (פרק 3). לקובץ שהורד בדפדפן זה מצורף; לקובץ שיצרתם בעצמכם לא. אם מריצים בשני המקומות ומשווים, קיום ADS מתבהר.

:: לראות פריסה (runs) ו-attributes על MFT
fsutil file layout C:\path\to\file.dat

:: רק extents (תת-פקודה שמופיעה בתיעוד הרשמי)
fsutil file queryextents C:\path\to\file.dat

איפה להסתכל: layout מציג לכל stream גודל, גודל מוקצה, ואם non-resident גם רשימת extents (זוגות VCN, LCN, מספר clusters). קובץ קטן מאוד בלי שורות extent הוא resident (סעיף 2.2); כמה שורות אומרות פרגמנטציה. הדרך הקצרה ביותר להרגיש resident / non-resident היא להריץ על קובץ טקסט של כמה בתים ועל קובץ של מאות MB ולהשוות.

:: הגדרת יצירת שם מקוצר 8.3, ושמות מקוצרים קיימים
fsutil 8dot3name query C:
dir /x

איפה להסתכל: query מחזיר אם יצירת שם מקוצר דלוקה או כבויה ב-volume הזה (בלי volume זו ברירת המחדל המשותפת).4 dir /x מציג עמודה של שם מקוצר ליד השם הארוך; עמודה ריקה אומרת ששם מקוצר לא נוצר. כך בודקים אצלכם את “לא בהכרח יש שם מקוצר” מסעיף 4.2.

:: מצב USN Journal
fsutil usn queryjournal C:

איפה להסתכל: מוצגים journal ID, טווח USN תקף (First USN / Next USN), MaximumSize ו-AllocationDelta.12 אחרי שיוצרים קובץ ומריצים שוב, Next USN אמור להתקדם. זו בדיקה ש”השינוי נרשם”. MaximumSize הוא מדד ל”כמה רחוק אפשר לחזור” מפרק 6. ב-volume שבו ה-journal כבוי תקבלו שגיאה.

:: בדיקת reparse point (יעד ו-tag)
dir /aL C:\Users\%USERNAME%
fsutil reparsepoint query "C:\Users\%USERNAME%\OneDrive"

איפה להסתכל: מה שמופיע ב-dir /aL הוא reparse point (עם FILE_ATTRIBUTE_REPARSE_POINT). symbolic link ו-junction מוצגים עם סוג כמו <SYMLINKD> <JUNCTION>. fsutil reparsepoint query מציג את ערך ה-reparse tag, ובסוג החלפת שם גם את נתיב היעד. יעד שאינו reparse point מחזיר שגיאה, ועצם השגיאה היא בדיקה שזו תיקייה רגילה.

אם עוקבים אחרי פעולת קובץ ב-Procmon, הדמויות מהפרק הזה זורמות בשמן האמיתי (כתיבה ל-$LogFile, נתיב עם שם stream, טיפול reparse). לשימוש ראו “מדריך מעשי ל-Process Monitor (ProcMon)”.

9. סיכום

  • המרכז של NTFS הוא MFT. כל הקבצים הם רשומות בפנקס, והמידע נמצא “בתוך הרשומה” או “באזור חיצוני שהרשומה מצביעה עליו”. נתונים קטנים resident, נתונים גדולים הפניה ל-runs, והאיטיות בטיפול בהמון קבצים קטנים והפרגמנטציה הם תוצאה של המבנה הזה.1
  • אפשר כמה data streams. Zone.Identifier (Mark of the Web) הוא פשוט ADS, נראה ב-dir /r, ולא עובר מחוץ ל-NTFS.211
  • שם הוא attribute, ואפשר כמה. hard link הוא שם באותו מעמד לאותה רשומה, ושם 8.3 הוא שם נוסף לתאימות. “מחיקה = להוריד שם”, והישות נעלמת כשהשם האחרון, ה-handles, והייחוסים בתוך ה-kernel (כמו mapped section) נעלמו כולם.34
  • reparse point הוא hook רשמי על פתיחה, ו-symbolic link, junction ו-Files On-Demand הם יישומים שלו. קוד שעובר עץ צריך להיות מודע ל-FILE_ATTRIBUTE_REPARSE_POINT.56
  • יש שני journals. $LogFile משחזר עקביות מבנה (לא להישבר), USN הוא היסטוריית שינויים (מה השתנה). “יש journaling ולכן גם הנתונים בטוחים” לא נכון: עמידות הנתונים בונים בכלים מפרק 4.78
  • גודל לוגי והקצאה הם שני דברים. sparse, דחיסה, ADS ועיגול ל-cluster הם ארבע הסיבות העיקריות ל”הגדלים לא מסתכמים”. כולל העניין שקובץ דחוס לא נהיה I/O אסינכרוני, זה מגירה לחקירת ביצועים.910

ההמשך בפרק האחרון, פרק 6 “filter drivers ו-minifilter: למה Procmon וסריקת אנטי-וירוס יכולים להתערב ב-I/O”. אלה שיושבים באמצע מאז פרק 1: אנטי-וירוס, Procmon, OneDrive, הצפנה. איך הם מתערבים ב-I/O. סגירת הסדרה: מי הם הדיירים שעומדים ברווח של מחסנית ההתקנים.

מאמרים קשורים

תחומי ייעוץ קשורים

ב-KomuraSoft LLC מטפלים בתכנון ובחקירה של אפליקציות Windows עסקיות שנשענות על מנגנוני NTFS: התנהגות מוזרה של גודל קובץ או ביצועי העתקה, ותקלות סביב links ו-streams.

מקורות

  1. Microsoft Learn, Master File Table. לכל קובץ ב-volume של NTFS יש לפחות רשומה אחת ב-MFT, כולל רשומה של MFT עצמה. כל המידע על הקובץ (גודל, timestamps, הרשאות גישה, תוכן נתונים) נשמר בתוך רשומת MFT או באזור מחוץ ל-MFT שהרשומה מתארת את מיקומו. במחיקת קובץ הרשומה מסומנת כפנויה וחוזרת לשימוש, אבל גודל MFT לא מצטמצם. שמור MFT zone כדי לשמור על MFT רציף, ועם התקדמות ההקצאה מתחילה פרגמנטציה של MFT. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  2. Microsoft Learn, File Streams. נתוני קובץ ב-NTFS נשמרים כ-stream אחד או יותר. יש default data stream (בלי שם) ו-alternate data streams עם שם. אפשר לציין stream בפורמט filename:streamname ולפתוח ב-CreateFile. ↩ ↩2 ↩3 ↩4

  3. Microsoft Learn, fsutil 8dot3name. NTFS יכולה לייצר שם מקוצר בפורמט 8.3 לשם ארוך. ב-fsutil 8dot3name אפשר לבדוק ולהגדיר יצירה, להסיר שמות מקוצרים קיימים (strip), ולסרוק הפניות Registry שיושפעו מההסרה. ↩ ↩2 ↩3 ↩4 ↩5

  4. Microsoft Learn, Reparse points. reparse point הוא אוסף של נתונים שהמשתמש מגדיר ו-reparse tag שמזהה באופן ייחודי את פורמט הנתונים. בפתיחת קובץ עם reparse point מערכת הקבצים מנסה טיפול שמתאים ל-tag (טיפול בידי file system filter שמפרש את ה-tag). משמש למימוש קישורים במערכת הקבצים של NTFS ולאחסון מרוחק (hierarchical storage). אפשר לבדוק קיום ב-attribute FILE_ATTRIBUTE_REPARSE_POINT. ↩ ↩2 ↩3 ↩4

  5. Microsoft Learn, NTFS overview. NTFS משתמשת בקובץ log ובמידע checkpoint, ובמקרה של כשל מערכת מריצה את ה-transaction log באתחול הבא ומשחזרת אוטומטית את עקביות מערכת הקבצים. יש גם מיפוי דינמי מחדש של sectors פגומים, ו-self-healing NTFS שמתקן נזק קל ברקע. ↩ ↩2 ↩3 ↩4

  6. Microsoft Learn, Change Journals. בכל שינוי לקובץ או directory ב-volume נרשמים תוכן השינוי ושם היעד ב-USN change journal של אותו volume. ה-journal נשמר לפי volume. אפשר להשתמש בו לשחזור אינדקס מערכת קבצים אחרי כשל ולהימנע מאינדוקס מחדש של כל ה-volume. ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  7. Microsoft Learn, Sparse Files. בקובץ sparse לא מקצים שטח דיסק פיזי לטווחים גדולים שמורכבים מאפסים, ומקצים אזור רק לחלקים שמכילים נתונים. קריאת טווח בלי הקצאה מחזירה אפסים. ↩ ↩2 ↩3

  8. Microsoft Learn, File Compression and Decompression. דחיסת קבצים של NTFS נעשית בשקיפות, והנתונים נדחסים ומאוחסנים לפי יחידת דחיסה. ב-GetCompressedFileSize אפשר לקבל את הגודל אחרי דחיסה (הקצאה אמיתית). קריאה וכתיבה של קובץ דחוס מלוות בעלות decompress ודחיסה מחדש. ↩ ↩2 ↩3

  9. Microsoft Learn, Streams - Sysinternals. כלי streams של Sysinternals יכול למנות ולמחוק alternate data streams של קובץ NTFS. ↩ ↩2

  10. Microsoft Learn, Creating, Modifying, and Deleting a Change Journal ו-fsutil usn. MaximumSize של change journal הוא ערך יעד, וכשהגודל חורג מסכום MaximumSize ו-AllocationDelta הוא נגזר ב-checkpoint של NTFS. AllocationDelta הוא יחידת ההוספה לסוף ה-journal והמחיקה מההתחלה. ב-fsutil usn queryjournal אפשר לעיין במצב ובקיבולת, וב-readjournal בתוכן הרשום. מתוכנית משתמשים ב-FSCTL_CREATE_USN_JOURNAL / FSCTL_QUERY_USN_JOURNAL / FSCTL_READ_USN_JOURNAL / FSCTL_DELETE_USN_JOURNAL. מחיקה או כיבוי של journal פעיל מלווים בסריקת MFT כולה וכופים על שירותים שמשתמשים ב-journal סריקה מחדש של ה-volume. ↩ ↩2 ↩3 ↩4

מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.

העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.

המאמר קשור ישירות לשירותים הבאים.

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

מהי MFT (Master File Table)?
זו מבנה הנתונים בלב volume של NTFS: פנקס שמחזיק לפחות רשומה אחת (file record) לכל קובץ ב-volume, כולל רשומה ל-MFT עצמה. כל מה שקשור לקובץ, מגודל, timestamps והרשאות גישה ועד תוכן הנתונים עצמו, נשמר או בתוך רשומת MFT או באזור מחוץ ל-MFT שהרשומה מצביעה עליו. קובץ קטן נכנס כולו, כולל הנתונים, לתוך רשומת ה-MFT שלו (resident); לקובץ גדול נרשמת ברשומה רק הפניה לפריסת הנתונים (runs של clusters) (non-resident). מחיקת קובץ מסמנת את הרשומה כפנויה לשימוש חוזר, אבל גודל ה-MFT עצמו לא מצטמצם.
מהם נתוני Zone.Identifier הבלתי נראים שמצורפים לקבצים?
זה אחד מ-alternate data streams של NTFS. ב-NTFS קובץ אחד יכול להחזיק כמה רצפי בתים (streams); מה שקוראים וכותבים בדרך כלל הוא ה-stream ברירת המחדל בלי שם. Windows רושם מאיפה הקובץ הגיע, למשל שהורד מהאינטרנט, ב-stream נוסף שמציינים בנקודתיים, כמו file.txt:Zone.Identifier. זה מה שנקרא Mark of the Web, וזה מה ש-SmartScreen ותצוגה מוגנת של Office משתמשים בו כראיה. alternate streams לא מופיעים בתצוגת הגודל ב-Explorer; אפשר לבדוק אותם בפקודה dir /r או בכלי streams של Sysinternals. כדאי גם לשים לב שהם לא נשמרים כשמעתיקים למערכת קבצים שאינה NTFS, כמו FAT.
מה ההבדל בין hard link ל-symbolic link?
hard link הוא עוד שם באותו מעמד שנוסף, ומצביע על אותה ישות קובץ: אותה רשומת MFT. אפשר ליצור אותו רק בתוך אותו volume, גישה לקובץ דרך כל אחד משמותיו נותנת את אותו קובץ, ומחיקת שם אחד לא מסירה את הקובץ כל עוד שם אחר נשאר. symbolic link הוא שלט שמפנה לנתיב אחר, וממומש כ-reparse point. כי הוא מחזיק רק את נתיב היעד כמחרוזת, הוא יכול להצביע ל-volume אחר או אפילו למיקום מרוחק, אבל הופך למבוי סתום אם היעד נעלם. בפועל, כלל האצבע: hard link לשיתוף הישות הבסיסית (שמשנה את משמעות המחיקה), ו-symbolic link להפניית נתיב (להעברה או redirect).
NTFS היא journaling file system, אז הנתונים שורדים ניתוק חשמל?
צריך להבין בדיוק מה מוגן. מה שיומן הטרנזקציות של NTFS ($LogFile) מגן עליו הוא עקביות מבנה מערכת הקבצים (metadata). גם אם מתרחש כשל מערכת, NTFS משחזרת עקביות אוטומטית באמצעות ה-journal באתחול הבא, ומונעת מצב שבו ה-volume פגום ואינו ניתן לקריאה. אבל זה לא אומר שתוכן הקובץ שהיה באמצע כתיבה משוחזר. כמו שראינו בפרק 4 של הסדרה, נתונים dirty שיושבים במטמון אובדים בניתוק חשמל. לכן ההבנה הנכונה היא 'ה-volume לא יישבר, אבל תוכן הכתיבה האחרונה עדיין יכול להיעלם'. אם נדרשת עמידות לנתונים עצמם, צריך לבנות אותה בעצמכם, עם FlushFileBuffers, WRITE_THROUGH, או תכנון כתיבה ברמת האפליקציה כמו כתיבה לקובץ זמני ואז rename.
למה הגודל של קובץ שונה מהגודל בדיסק?
כי NTFS מנהלת בנפרד את האורך הלוגי של הקובץ ואת שטח הדיסק שמוקצה לו בפועל. גם בקובץ רגיל יש הבדל כלשהו כי ההקצאה מעוגלת כלפי מעלה ל-clusters שלמים (4KB כברירת מחדל), אבל קבצים sparse וקבצים דחוסים הם המקום שבו הפער נהיה גדול. קובץ sparse לא מקצה אחסון אמיתי לטווחים שנמשכים כאפסים: הוא מנהל אותם כחורים. כך שבהחלט אפשרי שקובץ בגודל לוגי של כמה GB ישתמש רק בכמה MB בדיסק. לקובץ דחוס מוקצה רק הגודל אחרי דחיסה. להפך, אם הגודל בדיסק נראה גדול יותר, עיגול ל-cluster או alternate data stream הם לעיתים קרובות הסיבה.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

מתמחה בפיתוח תוכנה עבור Windows, ייעוץ טכני וחקירת תקלות, בעיקר בפרויקטים עם מערכות קיימות ובאגים שקשה לשחזר.

קישורים ציבוריים

חזרה לבלוג