क्या उस फ़ाइल को स्थानांतरित करना सुरक्षित है जिसे जोड़ा जा रहा है?


28

मेरे पास नोड.जेएस प्रक्रिया है जो 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

resp।

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

इस बात पर निर्भर करते हुए कि आपके आवेदन के लेखन के दौरान कॉपी एंड-ऑफ़-फ़ाइल तक पहुंचती है या नहीं, ऐसा हो सकता है कि आपके पास नई फ़ाइल में केवल एक पंक्ति हो।

इसके अतिरिक्त, यदि आपका एप्लिकेशन पुरानी फ़ाइल को बंद नहीं करता है और उसे फिर से खोल देता है, तो यह पुरानी फ़ाइल को लिखना जारी रखेगा, भले ही वह नष्ट हो जाए: कर्नेल जानता है कि कौन सी फाइलें खुली हैं और यद्यपि यह फ़ाइल-सिस्टम प्रविष्टि को हटा देगा, यह जब तक आपका एप्लिकेशन अपनी खुली फ़ाइल-हैंडल को बंद नहीं करता है, तब तक पुरानी फ़ाइल का इनकोड और संबद्ध ब्लॉक नहीं हटाएगा।


3
FYI करें, यूनिक्स के शुरुआती संस्करणों में rename()सिस्टम कॉल नहीं था । तो mvवास्तव में मूल संस्करण ने link()हार्ड लिंक बनाने के लिए कॉल किया था , इसके बाद unlink()मूल नाम को हटा दिया गया था। rename()FreeBSD में जोड़ा गया था, इसे कर्नेल में परमाणु रूप से लागू करने के लिए।
Barmar

मुझे क्षमा करें लेकिन क्या है file-system borders?
laike9m

1
@ laike9m - फ़ाइल सिस्टम सीमाएँ इस तथ्य को संदर्भित करती हैं कि एक सरल फ़ाइल सिस्टम को एक डिस्क डिवाइस की तरह एक मेमोरी डिवाइस पर एक विभाजन पर रहना पड़ता है। यदि आप फ़ाइल सिस्टम के भीतर एक फ़ाइल का नाम बदलते हैं, तो वह सब बदल जाता है जो एक निर्देशिका प्रविष्टि में नाम है। यह अभी भी एक ही इनोड है - अगर यह एक फाइल सिस्टम में इनोड्स के आधार पर शुरू करने के लिए था - जैसे अधिकांश लिनक्स फाइल सिस्टम हैं। लेकिन, यदि आप फ़ाइल को किसी अन्य फाइल सिस्टम में स्थानांतरित करते हैं, तो वास्तविक डेटा को स्थानांतरित करना होगा और फ़ाइल को नए फाइल सिस्टम से एक नया इनकोड प्राप्त होगा। यह फ़ाइल के किसी भी संचालन को बाधित करेगा जो ऐसा होने पर प्रगति पर था।
जो

9

चूंकि आप कहते हैं कि आप नोड। जेएस का उपयोग कर रहे हैं, मेरा मानना ​​है कि आप फ़ाइलों का नाम बदलने के लिए fs.rename()(या fs.renameSync()) का उपयोग कर रहे हैं। यह नोड.जेएस पद्धति का नाम बदलकर (2) सिस्टम कॉल का उपयोग करने के लिए प्रलेखित किया गया है , जो किसी भी तरह से फ़ाइल को स्पर्श नहीं करता है, लेकिन केवल उस नाम को बदलता है जिसके तहत इसे फ़ाइल सिस्टम में सूचीबद्ध किया गया है:

" नाम बदलें () एक फ़ाइल का नाम बदल देता है, यदि आवश्यक हो तो इसे निर्देशिकाओं के बीच ले जा रहा है। फ़ाइल में कोई अन्य हार्ड लिंक (जैसा कि लिंक (2) का उपयोग करके बनाया गया है ) अप्रभावित हैं। पुरानेपथ के लिए ओपन फ़ाइल विवरणक भी अप्रभावित हैं।"

विशेष रूप से, ऊपर उद्धृत अंतिम वाक्य पर ध्यान दें, जो कहता है कि कोई भी ओपन फ़ाइल डिस्क्रिप्टर (जैसे कि आपका प्रोग्राम फ़ाइल में लिखने के लिए उपयोग कर रहा होगा) का नाम बदलने के बाद भी इसे इंगित करता रहेगा। इस प्रकार, कोई डेटा हानि या भ्रष्टाचार नहीं होगा भले ही फ़ाइल का नाम बदल दिया जाए, जबकि यह एक साथ लिखा जा रहा है।


एंड्रियास वेइस अपने जवाब में नोट करते हैं , नाम बदलने (2) सिस्टम कॉल (और इस प्रकार fs.rename()नोड में। js) फाइलसिस्टम सीमाओं के पार काम नहीं करेगा। इस प्रकार, एक फाइल को एक अलग फाइल सिस्टम में इस तरह से स्थानांतरित करने का प्रयास बस विफल हो जाएगा।

यूनिक्स mvकमांड त्रुटि का पता लगाकर इस सीमा को छिपाने की कोशिश करता है और इसके बजाय, इसकी सामग्री को एक नई फ़ाइल में कॉपी करके और मूल को हटाकर फ़ाइल को स्थानांतरित करता है। दुर्भाग्य से, इस तरह फ़ाइलों को ले करता है, तो फ़ाइल, जबकि यह करने के लिए लिखा जा रहा है ले जाया जाता है जोखिम डेटा हानि। इस प्रकार, यदि आप सुरक्षित रूप से उन फ़ाइलों का नाम बदलना चाहते हैं जो एक साथ लिखी जा सकती हैं, तो आपको उपयोग नहीं करना चाहिए mv(या, कम से कम, आपको यह पूरी तरह सुनिश्चित करना चाहिए कि नया और पुराना पथ एक ही फाइल सिस्टम पर है)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.