28 |
28 |
29 #include <stdio.h> |
29 #include <stdio.h> |
30 #include <stdlib.h> |
30 #include <stdlib.h> |
31 #include <errno.h> |
31 #include <errno.h> |
32 |
32 |
33 #include <ucx/string.h> |
33 #include <cx/string.h> |
34 #include <ucx/list.h> |
34 #include <cx/list.h> |
35 #include <ucx/map.h> |
35 #include <cx/map.h> |
36 |
36 |
37 #include "../daemon/session.h" |
37 #include "../daemon/session.h" |
38 |
38 |
39 #include "testutils.h" |
39 #include "testutils.h" |
40 |
40 |
41 #include "vfs.h" |
41 #include "vfs.h" |
42 |
42 |
43 typedef struct TestVFS { |
43 typedef struct TestVFS { |
44 UcxMap *files; |
44 CxMap *files; |
45 int count_unlink; |
45 int count_unlink; |
46 int count_rmdir; |
46 int count_rmdir; |
47 } TestVFS; |
47 } TestVFS; |
48 |
48 |
49 typedef struct TestVFSFile { |
49 typedef struct TestVFSFile { |
50 VFSFile file; |
50 VFSFile file; |
51 sstr_t path; |
51 cxmutstr path; |
52 int isdir; |
52 int isdir; |
53 UcxBuffer *content; |
53 CxBuffer content; |
54 } TestVFSFile; |
54 } TestVFSFile; |
55 |
55 |
56 typedef struct TestVFSDir { |
56 typedef struct TestVFSDir { |
57 VFSDir dir; |
57 VFSDir dir; |
58 TestVFSFile *file; |
58 TestVFSFile *file; |
59 UcxMapIterator i; |
59 CxIterator i; |
60 sstr_t name; |
60 cxmutstr name; |
61 } TestVFSDir; |
61 } TestVFSDir; |
62 |
62 |
63 /* dir io */ |
63 /* dir io */ |
64 |
64 |
65 static char* test_resource_name(char *url) { |
65 static const char* test_resource_name(char *url) { |
66 sstr_t urlstr = sstr(url); |
66 cxstring urlstr = cx_str(url); |
67 if(urlstr.ptr[urlstr.length-1] == '/') { |
67 if(urlstr.ptr[urlstr.length-1] == '/') { |
68 urlstr.length--; |
68 urlstr.length--; |
69 } |
69 } |
70 sstr_t resname = sstrrchr(urlstr, '/'); |
70 cxstring resname = cx_strrchr(urlstr, '/'); |
71 if(resname.length > 1) { |
71 if(resname.length > 1) { |
72 return resname.ptr+1; |
72 return resname.ptr+1; |
73 } else { |
73 } else { |
74 return url; |
74 return url; |
75 } |
75 } |
77 |
77 |
78 int testvfs_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { |
78 int testvfs_readdir(VFS_DIR dir, VFS_ENTRY *entry, int getstat) { |
79 TestVFS *vfs = dir->ctx->vfs->instance; |
79 TestVFS *vfs = dir->ctx->vfs->instance; |
80 TestVFSDir *vfsdir = (TestVFSDir*)dir; |
80 TestVFSDir *vfsdir = (TestVFSDir*)dir; |
81 |
81 |
82 sstr_t prefix = sstrcat(2, vfsdir->file->path, S("/")); |
82 cxmutstr prefix = cx_strcat(2, vfsdir->file->path, cx_str("/")); |
83 |
83 |
|
84 // not the most efficient file system implementation ever, but it is only |
|
85 // for testing |
|
86 // check every entry in vfs->files and return, if the parent path |
|
87 // matches the open directory |
84 TestVFSFile *file = NULL; |
88 TestVFSFile *file = NULL; |
85 UCX_MAP_FOREACH(key, file, vfsdir->i) { |
89 cx_foreach(TestVFSFile *, entry, vfsdir->i) { |
86 sstr_t file_path = sstrcat( |
90 if(file) break; |
|
91 cxmutstr file_path = cx_strcat( |
87 2, |
92 2, |
88 prefix, |
93 prefix, |
89 sstr(test_resource_name(file->path.ptr))); |
94 cx_str(test_resource_name(entry->path.ptr))); |
90 void *m = ucx_map_get(vfs->files, ucx_key(file_path.ptr, file_path.length)); |
95 file = cxMapGet(vfs->files, cx_hash_key(file_path.ptr, file_path.length)); |
91 // don't ask why alfree and not free() |
96 free(file_path.ptr); |
92 alfree(ucx_default_allocator(), file_path.ptr); |
|
93 if(m) { |
|
94 break; |
|
95 } else { |
|
96 file = NULL; |
|
97 } |
|
98 } |
97 } |
99 free(prefix.ptr); |
98 free(prefix.ptr); |
100 |
99 |
101 if(file) { |
100 if(file) { |
102 vfsdir->name = sstrdup_a( |
101 vfsdir->name = cx_strdup_a( |
103 session_get_allocator(dir->ctx->sn), |
102 pool_allocator(dir->ctx->sn->pool), |
104 sstr(test_resource_name(file->path.ptr))); |
103 cx_str(test_resource_name(file->path.ptr))); |
105 ZERO(entry, sizeof(VFS_ENTRY)); |
104 ZERO(entry, sizeof(VFS_ENTRY)); |
106 entry->name = vfsdir->name.ptr; |
105 entry->name = vfsdir->name.ptr; |
107 |
106 |
108 if(getstat) { |
107 if(getstat) { |
109 ZERO(&entry->stat, sizeof(struct stat)); |
108 ZERO(&entry->stat, sizeof(struct stat)); |
124 |
123 |
125 } |
124 } |
126 |
125 |
127 ssize_t testvfs_read(SYS_FILE fd, void *buf, size_t nbyte) { |
126 ssize_t testvfs_read(SYS_FILE fd, void *buf, size_t nbyte) { |
128 TestVFSFile *file = (TestVFSFile*)fd; |
127 TestVFSFile *file = (TestVFSFile*)fd; |
129 return (ssize_t)ucx_buffer_read(buf, 1, nbyte, file->content); |
128 return (ssize_t)cxBufferRead(buf, 1, nbyte, &file->content); |
130 } |
129 } |
131 |
130 |
132 ssize_t testvfs_write(SYS_FILE fd, const void *buf, size_t nbyte) { |
131 ssize_t testvfs_write(SYS_FILE fd, const void *buf, size_t nbyte) { |
133 TestVFSFile *file = (TestVFSFile*)fd; |
132 TestVFSFile *file = (TestVFSFile*)fd; |
134 return (ssize_t)ucx_buffer_write(buf, 1, nbyte, file->content); |
133 return (ssize_t)cxBufferWrite(buf, 1, nbyte, &file->content); |
135 } |
134 } |
136 |
135 |
137 ssize_t testvfs_pread(SYS_FILE fd, void *buf, size_t nbyte, off_t offset) { |
136 ssize_t testvfs_pread(SYS_FILE fd, void *buf, size_t nbyte, off_t offset) { |
138 TestVFSFile *file = (TestVFSFile*)fd; |
137 TestVFSFile *file = (TestVFSFile*)fd; |
139 file->content->pos = (size_t)offset; |
138 file->content.pos = (size_t)offset; |
140 return testvfs_read(fd, buf, nbyte); |
139 return testvfs_read(fd, buf, nbyte); |
141 } |
140 } |
142 |
141 |
143 ssize_t testvfs_pwrite(SYS_FILE fd, const void *buf, size_t nbyte, off_t offset) { |
142 ssize_t testvfs_pwrite(SYS_FILE fd, const void *buf, size_t nbyte, off_t offset) { |
144 TestVFSFile *file = (TestVFSFile*)fd; |
143 TestVFSFile *file = (TestVFSFile*)fd; |
145 file->content->pos = (size_t)offset; |
144 file->content.pos = (size_t)offset; |
146 return testvfs_write(fd, buf, nbyte); |
145 return testvfs_write(fd, buf, nbyte); |
147 } |
146 } |
148 |
147 |
149 off_t testvfs_seek(SYS_FILE fd, off_t offset, int whence) { |
148 off_t testvfs_seek(SYS_FILE fd, off_t offset, int whence) { |
150 TestVFSFile *file = (TestVFSFile*)fd; |
149 TestVFSFile *file = (TestVFSFile*)fd; |
151 ucx_buffer_seek(file->content, offset, whence); |
150 cxBufferSeek(&file->content, offset, whence); |
152 return (off_t)file->content->pos; |
151 return (off_t)file->content.pos; |
153 } |
152 } |
154 |
153 |
155 void testvfs_close(SYS_FILE fd) { |
154 void testvfs_close(SYS_FILE fd) { |
156 TestVFSFile *file = (TestVFSFile*)fd; |
155 TestVFSFile *file = (TestVFSFile*)fd; |
157 file->content->pos = 0; |
156 file->content.pos = 0; |
158 } |
157 } |
159 |
158 |
160 VFS_IO test_file_io = { |
159 VFS_IO test_file_io = { |
161 testvfs_read, |
160 testvfs_read, |
162 testvfs_write, |
161 testvfs_write, |
178 |
177 |
179 SYS_FILE testvfs_open(VFSContext *ctx, const char *path, int oflags) { |
178 SYS_FILE testvfs_open(VFSContext *ctx, const char *path, int oflags) { |
180 TestVFS *vfs = ctx->vfs->instance; |
179 TestVFS *vfs = ctx->vfs->instance; |
181 TestVFSFile *file = NULL; |
180 TestVFSFile *file = NULL; |
182 |
181 |
183 sstr_t s_path = sstr((char*)path); |
182 cxstring s_path = cx_str((char*)path); |
184 if(sstrsuffix(s_path, S("/"))) { |
183 if(cx_strsuffix(s_path, cx_str("/"))) { |
185 s_path.length--; |
184 s_path.length--; |
186 } |
185 } |
187 |
186 |
188 file = ucx_map_sstr_get(vfs->files, s_path); |
187 file = cxMapGet(vfs->files, cx_hash_key_bytes((const unsigned char*)s_path.ptr, s_path.length)); |
189 if(!file) { |
188 if(!file) { |
190 if((oflags & O_CREAT) == O_CREAT) { |
189 if((oflags & O_CREAT) == O_CREAT) { |
191 file = pool_malloc(ctx->sn->pool, sizeof(TestVFSFile)); |
190 file = pool_malloc(ctx->sn->pool, sizeof(TestVFSFile)); |
192 ZERO(file, sizeof(TestVFSFile)); |
191 ZERO(file, sizeof(TestVFSFile)); |
193 file->file.ctx = ctx; |
192 file->file.ctx = ctx; |
194 file->path = sstrdup_a(session_get_allocator(ctx->sn), s_path); |
193 file->path = cx_strdup_a(pool_allocator(ctx->sn->pool), s_path); |
195 file->file.io = &test_file_io; |
194 file->file.io = &test_file_io; |
196 |
195 |
197 file->content = pool_calloc(ctx->sn->pool, 1, sizeof(UcxBuffer)); |
196 cxBufferInit(&file->content, pool_malloc(ctx->sn->pool, 2048), 2048, pool_allocator(ctx->sn->pool), 0); |
198 file->content->capacity = 2048; |
|
199 file->content->space = pool_malloc(ctx->sn->pool, file->content->capacity); |
|
200 file->content->flags = 0; |
|
201 file->content->pos = 0; |
|
202 file->content->size = 0; |
|
203 |
197 |
204 ucx_map_sstr_put(vfs->files, s_path, file); |
198 cxMapPut(vfs->files, cx_hash_key((void*)s_path.ptr, s_path.length), file); |
205 } else { |
199 } else { |
206 ctx->vfs_errno = ENOENT; |
200 ctx->vfs_errno = ENOENT; |
207 } |
201 } |
208 } |
202 } |
209 |
203 |
212 |
206 |
213 int testvfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { |
207 int testvfs_stat(VFSContext *ctx, const char *path, struct stat *buf) { |
214 TestVFS *vfs = ctx->vfs->instance; |
208 TestVFS *vfs = ctx->vfs->instance; |
215 TestVFSFile *file = NULL; |
209 TestVFSFile *file = NULL; |
216 |
210 |
217 sstr_t s_path = sstr((char*)path); |
211 cxstring s_path = cx_str((char*)path); |
218 if(sstrsuffix(s_path, S("/"))) { |
212 if(cx_strsuffix(s_path, cx_str("/"))) { |
219 s_path.length--; |
213 s_path.length--; |
220 } |
214 } |
221 |
215 |
222 file = ucx_map_sstr_get(vfs->files, s_path); |
216 file = cxMapGet(vfs->files, cx_hash_key((void*)s_path.ptr, s_path.length)); |
223 if(!file) { |
217 if(!file) { |
224 ctx->vfs_errno = ENOENT; |
218 ctx->vfs_errno = ENOENT; |
225 return 1; |
219 return 1; |
226 } |
220 } |
227 |
221 |
239 |
233 |
240 VFS_DIR testvfs_opendir(VFSContext *ctx, const char *path) { |
234 VFS_DIR testvfs_opendir(VFSContext *ctx, const char *path) { |
241 TestVFS *vfs = ctx->vfs->instance; |
235 TestVFS *vfs = ctx->vfs->instance; |
242 TestVFSFile *file = NULL; |
236 TestVFSFile *file = NULL; |
243 |
237 |
244 sstr_t s_path = sstr((char*)path); |
238 cxstring s_path = cx_str((char*)path); |
245 if(sstrsuffix(s_path, S("/"))) { |
239 if(cx_strsuffix(s_path, cx_str("/"))) { |
246 s_path.length--; |
240 s_path.length--; |
247 } |
241 } |
248 |
242 |
249 file = ucx_map_sstr_get(vfs->files, s_path); |
243 file = cxMapGet(vfs->files, cx_hash_key((void*)s_path.ptr, s_path.length)); |
250 if(!file) { |
244 if(!file) { |
251 ctx->vfs_errno = ENOENT; |
245 ctx->vfs_errno = ENOENT; |
252 return NULL; |
246 return NULL; |
253 } |
247 } |
254 |
248 |
297 return 0; |
291 return 0; |
298 } |
292 } |
299 |
293 |
300 int testvfs_unlink(VFSContext *ctx, const char *path) { |
294 int testvfs_unlink(VFSContext *ctx, const char *path) { |
301 TestVFS *vfs = ctx->vfs->instance; |
295 TestVFS *vfs = ctx->vfs->instance; |
302 TestVFSFile *file = ucx_map_cstr_get(vfs->files, path); |
296 CxHashKey path_key = cx_hash_key_str(path); |
|
297 TestVFSFile *file = cxMapGet(vfs->files, path_key); |
303 if(!file) { |
298 if(!file) { |
304 return 1; |
299 return 1; |
305 } |
300 } |
306 |
301 |
307 if(file->isdir) { |
302 if(file->isdir) { |
308 return 1; |
303 return 1; |
309 } |
304 } |
310 |
305 |
311 ucx_map_cstr_remove(vfs->files, path); |
306 (void)cxMapRemove(vfs->files, path_key); |
312 vfs->count_unlink++; |
307 vfs->count_unlink++; |
313 return 0; |
308 return 0; |
314 } |
309 } |
315 |
310 |
316 int testvfs_rmdir(VFSContext *ctx, const char *path) { |
311 int testvfs_rmdir(VFSContext *ctx, const char *path) { |
317 TestVFS *vfs = ctx->vfs->instance; |
312 TestVFS *vfs = ctx->vfs->instance; |
318 TestVFSFile *dir = ucx_map_cstr_get(vfs->files, path); |
313 CxHashKey path_key = cx_hash_key_str(path); |
|
314 TestVFSFile *dir = cxMapGet(vfs->files, path_key); |
319 if(!dir) { |
315 if(!dir) { |
320 ctx->vfs_errno = ENOENT; |
316 ctx->vfs_errno = ENOENT; |
321 return 1; |
317 return 1; |
322 } |
318 } |
323 |
319 |
324 if(!dir->isdir) { |
320 if(!dir->isdir) { |
325 return 1; |
321 return 1; |
326 } |
322 } |
327 |
323 |
328 UcxMapIterator i = ucx_map_iterator(vfs->files); |
324 CxIterator i = cxMapIteratorValues(vfs->files); |
329 TestVFSFile *f; |
325 cx_foreach(TestVFSFile *, f, i) { |
330 UCX_MAP_FOREACH(key, f, i) { |
326 if(f->path.length > dir->path.length && cx_strprefix(cx_strcast(f->path), cx_strcast(dir->path))){ |
331 if(f->path.length > dir->path.length && sstrprefix(f->path, dir->path)){ |
|
332 return 1; // dir not empty |
327 return 1; // dir not empty |
333 } |
328 } |
334 } |
329 } |
335 |
330 |
336 ucx_map_cstr_remove(vfs->files, path); |
331 (void)cxMapRemove(vfs->files, path_key); |
337 vfs->count_rmdir++; |
332 vfs->count_rmdir++; |
338 return 0; |
333 return 0; |
339 } |
334 } |
340 |
335 |
341 static VFS testVFSClass = { |
336 static VFS testVFSClass = { |
354 |
349 |
355 VFS* testvfs_create(Session *sn) { |
350 VFS* testvfs_create(Session *sn) { |
356 TestVFS *vfs = pool_malloc(sn->pool, sizeof(TestVFS)); |
351 TestVFS *vfs = pool_malloc(sn->pool, sizeof(TestVFS)); |
357 vfs->count_unlink = 0; |
352 vfs->count_unlink = 0; |
358 vfs->count_rmdir = 0; |
353 vfs->count_rmdir = 0; |
359 vfs->files = ucx_map_new_a(session_get_allocator(sn), 64); |
354 vfs->files = cxHashMapCreate(pool_allocator(sn->pool), 64); |
360 |
355 |
361 testVFSClass.instance = vfs; |
356 testVFSClass.instance = vfs; |
362 return &testVFSClass; |
357 return &testVFSClass; |
363 } |
358 } |
364 |
359 |
450 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); |
445 UCX_TEST_ASSERT(vfs_open(vfs, "/dir/file4", O_CREAT), "creation of file4 failed"); |
451 |
446 |
452 VFSDir *dir = vfs_opendir(vfs, "/dir"); |
447 VFSDir *dir = vfs_opendir(vfs, "/dir"); |
453 UCX_TEST_ASSERT(dir, "dir not opened"); |
448 UCX_TEST_ASSERT(dir, "dir not opened"); |
454 |
449 |
455 UcxMap *files = ucx_map_new(8); |
450 CxMap *files = cxHashMapCreate(cxDefaultAllocator, 8); |
456 |
451 |
457 VFSEntry entry; |
452 VFSEntry entry; |
458 while(vfs_readdir(dir, &entry)) { |
453 while(vfs_readdir(dir, &entry)) { |
459 ucx_map_cstr_put(files, entry.name, dir); |
454 cxMapPut(files, cx_hash_key_str(entry.name), dir); |
460 } |
455 } |
461 |
456 |
462 UCX_TEST_ASSERT(files->count == 4, "wrong files count"); |
457 UCX_TEST_ASSERT(files->size == 4, "wrong files count"); |
463 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file1"), "file1 missing"); |
458 UCX_TEST_ASSERT(cxMapGet(files, cx_hash_key_str("file1")), "file1 missing"); |
464 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file2"), "file2 missing"); |
459 UCX_TEST_ASSERT(cxMapGet(files, cx_hash_key_str("file2")), "file2 missing"); |
465 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file3"), "file3 missing"); |
460 UCX_TEST_ASSERT(cxMapGet(files, cx_hash_key_str("file3")), "file3 missing"); |
466 UCX_TEST_ASSERT(ucx_map_cstr_get(files, "file4"), "file4 missing"); |
461 UCX_TEST_ASSERT(cxMapGet(files, cx_hash_key_str("file4")), "file4 missing"); |
467 |
462 |
468 ucx_map_free(files); |
463 cxMapDestroy(files); |
469 |
464 |
470 UCX_TEST_END; |
465 UCX_TEST_END; |
471 |
466 |
472 testutil_destroy_session(sn); |
467 testutil_destroy_session(sn); |
473 } |
468 } |