1 /*
2 * libhfsuser - Userspace support library for NetBSD's libhfs
3 * Copyright 2013-2017 0x09.net.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 #include "cache.h"
26
27 #include <stdlib.h>
28 #include <pthread.h>
29
30 struct ringnode {
31 struct ringnode* next,* prev;
32 char* path;
33 size_t len;
34 hfs_catalog_keyed_record_t record;
35 hfs_catalog_key_t key;
36 };
37
38 struct hfs_record_cache {
39 pthread_rwlock_t lock;
40 struct ringnode* head;
41 struct ringnode backing[];
42 };
43
hfs_record_cache_create(size_t length)44 struct hfs_record_cache* hfs_record_cache_create(size_t length) {
45 if(!length)
46 return NULL;
47 struct hfs_record_cache* buf = malloc(sizeof(*buf) + sizeof(*buf->backing)*length);
48 if(!buf || pthread_rwlock_init(&buf->lock,NULL)) {
49 free(buf);
50 return NULL;
51 }
52
53 struct ringnode* tail = buf->head = buf->backing;
54 for(size_t i = 0; i <= length; i++) {
55 tail->next = buf->backing + i%length;
56 tail->next->prev = tail;
57 tail = tail->next;
58 tail->path = NULL;
59 }
60 return buf;
61 }
62
hfs_record_cache_destroy(struct hfs_record_cache * buf)63 void hfs_record_cache_destroy(struct hfs_record_cache* buf) {
64 if(!buf)
65 return;
66 pthread_rwlock_wrlock(&buf->lock);
67 struct ringnode* tail = buf->head;
68 do {
69 free(tail->path);
70 tail = tail->next;
71 } while(tail != buf->head);
72 pthread_rwlock_unlock(&buf->lock);
73 pthread_rwlock_destroy(&buf->lock);
74 free(buf);
75 }
76
hfs_record_cache_lookup(struct hfs_record_cache * buf,const char * path,size_t len,hfs_catalog_keyed_record_t * record,hfs_catalog_key_t * key)77 bool hfs_record_cache_lookup(struct hfs_record_cache* buf, const char* path, size_t len, hfs_catalog_keyed_record_t* record, hfs_catalog_key_t* key) {
78 bool ret = false;
79 if(!buf || pthread_rwlock_rdlock(&buf->lock))
80 return ret;
81 struct ringnode* it = buf->head;
82 do {
83 if(!it->path) break;
84 if(len == it->len && !memcmp(it->path,path,len)) {
85 *record = it->record;
86 *key = it->key;
87 ret = true;
88 break;
89 }
90 it = it->next;
91 } while(it != buf->head);
92 pthread_rwlock_unlock(&buf->lock);
93 return ret;
94 }
95
hfs_record_cache_lookup_parents(struct hfs_record_cache * buf,char * path,size_t len,hfs_catalog_keyed_record_t * record,hfs_catalog_key_t * key)96 size_t hfs_record_cache_lookup_parents(struct hfs_record_cache* buf, char* path, size_t len, hfs_catalog_keyed_record_t* record, hfs_catalog_key_t* key) {
97 char* c;
98 while((c = strrchr(path, '/'))) {
99 *c = '\0';
100 len = c - path;
101 if(*path && hfs_record_cache_lookup(buf, path, len, record, key))
102 break;
103 }
104 return len;
105 }
106
hfs_record_cache_add(struct hfs_record_cache * buf,const char * path,size_t len,hfs_catalog_keyed_record_t * record,hfs_catalog_key_t * key)107 void hfs_record_cache_add(struct hfs_record_cache* buf, const char* path, size_t len, hfs_catalog_keyed_record_t* record, hfs_catalog_key_t* key) {
108 if(!buf || pthread_rwlock_wrlock(&buf->lock))
109 return;
110 struct ringnode* tail = buf->head->prev;
111 char* newpath = realloc(tail->path,len);
112 if(!newpath) {
113 do {
114 free(tail->path);
115 tail->path = NULL;
116 tail = tail->next;
117 } while(tail != buf->head->prev);
118 goto end;
119 }
120 memcpy(newpath, path,len);
121 tail->path = newpath;
122 tail->len = len;
123 tail->key = *key;
124 tail->record = *record;
125 buf->head = tail;
126 end:
127 pthread_rwlock_unlock(&buf->lock);
128 }
129