شاید برای خیلی ها تون پیش اومده باشه که به اشتباه یک فایل یا حتی پوشه رو از فایل سیستم های ext3 و یا ext4 حذف کرده باشین ( منظورم از حذف با استفاده از دستور rm هست) و بعد هم به مطالبی بر خورده باشین که این کار ممکن نیست و کلا بی خیال ماجرا شده باشین! تو این پست می خوام دلیل به ظاهر غیرممکن بودن این قضیه و کنارش روشهایی برای ممکن کردنش و همینطور ابزارهایی رو که از این روشها استفاده می کنن بهتون معرفی کنم.
اول از همه یه توضیحی در مورد این فایل سیستم ها و ساختارشون می گم تا ادامه مطلب براتون واضح تر بشه.
شکل بالا ساختار کلی فایل سیستم های ext2/3/4 رو نشون می ده. همونطور که می بینید کل فایل سیستم به بخش هایی به اسم block group تقسیم می شه. اون قسمت اول یعنی boot block هم برای پارتیشن بوت سکتور رزرو شده و ext بهش کاری نداره. همونطور که می بینید هر block group به بخش های مختلفی تقسیم می شه. علت این تقسیم بندی اینه که فایلها کمتر تکه تکه بشن، چون کرنل همیشه سعی می کنه block هایی رو که متعلق به یه فایل هستن تو یه block group نگه داری کنه. یکی از بخش های موجود تو هر گروه Data block ها هستن که محتوای فایل تو اونها نگه داری می شه. تعداد این block ها ثابته و اگه اندازه فایل به اندازه کافی کوچیک باشه کل فایل تو یه block group نگه داری می شه ولی اگه اندازه اش بزرگتر از حدی باشه که تو یه block group جا بشه block ها در مکان دیگه ای قرار می گیرن و آدرسشون تو آخرین block از data blocks قرار می گیره. که به این نوع block ها می گن indirect block. یکی دیگه از بخش ها inode table هست که کارش نگه داری metadata های مربوط به هر فایل هست، مثل نوع فایل و مجوزهاش، انداز فایل، مالک فایل، زمانهای آخرین دسترسی و آخرین تغییر و حذف فایل، تعداد data block ها و آدرسشون و …. برای دیدن شماره inode مربوط به یه فایل می تونین از دستور ls -i filename استفاده کنین. بخش های دیگه رو هم توضیح نمی دم ولی اگه خیلی مشتاق به دونستن اینکه هر کدوم چی کار می کنن و ساختارشون چطوریه هستین، می تونین فصل ۱۸ کتاب understanding the linux kernel 3rd edition رو بخونین. البته این کتاب بیشتر در مورد فایل سیستم ext2 و در آخر فصل از ext3 گفته که البته ساختار کلی همونه ولی برای به روز بودن و متوجه شدن تغییرات می تونین یا کد کرنل رو بخونین یا تو سایتهای مختلف در موردش جستجو کنید که البته خیلی چیز خاصی پیدا نخواهید کرد. برای خوندن کد کرنل و مشاهده تغییرات موجود تو ورژنهای مختلفش و یا جستجوی تابع یا ساختار خاصی از اون هم می تونین از سایت http://lxr.linux.no استفاده کنید.
شکل بالا هم ساختار یه دایرکتوری رو نشون می ده. یکی از نکاتی که شایدم زیاد شنیده باشین اینه که توی لینوکس به همه چیز به عنوان یه فایل نگاه می شه و تفاوتشون اینه که از data block ها به شیوه های مختلف استفاده می کنن. بنابراین دایرکتوری هم به عنوان یه فایل در نظر گرفته می شه ولی از data block ها برای ذخیره نام فایلهایی که توش قرار گرفتن همراه با شماره inode متناظرشون استفاده می کنه. گزینه های rec_len و name_len و file_type هم به ترتیب طول اطلاعات موجود تو ردیف مورد نظر، طول فایل و نوع فایل رو مشخص می کنند. مثلا نوع ۲ یعنی فایل از نوع دایرکتوری هست. به عنوان نمونه تو شکل بالا inode شماره ۲۱ متعلق به . یعنی نام دایرکتوری جاری هست. طول کل ردیف ۱۲، طول نام فایل ۱ و نوع فایل از نوع ۲ یعنی دایرکتوری هست.
خاصیت journaling:
از فایل سیستم ext3 به بعد این خاصیت به فایل سیستم های ext اضافه شد ( البته فایل سیستم های زیادی این خاصیت رو دارن ) که به این صورته که فایل سیستم فضایی به اسم journal رو در نظر می گیره که metadata ها قبل از به روز شدن تو اون قرار می گیرن و بنابراین در حالتی که سیستم کرش کنه یا مشکلی براش پیش بیاد به جای اینکه سیستم عامل کل metadata ها رو بخونه وساختارشون رو بررسی کنه فقط سراغ journal می ره و اون رو یا بررسی می کنه و یا metadata ها رو جایگزین می کنه و بنابراین فرآیند بازیابی خیلی سریعتر می شه. ساختارهای metadata ها هم می تونن مثل entry های دایرکتوری و یا مثل خود inode باشن و نکته دیگه ای هم که وجود داره اینه که اگه حتی یکی از اطلاعات موجود تو این ساختار هم تغییر کنه ( مثلا زمان آخرین دسترسی ) کل اون ساختار تو journal ذخیره می شه نه فقط اون داده ای که تغییر کرده و تو این حالت مثلا کل inode ذخیره می شه.
فرآیند حذف:
وقتی که یه فایل رو از سیستم حذف می کنید فرآیند های زیادی تو فایل سیستم رخ می ده که اینجا نیاز به توضیح دادن همه اش نیست و اگه مشتاق به دونستنش باشین باز هم می تونین به همون کتابی که معرفی کردم مراجعه کنید. اما به زبون ساده و کاملا غیرفنی می شه گفت در حالت کلی سیستم عامل هر کدوم از data block ها، inode و entry دایرکتوری رو به عنوان فضای اختصاص داده نشده علامت می زنه و در نظر می گیره. مثلا در مورد entry دایرکتوری inode متناظر اون entry رو صفر می کنه و طول رکورد entry قبلی رو با entry حذف شده جمع می کنه و به عنوان طول جدید قرار می ده تا entry حذف شده نادیده گرفته بشه. که البته تو شکل هم در مورد oldfile entry که یه entry حذف شده اس می تونین این قضیه رو ببینین. توی این حالت عمل بازیابی خیلی راحته چون آدرس data block ها بعد از حذف فایل هنوز هم تو inode موجود هستن و خیلی راحت می شه با ابزارهایی مثل debugfs یا e2undel مجددا ساختار فایل رو درست کرد و به حالت اول برگردوند. اما این قضیه فقط در مورد فایل سیستم ext2 درسته. در مورد ex3 و ex4 موقع عمل حذف کار اضافه ای که صورت می گیره اینه که به دلیل اینکه این فایل سیستم ها بعد از کرش بتونن به درستی به کارشون ادامه بدن و مشکلی تو کارکردشون پیش نیاد، بعد از آزاد کردن data block ها متغیرهایی که آدرس اونها و همچنین اندازه فایل رو مشخص می کنن تو inode صفر می شن و بنابراین هر رابطه ای که بین inode و datablock های متناظرش قرار داره قطع می شه و دقیقا علت اینکه می گن بازیابی از این فایل سیستم ها ممکن نیست همینه.
اما از اونجا که به هر حال هر غیرممکنی رو با یه سری روش های هکری می شه ممکن کرد و ما مخصوصا تو دنیای متن باز از این هکرها کم نداریم، ایده های جالبی رو که تو این زمینه دادن و ابزارهایی رو که از این ایده ها استفاده می کنن معرفی می کنم.
یکی از ایده های موجود استفاده از journal هست. همونطوری که قبلا گفتم وقتی که حتی یکی از اطلاعات موجود در inode یک فایل تغییر کنه کل اون inode به طور کامل در journal نوشته می شه. یکی از این اطلاعات تاریخ آخرین دسترسی هست. بنابراین اگه اندازه پارتیشن نسبت به journal خیلی بزرگ نباشه و همینطور به فایلی که حذفش کردیم اخیرا دسترسی داشتیم می تونیم امید به بازیابی اون داشته باشیم. این ایده رو کارلو وود توسعه دهده ext3grep داده. این ابزار کار اصلی که انجام می ده اینه که journal رو برای پیدا کردن کپی های قدیمی از inode مورد نظر جستجو می کنه و در صورت پیدا کردنش با استفاده از فیلد اشاره گر به data block های مربوطه، inode اونا رو پیدا می کنه و یه کپی از فایل مورد نظر رو تو سیستم ذخیره می کنه. البته این ابزار فقط مخصوص فایل سیستم ext3 هست و رو ext4 دیگه جواب نمی ده.
برای بازیابی از فایل سیستم ext4 ابزار دیگه ای به extundelete وجود داره. این ابزار ایده اولیش رو از ext3gerp گرفته و مثل اون با جستجو در journal دنبال inode مورد نظر می گرده و در کنار این کار سعی می کنه entry های دایرکتوری که همونطور که تو شکل هم معلومه و گفتم معمولا پاک نمی شن و سر جاشون باقی می مونن رو با اون inode مورد نظر match کنه تا اسم فایل مورد نظر رو هم پیدا کنه و اگر هم پیداش نکرد یه دور هم journal رو برای پیدا کردن entry مورد نظر جستجو می کنه تا بالاخره بتونه اسم فایل رو پیدا کنه که این قسمت دوم یعنی جستجو در journal برای پیدا کردن نام دایرکتوری درext3gerep تا جایی که من می دونم انجام نمی شه و تنها سعی می کنه با جستجو در entry های دایرکتوری نام فایل رو پیدا کنه. این ابزار با اینکه ایده اصلی ext3grep رو گرفته ولی به دلایل مختلف در اکثر مواقع استفاده از اون نسبت به ext3grep ارجح تره. از جمله اینکه همونطور که گفتم علاوه بر فایل سیستم ext3 فایل سیستم ext4 رو هم پشتیبانی می کنه و یا به دلیل اینکه از کتابخونه ext2fs استفاده می کنه خیلی از مشخصه های ext3/4 به طور اتوماتیک توش ساپورت می شن و یا چون بعد از بررسی journal می تونه عمل بازیابی رو انجام بده سرعتش برای فضاهای زیاد نسبت به ext3grep خیلی بالاتره. ext3grep بعد از بررسی journal باید کل فضایی رو که بهش برای بازیابی دادیم بررسی کنه و بعد عمل بازیابی رو شروع می کنه بنابراین فقط برای فضاهای کم استفاده از اون بهینه تره. البته اینم اضافه کنم که آپشن های موجود تو ext3grep از extundelete بیشترن و امکان بررسی به صورت دستی علاوه بر بررسی به صورت اتوماتیک توش وجود داره و کلا دست آدم برای دست و پنجه نرم کردن با فایل سیستم بیشتر توش بازه.
ایده بعدی استفاده از header و footer موجود در انواع فایل هاست. همونطور که می دونین ( یا اگه نمی دونین الان دیگه متوجه می شین ) بعضی از انواع فایلها با یه سری مقادیر در چند بایت اول header شون شروع می شن و با یه سری مقادیر در چند بایت آخر footer شون به پایان می رسن. مثلا یک فایل JPEG با 0xffd8 شروع می شه و با 0xffd9 به پایان می رسه. بنابراین می شه یه فضایی رو مشخص کرد و تو اون فضا block هایی با این مقادیر رو جستجو کرد و فضای بین این دو block رو به عنوان فایل در نظر گرفت. برای کوچکتر کردن فضا هم می شه از debugfs و Sleuth Kit استفاده کرد. به این صورت که inode حذف شده رو پیدا کرد و تو block group مربوط به اون دنبال block های اختصاص یافته نشده گشت و بررسی رو فقط رو اونا انجام داد. البته این روش مشکلات زیادی داره. اول اینکه همه فایلها ممکنه header یا footer خاصی نداشته باشن و یا header یا footer های مختلفی داشته باشن. مثلا یک فایل MPEG هم ممکنه با 0x000001ba آغاز بشه و با 0x000001b9 به پایان برسه و هم با 0x000001b3 شروع بشه و با 0x000001b7 به پایان برسه و بنابراین باید تمام شرایط موجود رو در نظر گرفت. ابزارهایی مثل photorec و foremost و همینطور آپشن search از ext3grep و خیلی از ابزارهای تجاری از این روش استفاده می کنند.
ایده بعدی یه جورایی brute force کردن فایل سیستم با استفاده از ابزار grep هست. همونطور که می دونین با استفاده از ابزار grep می شه یک الگو یا یک متن خاص رو در خطوط مختلف یک یا چند فایل جستجو کرد. بنابراین اگه حتی از وجود یک الگو یا عبارت خاص در فایل حذف شده اتون خبر داشته باشین می تونین اون رو با روشی که در ادامه توضیح خواهم داد بازیابی کنید.
فرآیندی که بعد از حذف یک یا چند فایل از سیستم باید انجام بدین:
قبل از گفتن هر چیزی اینو باید بگم که بازیابی نه فقط از این فایل سیستم ها بلکه از هر فایل سیستمی نیازمند این هست که اطلاعات جدیدی روی اطلاعات قبلی نوشته نشده باشند و بنابراین اگه واقعا چنین مشکلی براتون پیش اومد هیچ کاری انجام ندین و سیستم رو یا با یه دیسک زنده راه اندازی کنید و یا اگه سیستم عامل دیگه ای دارین از طریق اون سیستم رو بوت کنید و یا اگه اون پارتیشن، پارتیشن روت سیستم نیست ( مثلا پارتیشن home ) اون رو umount کنید و یا اگر پارتیشن روت هست اون رو به صورت ro یا همون read only مجددا mount کنید و بعد فرآیند بازیابی رو انجام بدین این نکته رو هم در نظر داشته باشین که بعد از حذف فایل حتی اگه شما دستی هم رو فایل سیستم چیزی ننویسید ممکنه یه سری از پروسس های در حال اجرا (مثلا پروسس هایی که در کنار کارشون وقایع مورد نظر رو هم در سیستم ثبت می کنن) بیان و از سر بدشانسی شما رو همون بلاک هایی که حذف کردین اطلاعات جدید رو بنویسن بنابراین کارهایی رو که گفتم به محض حذف ناخواسته فایل انجام بدین.
بعد از انجام اعمال فوق می تونین یک پشتیبان از فایل سیستم مورد نظرتون به این صورت بگیرین و تست ها رو روی اون انجام بدین. البته بعد از اینکه این بلا سرتون اومد کلا درس عبرت می گیرین که همیشه یه پشتیبان از سیستمتون تهیه کنین!
dd if=/dev/partition of=backup
البته قبل از umount کردن پارتیشن یا بقیه کارهایی که گفتم یه بررسی بکنین که آیا فایل مورد نظرتون توسط یه برنامه دیگه در حال اجراست و آیا شما در حین اجرا به طور تصادفی حذفش کردین یا نه و اگه اینطوری بود روندی رو که می گم تست کنید و اگه جواب نداد که البته معمولا باید جواب بده، مراحل بعدی رو دنبال کنید. مثلا من یه فایل موسیقی به نام ocarina.mp3 که در مسیر home/zahra/ وجود داره و در حال پخش شدن هم هست رو حذف می کنم. اول از همه اطلاعات شماره پروسس ( PID ) و توصیف کننده فایل ( fd ) مربوط به اون رو از طریق دستور زیر به دست میارم:
zahra@belendax ~ $ lsof | grep /home/zahra/implora.mp3
vlc 4451 zahra 13r REG 8,6 3697716 830396 /home/zahra/implora.mp3 (deleted)
که این خروجی نشون می ده این فایل در حال حاضر داره توسط vlc و با شماره پروسس ۴۴۵۱ و توصیف کننده فایل ۱۳ اجرا می شه. پس خیلی راحت فایل رو از مسیر مربوط به پروسسش یه جای دیگه کپی می کنم. مثلا:
zahra@belendax ~ $ cp /proc/4451/fd/13 /home/zahra/implora2.mp3
در صورتی که این روش جواب نداد یا اصلا فایلی که حذف کردین توسط هیچ برنامه خاصی اجرا نمی شد عمل umount کردن و یا بقیه اعمالی که گفتم رو انجام بدین و مراحل زیر رو دنبال کنید:
قدم اول استفاده از نرم افزار extundelete هست. اول از همه این نرم افزار رو از اینجا دانلود کنید و بعد اون رو از حالت فشرده خارج کنید و کامپایل و نصب کنید. با اجرای
extundelete –help
می تونین آپشن های مختلفی رو که این ابزار برای بازیابی استفاده می کنه مشاهده کنید. مثلا
extundelete /dev/partition –restore-file /path/of/file
فایلی رو که تو مسیر مورد نظر اون پارتیشن وجود داشته و حذف شده بازیابی می کنه.
درصورتی که extundelete موفق به انجام این کار نشد و فایل سیستم شما ext3 بود می تونین ext3grep رو هم امتحان کنید. ( البته “معمولا” وقتی اون جواب نده اینم جواب نمی ده). به هر حال این نرم افزار رو هم می تونید از اینجا دانلود کنید. این رو هم به همون صورت از حالت فشرده خارج و بعد کامپایل کنید. برای این هم به همون صورت با اجرای
ext3grep –help
می تونین آپشن های مختلفش رو ببینید. در مورد نحوه استفاده هم فکر می کنم توسعه دهنده این پروژه خیلی کامل و قشنگ طریقه استفاده ازش رو ذکر کرده و من اینجا نیاز به توضیح اضافه ای نمی بینم.
اگر این روش هم جواب نداد و فرمت فایلی که حذف کردین رو می دونستین و در ضمن این فرمت توسط ابزارهایی که گفتم( foremost و …) پشتیبانی می شد یا حداقل خودتون می دونستین که فرمت مورد نظرتون با چی شروع می شه و به پایان می رسه می تونین از اون ابزارها استفاده کنین. فقط قبلش بهتره که فضای مورد جستجو توسط این ابزارها رو تا حد ممکن کوچیک کنید تا وقت زیادی ازتون تلف نشه. همونطور که گفتم data block ها سعی می کنند که با inode مورد نظرشون در یک block group ذخیره بشن. ( البته در حالتی که indirect block نداشته باشیم ) ، برای همین می تونیم به جای کل فایل سیستم فقط block group مربوطه رو جستجو کنیم و همینطور در این block group هم تنها باید block هایی رو در نظر بگیریم که آزاد یا تخصیص نیافته هستند. برای انجام این اعمال می تونیم از debugfs یا TSK استفاده کنیم. روش کار رو با استفاده از یک مثال نشون می دم. به عنوان مثال من یک فایل به اسم server.jpg رو در مسیر home/zahra/ از پارتیشن dev/sda7/ حذف می کنم و بعد برای بازیابی دستورات رو به این صورت وارد می کنم. اول از همه debugfs رو اجرا می کنم:
belendax zahra # debugfs /dev/sda7
debugfs 1.41.9 (22-Aug-2009)
debugfs:
بعد به مسیر مورد نظر می رم:
debugfs: cd /home/zahra
debugfs:
بعد با استفاده از فرمان ls -d فایلهای موجود و حذف شده رو در پوشه جاری می بینم:
51094 (52) .bash_history <51095> (28) server.jpg
58120 (24) killer.c 58793 (16) Music
دقت کنید که من فقط یه قسمت از خروجی رو لیست کردم. فایلهای حذف شده شماره inode اشون بین علامتهای <> هست که همونطور که مشاهده می کنید فایل server.jpg که من حذف کردم جز فایلهای حذف شده نشون داده و شماره inode اش برابر با ۵۱۰۹۵ هست. با استفاده از این شماره inode می تونیم با زدن دستور زیر شماره block group مربوطه رو به دست بیاریم:
debugfs: imap <51095>
Inode 51095 is part of block group 6
located at block 196731, offset 0×0600
debugfs:
که خروجی به ما میگه این inode تو block group شماره ۶ هست. حالا باید محدوده block های موجود تو این گروه رو مشخص کنیم. برای همین اول باید متوجه بشیم که تو هر گروه چند تا block وجود داره. این مقدار معمولا ۳۲۷۶۸ تاست ولی خوب برای اطمینان دستور زیر رو بزنید و دنبال مقدار Blocks per group بگردین:
debugfs: stats
…
Blocks per group: 32768
…
خوب حالا می تونیم محدوده بلاک های گروه ۶ رو محاسبه کنیم. که این محدوده از ۱۹۶۶۰۸(۶*۳۲۷۶۸) تا ۲۲۹۳۷۵(۱-۷*۳۲۷۶۸) هست. حالا فرمان quit رو می زنیم تا از debugfs خارج بشیم. برای به دست آوردن block های آزاد از ابزار blkls که در TSK موجود هست استفاده می کنیم:
blkls /dev/sda7 196608-229375 > test.jpg
حالا می تونیم فایل test.jpg رو به عنوان ورودی به ابزارهایی که گفتم بدیم تا فایل JPEG موجود رو بتونن ازش استخراج کنن.
در صورتی که این روش هم جواب نداد می ریم سراغ ایده آخر. یعنی جستجوی یک الگو یا عبارت در فایل باینری. این روش رو هم با ذکر یک مثال توضیح می دم:
مثلا من یک فایل از نوع متنی داشتم که حذفش کردم و می دونم که توش عبارت “this is a test” وجود داشته. اول از همه فایل سیستم مورد نظرم رو umount می کنم و بعد دستور زیر رو تو کنسول وارد می کنم:
grep –binary-files=text -10 “this is a test” /dev/sda7 > recover
با آپشن binary-files نوع فایلم رو که یک فایل متنی بوده مشخص کردم. آپشن 10 یعنی ۱۰ خط قبل و ۱۰ خط بعد از الگوی مورد نظر رو تو فایل خروجی که همون recover هست بریز. dev/sad7/ هم پارتیشنی هست که این بررسی رو روش انجام دادم. این روش بسته به فضای فایل سیستم یه مقدار وقت می بره. اما اگه چیزجدیدی رو اون بلاک ها نوشته نشده باشه حتما جواب می گیرین و کلا ربطی به نوع فایل سیستمی که ازش استفاده می کنین نداره.
اگه بعد از طی کردن تمام این روشها بازم جواب نگرفتین اگه خیلی سمج هستین دنبال یه ایده جدید بگردین اگرم که نه کلا بی خیال ماجرا بشین و برای آینده یادتون باشه که یه پشتیبانی دوره ای خودکار از سیستمتون تهیه کنید!
تبصره ۱: اگه کلا زدین پارتیشن رو پروندین می تونین از ابزار testdisk برای به دست آوردن partition table قبلی استفاده کنید.
تبصره ۲: علت اینکه آن دو فایل برای دانلود روی سرور اینجانب قرار داده شده، راحتی کار ایرانیان گرامی می باشد! چون یکی از آنها در sf و دیگری در google code می باشد و خدا را شکر این دو دوست گرامی در صدر دوستان دیگر با هدف خیری که جز رسیدن ما به استقلال چیز دیگری نمی باشد، ما را تحریم نموده اند!
تبصره ۳: تمام برنامه هایی که اسم بردم ebuild اشون واسه جنتو نوشته شده و تو portage یافت می شن! اینو فقط محض این گفتم که بدونین تو portage نیست در جهان هم یافت می شه و کلا Gentoo Rocks!
منابع:
Understanding The Linux Kernel 3rd edition
http://www.xs4all.nl/~carlo17/howto/undelete_ext3.html
http://extundelete.sourceforge.net/
http://linux.sys-con.com/node/117909/


