הרצאות שבוע #14- מערכות קבצים (חלק ה

‫שבוע ‪#14‬‬
‫פרק‪File System Implementation :‬‬
‫מימוש מערכת הקבצים – חלק אחרון‬
‫קורס מערכות הפעלה ב'‬
‫מכללת הדסה ‪ /‬מכללה חרדית‬
‫צבי מלמד‬
‫‪Tzvi.Melamed@gmail.com‬‬
‫הרצאות הקורס מבוססות במידה רבה ביותר על ההרצאות של ד"ר יורם ביברמן‬
‫© כל הזכויות שמורות לד"ר יורם ביברמן ולצבי מלמד‬
‫©צבי מלמד‬
‫‪1‬‬
‫הפונקציה )(‪fcntl‬‬
‫• הפונקציה )(‪ fcntl‬משמשת לצורך קביעת ושליפת התכונות של‬
‫קובץ פתוח‪:‬‬
‫©צבי מלמד‬
‫‪161‬‬
‫הפונקציה )(‪ - fcntl‬שימושים‬
‫‪fcntl(filedes, F_DUPFD, filedes2); (1‬‬
‫– ‪F_DUPFD = DUplicate File Descriptor‬‬
‫–‬
‫שקולה לפונקציה ‪dup(filedes, filedes2); :‬‬
‫–‬
‫מחזירה את מספר המתאר החדש )שיהיה בהכרח קטן או‬
‫שווה ל‪(filedes2-‬‬
‫–‬
‫מחזירה ‪ -1‬אם נכשלה‪.‬‬
‫– המתאר החדש מצביע לאותה כניסה בטבלת הקבצים‬
‫הפתוחים אך יש לו דגלי מתאר נפרדים‪.‬‬
‫•‬
‫)הדגל היחיד שקיים‪ FD_CLOEXEC :‬מציין אם יש‬
‫לסגור את הקובץ כשמבצעים )(‪( exec‬‬
‫©צבי מלמד‬
‫‪162‬‬
‫ שימושים‬- fcntl() ‫הפונקציה‬
fcntl(filedes, F_SETPFD, FD_CLOEXEC); (2
SET File Descriptor –
‫ קובע שהקובץ ייסגר בזמן‬- FD_CLose On EXEC
–
exec() ‫ביצוע‬
:‫ על ידי הפקודה‬FD ‫ נקבל את ערך הסטטוס של ה‬,‫( באופן סימטרי‬3
val = fcntl(filedes, F_GETPFD, 0);
if (val== .....)
163
‫©צבי מלמד‬
‫דוגמה‪file_fnctl1.c :‬‬
‫©צבי מלמד‬
‫‪164‬‬
‫הרצה‪file_fnctl1.c :‬‬
‫©צבי מלמד‬
‫‪165‬‬
‫ שימושים‬- fcntl() ‫הפונקציה‬
.‫( טיפול בדגלי הסטטוס‬4
:‫ והוגדרו‬fd ‫ מכיל את המספר של‬argv[1] ‫– נניח ש‬
int val, accmode;
if ((val=fcntl(atoi(argv[1]), F_GETFL,0)<0)
...
(0 ‫ הפרמטר השלישי הוא תמיד‬f_fetgl ‫)כאשר הפעולה היא‬
accmode = val & O_ACCMODE;
(‫)זאת הדרך לנקות חלק מהסיביות בכדי שלא ישפיעו על הפעולות הבאות‬
if (accmode==O_RDONLY) puts(“read-only”);
if (accmode==O_WRONLY) puts(“write-only”);
if (accmode==O_RDWR) puts(“read + write”);
else puts (“unknown access mode”);
if (val & O_APPEND) puts (“+ append”);
if (val & O_SYNC) puts (“+ synchronized writes”);
166
‫©צבי מלמד‬
‫הערות על דגלי הסטטוס – הערה ‪#1‬‬
‫• כאשר רוצים לקבוע דגל סטטוס חדש צריך‬
‫לבצע‪:‬‬
‫– לקבל את הדגלים הקיימים‬
‫– להוסיף את הדגל הרצוי‬
‫– לעדכן את הדגלים‪.‬‬
‫;‪int val‬‬
‫)‪if (val=fcntl(fd, F_GETFL,0) <0‬‬
‫‪... error...‬‬
‫;‪val |= O_SYNC‬‬
‫)‪if (fcntl(fd, F_SETFL, val) <0‬‬
‫‪... error...‬‬
‫בכדי לבטל דגל מסוים‪ ,‬הפעולה שנעשה‪:‬‬
‫‪val &= ~O_SYNC‬‬
‫©צבי מלמד‬
‫‪167‬‬
‫הערות על דגלי הסטטוס – הערה ‪#2‬‬
‫• כאשר מריצים פקודה עם ‪ – redirection‬למשל‪a,out >out.txt :‬‬
‫ה‪ shell-‬פותח את הקובץ ‪ out.txt‬אבל לא מדליק עבורו את הדגל‬
‫‪.O_SYNC‬‬
‫• אם נרצה להדליק את הדגל הזה‪ ,‬נצטרך לעשות באמצעות ‪) fcntl‬כפי‬
‫שראינו(‬
‫• באופן דומה לגבי‪ - a.out 2>>err.txt:‬נפתח במוד ‪O_APPEND‬‬
‫אבל ללא ‪O_SYNC‬‬
‫• ב‪) bash -‬להבדיל מ‪ (tcsh-‬הפקודה ‪a.out 5<>temp.txt‬‬
‫מקשרת את מתאר הקובץ ‪ ,#5‬לקובץ הנ"ל שנפתח לקריאה‪+‬כתיבה‪ .‬אזי‬
‫ניתן לבצע‪:‬‬
‫‪read(5, &num, 4)...‬‬
‫‪write(5, &num, 4)...‬‬
‫לקובץ יש מכוון יחיד שמוזז בכל אחת מהפעולות‬
‫©צבי מלמד‬
‫‪168‬‬
‫הערות על דגלי הסטטוס – הערה ‪#3‬‬
‫•‬
‫•‬
‫הדלקת הדגל ‪ O_SYNC‬מגדילה את זמן הריצה ‪clock or wall-) system-time‬‬
‫‪ (time‬אבל השפעתה זניחה על ה‪cpu-time -‬‬
‫לדוגמא‪ ,‬בניסוי שמתואר בספר )בשקף הבא(‪ :‬קוראים קובץ של ‪~100MB‬‬
‫מהדיסק‪ ,‬וכותבים אותו‪...‬‬
‫‪ .1‬קריאה מהדיסק ‪ -‬בלוקים של ‪ 4KB‬וכתיבה לתוך ‪/dev/null‬‬
‫‪ .2‬קריאה מהדיסק כנ"ל‪ ,‬וכתיבה לקובץ בדיסק )הגרעין כותב את ה‪data-‬‬
‫לתור של ה‪] (disk-driver-‬אין עליה משמעותית ב‪ – clock-time‬בגלל‬
‫שהכתיבה היא ל‪(system-cache-‬‬
‫‪ .3‬כתיבות סינכרוניות תוך שימוש ב‪ .O_SYNCH-‬היינו מצפים שהזמן יעלה‬
‫משמעותית – אבל לא‪ ...‬מסקנה‪ :‬מערכת הקבצים של ‪ ext2‬איננה‬
‫מכבדת את הדגל הזה‬
‫‪ .4‬בשלוש השורות הבאות – כתיבות סינכרוניות על ידי פקודות סינכרון –‬
‫ואכן הזמן עולה פי שלוש‪ ,‬למרות שזמן המעבד נותר כמעט ללא שינוי‬
‫©צבי מלמד‬
‫‪169‬‬
‫הערות על דגלי הסטטוס – הערה ‪#3‬‬
‫©צבי מלמד‬
‫‪170‬‬
‫דוגמא‪ :‬הקובץ ‪file_fcntl2.c‬‬
‫©צבי מלמד‬
‫‪171‬‬
‫דוגמא‪ :‬הקובץ‬
‫‪file_fcntl2.c‬‬
‫©צבי מלמד‬
‫‪172‬‬
#include
#include
#include
#include
#include
#include
#include
#include
#include
<sys/types.h>
<sys/stat.h>
<fcntl.h>
<stdlib.h>
<stdio.h>
<unistd.h>
<fcntl.h>
<string.h>
<time.h>
// EXIT_SUCCESS
// perror
// read/write/lseek/STDIN_FILENO
files_fcntl2.c
(full text)
#define
OUTPUT_STR
"This string is sent to stdout"
//---------------------------------------------------------int main(int argc, char **argv) {
int fd ;
int val ;
long i ;
unsigned long t1 = (unsigned) time(NULL) ;
if (argc != 3) {
printf("usage: %s <output file name> <0/1 (for O_SYNC)\n", argv[0]) ;
return( EXIT_FAILURE ) ;
}
173
‫©צבי מלמד‬
if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
perror("cannot open output file") ;
return( EXIT_FAILURE ) ;
}
if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
perror("cannot fcntl(fd, F_GETFL,...)") ;
return( EXIT_FAILURE ) ;
}
if (atoi(argv[2]) == 1) {
val |= O_SYNC ;
if (fcntl(fd, F_SETFL, val) < 0)
fputs("unable to raise O_SYNC flag on file", stderr) ;
else
fputs("O_SYNC raised\n", stderr) ;
}
else {
val &= ~O_SYNC ;
if (fcntl(fd, F_SETFL, val) < 0)
fputs("unable to turn off O_SYNC flag", stderr) ;
else
fputs("O_SYNC is turned off\n", stderr) ;
}
files_fcntl2.c
(full text)
174
‫©צבי מלמד‬
files_fcntl2.c (full text)
for (i=0; i < 5000000; i++)
if (write(fd, OUTPUT_STR, strlen(OUTPUT_STR)) <
strlen(OUTPUT_STR)) {
perror("write failed") ;
return( EXIT_FAILURE ) ;
}
fprintf(stderr, "time = %ld\n",
return( EXIT_SUCCESS ) ;
}
175
‫©צבי מלמד‬
(unsigned) time(NULL) - t1) ;
‫הערות על דגלי הסטטוס – הערה ‪#4‬‬
‫• פקודת )(‪ umask‬מגבילה את ההרשאות שתהליך יכול לתת‬
‫לקבצים – בפקודת הפתיחה ‪ /‬יצירה‪.‬‬
‫• הדגמה ‪ -‬בשקף הבא‬
‫©צבי מלמד‬
‫‪176‬‬
‫‪umask demo – file_open_777.c‬‬
‫התוכנית פותחת‪/‬יוצרת קבצים‬
‫עם בקשה להרשאה ‪.777‬‬
‫בהרצה בעמוד הבא‪ ,‬נראה מהן‬
‫ההרשאות שנוצרות בפועל‪,‬‬
‫כתלות בהגדרת ה‪UMASK-‬‬
‫©צבי מלמד‬
‫‪177‬‬
‫‪umask demo – file_open_777.c‬‬
‫הצגת ‪ umask‬אוקטלי ובצורת‬
‫טקסט )הדגל ‪(–S‬‬
‫קיראו בעיון‪ ,‬שורה‬
‫אחר שורה‪.‬‬
‫שימו לב כיצד‬
‫ההרשאות משתנות‬
‫כאשר ה ‪UMAX‬‬
‫משתנה‬
‫©צבי מלמד‬
‫‪178‬‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים ‪/‬רשומות‬
‫•‬
‫‪.1‬‬
‫‪.2‬‬
‫•‬
‫‪.1‬‬
‫‪.2‬‬
‫קיימות שתי תפישות שונות בסוגיית הנעילה‪:‬‬
‫מנעול הכרחי – ‪ – mandatory lock‬בכדי לפנות לקובץ‪ ,‬ראשית חובה‬
‫לנעול אותו‬
‫– ה‪ kernel-‬בודק בכל ‪ open, read, write‬שאין הפרה של נעילה על‬
‫הקובץ‪ .‬נקרא גם‪enforcement-mode locking:‬‬
‫מנעול המלצתי ‪ – advisory lock‬לא חייבים לנעול את הקובץ בכדי‬
‫לקרוא‪/‬לכתוב ממנו‪ ,‬אבל זה מומלץ מסיבות של סנכרון בין תהליכים‪.‬‬
‫– כמו כן אפשרי רק לבדוק אם הקובץ נעול‬
‫)תזכורת( קיימים שני סוגי מנעולים‪:‬‬
‫‪ – shared lock‬משותף )לקריאה( – מספר תהליכים יכולים לקבל אותו‪,‬‬
‫ורק לקרוא מהקובץ בו זמנית‬
‫‪ – exclusive lock‬בלבדי )לכתיבה(‪ ,‬לתהליך אחד בכל נקודת זמן‬
‫©צבי מלמד‬
‫‪179‬‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים ‪/‬רשומות‬
‫• בווריאנטים שונים של יוניקס קיימות פקודות נעילה שונות‪:‬‬
‫– )(‪ lockf‬במערכות ‪) system-V‬אומץ על ידי ‪(POSIX‬‬
‫– )(‪ flock‬במערכות ‪BSD‬‬
‫•‬
‫נכיר כאן את אפשרויות הנעילה באמצעות )(‪ ,fcntl‬שהינן פעולות‬
‫ברמה נמוכה יותר‪ .‬בד"כ משתמשים בפעולות אלה כאשר‬
‫הפעולות המופשטות יותר אינן מספקות‪.‬‬
‫•‬
‫)(‪ - fcntl‬מספק מנעול המלצתי‪.‬‬
‫–‬
‫בלינוקס )(‪ lockf‬מספק ממשק נוח יותר ל‪fcntl()-‬‬
‫©צבי מלמד‬
‫‪180‬‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים ‪/‬רשומות‬
‫–‬
‫בלינוקס )(‪ lockf‬מספק ממשק נוח יותר ל‪fcntl()-‬‬
‫©צבי מלמד‬
‫‪181‬‬
‫ לשם נעילת הקבצים‬fcntl()-‫שימוש ב‬
: struct flock ‫המשתנה שנזדקק לו – מטיפוס‬
•
#include <fcntl.h>
struct flock fl;
: struct flock ‫• עלינו להגדיר את המשתנה שנזדקק לו – מטיפוס‬
#include <fcntl.h>
struct flock fl;
struct flock {
short l_type;
/* F_RDLCK, F_WRLCK, or F_UNLCK */
off_t l_start;
/* offset in bytes, relative to l_whence */
short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */
off_t l_len;
/* length, in bytes; 0 means lock to EOF */
pid_t l_pid;
/* returned with F_GETLK */
};
182
‫©צבי מלמד‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים‬
‫•‬
‫נכריז על ‪) type of lock‬אופנות הנעילה(‪:‬‬
‫;‪fl.l_type = F_WRLCK‬‬
‫אפשרויות נוספות‪:‬‬
‫– ‪ – F_RDLCK‬לקריאה בלבד‬
‫– ‪ – F_UNLCK‬שחרור מנעול שנרכש‬
‫• עכשיו נגדיר באמצעות שלוש תכונות את קטע הקובץ שינעל‪:‬‬
‫;‪fl.l_whence = SEEK_SET‬‬
‫• כלומר‪ ,‬הנעילה היא יחסית לתחילת הקובץ‪.‬‬
‫• אפשרויות נוספות‪:‬‬
‫– ‪ – SEEK_CUR‬הנעילה היא יחסית למקום הנוכחי של המכוון‬
‫– ‪ –SEEK_END‬הנעילה היא יחסית לסוף הקובץ‬
‫©צבי מלמד‬
‫‪183‬‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים‬
‫•‬
‫באיזה הסטה )יחסית למה שתואר קודם( יתחיל הקטע הנעול )כאן‪:‬‬
‫בהסטה אפס(‪ ,‬וכמה בתים יש לנעול )אפס = לנעול עד סוף הקובץ(‬
‫;‪fl.l_start = 0‬‬
‫;‪fl.l_len = 0‬‬
‫• עכשיו אנו יכולים לפתוח את הקובץ‪ ,‬ואז לנעול אותו‪:‬‬
‫;)‪fd=open(“out_file”, O_WRONLY‬‬
‫)‪if (fcntl(fd, F_SETLKW, &fl) < 0‬‬
‫‪......‬‬
‫• הפתיחה צריכה להיות בהתאמה לסוג המנעול הדרוש – )כתיבה ‪ +‬מנעול‬
‫בלבדי(‬
‫©צבי מלמד‬
‫‪184‬‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים‬
‫• הנעילה תחסום את התהליך עד שניתן יהיה לספק לו את המנעול )זאת‬
‫משמעות ה‪ W-‬ב‪ ,F_SETLKW -‬כאשר ‪ W‬עבור ‪.(wait‬‬
‫• אפשרויות נוספות לדגלים‪:‬‬
‫– ‪ –F_SETLK‬פעולת הנעילה תיכשל )ותחזיר ‪ (-1‬ותחזור מיד אם לא ניתן לקבל‬
‫את המנעול מידית )כלומר ניסיון נעילה ללא נכונות להמתין(‬
‫– ‪ –F_GETLK‬בדיקת מצב הנעילה‪ .‬אם קיים מנעול שמתנגש עם זה שמתואר ב‪-‬‬
‫‪ fl‬אזי ערכו יוחזר ב‪ .fl.l_type -‬אחרת‪ ,‬בשדה הזה יוחזר הערך‪:‬‬
‫‪F_UNLCK‬‬
‫• לאחר שבצענו את הפעולות הנ"ל‪ ,‬קטע הקובץ הדרוש נעול במנעול המבוקש‪.‬‬
‫• בכדי לשחרר את המנעול צריך לשנות רק שדה אחד במבנה )השאר נותרים כמות‬
‫שהם(‪:‬‬
‫;‪fl.l_type = F_UNLCK‬‬
‫‪...fcntl(fd, F_SETLKW, &fl)...‬‬
‫©צבי מלמד‬
‫‪185‬‬
‫שימוש ב‪ fcntl()-‬לשם נעילת הקבצים‬
‫• הערה‪:‬‬
‫– נניח שביקשנו לנעול את הקובץ באופן בלבדי )‪,(F_WRLCK‬‬
‫ולהמתין עד קבלת המנעול )‪.(F_SETLKW‬‬
‫– אם הקובץ נעול כבר על ידי קוראים ‪ ‬עלינו להמתין‬
‫– אם במהלך ההמתנה יגיעו קוראים נוספים – הם יקבלו את‬
‫המנעול‬
‫– התוצאה‪ :‬חשש להרעבה‬
‫©צבי מלמד‬
‫‪186‬‬
‫דוגמא‪:‬‬
‫‪fcntl_lock.c‬‬
‫©צבי מלמד‬
‫‪187‬‬
‫דוגמא‪:‬‬
‫‪fcntl_lock.c‬‬
‫©צבי מלמד‬
‫‪188‬‬
‫דוגמא‪:‬‬
‫‪fcntl_lock.c‬‬
‫©צבי מלמד‬
‫‪189‬‬
‫הרצה‪:‬‬
‫‪fcntl_lock.c‬‬
‫©צבי מלמד‬
‫‪190‬‬
‫טיפול בהרשאות‬
‫• ההרשאות לקובץ נקבעות כאשר יצרנו את הקובץ‬
‫– ‪ – BTW) apropos: umask‬שימו לב ‪ apropos‬היא פקודת‬
‫יוניקס‪ .‬נסו להריץ‪ apropos apropos :‬או ‪(man apropos‬‬
‫• פעולות רלבנטיות בהקשר להרשאות‪:‬‬
‫– א‪ .‬לבדוק את ההרשאות הקיימות‬
‫– ב‪ .‬לשנות את ההרשאות‬
‫• בהתאמה‪ ,‬קיימות שתי פונקציות ספריה‪:‬‬
‫– )(‪access‬‬
‫– )(‪chmod‬‬
‫©צבי מלמד‬
‫‪191‬‬
access() ‫טיפול בהרשאות – הפונקציה‬
NAME
access - check user\u2019s permissions for a file
SYNOPSIS
#include <unistd.h>
int access(const char *pathname, int mode);
DESCRIPTION
access checks whether the process would be allowed to read, write or
test for existence of the file (or other file system object) whose name
is pathname. If pathname is a symbolic link permissions of the file
referred to by this symbolic link are tested.
mode is a mask consisting of one or more of R_OK, W_OK, X_OK and F_OK.
192
‫©צבי מלמד‬
access() ‫טיפול בהרשאות – הפונקציה‬
‫ בודקת האם התהליך הנוכחי רשאי לבצע פעולה כלשהי‬access() ‫• הפונקציה‬
‫על קובץ‬
R_OK, W_OK, X_OK, :‫ ומסכה של הרשאות‬,‫ לקובץ‬path ‫• מקבלת‬
(‫ ביניהן‬OR ‫ׁ )ניתן לבצע‬F_OK
‫ אם לפחות אחת מהן אסורה‬-1 ‫ אפס אם כולן מותרות או‬:‫• מחזירה‬
if (access(“../my_file”, R_OK)==0)
puts(“can read ../my_file\n”);
if (access(“~yoramb/os”, W_OK)==0)
puts(“~yoramb/os” is writable\n”);
if (access(“~/bin/my_script”, R_OK|W_OK)==0) &&
(access(“~/bin/my_script, X_OK)!=0)
{
puts(“~/bin/my_script is read-write enabled, “);
puts(“but it is not executable\n”);
}
193
‫©צבי מלמד‬
‫טיפול בהרשאות – הפונקציה )(‪access‬‬
‫• ניתן לבדוק גם את קיומו או אי‪-‬קיומו של הקובץ על ידי שימוש‬
‫ב‪F_OK -‬‬
‫)‪if (access(“../../dir2/dir3/kuku.txt”, F_OK)==0‬‬
‫;)”‪puts(“../../dir2/dir3/kuku.txt”, exists‬‬
‫©צבי מלמד‬
‫‪194‬‬
‫עדכון הרשאות – הפונקציה )(‪chmod‬‬
‫©צבי מלמד‬
‫‪195‬‬
‫עדכון הרשאות – הפונקציה )(‪chmod‬‬
‫• הפונקציה )(‪ chmod‬מאפשרת לעדכן‪/‬לשנות את ההרשאות על‬
‫קובץ קיים‬
‫)‪if (chmod(“myfile”, S_IRUSR | S_IWUSR)==-1‬‬
‫;)”‪perror(“chmod myfile failed‬‬
‫הסבר הדגלים‪:‬‬
‫•‬
‫‪ – S_I‬תחילית קבועה לכל הדגלים בפונקציה זאת‬
‫•‬
‫התו הבא‪ R :‬קריאה‪ W ,‬כתיבה‪ X ,‬ביצוע‬
‫•‬
‫‪ USR‬או ‪ – U‬בעלים‬
‫•‬
‫‪ GRP‬או ‪ – G‬הקבוצה‬
‫•‬
‫‪ OTH‬או ‪) Other – O‬כל השאר(‬
‫•‬
‫פרטים נוספים‪man 2 chmod :‬‬
‫ק‪+‬כ‪+‬הרצה לבעלים – ‪S_IRWXU‬‬
‫ק‪+‬כ‪+‬הרצה לקבוצה – ‪S_IRWXG‬‬
‫ק‪+‬כ‪+‬הרצה לכל העולם – ‪S_IRWXO‬‬
‫קריאה לקבוצה – ‪S_IRGRP‬‬
‫קריאה לעולם – ‪S_IROTH‬‬
‫©צבי מלמד‬
‫‪196‬‬
– ‫דוגמא‬
check_n_update
_access_mode.c
197
‫©צבי מלמד‬
check_n_update_access_mode.c – ‫הרצה‬
198
‫©צבי מלמד‬
check_n_update_access_mode.c
#include
#include
#include
#include
#include
#include
<stdio.h>
<stdlib.h>
<unistd.h>
<strings.h>
<string.h>
<sys/stat.h>
//
//
//
//
for
for
for
for
access()
rindex()
strcmp()
chmod()
int main(int argc, char **argv) {
char *suffix ;
if (argc != 2) {
fprintf(stderr, "Usage: %s <file name>\n", argv[0]) ;
exit(EXIT_FAILURE) ;
}
if (access(argv[1], F_OK) != 0) {
puts("File does not exist");
exit(EXIT_SUCCESS) ;
}
199
‫©צבי מלמד‬
if (access(argv[1], R_OK | W_OK | X_OK) == 0) {
puts("rwx");
}
if (access(argv[1], R_OK) == 0) puts("r");
if (access(argv[1], W_OK) == 0) puts("w");
if (access(argv[1], X_OK) == 0) puts("x");
// .c file?: change its access mode to
rw- --- ---
suffix = rindex(argv[1], '.') ;
printf("suffix is ===%s\n", suffix);
if(suffix != NULL && strcmp(suffix, ".c")==0)
if (chmod(argv[1], S_IRUSR | S_IWUSR) == -1 ) {
perror("chmod() failed") ;
exit(EXIT_FAILURE) ;
}
else
puts("chmod to rw- --- ---") ;
else
puts("no chmod was done") ;
exit(EXIT_SUCCESS) ;
}
200
‫©צבי מלמד‬
check_n_update_
access_mode.c
‫טיפול בהרשאות – ברמת ה‪shell-‬‬
‫• בדיקה ושינוי של הרשאות או קיום של קבצים אפשרית גם ברמת ה‪-‬‬
‫‪) shell‬כולם תומכים בזה‪ ,‬הסינטקס עשוי להיות שונה במקצת(‬
‫• הסקריפט הבא )‪:(tcsh script‬‬
‫– יוצר קובץ בשם ‪myfile‬‬
‫– בודק ו"מדפיס" האם הוא ‪writable‬‬
‫– מבטל את הרשאות הכתיבה‬
‫– בודק ו"מדפיס" האם הוא ‪writable‬‬
‫– בודק האם הוא קיים ומדפיס הודעה‬
‫– מוחק את הקובץ‬
‫– בודק האם הוא קיים ומדפיס הודעה‬
‫©צבי מלמד‬
‫‪201‬‬
‫טיפול בהרשאות‬
‫– ברמת ה‪shell-‬‬
‫התחלה‬
‫המשך‬
‫©צבי מלמד‬
‫‪202‬‬
‫טיפול בהרשאות – ברמת ה‪shell-‬‬
‫** הדגמה **‬
‫©צבי מלמד‬
‫‪203‬‬
‫הפונקציה )(‪ stat‬לקבלת מידע על קובץ‬
‫©צבי מלמד‬
‫‪204‬‬
‫הפונקציה )(‪ stat‬לקבלת מידע על קובץ‬
‫• הפונקציה )כמו גם חברותיה( מקבלת מתאר קובץ או ‪+ path-name‬‬
‫מצביע למבנה ‪ .struct stat‬ממלאת את המבנה בנתונים אודות הקובץ‪.‬‬
‫• ‪ members‬של המבנה כוללים )בין היתר(‪:‬‬
‫– ‪ – mode_t st_mode‬סוג הקובץ )רגיל‪ ,‬תיקייה‪ ,soft-link ,‬וכו'( וכן‬
‫הרשאות הגישה לקובץ‬
‫– ‪ – off_t st_size‬גודל הקובץ בבתים‬
‫– ‪a=access, m=modify, ) mode_t st_atime / st_mtime / st_ctime‬‬
‫‪ – (c=creation‬הזמן בשניות של יוניקס‪.‬‬
‫• ‪ – create‬יצירת הקובץ או שינוי תכונותיו‪/‬הרשאותיו‬
‫– עוד חברים שנראה בדוגמא מיד‬
‫• בדיקת תכולת המבנה – באמצעות מאקרו'אים‬
‫©צבי מלמד‬
‫‪205‬‬
‫הפונקציה )(‪ stat‬לקבלת מידע על קובץ‬
‫©צבי מלמד‬
‫‪206‬‬
‫ לקבלת מידע על קובץ‬stat() ‫הפונקציה‬
if (“my_file”, &fs) == -1) {
......
}
if (S_ISDIR(fs.st_mode))
puts("it is a dir") ;
else if (S_ISLNK(fs.st_mode))
puts("it is a soft link") ;
else if (S_FIFO(fs.st_mode))
puts("it is a soft link") ;
else if (S_ISREG(fs.st_mode))
puts("it is a normal file") ;
207
‫©צבי מלמד‬
‫ לקבלת מידע על קובץ‬stat() ‫הפונקציה‬
‫ במידת הצורך‬,‫ בכדי לבדוק את ההרשאות )ואז‬stat ‫• ניתן להשתמש בפונקציה‬
:( chmod() ‫לעדכן אותן על ידי‬
if (“my_file”, &fs) == -1) {
......
}
if (! (S_IWGRP & fs.st_mode) {
// no group write permission
mode_t curr_mode =
fs.st_mode & ~S_IFMT;
// clean file type from st_mode
// remain only with permissions
mode_t new_mode = curr_mode | S_IWGRP;
// add the w permissions to g
if (chmod(“my_file” new_mode) == -1;) {
......
}
208
‫©צבי מלמד‬
‫הפונקציה )(‪ stat‬לקבלת מידע על קובץ‬
‫©צבי מלמד‬
‫‪209‬‬
‫דוגמא‪stat.c :‬‬
‫©צבי מלמד‬
‫‪210‬‬
‫דוגמא‪stat.c :‬‬
‫©צבי מלמד‬
‫‪211‬‬
‫הרצה‪stat.c :‬‬
‫©צבי מלמד‬
‫‪212‬‬
‫הרצה‪stat.c :‬‬
‫©צבי מלמד‬
‫‪213‬‬
‫דוגמא‪stat_link.c :‬‬
‫קריאה לפונקציה )(‪lstat‬‬
‫קריאה לפונקציה )(‪readlink‬‬
‫©צבי מלמד‬
‫‪214‬‬
‫דוגמא‪stat_link.c :‬‬
‫©צבי מלמד‬
‫‪215‬‬
‫דוגמא‪stat_link.c :‬‬
‫©צבי מלמד‬
‫‪216‬‬
‫שינוי שם קובץ ‪ /‬העברה לתיקייה אחרת‬
‫•‬
‫•‬
‫•‬
‫•‬
‫)‪if (rename(“file_name”, “new_name”) == -1‬‬
‫‪--- error --‬‬‫)‪if (rename(“file_name”, “/tmp/new_name”) == -1‬‬
‫‪--- error --‬‬‫אם הקובץ ‪ file_name‬קיים‪ ,‬אז ראשית הוא ימחק ואז יבוצע שינוי‬
‫השם‬
‫)‪if (unlink(“/tmp/new_name”) == -1‬‬
‫‪--- error --‬‬‫הקובץ ימחק אם לא קיים תהליך אחר שמשתמש בו‪.‬‬
‫אם משתמשים בו – הקובץ יימחק מהרשימה בתיקייה אבל ימחק‬
‫בפועל רק כשתתבצע סגירת הקובץ על ידי התהליך האחר‬
‫וכל זאת‪ ..‬בתנאי‪ ,‬שזהו הלינק האחרון לקובץ )‪(hard link‬‬
‫©צבי מלמד‬
‫‪217‬‬
‫יצירת קשר סימבולי ‪soft link‬‬
‫‪if (symlink(“~david/bin/script_name”,‬‬
‫)‪“~/bin/my_script_name”) == -1‬‬
‫‪--- error --‬‬‫• יצירת ‪ soft-link‬כפי שהכרנו בפקודה ‪ln-s‬‬
‫• לא מתבצעת בדיקה שהקובץ ה"מוצבע" אכן קיים‬
‫©צבי מלמד‬
‫‪218‬‬
‫פעולות על תיקיות – קריאת תוכן התיקייה‬
‫•‬
‫•‬
‫•‬
‫•‬
‫•‬
‫תיקייה – קובץ בינארי שכולל טבלה בת שתי עמודות‬
‫בכדי לפתוח קובץ‪FILE *fd = fopen(“myfile”, “r”); :‬‬
‫באופן דומה פתיחת התיקייה על ידי שימוש במשתנה מטיפוס ‪DIR‬‬
‫כל כניסה‪/‬שורה בטבלת התיקייה‪ :‬משתנה מטיפוס *‪(directory struct dirent‬‬
‫)‪entry‬‬
‫– החבר הרלבנטי‪– d_name :‬מכיל את שם הכניסה )לא את ה‪(path-‬‬
‫פתיחה וסגירה על ידי‪:‬‬
‫;)”‪DIR *dir = opendir(“~yoramb/os‬‬
‫‪if (dir == NULL) ...‬‬
‫‪................‬‬
‫)‪if (closedir(dir)==-1‬‬
‫‪--- error ---‬‬‫©צבי מלמד‬
‫‪219‬‬
‫פעולות על תיקיות – סריקת תוכן התיקייה‬
‫• לאחר שפתחנו את התיקייה נסרוק אותה על ידי‪:‬‬
‫;‪struct dirent *dentry‬‬
‫)‪while (dentry=readdir(dir)!=NULL‬‬
‫;)‪printf(“%s\n”, dentry->d_name‬‬
‫• הלולאה עוברת על תוכן התיקייה‪ ,‬כולל ”‪ “.‬וגם "‪"..‬‬
‫• לחזור לתחילת התיקייה‪:‬‬
‫;)‪rewinddir(dir‬‬
‫©צבי מלמד‬
‫‪220‬‬
man 2 readdir
221
‫©צבי מלמד‬
‫פעולות על תיקיות – שינוי ה‪PWD-‬‬
‫• ‪ – PWD‬תיקיית העבודה הנוכחית )ברמת התהליך(‬
‫• נניח שהגדרנו‪char pwd[N] :‬‬
‫• בכדי לקבל את המסלול המלא לתיקיית העבודה‪ ,‬נבצע‪:‬‬
‫))‪if (!getcwd(pwd, N‬‬
‫‪--- error --‬‬‫• בכדי לשנות את תיקיית העבודה‪ ,‬נבצע‪:‬‬
‫))”‪if (!chdir(“../..‬‬
‫‪--- error --‬‬‫• )עלינו לתיקיית "הסב" – כלומר‪ ,‬שתי רמות בעץ התיקיות(‬
‫©צבי מלמד‬
‫‪222‬‬
‫יצירת ומחיקת מדריך‬
‫;)‪int mkdir(const char *path, mode_t mode‬‬
‫;)‪int rmdir(const char *path‬‬
‫• הפונקציה ‪ mkdir‬מנסה ליצור מדריך בשם המבוקש‪ ,‬בעל ההרשאות‬
‫הרצויות‪.‬‬
‫– הרשאה מקובלת‪0700 :‬‬
‫– בתיקייה‪ :‬דרוש הרשאת ‪ execute‬בכדי ליצור קובץ‬
‫• הפונקציה ‪ rmdir‬תנסה למחוק את התיקייה‬
‫– סיבות לכשלון‪ :‬תיקייה איננה ריקה‪ ,‬בשימוש של תהליך אחר‪,‬‬
‫חוסר הרשאות‪ ,‬ועוד‬
‫©צבי מלמד‬
‫‪223‬‬
‫דוגמא‪scan_dir.c :‬‬
‫©צבי מלמד‬
‫‪224‬‬
‫דוגמא‪scan_dir.c :‬‬
‫©צבי מלמד‬
‫‪225‬‬
‫הרצה‪scan_dir.c :‬‬
‫©צבי מלמד‬
‫‪226‬‬
‫קבצים ממופים לזיכרון ‪memory mapped files‬‬
‫• מיפוי קובץ לזיכרון מאפשר לקרוא‪/‬לכתוב על הקובץ‪ ,‬באמצעות‬
‫פעולות על הזיכרון‬
‫• מטפלים בקובץ כאילו היה מערך של תוים‬
‫• יתרונות‬
‫– מקל על מספר תהליכים לטפל באותו קובץ‪.‬‬
‫• במידת הצורך – יפעילו סמפורים‬
‫– פעולות קריאה‪/‬כתיבה מתבצעות על ידי מצביע לזיכרון ולא על‬
‫ידי קריאות ‪read/write‬‬
‫• מי מבצע אם כך את הקלט‪/‬פלט?‬
‫©צבי מלמד‬
‫‪227‬‬
‫קבצים ממופים לזיכרון ‪memory mapped files‬‬
‫– הקלט‪/‬פלט מתבצע על ידי מערכת ההפעלה )אופטימליות‬
‫בביצוע(‬
‫– התכנית פונה לאזור של מערכת ההפעלה‪ .‬נחסכת ההעתקת‬
‫הנתונים לחוצצים במרחב המשתמש‬
‫• ניתן למפות קובץ שגודלו על ‪) 2GB‬זה נכון ב‪ 32-‬ביט‪ ..‬יותר מכך ב‬
‫‪ 64‬ביט(‬
‫• לא ניתן להגדיל את הקובץ בשיטה הזאת‪ .‬לשם כך דרושה פעולת‬
‫‪write‬‬
‫• כשמערכת ההפעלה מריצה תהליך )תכנית( היא פועלת בשיטה‬
‫הזאת‪ :‬ממפה את הקובץ לזיכרון‪ .‬טוענת דף ראשון‪ .‬שאר הדפים‬
‫בשיטת דרישת הדפים‪.‬‬
‫©צבי מלמד‬
‫‪228‬‬
man 2 mmap
229
‫©צבי מלמד‬
‫קבצים ממופים לזיכרון ‪memory mapped files‬‬
‫‪mmap1.c‬‬
‫©צבי מלמד‬
‫‪230‬‬
‫קבצים ממופים לזיכרון ‪memory mapped files‬‬
‫‪mmap1.c‬‬
‫©צבי מלמד‬
‫‪231‬‬
‫קבצים ממופים לזיכרון ‪memory mapped files‬‬
‫‪mmap1.c‬‬
‫©צבי מלמד‬
‫‪232‬‬