1 /******************************************************************************
4 * Company XS Embedded GmbH
5 *****************************************************************************/
6 /******************************************************************************
7 * This Source Code Form is subject to the terms of the
8 * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
9 * with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 ******************************************************************************/
12 * @file persistence_client_library_file.c
13 * @ingroup Persistence client library
14 * @author Ingo Huerner
15 * @brief Implementation of the persistence client library.
16 * Library provides an API to access persistent data
20 #include "persistence_client_library_file.h"
21 #include "persistence_client_library_backup_filelist.h"
22 #include "persistence_client_library_pas_interface.h"
23 #include "persistence_client_library_handle.h"
24 #include "persistence_client_library_prct_access.h"
25 #include "persistence_client_library_data_organization.h"
26 #include "persistence_client_library_db_access.h"
30 #include <persistence_file_cache.h>
33 #include <fcntl.h> // for open flags
38 #include <sys/types.h>
44 int pclFileClose(int fd)
46 int rval = EPERS_NOT_INITIALIZED;
48 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileClose fd: "), DLT_INT(fd));
50 if(gPclInitialized >= PCLinitialized)
52 if(fd < MaxPersHandle)
54 // check if a backup and checksum file needs to bel deleted
55 if( gFileHandleArray[fd].permission != PersistencePermission_ReadOnly)
58 remove(gFileHandleArray[fd].backupPath); // we don't care about return value
60 // remove checksum file
61 remove(gFileHandleArray[fd].csumPath); // we don't care about return value
64 __sync_fetch_and_sub(&gOpenFdArray[fd], FileClosed); // set closed flag
66 rval = pfcCloseFile(fd);
74 rval = EPERS_MAXHANDLE;
83 int pclFileGetSize(int fd)
85 int size = EPERS_NOT_INITIALIZED;
87 if(gPclInitialized >= PCLinitialized)
91 size = pfcFileGetSize(fd);
94 size = fstat(fd, &buf);
96 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileGetSize fd: "), DLT_INT(fd));
109 void* pclFileMapData(void* addr, long size, long offset, int fd)
114 DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("pclFileMapData not supported when using file cache"));
116 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileMapData fd: "), DLT_INT(fd));
118 if(gPclInitialized >= PCLinitialized)
120 if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
122 int mapFlag = PROT_WRITE | PROT_READ;
123 ptr = mmap(addr,size, mapFlag, MAP_SHARED, fd, offset);
127 ptr = EPERS_MAP_LOCKFS;
137 int pclFileOpen(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no)
139 int handle = EPERS_NOT_INITIALIZED;
141 if(gPclInitialized >= PCLinitialized)
144 PersistenceInfo_s dbContext;
146 char dbKey[DbKeyMaxLen] = {0}; // database key
147 char dbPath[DbPathMaxLen] = {0}; // database location
148 char backupPath[DbPathMaxLen] = {0}; // backup file
149 char csumPath[DbPathMaxLen] = {0}; // checksum file
151 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileOpen: "), DLT_INT(ldbid), DLT_STRING(resource_id) );
153 dbContext.context.ldbid = ldbid;
154 dbContext.context.seat_no = seat_no;
155 dbContext.context.user_no = user_no;
157 // get database context: database path and database key
158 shared_DB = get_db_context(&dbContext, resource_id, ResIsFile, dbKey, dbPath);
160 if(dbContext.configKey.type == PersistenceResourceType_file) // check if the resource is really a file
162 // create backup path
164 char fileSubPath[DbPathMaxLen] = {0};
166 if(dbContext.configKey.policy == PersistencePolicy_wc)
168 length = gCPathPrefixSize;
172 length = gWTPathPrefixSize;
175 strncpy(fileSubPath, dbPath+length, DbPathMaxLen);
176 snprintf(backupPath, DbPathMaxLen-1, "%s%s", gBackupPrefix, fileSubPath);
177 snprintf(csumPath, DbPathMaxLen-1, "%s%s%s", gBackupPrefix, fileSubPath, ".crc");
179 if(shared_DB >= 0) // check valid database context
181 int flags = pclGetPosixPermission(dbContext.configKey.permission);
183 // file will be opened writable, so check about data consistency
184 if( (dbContext.configKey.permission != PersistencePermission_ReadOnly)
185 && pclBackupNeeded(dbPath) )
187 if((handle = pclVerifyConsistency(dbPath, backupPath, csumPath, flags)) == -1)
189 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileOpen: error => file inconsistent, recovery N O T possible!"));
195 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileOpen: No Backup => file is read only OR is in blacklist!"));
200 if(handle > 0) // when the file is open, close it and do a new open unde PFC control
205 handle = pfcOpenFile(dbPath);
207 if(handle <= 0) // check if open is needed or already done in verifyConsistency
209 handle = open(dbPath, flags);
213 if(handle == -1 && errno == ENOENT) // file does not exist, create file and folder
216 if((handle = pclCreateFile(dbPath)) == -1)
218 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileOpen: error => failed to create file: "), DLT_STRING(dbPath));
222 // check if there is default data available
223 char pathPrefix[DbPathMaxLen] = {0};
224 char defaultPath[DbPathMaxLen] = {0};
225 int defaultHandle = -1;
227 // create path to default data
228 if(dbContext.configKey.policy == PersistencePolicy_wc)
230 snprintf(pathPrefix, DbPathMaxLen, gLocalCachePath, gAppId);
232 else if(dbContext.configKey.policy == PersistencePolicy_wt)
234 snprintf(pathPrefix, DbPathMaxLen, gLocalWtPath, gAppId);
237 snprintf(defaultPath, DbPathMaxLen, "%s%s%s", pathPrefix, gDefDataFolder, resource_id);
238 printf("=> => => => defaultPath: %s => resourceID: %s\n", defaultPath, resource_id);
240 defaultHandle = open(defaultPath, O_RDONLY);
241 if(defaultHandle != -1) // check if default data is available
245 memset(&buf, 0, sizeof(buf));
247 fstat(defaultHandle, &buf);
248 sendfile(handle, defaultHandle, 0, buf.st_size);
249 close(defaultHandle);
253 printf(" = = = = Failed to open file: %d => %s\n", defaultHandle, strerror(errno));
258 if(handle < MaxPersHandle && handle > 0 )
260 __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
262 if(dbContext.configKey.permission != PersistencePermission_ReadOnly)
264 strcpy(gFileHandleArray[handle].backupPath, backupPath);
265 strcpy(gFileHandleArray[handle].csumPath, csumPath);
266 gFileHandleArray[handle].backupCreated = 0;
267 gFileHandleArray[handle].permission = dbContext.configKey.permission;
273 handle = EPERS_MAXHANDLE;
276 else // requested resource is not in the RCT, so create resource as local/cached.
278 // assemble file string for local cached location
279 snprintf(dbPath, DbPathMaxLen, gLocalCacheFilePath, gAppId, user_no, seat_no, resource_id);
280 handle = pclCreateFile(dbPath);
282 if(handle < MaxPersHandle && handle > 0)
284 __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
286 strcpy(gFileHandleArray[handle].backupPath, backupPath);
287 strcpy(gFileHandleArray[handle].csumPath, csumPath);
288 gFileHandleArray[handle].backupCreated = 0;
289 gFileHandleArray[handle].permission = PersistencePermission_ReadWrite; // make it writable
294 handle = EPERS_MAXHANDLE;
300 handle = EPERS_RESOURCE_NO_FILE;
309 int pclFileReadData(int fd, void * buffer, int buffer_size)
311 int readSize = EPERS_NOT_INITIALIZED;
313 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileReadData fd: "), DLT_INT(fd));
314 if(gPclInitialized >= PCLinitialized)
317 readSize = pfcReadFile(fd, buffer, buffer_size);
319 readSize = read(fd, buffer, buffer_size);
327 int pclFileRemove(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no)
329 int rval = EPERS_NOT_INITIALIZED;
331 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileReadData "), DLT_INT(ldbid), DLT_STRING(resource_id));
333 if(gPclInitialized >= PCLinitialized)
335 if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
338 PersistenceInfo_s dbContext;
340 char dbKey[DbKeyMaxLen] = {0}; // database key
341 char dbPath[DbPathMaxLen] = {0}; // database location
343 dbContext.context.ldbid = ldbid;
344 dbContext.context.seat_no = seat_no;
345 dbContext.context.user_no = user_no;
347 // get database context: database path and database key
348 shared_DB = get_db_context(&dbContext, resource_id, ResIsFile, dbKey, dbPath);
350 if( (shared_DB >= 0) // check valid database context
351 && (dbContext.configKey.type == PersistenceResourceType_file) ) // check if type matches
353 rval = remove(dbPath);
356 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileRemove => remove ERROR"), DLT_STRING(strerror(errno)) );
362 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileRemove ==> no valid database context or resource not a file"));
376 int pclFileSeek(int fd, long int offset, int whence)
378 int rval = EPERS_NOT_INITIALIZED;
380 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileSeek fd:"), DLT_INT(fd));
382 if(gPclInitialized >= PCLinitialized)
384 if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
387 rval = pfcFileSeek(fd, offset, whence);
389 rval = lseek(fd, offset, whence);
403 int pclFileUnmapData(void* address, long size)
405 int rval = EPERS_NOT_INITIALIZED;
407 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileUnmapData"));
409 if(gPclInitialized >= PCLinitialized)
411 if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
413 rval = munmap(address, size);
426 int pclFileWriteData(int fd, const void * buffer, int buffer_size)
428 int size = EPERS_NOT_INITIALIZED;
430 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileWriteData fd:"), DLT_INT(fd));
432 if(gPclInitialized >= PCLinitialized)
434 if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
436 if(fd < MaxPersHandle)
438 if(gFileHandleArray[fd].permission != PersistencePermission_ReadOnly)
440 // check if a backup file has to be created
441 if(gFileHandleArray[fd].backupCreated == 0)
443 char csumBuf[ChecksumBufSize] = {0};
445 // calculate checksum
446 pclCalcCrc32Csum(fd, csumBuf);
447 // create checksum and backup file
448 pclCreateBackup(gFileHandleArray[fd].backupPath, fd, gFileHandleArray[fd].csumPath, csumBuf);
450 gFileHandleArray[fd].backupCreated = 1;
454 size = pfcWriteFile(fd, buffer, buffer_size);
456 size = write(fd, buffer, buffer_size);
461 size = EPERS_RESOURCE_READ_ONLY;
475 int pclFileCreatePath(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no, char** path, unsigned int* size)
477 int handle = EPERS_NOT_INITIALIZED;
479 if(gPclInitialized >= PCLinitialized)
482 PersistenceInfo_s dbContext;
484 char dbKey[DbKeyMaxLen] = {0}; // database key
485 char dbPath[DbPathMaxLen] = {0}; // database location
486 char backupPath[DbPathMaxLen] = {0}; // backup file
487 char csumPath[DbPathMaxLen] = {0}; // checksum file
489 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileOpen: "), DLT_INT(ldbid), DLT_STRING(resource_id) );
491 dbContext.context.ldbid = ldbid;
492 dbContext.context.seat_no = seat_no;
493 dbContext.context.user_no = user_no;
495 // get database context: database path and database key
496 shared_DB = get_db_context(&dbContext, resource_id, ResIsFile, dbKey, dbPath);
498 if( dbContext.configKey.type == PersistenceResourceType_file) // check if type matches
500 if(shared_DB >= 0) // check valid database context
502 int flags = pclGetPosixPermission(dbContext.configKey.permission);
504 // file will be opened writable, so check about data consistency
505 if( dbContext.configKey.permission != PersistencePermission_ReadOnly
506 && pclBackupNeeded(dbPath) )
508 snprintf(backupPath, DbPathMaxLen-1, "%s%s", dbPath, "~");
509 snprintf(csumPath, DbPathMaxLen-1, "%s%s", dbPath, "~.crc");
511 if((handle = pclVerifyConsistency(dbPath, backupPath, csumPath, flags)) == -1)
513 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileOpen: error => file inconsistent, recovery N O T possible!"));
516 // we don't need the file handle here
517 // the application calling this function must use the POSIX open() function to get an file descriptor
521 handle = get_persistence_handle_idx();
525 if(handle < MaxPersHandle)
527 __sync_fetch_and_add(&gOpenHandleArray[handle], FileOpen); // set open flag
529 if(dbContext.configKey.permission != PersistencePermission_ReadOnly)
531 strncpy(gOssHandleArray[handle].backupPath, backupPath, DbPathMaxLen);
532 strncpy(gOssHandleArray[handle].csumPath, csumPath, DbPathMaxLen);
534 gOssHandleArray[handle].backupCreated = 0;
535 gOssHandleArray[handle].permission = dbContext.configKey.permission;
538 *size = strlen(dbPath);
539 *path = malloc((*size)+1); // allocate 1 byte for the string termination
540 memcpy(*path, dbPath, (*size));
541 (*path)[(*size)] = '\0'; // terminate string
542 gOssHandleArray[handle].filePath = *path;
544 if(access(*path, F_OK) == -1)
546 // file does not exist, create it.
547 int handle = pclCreateFile(*path);
548 close(handle); // don't need the open file
553 set_persistence_handle_close_idx(handle);
554 handle = EPERS_MAXHANDLE;
558 else // requested resource is not in the RCT, so create resource as local/cached.
560 // assemble file string for local cached location
561 snprintf(dbPath, DbPathMaxLen, gLocalCacheFilePath, gAppId, user_no, seat_no, resource_id);
562 handle = get_persistence_handle_idx();
566 if(handle < MaxPersHandle)
568 snprintf(backupPath, DbPathMaxLen, "%s%s", dbPath, "~");
569 snprintf(csumPath, DbPathMaxLen, "%s%s", dbPath, "~.crc");
571 __sync_fetch_and_add(&gOpenHandleArray[handle], FileOpen); // set open flag
572 strncpy(gOssHandleArray[handle].backupPath, backupPath, DbPathMaxLen);
573 strncpy(gOssHandleArray[handle].csumPath, csumPath, DbPathMaxLen);
574 gOssHandleArray[handle].backupCreated = 0;
575 gOssHandleArray[handle].permission = PersistencePermission_ReadWrite; // make it writable
579 set_persistence_handle_close_idx(handle);
580 handle = EPERS_MAXHANDLE;
587 handle = EPERS_RESOURCE_NO_FILE;
596 int pclFileReleasePath(int pathHandle)
598 int rval = EPERS_NOT_INITIALIZED;
600 //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileClose fd: "), DLT_INT(fd));
602 if(gPclInitialized >= PCLinitialized)
604 if(pathHandle < MaxPersHandle)
606 // check if a backup and checksum file needs to bel deleted
607 if( gFileHandleArray[pathHandle].permission != PersistencePermission_ReadOnly)
609 // remove backup file
610 remove(gOssHandleArray[pathHandle].backupPath); // we don't care about return value
612 // remove checksum file
613 remove(gOssHandleArray[pathHandle].csumPath); // we don't care about return value
616 free(gOssHandleArray[pathHandle].filePath);
617 __sync_fetch_and_sub(&gOpenHandleArray[pathHandle], FileClosed); // set closed flag
618 set_persistence_handle_close_idx(pathHandle);
619 gOssHandleArray[pathHandle].filePath = NULL;
624 rval = EPERS_MAXHANDLE;