การย้ายไฟล์ที่ถูกผนวกเข้านั้นปลอดภัยหรือไม่?


28

ฉันมีกระบวนการ Node.js ที่ใช้ในการเพิ่มสายที่จะfs.appendFile file.logเฉพาะสายที่สมบูรณ์ประมาณ 40 ตัวอักษรต่อบรรทัดถูกผนวกสายเช่นเป็นเหมือนfs.appendFile("start-end")ไม่เหมือน 2 สายและfs.appendFile("start-") fs.appendFile("end")หากฉันย้ายไฟล์นี้ไปfile2.logฉันจะแน่ใจได้หรือไม่ว่าไม่มีเส้นใดที่สูญหายหรือคัดลอกบางส่วน?

คำตอบ:


36

ตราบใดที่คุณไม่ย้ายไฟล์ข้ามเส้นขอบระบบไฟล์การทำงานควรจะปลอดภัย นี่เป็นผลมาจากกลไกการเคลื่อนไหวของ«ทำจริงอย่างไร

หากคุณmvเป็นไฟล์ในระบบไฟล์เดียวกันไฟล์นั้นจะไม่ได้รับการสัมผัส แต่จะมีการเปลี่ยนแปลงเฉพาะรายการระบบไฟล์เท่านั้น

$ mv foo bar

จริง ๆ แล้วทำสิ่งที่ชอบ

$ ln foo bar
$ rm foo

สิ่งนี้จะสร้างฮาร์ดลิงก์ (รายการไดเร็กทอรีที่สอง) สำหรับไฟล์ (ที่จริงแล้ว inode ที่ชี้โดยรายการระบบไฟล์) fooตั้งชื่อbarและลบfooรายการ ตั้งแต่ตอนนี้เมื่อลบfooจะมีรายการระบบไฟล์ที่สองชี้ไปfooที่ไอโหนดของการลบรายการเก่าfooไม่ได้ลบบล็อกใด ๆ ที่เป็นของไอโหนด

โปรแกรมของคุณจะต่อท้ายไฟล์อย่างมีความสุขเนื่องจากไฟล์เปิดชี้ไปที่ไอโหนดของไฟล์ไม่ใช่รายการระบบไฟล์

หมายเหตุ:หากโปรแกรมของคุณปิดและเปิดไฟล์ใหม่ระหว่างการเขียนคุณจะต้องสร้างไฟล์ใหม่ด้วยรายการระบบไฟล์เก่า!

การย้ายข้ามระบบไฟล์:

หากคุณย้ายไฟล์ข้ามพรมแดนระบบไฟล์สิ่งต่าง ๆ น่าเกลียด ในกรณีนี้คุณไม่สามารถรับประกันว่าจะมีไฟล์ของคุณทำให้สอดคล้องกันเนื่องจากmvจะจริง

  • สร้างไฟล์ใหม่บนระบบไฟล์เป้าหมาย
  • คัดลอกเนื้อหาของไฟล์เก่าไปยังไฟล์ใหม่
  • ลบไฟล์เก่า

หรือ

$ cp /path/to/foo /path/to/bar
$ rm /path/to/foo

รับผิดชอบ

$ touch /path/to/bar
$ cat < /path/to/foo > /path/to/bar
$ rm /path/to/foo

ขึ้นอยู่กับว่าการคัดลอกมาถึงจุดสิ้นสุดไฟล์ในระหว่างการเขียนแอปพลิเคชันของคุณหรือไม่อาจเกิดขึ้นได้ว่าคุณมีเพียงครึ่งหนึ่งของบรรทัดในไฟล์ใหม่

นอกจากนี้หากแอปพลิเคชันของคุณไม่ปิดและเปิดไฟล์เก่าอีกครั้งมันจะเขียนต่อไปยังไฟล์เก่าแม้ว่ามันจะถูกลบไปแล้ว: เคอร์เนลรู้ว่าไฟล์ใดบ้างที่เปิดอยู่และแม้ว่ามันจะลบรายการระบบไฟล์ก็ตาม จะไม่ลบ inode ของไฟล์เก่าและบล็อกที่เกี่ยวข้องจนกว่าแอปพลิเคชันของคุณจะปิดการจัดการไฟล์ที่เปิดอยู่


3
FYI, Unix รุ่นแรก ๆ ไม่มีการrename()เรียกระบบ ดังนั้นเวอร์ชันดั้งเดิมของการmvโทรได้จริงlink()เพื่อสร้างฮาร์ดลิงก์ตามด้วยunlink()เพื่อลบชื่อเดิม rename()ถูกเพิ่มเข้ามาใน FreeBSD เพื่อนำอะตอมนี้ไปใช้ในเคอร์เนล
Barmar

ฉันขอโทษ แต่อะไรนะfile-system borders?
laike9m

1
@ laike9m - เส้นขอบระบบไฟล์หมายถึงความจริงที่ว่าระบบไฟล์อย่างง่ายต้องอยู่ในพาร์ติชั่นเดียวในอุปกรณ์หน่วยความจำเดียวเช่นดิสก์ไดรฟ์ หากคุณเปลี่ยนชื่อไฟล์ภายในระบบไฟล์การเปลี่ยนแปลงทั้งหมดนั้นคือชื่อในรายการไดเร็กทอรี มันยังคงมีไอโหนดเดียวกัน - ถ้ามันอยู่ในระบบไฟล์โดยอิงจากไอโหนดเพื่อเริ่มต้น - เหมือนระบบไฟล์ Linux ส่วนใหญ่ แต่ถ้าคุณย้ายไฟล์ไปยังระบบไฟล์อื่นต้องย้ายข้อมูลจริงและไฟล์จะได้รับ inode ใหม่จากระบบไฟล์ใหม่ สิ่งนี้จะรบกวนการดำเนินการใด ๆ ของไฟล์ที่อยู่ระหว่างดำเนินการ
โจ

9

เนื่องจากคุณบอกว่าคุณกำลังใช้ node.js ฉันถือว่าคุณกำลังใช้fs.rename()(หรือfs.renameSync()) เพื่อเปลี่ยนชื่อไฟล์ วิธี node.js นี้มีการบันทึกไว้เพื่อใช้การเปลี่ยนชื่อ (2) การเรียกใช้ระบบซึ่งไม่ได้สัมผัสไฟล์ด้วยตัวเอง แต่อย่างใด แต่เปลี่ยนชื่อภายใต้รายการระบบไฟล์เท่านั้น:

" rename () เปลี่ยนชื่อไฟล์ย้ายระหว่างไดเรกทอรีหากต้องการฮาร์ดลิงก์อื่น ๆ ไปยังไฟล์ (ตามที่สร้างโดยใช้ลิงค์ (2) ) จะไม่ได้รับผลกระทบตัวอธิบายไฟล์ที่เปิดสำหรับoldpathก็ไม่ได้รับผลกระทบเช่นกัน"

โดยเฉพาะอย่างยิ่งให้สังเกตประโยคสุดท้ายที่ยกมาด้านบนซึ่งระบุว่าตัวอธิบายไฟล์แบบเปิดใด ๆ (เช่นโปรแกรมของคุณจะใช้ในการเขียนไฟล์) จะยังคงชี้ไปที่มันแม้ว่าจะถูกเปลี่ยนชื่อแล้วก็ตาม ดังนั้นจะไม่มีการสูญหายของข้อมูลหรือความเสียหายแม้ว่าไฟล์จะถูกเปลี่ยนชื่อในขณะที่มันถูกเขียนไปพร้อมกัน


ในฐานะที่เป็น Andreas Weise บันทึกในคำตอบของเขาการเปลี่ยนชื่อ (2) การเรียกระบบ (และfs.rename()ใน node.js) จะไม่ทำงานข้ามขอบเขตของระบบไฟล์ ดังนั้นการพยายามย้ายไฟล์ไปยังระบบไฟล์อื่นด้วยวิธีนี้จะล้มเหลว

mvคำสั่งUnix พยายามซ่อนข้อ จำกัด นี้โดยการตรวจหาข้อผิดพลาดและย้ายไฟล์โดยการคัดลอกเนื้อหาไปยังไฟล์ใหม่และลบต้นฉบับ น่าเสียดายที่การย้ายไฟล์เช่นนี้จะทำให้ข้อมูลมีความเสี่ยงหากไฟล์ถูกย้ายในขณะที่กำลังเขียนอยู่ ดังนั้นหากคุณต้องการเปลี่ยนชื่อไฟล์ที่อาจถูกเขียนไปพร้อม ๆ กันอย่างปลอดภัยคุณไม่ควรใช้mv(หรืออย่างน้อยคุณควรตรวจสอบให้แน่ใจว่าเส้นทางใหม่และเก่าอยู่ในระบบไฟล์เดียวกัน)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.