Add the implementation of tfs
[thunix.git] / fs / tfs / dir.c
blob1f022f6ace393d4733013e71aedf596e0c60f65e
1 #include <stdio.h>
2 #include <string.h>
3 #include <malloc.h>
5 #include "tfs.h"
6 #include "cache.h"
7 #include "dirent.h"
9 /*
10 * NOTE! unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
12 * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller.
14 static inline int tfs_match_entry (const char * const name,
15 struct tfs_dir_entry * de)
17 if (!de->d_inode)
18 return 0;
19 return !strncmp(name, de->d_name, strlen(name));
22 struct tfs_dir_entry * tfs_find_entry(struct tfs_sb_info *sbi,
23 const char *dname,
24 struct inode *inode)
26 uint32_t block;
27 int i = 0;
28 int index = 0;
29 struct tfs_dir_entry *de;
30 struct cache_struct *cs;
32 block = inode->i_data[index++];
33 if (!block)
34 return NULL;
35 cs = get_cache_block(sbi, block);
36 de = (struct tfs_dir_entry *)cs->data;
38 while(i < (int)inode->i_size) {
39 if ((char *)de >= (char *)cs->data + sbi->s_block_size) {
40 if ((block = inode->i_data[index++]) < sbi->s_data_area)
41 return NULL;
42 cs = get_cache_block(sbi, block);
43 de = (struct tfs_dir_entry *)cs->data;
45 if (tfs_match_entry(dname, de))
46 return de;
48 de++;
51 return NULL;
54 int tfs_add_entry(struct tfs_sb_info *sbi, struct inode *dir, const char *name, int inr, int * dirty)
56 uint32_t block;
57 int i = 0, index = 0;
58 struct cache_struct *cs;
59 struct tfs_dir_entry *de;
61 if (strlen(name) > TFS_NAME_LEN) {
62 printk("ERROR: file name too long!\n");
63 return -1;
66 if (!(block = dir->i_data[index++]))
67 goto alloc_new_block;
68 cs = get_cache_block(sbi, block);
69 de = (struct tfs_dir_entry *)cs->data;
70 while (i <= (int)dir->i_size) {
71 if ((void *)de >= cs->data + sbi->s_block_size) {
72 if (!(block = dir->i_data[index++]))
73 break;
74 cs = get_cache_block(sbi, block);
75 de = (struct tfs_dir_entry *)cs->data;
77 if (!de->d_inode)
78 break;
79 i += sizeof(struct tfs_dir_entry);
80 de++;
83 *dirty = 0;
85 alloc_new_block:
86 /* allocate a new block to hold the new entry */
87 if (!block) {
88 block = tfs_alloc_block(sbi, sbi->s_data_area);
89 dir->i_data[index - 1] = block;
90 if (block == -1) {
91 printk("ERROR: allocate new block failed, out of space!\n");
92 return -1;
94 cs = get_cache_block(sbi, block);
95 de = (struct tfs_dir_entry *)cs->data;
96 memset(cs->data, 0, sbi->s_block_size);
98 /*
99 * This will go through the next if sentence, since if we
100 * allocated a new entry, then 'i >= dir->i_size' would
101 * be true.
105 if (i >= dir->i_size) {
106 /* Add a new entry at last */
107 dir->i_size += sizeof(struct tfs_dir_entry);
109 /* tell the caller to update this inode */
110 *dirty = 1;
114 * Else, we find a unused hole, this usually happens when user
115 * removes a file or directory, so we can just fill up
116 * the hole, and do not need allocate more space.
118 de->d_inode = inr;
119 memcpy(de->d_name, name, strlen(name));
121 /* write the entry back to disk */
122 tfs_bwrite(sbi, block, cs->data);
124 return 0;
128 int tfs_mkdir(struct tfs_sb_info *sbi, const char *path)
130 struct inode *dir;
131 struct inode *parent_dir;
132 int dirty;
133 int res = 0;
135 dir = tfs_mknod(sbi, path, TFS_DIR, &parent_dir);
136 if (!dir) {
137 TFS_DEBUG("mknod for path failed!\n");
138 return -1;
141 res = tfs_add_entry(sbi, dir, ".", dir->i_ino, &dirty);
142 if (res == -1) {
143 TFS_DEBUG("trying to add '.' under %s failed!\n", path);
144 goto out;
147 res = tfs_add_entry(sbi, dir, "..", parent_dir->i_ino, &dirty);
148 if (res == -1) {
149 TFS_DEBUG("trying to add .. under %s failed!\n", path);
150 goto out;
153 if (dirty)
154 tfs_iwrite(sbi, dir);
155 out:
156 free_inode(dir);
157 if (this_dir->dd_dir->inode != parent_dir)
158 free_inode(parent_dir);
160 return res;
165 /* for relative path searching */
166 DIR *this_dir;
168 DIR *tfs_opendir(struct tfs_sb_info *sbi, const char *path)
170 DIR *dir = malloc(sizeof(*dir));
172 if (!dir) {
173 printk("malloc for DIR structure error!\n");
174 return NULL;
177 dir->dd_dir = tfs_open(sbi, path);
178 if (!dir->dd_dir) {
179 free(dir);
180 return NULL;
183 return dir;
186 /* read one directry entry at a time */
187 struct dirent * tfs_readdir(DIR *dir)
189 struct dirent *dirent;
190 struct tfs_dir_entry *de;
191 struct cache_struct *cs;
192 struct file *file = dir->dd_dir;
193 struct inode *inode = file->inode;
194 struct tfs_sb_info *sbi = file->sbi;
195 int index = file->offset >> sbi->s_block_shift;
196 uint32_t block;
198 if (file->offset >= inode->i_size)
199 return NULL;
200 if (!(block = tfs_bmap(inode, index)))
201 return NULL;
202 cs = get_cache_block(sbi, block);
203 de = (struct tfs_dir_entry *)(cs->data + (file->offset & (sbi->s_block_size- 1)));
205 if (!(dirent = malloc(sizeof(*dirent)))) {
206 printk("malloc dirent structure in tfs_readdir error!\n");
207 return NULL;
209 memset(dirent, 0, sizeof(*dirent));
210 dirent->d_ino = de->d_inode;
211 dirent->d_off = file->offset;
212 dirent->d_reclen = sizeof(struct tfs_dir_entry);
213 dirent->d_type = 0;
214 memcpy(dirent->d_name, de->d_name, TFS_NAME_LEN);
216 file->offset += sizeof(struct tfs_dir_entry);
218 return dirent;
222 void tfs_closedir(DIR *dir)
224 if (dir) {
225 free_inode(dir->dd_dir->inode);
226 free(dir->dd_dir);
227 free(dir);
231 #if 0 /* the debug part */
232 int main(int argc, char *argv[])
235 #endif