GDLT-2: Change to gzip wrapper format. Change file signature creation to
[profile/ivi/dlt-daemon.git] / src / lib / dlt_filetransfer.c
1 /**
2  * @licence app begin@
3  * Copyright (C) 2012  BMW AG
4  *
5  * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
6  *
7  * Contributions are licensed to the GENIVI Alliance under one or more
8  * Contribution License Agreements.
9  *
10  * \copyright
11  * This Source Code Form is subject to the terms of the
12  * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
13  * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
14  *
15  *
16  * \author Alexander Wenzel <alexander.aw.wenzel@bmw.de> BMW 2011-2012
17  *
18  * \file dlt_filetransfer.c
19  * For further information see http://www.genivi.org/.
20  * @licence end@
21  */
22
23
24 /*******************************************************************************
25 **                                                                            **
26 **  SRC-MODULE: dlt-test-client.c                                             **
27 **                                                                            **
28 **  TARGET    : linux                                                         **
29 **                                                                            **
30 **  PROJECT   : DLT                                                           **
31 **                                                                            **
32 **  AUTHOR    : Alexander Wenzel Alexander.AW.Wenzel@bmw.de                   **
33 **                                                                            **
34 **  PURPOSE   :                                                               **
35 **                                                                            **
36 **  REMARKS   :                                                               **
37 **                                                                            **
38 **  PLATFORM DEPENDANT [yes/no]: yes                                          **
39 **                                                                            **
40 **  TO BE CHANGED BY USER [yes/no]: no                                        **
41 **                                                                            **
42 *******************************************************************************/
43
44 /*******************************************************************************
45 **                      Author Identity                                       **
46 ********************************************************************************
47 **                                                                            **
48 ** Initials     Name                       Company                            **
49 ** --------     -------------------------  ---------------------------------- **
50 **  aw          Alexander Wenzel           BMW                                **
51 *******************************************************************************/
52
53 #include "dlt_filetransfer.h"
54
55 //!Defines the buffer size of a single file package which will be logged to dlt
56 #define BUFFER_SIZE 1024
57
58 //!Defines the minimum timeout between two dlt logs. This is important because dlt should not be flooded with too many logs in a short period of time.
59 #define MIN_TIMEOUT 20
60
61
62 #define DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES LONG_MAX
63
64
65 //!Buffer for dlt file transfer. The size is defined by BUFFER_SIZE
66 unsigned char buffer[BUFFER_SIZE];
67
68
69 //!Get some information about the file size of a file
70 /**See stat(2) for more informations.
71  * @param file Absolute file path
72  * @return Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
73  */
74 unsigned long getFilesize(const char* file){
75         struct stat st;
76         stat(file, &st);
77         return (unsigned long)st.st_size;
78 }
79
80 //!Get some information about the file serial number of a file
81 /** See stat(2) for more informations.
82  * @param file Absolute file path
83  * @return Returns a unique number associated with each filename
84  */
85 unsigned long getFileSerialNumber(const char* file){
86         struct stat st;
87         unsigned long ret;
88         stat(file, &st);
89         ret = st.st_ino;
90         ret = ret << (sizeof(ret)*8)/2;
91         ret |= st.st_size;
92         return ret;
93 }
94
95 //!Returns the creation date of a file
96 /** See stat(2) for more informations.
97  * @param file Absolute file path
98  * @return Returns the creation date of a file
99 */
100 time_t getFileCreationDate(const char* file){
101         struct stat st;
102         stat(file, &st);
103         return st.st_ctime;
104 }
105
106 //!Returns the creation date of a file
107 /** Format of the creation date is Day Mon dd hh:mm:ss yyyy
108  * @param file Absolute file path
109  * @return Returns the creation date of a file
110 */
111 char* getFileCreationDate2(const char* file){
112         struct stat st;
113         stat(file, &st);
114         
115         struct tm  *ts= localtime(&st.st_ctime);
116         return asctime(ts);
117 }
118
119 //!Checks if the file exists
120 /**@param file Absolute file path
121  * @return Returns 1 if the file exists, 0 if the file does not exist
122  */
123 int isFile (const char* file)
124 {
125         struct stat   st;   
126         return (stat (file, &st) == 0);
127 }
128
129 //!Waits a period of time
130 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
131  * @param timeout Timeout to in ms but can not be smaller as MIN_TIMEOUT
132  */
133 void doTimeout(int timeout)
134 {
135         usleep(timeout * 1000);
136 }
137
138 //!Checks free space of the user buffer
139 /**
140  * @param returns -1 if more than 50% space in the user buffer is free. Otherwise 1 will be returned.
141  */
142 int checkUserBufferForFreeSpace()
143 {
144         int total_size, used_size;
145
146         dlt_user_check_buffer(&total_size, &used_size);
147
148         if((total_size - used_size) < (total_size/2))
149         {
150                 return -1;
151         }
152         return 1;
153 }
154
155 //!Deletes the given file
156 /**
157  * @param filename Absolute file path
158  * @return If the file is successfully deleted, a zero value is returned.If the file can not be deleted a nonzero value is returned.
159  */
160 int doRemoveFile(const char*filename){
161         return remove( filename); 
162 }
163
164 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
165
166         if(errno != ENOENT)
167         {
168                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
169                         DLT_STRING("FLER"),
170                         DLT_INT(errorCode),
171                         DLT_INT(-errno),
172                         DLT_UINT(getFileSerialNumber(filename)),
173                         DLT_STRING(filename),
174                         DLT_UINT(getFilesize(filename)),
175                         DLT_STRING(getFileCreationDate2(filename)),
176                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
177                         DLT_UINT(BUFFER_SIZE),
178                         DLT_STRING("FLER")
179                 );              
180         } else {
181                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
182                         DLT_STRING("FLER"),
183                         DLT_INT(errorCode),
184                         DLT_INT(-errno),
185                         DLT_STRING(filename),
186                         DLT_STRING("FLER")
187                 );
188         }
189 }
190
191
192
193 //!Logs specific file inforamtions to dlt
194 /**The filename, file size, file serial number and the number of packages will be logged to dlt.
195  * @param fileContext Specific context
196  * @param filename Absolute file path
197  * @return Returns 0 if everything was okey.If there was a failure a value < 0 will be returned.
198  */
199 int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
200         
201         if(isFile(filename))
202         {
203                 DLT_LOG(*fileContext,DLT_LOG_INFO,
204                         DLT_STRING("FLIF"),
205                         DLT_STRING("file serialnumber"),DLT_UINT(getFileSerialNumber(filename)),
206                         DLT_STRING("filename"),DLT_STRING(filename),
207                         DLT_STRING("file size in bytes"),DLT_UINT(getFilesize(filename)),
208                         DLT_STRING("file creation date"),DLT_STRING(getFileCreationDate2(filename)),
209                         DLT_STRING("number of packages"),DLT_UINT(dlt_user_log_file_packagesCount(fileContext, filename)),
210                         DLT_STRING("FLIF")
211                 );
212                 return 0;
213         } else {
214                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_INFO_ABOUT);
215                 return DLT_FILETRANSFER_ERROR_INFO_ABOUT;
216         }
217 }
218
219 //!Transfer the complete file as several dlt logs.
220 /**This method transfer the complete file as several dlt logs. At first it will be checked that the file exist.
221  * In the next step some generic informations about the file will be logged to dlt.
222  * Now the header will be logged to dlt. See the method dlt_user_log_file_header for more informations.
223  * Then the method dlt_user_log_data will be called with the parameter to log all packages in a loop with some timeout.
224  * At last dlt_user_log_end is called to signal that the complete file transfer was okey. This is important for the plugin of the dlt viewer. 
225  * @param fileContext Specific context to log the file to dlt
226  * @param filename Absolute file path
227  * @param deleteFlag Flag if the file will be deleted after transfer. 1->delete, 0->notDelete
228  * @param timeout Timeout in ms to wait between some logs. Important that the FIFO of dlt will not be flooded with to many messages in a short period of time.
229  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
230  */
231 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
232 {       
233         if(!isFile(filename))
234         {
235                 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_COMPLETE);
236                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE;
237         }
238         
239         if(dlt_user_log_file_header(fileContext,filename) != 0)
240         {
241                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE1;
242         }
243                 
244         if(dlt_user_log_file_data(fileContext, filename,DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES,timeout) != 0)
245         {
246                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE2;
247         }
248                 
249         if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
250         {
251                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE3;
252         }               
253                         
254         return 0;
255 }
256
257 //!This method gives information about the number of packages the file have
258 /**Every file will be divided into several packages. Every package will be logged as a single dlt log.
259  * The number of packages depends on the BUFFER_SIZE.
260  * At first it will be checked if the file exist. Then the file will be divided into
261  * several packages depending on the buffer size.
262  * @param fileContext Specific context to log the file to dlt
263  * @param filename Absolute file path
264  * @return Returns the number of packages if everything was okey. If there was a failure a value < 0 will be returned.
265  */
266 int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filename){
267         int packages;
268         long filesize;
269         
270         if(isFile(filename))
271         {
272                 packages = 1;
273                 filesize = getFilesize(filename);
274                 if(filesize < BUFFER_SIZE)
275                 {       
276                         return packages;
277                 } 
278                 else 
279                 {
280                         packages = filesize/BUFFER_SIZE;
281                         
282                         if(filesize%BUFFER_SIZE == 0)
283                         {       
284                                 return packages;
285                         }
286                         else
287                         {
288                                 return packages+1;
289                         }
290                 }
291         } else {
292                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_PACKAGE_COUNT);
293                 return -1;
294         }
295 }
296
297 //!Transfer the head of the file as a dlt logs.
298 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
299  * the file name, the file size, package number the file have and the buffer size.
300  * All these informations are needed from the plugin of the dlt viewer.
301  * See the Mainpages.c for more informations.
302  * @param fileContext Specific context to log the file to dlt
303  * @param filename Absolute file path
304  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
305  */
306 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
307
308         if(isFile(filename))
309         {
310                 DLT_LOG(*fileContext,DLT_LOG_INFO,
311                                         DLT_STRING("FLST"),
312                                         DLT_UINT(getFileSerialNumber(filename)),
313                                         DLT_STRING(filename),
314                                         DLT_UINT(getFilesize(filename)),
315                                         DLT_STRING(getFileCreationDate2(filename));
316                                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
317                                         DLT_UINT(BUFFER_SIZE),
318                                         DLT_STRING("FLST")              
319                                 );
320
321                 return 0;
322         }
323         else
324         {
325                 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
326                 return DLT_FILETRANSFER_ERROR_FILE_HEAD;
327         }
328 }
329
330 //!Transfer the content data of a file.
331 /**See the Mainpages.c for more informations.
332  * @param fileContext Specific context to log the file to dlt
333  * @param filename Absolute file path
334  * @param packageToTransfer Package number to transfer. If this param is LONG_MAX, the whole file will be transferred with a specific timeout
335  * @param timeout Timeout to wait between dlt logs. Important because the dlt FIFO should not be flooded. Default is defined by MIN_TIMEOUT. The given timeout in ms can not be smaller than MIN_TIMEOUT.
336  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
337  */
338 int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int packageToTransfer, int timeout){
339         FILE *file;
340         int pkgNumber;
341         long readBytes;
342                 
343         if(isFile(filename))
344         {
345         
346                 file = fopen (filename,"rb");
347                 if (file == NULL)
348                 {
349                         dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
350                         return DLT_FILETRANSFER_ERROR_FILE_DATA;
351                 }
352                 
353                 if( (packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
354                 {
355                         DLT_LOG(*fileContext,DLT_LOG_ERROR,
356                                 DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
357                                 DLT_STRING("packageToTransfer:"),
358                                 DLT_UINT(packageToTransfer),
359                                 DLT_STRING("numberOfMaximalPackages:"),
360                                 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
361                                 DLT_STRING("for File:"),
362                                 DLT_STRING(filename)
363                         );
364                         return DLT_FILETRANSFER_ERROR_FILE_DATA;
365                 }
366
367                 readBytes = 0;
368                 
369                 if(packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES)
370                 {
371 //                              If a single package should be transferred. The user has to check that the free space in the user buffer > 50%
372 //                              if(checkUserBufferForFreeSpace()<0)
373 //                                      return DLT_FILETRANSFER_ERROR_FILE_DATA_USER_BUFFER_FAILED;
374
375                                 fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET );
376                                 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
377
378                                 DLT_LOG(*fileContext,DLT_LOG_INFO,
379                                 DLT_STRING("FLDA"),
380                                 DLT_UINT(getFileSerialNumber(filename)),
381                                 DLT_UINT(packageToTransfer),
382                                 DLT_RAW(buffer,readBytes),
383                                 DLT_STRING("FLDA")
384                                 );
385
386                                 doTimeout(timeout);
387
388                 } else {
389                         pkgNumber = 0;
390                         while( !feof( file ) )
391                         {
392 //                              If the complete file should be transferred, the user buffer will be checked.
393 //                              If free space < 50% the package won't be transferred.
394                                 if(checkUserBufferForFreeSpace()>0)
395                                 {
396                                         pkgNumber++;
397                                         readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
398                                 
399                                         DLT_LOG(*fileContext,DLT_LOG_INFO,
400                                                         DLT_STRING("FLDA"),
401                                                         DLT_UINT(getFileSerialNumber(filename)),
402                                                         DLT_UINT(pkgNumber),
403                                                         DLT_RAW(buffer,readBytes),
404                                                         DLT_STRING("FLDA")
405                                         );
406                                 }
407                                 doTimeout(timeout);
408                         }
409                 }
410                 
411                 fclose(file);
412                 
413                 return 0;
414                 
415         } else {
416                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
417                 return DLT_FILETRANSFER_ERROR_FILE_DATA;
418         }
419         
420 }
421 //!Transfer the end of the file as a dlt logs.
422 /**The end of the file must be logged to dlt because the end contains inforamtion about the file serial number.
423  * This informations is needed from the plugin of the dlt viewer.
424  * See the Mainpages.c for more informations.
425  * @param fileContext Specific context to log the file to dlt
426  * @param filename Absolute file path
427  * @param deleteFlag Flag to delete the file after the whole file is transferred (logged to dlt).1->delete,0->NotDelete
428  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
429  */
430 int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int deleteFlag){
431
432         if(isFile(filename))
433         {
434
435                 DLT_LOG(*fileContext,DLT_LOG_INFO,
436                                 DLT_STRING("FLFI"),
437                                 DLT_UINT(getFileSerialNumber(filename)),
438                                 DLT_STRING("FLFI")
439                 );
440                 
441                 if(deleteFlag){
442                                 if( doRemoveFile(filename) != 0 ){
443                                         dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
444                                         return -1;
445                                 }
446                 }
447         
448                 return 0;
449         }else{
450                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
451                 return DLT_FILETRANSFER_ERROR_FILE_END;
452         }
453 }