symlink#
יצירת קישור סימבולי ב־NEWFILE המצביע על המחרוזת OLDFILE.
symlink היא העטיפה הדקה סביב קריאת המערכת symlink(2) של POSIX. היא אינה מעתיקה דבר, אינה קוראת את OLDFILE, ואינה דורשת ש־OLDFILE יהיה קיים. היא כותבת רשומת ספרייה חדשה ב־NEWFILE שה־payload שלה הוא הבתים המילוליים של OLDFILE, והקרנל מאוחר יותר מפענח את ה־payload הזה בכל פעם שמשהו פותח, מבצע stat, או חוצה את הקישור.
תקציר#
symlink OLDFILE, NEWFILE
מה מקבלים בחזרה#
1 בהצלחה, 0 בכישלון (עם $! מוגדר). במערכות שאינן תומכות בקישורים סימבוליים כלל, symlink מעלה חריגה במקום להחזיר 0. כדי לבדוק תמיכה בזמן ריצה בלי למות, יש לעטוף קריאה לא־מזיקה ב־eval:
my $symlink_exists = eval { symlink("", ""); 1 };
תבנית ה־eval היא בדיקת היכולת האידיומטית - היא מריצה symlink שהוא no-op שתפקידו היחיד הוא להיכשל בזול בפלטפורמות שבהן הקריאה קיימת, ולזרוק בפלטפורמות שבהן היא אינה קיימת.
כיצד symlinks שונים מקישורים קשיחים#
symlink וקישור קשיח (link) נראים דומים מה־shell אך מתנהגים שונה מאוד:
linkיוצר רשומת ספרייה שנייה המצביעה על אותו inode. שני השמות שווים; מחיקת אחד מהם משאירה את הקובץ חי תחת השני.symlinkיוצרת קובץ זעיר מסוגlnkשתוכנו הוא שם נתיב. היעד נפתר לפי שם בכל חיפוש. שני השמות אינם שווים - ל־symlink יש inode משלו, ביטי הרשאות משלו (מתעלמים מהם בדרך כלל), וחותמות זמן משלו.
השלכות מעשיות:
OLDFILEנשמר מילה במילה. הוא אינו עובר קנוניזציה, אינו נפתר מול ספריית העבודה הנוכחית, ולא נבדק לקיום. ניתן ליצור symlink המצביע על נתיב שעדיין אינו קיים (symlink תלוי באוויר) והוא יתחיל לעבוד ברגע שהיעד מופיע.מכיוון ש־
OLDFILEהוא רק מחרוזת, הוא יכול להיות יחסי. יעדי symlink יחסיים נפתרים בזמן חיפוש יחסית לספרייה המכילה אתNEWFILE, לא ספריית העבודה הנוכחית של התהליך. זהו מקור ההפתעה הגדול ביותר.symlinks יכולים לחצות גבולות של מערכות קבצים. קישורים קשיחים אינם יכולים.
symlinks יכולים להצביע על ספריות. קישורים קשיחים לספריות אסורים בכל Unix מקובל.
unlinkעל symlink מסיר את הקישור, לא את היעד. כדי להסיר את היעד, יש לבצע unlink על נתיב היעד ישירות.
דוגמאות#
יצירת symlink לקובץ קיים:
symlink "/etc/hostname", "hostname.lnk"
or die "symlink failed: $!";
symlink תלוי באוויר - היעד עדיין אינו קיים, וזה בסדר:
symlink "/will/appear/later", "pending.lnk"
or die "symlink failed: $!";
# opening pending.lnk now fails with ENOENT;
# it will start working once /will/appear/later exists.
יעד יחסי נפתר מול ספריית הקישור, לא ה־cwd:
chdir "/var/log" or die $!;
symlink "syslog", "/tmp/current.lnk"
or die "symlink failed: $!";
# readlink("/tmp/current.lnk") eq "syslog"
# opening /tmp/current.lnk resolves syslog in /tmp, not /var/log.
symlink לספרייה - זה עובד, בניגוד ל־link:
symlink "/var/log", "logs"
or die "symlink failed: $!";
opendir my $dh, "logs" or die $!; # traverses the symlink
בדיקה והסרה של symlink בלי לגעת ביעד שלו:
my $target = readlink "hostname.lnk"; # the stored OLDFILE string
unlink "hostname.lnk" or die $!; # removes the link only
# /etc/hostname is untouched.
תבנית החלפה אטומית - להחליף symlink המצביע על ספריית המהדורה ה־״נוכחית״ על־ידי כתיבת symlink חדש ושינוי שמו על־פני הקודם:
symlink "release-2", "current.new" or die $!;
rename "current.new", "current" or die $!;
# rename over an existing symlink is atomic on POSIX filesystems.
מקרי קצה#
OLDFILEis stored verbatim. No normalisation, no resolution, no existence check.symlink "", "foo"succeeds on most systems and creates an empty-target symlink that every lookup rejects withENOENT. This is why the capability-probe idiom uses("", "")a cheap call that always fails on supporting platforms.
OLDFILEיחסי נפתר יחסית לספרייתNEWFILE, לא לספריית העבודה הנוכחית. אם בונים אתNEWFILEמנתיב יחסי, יש לחשוב בזהירות באיזו ספרייה הקרנל יראה אותו.NEWFILEכבר קיים → כישלון עם$!מוגדר ל־EEXIST. אין דגל ״החלף״; כדי לדרוס, יש לכתוב לשם רענן ולבצעrenameעל־פני הישן (אטומי).הרשאות על ה־symlink עצמו כמעט תמיד מתעלמים מהן. הקרנל אוכף את ההרשאות של היעד. ברוב מערכות הקבצים ה־symlink מדווח כ־
lrwxrwxrwxללא קשר למה ש־chmodנקרא עליו.statעוקב אחר symlinks,lstatלא. כדי לבחון את הקישור עצמו - את סוגו, את ספירת הקישורים שלו, את אורך מחרוזת היעד שלו - יש להשתמש ב־lstat. כדי לבחון על מה הקישור מצביע, יש להשתמש ב־stat.unlinkמסיר את הקישור, לא את היעד. אין דרך למחוק את היעד דרך ה־symlink אלא על־ידי פתרונו תחילה.פלטפורמות ללא תמיכה ב־symlink מעלות חריגה על כל קריאה, גם כזו שהייתה נכשלת אחרת. יש להשתמש בבדיקת ה־
evalהמוצגת לעיל במקום להניח ערך החזרה.מערכות קבצים ללא תמיכה ב־symlink (חלק מווריאנטים של FAT, חיבורי רשת מסוימים) נכשלות עם
EPERMאוEOPNOTSUPPגם בקרנל שמממש אתsymlink(2). יש לבדוק את$!בכישלון במקום להניח שהקריאה נדחתה מהסיבה הברורה.לולאות symlink אינן מזוהות בזמן היצירה.
symlink "a", "b"ולאחריוsymlink "b", "a"מצליחה; הלולאה צפה רק כאשר משהו מנסה לפתור אחד מהשמות, מה שנכשל עםELOOPלאחר שהקרנל מגיע לגבול המעקב שלו (בדרך כלל 40).
הבדלים מ־upstream#
תואם מלא ל־upstream Perl 5.42.
ראו גם#
link- ליצור קישור קשיח (אותו inode, אותה מערכת קבצים, קובץ בלבד); המקבילה המחמירה שלsymlinkreadlink- לקרוא את מחרוזת ה־OLDFILEהמאוחסנת ב־symlink בלי לפתור אותהlstat- לבצע stat על ה־symlink עצמו ולא על היעד שלו; הדרך היחידה לראות שנתיב הוא symlink מ־Perlstat- לבצע stat על מה שה־symlink מצביע עליו, תוך מעקב אחר שרשרת הקישוריםunlink- להסיר symlink (את הקישור, לא את היעד); גם הדרך להסיר symlink תלוי באוויר$!-errnoמוגדר בכישלון; יש לבחון אותו כדי להבחין ביןEEXIST,EPERM,EOPNOTSUPP,ENOENTעל ספריית האב