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