ผู้เริ่มต้นมักได้ยินวลี "ทุกอย่างเป็นไฟล์บน Linux / Unix" อย่างไรก็ตามสิ่งที่เป็นไดเรกทอรีแล้ว แตกต่างจากไฟล์อย่างไร
ผู้เริ่มต้นมักได้ยินวลี "ทุกอย่างเป็นไฟล์บน Linux / Unix" อย่างไรก็ตามสิ่งที่เป็นไดเรกทอรีแล้ว แตกต่างจากไฟล์อย่างไร
คำตอบ:
หมายเหตุ: เดิมนี้ถูกเขียนขึ้นเพื่อรองรับคำตอบของฉันสำหรับเหตุใดไดเรกทอรีปัจจุบันในls
คำสั่งที่ระบุว่าเชื่อมโยงกับตัวเอง แต่ฉันรู้สึกว่านี่เป็นหัวข้อที่ควรค่าแก่การยืนหยัดด้วยตนเองและด้วยเหตุนี้คำถาม & คำตอบนี้
โดยพื้นฐานแล้วไดเรกทอรีเป็นเพียงไฟล์พิเศษซึ่งมีรายการของรายการและ ID ของพวกเขา
ก่อนที่เราจะเริ่มการสนทนาสิ่งสำคัญคือการสร้างความแตกต่างระหว่างคำศัพท์สองสามคำและเข้าใจว่าไดเรกทอรีและไฟล์ใดเป็นตัวแทน คุณอาจเคยได้ยินคำว่า "Everything is a file" สำหรับ Unix / Linux สิ่งที่ผู้ใช้มักเข้าใจว่าเป็นไฟล์คือ: /etc/passwd
- วัตถุที่มีพา ธ และชื่อ ในความเป็นจริงชื่อ (ไม่ว่าจะเป็นไดเรกทอรีหรือไฟล์หรืออะไรก็ตาม) เป็นเพียงสตริงข้อความ - คุณสมบัติของวัตถุจริง วัตถุนั้นถูกเรียกว่าinodeหรือ I-number และเก็บไว้ในดิสก์ในตาราง inode โปรแกรมที่เปิดยังมีตารางไอโหนด แต่นั่นไม่ใช่ความกังวลของเราในตอนนี้
แนวคิดของ Unix เกี่ยวกับไดเร็กตอรี่ก็เหมือนกับที่ Ken Thompson กล่าวไว้ในการสัมภาษณ์ปี 1989 :
... จากนั้นไฟล์บางไฟล์เป็นไดเรกทอรีที่เพิ่งมีชื่อและหมายเลข
การสังเกตที่น่าสนใจสามารถทำได้จากการพูดคุยของ Dennis Ritchie ในปี 1972ว่า
"... ไดเรกทอรีไม่เกินไฟล์ แต่เนื้อหาถูกควบคุมโดยระบบและเนื้อหาเป็นชื่อของไฟล์อื่น ๆ (บางครั้งไดเรกทอรีเรียกว่าแคตตาล็อกในระบบอื่น)"
... แต่ไม่มีการพูดถึงไอโหนดใด ๆ ในการพูดคุย อย่างไรก็ตามคู่มือ 1971เกี่ยวกับformat of directories
รัฐ:
ความจริงที่ว่าไฟล์คือไดเร็กทอรีถูกระบุโดยบิตในคำแฟล็กของรายการ i - node
รายการไดเรกทอรีมีความยาว 10 ไบต์ คำแรกคือไอ - โหนดของไฟล์ที่แสดงโดยรายการถ้าไม่ใช่ -; ถ้าศูนย์รายการว่างเปล่า
ดังนั้นจึงมีตั้งแต่จุดเริ่มต้น
การจับคู่ไดเรกทอรีและ inode ยังอธิบายในโครงสร้างไดเรกทอรีที่จัดเก็บในระบบไฟล์ UNIX อย่างไร . ตัวไดเรกทอรีเองนั้นเป็นโครงสร้างข้อมูลโดยเฉพาะอย่างยิ่ง: รายการของวัตถุ (ไฟล์และหมายเลข inode) ที่ชี้ไปยังรายการเกี่ยวกับวัตถุเหล่านั้น (การอนุญาตประเภทเจ้าของขนาด ฯลฯ ) ดังนั้นแต่ละไดเรกทอรีมีหมายเลขไอโหนดของตัวเองแล้วชื่อไฟล์และหมายเลขไอโหนดของพวกเขา ที่มีชื่อเสียงมากที่สุดคือinode # 2 ซึ่งเป็น/
ไดเรกทอรี (หมายเหตุ แต่ที่/dev
และ/run
มีระบบไฟล์เสมือนดังนั้นตั้งแต่พวกเขาเป็นโฟลเดอร์รากระบบแฟ้มของพวกเขาพวกเขายังมี inode 2; เช่น inode นั้นมีความเป็นเอกลักษณ์ในระบบไฟล์ของตัวเอง แต่เมื่อติดตั้งระบบไฟล์หลายตัวคุณจะมี inode ที่ไม่ซ้ำกัน) แผนภาพที่ยืมมาจากคำถามที่เชื่อมโยงอาจอธิบายได้อย่างกระชับยิ่งขึ้น:
ข้อมูลทั้งหมดที่เก็บไว้ในไอโหนดสามารถเข้าถึงได้ผ่านการstat()
เรียกใช้ระบบตาม Linux man 7 inode
:
แต่ละไฟล์มีไอโหนดที่มีข้อมูลเมตาเกี่ยวกับไฟล์ แอปพลิเคชันสามารถดึงข้อมูลเมตานี้โดยใช้ stat (2) (หรือการโทรที่เกี่ยวข้อง) ซึ่งส่งกลับโครงสร้าง stat หรือ statx (2) ซึ่งส่งกลับโครงสร้าง statx
เป็นไปได้หรือไม่ที่จะเข้าถึงไฟล์โดยรู้หมายเลขไอโหนดเท่านั้น ( ref1 , ref2 )? ในการใช้งาน Unix บางอย่างมันเป็นไปได้ แต่มันข้ามการตรวจสอบการอนุญาตและการเข้าถึงดังนั้นบน Linux ก็ยังไม่ได้ติดตั้งและคุณต้องสำรวจทรีของระบบไฟล์ (ผ่านfind <DIR> -inum 1234
ตัวอย่าง) เพื่อรับชื่อไฟล์และ inode ที่เกี่ยวข้อง
ในระดับซอร์สโค้ดมันถูกกำหนดไว้ในซอร์สเคอร์เนลของ Linuxและยังได้รับการยอมรับจากระบบไฟล์จำนวนมากที่ทำงานบนระบบปฏิบัติการ Unix / Linux รวมถึงระบบไฟล์ ext3 และ ext4 (ค่าเริ่มต้นของ Ubuntu) สิ่งที่น่าสนใจ: มีข้อมูลเป็นเพียงบล็อกของข้อมูลลินุกซ์จริงมีฟังก์ชั่น inode_init_alwaysที่สามารถตรวจสอบว่า inode เป็นท่อ ( inode->i_pipe
) ใช่ซ็อกเก็ตและท่อเป็นเทคนิคเช่นกันไฟล์ - ไฟล์ที่ไม่ระบุชื่อซึ่งอาจไม่มีชื่อไฟล์ในดิสก์ FIFOและซ็อกเก็ต Unix-Domainมีชื่อไฟล์ในระบบไฟล์
ข้อมูลอาจไม่ซ้ำกัน แต่หมายเลขไอโหนดไม่ซ้ำกัน ถ้าเรามีลิงก์ไปยัง foo ที่เรียกว่า foobar นั่นจะชี้ไปที่ inode 123 เช่นกัน ไอโหนดนี้มีข้อมูลว่าบล็อกพื้นที่ว่างในดิสก์นั้นถูกครอบครองโดยไอโหนดนั้น และในทางเทคนิคแล้วคุณจะสามารถ.
เชื่อมโยงกับชื่อไฟล์ไดเรกทอรีได้อย่างไร ดีเกือบ: คุณไม่สามารถสร้าง hardlinks ไปยังไดเรกทอรีบน Linux ตัวเองแต่ filesystems สามารถอนุญาตให้เชื่อมโยงอย่างหนักเพื่อไดเรกทอรีในทางที่มีระเบียบวินัยมากซึ่งทำให้ข้อ จำกัด ของการมีเพียง.
และ..
การเชื่อมโยงอย่างหนัก
ระบบแฟ้มใช้โครงสร้างไดเรกทอรีเป็นหนึ่งในโครงสร้างข้อมูลแบบต้นไม้ โดยเฉพาะอย่างยิ่ง,
จุดสำคัญที่นี่คือไดเรกทอรีเองเป็นโหนดในต้นไม้และไดเรกทอรีย่อยเป็นโหนดลูกโดยที่เด็กแต่ละคนมีลิงค์กลับไปที่โหนดแม่ ดังนั้นสำหรับลิงก์ไดเรกทอรีจำนวน inode จึงเป็นขั้นต่ำ 2 สำหรับไดเรกทอรีที่ไม่มีการเชื่อมโยง (ลิงก์ไปยังชื่อไดเรกทอรี/home/example/
และลิงก์ไปยังตนเอง/home/example/.
) และแต่ละไดเรกทอรีย่อยเพิ่มเติมคือลิงก์ / โหนดเพิ่มเติม:
# new directory has link count of 2
$ stat --format=%h .
2
# Adding subdirectories increases link count
$ mkdir subdir1
$ stat --format=%h .
3
$ mkdir subdir2
$ stat --format=%h .
4
# Count of links for root
$ stat --format=%h /
25
# Count of subdirectories, minus .
$ find / -maxdepth 1 -type d | wc -l
24
แผนภาพที่พบในหน้าหลักสูตรของ Ian D. Allenแสดงไดอะแกรมที่ชัดเจนอย่างง่าย:
WRONG - names on things RIGHT - names above things
======================= ==========================
R O O T ---> [etc,bin,home] <-- ROOT directory
/ | \ / | \
etc bin home ---> [passwd] [ls,rm] [abcd0001]
| / \ \ | / \ |
| ls rm abcd0001 ---> | <data> <data> [.bashrc]
| | | |
passwd .bashrc ---> <data> <data>
สิ่งเดียวในไดอะแกรม RIGHT ที่ไม่ถูกต้องคือไฟล์นั้นไม่ได้รับการพิจารณาทางเทคนิคว่าอยู่ในแผนผังไดเรกทอรีเอง: การเพิ่มไฟล์ไม่มีผลต่อการนับลิงก์:
$ mkdir subdir2
$ stat --format=%h .
4
# Adding files doesn't make difference
$ cp /etc/passwd passwd.copy
$ stat --format=%h .
4
ในการอ้างLinus Torvalds :
จุดรวมของ "ทุกอย่างคือไฟล์" ไม่ใช่ว่าคุณมีชื่อไฟล์แบบสุ่ม (แน่นอนซ็อกเก็ตและท่อแสดงว่า "ไฟล์" และ "ชื่อไฟล์" ไม่มีส่วนเกี่ยวข้องกัน) แต่ความจริงที่ว่าคุณสามารถใช้งานร่วมกันได้ เครื่องมือในการทำงานกับสิ่งต่าง ๆ
พิจารณาว่าไดเรกทอรีเป็นเพียงกรณีพิเศษของไฟล์โดยธรรมชาติจะต้องมี API ที่ช่วยให้เราสามารถเปิด / อ่าน / เขียน / ปิดพวกเขาในลักษณะคล้ายกับไฟล์ปกติ
นั่นคือที่dirent.h
มาของไลบรารี C ซึ่งกำหนดdirent
โครงสร้างซึ่งคุณสามารถหาได้ในman 3 readdir :
struct dirent {
ino_t d_ino; /* Inode number */
off_t d_off; /* Not an offset; see below */
unsigned short d_reclen; /* Length of this record */
unsigned char d_type; /* Type of file; not supported
by all filesystem types */
char d_name[256]; /* Null-terminated filename */
};
ดังนั้นในรหัส C ของคุณคุณต้องกำหนดstruct dirent *entry_p
และเมื่อเราเปิดไดเรกทอรีด้วยopendir()
และเริ่มอ่านมันด้วยreaddir()
เราจะเก็บแต่ละรายการไว้ในentry_p
โครงสร้างนั้น แน่นอนว่าแต่ละรายการจะมีฟิลด์ที่กำหนดในเทมเพลตสำหรับdirent
แสดงไว้ด้านบน
ตัวอย่างการปฏิบัติของวิธีการทำงานนี้สามารถพบได้ในคำตอบของฉันเกี่ยวกับวิธีการไฟล์รายชื่อและหมายเลขไอโหนดของพวกเขาในไดเรกทอรีการทำงานปัจจุบัน
โปรดทราบว่าคู่มือ POSIX ใน fdopenระบุว่า "[t] เขารายการไดเรกทอรีสำหรับจุดและจุดจุดเป็นตัวเลือก" และreaddir คู่มือรัฐ struct dirent
จะต้องมีd_name
และd_ino
เขตข้อมูล
หมายเหตุเกี่ยวกับ "การเขียน" ไปยังไดเรกทอรี:การเขียนไปยังไดเรกทอรีกำลังแก้ไข "รายการ" ของรายการ ดังนั้นการสร้างหรือลบไฟล์จะเชื่อมโยงโดยตรงกับสิทธิ์ในการเขียนไดเรกทอรีและการเพิ่ม / ลบไฟล์เป็นการดำเนินการเขียนในไดเรกทอรีดังกล่าว
open()
และread()
ซ็อกเก็ตมีconnect()
และread()
เช่นกัน สิ่งที่จะแม่นยำมากกว่าคือ "ไฟล์" ถูกจัดระเบียบ "ข้อมูล" จริง ๆ ที่เก็บไว้ในดิสก์หรือหน่วยความจำและไฟล์บางไฟล์ไม่ระบุชื่อ - ไม่มีไฟล์ชื่อ โดยปกติผู้ใช้จะนึกถึงไฟล์ในรูปของไอคอนนั้นบนเดสก์ท็อป แต่นั่นไม่ใช่สิ่งเดียวที่มีอยู่ ดูเพิ่มเติมที่unix.stackexchange.com/a/116616/85039