এই post পড়ার আগে Part 1: C তে 'ls' কমান্ড বানানো পড়ে নাও — সেখানে opendir(), DIR structure, আর GDB দিয়ে debug করা শেখানো হয়েছে।
আমার C দিয়ে systems programming শেখার যাত্রায় ফিরে আসা হলো। আগের post এ আমরা directory stream এর বেসিক শিখেছিলাম আর gdb দিয়ে ভেতরে উঁকি দিয়েছিলাম। এবার আসল কাজ — directory থেকে পড়া আর তার content print করা।
Part 1 এ যা করেছিলাম
আগের post এ আমরা একটা directory open করেছিলাম আর DIR pointer পেয়েছিলাম:
//myls.c
#include <dirent.h>
#include <stdio.h>
int main(int argc, char **argv) {
// DIR এর একটা pointer define করি
DIR *dir_stream;
// current directory (".") open করি
dir_stream = opendir(".");
// opendir error হলে NULL return করে, তাই error handle করি...
if (dir_stream == NULL) {
perror("Error while trying to open directory \n");
return 1;
}
return 0;
}
আমরা gdb ব্যবহার করে dir_stream এর ভেতরটা inspect করেছিলাম, যেখান থেকে internal structure এর বিস্তারিত দেখা গেছে। এবার সামনে এগোই আর আসলেই directory থেকে পড়ি।
readdir() ব্যবহার করা
Directory র ভেতরের জিনিস পড়তে আমরা readdir function ব্যবহার করবো, যেটা C standard library র অংশ (dirent.h এ include করা আছে)। documentation দেখি:
man readdir
তাহলে, readdir function একটা DIR pointer নেয় (যেটা আমাদের কোডে dir_stream) আর dirent struct এর একটা pointer return করে। এই struct টা dir_stream এর পরবর্তী entry কে represent করে। সব entry পড়তে আমাদের শুধু একটা loop এ readdir call করতে থাকতে হবে যতক্ষণ না NULL return করে।
dirent Structure
Documentation আমাদের আরো বলে dirent struct টা দেখতে কেমন:
struct dirent {
ino_t d_ino; // inode number
off_t d_off; // offset to next entry
unsigned short d_reclen; // length of this record
unsigned char d_type; // type of file
char d_name[256]; // filename
};
এখানে মজার ব্যাপার হলো: এই struct টা directory র প্রতিটা file সম্পর্কে কিছু কাজের তথ্য দেয়:
- d_name: File এর নাম।
- d_reclen: Directory entry র size।
তাহলে, আমরা যদি dir_stream এ iterate করি, প্রতিটা entry তে readdir call করি, আর এই value গুলো print করি — তাহলেই আমাদের নিজের একটা basic ls function তৈরি হয়ে যাবে!
closedir() ব্যবহার করা
কাজ শেষ হলে directory close করতেও ভুললে চলবে না। এর জন্য C standard library র closedir function ব্যবহার করবো (এটাও dirent.h তে আছে)।
man closedir
Directory close করতে শুধু আমাদের directory stream dir_stream এর pointer পাঠাতে হবে। সফল হলে 0 return করবে, আর error হলে -1।
সম্পূর্ণ Implementation
চলো লিখে ফেলি!
// myls.c
#include <dirent.h>
#include <stdio.h>
int main(int argc, char **argv) {
// DIR এর একটা pointer define করি
DIR *dir_stream;
// dirent struct এর একটা pointer define করি
struct dirent *dir_read;
// current directory (".") open করি
dir_stream = opendir(".");
// opendir error হলে NULL return করে, তাই error handle করি...
if (dir_stream == NULL) {
perror("Error while trying to open directory\n");
return 1;
}
// এবার ভেতরের জিনিস পড়ি:
while ((dir_read = readdir(dir_stream)) != NULL) {
printf("%s\t%d bytes\n", dir_read->d_name, dir_read->d_reclen);
}
// কাজ শেষে directory close করি
if (closedir(dir_stream) == -1) {
perror("Can't close the dir \n");
return -1;
}
return 0;
}
এবার compile করে result দেখি:
gcc -Wall -Werror -g myls.c -o myls
কোডটা ধাপে ধাপে কী করছে
আগে পুরো কোডটা একসাথে দেখলাম, এবার একটু ভেঙে বুঝি:
1. Variable declare:
DIR *dir_stream;
struct dirent *dir_read;
দুইটা pointer — একটা directory stream এর জন্য, আরেকটা প্রতিটা entry পড়ার জন্য।
2. Directory open:
dir_stream = opendir(".");
Part 1 এ এটা শিখেছি — current directory open করে DIR* পাই।
3. Loop দিয়ে entry পড়া:
while ((dir_read = readdir(dir_stream)) != NULL) {
printf("%s\t%d bytes\n", dir_read->d_name, dir_read->d_reclen);
}
এটাই মূল অংশ। প্রতিবার readdir() call হলে পরবর্তী entry র pointer আসে। NULL আসলে মানে সব entry পড়া শেষ। Arrow operator (->) দিয়ে struct এর ভেতরের field access করছি।
4. Directory close:
if (closedir(dir_stream) == -1) {
perror("Can't close the dir \n");
return -1;
}
Resource cleanup — open করলে close ও করতে হবে। Unix এর নিয়ম: যা open করো, তা close করো।
Output দেখি
Built-in ls command দিলে যা আসে:
$ ls
myls myls.c test_folder notes.txt
আর আমাদের নিজের myls দিলে:
$ ./myls
. 32 bytes
.. 32 bytes
myls 32 bytes
myls.c 32 bytes
test_folder 32 bytes
notes.txt 32 bytes
লক্ষ্য করো — আমাদের version এ . (current directory) আর .. (parent directory) ও দেখাচ্ছে, কারণ এগুলোও directory entry। আসল ls command এগুলো by default লুকিয়ে রাখে (hidden files — যেগুলো . দিয়ে শুরু)। ভবিষ্যতে এটা handle করবো!
আজকে কী শিখলাম
| বিষয় | কী শিখলাম |
|---|---|
readdir() | Directory stream থেকে entry পড়ে, struct dirent* return করে |
struct dirent | File এর নাম (d_name), size (d_reclen), type (d_type) ইত্যাদি ধারণ করে |
closedir() | Directory stream বন্ধ করে, resource cleanup করে |
Arrow operator (->) | Pointer দিয়ে struct এর field access করার উপায় |
| Hidden files | . দিয়ে শুরু হওয়া file গুলো — ls default এ লুকায় |
উপসংহার
আমাদের কোড directory র content list করছে ঠিক built-in ls command এর মতো — দেখতে বেশ satisfying, তাই না? Built-in ls অনেক বেশি functionality দেয়, কিন্তু আমরা এমন একটা জায়গায় আছি যেখান থেকে নিজেরাই নতুন feature যোগ করা শুরু করতে পারি। সেটা ভবিষ্যত post গুলোতে হবে।
সাথে থাকার জন্য ধন্যবাদ। Happy coding, পরের বার দেখা হবে!
সম্পূর্ণ সিরিজ
| Part | বিষয় |
|---|---|
| Part 1 | opendir(), DIR structure, GDB দিয়ে debug |
| Part 2 (এই post) | readdir(), dirent struct, closedir(), সম্পূর্ণ ls |

