1// beos_stat_cache.c 2 3#include <errno.h> 4#include <stdio.h> 5#include <stdlib.h> 6 7#include <OS.h> 8 9#include "beos_stat_cache.h" 10#include "pathsys.h" 11#include "StatCacheServer.h" 12 13#define SET_ERRNO_AND_RETURN(error) { \ 14 if ((error) == B_OK) \ 15 return 0; \ 16 errno = (error); \ 17 return -1; \ 18} 19 20// get_server_port 21static 22port_id 23get_server_port() 24{ 25 static port_id id = -1; 26 static bool initialized = false; 27 if (!initialized) { 28 id = find_port(STAT_CACHE_SERVER_PORT_NAME); 29 initialized = true; 30 } 31 return id; 32} 33 34// get_reply_port 35static 36port_id 37get_reply_port() 38{ 39 static port_id id = -1; 40 if (id < 0) 41 id = create_port(1, "stat cache reply port"); 42 return id; 43} 44 45// send_request 46static 47status_t 48send_request(int32 command, const char *path) 49{ 50 port_id requestPort = get_server_port(); 51 port_id replyPort = get_reply_port(); 52 stat_cache_request request; 53 int requestSize; 54 55 // get request port 56 if (requestPort < 0) 57 return requestPort; 58 // get reply port 59 if (replyPort < 0) 60 return replyPort; 61 // normalize the path 62 if (!path || !normalize_path(path, request.path, sizeof(request.path))) 63 return B_BAD_VALUE; 64 requestSize = (request.path + strlen(request.path) + 1) - (char*)&request; 65 // send request 66 request.replyPort = replyPort; 67 request.command = command; 68 return write_port(requestPort, 0, &request, requestSize); 69} 70 71// receive_reply 72static 73status_t 74receive_reply(void **_reply, int32 *_replySize, void *buffer, int32 replySize) 75{ 76 port_id replyPort = get_reply_port(); 77 ssize_t bytesRead; 78 void *reply; 79 int32 code; 80 81 // get reply port 82 if (replyPort < 0) 83 return replyPort; 84 85 // get the reply size 86 if (!buffer) { 87 replySize = port_buffer_size(replyPort); 88 if (replySize < 0) 89 return replySize; 90 } 91 92 // allocate reply 93 if (buffer) { 94 reply = buffer; 95 } else { 96 reply = malloc(replySize); 97 if (!reply) 98 return B_NO_MEMORY; 99 } 100 101 // read the reply 102 bytesRead = read_port(replyPort, &code, reply, replySize); 103 if (bytesRead < 0) { 104 if (!buffer) 105 free(reply); 106 return bytesRead; 107 } 108 if (bytesRead != replySize) { 109 if (!buffer) 110 free(reply); 111 return B_ERROR; 112 } 113 114 if (_reply) 115 *_reply = reply; 116 if (_replySize) 117 *_replySize = replySize; 118 return B_OK; 119} 120 121// beos_stat_cache_stat 122int 123beos_stat_cache_stat(const char *filename, struct stat *st) 124{ 125 stat_cache_stat_reply reply; 126 status_t error; 127 128 // fall back to standard, if there is no server 129 if (get_server_port() < 0) 130 return stat(filename, st); 131 132 // send the request 133 error = send_request(STAT_CACHE_COMMAND_STAT, filename); 134 if (error != B_OK) 135 SET_ERRNO_AND_RETURN(error); 136 137 // get the reply 138 error = receive_reply(NULL, NULL, &reply, sizeof(reply)); 139 if (error != B_OK) 140 error = reply.error; 141 if (error != B_OK) 142 SET_ERRNO_AND_RETURN(error); 143 144 *st = reply.st; 145 return 0; 146} 147 148// beos_stat_cache_opendir 149DIR * 150beos_stat_cache_opendir(const char *dirName) 151{ 152 stat_cache_readdir_reply *reply; 153 int32 replySize; 154 status_t error; 155 156 // fall back to standard, if there is no server 157 if (get_server_port() < 0) 158 return opendir(dirName); 159 160 // send the request 161 error = send_request(STAT_CACHE_COMMAND_READDIR, dirName); 162 if (error != B_OK) { 163 errno = error; 164 return NULL; 165 } 166 167 // get the reply 168 error = receive_reply((void**)&reply, &replySize, NULL, 0); 169 if (error != B_OK) 170 error = reply->error; 171 if (error != B_OK) { 172 free(reply); 173 errno = error; 174 return NULL; 175 } 176 177 reply->clientData = reply->buffer; 178 179 // a bit ugly, but anyway... 180 return (DIR*)reply; 181} 182 183// beos_stat_cache_readdir 184struct dirent * 185beos_stat_cache_readdir(DIR *dir) 186{ 187 stat_cache_readdir_reply *reply; 188 struct dirent *entry; 189 190 // fall back to standard, if there is no server 191 if (get_server_port() < 0) 192 return readdir(dir); 193 194 reply = (stat_cache_readdir_reply*)dir; 195 if (reply->entryCount == 0) 196 return NULL; 197 198 entry = (struct dirent*)reply->clientData; 199 200 // get the next entry 201 if (--reply->entryCount > 0) 202 reply->clientData = (uint8*)entry + entry->d_reclen; 203 204 return entry; 205} 206 207// beos_stat_cache_closedir 208int 209beos_stat_cache_closedir(DIR *dir) 210{ 211 stat_cache_readdir_reply *reply; 212 213 // fall back to standard, if there is no server 214 if (get_server_port() < 0) 215 return closedir(dir); 216 217 reply = (stat_cache_readdir_reply*)dir; 218 free(reply); 219 return 0; 220} 221 222