AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
dentry.c
Go to the documentation of this file.
1
7
8#include <ext2.h>
9
20int ext2_dentry_find(struct ext2 *desc, struct ext2_inode *inode, const char *name, ino_t *ino)
21{
22 if ((inode->mode & S_IFMT) != S_IFDIR)
23 return -ENOTDIR;
24
25 size_t bs = desc->bs;
26 size_t blocks_nr = inode->size / bs;
27 size_t length = strlen(name);
28
29 char *buf = kmalloc(bs, &M_BUFFER, 0);
30 struct ext2_dentry *d;
31 int err = -ENOENT;
32
33 if (!buf)
34 return -ENOMEM;
35
36 for (size_t i = 0; i < blocks_nr && err == -ENOENT; ++i) {
37 int r;
38
39 if ((r = ext2_inode_block_read(desc, inode, i, buf))) {
40 err = r;
41 break;
42 }
43
44 d = (struct ext2_dentry *) buf;
45 while ((char *) d < (char *) buf + bs && d->size) {
46 /* entries with no inode are unused */
47 if (d->ino && d->length == length && !memcmp(d->name, name, length)) {
48 /* read it before the buffer is freed */
49 *ino = d->ino;
50 err = 0;
51 break;
52 }
53 d = (struct ext2_dentry *) ((char *) d + d->size);
54 }
55 }
56
57 kfree(buf);
58 return err;
59}
60
62static inline uint8_t ext2_dentry_type(mode_t mode)
63{
64 switch (mode & S_IFMT) {
65 case S_IFSOCK: return EXT2_DENTRY_TYPE_SCKT;
66 case S_IFLNK: return EXT2_DENTRY_TYPE_SLINK;
67 case S_IFREG: return EXT2_DENTRY_TYPE_RGL;
68 case S_IFBLK: return EXT2_DENTRY_TYPE_BLK;
69 case S_IFDIR: return EXT2_DENTRY_TYPE_DIR;
70 case S_IFCHR: return EXT2_DENTRY_TYPE_CHR;
71 case S_IFIFO: return EXT2_DENTRY_TYPE_FIFO;
72 default: return EXT2_DENTRY_TYPE_BAD;
73 }
74}
75
87int ext2_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)
88{
89 int err = 0;
90
91 /* not a directory */
92 if ((dir->mode & S_IFMT) != S_IFDIR)
93 return -ENOTDIR;
94
95 struct ext2 *desc = dir->p;
96
97 uint8_t type = desc->filetype ? ext2_dentry_type(mode) : 0;
98 size_t length = strlen(name);
99 size_t size = length + sizeof(struct ext2_dentry);
100 size = (size + 3) & ~3; /* entries are aligned to 4 bytes */
101
102 /* look for room for the entry */
103 struct ext2_inode dir_inode;
104
105 if ((err = ext2_inode_read(desc, dir->ino, &dir_inode)))
106 return err;
107
108 char *buf = kmalloc(desc->bs, &M_BUFFER, 0);
109 struct ext2_dentry *cur = NULL;
110
111 if (!buf)
112 return -ENOMEM;
113
114 size_t bs = desc->bs;
115 size_t blocks_nr = dir_inode.size / bs;
116 size_t flag = 0; /* 0: a new block, 1: an unused entry, 2: a split */
117 size_t block = 0;
118
119 for (block = 0; block < blocks_nr; ++block) {
120 /* a block that can't be read isn't written back */
121 if ((err = ext2_inode_block_read(desc, &dir_inode, block, buf)))
122 goto out;
123
124 cur = (struct ext2_dentry *) buf;
125
126 while ((char *) cur < (char *) buf + bs && cur->size) {
127 /* an unused entry big enough */
128 if ((!cur->ino) && cur->size >= size) {
129 flag = 1;
130 goto done;
131 }
132
133 /* an entry with room for the new one after its name */
134 if ((((cur->length + sizeof(struct ext2_dentry) + 3) & ~3) + size) <= cur->size) {
135 flag = 2;
136 goto done;
137 }
138
139 cur = (struct ext2_dentry *) ((char *) cur + cur->size);
140 }
141 }
142
143done:
144 if (flag == 1) {
145 /* take the unused entry */
146 memcpy(cur->name, name, length);
147 cur->ino = ino;
148 cur->length = length;
149 cur->type = type;
150
151 err = ext2_inode_block_write(desc, &dir_inode, dir->ino, block, buf);
152 } else if (flag == 2) {
153 /* split the entry: the new one takes the room after its name */
154 size_t new_size = (cur->length + sizeof(struct ext2_dentry) + 3) & ~3;
155 struct ext2_dentry *next = (struct ext2_dentry *) ((char *) cur + new_size);
156
157 next->ino = ino;
158 next->size = cur->size - new_size;
159 next->length = length;
160 next->type = type;
161 memcpy(next->name, name, length);
162
163 cur->size = new_size;
164
165 err = ext2_inode_block_write(desc, &dir_inode, dir->ino, block, buf);
166 } else {
167 /* no room left: the entry gets a new block of its own */
168 memset(buf, 0, bs);
169 cur = (struct ext2_dentry *) buf;
170 cur->ino = ino;
171 cur->size = bs;
172 cur->length = length;
173 cur->type = type;
174 memcpy(cur->name, name, length);
175
176 if ((err = ext2_inode_block_write(desc, &dir_inode, dir->ino, blocks_nr, buf)))
177 goto out;
178
179 dir_inode.size += bs;
180 err = ext2_inode_write(desc, dir->ino, &dir_inode);
181 dir->size = dir_inode.size;
182 }
183
184out:
185 kfree(buf);
186 return err;
187}
int ext2_dentry_create(struct vnode *dir, const char *name, ino_t ino, mode_t mode)
Adds an entry to a directory.
Definition dentry.c:87
int ext2_dentry_find(struct ext2 *desc, struct ext2_inode *inode, const char *name, ino_t *ino)
Finds the inode number of a name in a directory.
Definition dentry.c:20
static uint8_t ext2_dentry_type(mode_t mode)
Returns the directory entry type of a file's mode.
Definition dentry.c:62
#define EXT2_DENTRY_TYPE_SCKT
Definition ext2.h:162
#define EXT2_DENTRY_TYPE_SLINK
Definition ext2.h:163
#define EXT2_DENTRY_TYPE_BAD
Definition ext2.h:156
#define EXT2_DENTRY_TYPE_RGL
Definition ext2.h:157
#define EXT2_DENTRY_TYPE_BLK
Definition ext2.h:160
#define EXT2_DENTRY_TYPE_FIFO
Definition ext2.h:161
int ext2_inode_read(struct ext2 *desc, ino_t inode, struct ext2_inode *ref)
Reads an inode from the disk.
Definition inode.c:33
int ext2_inode_block_read(struct ext2 *desc, struct ext2_inode *inode, size_t idx, void *buf)
Reads a block of a file.
Definition inode.c:144
#define EXT2_DENTRY_TYPE_DIR
Definition ext2.h:158
int ext2_inode_write(struct ext2 *desc, ino_t inode, struct ext2_inode *i)
Writes an inode to the disk.
Definition inode.c:51
#define EXT2_DENTRY_TYPE_CHR
Definition ext2.h:159
int ext2_inode_block_write(struct ext2 *desc, struct ext2_inode *inode, uint32_t inode_nr, size_t idx, void *buf)
Writes a block of a file, allocating it and the indirect blocks above it if they don't exist yet.
Definition inode.c:235
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition kvmem.c:123
void kfree(void *)
Frees an object that kmalloc() gave.
Definition kvmem.c:146
int memcmp(const void *a, const void *b, size_t n)
Compares n bytes.
Definition libc.c:51
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
#define NULL
Definition stddef.h:27
unsigned char uint8_t
Definition stddef.h:20
A directory entry, as it is on the disk.
Definition ext2.h:142
uint16_t size
entry total size
Definition ext2.h:146
uint8_t name[0]
the name follows (not NUL-terminated)
Definition ext2.h:152
uint32_t ino
inode number
Definition ext2.h:144
uint8_t type
entry type
Definition ext2.h:150
uint8_t length
name length
Definition ext2.h:148
An inode, as it is on the disk.
Definition ext2.h:114
uint32_t size
Definition ext2.h:117
uint16_t mode
Definition ext2.h:115
A mounted ext2 filesystem.
Definition ext2.h:168
size_t bs
the block size
Definition ext2.h:177
int filetype
directory entries have their file's type (EXT2_INCOMPAT_FILETYPE); without it, the byte is 0
Definition ext2.h:184
A file in memory (a vnode): what its inode says, and the kernel's own state.
Definition vfs.h:113
ino_t ino
Definition vfs.h:114
size_t size
Definition vfs.h:115
void * p
the filesystem's own data
Definition vfs.h:130
mode_t mode
Definition vfs.h:118
uintptr_t ino_t
Definition types.h:23
uint32_t mode_t
Definition types.h:15