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

sysopen#

פותח קובץ בדרך הרמה־נמוכה, מעביר מסיכת ביטים שלמה של MODE ישירות לקריאת המערכת open(2) הבסיסית.

sysopen הוא מוצא החירום למקרה ש־DWIM של מצב מחרוזת של open בדרך - כשצריך O_EXCL ליצירה־אם־לא־קיים אטומית, O_NOFOLLOW לסירוב ל־symlinks, O_NONBLOCK על FIFO, או כל דגל אחר שאין לו מחרוזת "<" / ">" / ">>" מתאימה. קבועי הדגלים חיים ב־Fcntl ומשולבים עם |.

תקציר#

sysopen FILEHANDLE, FILENAME, MODE
sysopen FILEHANDLE, FILENAME, MODE, PERMS

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

1 בהצלחה, undef בכשל (כאשר $! מוגדר ל־errno מה־syscall שנכשל). שלא כמו open, אין קסם - FILENAME נלקח מילולית, אף >, <, |, או - מובילים אינם מפורשים, אף מחרוזת מצב שכבתית אינה מנותחת.

אם FILEHANDLE הוא סקלר לא־מוגדר, הוא מאוטוויפיק למטפל רענן:

sysopen my $fh, $path, O_RDONLY
    or die "sysopen $path: $!";

MODE - מסיכת הביטים של Fcntl#

MODE הוא מספר שלם הנבנה על ידי OR של קבועים מ־Fcntl. מצב הגישה הוא חובה ובלעדי הדדית; דגלי המתאם הם אופציונליים ומשולבים בחופשיות:

דגל

משמעות

O_RDONLY

פותח לקריאה בלבד.

O_WRONLY

פותח לכתיבה בלבד.

O_RDWR

פותח לקריאה ולכתיבה.

O_CREAT

יוצר את הקובץ אם הוא אינו קיים.

O_EXCL

עם O_CREAT: נכשל אם הקובץ כבר קיים.

O_APPEND

כל כתיבה מבצעת seek לסוף הקובץ תחילה (צירוף אטומי).

O_TRUNC

קוטם את הקובץ לאורך אפס בפתיחה.

O_NONBLOCK

מצב לא־חוסם עבור ה־descriptor המתקבל.

O_NOFOLLOW

נכשל עם ELOOP אם רכיב הנתיב הסופי הוא symlink.

יש לייבא אותם בשם או עם תג:

use Fcntl qw(O_RDWR O_CREAT O_EXCL O_APPEND);
# or
use Fcntl ':DEFAULT';

הערכים הישנים 0, 1, 2 עבור לקריאה־בלבד, לכתיבה־בלבד, קריאה־כתיבה עובדים גם בכל מערכת ש־Perl תומך בה, אך יש לתת שם לקבועים - הקוד המתקבל שורד סקירה בין־פלטפורמית ונקרא ללא מילון מונחים.

PERMS - ביטי ההרשאה בזמן יצירה#

PERMS הוא מצב אוקטלי (כפי ש־chmod לוקח) המוחל על ה־inode רק כאשר O_CREAT יוצר בפועל את הקובץ. אם PERMS מושמט, Perl מעביר 0666. ה־umask של התהליך מוחל על ידי הקרנל מעל, כך ש־umask ברירת מחדל של 022 מניב 0644 על הדיסק.

sysopen my $fh, $path, O_WRONLY | O_CREAT | O_EXCL, 0600
    or die "create $path: $!";

אסור לכתוב 0644 כארגומנט PERMS ללא סיבה. 0644 קשיח מסיר כתיבת קבוצה אפילו ממשתמשים שהגדירו בכוונה umask סלחני; 0666 בתוספת ה־umask של המשתמש הוא ברירת המחדל הנישאת וזה מה ש־sysopen משתמש בו כשמשמיטים את הארגומנט לחלוטין.

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

  • $! - מוגדר בכשל ל־errno המוחזר על ידי open(2).

  • ${^OPEN} - תצורת השכבות של ה־pragma open. sysopen מחיל את אותה מחסנית PerlIO ברירת מחדל ש־open היה מחיל עבור קריאה ללא שכבות. יש להשתמש ב־binmode מיד אחרי sysopen מוצלח כשצריך לדרוס או להסיר שכבות (טיפוסי לקבצים בינאריים, sockets־כקבצים, או descriptors של O_NONBLOCK).

  • umask של תהליך - מסכל את PERMS כש־O_CREAT יוצר את הקובץ.

דוגמאות#

יצירה־אם־לא־קיים אטומית - הסיבה הקנונית לפנות ל־sysopen:

use Fcntl qw(O_WRONLY O_CREAT O_EXCL);
sysopen my $fh, "lock.pid", O_WRONLY | O_CREAT | O_EXCL, 0644
    or die "another instance is already running: $!";
print $fh "$$\n";
close $fh;

פתיחה־או־יצירה לקריאה/כתיבה, תוך שימור התוכן הקיים:

use Fcntl qw(O_RDWR O_CREAT);
sysopen my $fh, $path, O_RDWR | O_CREAT, 0666
    or die "sysopen $path: $!";

לוג רק־לצירוף עם ערובת הצירוף - כל כתיבה נוחתת ב־EOF ללא קשר לשילוב עם כותבים אחרים:

use Fcntl qw(O_WRONLY O_CREAT O_APPEND);
sysopen my $log, "/var/log/app.log", O_WRONLY | O_CREAT | O_APPEND, 0644
    or die "open log: $!";
print $log "startup\n";

פתיחת FIFO מבלי לחסום בלחיצת היד של צד הקורא:

use Fcntl qw(O_RDONLY O_NONBLOCK);
sysopen my $fifo, "/tmp/q", O_RDONLY | O_NONBLOCK
    or die "sysopen fifo: $!";

סירוב לעקוב אחרי symlink בעלה - שימושי בספריות שניתנות לכתיבה על ידי משתמשים לא־אמינים:

use Fcntl qw(O_RDONLY O_NOFOLLOW);
sysopen my $fh, "$dir/config", O_RDONLY | O_NOFOLLOW
    or die "sysopen config: $!";

כפייה של קלט/פלט ברמת בייט אחרי פתיחה - הסרה של כל שכבת :utf8 או :crlf שמחסנית PerlIO ברירת המחדל הייתה מתקינה אחרת:

sysopen my $fh, $path, O_RDONLY or die $!;
binmode $fh;

מקרי קצה#

  • O_EXCL ללא O_CREAT הוא no-op. בדיקת הבלעדיות מופעלת רק כש־O_CREAT מבקש מהקרנל ליצור את הקובץ. תמיד יש לכתוב אותם יחד: O_CREAT | O_EXCL.

  • O_EXCL אינו נעילה. הוא מונע פתיחה מוצלחת על קובץ שכבר קיים, לא יותר. ברגע שהקובץ קיים, כל sysopen עוקב עם O_CREAT | O_EXCL נכשל. הוא אינו מסדרל גישה לתוכן - יש להשתמש ב־flock לכך.

  • O_EXCL במערכות קבצים רשת. מימושי NFS משתנים; גרסאות NFS ישנות מאבדות בשקט את הסמנטיקה הבלעדית. אסור להסתמך על O_EXCL לרוחב NFSv2.

  • O_CREAT | O_EXCL ו־symlinks. כששני הדגלים מוגדרים, הקרנל מסרב לפתוח symlink קיים מראש ברכיב הנתיב הסופי. הוא אינו מגן על רכיבי נתיב ביניים; יש להשתמש ב־O_NOFOLLOW או לפתור את הספרייה עם opendir בתוספת סמנטיקת openat אם צריך זאת.

  • O_TRUNC עם O_RDONLY. ההתנהגות אינה מוגדרת על ידי POSIX. אסור לשלב אותם.

  • PERMS מושמט. ברירת המחדל היא 0666, ממוסכת על ידי umask. זה לא 0644. יש להשמיט את PERMS אלא אם רוצים באופן פעיל לדרוס את ה־umask של המשתמש.

  • FILEHANDLE כביטוי. אם FILEHANDLE הוא bareword, הוא מציין גלובל של חבילה. אם הוא ביטוי המוערך ל־glob, globref, או IO::Handle, המטפל הזה נפתח. אם הוא סקלר לא־מוגדר, מטפל רענן מאוטוויפיק לתוכו - הצורה הלקסיקלית בשימוש לאורך הדוגמאות האלה.

  • אין קסם ב־FILENAME. FILENAME של "-" פותח קובץ הנקרא מילולית -, לא STDIN. > מוביל פותח קובץ הנקרא מילולית >filename, לא כתיבה ל־filename. זוהי כל הנקודה של sysopen מול open.

  • שכבות PerlIO ברירת מחדל עדיין חלות. sysopen הוא ”רמה נמוכה“ יחסית למחרוזת המצב, לא יחסית ל־PerlIO. המטפל המתקבל כולל את אותה מחסנית שכבות כמו open ללא שכבות; יש לקרוא ל־binmode כדי לשנות אותה.

  • ביטוי FILEHANDLE סגור או לא־חוקי. מחזיר undef כאשר $! מוגדר (לרוב EBADF עבור descriptor קיים גרוע; ENOENT, EACCES, EEXIST, ELOOP עבור שגיאות ברמת הנתיב).

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

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

ראו גם#

  • open - פותח ברמה גבוהה יותר עם ניתוח מצב מחרוזת, pipes, - כ־STDIN / STDOUT, ומצבים שכבתיים; יש להשתמש בו אלא אם צריכים במיוחד דגל ש־sysopen חושף

  • fcntl - משנה דגלים על descriptor שכבר פתוח (לדוגמה, הגדרת O_NONBLOCK בדיעבד); חולק את אוצר הקבועים של Fcntl

  • sysread - קריאה לא־buffered; עובד על כל מטפל, לא רק על אחד שהושג מ־sysopen, למרות השם

  • syswrite - כתיבה לא־buffered, אותה הערה

  • Fcntl - המודול שמייצא קבועי O_* ואת התגים :DEFAULT / :flock / :mode

  • binmode - קובע או מסיר שכבות PerlIO על המטפל לאחר פתיחה

  • umask - מסיכת התהליך המחסירה ביטים מ־PERMS כש־O_CREAT יוצר את הקובץ