Added use of default data for files; added test data that can be used by PAS installa...
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_file.c
1 /******************************************************************************
2  * Project         Persistency
3  * (c) copyright   2012
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 ******************************************************************************/
11  /**
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
17  * @see            
18  */
19
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"
27 #include "crc32.h"
28
29 #if USE_FILECACHE
30    #include <persistence_file_cache.h>
31 #endif
32
33 #include <fcntl.h>   // for open flags
34 #include <errno.h>
35 #include <string.h>
36 #include <sys/mman.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41
42
43
44 int pclFileClose(int fd)
45 {
46    int rval = EPERS_NOT_INITIALIZED;
47
48    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileClose fd: "), DLT_INT(fd));
49
50    if(gPclInitialized >= PCLinitialized)
51    {
52       if(fd < MaxPersHandle)
53       {
54          // check if a backup and checksum file needs to bel deleted
55          if( gFileHandleArray[fd].permission != PersistencePermission_ReadOnly)
56          {
57             // remove backup file
58             remove(gFileHandleArray[fd].backupPath);  // we don't care about return value
59
60             // remove checksum file
61             remove(gFileHandleArray[fd].csumPath);    // we don't care about return value
62
63          }
64          __sync_fetch_and_sub(&gOpenFdArray[fd], FileClosed);   // set closed flag
65 #if USE_FILECACHE
66          rval = pfcCloseFile(fd);
67 #else
68          rval = close(fd);
69 #endif
70
71       }
72       else
73       {
74           rval = EPERS_MAXHANDLE;
75       }
76    }
77
78    return rval;
79 }
80
81
82
83 int pclFileGetSize(int fd)
84 {
85    int size = EPERS_NOT_INITIALIZED;
86
87    if(gPclInitialized >= PCLinitialized)
88    {
89
90 #if USE_FILECACHE
91       size = pfcFileGetSize(fd);
92 #else
93       struct stat buf;
94       size = fstat(fd, &buf);
95
96       //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileGetSize fd: "), DLT_INT(fd));
97
98       if(size != -1)
99       {
100          size = buf.st_size;
101       }
102 #endif
103    }
104    return size;
105 }
106
107
108
109 void* pclFileMapData(void* addr, long size, long offset, int fd)
110 {
111    void* ptr = 0;
112
113 #if USE_FILECACHE
114    DLT_LOG(gPclDLTContext, DLT_LOG_WARN, DLT_STRING("pclFileMapData not supported when using file cache"));
115 #else
116    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileMapData fd: "), DLT_INT(fd));
117
118    if(gPclInitialized >= PCLinitialized)
119    {
120       if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
121       {
122          int mapFlag = PROT_WRITE | PROT_READ;
123          ptr = mmap(addr,size, mapFlag, MAP_SHARED, fd, offset);
124       }
125       else
126       {
127          ptr = EPERS_MAP_LOCKFS;
128       }
129    }
130 #endif
131
132    return ptr;
133 }
134
135
136
137 int pclFileOpen(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no)
138 {
139    int handle = EPERS_NOT_INITIALIZED;
140
141    if(gPclInitialized >= PCLinitialized)
142    {
143       int shared_DB = 0;
144       PersistenceInfo_s dbContext;
145
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
150
151       //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileOpen: "), DLT_INT(ldbid), DLT_STRING(resource_id) );
152
153       dbContext.context.ldbid   = ldbid;
154       dbContext.context.seat_no = seat_no;
155       dbContext.context.user_no = user_no;
156
157       // get database context: database path and database key
158       shared_DB = get_db_context(&dbContext, resource_id, ResIsFile, dbKey, dbPath);
159
160       if(dbContext.configKey.type == PersistenceResourceType_file)   // check if the resource is really a file
161       {
162          // create backup path
163          int length = 0;
164          char fileSubPath[DbPathMaxLen] = {0};
165
166          if(dbContext.configKey.policy ==  PersistencePolicy_wc)
167          {
168             length = gCPathPrefixSize;
169          }
170          else
171          {
172             length = gWTPathPrefixSize;
173          }
174
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");
178
179          if(shared_DB >= 0)                                          // check valid database context
180          {
181             int flags = pclGetPosixPermission(dbContext.configKey.permission);
182
183             // file will be opened writable, so check about data consistency
184             if( (dbContext.configKey.permission != PersistencePermission_ReadOnly)
185                && pclBackupNeeded(dbPath) )
186             {
187                if((handle = pclVerifyConsistency(dbPath, backupPath, csumPath, flags)) == -1)
188                {
189                   DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileOpen: error => file inconsistent, recovery  N O T  possible!"));
190                   return -1;
191                }
192             }
193             else
194             {
195                DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileOpen: No Backup => file is read only OR is in blacklist!"));
196             }
197
198 #if USE_FILECACHE
199
200             if(handle > 0)   // when the file is open, close it and do a new open unde PFC control
201             {
202                close(handle);
203             }
204
205             handle = pfcOpenFile(dbPath);
206 #else
207             if(handle <= 0)   // check if open is needed or already done in verifyConsistency
208             {
209                handle = open(dbPath, flags);
210             }
211 #endif
212
213             if(handle == -1 && errno == ENOENT) // file does not exist, create file and folder
214             {
215
216                if((handle = pclCreateFile(dbPath)) == -1)
217                {
218                   DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileOpen: error => failed to create file: "), DLT_STRING(dbPath));
219                }
220                else
221                {
222                 // check if there is default data available
223                 char pathPrefix[DbPathMaxLen] = {0};
224                 char defaultPath[DbPathMaxLen] = {0};
225                 int defaultHandle = -1;
226
227                 // create path to default data
228                 if(dbContext.configKey.policy == PersistencePolicy_wc)
229                 {
230                         snprintf(pathPrefix, DbPathMaxLen, gLocalCachePath, gAppId);
231                 }
232                 else if(dbContext.configKey.policy == PersistencePolicy_wt)
233                 {
234                         snprintf(pathPrefix, DbPathMaxLen, gLocalWtPath, gAppId);
235                 }
236
237                 snprintf(defaultPath, DbPathMaxLen, "%s%s%s", pathPrefix, gDefDataFolder, resource_id);
238                 printf("=> => => => defaultPath: %s => resourceID: %s\n", defaultPath, resource_id);
239
240                 defaultHandle = open(defaultPath, O_RDONLY);
241                 if(defaultHandle != -1) // check if default data is available
242                 {
243                                                         // copy default data
244                                                         struct stat buf;
245                                                         memset(&buf, 0, sizeof(buf));
246
247                                                         fstat(defaultHandle, &buf);
248                                                         sendfile(handle, defaultHandle, 0, buf.st_size);
249                         close(defaultHandle);
250                 }
251                 else
252                 {
253                         printf(" = = = =  Failed to open file: %d => %s\n", defaultHandle, strerror(errno));
254                 }
255                }
256             }
257
258             if(handle < MaxPersHandle && handle > 0 )
259             {
260                __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
261
262                if(dbContext.configKey.permission != PersistencePermission_ReadOnly)
263                {
264                   strcpy(gFileHandleArray[handle].backupPath, backupPath);
265                   strcpy(gFileHandleArray[handle].csumPath,   csumPath);
266                   gFileHandleArray[handle].backupCreated = 0;
267                   gFileHandleArray[handle].permission = dbContext.configKey.permission;
268                }
269             }
270             else
271             {
272                close(handle);
273                handle = EPERS_MAXHANDLE;
274             }
275          }
276          else  // requested resource is not in the RCT, so create resource as local/cached.
277          {
278             // assemble file string for local cached location
279             snprintf(dbPath, DbPathMaxLen, gLocalCacheFilePath, gAppId, user_no, seat_no, resource_id);
280             handle = pclCreateFile(dbPath);
281
282             if(handle < MaxPersHandle && handle > 0)
283             {
284                __sync_fetch_and_add(&gOpenFdArray[handle], FileOpen); // set open flag
285
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
290             }
291             else
292             {
293                close(handle);
294                handle = EPERS_MAXHANDLE;
295             }
296          }
297       }
298       else
299       {
300          handle = EPERS_RESOURCE_NO_FILE;
301       }
302    }
303
304    return handle;
305 }
306
307
308
309 int pclFileReadData(int fd, void * buffer, int buffer_size)
310 {
311    int readSize = EPERS_NOT_INITIALIZED;
312
313    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileReadData fd: "), DLT_INT(fd));
314    if(gPclInitialized >= PCLinitialized)
315    {
316 #if USE_FILECACHE
317       readSize = pfcReadFile(fd, buffer, buffer_size);
318 #else
319       readSize = read(fd, buffer, buffer_size);
320 #endif
321    }
322    return readSize;
323 }
324
325
326
327 int pclFileRemove(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no)
328 {
329    int rval = EPERS_NOT_INITIALIZED;
330
331    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileReadData "), DLT_INT(ldbid), DLT_STRING(resource_id));
332
333    if(gPclInitialized >= PCLinitialized)
334    {
335       if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
336       {
337          int shared_DB = 0;
338          PersistenceInfo_s dbContext;
339
340          char dbKey[DbKeyMaxLen]   = {0};      // database key
341          char dbPath[DbPathMaxLen] = {0};    // database location
342
343          dbContext.context.ldbid   = ldbid;
344          dbContext.context.seat_no = seat_no;
345          dbContext.context.user_no = user_no;
346
347          // get database context: database path and database key
348          shared_DB = get_db_context(&dbContext, resource_id, ResIsFile, dbKey, dbPath);
349
350          if(   (shared_DB >= 0)                                               // check valid database context
351             && (dbContext.configKey.type == PersistenceResourceType_file) )   // check if type matches
352          {
353             rval = remove(dbPath);
354             if(rval == -1)
355             {
356                DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileRemove => remove ERROR"), DLT_STRING(strerror(errno)) );
357             }
358          }
359          else
360          {
361             rval = shared_DB;
362             DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileRemove ==> no valid database context or resource not a file"));
363          }
364       }
365       else
366       {
367          rval = EPERS_LOCKFS;
368       }
369    }
370
371    return rval;
372 }
373
374
375
376 int pclFileSeek(int fd, long int offset, int whence)
377 {
378    int rval = EPERS_NOT_INITIALIZED;
379
380    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileSeek fd:"), DLT_INT(fd));
381
382    if(gPclInitialized >= PCLinitialized)
383    {
384       if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
385       {
386 #if USE_FILECACHE
387          rval = pfcFileSeek(fd, offset, whence);
388 #else
389          rval = lseek(fd, offset, whence);
390 #endif
391       }
392       else
393       {
394          rval = EPERS_LOCKFS;
395       }
396    }
397
398    return rval;
399 }
400
401
402
403 int pclFileUnmapData(void* address, long size)
404 {
405    int rval = EPERS_NOT_INITIALIZED;
406
407    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileUnmapData"));
408
409    if(gPclInitialized >= PCLinitialized)
410    {
411       if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
412       {
413          rval =  munmap(address, size);
414       }
415       else
416       {
417          rval = EPERS_LOCKFS;
418       }
419    }
420
421    return rval;
422 }
423
424
425
426 int pclFileWriteData(int fd, const void * buffer, int buffer_size)
427 {
428    int size = EPERS_NOT_INITIALIZED;
429
430    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileWriteData fd:"), DLT_INT(fd));
431
432    if(gPclInitialized >= PCLinitialized)
433    {
434       if(AccessNoLock != isAccessLocked() ) // check if access to persistent data is locked
435       {
436          if(fd < MaxPersHandle)
437          {
438             if(gFileHandleArray[fd].permission != PersistencePermission_ReadOnly)
439             {
440                // check if a backup file has to be created
441                if(gFileHandleArray[fd].backupCreated == 0)
442                {
443                   char csumBuf[ChecksumBufSize] = {0};
444
445                   // calculate checksum
446                   pclCalcCrc32Csum(fd, csumBuf);
447                   // create checksum and backup file
448                   pclCreateBackup(gFileHandleArray[fd].backupPath, fd, gFileHandleArray[fd].csumPath, csumBuf);
449
450                   gFileHandleArray[fd].backupCreated = 1;
451                }
452
453 #if USE_FILECACHE
454                size = pfcWriteFile(fd, buffer, buffer_size);
455 #else
456                size = write(fd, buffer, buffer_size);
457 #endif
458             }
459             else
460             {
461                size = EPERS_RESOURCE_READ_ONLY;
462             }
463          }
464       }
465       else
466       {
467          size = EPERS_LOCKFS;
468       }
469    }
470
471    return size;
472 }
473
474
475 int pclFileCreatePath(unsigned int ldbid, const char* resource_id, unsigned int user_no, unsigned int seat_no, char** path, unsigned int* size)
476 {
477    int handle = EPERS_NOT_INITIALIZED;
478
479    if(gPclInitialized >= PCLinitialized)
480    {
481       int shared_DB = 0;
482       PersistenceInfo_s dbContext;
483
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
488
489       //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileOpen: "), DLT_INT(ldbid), DLT_STRING(resource_id) );
490
491       dbContext.context.ldbid   = ldbid;
492       dbContext.context.seat_no = seat_no;
493       dbContext.context.user_no = user_no;
494
495       // get database context: database path and database key
496       shared_DB = get_db_context(&dbContext, resource_id, ResIsFile, dbKey, dbPath);
497
498       if( dbContext.configKey.type == PersistenceResourceType_file)     // check if type matches
499       {
500          if(shared_DB >= 0)                                             // check valid database context
501          {
502             int flags = pclGetPosixPermission(dbContext.configKey.permission);
503
504             // file will be opened writable, so check about data consistency
505             if(   dbContext.configKey.permission != PersistencePermission_ReadOnly
506                && pclBackupNeeded(dbPath) )
507             {
508                snprintf(backupPath, DbPathMaxLen-1, "%s%s", dbPath, "~");
509                snprintf(csumPath,   DbPathMaxLen-1, "%s%s", dbPath, "~.crc");
510
511                if((handle = pclVerifyConsistency(dbPath, backupPath, csumPath, flags)) == -1)
512                {
513                   DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pclFileOpen: error => file inconsistent, recovery  N O T  possible!"));
514                   return -1;
515                }
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
518                close(handle);
519             }
520
521             handle = get_persistence_handle_idx();
522
523             if(handle != -1)
524             {
525                if(handle < MaxPersHandle)
526                {
527                   __sync_fetch_and_add(&gOpenHandleArray[handle], FileOpen); // set open flag
528
529                   if(dbContext.configKey.permission != PersistencePermission_ReadOnly)
530                   {
531                      strncpy(gOssHandleArray[handle].backupPath, backupPath, DbPathMaxLen);
532                      strncpy(gOssHandleArray[handle].csumPath,   csumPath, DbPathMaxLen);
533
534                      gOssHandleArray[handle].backupCreated = 0;
535                      gOssHandleArray[handle].permission = dbContext.configKey.permission;
536                   }
537
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;
543
544                   if(access(*path, F_OK) == -1)
545                   {
546                      // file does not exist, create it.
547                      int handle = pclCreateFile(*path);
548                      close(handle);    // don't need the open file
549                   }
550                }
551                else
552                {
553                   set_persistence_handle_close_idx(handle);
554                   handle = EPERS_MAXHANDLE;
555                }
556             }
557          }
558          else  // requested resource is not in the RCT, so create resource as local/cached.
559          {
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();
563
564             if(handle != -1)
565             {
566                if(handle < MaxPersHandle)
567                {
568                   snprintf(backupPath, DbPathMaxLen, "%s%s", dbPath, "~");
569                   snprintf(csumPath,   DbPathMaxLen, "%s%s", dbPath, "~.crc");
570
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
576                }
577                else
578                {
579                   set_persistence_handle_close_idx(handle);
580                   handle = EPERS_MAXHANDLE;
581                }
582             }
583          }
584       }
585       else
586       {
587          handle = EPERS_RESOURCE_NO_FILE;
588       }
589    }
590
591    return handle;
592 }
593
594
595
596 int pclFileReleasePath(int pathHandle)
597 {
598    int rval = EPERS_NOT_INITIALIZED;
599
600    //DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("pclFileClose fd: "), DLT_INT(fd));
601
602    if(gPclInitialized >= PCLinitialized)
603    {
604       if(pathHandle < MaxPersHandle)
605       {
606          // check if a backup and checksum file needs to bel deleted
607          if( gFileHandleArray[pathHandle].permission != PersistencePermission_ReadOnly)
608          {
609             // remove backup file
610             remove(gOssHandleArray[pathHandle].backupPath);  // we don't care about return value
611
612             // remove checksum file
613             remove(gOssHandleArray[pathHandle].csumPath);    // we don't care about return value
614
615          }
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;
620          rval = 1;
621       }
622       else
623       {
624         rval = EPERS_MAXHANDLE;
625       }
626    }
627
628    return rval;
629 }
630
631
632
633
634