Clean up the warning messages
[thunix.git] / fs / tfs / dir.c
blob3d8982adcc39b2e9ae1950bb85833a59533ea836
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 cache_struct * tfs_find_entry(struct tfs_sb_info *sbi,
23 const char *dname,
24 struct inode *inode,
25 struct tfs_dir_entry **res)
27 uint32_t block;
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(1) {
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 (de->d_inode == 0) {
46 de++;
47 continue;
49 if (tfs_match_entry(dname, de)) {
50 *res = de;
51 return cs;
54 de++;
57 return NULL;
60 int tfs_add_entry(struct tfs_sb_info *sbi, struct inode *dir, const char *name, int inr, int * dirty)
62 uint32_t block;
63 int index = 0;
64 struct cache_struct *cs;
65 struct tfs_dir_entry *de;
67 if (strlen(name) > TFS_NAME_LEN) {
68 printk("ERROR: file name too long!\n");
69 return -1;
72 if (!(block = dir->i_data[index++]))
73 goto alloc_new_block;
74 cs = get_cache_block(sbi, block);
75 de = (struct tfs_dir_entry *)cs->data;
76 while (1) {
77 if ((void *)de >= cs->data + sbi->s_block_size) {
78 if (!(block = dir->i_data[index++]))
79 break;
80 cs = get_cache_block(sbi, block);
81 de = (struct tfs_dir_entry *)cs->data;
83 if (!de->d_inode)
84 break;
85 de++;
88 *dirty = 0;
90 alloc_new_block:
91 /* allocate a new block to hold the new entry */
92 if (!block) {
93 block = tfs_alloc_block(sbi, sbi->s_data_area);
94 if (block == -1) {
95 printk("ERROR: allocate new block failed, out of space!\n");
96 return -1;
98 if (index > TFS_N_BLOCKS) {
99 printk("file too big!\n");
100 return -1;
102 dir->i_data[index - 1] = block;
103 cs = get_cache_block(sbi, block);
104 de = (struct tfs_dir_entry *)cs->data;
105 memset(cs->data, 0, sbi->s_block_size);
108 /* Add a new entry at last */
109 dir->i_size += sizeof(struct tfs_dir_entry);
110 /* tell the caller to update this inode */
111 *dirty = 1;
113 memset(de, 0, sizeof(*de));
114 de->d_inode = inr;
115 memcpy(de->d_name, name, strlen(name));
117 /* write the entry back to disk */
118 tfs_bwrite(sbi, block, cs->data);
120 return 0;
124 int tfs_mkdir(struct tfs_sb_info *sbi, const char *path)
126 struct inode *dir;
127 struct inode *parent_dir;
128 int dirty;
129 int res = 0;
131 dir = tfs_mknod(sbi, path, TFS_DIR, &parent_dir);
132 if (!dir) {
133 TFS_DEBUG("mknod for path failed!\n");
134 return -1;
137 res = tfs_add_entry(sbi, dir, ".", dir->i_ino, &dirty);
138 if (res == -1) {
139 TFS_DEBUG("trying to add '.' under %s failed!\n", path);
140 goto out;
143 res = tfs_add_entry(sbi, dir, "..", parent_dir->i_ino, &dirty);
144 if (res == -1) {
145 TFS_DEBUG("trying to add .. under %s failed!\n", path);
146 goto out;
149 if (dirty)
150 tfs_iwrite(sbi, dir);
151 out:
152 free_inode(dir);
153 if (this_dir->dd_dir->inode != parent_dir)
154 free_inode(parent_dir);
156 return res;
161 * Check if the dir is empty or not.
163 static int is_empty_dir(struct tfs_sb_info *sbi, struct inode *dir)
165 if (dir->i_size > 2 * sizeof(struct tfs_dir_entry))
166 return 0;
167 else if (dir->i_size < 2 * sizeof(struct tfs_dir_entry))
168 return -1;
169 else
170 return 1;
174 int tfs_rmdir(struct tfs_sb_info *sbi, const char *path)
176 int res;
177 struct inode *dir;
178 struct inode *inode;
179 struct cache_struct *cs;
180 struct tfs_dir_entry *de;
181 const char * base_name = get_base_name(path);
183 if (!base_name) {
184 printk("%s: invalid path name!\n", path);
185 return -1;
188 dir = tfs_namei(sbi, path, LOOKUP_PARENT);
189 if (!dir) {
190 printk("ERROR: path not exist!\n");
191 return -1;
194 cs = tfs_find_entry(sbi, base_name, dir, &de);
195 if (!cs) {
196 printk("%s: path not exist!\n", path);
197 return -1;
200 inode = tfs_iget_by_inr(sbi, de->d_inode);
201 if (!inode) {
202 printk("%s: path not exist!\n", path);
203 return -1;
205 if (inode->i_mode != TFS_DIR) {
206 printk("%s: not a directory!\n", path);
207 return -1;
210 res = is_empty_dir(sbi, inode);
211 if (res == 0) {
212 printk("%s: path not empty!\n", path);
213 return -1;
214 } else if (res == -1) {
215 printk("%s: path correupted: the size is less than two direntry!\n", path);
216 return -1;
219 dir->i_size -= sizeof(struct tfs_dir_entry);
220 tfs_iwrite(sbi, dir);
221 de->d_inode = 0;
222 tfs_bwrite(sbi, cs->block, cs->data);
223 tfs_release_inode(sbi, inode);
225 return 0;
229 int tfs_unlink(struct tfs_sb_info *sbi, const char *path)
231 int res;
232 struct inode *dir;
233 struct inode *inode;
234 struct cache_struct *cs;
235 struct tfs_dir_entry *de;
236 const char * base_name = get_base_name(path);
238 if (!base_name) {
239 printk("%s: invalid path name!\n", path);
240 return -1;
243 dir = tfs_namei(sbi, path, LOOKUP_PARENT);
244 if (!dir) {
245 printk("ERROR: path not exist!\n");
246 return -1;
249 cs = tfs_find_entry(sbi, base_name, dir, &de);
250 if (!cs) {
251 printk("%s: path not exist!\n", path);
252 return -1;
255 inode = tfs_iget_by_inr(sbi, de->d_inode);
256 if (!inode) {
257 printk("%s: path not exist!\n", path);
258 return -1;
260 if (inode->i_mode != TFS_FILE) {
261 printk("%s: not a file!\n", path);
262 return -1;
265 dir->i_size -= sizeof(struct tfs_dir_entry);
266 tfs_iwrite(sbi, dir);
267 de->d_inode = 0;
268 tfs_bwrite(sbi, cs->block, cs->data);
269 tfs_release_inode(sbi, inode);
271 return 0;
275 /* for relative path searching */
276 DIR *this_dir;
278 DIR *tfs_opendir(struct tfs_sb_info *sbi, const char *path)
280 DIR *dir = malloc(sizeof(*dir));
282 if (!dir) {
283 printk("malloc for DIR structure error!\n");
284 return NULL;
287 dir->dd_dir = tfs_open(sbi, path, 0);
288 if (!dir->dd_dir) {
289 free(dir);
290 return NULL;
293 return dir;
296 /* read one directry entry at a time */
297 struct dirent * tfs_readdir(DIR *dir)
299 struct dirent *dirent;
300 struct tfs_dir_entry *de;
301 struct cache_struct *cs;
302 struct file *file = dir->dd_dir;
303 struct inode *inode = file->inode;
304 struct tfs_sb_info *sbi = file->sbi;
305 int index = file->offset >> sbi->s_block_shift;
306 uint32_t block;
308 if (!(block = tfs_bmap(inode, index)))
309 return NULL;
310 cs = get_cache_block(sbi, block);
311 de = (struct tfs_dir_entry *)(cs->data + (file->offset & (sbi->s_block_size- 1)));
313 if (!(dirent = malloc(sizeof(*dirent)))) {
314 printk("malloc dirent structure in tfs_readdir error!\n");
315 return NULL;
317 memset(dirent, 0, sizeof(*dirent));
318 dirent->d_ino = de->d_inode;
319 dirent->d_off = file->offset;
320 dirent->d_reclen = sizeof(struct tfs_dir_entry);
321 dirent->d_type = 0;
322 memcpy(dirent->d_name, de->d_name, TFS_NAME_LEN);
324 file->offset += sizeof(struct tfs_dir_entry);
326 /* Skip the invalid one */
327 if (de->d_inode == 0) {
328 free(dirent);
329 return tfs_readdir(dir);
332 return dirent;
336 void tfs_closedir(DIR *dir)
338 if (dir) {
339 free_inode(dir->dd_dir->inode);
340 free(dir->dd_dir);
341 free(dir);