diff --git a/fs/exec.c b/fs/exec.c index 3b5427bd29c2f0eff59cd177ec52ee6beec9b4e2..b38f3b21636b9e1a2914307bbf746995b3449234 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -42,7 +42,7 @@ static unsigned long * create_tables(char * p,int argc,int envc) { return sp; } -static int count(char ** argv) { +int count(char ** argv) { int i=0; char ** tmp; if ((tmp = argv)) { diff --git a/kernel/main.c b/kernel/main.c index 2bd10c441e3d06892fb861a42942517aeb3ddc8c..ffd784b7c2fb516872246f03f1fd3fe90ef21507 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -172,7 +172,7 @@ static void run_sh() { int pid; if (!(pid=fork())) { printf("read to start shell\n"); - execve("/bin/sh",argv,envp); + execve("/tmp/et",argv,envp); } } @@ -182,8 +182,8 @@ void init() { (void) dup(0); (void) dup(0); - //run_sh(); - easy_shell(); + run_sh(); + //easy_shell(); printf("Free mem: %d bytes\n\r",memory_end-main_memory_start); } diff --git a/tools/Makefile b/tools/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..068a861be71656ce953b9dfaf2f04c31494b0ef3 --- /dev/null +++ b/tools/Makefile @@ -0,0 +1,25 @@ +rt.img: mfs et root.img + ./mfs -c et -t /tmp/et -o rt.img root.img + +mfs: mfs.cpp utils.cpp mfs.h + g++ -o mfs mfs.cpp utils.cpp + +et: myld test + ./myld test + +myld: myld.c + gcc -o myld myld.c + +test: test.o + ld -Ttext 0x0 --oformat binary -o test test.o + +test.o: test.S + as -o test.o test.S + +clean: + -rm test + -rm test.o + -rm myld + -rm et + -rm mfs + -rm rt.img diff --git a/tools/mfs.cpp b/tools/mfs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e23f2b4d0fd9222034c2888c39a3af9d27d0d615 --- /dev/null +++ b/tools/mfs.cpp @@ -0,0 +1,570 @@ +#include "mfs.h" + +#include +#include +#include +#include + +#define BLOCKS 1440 + +Mode mode; + +FILE* img_file = NULL; +FILE* tfile = NULL; + +#define UPPER(size,n) ((size+((n)-1))/(n)) + +#define INODE_SIZE (sizeof(struct d_inode)) +#define INODE_BLOCKS UPPER(INODES,INODES_PER_BLOCK) +#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE) + + +#define BITS_PER_BLOCK (BLOCK_SIZE<<3) + +static char super_block_buffer[BLOCK_SIZE]; +#define Super (*(struct super_block *)super_block_buffer) + +#define INODES (Super.s_ninodes) +#define ZONESIZE (Super.s_log_zone_size) +#define ZONES (Super.s_nzones) +#define MAXSIZE (Super.s_max_size) +#define IMAPS (Super.s_imap_blocks) +#define ZMAPS (Super.s_zmap_blocks) +#define MAGIC (Super.s_magic) +#define FIRSTZONE (Super.s_firstdatazone) + +#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS) + +static char inode_map[BLOCK_SIZE * I_MAP_SLOTS]; +static char zone_map[BLOCK_SIZE * Z_MAP_SLOTS]; + +static char * inode_buffer = NULL; + +static char* images[BLOCKS] = {NULL, }; +d_inode* root = NULL; + +char* filename = NULL; +char* dir_name = NULL; +char* src_file = NULL; + +char* target_name = NULL; + +#define bitop(name,op) \ +static inline int name(char * addr,unsigned int nr) \ +{ \ + int __res; \ + __asm__ __volatile__("bt" op " %1,%2; adcl $0,%0" \ + :"=g" (__res) \ + :"r" (nr),"m" (*(addr)),"0" (0)); \ + return __res; \ +} + +bitop(bit,"") +bitop(setbit,"s") +bitop(clrbit,"r") + +#define mark_inode(x) (setbit(inode_map,(x))) +#define unmark_inode(x) (clrbit(inode_map,(x))) + +#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1)) +#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1)) + +void free_images() { + if (inode_buffer) { + delete[] inode_buffer; + inode_buffer = NULL; + } + + for (int i = FIRSTZONE; i < BLOCKS; i++) { + delete[] images[i]; + images[i] = NULL; + } +} + +void setup_super_block() { + memset(inode_map,0xff,sizeof(inode_map)); + memset(zone_map, 0xff,sizeof(zone_map)); + memset(super_block_buffer,0,BLOCK_SIZE); + + ZONESIZE = 0; + ZONES = BLOCKS; + INODES = BLOCKS / 3; + MAXSIZE = (7+512+512*512)*1024; + MAGIC = SUPER_MAGIC; + + IMAPS = UPPER(INODES,BITS_PER_BLOCK); + ZMAPS = UPPER(BLOCKS - NORM_FIRSTZONE,BITS_PER_BLOCK); + FIRSTZONE = NORM_FIRSTZONE; +} + +void setup_map() { + for (int i = FIRSTZONE ; ii_zone[n]) { + inode->i_zone[n] = get_new_block(); + } + return inode->i_zone[n]; + } + + n -= 7; + if (n < 512) { + if (is_create && !inode->i_zone[7]) { + inode->i_zone[7] = get_new_block(); + } + ind = get_block(inode->i_zone[7]); + if (is_create && !((unsigned short*)ind)[n]) + ((unsigned short*)ind)[n] = get_new_block(); + + return *(((unsigned short*)ind) + n); + } + + n -= 512; + if (is_create && !inode->i_zone[8]) + inode->i_zone[8] = get_new_block(); + + ind = get_block(inode->i_zone[8]); + + if (is_create && !((unsigned short*)ind)[n>>9]) + ((unsigned short*)ind)[n>>9] = get_new_block(); + + ind = get_block(*(((unsigned short*)ind) + (n >> 9))); + + if (!(*(((unsigned short*)ind) + (n & 511)))) { + *(((unsigned short*)ind) + (n & 511)) = get_new_block(); + } + + return *(((unsigned short*)ind) + (n & 511)); +} + +unsigned short bmap(struct d_inode* inode, int n) { + _bmap(inode, n, false); +} + +unsigned short create_block(struct d_inode* inode, int n) { + _bmap(inode, n, true); +} + +// Read an image file. +FILE* read_file() { + int i; + + img_file = fopen(filename, "r+"); + + super_block * sb = (super_block*)super_block_buffer;; + + // skip boot block + fseek(img_file, BLOCK_SIZE, 0); + + if (fread(super_block_buffer, sizeof(char), BLOCK_SIZE, img_file) != BLOCK_SIZE) { + printf("Error in super_block\n"); + return NULL; + } + int blocks = 1; + images[blocks++] = super_block_buffer; + + for (i = 0; i < sb->s_imap_blocks; i++) { + fread(inode_map + i * BLOCK_SIZE, sizeof(char), BLOCK_SIZE, img_file); + images[blocks++] = inode_map + i * BLOCK_SIZE; + } + printf("%d imap blocks read\n", i); + + for (i = 0; i < sb->s_zmap_blocks; i++) { + fread(zone_map + i * BLOCK_SIZE, sizeof(char), BLOCK_SIZE, img_file); + images[blocks++] = zone_map + i * BLOCK_SIZE; + } + printf("%d zmap blocks read\n", i); + + inode_buffer = new char[INODE_BUFFER_SIZE]; + fread(inode_buffer, sizeof(char), INODE_BUFFER_SIZE, img_file); + + printf("first zone: %d, first data zone: %u\n", + INODE_BLOCKS + 2 + sb->s_imap_blocks + sb->s_zmap_blocks, + sb->s_firstdatazone); + + for (int i = 0; i < INODE_BLOCKS; i++) { + images[2 + IMAPS + ZMAPS + i] = inode_buffer + BLOCK_SIZE * i; + } + + for (int i = FIRSTZONE; i < BLOCKS; i++) { + images[i] = new char[BLOCK_SIZE]; + if (BLOCK_SIZE != fread(images[i], sizeof(char), BLOCK_SIZE, img_file)) { + printf("error when read blocks, %d\n", i); + } + } + + root = iget(ROOT_INO); + + return img_file; +} + +m_inode* find_entry(m_inode* pwd, const char* name) { + char* pwd_block = get_block(bmap(pwd->p, 0)); + + for (int i = 0; i < pwd->p->i_size / sizeof(struct dir_entry); i++) { + struct dir_entry* dir = ((struct dir_entry*)pwd_block) + i; + if (strcmp(dir->name, name) == 0) { + return new m_inode(iget(dir->inode), dir->inode); + } + } + return NULL; +} + +m_inode* namei(const char* dir_name) { + assert(dir_name[0] == '/'); + char** dirs = split(dir_name); + char** dir_list = dirs; + + m_inode* pwd = new m_inode(root, 1); + + while (*dir_list) { + m_inode* old = pwd; + pwd = find_entry(pwd, *dir_list); + delete old; + dir_list++; + } + + free_strings(dirs); + return pwd; +} + +void list_dir() { + m_inode* inode = namei(dir_name); + char* pwd_block = get_block(bmap(inode->p, 0)); + + for (int i = 0; i < inode->p->i_size / sizeof(struct dir_entry); i++) { + struct dir_entry* dir = ((struct dir_entry*)pwd_block) + i; + printf("%d, %s\n", dir->inode, dir->name); + } + + delete inode; +} + +int find_empty_inode() { + int i = 0, j = 0, k = 0; + for (i = 0; i < IMAPS; i++) { + for (j = 0; j < BLOCK_SIZE; j++) { + char bitmap = inode_map[i * BLOCK_SIZE + j]; + if ((bitmap & 0xff) < 0xff) { + for (k = 0; k < 8; k++) { + if (((1 << k) & bitmap) == 0) { + inode_map[i*BLOCK_SIZE + j] |= (1 << k); + goto found; + } + } + } + } + } + +found: + return i * BLOCK_SIZE * 8 + j * 8 + k; +} + +m_inode* get_new_dir_inode(m_inode* parent) { + int nr = find_empty_inode(); + + d_inode* inode = iget(nr); + inode->i_mode = I_DIRECTORY | 0777; + inode->i_size = 2 * sizeof(struct dir_entry); + inode->i_zone[0] = get_new_block(); + dir_entry* de = (struct dir_entry*)images[inode->i_zone[0]]; + de->inode = nr; + strncpy(de->name, ".", NAME_LEN); + + de++; + de->inode = parent ? parent->i_num : nr; + strncpy(de->name, "..", NAME_LEN); + + return new m_inode(inode, nr); +} + +m_inode* get_new_file_inode() { + int nr = find_empty_inode(); + d_inode* inode = iget(nr); + inode->i_zone[0] = get_new_block(); + inode->i_zone[1] = get_new_block(); + inode->i_size = BLOCK_SIZE * 2; + inode->i_mode = I_REGULAR | 0777; + + return new m_inode(inode, nr); +} + +void write_image() { + tfile = fopen(target_name, "w+"); + // skip boot block + fwrite(images[1], sizeof(char), BLOCK_SIZE, tfile); + for (int i = 1; i < BLOCKS; i++) { + fwrite(images[i], sizeof(char), BLOCK_SIZE, tfile); + } + fclose(tfile); +} + +m_inode* create_new_file() { + char* parent_name = get_dir_name(dir_name); + m_inode* parent = namei(parent_name); + const char* dname = get_entry_name(dir_name); + printf("new file: %s\n", dname); + + m_inode* ndnode = get_new_file_inode(); + + char* pwd_block = get_block(bmap(parent->p, 0)); + struct dir_entry* dir = (struct dir_entry*)pwd_block; + + int i = 0; + for (i = 0; i < parent->p->i_size / sizeof(struct dir_entry); i++) { + if (!dir->inode) { + dir->inode = ndnode->i_num; + strncpy(dir->name, dname, NAME_LEN); + break; + } + + if ((char*)dir > pwd_block + BLOCK_SIZE) { + pwd_block = get_block(bmap(parent->p, i / DIR_ENTRIES_PER_BLOCK)); + dir = (struct dir_entry*)pwd_block; + } + + dir++; + } + + if (i * sizeof(struct dir_entry) == parent->p->i_size) { + parent->p->i_size = (i + 1) * sizeof(struct dir_entry); + dir->inode = ndnode->i_num; + strncpy(dir->name, dname, NAME_LEN); + } + + return ndnode; +} + +// Copy a file into root image. +int write_file(const char* src_file, const char* dst_file) { + read_file(); + FILE* srcf = fopen(src_file, "r"); + m_inode* finode = create_new_file(); + dir_name = get_dir_name(dir_name); + list_dir(); + + printf("i_zone[0] is %d\n", finode->p->i_zone[0]); + fread(get_block(finode->p->i_zone[0]), sizeof(char), BLOCK_SIZE, srcf); + fread(get_block(finode->p->i_zone[1]), sizeof(char), BLOCK_SIZE, srcf); + + write_image(); + fclose(img_file); + fclose(srcf); + return 0; +} + + +int make_dir() { + read_file(); + + char* parent_name = get_dir_name(dir_name); + m_inode* parent = namei(parent_name); + const char* dname = get_entry_name(dir_name); + printf("mkdir: %s\n", dname); + + m_inode* ndnode = get_new_dir_inode(parent); + + char* pwd_block = get_block(bmap(parent->p, 0)); + struct dir_entry* dir = (struct dir_entry*)pwd_block; + + int i = 0; + for (i = 0; i < parent->p->i_size / sizeof(struct dir_entry); i++) { + if (!dir->inode) { + dir->inode = ndnode->i_num; + strncpy(dir->name, dname, NAME_LEN); + break; + } + + if ((char*)dir > pwd_block + BLOCK_SIZE) { + pwd_block = get_block(create_block(parent->p, i / DIR_ENTRIES_PER_BLOCK)); + dir = (struct dir_entry*)pwd_block; + } + + dir++; + } + + if (i * sizeof(struct dir_entry) == parent->p->i_size) { + parent->p->i_size = (i + 1) * sizeof(struct dir_entry); + dir->inode = ndnode->i_num; + strncpy(dir->name, dname, NAME_LEN); + } + + dir_name = parent_name; + list_dir(); + + delete[] dname; + delete parent; + delete ndnode; + + write_image(); + free_images(); + fclose(img_file); + return 0; +} + +void setup_image() { + int blocks = 0; + // skip boot block + images[blocks++] = super_block_buffer; + // setup super block + images[blocks++] = super_block_buffer; + for (int i = 0; i < IMAPS; i++) { + images[blocks++] = inode_map + BLOCK_SIZE * i; + } + for (int i = 0; i < ZMAPS; i++) { + images[blocks++] = zone_map + BLOCK_SIZE * i; + } + for (int i = 0; i < INODE_BLOCKS; i++) { + images[blocks++] = inode_buffer + BLOCK_SIZE * i; + } + + assert(blocks == FIRSTZONE); + while (blocks < BLOCKS) { + images[blocks++] = new char[BLOCK_SIZE]; + } +} + +void init_fs() { + setup_table(); + setup_image(); + img_file = fopen(filename, "w+"); + + // create an empty dir, root. + delete get_new_dir_inode(NULL); + write_image(); + + free_images(); + fclose(img_file); +} + +int main(int argc, char** argv) { + char * t; + + int i = 0; + FILE* img_file = NULL; + + while (argc--) { + t = argv[i++]; + + if (t[0] == '-') { + if (t[1] == 'r') { + mode = READ; + } + else if (t[1] == 'l') { + argc--; + dir_name = argv[i++]; + mode = LIST; + } + else if (t[1] == 'c') { + argc--; + src_file = argv[i++]; + mode = COPY; + } + else if (t[1] == 't') { + argc--; + dir_name = argv[i++]; + mode = COPY; + } + else if (t[1] == 'm') { + argc--; + dir_name = argv[i++]; + mode = MAKE_DIR; + } + else if (t[1] == 'i') { + mode = INIT; + } + else if (t[1] == 'o') { + argc--; + target_name = argv[i++]; + } + } + else { + filename = t; + } + } + + if (mode == READ) { + return 0; + } + else if (mode == LIST) { + read_file(); + list_dir(); + return 0; + } + else if (mode == COPY) { + write_file(src_file, dir_name); + return 0; + } + else if (mode == MAKE_DIR) { + make_dir(); + return 0; + } + else if (mode == INIT) { + init_fs(); + } + + + return 0; +} + diff --git a/tools/mfs.h b/tools/mfs.h new file mode 100644 index 0000000000000000000000000000000000000000..303926f068e6e7386fbd3741b53685266d375fa4 --- /dev/null +++ b/tools/mfs.h @@ -0,0 +1,152 @@ +#ifndef _FS_H +#define _FS_H + +#include + +#define I_DIRECTORY 0040000 +#define I_REGULAR 0100000 + +enum Mode { + READ, + WRITE, + LIST, + EXTRACT, + COPY, + MAKE_DIR, + INIT, +}; + +void buffer_init(long buffer_end); + +#define MAJOR(a) (((unsigned)(a))>>8) +#define MINOR(a) ((a)&0xff) + +#define NAME_LEN 14 +#define ROOT_INO 1 + +#define I_MAP_SLOTS 8 +#define Z_MAP_SLOTS 8 + +#define SUPER_MAGIC 0x137F + +#define NR_OPEN 20 +#define NR_INODE 32 +#define NR_FILE 64 +#define NR_SUPER 8 +#define NR_HASH 307 +#define BLOCK_SIZE 1024 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct d_inode))) +#define DIR_ENTRIES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct dir_entry))) + +struct buffer_head { + char * b_data; + unsigned long b_blocknr; + unsigned short b_dev; + unsigned char b_uptodate; + unsigned char b_dirt; + unsigned char b_count; + unsigned char b_lock; + struct task_struct * b_wait; + struct buffer_head * b_prev; + struct buffer_head * b_next; + struct buffer_head * b_prev_free; + struct buffer_head * b_next_free; +}; + +struct d_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned int i_size; + unsigned int i_time; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +}; + +class m_inode { +public: + d_inode* p; + unsigned short i_num; + + m_inode(d_inode* dp, unsigned short num): p(dp), i_num(num) {} +}; + +struct file { + unsigned short f_mode; + unsigned short f_flags; + unsigned short f_count; + struct m_inode * f_inode; + off_t f_pos; +}; + +struct super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned int s_max_size; + unsigned short s_magic; + char * s_imap[8]; + char * s_zmap[8]; +}; + +struct d_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned int s_max_size; + unsigned short s_magic; +}; + +struct dir_entry { + unsigned short inode; + char name[NAME_LEN]; +}; + + +extern struct m_inode inode_table[NR_INODE]; +extern struct file file_table[NR_FILE]; + +extern void truncate(struct m_inode * inode); +extern void sync_inodes(void); +extern int create_block(struct m_inode * inode,int block); + +extern struct m_inode * new_inode(int dev); +extern void iput(struct m_inode * inode); + +extern inline void wait_on_buffer(struct buffer_head* bh); +extern struct buffer_head * getblk(int dev, int block); +extern void ll_rw_block(int rw, struct buffer_head * bh); +extern void brelse(struct buffer_head * buf); +extern struct buffer_head * bread(int dev,int block); +extern void bread_page(unsigned long addr,int dev,int b[4]); + +extern struct m_inode * namei(const char * pathname); +extern int open_namei(const char * pathname, int flag, int mode, + struct m_inode ** res_inode); + +extern struct m_inode * get_empty_inode(void); +extern struct buffer_head * get_hash_table(int dev, int block); + +extern int new_block(int dev); +extern int free_block(int dev, int block); +extern int sync_dev(int dev); + +extern struct super_block * get_super(int dev); + +char* get_dir_name(char* full_name); +const char* get_entry_name(char* full_name); +void free_strings(char** dirs); +char** split(const char* name); + +#endif diff --git a/tools/myld.c b/tools/myld.c new file mode 100644 index 0000000000000000000000000000000000000000..9dbe8e6bae142d4437ed7d79088471c62a98858a --- /dev/null +++ b/tools/myld.c @@ -0,0 +1,39 @@ +#include +#include + +struct exec { + unsigned int a_magic; + unsigned int a_text; + unsigned int a_data; + unsigned int a_bss; + unsigned int a_syms; + unsigned int a_entry; + unsigned int a_trsize; + unsigned int a_drsize; +}; + +#define ZMAGIC 0413 + +#define BLOCK_SIZE 1024 + +char* content[BLOCK_SIZE * 2]; + +int main(int argc, char** argv) { + memset(content, 0, BLOCK_SIZE*2); + struct exec* header = (struct exec*) content; + header->a_magic = ZMAGIC; + + FILE* f = fopen("test", "r"); + unsigned int len = fread(content + BLOCK_SIZE, sizeof(char), BLOCK_SIZE, f); + printf("read %d bytes\n", len); + header->a_text = len; + fclose(f); + + f = fopen("et", "w+"); + fwrite(content, sizeof(char), BLOCK_SIZE, f); + fwrite(content + BLOCK_SIZE, sizeof(char), BLOCK_SIZE, f); + fclose(f); + + return 0; +} + diff --git a/tools/root.img b/tools/root.img new file mode 100644 index 0000000000000000000000000000000000000000..308cc89e226af2b1b9eab6ad467add4d1c4b3473 Binary files /dev/null and b/tools/root.img differ diff --git a/tools/test.S b/tools/test.S new file mode 100644 index 0000000000000000000000000000000000000000..a1649b167c56d7f4150baf3d8680baad3ce81959 --- /dev/null +++ b/tools/test.S @@ -0,0 +1,14 @@ +.code32 + +movl $4, %eax +movl $1, %ebx +movl $msg, %ecx +movl $9, %edx + +int $0x80 + +loop: + jmp loop + +msg: + .ascii "hello sh\n" diff --git a/tools/utils.cpp b/tools/utils.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b33d05092581de065b11989ac19dd455b72e2906 --- /dev/null +++ b/tools/utils.cpp @@ -0,0 +1,112 @@ +#include "mfs.h" + +#include + +void free_strings(char** dirs) { + char** dir_list = dirs; + while (*dir_list) { + delete[] (*dir_list); + dir_list++; + } + + delete[] dirs; +} + +char** split(const char* name) { + const char* p = name; + int cnt = 0; + while (*p) { + if (*p == '/') { + cnt += 1; + } + p++; + } + char** array = new char*[cnt+1]; + for (int i = 0; i < cnt + 1; i++) { + array[i] = NULL; + } + + p = name + 1; + int j = 0, i = 0; + while (*p) { + if (*p == '/') { + array[j][i++] = '\0'; + j++; + i = 0; + } + else { + if (array[j] == NULL) { + array[j] = new char[NAME_LEN + 1]; + } + array[j][i++] = *p; + } + p++; + } + + return array; +} + + +char* get_dir_name(char* full_name) { + char* p = full_name; + int len = strlen(full_name); + int dir_len = 0; + + if (full_name[len-1] == '/') { + full_name[len-1] = '\0'; + len--; + } + + p = full_name + len - 1; + + while (p >= full_name) { + if (*p == '/') { + dir_len = p - full_name; + break; + } + p--; + } + + char * d = NULL; + if (dir_len == 0) { + d = new char[2]; + d[0] = '/'; + d[1] = '\0'; + return d; + } + + d = new char[dir_len + 1]; + strncpy(d, full_name, dir_len); + d[dir_len] = '\0'; + + return d; +} + +const char* get_entry_name(char* full_name) { + char* p = full_name; + int len = strlen(full_name); + int dir_len = 0; + + if (full_name[len-1] == '/') { + full_name[len-1] = '\0'; + len--; + } + + p = full_name + len - 1; + + while (p >= full_name) { + if (*p == '/') { + dir_len = len - (p - full_name); + break; + } + p--; + } + + char * d = NULL; + d = new char[dir_len + 1]; + strncpy(d, p + 1, dir_len); + d[dir_len] = '\0'; + + return d; +} +