Updated filetransfer documentation, lib and test application
[profile/ivi/dlt-daemon.git] / src / lib / dlt_filetransfer.c
1 #include "dlt_filetransfer.h"
2
3 //!Defines the buffer size of a single file package which will be logged to dlt
4 #define BUFFER_SIZE 1024
5
6 //!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.
7 #define MIN_TIMEOUT 20
8
9 //! Error code for dlt_user_log_file_complete
10 #define ERROR_FILE_COMPLETE -300
11 //! Error code for dlt_user_log_file_complete
12 #define ERROR_FILE_COMPLETE1 -301
13 //! Error code for dlt_user_log_file_complete
14 #define ERROR_FILE_COMPLETE2 -302
15 //! Error code for dlt_user_log_file_complete
16 #define ERROR_FILE_COMPLETE3 -303
17 //! Error code for dlt_user_log_file_head
18 #define ERROR_FILE_HEAD -400
19 //! Error code for dlt_user_log_file_data
20 #define ERROR_FILE_DATA -500
21 //! Error code for dlt_user_log_file_end
22 #define ERROR_FILE_END -600
23 //! Error code for dlt_user_log_file_infoAbout
24 #define ERROR_INFO_ABOUT -700
25 //! Error code for dlt_user_log_file_packagesCount
26 #define ERROR_PACKAGE_COUNT -800
27
28
29 //!Buffer for dlt file transfer. The size is defined by BUFFER_SIZE
30 unsigned char buffer[BUFFER_SIZE];
31
32
33 //!Get some information about the file size of a file
34 /**See stat(2) for more informations.
35  * @param file Absolute file path
36  * @return Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
37  */
38 unsigned long getFilesize(const char* file){
39         struct stat st;
40         stat(file, &st);
41         return (unsigned long)st.st_size;
42 }
43
44 //!Get some information about the file serial number of a file
45 /** See stat(2) for more informations.
46  * @param file Absolute file path
47  * @return Returns a unique number associated with each filename
48  */
49 unsigned long getFileSerialNumber(const char* file){
50         struct stat st;
51         stat(file, &st);
52         return (unsigned long)st.st_ino;
53 }
54
55 //!Returns the creation date of a file
56 /** See stat(2) for more informations.
57  * @param file Absolute file path
58  * @return Returns the creation date of a file
59 */
60 time_t getFileCreationDate(const char* file){
61         struct stat st;
62         stat(file, &st);
63         return st.st_ctime;
64 }
65
66 //!Returns the creation date of a file
67 /** Format of the creation date is Day Mon dd hh:mm:ss yyyy
68  * @param file Absolute file path
69  * @return Returns the creation date of a file
70 */
71 char* getFileCreationDate2(const char* file){
72         struct stat st;
73         stat(file, &st);
74         
75         struct tm  *ts= localtime(&st.st_ctime);
76         return asctime(ts);
77 }
78
79 //!Checks if the file exists
80 /**@param file Absolute file path
81  * @return Returns 1 if the file exists, 0 if the file does not exist
82  */
83 int isFile (const char* file)
84 {
85         struct stat   st;   
86         return (stat (file, &st) == 0);
87 }
88
89 //!Waits a period of time
90 /**Waits a period of time. The minimal time to wait is MIN_TIMEOUT. This makes sure that the FIFO of dlt is not flooded.
91  * @param timeout Timeout to wait in seconds in ms but can not be smaller as MIN_TIMEOUT
92  */
93 void doTimeout(int timeout)
94 {
95         int total_size, used_size;
96         
97         dlt_user_check_buffer(&total_size, &used_size);
98         
99         /* sleep only if more than 50% of buffer used */
100         if((total_size - used_size) < (total_size/2))
101         {
102                 printf("Wait %d of %d already used\n",used_size,total_size);
103
104                 if(timeout>MIN_TIMEOUT)
105                 {       
106                         usleep(timeout * 1000);
107                 }
108                 else
109                 {
110                         usleep(MIN_TIMEOUT * 1000);
111                 }                               
112         }
113 }
114
115 //!Deletes the given file
116 /**
117  * @param filename Absolute file path
118  * @return If the file is successfully deleted, a zero value is returned.If the file can not be deleted a nonzero value is returned.
119  */
120 int doRemoveFile(const char*filename){
121         return remove( filename); 
122 }
123
124 void dlt_user_log_file_errorMessage(DltContext *fileContext, const char *filename, int errorCode){
125
126         if(errno != ENOENT)
127         {
128                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
129                         DLT_STRING("FLER"),
130                         DLT_INT(errorCode),
131                         DLT_INT(-errno),
132                         DLT_UINT(getFileSerialNumber(filename)),
133                         DLT_STRING(filename),
134                         DLT_UINT(getFilesize(filename)),
135                         DLT_STRING(getFileCreationDate2(filename)),
136                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
137                         DLT_UINT(BUFFER_SIZE),
138                         DLT_STRING("FLER")
139                 );              
140         } else {
141                 DLT_LOG(*fileContext,DLT_LOG_ERROR,
142                         DLT_STRING("FLER"),
143                         DLT_INT(errorCode),
144                         DLT_INT(-errno),
145                         DLT_STRING(filename),
146                         DLT_STRING("FLER")
147                 );
148         }
149 }
150
151
152
153 //!Logs specific file inforamtions to dlt
154 /**The filename, file size, file serial number and the number of packages will be logged to dlt.
155  * @param fileContext Specific context
156  * @param filename Absolute file path
157  * @return Returns 0 if everything was okey.If there was a failure a value < 0 will be returned.
158  */
159 int dlt_user_log_file_infoAbout(DltContext *fileContext, const char *filename){
160         
161         if(isFile(filename))
162         {
163                 DLT_LOG(*fileContext,DLT_LOG_INFO,
164                         DLT_STRING("FLIF"),
165                         DLT_STRING("file serialnumber"),DLT_UINT(getFileSerialNumber(filename)),
166                         DLT_STRING("filename"),DLT_STRING(filename),
167                         DLT_STRING("file size in bytes"),DLT_UINT(getFilesize(filename)),
168                         DLT_STRING("file creation date"),DLT_STRING(getFileCreationDate2(filename)),
169                         DLT_STRING("number of packages"),DLT_UINT(dlt_user_log_file_packagesCount(fileContext, filename)),
170                         DLT_STRING("FLIF")
171                 );
172                 return 0;
173         } else {
174                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_INFO_ABOUT);
175                 return ERROR_INFO_ABOUT;
176         }
177 }
178
179 //!Transfer the complete file as several dlt logs.
180 /**This method transfer the complete file as several dlt logs. At first it will be checked that the file exist.
181  * In the next step some generic informations about the file will be logged to dlt.
182  * Now the header will be logged to dlt. See the method dlt_user_log_file_header for more informations.
183  * Then the method dlt_user_log_data will be called with the parameter to log all packages in a loop with some timeout.
184  * 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. 
185  * @param fileContext Specific context to log the file to dlt
186  * @param filename Absolute file path
187  * @param deleteFlag Flag if the file will be deleted after transfer. 1->delete, 0->notDelete
188  * @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.
189  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
190  */
191 int dlt_user_log_file_complete(DltContext *fileContext, const char *filename, int deleteFlag, int timeout)
192 {       
193         if(!isFile(filename))
194         {
195                 dlt_user_log_file_errorMessage(fileContext,filename, ERROR_FILE_COMPLETE);
196                 return ERROR_FILE_COMPLETE;
197         }
198         
199         if(dlt_user_log_file_header(fileContext,filename) != 0)
200         {
201                 return ERROR_FILE_COMPLETE1;
202         }
203                 
204         if(dlt_user_log_file_data(fileContext, filename,LONG_MAX,timeout) != 0)
205         {
206                 return ERROR_FILE_COMPLETE2;
207         }
208                 
209         if(dlt_user_log_file_end(fileContext,filename, deleteFlag) != 0)
210         {
211                 return ERROR_FILE_COMPLETE3;
212         }               
213                         
214         return 0;
215 }
216
217 //!This method gives information about the number of packages the file have
218 /**Every file will be divided into several packages. Every package will be logged as a single dlt log.
219  * The number of packages depends on the BUFFER_SIZE.
220  * At first it will be checked if the file exist. Then the file will be divided into
221  * several packages depending on the buffer size.
222  * @param fileContext Specific context to log the file to dlt
223  * @param filename Absolute file path
224  * @return Returns the number of packages if everything was okey. If there was a failure a value < 0 will be returned.
225  */
226 int dlt_user_log_file_packagesCount(DltContext *fileContext, const char *filename){
227         int packages;
228         long filesize;
229         
230         if(isFile(filename))
231         {
232                 packages = 1;
233                 filesize = getFilesize(filename);
234                 if(filesize < BUFFER_SIZE)
235                 {       
236                         return packages;
237                 } 
238                 else 
239                 {
240                         packages = filesize/BUFFER_SIZE;
241                         
242                         if(filesize%BUFFER_SIZE == 0)
243                         {       
244                                 return packages;
245                         }
246                         else
247                         {
248                                 return packages+1;
249                         }
250                 }
251         } else {
252                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_PACKAGE_COUNT);
253                 return -1;
254         }
255 }
256
257 //!Transfer the head of the file as a dlt logs.
258 /**The head of the file must be logged to dlt because the head contains inforamtion about the file serial number,
259  * the file name, the file size, package number the file have and the buffer size.
260  * All these informations are needed from the plugin of the dlt viewer.
261  * See the Mainpages.c for more informations.
262  * @param fileContext Specific context to log the file to dlt
263  * @param filename Absolute file path
264  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
265  */
266 int dlt_user_log_file_header(DltContext *fileContext,const char *filename){
267
268         if(isFile(filename))
269         {
270                 DLT_LOG(*fileContext,DLT_LOG_INFO,
271                                         DLT_STRING("FLST"),
272                                         DLT_UINT(getFileSerialNumber(filename)),
273                                         DLT_STRING(filename),
274                                         DLT_UINT(getFilesize(filename)),
275                                         DLT_STRING(getFileCreationDate2(filename));
276                                         DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
277                                         DLT_UINT(BUFFER_SIZE),
278                                         DLT_STRING("FLST")              
279                                 );
280
281                 return 0;
282         }
283         else
284         {
285                 dlt_user_log_file_errorMessage(fileContext,filename, ERROR_FILE_HEAD);
286                 return ERROR_FILE_HEAD;
287         }
288 }
289
290 //!Transfer the content data of a file.
291 /**See the Mainpages.c for more informations.
292  * @param fileContext Specific context to log the file to dlt
293  * @param filename Absolute file path
294  * @param packageToTransfer Package number to transfer. If this param is LONG_MAX, the whole file will be transferred with a specific timeout
295  * @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.
296  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
297  */
298 int dlt_user_log_file_data(DltContext *fileContext,const char *filename, int packageToTransfer, int timeout){
299         FILE *file;
300         int pkgNumber;
301         long readBytes;
302                 
303         if(isFile(filename))
304         {
305         
306                 file = fopen (filename,"rb");
307                 if (file == NULL)
308                 {
309                         dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_DATA);
310                         return ERROR_FILE_DATA;
311                 }
312                 
313                 if( (packageToTransfer != LONG_MAX && packageToTransfer > dlt_user_log_file_packagesCount(fileContext,filename)) || packageToTransfer <= 0)
314                 {
315                         DLT_LOG(*fileContext,DLT_LOG_ERROR,
316                                 DLT_STRING("Error at dlt_user_log_file_data: packageToTransfer out of scope"),
317                                 DLT_STRING("packageToTransfer:"),
318                                 DLT_UINT(packageToTransfer),
319                                 DLT_STRING("numberOfMaximalPackages:"),
320                                 DLT_UINT(dlt_user_log_file_packagesCount(fileContext,filename)),
321                                 DLT_STRING("for File:"),
322                                 DLT_STRING(filename)
323                         );
324                         return ERROR_FILE_DATA;
325                 }
326
327                 readBytes = 0;
328                 
329                 if(packageToTransfer != LONG_MAX)
330                 {
331                                 fseek ( file , (packageToTransfer-1)*BUFFER_SIZE , SEEK_SET );
332                                 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);
333                                 
334                                 DLT_LOG(*fileContext,DLT_LOG_INFO,
335                                         DLT_STRING("FLDA"),
336                                         DLT_UINT(getFileSerialNumber(filename)),
337                                         DLT_UINT(packageToTransfer),
338                                         DLT_RAW(buffer,readBytes),
339                                         DLT_STRING("FLDA")      
340                                 );
341                                 
342                                 //doTimeout(timeout);
343                                         
344                 } else {
345                         pkgNumber = 0;
346                         while( !feof( file ) )
347                         {
348                                 pkgNumber++;
349                                 readBytes = fread(buffer, sizeof(char), BUFFER_SIZE, file);     
350                                 
351                                 DLT_LOG(*fileContext,DLT_LOG_INFO,
352                                         DLT_STRING("FLDA"),
353                                         DLT_UINT(getFileSerialNumber(filename)),
354                                         DLT_UINT(pkgNumber),
355                                         DLT_RAW(buffer,readBytes),
356                                         DLT_STRING("FLDA")              
357                                 );
358                                 
359                                 //doTimeout(timeout); 
360                         }
361                 }
362                 
363                 fclose(file);
364                 
365                 return 0;
366                 
367         } else {
368                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_DATA);
369                 return ERROR_FILE_DATA;
370         }
371         
372 }
373 //!Transfer the end of the file as a dlt logs.
374 /**The end of the file must be logged to dlt because the end contains inforamtion about the file serial number.
375  * This informations is needed from the plugin of the dlt viewer.
376  * See the Mainpages.c for more informations.
377  * @param fileContext Specific context to log the file to dlt
378  * @param filename Absolute file path
379  * @param deleteFlag Flag to delete the file after the whole file is transferred (logged to dlt).1->delete,0->NotDelete
380  * @return Returns 0 if everything was okey. If there was a failure a value < 0 will be returned.
381  */
382 int dlt_user_log_file_end(DltContext *fileContext,const char *filename,int deleteFlag){
383
384         if(isFile(filename))
385         {
386
387                 DLT_LOG(*fileContext,DLT_LOG_INFO,
388                                 DLT_STRING("FLFI"),
389                                 DLT_UINT(getFileSerialNumber(filename)),
390                                 DLT_STRING("FLFI")
391                 );
392                 
393                 if(deleteFlag){
394                                 if( doRemoveFile(filename) != 0 ){
395                                         dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_END);
396                                         return -1;
397                                 }
398                 }
399         
400                 return 0;
401         }else{
402                 dlt_user_log_file_errorMessage(fileContext,filename,ERROR_FILE_END);
403                 return ERROR_FILE_END;
404         }
405 }