Home | History | Annotate | Download | only in src
      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 
     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 
     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 
    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 
    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 
    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 
    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 
    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