מטפלי קובץ, קבצים, ספריות

stat#

מקבל את מידע הסטטוס של קובץ.

stat מבקש ממערכת ההפעלה את רשומת המטא־נתונים של קובץ - גודל, בעלות, הרשאות, חותמות זמן, inode - ומחזיר אותה כרשימה בת 13 איברים. זוהי הפרימיטיב הבסיסי שמאחורי בדיקות הקבצים -X (-e, -f, -r, …), מאחורי מודולים כמו File::stat, ומאחורי כל סקריפט שצריך לבדוק קובץ מבלי לפתוח אותו. stat מבטל הפניות של symlinks ומדווח על היעד; יש להשתמש ב־lstat כדי לקבל את הקישור עצמו.

תקציר#

stat FILEHANDLE
stat EXPR
stat DIRHANDLE
stat
stat _

מה מקבלים בחזרה#

בהקשר רשימה, רשימה בת 13 איברים של שדות מספריים. בהקשר סקלר, בוליאני: אמת בהצלחה, שקר בכשל. בכל מקרה, בהצלחה ה־buffer של stat של הקרנל נשמר ב־cache במטפל הקובץ המיוחד _, ש־stat, lstat, או בדיקת -X עוקבים יכולים להשתמש בו מחדש ללא syscall חדש.

בכשל, הקשר רשימה מחזיר את הרשימה הריקה ו־$! מוגדר לערך errno מ־stat(2) שנכשל.

השדות, לפי הסדר:

אינדקס

שדה

משמעות

0

dev

מספר ההתקן של מערכת הקבצים המחזיקה את הקובץ

1

ino

מספר inode

2

mode

מצב קובץ - ביטי סוג וגם ביטי הרשאה משולבים

3

nlink

מספר הקישורים הקשיחים לקובץ

4

uid

מזהה משתמש מספרי של הבעלים

5

gid

מזהה קבוצה מספרי של הבעלים

6

rdev

מזהה התקן, עבור קבצים מיוחדים של תווים/בלוקים

7

size

גודל כולל בבייטים

8

atime

זמן הגישה האחרונה, שניות מאז ה־epoch (1970-01-01 00:00 GMT)

9

mtime

זמן השינוי האחרון, שניות מאז ה־epoch

10

ctime

זמן שינוי inode, שניות מאז ה־epoch - לא זמן יצירה

11

blksize

גודל בלוק קלט/פלט מועדף לקריאות/כתיבות כנגד הקובץ הזה

12

blocks

מספר בלוקי מערכת הקבצים שהוקצו בפועל (לרוב 512 בייטים כל אחד)

שדה 2 (mode) אורז גם את סוג הקובץ וגם את ביטי ההרשאה במספר אחד. יש למסך עם 07777 כדי לראות רק את ההרשאות; יש להשתמש בקבועי S_IF* ובמסייעי S_IS* מ־Fcntl כדי לבדוק את הסוג בצורה נישאת.

my $mode = (stat($filename))[2];
printf "permissions are %04o\n", $mode & 07777;

לא כל מערכת קבצים מאכלסת כל שדה. atime, blksize, ו־blocks עשויים לחזור כ־0 במערכות קבצים שאינן עוקבות אחריהם (לדוגמה כמה mounts של FUSE או מערכות קבצים רשת); ctime אינו ”זמן יצירה“ נישא - הוא עוקב אחר השינוי האחרון של ה־inode עצמו (הרשאות, בעלות, ספירת קישורים), לא מתי הקובץ נוצר לראשונה.

מצב גלובלי שהוא נוגע בו#

  • $_ - נקרא כאשר stat נקרא ללא ארגומנט. stat ללא EXPR מבצע stat על שם הקובץ המוחזק ב־$_, לא על מטפל ה־_ ב־cache.

  • $! - מוגדר ל־errno של ה־stat(2) syscall שנכשל כאשר הקריאה נכשלת.

  • מטפל הקובץ המיוחד _ - cache לכל מפרש של תוצאת stat, lstat, או -X מוצלחת אחרונה. העברת _ כארגומנט עושה שימוש חוזר ב־buffer ה־cached הזה ואינה מנפיקה syscall. קריאות מוצלחות מרעננות אותו; קריאות שנכשלו משאירות את התוכן הקודם במקום.

דוגמאות#

פירוק בסיסי בהקשר רשימה:

my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
    $atime, $mtime, $ctime, $blksize, $blocks) = stat($filename);

בחירת שדה יחיד עם פרוסת רשימה:

my $size  = (stat($filename))[7];
my $mtime = (stat($filename))[9];

הקשר סקלר כבדיקת קיום־ועוד־מטא־נתונים־קריאים:

if (stat($path)) {
    my $size = (stat _)[7];          # reuse the cached buffer
    print "size = $size\n";
} else {
    warn "stat $path: $!";
}

שימוש חוזר ב־cache לרוחב בדיקת -X ו־stat:

if (-x $file && (($d) = stat(_)) && $d < 0) {
    print "$file is executable NFS file\n";
}

גישה במאחזרים בעלי שם דרך File::stat:

use File::stat;
my $sb = stat($filename);
printf "file %s, size %s, perm %04o, mtime %s\n",
       $filename, $sb->size, $sb->mode & 07777,
       scalar localtime $sb->mtime;

פענוח ה־mode עם Fcntl:

use Fcntl ':mode';
my $mode = (stat($filename))[2];
printf "permissions %04o\n", S_IMODE($mode);
print "is a directory\n" if S_ISDIR($mode);

מקרי קצה#

  • ללא ארגומנט: stat; מבצע stat על $_, לא על מטפל ה־_ ב־cache. כדי לקרוא מחדש את ה־cache יש לכתוב stat(_) כשהקו התחתון הוא bareword מפורש.

  • ה־bareword _ הוא מיוחד: הוא מציין את ה־cache של stat, לא קובץ. ציטוט שלו (stat("_")) מבצע stat על קובץ הנקרא מילולית _ בספרייה הנוכחית.

  • Symlinks נעקבים: stat מדווח על היעד של symlink. עבור הקישור עצמו, יש להשתמש ב־lstat. symlink שבור גורם ל־stat להיכשל עם ENOENT; lstat על אותו נתיב מצליח.

  • צורת DIRHANDLE: העברת מטפל ספרייה מ־opendir מחזירה את ה־stat של הספרייה הפתוחה עצמה. לא כל פלטפורמה תומכת בזה; באלה שלא, הקריאה נכשלת ו־$! מוגדר.

  • מספרי inode עלולים לגלוש ממספרים שלמים: במערכות קבצים עם מספרי inode בני 64 ביט מעבר לטווח המספרים השלמים של Perl, ino מוחזר כמחרוזת עשרונית כדי לשמר את הערך המלא. יש להשוות מספרי inode עם eq, לא ==, כדי להישאר נכונים על מערכות הקבצים האלה. eq עובד בסדר גם על inodes מספריים.

  • ctime אינו זמן יצירה: זהו זמן שינוי ה־inode - מעודכן על ידי chmod, chown, rename, שינויי ספירת קישורים, וכתיבות הקובץ עצמן. Linux חושף זמן יצירה אמיתי (btime) דרך statx(2), אך זה אינו חלק מרשימת ההחזרה של stat.

  • שדות אפס במערכות קבצים מסוימות: atime (ב־mounts של noatime), blksize, ו־blocks עלולים להיות מדווחים כ־0. יש להתייחס ל־0 כ“לא זמין“, לא כערך משמעותי.

  • הקשר סקלר אינו מאכלס את _ בכשל: stat שנכשל משאיר את ה־buffer ה־cached הקודם ללא נגיעה. תמיד יש לבדוק את ערך ההחזרה לפני stat(_) או -X _ המשך.

  • חלונות race: המטא־נתונים המוחזרים הם תצלום מצב. כל דבר הפועל על נתיב על סמך תוצאת stat (בדיקות הרשאה, דפוסי TOCTOU) חייב להיכתב לסבול שינוי הקובץ בין ה־stat לפעולת ההמשך - או יותר טוב, לפתוח את הקובץ תחילה ולבצע stat על מטפל הקובץ.

הבדלים מהמקור#

תואם במלואו ל־Perl 5.42 במקור.

ראו גם#

  • lstat - כמו stat אך אינו עוקב אחר symlinks; מדווח על הקישור עצמו

  • אופרטורי בדיקת קובץ -X (-e, -f, -r, -w, -x, …) - בנויים מעל אותו buffer של stat; חולקים את ה־cache _ עם stat ו־lstat

  • chmod - משנה את ביטי ההרשאה המדווחים בשדה 2 (mode)

  • chown - משנה את ה־uid וה־gid המדווחים בשדות 4 ו־5

  • File::stat - מאחזרים בעלי שם ($sb->size, $sb->mtime, …) מעל אותה רשימה בת 13 שדות; use File::stat דורס את stat בתיחום הנוכחי

  • Fcntl - התג :mode מייצא את קבועי S_I* ומסייעי S_IS* לפענוח שדה 2