GDLT-38, Update <FILE> fields in licenses.
[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.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         stat(file, &st);
88         return (unsigned long)st.st_ino;
89 }
90
91 //!Returns the creation date of a file
92 /** See stat(2) for more informations.
93  * @param file Absolute file path
94  * @return Returns the creation date of a file
95 */
96 time_t getFileCreationDate(const char* file){
97         struct stat st;
98         stat(file, &st);
99         return st.st_ctime;
100 }
101
102 //!Returns the creation date of a file
103 /** Format of the creation date is Day Mon dd hh:mm:ss yyyy
104  * @param file Absolute file path
105  * @return Returns the creation date of a file
106 */
107 char* getFileCreationDate2(const char* file){
108         struct stat st;
109         stat(file, &st);
110         
111         struct tm  *ts= localtime(&st.st_ctime);
112         return asctime(ts);
113 }
114
115 //!Checks if the file exists
116 /**@param file Absolute file path
117  * @return Returns 1 if the file exists, 0 if the file does not exist
118  */
119 int isFile (const char* file)
120 {
121         struct stat   st;   
122         return (stat (file, &st) == 0);
123 }
124
125 //!Waits a period of time
126 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
127  * @param timeout Timeout to in ms but can not be smaller as MIN_TIMEOUT
128  */
129 void doTimeout(int timeout)
130 {
131         usleep(timeout * 1000);
132 }
133
134 //!Checks free space of the user buffer
135 /**
136  * @param returns -1 if more than 50% space in the user buffer is free. Otherwise 1 will be returned.
137  */
138 int checkUserBufferForFreeSpace()
139 {
140         int total_size, used_size;
141
142         dlt_user_check_buffer(&total_size, &used_size);
143
144         if((total_size - used_size) < (total_size/2))
145         {
146                 return -1;
147         }
148         return 1;
149 }
150
151 //!Deletes the given file
152 /**
153  * @param filename Absolute file path
154  * @return If the file is successfully deleted, a zero value is returned.If the file can not be deleted a nonzero value is returned.
155  */
156 int doRemoveFile(const char*filename){
157         return remove( filename); 
158 }
159
160 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
161
162         if(errno != ENOENT)
163         {
164                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
165                         DLT_STRING("FLER"),
166                         DLT_INT(errorCode),
167                         DLT_INT(-errno),
168                         DLT_UINT(getFileSerialNumber(filename)),
169                         DLT_STRING(filename),
170                         DLT_UINT(getFilesize(filename)),
171                         DLT_STRING(getFileCreationDate2(filename)),
172                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
173                         DLT_UINT(BUFFER_SIZE),
174                         DLT_STRING("FLER")
175                 );              
176         } else {
177                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
178                         DLT_STRING("FLER"),
179                         DLT_INT(errorCode),
180                         DLT_INT(-errno),
181                         DLT_STRING(filename),
182                         DLT_STRING("FLER")
183                 );
184         }
185 }
186
187
188
189 //!Logs specific file inforamtions to dlt
190 /**The filename, file size, file serial number and the number of packages will be logged to dlt.
191  * @param fileContext Specific context
192  * @param filename Absolute file path
193  * @return Returns 0 if everything was okey.If there was a failure a value < 0 will be returned.
194  */
195 int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
196         
197         if(isFile(filename))
198         {
199                 DLT_LOG(*fileContext,DLT_LOG_INFO,
200                         DLT_STRING("FLIF"),
201                         DLT_STRING("file serialnumber"),DLT_UINT(getFileSerialNumber(filename)),
202                         DLT_STRING("filename"),DLT_STRING(filename),
203                         DLT_STRING("file size in bytes"),DLT_UINT(getFilesize(filename)),
204                         DLT_STRING("file creation date"),DLT_STRING(getFileCreationDate2(filename)),
205                         DLT_STRING("number of packages"),DLT_UINT(dlt_user_log_file_packagesCount(fileContext, filename)),
206                         DLT_STRING("FLIF")
207                 );
208                 return 0;
209         } else {
210                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_INFO_ABOUT);
211                 return DLT_FILETRANSFER_ERROR_INFO_ABOUT;
212         }
213 }
214
215 //!Transfer the complete file as several dlt logs.
216 /**This method transfer the complete file as several dlt logs. At first it will be checked that the file exist.
217  * In the next step some generic informations about the file will be logged to dlt.
218  * Now the header will be logged to dlt. See the method dlt_user_log_file_header for more informations.
219  * Then the method dlt_user_log_data will be called with the parameter to log all packages in a loop with some timeout.
220  * 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. 
221  * @param fileContext Specific context to log the file to dlt
222  * @param filename Absolute file path
223  * @param deleteFlag Flag if the file will be deleted after transfer. 1->delete, 0->notDelete
224  * @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.
225  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
226  */
227 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
228 {       
229         if(!isFile(filename))
230         {
231                 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_COMPLETE);
232                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE;
233         }
234         
235         if(dlt_user_log_file_header(fileContext,filename) != 0)
236         {
237                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE1;
238         }
239                 
240         if(dlt_user_log_file_data(fileContext, filename,DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES,timeout) != 0)
241         {
242                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE2;
243         }
244                 
245         if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
246         {
247                 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE3;
248         }               
249                         
250         return 0;
251 }
252
253 //!This method gives information about the number of packages the file have
254 /**Every file will be divided into several packages. Every package will be logged as a single dlt log.
255  * The number of packages depends on the BUFFER_SIZE.
256  * At first it will be checked if the file exist. Then the file will be divided into
257  * several packages depending on the buffer size.
258  * @param fileContext Specific context to log the file to dlt
259  * @param filename Absolute file path
260  * @return Returns the number of packages if everything was okey. If there was a failure a value < 0 will be returned.
261  */
262 int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filename){
263         int packages;
264         long filesize;
265         
266         if(isFile(filename))
267         {
268                 packages = 1;
269                 filesize = getFilesize(filename);
270                 if(filesize < BUFFER_SIZE)
271                 {       
272                         return packages;
273                 } 
274                 else 
275                 {
276                         packages = filesize/BUFFER_SIZE;
277                         
278                         if(filesize%BUFFER_SIZE == 0)
279                         {       
280                                 return packages;
281                         }
282                         else
283                         {
284                                 return packages+1;
285                         }
286                 }
287         } else {
288                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_PACKAGE_COUNT);
289                 return -1;
290         }
291 }
292
293 //!Transfer the head of the file as a dlt logs.
294 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
295  * the file name, the file size, package number the file have and the buffer size.
296  * All these informations are needed from the plugin of the dlt viewer.
297  * See the Mainpages.c for more informations.
298  * @param fileContext Specific context to log the file to dlt
299  * @param filename Absolute file path
300  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
301  */
302 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
303
304         if(isFile(filename))
305         {
306                 DLT_LOG(*fileContext,DLT_LOG_INFO,
307                                         DLT_STRING("FLST"),
308                                         DLT_UINT(getFileSerialNumber(filename)),
309                                         DLT_STRING(filename),
310                                         DLT_UINT(getFilesize(filename)),
311                                         DLT_STRING(getFileCreationDate2(filename));
312                                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
313                                         DLT_UINT(BUFFER_SIZE),
314                                         DLT_STRING("FLST")              
315                                 );
316
317                 return 0;
318         }
319         else
320         {
321                 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
322                 return DLT_FILETRANSFER_ERROR_FILE_HEAD;
323         }
324 }
325
326 //!Transfer the content data of a file.
327 /**See the Mainpages.c for more informations.
328  * @param fileContext Specific context to log the file to dlt
329  * @param filename Absolute file path
330  * @param packageToTransfer Package number to transfer. If this param is LONG_MAX, the whole file will be transferred with a specific timeout
331  * @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.
332  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
333  */
334 int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int packageToTransfer, int timeout){
335         FILE *file;
336         int pkgNumber;
337         long readBytes;
338                 
339         if(isFile(filename))
340         {
341         
342                 file = fopen (filename,"rb");
343                 if (file == NULL)
344                 {
345                         dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
346                         return DLT_FILETRANSFER_ERROR_FILE_DATA;
347                 }
348                 
349                 if( (packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
350                 {
351                         DLT_LOG(*fileContext,DLT_LOG_ERROR,
352                                 DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
353                                 DLT_STRING("packageToTransfer:"),
354                                 DLT_UINT(packageToTransfer),
355                                 DLT_STRING("numberOfMaximalPackages:"),
356                                 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
357                                 DLT_STRING("for File:"),
358                                 DLT_STRING(filename)
359                         );
360                         return DLT_FILETRANSFER_ERROR_FILE_DATA;
361                 }
362
363                 readBytes = 0;
364                 
365                 if(packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES)
366                 {
367 //                              If a single package should be transferred. The user has to check that the free space in the user buffer > 50%
368 //                              if(checkUserBufferForFreeSpace()<0)
369 //                                      return DLT_FILETRANSFER_ERROR_FILE_DATA_USER_BUFFER_FAILED;
370
371                                 fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET );
372                                 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
373
374                                 DLT_LOG(*fileContext,DLT_LOG_INFO,
375                                 DLT_STRING("FLDA"),
376                                 DLT_UINT(getFileSerialNumber(filename)),
377                                 DLT_UINT(packageToTransfer),
378                                 DLT_RAW(buffer,readBytes),
379                                 DLT_STRING("FLDA")
380                                 );
381
382                                 doTimeout(timeout);
383
384                 } else {
385                         pkgNumber = 0;
386                         while( !feof( file ) )
387                         {
388 //                              If the complete file should be transferred, the user buffer will be checked.
389 //                              If free space < 50% the package won't be transferred.
390                                 if(checkUserBufferForFreeSpace()>0)
391                                 {
392                                         pkgNumber++;
393                                         readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
394                                 
395                                         DLT_LOG(*fileContext,DLT_LOG_INFO,
396                                                         DLT_STRING("FLDA"),
397                                                         DLT_UINT(getFileSerialNumber(filename)),
398                                                         DLT_UINT(pkgNumber),
399                                                         DLT_RAW(buffer,readBytes),
400                                                         DLT_STRING("FLDA")
401                                         );
402                                 }
403                                 doTimeout(timeout);
404                         }
405                 }
406                 
407                 fclose(file);
408                 
409                 return 0;
410                 
411         } else {
412                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
413                 return DLT_FILETRANSFER_ERROR_FILE_DATA;
414         }
415         
416 }
417 //!Transfer the end of the file as a dlt logs.
418 /**The end of the file must be logged to dlt because the end contains inforamtion about the file serial number.
419  * This informations is needed from the plugin of the dlt viewer.
420  * See the Mainpages.c for more informations.
421  * @param fileContext Specific context to log the file to dlt
422  * @param filename Absolute file path
423  * @param deleteFlag Flag to delete the file after the whole file is transferred (logged to dlt).1->delete,0->NotDelete
424  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
425  */
426 int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int deleteFlag){
427
428         if(isFile(filename))
429         {
430
431                 DLT_LOG(*fileContext,DLT_LOG_INFO,
432                                 DLT_STRING("FLFI"),
433                                 DLT_UINT(getFileSerialNumber(filename)),
434                                 DLT_STRING("FLFI")
435                 );
436                 
437                 if(deleteFlag){
438                                 if( doRemoveFile(filename) != 0 ){
439                                         dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
440                                         return -1;
441                                 }
442                 }
443         
444                 return 0;
445         }else{
446                 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
447                 return DLT_FILETRANSFER_ERROR_FILE_END;
448         }
449 }