1 /*---------------------------------------------------------------------------*
2 * PANSIFileSystemImpl.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20
21 #include "LCHAR.h"
22 #include "PFileSystemImpl.h"
23 #include "PANSIFileSystemImpl.h"
24 #include "PANSIFileImpl.h"
25 #include "plog.h"
26 #include "pmemory.h"
27
28 //extern PFileSystem* PANSIFileSystemSingleton;
29 PFileSystem* PANSIFileSystemSingleton = (PFileSystem*)NULL;
30
31 #define MTAG NULL
32
33
34 #ifdef USE_THREAD
35 /* Prototype of private function */
36 PORTABLE_API ESR_ReturnCode PtrdFlush();
37 #endif
38
39 /**
40 * [file path, PFileSystem*] mapping.
41 */
42 extern PHashTable* PFileSystemPathMap;
43
44
PANSIFileSystemCreate(void)45 ESR_ReturnCode PANSIFileSystemCreate(void)
46 {
47 PANSIFileSystemImpl* impl;
48 ESR_ReturnCode rc;
49
50 if (PANSIFileSystemSingleton != NULL)
51 return ESR_SUCCESS;
52 impl = NEW(PANSIFileSystemImpl, MTAG);
53 if (impl == NULL)
54 return ESR_OUT_OF_MEMORY;
55 impl->super.super.destroy = &PANSIFileSystemDestroyImpl;
56 impl->super.super.createPFile = &PANSIFileSystemCreatePFileImpl;
57 impl->super.addPath = &PANSIFileSystemAddPathImpl;
58 impl->super.removePath = &PANSIFileSystemRemovePathImpl;
59 impl->super.getcwd = &PANSIFileSystemGetcwdImpl;
60 impl->super.super.mkdir = &PANSIFileSystemMkdirImpl;
61 impl->super.super.chdir = &PANSIFileSystemChdirImpl;
62
63 CHKLOG(rc, PHashTableCreate(NULL, MTAG, &impl->directoryMap));
64 PANSIFileSystemSingleton = &impl->super.super;
65 return ESR_SUCCESS;
66 CLEANUP:
67 return rc;
68 }
69
PANSIFileSystemDestroyImpl(PFileSystem * self)70 ESR_ReturnCode PANSIFileSystemDestroyImpl(PFileSystem* self)
71 {
72 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
73 PHashTableEntry* entry;
74 PHashTableEntry* oldEntry;
75 LCHAR* key;
76 LCHAR* value;
77 ESR_ReturnCode rc;
78
79 if (impl->directoryMap != NULL)
80 {
81 CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry));
82 while (entry != NULL)
83 {
84 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
85 oldEntry = entry;
86 CHKLOG(rc, PHashTableEntryAdvance(&entry));
87 CHKLOG(rc, PHashTableEntryRemove(oldEntry));
88 CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL));
89 FREE(key);
90 FREE(value);
91 }
92 CHKLOG(rc, PHashTableDestroy(impl->directoryMap));
93 impl->directoryMap = NULL;
94 }
95 FREE(self);
96 return ESR_SUCCESS;
97 CLEANUP:
98 return rc;
99 }
100
PANSIFileSystemAddPathImpl(PFileSystem * self,const LCHAR * virtualPath,const LCHAR * realPath)101 ESR_ReturnCode PANSIFileSystemAddPathImpl(PFileSystem* self, const LCHAR* virtualPath, const LCHAR* realPath)
102 {
103 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
104 ESR_BOOL exists;
105 LCHAR* key = NULL;
106 LCHAR* value = NULL;
107 ESR_ReturnCode rc;
108 size_t len;
109
110 if (virtualPath == NULL || realPath == NULL)
111 {
112 rc = ESR_INVALID_ARGUMENT;
113 PLogError(ESR_rc2str(rc));
114 goto CLEANUP;
115 }
116
117 len = LSTRLEN(virtualPath) + 1;
118 if (virtualPath[LSTRLEN(virtualPath)-1] != L('/'))
119 ++len;
120 key = MALLOC(sizeof(LCHAR) * len, MTAG);
121 if (key == NULL)
122 {
123 rc = ESR_OUT_OF_MEMORY;
124 PLogError(ESR_rc2str(rc));
125 goto CLEANUP;
126 }
127 LSTRCPY(key, virtualPath);
128 /* Make sure paths end with '/' */
129 CHKLOG(rc, PFileSystemCanonicalSlashes(key));
130 if (key[LSTRLEN(key)-1] != L('/'))
131 LSTRCAT(key, L("/"));
132 value = MALLOC(sizeof(LCHAR) * (LSTRLEN(realPath) + 1), MTAG);
133 if (value == NULL)
134 {
135 rc = ESR_OUT_OF_MEMORY;
136 PLogError(ESR_rc2str(rc));
137 goto CLEANUP;
138 }
139 LSTRCPY(value, realPath);
140
141 /* Make sure realPath is not an empty string */
142 lstrtrim(value);
143 if (LSTRLEN(value) == 0)
144 {
145 FREE(value);
146 value = NULL;
147 rc = ESR_INVALID_ARGUMENT;
148 PLogError(L("%s: realPath cannot be empty"), ESR_rc2str(rc));
149 goto CLEANUP;
150 }
151
152 /* Make sure paths end with '/' */
153 CHKLOG(rc, PFileSystemCanonicalSlashes(value));
154 if (value[LSTRLEN(value)-1] != L('/'))
155 LSTRCAT(value, L("/"));
156
157 CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists));
158 if (exists)
159 {
160 LCHAR* oldValue;
161
162 CHKLOG(rc, PHashTableGetValue(impl->directoryMap, key, (void **)&oldValue));
163 if (LSTRCMP(oldValue, value) != 0)
164 {
165 rc = ESR_IDENTIFIER_COLLISION;
166 PLogError(ESR_rc2str(rc));
167 goto CLEANUP;
168 }
169 }
170 CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL));
171 CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, self, NULL));
172 return ESR_SUCCESS;
173 CLEANUP:
174 FREE(key);
175 FREE(value);
176 return rc;
177 }
178
PANSIFileSystemRemovePathImpl(PFileSystem * self,const LCHAR * virtualPath)179 ESR_ReturnCode PANSIFileSystemRemovePathImpl(PFileSystem* self, const LCHAR* virtualPath)
180 {
181 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
182 LCHAR path[P_PATH_MAX];
183 LCHAR* key;
184 LCHAR* value;
185 PHashTableEntry* entry;
186 ESR_ReturnCode rc;
187
188 if (virtualPath == NULL)
189 {
190 rc = ESR_INVALID_ARGUMENT;
191 PLogError(ESR_rc2str(rc));
192 goto CLEANUP;
193 }
194 /* Make sure paths end with '/' */
195 LSTRCPY(path, virtualPath);
196 CHKLOG(rc, PFileSystemCanonicalSlashes(path));
197 if (path[LSTRLEN(path)-1] != L('/'))
198 LSTRCAT(path, L("/"));
199 CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, path, &entry));
200 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
201 CHKLOG(rc, PHashTableEntryRemove(entry));
202 CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL));
203 FREE(key);
204 FREE(value);
205 return ESR_SUCCESS;
206 CLEANUP:
207 return rc;
208 }
209
PANSIFileSystemGetRealPathImpl(PFileSystem * self,LCHAR * path,size_t * len)210 ESR_ReturnCode PANSIFileSystemGetRealPathImpl(PFileSystem* self, LCHAR* path, size_t* len)
211 {
212 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) self;
213 PHashTableEntry* entry;
214 LCHAR* key;
215 LCHAR* value;
216 LCHAR* bestKey = NULL;
217 LCHAR* bestValue = NULL;
218 ESR_BOOL isAbsolute;
219 ESR_ReturnCode rc;
220
221 CHKLOG(rc, PFileSystemGetAbsolutePath(path, len));
222 CHKLOG(rc, PHashTableEntryGetFirst(impl->directoryMap, &entry));
223 while (entry != NULL)
224 {
225 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void**)&key, (void**)&value));
226 if (LSTRNCMP(path, key, LSTRLEN(key)) == 0)
227 {
228 /* File-system handles file path */
229 if (bestKey == NULL || LSTRLEN(key) > LSTRLEN(bestKey))
230 {
231 /* Found a better match -- the new key is a subdirectory of the previous bestKey */
232 bestKey = key;
233 bestValue = value;
234 }
235 }
236 CHKLOG(rc, PHashTableEntryAdvance(&entry));
237 }
238 if (bestKey == NULL)
239 {
240 rc = ESR_INVALID_STATE;
241 PLogError(L("PANSIFileSystem does not handle the specified path: %s"), path);
242 goto CLEANUP;
243 }
244
245 if (LSTRLEN(bestValue) + 1 > *len)
246 {
247 *len = LSTRLEN(bestValue) + 1;
248 rc = ESR_BUFFER_OVERFLOW;
249 PLogError(ESR_rc2str(rc));
250 goto CLEANUP;
251 }
252 /* Delete the virtual-path */
253 LSTRCPY(path, path + LSTRLEN(bestKey));
254
255 CHKLOG(rc, PFileSystemIsAbsolutePath(path, &isAbsolute));
256 if (LSTRCMP(bestValue, L("/")) == 0 && isAbsolute)
257 {
258 /* do nothing */
259 }
260 else
261 {
262 /* Insert the key-path */
263 CHKLOG(rc, lstrinsert(bestValue, path, 0, len));
264 }
265 return ESR_SUCCESS;
266 CLEANUP:
267 return rc;
268 }
269
PANSIFileSystemCreatePFileImpl(PFileSystem * self,const LCHAR * path,ESR_BOOL littleEndian,PFile ** file)270 ESR_ReturnCode PANSIFileSystemCreatePFileImpl(PFileSystem* self, const LCHAR* path, ESR_BOOL littleEndian, PFile** file)
271 {
272 LCHAR realPath[P_PATH_MAX];
273 size_t len;
274 ESR_ReturnCode rc;
275
276 LSTRCPY(realPath, path);
277 len = P_PATH_MAX;
278 CHKLOG(rc, PANSIFileSystemGetRealPathImpl(self, realPath, &len));
279 return PANSIFileCreateImpl(realPath, littleEndian, file);
280 CLEANUP:
281 return rc;
282 }
283
PANSIFileSystemSetDefault(ESR_BOOL isDefault)284 ESR_ReturnCode PANSIFileSystemSetDefault(ESR_BOOL isDefault)
285 {
286 PANSIFileSystemImpl* impl = (PANSIFileSystemImpl*) PANSIFileSystemSingleton;
287 ESR_BOOL exists;
288 LCHAR* key = NULL;
289 LCHAR* value = NULL;
290 PHashTableEntry* entry;
291 ESR_ReturnCode rc;
292
293 if (isDefault)
294 {
295
296 key = MALLOC(sizeof(LCHAR), MTAG);
297 if (key == NULL)
298 {
299 rc = ESR_OUT_OF_MEMORY;
300 PLogError(ESR_rc2str(rc));
301 goto CLEANUP;
302 }
303 LSTRCPY(key, L(""));
304 value = MALLOC(sizeof(LCHAR), MTAG);
305 if (value == NULL)
306 {
307 rc = ESR_OUT_OF_MEMORY;
308 PLogError(ESR_rc2str(rc));
309 goto CLEANUP;
310 }
311 LSTRCPY(value, L(""));
312
313 CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, key, &exists));
314 if (exists)
315 {
316 LCHAR* key;
317 LCHAR* value;
318
319 CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry));
320 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
321 CHKLOG(rc, PHashTableEntryRemove(entry));
322 CHKLOG(rc, PHashTableRemoveValue(PFileSystemPathMap, key, NULL));
323 FREE(key);
324 FREE(value);
325 }
326 CHKLOG(rc, PHashTablePutValue(impl->directoryMap, key, value, NULL));
327 CHKLOG(rc, PHashTablePutValue(PFileSystemPathMap, key, PANSIFileSystemSingleton, NULL));
328
329 /* Set virtual current working directory to native current working directory */
330 }
331 else
332 {
333 CHKLOG(rc, PHashTableContainsKey(impl->directoryMap, L(""), &exists));
334 if (exists)
335 {
336 LCHAR* key;
337 LCHAR* value;
338
339 CHKLOG(rc, PHashTableGetEntry(impl->directoryMap, L(""), &entry));
340 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
341
342 CHKLOG(rc, PHashTableContainsKey(PFileSystemPathMap, L(""), &exists));
343 if (exists)
344 {
345 LCHAR* key;
346 PFileSystem* value;
347 PHashTableEntry* entry;
348
349 CHKLOG(rc, PHashTableGetEntry(PFileSystemPathMap, L(""), &entry));
350 CHKLOG(rc, PHashTableEntryGetKeyValue(entry, (void **)&key, (void **)&value));
351 if (value == PANSIFileSystemSingleton)
352 CHKLOG(rc, PHashTableEntryRemove(entry));
353 }
354
355 CHKLOG(rc, PHashTableEntryRemove(entry));
356 FREE(key);
357 FREE(value);
358 }
359 }
360 return ESR_SUCCESS;
361 CLEANUP:
362 FREE(key);
363 FREE(value);
364 return rc;
365 }
366