tl; ডা
is_path_exists_or_creatable()
নীচে সংজ্ঞায়িত ফাংশন কল করুন ।
কঠোরভাবে পাইথন ৩. ঠিক এভাবেই আমরা রোল করি।
দুটি গল্পের টেল
"আমি কীভাবে পথের নামের বৈধতা পরীক্ষা করব এবং, বৈধ পথের নামের জন্য, সেই পাথগুলির অস্তিত্ব বা লিখনযোগ্যতা?" স্পষ্টতই দুটি পৃথক প্রশ্ন। উভয়ই আকর্ষণীয়, এবং উভয়ই এখানে সত্যিকারের সন্তোষজনক উত্তর পেয়েছে না ... বা, ভাল, আমি যে কোনও জায়গায় গ্রেপ করতে পারি।
vikki এর উত্তর সম্ভবত নিকটতম hews কিন্তু এর অসাধারণ অসুবিধেও আছে:
- অকারণে ফাইল হ্যান্ডলগুলি ( ... এবং তারপর নির্ভরযোগ্যভাবে বন্ধ করতে ব্যর্থ হয়েছে ) খোলার ।
- অকারণে ( ... এবং তারপর নির্ভরযোগ্য বন্ধ বা মুছতে ব্যর্থ ) 0-বাইট ফাইলগুলি লিখতে হবে ।
- অ-উপেক্ষাযোগ্য অবৈধ পথের নাম এবং উপেক্ষা করা ফাইল সিস্টেমের সমস্যার মধ্যে ওএস-নির্দিষ্ট ত্রুটিগুলি উপেক্ষা করা। আশ্চর্যজনকভাবে, এটি উইন্ডোজের অধীনে গুরুত্বপূর্ণ। ( নীচে দেখুন। )
- একযোগে বহিরাগত প্রক্রিয়াগুলির ফলে বর্ণের অবস্থার উপেক্ষা করা (পুনরায়) প্যাথনামটির প্যারেন্ট ডিরেক্টরিগুলি পরীক্ষা করার জন্য। ( নীচে দেখুন। )
- বাসি, ধীর বা অন্যথায় অস্থায়ীভাবে অ্যাক্সেসযোগ্য ফাইল সিস্টেমের মধ্যে থাকা এই পথের নাম থেকে প্রাপ্ত সংযোগের সময়সীমা উপেক্ষা করা। এটি সম্ভাব্য ডস- ড্রাইভ আক্রমণগুলিতে জন-মুখোমুখি পরিষেবাগুলি প্রকাশ করতে পারে । ( নীচে দেখুন। )
আমরা সব ঠিক করব।
প্রশ্ন # 0: আবার পথের বৈধতা কী?
আমাদের ভঙ্গুর মাংসের বেদনার অজগর-ছাঁদযুক্ত মশপিটগুলিতে ফেলে দেওয়ার আগে আমাদের সম্ভবত "পথের নাম বৈধতা" বলতে কী বোঝানো উচিত। বৈধতা ঠিক কি সংজ্ঞা দেয়?
"পথের নাম বৈধতা" দ্বারা আমরা বর্তমান সিস্টেমের মূল ফাইল সিস্টেমের সাথে সম্মত একটি পাথনামের সিনট্যাকটিক যথার্থতা বলতে পারি - সে পথ বা তার পিতামাত ডিরেক্টরিগুলি শারীরিকভাবে বিদ্যমান কিনা তা নির্বিশেষে। কোনও সংজ্ঞা এই সংজ্ঞা অনুসারে সিন্থেটিকভাবে সঠিক হয় যদি এটি মূল ফাইল সিস্টেমের সমস্ত সিনট্যাকটিক প্রয়োজনীয়তা মেনে চলে।
"রুট ফাইল সিস্টেম," দ্বারা আমাদের অর্থ:
- পসিক্স-সামঞ্জস্যপূর্ণ সিস্টেমে ফাইল সিস্টেমটি রুট ডিরেক্টরিতে মাউন্ট করে (
/
)।
- উইন্ডোজে, ফাইল সিস্টেমে মাউন্ট করা হয়েছে
%HOMEDRIVE%
, বর্তমান উইন্ডোজ ইনস্টলেশন (সাধারণত তবে প্রয়োজনীয়ভাবে নয়C:
) সহ কোলন-প্রত্যয়যুক্ত ড্রাইভ লেটার ।
পরিবর্তে "সিনট্যাকটিক যথার্থতা" এর অর্থ মূল ফাইল সিস্টেমের ধরণের উপর নির্ভর করে। জন্য ext4
(এবং সবচেয়ে কিন্তু না সব POSIX সামঞ্জস্যপূর্ণ) ফাইল সিস্টেম, একটি পথনাম চিহ্নগুলি সিন্টেক্সের সঠিক যদি এবং কেবল যে পথনাম যদি:
- কোনও নাল বাইট নেই (অর্থাত্
\x00
পাইথনে)। এটি সমস্ত পসিক্স-সামঞ্জস্যপূর্ণ ফাইল সিস্টেমগুলির জন্য একটি কঠোর প্রয়োজনীয়তা।
- 255 বাইটের চেয়ে বেশি কোনও পথের উপাদান নেই (যেমন,
'a'*256
পাইথনে)। একটি পাথ উপাদান একটি পথনাম কোন ধারণকারী একটি দীর্ঘতম সাবস্ট্রিং হয় /
অক্ষর (যেমন, bergtatt
, ind
, i
, এবং fjeldkamrene
পথনাম মধ্যে /bergtatt/ind/i/fjeldkamrene
)।
সিনট্যাকটিক নির্ভুলতা। রুট ফাইল সিস্টেম। এটাই.
প্রশ্ন # 1: এখন আমরা কীভাবে পথের নাম বৈধতা করব?
পাইথনে প্যাথনামগুলির বৈধকরণ আশ্চর্যজনকভাবে অ-স্বজ্ঞাত। আমি এখানে নকল নামের সাথে দৃ agreement় চুক্তিতে রয়েছি : অফিসিয়াল os.path
প্যাকেজটির উচিত এটির জন্য একটি বাইরের সমাধান সমাধান সরবরাহ করা। অজানা (এবং সম্ভবত উদ্বেগহীন) কারণে, এটি হয় না। ভাগ্যক্রমে, আপনার নিজস্ব অ্যাডহক সমাধানটি আনرول করা সেই অন্ত্রের রেঞ্চিং নয় ...
ঠিক আছে, এটা আসলে। এটি লোমশ; এটা খারাপ; এটি জ্বলন্তভাবে বোরবাক হয়ে ওঠে এবং ঝাঁকুনির সাথে সাথে এটি গিরিযুক্ত হয়। তবে তুমি কি করবে? নুথিন '।
আমরা শীঘ্রই নিম্ন-স্তরের কোডের তেজস্ক্রিয় অতলগুলিতে নামব। তবে প্রথমে, উচ্চ স্তরের দোকানে কথা বলা যাক। অবৈধ পথের নামগুলি পাস করার সময় মান os.stat()
এবং os.lstat()
ফাংশনগুলি নিম্নলিখিত ব্যতিক্রমগুলি উত্থাপন করে:
- অস্তিত্বহীন ডিরেক্টরিতে থাকা পথের নামগুলির উদাহরণ
FileNotFoundError
।
- বিদ্যমান ডিরেক্টরিতে থাকা পথের নামগুলির জন্য:
- উইন্ডোজ এর অধীনে, দৃষ্টান্ত
WindowsError
যার winerror
অ্যাট্রিবিউট 123
(অর্থাত, ERROR_INVALID_NAME
)।
- অন্যান্য সমস্ত ওএসের অধীনে:
- নাল বাইট (
'\x00'
উদাহরণস্বরূপ) সহ পথনামগুলির উদাহরণস্বরূপ TypeError
।
- 255 বাইট চেয়ে দীর্ঘতর পাথ উপাদান ধারণকারী pathnames জন্য দৃষ্টান্ত
OSError
যার errcode
অ্যাট্রিবিউট হল:
- সুনোস এবং ওএসের বিএসডি পরিবারের অধীনে
errno.ERANGE
,। (এটি কোনও ওএস-স্তরের বাগ হিসাবে প্রতীয়মান হয়েছে, অন্যথায় পসিক্স স্ট্যান্ডার্ডের "নির্বাচনী ব্যাখ্যা" হিসাবে উল্লেখ করা হয়েছে))
- অন্যান্য সমস্ত ওএসের আওতায়
errno.ENAMETOOLONG
,।
গুরুতরভাবে, এর দ্বারা বোঝা যায় যে বিদ্যমান ডিরেক্টরিতে থাকা কেবলমাত্র পঠনাম বৈধতাযোগ্য। os.stat()
এবং os.lstat()
ফাংশন জেনেরিক বাড়াতে FileNotFoundError
ব্যতিক্রম যখন পাশ pathnames অ বিদ্যমান ডিরেক্টরিগুলি থেকে বসবাসরত নির্বিশেষে ঐ pathnames অবৈধ বা না কিনা। ডিরেক্টরি অস্তিত্ব পথের নামটি বৈধতার চেয়ে অগ্রাধিকার নেয়।
এর অর্থ কি অস্তিত্বহীন ডিরেক্টরিতে থাকা পথের নামগুলি বৈধতাযোগ্য নয় ? হ্যাঁ - যদি না আমরা বিদ্যমান ডিরেক্টরিতে থাকার জন্য সেই সমস্ত নামগুলি সংশোধন না করি। এটি কি নিরাপদেও সম্ভব? কোনও পথের নামটি সংশোধন করা আমাদের আসল পথের নামটি বৈধকরণ থেকে বিরত রাখা উচিত নয়?
এই প্রশ্নের উত্তর দেওয়ার জন্য, উপরে থেকে স্মরণ করুন যে ext4
ফাইল সিস্টেমে সিন্টেক্সিকভাবে সঠিক প্যাথনামগুলিতে নাল বাইট বা (বি) 255 বাইটের বেশি দৈর্ঘ্যের কোনও পাথ উপাদান (ক) থাকে না । অতএব, কোনও পথের নাম বৈধ হয় এবং কেবল যদি সেই পথের নামগুলির সমস্ত পথ উপাদান বৈধ হয়। এটি বেশিরভাগ রিয়েল-ওয়ার্ল্ডের আগ্রহের ফাইল সিস্টেমগুলির ক্ষেত্রে সত্য ।ext4
সেই পেডেন্টিক অন্তর্দৃষ্টি কি আসলে আমাদের সহায়তা করে? হ্যাঁ. এটি পুরো পথের নামটি একের মধ্যে যাচাই করার বৃহত্তর সমস্যাটিকে হ্রাস করে কেবলমাত্র সেই পথের নামের সমস্ত পাথ উপাদানকে বৈধতা দেওয়ার ছোট্ট সমস্যায় পড়ে। নিম্নোক্ত অ্যালগরিদম অনুসরণ করে ক্রস-প্ল্যাটফর্ম পদ্ধতিতে যেকোন স্বেচ্ছাকৃত পাথের নামটি বৈধতাযোগ্য (সেই পথের নামটি বিদ্যমান ডিরেক্টরিতে থাকে কিনা তা নির্বিশেষে) less
- সেই পথের নামটি পাথের উপাদানগুলিতে বিভক্ত করুন (উদাহরণস্বরূপ,
/troldskog/faren/vild
তালিকায় পাথের নাম ['', 'troldskog', 'faren', 'vild']
)।
- এই জাতীয় প্রতিটি উপাদান জন্য:
- একটি নতুন অস্থায়ী পথের নাম (যেমন,
/troldskog
) এর সাথে সেই উপাদানটির সাথে গ্যারান্টিযুক্ত ডিরেক্টরিটির পাথের নামটিতে যোগদান করুন ।
- যে পথের নামটি পাস করুন
os.stat()
বা os.lstat()
। যদি সেই পথের নাম এবং সেইজন্য সেই উপাদানটি অবৈধ হয়, তবে এই কলটি জেনেরিক FileNotFoundError
ব্যতিক্রমের চেয়ে অবৈধতার ধরণকে প্রকাশ করে একটি ব্যতিক্রম বাড়ানোর গ্যারান্টিযুক্ত । কেন? কারণ সেই পথের নামটি একটি বিদ্যমান ডিরেক্টরিতে থাকে। (বিজ্ঞপ্তি যুক্তি বিজ্ঞপ্তি হয়।)
একটি ডিরেক্টরি আছে কি গ্যারান্টিযুক্ত আছে? হ্যাঁ, তবে সাধারণত একটিমাত্র: মূল ফাইল সিস্টেমের শীর্ষস্থানীয় ডিরেক্টরি (উপরে বর্ণিত হিসাবে)।
অন্য কোনও ডিরেক্টরিতে থাকা পথের নামগুলি পাস করা (এবং যার ফলে এটির নিশ্চয়তা নেই) রেস শর্তগুলিতে আমন্ত্রণ জানায় os.stat()
বা os.lstat()
আমন্ত্রণ জানায়, এমনকি যদি সেই ডিরেক্টরিটি আগে থেকেই পরীক্ষা করা হয়েছিল। কেন? কারণ বাহ্যিক প্রক্রিয়াগুলি পরীক্ষা চালানোর পরে কিন্তু সেই পথের নামটি পাস করার আগেos.stat()
বা একযোগে সেই ডিরেক্টরিটি সরাতে বাধা দেওয়া যায় না os.lstat()
। উন্মাদনা কুকুর অবমুক্ত!
উপরোক্ত পদ্ধতির পাশাপাশি রয়েছে সুরক্ষা side (নয় যে বিশেষভাবে চমৎকার?):
সামনের মুখের অ্যাপ্লিকেশনগুলি অবিশ্বাস্য উত্স থেকে স্বেচ্ছাসেবক পথের নামগুলি যাচাই করে কেবল এই জাতীয় নামগুলি কেবল পরিষেবা (ডওস) আক্রমণ এবং অন্যান্য কালো-টুপি শেননিগানগুলিতে অস্বীকার করে os.stat()
বা os.lstat()
অস্বীকার করে। ক্ষতিকারক ব্যবহারকারীরা বারবার বাসি বা অন্যথায় ধীর (যেমন এনএফএস সাম্বা শেয়ার) হিসাবে পরিচিত ফাইল সিস্টেমে থাকা পাথের নামগুলি বৈধতা দেওয়ার চেষ্টা করতে পারেন; সেক্ষেত্রে, অন্ধভাবে অন্তর্নিহিত আগমনকারী নামগুলি হয় শেষ পর্যন্ত সংযোগের সময়সীমার সাথে ব্যর্থ হতে পারে বা বেকারত্ব প্রতিরোধ করার জন্য আপনার সাধ্যের চেয়ে বেশি সময় এবং সংস্থান ব্যয় করতে পারে।
উপরের পন্থাটি কেবল রুট ফাইল সিস্টেমের রুট ডিরেক্টরিটির বিপরীতে কোনও পাথের নামের পাথ উপাদানগুলিকে বৈধতা দিয়ে এটিকে বাধ্য করে ob (এমনকি যদি এটি বাসি, ধীর বা অ্যাক্সেসযোগ্যও না হয় তবে আপনি পথের নাম বৈধতার চেয়ে বড় সমস্যা পেয়েছেন))
নিখোঁজ? দুর্দান্ত চল শুরু করি. (পাইথন 3 ধরে নেওয়া হয়েছে। দেখুন "300 এর জন্য কী ফ্রেজিলেস হোপ, লেইসেক ?")
import errno, os
ERROR_INVALID_NAME = 123
'''
Windows-specific error code indicating an invalid pathname.
See Also
----------
https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
Official listing of all such codes.
'''
def is_pathname_valid(pathname: str) -> bool:
'''
`True` if the passed pathname is a valid pathname for the current OS;
`False` otherwise.
'''
try:
if not isinstance(pathname, str) or not pathname:
return False
_, pathname = os.path.splitdrive(pathname)
root_dirname = os.environ.get('HOMEDRIVE', 'C:') \
if sys.platform == 'win32' else os.path.sep
assert os.path.isdir(root_dirname)
root_dirname = root_dirname.rstrip(os.path.sep) + os.path.sep
for pathname_part in pathname.split(os.path.sep):
try:
os.lstat(root_dirname + pathname_part)
except OSError as exc:
if hasattr(exc, 'winerror'):
if exc.winerror == ERROR_INVALID_NAME:
return False
elif exc.errno in {errno.ENAMETOOLONG, errno.ERANGE}:
return False
except TypeError as exc:
return False
else:
return True
সম্পন্ন. এই কোডে স্কুইন্ট করবেন না। ( এটি কামড়ায়। )
প্রশ্ন # 2: সম্ভবত অবৈধ পথের নাম বা ক্রিয়েটিবিলিটি, এহ?
সম্ভবত অবৈধ পথের নামের অস্তিত্ব বা সৃজনশীলতা পরীক্ষা করা উপরোক্ত সমাধানটি দেওয়া হয়, বেশিরভাগ ক্ষেত্রে তুচ্ছ। এখানে ছোট কীটি উত্তীর্ণ পথটি পরীক্ষা করার আগে পূর্বনির্ধারিত ফাংশনটি কল করতে হবে :
def is_path_creatable(pathname: str) -> bool:
'''
`True` if the current user has sufficient permissions to create the passed
pathname; `False` otherwise.
'''
dirname = os.path.dirname(pathname) or os.getcwd()
return os.access(dirname, os.W_OK)
def is_path_exists_or_creatable(pathname: str) -> bool:
'''
`True` if the passed pathname is a valid pathname for the current OS _and_
either currently exists or is hypothetically creatable; `False` otherwise.
This function is guaranteed to _never_ raise exceptions.
'''
try:
return is_pathname_valid(pathname) and (
os.path.exists(pathname) or is_path_creatable(pathname))
except OSError:
return False
হয়ে গেছে এবং হয়ে গেছে। বেশ না বাদে
প্রশ্ন # 3: সম্ভবত উইন্ডোজটিতে অবৈধ পথের নাম বা লেখার যোগ্যতা
একটি সতর্কতা অবলম্বন আছে। অবশ্যই আছে।
সরকারী os.access()
ডকুমেন্টেশন হিসাবে স্বীকার:
দ্রষ্টব্য: I / O ক্রিয়াকলাপগুলি ব্যর্থ হতে পারে এমনকি যখন os.access()
ইঙ্গিত দেয় যে তারা সফল হবে, বিশেষত নেটওয়ার্ক ফাইল সিস্টেমে ক্রিয়াকলাপগুলির জন্য যেখানে সাধারণ পসিক্স অনুমতি-বিট মডেলের বাইরে পার্থক্য থাকতে পারে mant
কারও অবাক হওয়ার কিছু নেই, উইন্ডোজই এখানে সাধারণ সন্দেহভাজন। এনটিএফএস ফাইল সিস্টেমগুলিতে অ্যাক্সেস কন্ট্রোল লিস্টের (এসিএল) ব্যাপক ব্যবহারের জন্য ধন্যবাদ, সরলিস্টিক পসিক্স অনুমতি-বিট মডেলটি অন্তর্নিহিত উইন্ডোজ বাস্তবতায় খারাপভাবে মানচিত্র করে। যদিও এটি (তর্কযোগ্যভাবে) পাইথনের দোষ নয়, তবে এটি উইন্ডোজ-সামঞ্জস্যপূর্ণ অ্যাপ্লিকেশনগুলির জন্য উদ্বেগের কারণ হতে পারে।
এটি যদি আপনি হয় তবে আরও শক্তিশালী বিকল্পের সন্ধান করা হবে। যদি পাস করা পথটি না থাকে তবে আমরা পরিবর্তে সেই পথের পিতামহিত ডিরেক্টরিতে অবিলম্বে মুছে ফেলার গ্যারান্টিযুক্ত একটি অস্থায়ী ফাইল তৈরি করার চেষ্টা করি - সৃজনশীলতার আরও একটি বহনযোগ্য (ব্যয়বহুল) পরীক্ষা:
import os, tempfile
def is_path_sibling_creatable(pathname: str) -> bool:
'''
`True` if the current user has sufficient permissions to create **siblings**
(i.e., arbitrary files in the parent directory) of the passed pathname;
`False` otherwise.
'''
dirname = os.path.dirname(pathname) or os.getcwd()
try:
with tempfile.TemporaryFile(dir=dirname): pass
return True
except EnvironmentError:
return False
def is_path_exists_or_creatable_portable(pathname: str) -> bool:
'''
`True` if the passed pathname is a valid pathname on the current OS _and_
either currently exists or is hypothetically creatable in a cross-platform
manner optimized for POSIX-unfriendly filesystems; `False` otherwise.
This function is guaranteed to _never_ raise exceptions.
'''
try:
return is_pathname_valid(pathname) and (
os.path.exists(pathname) or is_path_sibling_creatable(pathname))
except OSError:
return False
উল্লেখ্য, যে এমনকি এই না যথেষ্ট হতে পারে।
ইউজার অ্যাক্সেস কন্ট্রোল (ইউএসি), সর্বদা অনিবার্য উইন্ডোজ ভিস্তা এবং এর পরবর্তী সমস্ত পুনরাবৃত্তি সিস্টেমকে ডিরেক্টরি ডিরেক্টরি সম্পর্কিত অনুমতি সম্পর্কে স্পষ্টতই মিথ্যা বলে ধন্যবাদ জানায়। অ প্রশাসক ব্যবহারকারীদের পারেন ক্যানোনিকাল ফাইল তৈরি করার প্রচেষ্টা চালাবেন যখন C:\Windows
বা C:\Windows\system32
ডিরেক্টরি, UAC কৃত্রিম যখন তা করার ব্যবহারকারী অনুমতি দেয় আসলে একটি "ভার্চুয়াল স্টোর" যে ব্যবহারকারীর প্রোফাইলে সব নির্মিত ফাইল আলাদা। (কে সম্ভবত কল্পনা করতে পারে যে প্রতারণাকারীদের ক্ষতির দীর্ঘমেয়াদী পরিণতি হবে?)
এটা পাগলামি. এটি উইন্ডোজ।
প্রমান কর
আমাদের সাহস? উপরের পরীক্ষাগুলি চালানোর সময় হয়েছে time
যেহেতু ইউএনআইএক্স-ওরিয়েন্টেড ফাইল সিস্টেমে এনএলএল একমাত্র চরিত্র নিষিদ্ধ, তাই আসুন শীতল, কঠোর সত্যকে প্রদর্শন করার জন্য এটি গ্রহণ করা যাক - অজ্ঞাত উইন্ডোজ শেনানিগান উপেক্ষা করে, যা আমাকে স্পষ্টভাবে বিরক্ত করেছিল এবং সমান পরিমাপে আমাকে ক্রোধ করে:
>>> print('"foo.bar" valid? ' + str(is_pathname_valid('foo.bar')))
"foo.bar" valid? True
>>> print('Null byte valid? ' + str(is_pathname_valid('\x00')))
Null byte valid? False
>>> print('Long path valid? ' + str(is_pathname_valid('a' * 256)))
Long path valid? False
>>> print('"/dev" exists or creatable? ' + str(is_path_exists_or_creatable('/dev')))
"/dev" exists or creatable? True
>>> print('"/dev/foo.bar" exists or creatable? ' + str(is_path_exists_or_creatable('/dev/foo.bar')))
"/dev/foo.bar" exists or creatable? False
>>> print('Null byte exists or creatable? ' + str(is_path_exists_or_creatable('\x00')))
Null byte exists or creatable? False
বিচক্ষণতার বাইরে। ব্যথা ছাড়াই। আপনি পাইথন বহনযোগ্যতা উদ্বেগ পাবেন।