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