3 * Copyright (C) 2012 BMW AG
5 * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
7 * Contributions are licensed to the GENIVI Alliance under one or more
8 * Contribution License Agreements.
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/.
16 * \author Alexander Wenzel <alexander.aw.wenzel@bmw.de> BMW 2011-2012
18 * \file dlt_filetransfer.c
19 * For further information see http://www.genivi.org/.
24 /*******************************************************************************
26 ** SRC-MODULE: dlt-test-client.c **
32 ** AUTHOR : Alexander Wenzel Alexander.AW.Wenzel@bmw.de **
38 ** PLATFORM DEPENDANT [yes/no]: yes **
40 ** TO BE CHANGED BY USER [yes/no]: no **
42 *******************************************************************************/
44 /*******************************************************************************
46 ********************************************************************************
48 ** Initials Name Company **
49 ** -------- ------------------------- ---------------------------------- **
50 ** aw Alexander Wenzel BMW **
51 *******************************************************************************/
56 #include "dlt_filetransfer.h"
57 #include "dlt_common.h"
59 //!Defines the buffer size of a single file package which will be logged to dlt
60 #define BUFFER_SIZE 1024
62 //!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.
63 #define MIN_TIMEOUT 20
66 #define DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES LONG_MAX
69 //!Buffer for dlt file transfer. The size is defined by BUFFER_SIZE
70 unsigned char buffer[BUFFER_SIZE];
73 //!Get some information about the file size of a file
74 /**See stat(2) for more informations.
75 * @param file Absolute file path
76 * @return Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
78 unsigned long getFilesize(const char* file, int *ok){
81 if ( -1 == stat(file, &st))
83 //we can only return 0, as the value is unsigned
88 return (unsigned long)st.st_size;
91 /** A simple Hash function for C-strings
92 * @param str input string. E.g. a file path.
93 * @param hash start and result value for hash computation
96 void stringHash(const char* str, unsigned long *hash )
100 unsigned int len = strlen(str);
107 for(i = 0; i < len; i++)
109 *hash = 53 * *hash + str[i];
115 //!Get some information about the file serial number of a file
116 /** See stat(2) for more informations.
117 * @param file Absolute file path
118 * @param value *ok == 0 -> error; *ok == 1 -> ok
119 * @return Returns a unique number associated with each filename
121 unsigned long getFileSerialNumber(const char* file, int *ok){
124 if ( -1 == stat(file, &st))
133 ret = ret << (sizeof(ret)*8)/2;
136 stringHash(file, &ret);
141 //!Returns the creation date of a file
142 /** See stat(2) for more informations.
143 * @param file Absolute file path
144 * @return Returns the creation date of a file
146 time_t getFileCreationDate(const char* file,int *ok){
148 if (-1 == stat(file, &st))
157 //!Returns the creation date of a file
158 /** Format of the creation date is Day Mon dd hh:mm:ss yyyy
159 * @param file Absolute file path
160 * @return Returns the creation date of a file
162 char* getFileCreationDate2(const char* file,int *ok){
164 if (-1 == stat(file, &st))
170 struct tm *ts= localtime(&st.st_ctime);
174 //!Checks if the file exists
175 /**@param file Absolute file path
176 * @return Returns 1 if the file exists, 0 if the file does not exist
178 int isFile (const char* file)
181 return (stat (file, &st) == 0);
184 //!Waits a period of time
185 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
186 * @param timeout Timeout to in ms but can not be smaller as MIN_TIMEOUT
188 void doTimeout(int timeout)
190 usleep(timeout * 1000);
193 //!Checks free space of the user buffer
195 * @param returns -1 if more than 50% space in the user buffer is free. Otherwise 1 will be returned.
197 int checkUserBufferForFreeSpace()
199 int total_size, used_size;
201 dlt_user_check_buffer(&total_size, &used_size);
203 if((total_size - used_size) < (total_size/2))
210 //!Deletes the given file
212 * @param filename Absolute file path
213 * @return If the file is successfully deleted, a zero value is returned.If the file can not be deleted a nonzero value is returned.
215 int doRemoveFile(const char*filename){
216 return remove( filename);
219 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
224 unsigned long fserial = getFileSerialNumber(filename,&ok);
226 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_errorMessage, error in getFileSerialNumber for: "),DLT_STRING(filename));
227 unsigned long fsize = getFilesize(filename,&ok);
229 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_errorMessage, error in getFilesize for: "),DLT_STRING(filename));
230 char *fcreationdate = getFileCreationDate2(filename,&ok);
232 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_errorMessage, error in getFilesize for: "),DLT_STRING(filename));
234 int package_count = dlt_user_log_file_packagesCount(fileContext,filename);
236 DLT_LOG(*fileContext,DLT_LOG_ERROR,
241 DLT_STRING(filename),
243 DLT_STRING(fcreationdate),
244 DLT_INT(package_count),
245 DLT_UINT(BUFFER_SIZE),
249 DLT_LOG(*fileContext,DLT_LOG_ERROR,
253 DLT_STRING(filename),
261 //!Logs specific file inforamtions to dlt
262 /**The filename, file size, file serial number and the number of packages will be logged to dlt.
263 * @param fileContext Specific context
264 * @param filename Absolute file path
265 * @return Returns 0 if everything was okey.If there was a failure a value < 0 will be returned.
267 int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
273 unsigned long fsize = getFilesize(filename,&ok);
275 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_infoAbout, Error getting size of file:"),DLT_STRING(filename));
277 unsigned long fserialnumber = getFileSerialNumber(filename,&ok);
279 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_infoAbout, Error getting serial number of file:"),DLT_STRING(filename));
282 char *creationdate = getFileCreationDate2(filename,&ok);
284 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_infoAbout, Error getting creation date of file:"),DLT_STRING(filename));
286 DLT_LOG(*fileContext,DLT_LOG_INFO,
288 DLT_STRING("file serialnumber"),DLT_UINT(fserialnumber),
289 DLT_STRING("filename"),DLT_STRING(filename),
290 DLT_STRING("file size in bytes"),DLT_UINT(fsize),
291 DLT_STRING("file creation date"),DLT_STRING(creationdate),
292 DLT_STRING("number of packages"),DLT_UINT(dlt_user_log_file_packagesCount(fileContext, filename)),
297 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_INFO_ABOUT);
298 return DLT_FILETRANSFER_ERROR_INFO_ABOUT;
302 //!Transfer the complete file as several dlt logs.
303 /**This method transfer the complete file as several dlt logs. At first it will be checked that the file exist.
304 * In the next step some generic informations about the file will be logged to dlt.
305 * Now the header will be logged to dlt. See the method dlt_user_log_file_header for more informations.
306 * Then the method dlt_user_log_data will be called with the parameter to log all packages in a loop with some timeout.
307 * 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.
308 * @param fileContext Specific context to log the file to dlt
309 * @param filename Absolute file path
310 * @param deleteFlag Flag if the file will be deleted after transfer. 1->delete, 0->notDelete
311 * @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.
312 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
314 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
316 if(!isFile(filename))
318 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_COMPLETE);
319 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE;
322 if(dlt_user_log_file_header(fileContext,filename) != 0)
324 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE1;
327 if(dlt_user_log_file_data(fileContext, filename,DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES,timeout) != 0)
329 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE2;
332 if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
334 return DLT_FILETRANSFER_ERROR_FILE_COMPLETE3;
340 //!This method gives information about the number of packages the file have
341 /**Every file will be divided into several packages. Every package will be logged as a single dlt log.
342 * The number of packages depends on the BUFFER_SIZE.
343 * At first it will be checked if the file exist. Then the file will be divided into
344 * several packages depending on the buffer size.
345 * @param fileContext Specific context to log the file to dlt
346 * @param filename Absolute file path
347 * @return Returns the number of packages if everything was okey. If there was a failure a value < 0 will be returned.
349 int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filename){
357 filesize = getFilesize(filename,&ok);
359 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("Error in: dlt_user_log_file_packagesCount, isFile"),DLT_STRING(filename),DLT_INT(DLT_FILETRANSFER_ERROR_PACKAGE_COUNT));
362 if(filesize < BUFFER_SIZE)
368 packages = filesize/BUFFER_SIZE;
370 if(filesize%BUFFER_SIZE == 0)
380 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("Error in: dlt_user_log_file_packagesCount, !isFile"),DLT_STRING(filename),DLT_INT(DLT_FILETRANSFER_ERROR_PACKAGE_COUNT));
385 //!Transfer the head of the file as a dlt logs.
386 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
387 * the file name, the file size, package number the file have and the buffer size.
388 * All these informations are needed from the plugin of the dlt viewer.
389 * See the Mainpages.c for more informations.
390 * @param fileContext Specific context to log the file to dlt
391 * @param filename Absolute file path
392 * @param alias Alias for the file. An alternative name to show in the receiving end
393 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
395 int dlt_user_log_file_header_alias(DltContext *fileContext,const char *filename, const char *alias){
401 unsigned long fserialnumber = getFileSerialNumber(filename,&ok);
403 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_header_alias, Error getting serial number of file:"),DLT_STRING(filename));
405 unsigned long fsize = getFilesize(filename,&ok);
407 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_header_alias, Error getting size of file:"),DLT_STRING(filename));
409 char *fcreationdate = getFileCreationDate2(filename,&ok);
411 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_header_alias, Error getting creation date of file:"),DLT_STRING(filename));
415 DLT_LOG(*fileContext,DLT_LOG_INFO,
417 DLT_UINT(fserialnumber),
420 DLT_STRING(fcreationdate);
421 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
422 DLT_UINT(BUFFER_SIZE),
430 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
431 return DLT_FILETRANSFER_ERROR_FILE_HEAD;
435 //!Transfer the head of the file as a dlt logs.
436 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
437 * the file name, the file size, package number the file have and the buffer size.
438 * All these informations are needed from the plugin of the dlt viewer.
439 * See the Mainpages.c for more informations.
440 * @param fileContext Specific context to log the file to dlt
441 * @param filename Absolute file path
442 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
444 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
450 unsigned long fserialnumber = getFileSerialNumber(filename,&ok);
452 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_header, Error getting serial number of file:"),DLT_STRING(filename));
454 unsigned long fsize = getFilesize(filename,&ok);
456 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_header, Error getting size of file:"),DLT_STRING(filename));
458 char *fcreationdate = getFileCreationDate2(filename,&ok);
460 DLT_LOG(*fileContext,DLT_LOG_ERROR,DLT_STRING("dlt_user_log_file_header, Error getting creation date of file:"),DLT_STRING(filename));
465 DLT_LOG(*fileContext,DLT_LOG_INFO,
467 DLT_UINT(fserialnumber),
468 DLT_STRING(filename),
470 DLT_STRING(fcreationdate);
471 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
472 DLT_UINT(BUFFER_SIZE),
480 dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
481 return DLT_FILETRANSFER_ERROR_FILE_HEAD;
485 //!Transfer the content data of a file.
486 /**See the Mainpages.c for more informations.
487 * @param fileContext Specific context to log the file to dlt
488 * @param filename Absolute file path
489 * @param packageToTransfer Package number to transfer. If this param is LONG_MAX, the whole file will be transferred with a specific timeout
490 * @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.
491 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
493 int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int packageToTransfer, int timeout){
501 file = fopen (filename,"rb");
504 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
505 return DLT_FILETRANSFER_ERROR_FILE_DATA;
508 if( (packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
510 DLT_LOG(*fileContext,DLT_LOG_ERROR,
511 DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
512 DLT_STRING("packageToTransfer:"),
513 DLT_UINT(packageToTransfer),
514 DLT_STRING("numberOfMaximalPackages:"),
515 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
516 DLT_STRING("for File:"),
520 return DLT_FILETRANSFER_ERROR_FILE_DATA;
525 if(packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES)
527 // If a single package should be transferred. The user has to check that the free space in the user buffer > 50%
528 // if(checkUserBufferForFreeSpace()<0)
529 // return DLT_FILETRANSFER_ERROR_FILE_DATA_USER_BUFFER_FAILED;
531 if ( 0 != fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET ) )
533 DLT_LOG(*fileContext,DLT_LOG_ERROR,
534 DLT_STRING("failed to fseek in file: "),
535 DLT_STRING(filename),
536 DLT_STRING("ferror:"),
537 DLT_INT(ferror(file))
544 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
547 unsigned long fserial = getFileSerialNumber(filename,&ok);
551 DLT_LOG(*fileContext,DLT_LOG_ERROR,
552 DLT_STRING("failed to get FileSerialNumber for: "),
553 DLT_STRING(filename));
556 DLT_LOG(*fileContext,DLT_LOG_INFO,
559 DLT_UINT(packageToTransfer),
560 DLT_RAW(buffer,readBytes),
568 while( !feof( file ) )
570 // If the complete file should be transferred, the user buffer will be checked.
571 // If free space < 50% the package won't be transferred.
572 if(checkUserBufferForFreeSpace()>0)
575 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
578 unsigned long fserial = getFileSerialNumber(filename,&ok);
582 DLT_LOG(*fileContext,DLT_LOG_ERROR,
583 DLT_STRING("failed to get FileSerialNumber for: "),
584 DLT_STRING(filename));
587 DLT_LOG(*fileContext,DLT_LOG_INFO,
591 DLT_RAW(buffer,readBytes),
604 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
605 return DLT_FILETRANSFER_ERROR_FILE_DATA;
609 //!Transfer the end of the file as a dlt logs.
610 /**The end of the file must be logged to dlt because the end contains inforamtion about the file serial number.
611 * This informations is needed from the plugin of the dlt viewer.
612 * See the Mainpages.c for more informations.
613 * @param fileContext Specific context to log the file to dlt
614 * @param filename Absolute file path
615 * @param deleteFlag Flag to delete the file after the whole file is transferred (logged to dlt).1->delete,0->NotDelete
616 * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
618 int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int deleteFlag){
624 unsigned long fserial = getFileSerialNumber(filename,&ok);
628 DLT_LOG(*fileContext,DLT_LOG_ERROR,
629 DLT_STRING("failed to get FileSerialNumber for: "),
630 DLT_STRING(filename));
633 DLT_LOG(*fileContext,DLT_LOG_INFO,
640 if( doRemoveFile(filename) != 0 ){
641 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
648 dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
649 return DLT_FILETRANSFER_ERROR_FILE_END;