add file read/write stuff
[tfsprogs.git] / dir.c
blob1548e82d287e9abdf5f1e7bb4d00c7a33007b3a8
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 return NULL;
34 cs = get_cache_block(sbi, block);
35 de = (struct tfs_dir_entry *)cs->data;
37 while(i < (int)inode->i_size) {
38 if ((char *)de >= (char *)cs->data + sbi->s_block_size) {
39 if ((block = inode->i_data[index++]) < sbi->s_data_area)
40 return NULL;
41 cs = get_cache_block(sbi, block);
42 de = (struct tfs_dir_entry *)cs->data;
44 if (tfs_match_entry(dname, de))
45 return de;
47 de++;
50 return NULL;
53 int tfs_add_entry(struct tfs_sb_info *sbi, struct inode *dir, const char *name, int inr, int * dirty)
55 uint32_t block;
56 int i = 0, index = 0;
57 struct cache_struct *cs;
58 struct tfs_dir_entry *de;
60 if (strlen(name) > TFS_NAME_LEN) {
61 printf("ERROR: file name too long!\n");
62 return -1;
65 if (!(block = dir->i_data[index++]))
66 goto alloc_new_block;
67 cs = get_cache_block(sbi, block);
68 de = (struct tfs_dir_entry *)cs->data;
69 while (i <= (int)dir->i_size) {
70 if ((void *)de >= cs->data + sbi->s_block_size) {
71 if (!(block = dir->i_data[index++]))
72 break;
73 cs = get_cache_block(sbi, block);
74 de = (struct tfs_dir_entry *)cs->data;
76 if (!de->d_inode)
77 break;
78 i += sizeof(struct tfs_dir_entry);
79 de++;
82 *dirty = 0;
84 alloc_new_block:
85 /* allocate a new block to hold the new entry */
86 if (!block) {
87 block = tfs_alloc_block(sbi, sbi->s_data_area);
88 dir->i_data[index - 1] = block;
89 if (block == -1) {
90 printf("ERROR: allocate new block failed, out of space!\n");
91 return -1;
93 cs = get_cache_block(sbi, block);
94 de = (struct tfs_dir_entry *)cs->data;
95 memset(cs->data, 0, sbi->s_block_size);
97 * tell the cache system to update the cache block
98 * in the next time read
100 cs->outdate = 1;
103 * This will go through the next if sentence, since if we
104 * allocated a new entry, then 'i >= dir->i_size' would
105 * be true.
109 if (i >= dir->i_size) {
110 /* Add a new entry at last */
111 dir->i_size += sizeof(struct tfs_dir_entry);
113 /* tell the caller to update this inode */
114 *dirty = 1;
118 * Else, we find a unused hole, this usually happens when user
119 * removes a file or directory, so we can just fill up
120 * the hole, and do not need allocate more space.
122 de->d_inode = inr;
123 memcpy(de->d_name, name, strlen(name));
125 /* write the entry back to disk */
126 tfs_bwrite(sbi, block, cs->data);
128 return 0;
132 int tfs_mkdir(struct tfs_sb_info *sbi, const char *path)
134 struct inode *dir;
135 struct inode *parent_dir;
136 int dirty;
137 int res = 0;
139 dir = tfs_mknod(sbi, path, TFS_DIR, &parent_dir);
140 if (!dir) {
141 TFS_DEBUG("mknod for path failed!\n");
142 return -1;
145 res = tfs_add_entry(sbi, dir, ".", dir->i_ino, &dirty);
146 if (res == -1) {
147 TFS_DEBUG("trying to add '.' under %s failed!\n", path);
148 goto out;
151 res = tfs_add_entry(sbi, dir, "..", parent_dir->i_ino, &dirty);
152 if (res == -1) {
153 TFS_DEBUG("trying to add .. under %s failed!\n", path);
154 goto out;
157 if (dirty)
158 tfs_iwrite(sbi, dir);
159 out:
160 free_inode(dir);
161 free_inode(parent_dir);
163 return res;
167 /* read one directry entry at a time */
168 static struct dirent * tfs_readdir(struct tfs_sb_info *sbi, struct inode *inode, uint32_t offset)
170 struct dirent *dirent;
171 struct tfs_dir_entry *de;
172 struct cache_struct *cs;
173 int index = offset >> sbi->s_block_shift;
174 uint32_t block;
176 if (!(block = inode->i_data[index]))
177 return NULL;
178 cs = get_cache_block(sbi, block);
179 de = (struct tfs_dir_entry *)(cs->data + (offset & (sbi->s_block_size- 1)));
181 if (!(dirent = malloc(sizeof(*dirent)))) {
182 printf("malloc dirent structure in tfs_readdir error!\n");
183 return NULL;
185 memset(dirent, 0, sizeof(*dirent));
186 dirent->d_ino = de->d_inode;
187 dirent->d_off = offset;
188 dirent->d_reclen = sizeof(struct tfs_dir_entry);
189 dirent->d_type = 0;
190 memcpy(dirent->d_name, de->d_name, TFS_NAME_LEN);
192 return dirent;
196 #if 0 /* the debug part */
197 int main(int argc, char *argv[])
200 #endif