added creation date and a simple hash on the file name for to improve the uniqueness...
[profile/ivi/dlt-daemon.git] / src / lib / dlt_filetransfer.c
index 935573d..ce18f52 100644 (file)
@@ -1,3 +1,55 @@
+/**
+ * @licence app begin@
+ * Copyright (C) 2012  BMW AG
+ *
+ * This file is part of GENIVI Project Dlt - Diagnostic Log and Trace console apps.
+ *
+ * Contributions are licensed to the GENIVI Alliance under one or more
+ * Contribution License Agreements.
+ *
+ * \copyright
+ * This Source Code Form is subject to the terms of the
+ * Mozilla Public License, v. 2.0. If a  copy of the MPL was not distributed with
+ * this file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ *
+ * \author Alexander Wenzel <alexander.aw.wenzel@bmw.de> BMW 2011-2012
+ *
+ * \file dlt_filetransfer.c
+ * For further information see http://www.genivi.org/.
+ * @licence end@
+ */
+
+
+/*******************************************************************************
+**                                                                            **
+**  SRC-MODULE: dlt-test-client.c                                             **
+**                                                                            **
+**  TARGET    : linux                                                         **
+**                                                                            **
+**  PROJECT   : DLT                                                           **
+**                                                                            **
+**  AUTHOR    : Alexander Wenzel Alexander.AW.Wenzel@bmw.de                   **
+**                                                                            **
+**  PURPOSE   :                                                               **
+**                                                                            **
+**  REMARKS   :                                                               **
+**                                                                            **
+**  PLATFORM DEPENDANT [yes/no]: yes                                          **
+**                                                                            **
+**  TO BE CHANGED BY USER [yes/no]: no                                        **
+**                                                                            **
+*******************************************************************************/
+
+/*******************************************************************************
+**                      Author Identity                                       **
+********************************************************************************
+**                                                                            **
+** Initials     Name                       Company                            **
+** --------     -------------------------  ---------------------------------- **
+**  aw          Alexander Wenzel           BMW                                **
+*******************************************************************************/
+
 #include "dlt_filetransfer.h"
 
 //!Defines the buffer size of a single file package which will be logged to dlt
@@ -7,15 +59,7 @@
 #define MIN_TIMEOUT 20
 
 
-#define ERROR_FILE_COMPLETE -300
-#define ERROR_FILE_COMPLETE1 -301
-#define ERROR_FILE_COMPLETE2 -302
-#define ERROR_FILE_COMPLETE3 -303
-#define ERROR_FILE_HEAD -400
-#define ERROR_FILE_DATA -500
-#define ERROR_FILE_END -600
-#define ERROR_INFO_ABOUT -700
-#define ERROR_PACKAGE_COUNT -800
+#define DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES LONG_MAX
 
 
 //!Buffer for dlt file transfer. The size is defined by BUFFER_SIZE
@@ -33,6 +77,30 @@ unsigned long getFilesize(const char* file){
        return (unsigned long)st.st_size;
 }
 
+/** A simple Hash function for C-strings
+ * @param str input string. E.g. a file path.
+ * @param hash start and result value for hash computation
+ *
+ */
+void stringHash(const char* str, unsigned long *hash )
+{
+    if (!str || !hash)
+        return;
+   unsigned int len = strlen(str);
+
+   unsigned int i = 0;
+   if (len <= 0){
+    return;
+   }
+
+   for(i = 0; i < len;  i++)
+   {
+      *hash = 53 * *hash  + str[i];
+   }
+
+}
+
+
 //!Get some information about the file serial number of a file
 /** See stat(2) for more informations.
  * @param file Absolute file path
@@ -40,8 +108,14 @@ unsigned long getFilesize(const char* file){
  */
 unsigned long getFileSerialNumber(const char* file){
        struct stat st;
+       unsigned long ret;
        stat(file, &st);
-       return (unsigned long)st.st_ino;
+       ret = st.st_ino;
+       ret = ret << (sizeof(ret)*8)/2;
+       ret |= st.st_size;
+    ret ^= st.st_ctime;
+    stringHash(file, &ret);
+       return ret;
 }
 
 //!Returns the creation date of a file
@@ -54,31 +128,20 @@ time_t getFileCreationDate(const char* file){
        stat(file, &st);
        return st.st_ctime;
 }
+
+//!Returns the creation date of a file
+/** Format of the creation date is Day Mon dd hh:mm:ss yyyy
+ * @param file Absolute file path
+ * @return Returns the creation date of a file
+*/
 char* getFileCreationDate2(const char* file){
        struct stat st;
        stat(file, &st);
        
        struct tm  *ts= localtime(&st.st_ctime);
-       //char       buf[80];
-       /* Format and print the time, "ddd yyyy-mm-dd hh:mm:ss zzz" */
-       //strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", ts);
        return asctime(ts);
 }
 
-
-
-
-//void sighandler(int sig)
-//{
-//     
-//     fprintf(stderr, "Signal handler called with %d\n", sig);
-//     signal(sig, &sighandler);
-//     exit(1); 
-//     
-//}
-
-
-
 //!Checks if the file exists
 /**@param file Absolute file path
  * @return Returns 1 if the file exists, 0 if the file does not exist
@@ -91,28 +154,28 @@ int isFile (const char* file)
 
 //!Waits a period of time
 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
- * @param timeout Timeout to wait in seconds in ms but can not be smaller as MIN_TIMEOUT
+ * @param timeout Timeout to in ms but can not be smaller as MIN_TIMEOUT
  */
 void doTimeout(int timeout)
 {
+       usleep(timeout * 1000);
+}
+
+//!Checks free space of the user buffer
+/**
+ * @param returns -1 if more than 50% space in the user buffer is free. Otherwise 1 will be returned.
+ */
+int checkUserBufferForFreeSpace()
+{
        int total_size, used_size;
-       
+
        dlt_user_check_buffer(&total_size, &used_size);
-       
-       /* sleep only if more than 50% of buffer used */
+
        if((total_size - used_size) < (total_size/2))
        {
-               printf("Wait %d of %d already used\n",used_size,total_size);
-
-               if(timeout>MIN_TIMEOUT)
-               {       
-                       usleep(timeout * 1000);
-               }
-               else
-               {
-                       usleep(MIN_TIMEOUT * 1000);
-               }                               
+               return -1;
        }
+       return 1;
 }
 
 //!Deletes the given file
@@ -126,7 +189,7 @@ int doRemoveFile(const char*filename){
 
 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
 
-       if(-errno != -2)
+       if(errno != ENOENT)
        {
                DLT_LOG(*fileContext,DLT_LOG_ERROR,
                        DLT_STRING("FLER"),
@@ -174,9 +237,8 @@ int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
                );
                return 0;
        } else {
-       
-               dlt_user_log_file_errorMessage(fileContext,filename,ERROR_INFO_ABOUT);
-               return ERROR_INFO_ABOUT;
+               dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_INFO_ABOUT);
+               return DLT_FILETRANSFER_ERROR_INFO_ABOUT;
        }
 }
 
@@ -194,32 +256,25 @@ int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
  */
 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
 {      
-       //No signal handling in library - part of the main program!
-       //signal(SIGABRT, &sighandler);
-       //signal(SIGTERM, &sighandler);
-       //signal(SIGINT, &sighandler);
-
        if(!isFile(filename))
        {
-               dlt_user_log_file_errorMessage(fileContext,filename, ERROR_FILE_COMPLETE);
-               return ERROR_FILE_COMPLETE;
+               dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_COMPLETE);
+               return DLT_FILETRANSFER_ERROR_FILE_COMPLETE;
        }
        
-       //dlt_user_log_file_infoAbout(fileContext,filename);
-       
        if(dlt_user_log_file_header(fileContext,filename) != 0)
        {
-               return ERROR_FILE_COMPLETE1;
+               return DLT_FILETRANSFER_ERROR_FILE_COMPLETE1;
        }
                
-       if(dlt_user_log_file_data(fileContext, filename,LONG_MAX,timeout) != 0)
+       if(dlt_user_log_file_data(fileContext, filename,DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES,timeout) != 0)
        {
-               return ERROR_FILE_COMPLETE2;
+               return DLT_FILETRANSFER_ERROR_FILE_COMPLETE2;
        }
                
        if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
        {
-               return ERROR_FILE_COMPLETE3;
+               return DLT_FILETRANSFER_ERROR_FILE_COMPLETE3;
        }               
                        
        return 0;
@@ -260,7 +315,7 @@ int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filenam
                        }
                }
        } else {
-               dlt_user_log_file_errorMessage(fileContext,filename,ERROR_PACKAGE_COUNT);
+               dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_PACKAGE_COUNT);
                return -1;
        }
 }
@@ -272,6 +327,40 @@ int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filenam
  * See the Mainpages.c for more informations.
  * @param fileContext Specific context to log the file to dlt
  * @param filename Absolute file path
+ * @param alias Alias for the file. An alternative name to show in the receiving end
+ * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
+ */
+int dlt_user_log_file_header_alias(DltContext *fileContext,const char *filename, const char *alias){
+
+       if(isFile(filename))
+       {
+               DLT_LOG(*fileContext,DLT_LOG_INFO,
+                                       DLT_STRING("FLST"),
+                                       DLT_UINT(getFileSerialNumber(filename)),
+                                       DLT_STRING(alias),
+                                       DLT_UINT(getFilesize(filename)),
+                                       DLT_STRING(getFileCreationDate2(filename));
+                                       DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
+                                       DLT_UINT(BUFFER_SIZE),
+                                       DLT_STRING("FLST")
+                               );
+
+               return 0;
+       }
+       else
+       {
+               dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
+               return DLT_FILETRANSFER_ERROR_FILE_HEAD;
+       }
+}
+
+//!Transfer the head of the file as a dlt logs.
+/**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
+ * the file name, the file size, package number the file have and the buffer size.
+ * All these informations are needed from the plugin of the dlt viewer.
+ * See the Mainpages.c for more informations.
+ * @param fileContext Specific context to log the file to dlt
+ * @param filename Absolute file path
  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
  */
 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
@@ -293,8 +382,8 @@ int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
        }
        else
        {
-               dlt_user_log_file_errorMessage(fileContext,filename, ERROR_FILE_HEAD);
-               return ERROR_FILE_HEAD;
+               dlt_user_log_file_errorMessage(fileContext,filename, DLT_FILETRANSFER_ERROR_FILE_HEAD);
+               return DLT_FILETRANSFER_ERROR_FILE_HEAD;
        }
 }
 
@@ -317,11 +406,11 @@ int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int pac
                file = fopen (filename,"rb");
                if (file == NULL)
                {
-                       dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_DATA);
-                       return ERROR_FILE_DATA;
+                       dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
+                       return DLT_FILETRANSFER_ERROR_FILE_DATA;
                }
                
-               if( (packageToTransfer != LONG_MAX && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
+               if( (packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
                {
                        DLT_LOG(*fileContext,DLT_LOG_ERROR,
                                DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
@@ -332,42 +421,51 @@ int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int pac
                                DLT_STRING("for File:"),
                                DLT_STRING(filename)
                        );
-                       return ERROR_FILE_DATA;
+                       fclose(file);
+                       return DLT_FILETRANSFER_ERROR_FILE_DATA;
                }
 
                readBytes = 0;
                
-               if(packageToTransfer != LONG_MAX)
+               if(packageToTransfer != DLT_FILETRANSFER_TRANSFER_ALL_PACKAGES)
                {
+//                             If a single package should be transferred. The user has to check that the free space in the user buffer > 50%
+//                             if(checkUserBufferForFreeSpace()<0)
+//                                     return DLT_FILETRANSFER_ERROR_FILE_DATA_USER_BUFFER_FAILED;
+
                                fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET );
                                readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
-                               
+
                                DLT_LOG(*fileContext,DLT_LOG_INFO,
-                                       DLT_STRING("FLDA"),
-                                       DLT_UINT(getFileSerialNumber(filename)),
-                                       DLT_UINT(packageToTransfer),
-                                       DLT_RAW(buffer,readBytes),
-                                       DLT_STRING("FLDA")      
+                               DLT_STRING("FLDA"),
+                               DLT_UINT(getFileSerialNumber(filename)),
+                               DLT_UINT(packageToTransfer),
+                               DLT_RAW(buffer,readBytes),
+                               DLT_STRING("FLDA")
                                );
-                               
+
                                doTimeout(timeout);
-                                       
+
                } else {
                        pkgNumber = 0;
                        while( !feof( file ) )
                        {
-                               pkgNumber++;
-                               readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);     
-                               
-                               DLT_LOG(*fileContext,DLT_LOG_INFO,
-                                       DLT_STRING("FLDA"),
-                                       DLT_UINT(getFileSerialNumber(filename)),
-                                       DLT_UINT(pkgNumber),
-                                       DLT_RAW(buffer,readBytes),
-                                       DLT_STRING("FLDA")              
-                               );
+//                             If the complete file should be transferred, the user buffer will be checked.
+//                             If free space < 50% the package won't be transferred.
+                               if(checkUserBufferForFreeSpace()>0)
+                               {
+                                       pkgNumber++;
+                                       readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
                                
-                               doTimeout(timeout); 
+                                       DLT_LOG(*fileContext,DLT_LOG_INFO,
+                                                       DLT_STRING("FLDA"),
+                                                       DLT_UINT(getFileSerialNumber(filename)),
+                                                       DLT_UINT(pkgNumber),
+                                                       DLT_RAW(buffer,readBytes),
+                                                       DLT_STRING("FLDA")
+                                       );
+                               }
+                               doTimeout(timeout);
                        }
                }
                
@@ -376,8 +474,8 @@ int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int pac
                return 0;
                
        } else {
-               dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_DATA);
-               return ERROR_FILE_DATA;
+               dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_DATA);
+               return DLT_FILETRANSFER_ERROR_FILE_DATA;
        }
        
 }
@@ -403,14 +501,14 @@ int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int delet
                
                if(deleteFlag){
                                if( doRemoveFile(filename) != 0 ){
-                                       dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_END);
+                                       dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
                                        return -1;
                                }
                }
        
                return 0;
        }else{
-               dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_END);
-               return ERROR_FILE_END;
+               dlt_user_log_file_errorMessage(fileContext,filename,DLT_FILETRANSFER_ERROR_FILE_END);
+               return DLT_FILETRANSFER_ERROR_FILE_END;
        }
 }