Add multi-user support
[apps/core/preloaded/print-service.git] / libptdb / ptdb.c
1 /*
2 *       Printservice
3 *
4 * Copyright 2013  Samsung Electronics Co., Ltd
5
6 * Licensed under the Flora License, Version 1.1 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9
10 * http://floralicense.org/license/
11
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <alloca.h>
23 #include <libgen.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <pt_debug.h>
27
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <errno.h>
33 #include <stdbool.h>
34
35 #include <pt_db.h>
36
37 #define TEMPLATE "/tmp/mobileprint/printXXXXXX"
38 #define FILE_NAME "printXXXXXX"
39 #define FILE_BASE_DIR "mobileprint/"
40 #define MASK_MODE 022
41 #define BUFF_SIZE 512
42 #define STR_PAR "Invalid parameters: "
43 #define STR_PTR "Invalid pointers: "
44
45 enum {
46         PIPE_READ = 0,
47         PIPE_WRITE = 1
48 };
49
50 typedef enum {
51         PT_MODELNAME = 0,
52         PT_PRODUCTNAME
53 } pt_search_key;
54
55 typedef enum {
56         PT_FILE_TMP = 0
57 } pt_file_type;
58
59 typedef enum {
60         PT_FREE_FILE_CLOSE = 0, /** Close file descriptor and free memory\
61                                                                 allocated for structure */
62         PT_FREE_FILE_DEL                /** The same as PT_FREE_FILE_CLOSE, plus delete file\
63                                                                 from file-system */
64 } pt_free_file_type;
65
66 typedef struct {
67         uint32_t *buffer;
68         uint32_t len;
69 } info;
70
71 typedef struct {
72         uint32_t *buffer;
73         uint32_t len;
74 } prod;
75
76 typedef struct {
77         uint32_t name;
78         prod product;
79         info inform;
80 } model;
81
82 typedef struct {
83         char *value;
84         char *modified;
85 } outstr;
86
87 typedef struct {
88         pt_file_type file_type;
89         char *file_dir;
90         char *file_name;
91 } pt_file_info;
92
93 typedef struct {
94         FILE *ptfile;
95         const char *ptpath;
96 } pt_file;
97
98 /* Create file */
99 static pt_file *pt_create_file(pt_file_info *file_info);
100
101 /* Set information of file */
102 static pt_file_info *pt_create_file_info(char *name, char *dir, pt_file_type type);
103
104 /* Synchronize a file's in-core state with storage device. */
105 static int pt_sync_file(pt_file *file);
106
107 /* Execute ppdc command with predefined set of parameters */
108 static char *pt_exec_ppdc(pt_file *file);
109
110 /* Read and parse drv file */
111 /* Return parsed structure */
112 static drvm *read_drv(FILE *FD);
113
114 static pt_dbconfig *pt_tune_db(FILE *file, const char *path);
115
116 /* Extract specific drv file from database by modelname */
117 static pt_file *extract_drv_by_model(drvm drv, const char *modelname);
118
119 /* Extract specific drv file from database by product */
120 static pt_file *extract_drv_by_product(drvm drv, const char *product);
121
122 /* Extract specific drv file from database by specified key */
123 static pt_file *extract_drv_by_key(drvm drv, const char *key, pt_search_key type);
124
125 /* Read and parse drv file */
126 /* Return model structure */
127 static model *read_model(FILE* FD);
128
129 /* Extract value of search key accordingly    */
130 /* specification of drv file */
131 static char *filter(char *string, pt_search_key key);
132
133 /* Return value of a string, deleting quotes */
134 static outstr *filter_string(const char *original);
135
136 /* Extraction value of Product */
137 /* accordingly specification of drv file */
138 static char *filter_product(char *original, pt_search_key key);
139
140 /* Read all data from file/pipe */
141 static char *reliable_read(int fd);
142
143 /* Get size of file in bytes */
144 static int get_file_size(const char *path);
145
146 static void pt_free_dbconfig(pt_dbconfig *dbconfig);
147
148 static void pt_free_config(pt_dbconfig *config);
149
150 /* Free memory allocated by drvm structure */
151 static void pt_free_drvm(drvm *drv);
152
153 /* Clean resources linked with file */
154 static int pt_free_file(pt_file *file, pt_free_file_type free_type);
155
156 /* Free memory allocated by pt_file_info structure */
157 static void pt_free_file_info(pt_file_info *file_info);
158
159 /* Free memory allocated by prod structure */
160 static void pt_free_prod(prod *product);
161
162 /* Free memory allocated by string */
163 static void pt_free_strings(gpointer data);
164
165 /* Free memory allocated by model structure */
166 static void pt_free_model(gpointer data);
167
168 /* Free memory allocated by info structure */
169 static void pt_free_info(info *inf);
170
171 /* Clean memory of allocated outstr structure */
172 static void clean_outstr(outstr *ostr);
173
174 int get_file_size(const char *path)
175 {
176         struct stat statbuff;
177         if(stat(path, &statbuff)) {
178                 return -1;
179         }
180         return statbuff.st_size;
181 }
182
183 void pt_free_file_info(pt_file_info *file_info)
184 {
185         if(file_info) {
186                 if(file_info->file_dir) {
187                         free(file_info->file_dir);
188                 }
189
190                 if(file_info->file_name) {
191                         free(file_info->file_name);
192                 }
193
194                 free(file_info);
195         }
196 }
197
198 pt_file_info *pt_create_file_info(char *name, char *dir, pt_file_type type)
199 {
200         pt_file_info *info = (pt_file_info*)malloc(sizeof(pt_file_info));
201         if(!info) {
202                 return NULL;
203         }
204         memset(info, '\0', sizeof(pt_file_info));
205         char *tmp_name = NULL;
206         if(name) {
207                 tmp_name = strdup(name);
208                 if(!tmp_name) {
209                         PT_ERROR("String duplicating fails");
210                         pt_free_file_info(info);
211                         return NULL;
212                 }
213                 info->file_name = tmp_name;
214         } else {
215                 info->file_name = NULL;
216         }
217
218         char *tmp_dir = NULL;
219         if(dir) {
220                 tmp_dir = strdup(dir);
221                 if(!tmp_dir) {
222                         PT_ERROR("String duplicating fails");
223                         pt_free_file_info(info);
224                         free(tmp_name);
225                         return NULL;
226                 }
227                 info->file_dir = tmp_dir;
228         } else {
229                 info->file_dir = NULL;
230         }
231
232         info->file_type = type;
233         return info;
234 }
235
236 int pt_sync_file(pt_file *file)
237 {
238         if(!file) {
239                 return -1;
240         }
241
242         if(!file->ptfile) {
243                 return -1;
244         }
245
246         int res = fflush(file->ptfile);
247         return res;
248 }
249
250 int pt_free_file(pt_file *file, pt_free_file_type free_type)
251 {
252         if(!file) {
253                 return -1;
254         }
255         if(!file->ptpath) {
256                 return -1;
257         }
258         if(!file->ptfile) {
259                 return -1;
260         }
261
262         if(free_type == PT_FREE_FILE_CLOSE) {
263                 if(fclose(file->ptfile)) {
264                         return -1;
265                 }
266                 free((void *)file->ptpath);
267                 free(file);
268         } else if(free_type == PT_FREE_FILE_DEL) {
269                 if(fclose(file->ptfile)) {
270                         return -1;
271                 }
272                 if(unlink(file->ptpath)) {
273                         return -1;
274                 }
275                 free((void *)file->ptpath);
276                 free(file);
277         }
278         return 0;
279 }
280
281 pt_file *pt_create_file(pt_file_info *file_info)
282 {
283         FILE *fd = NULL;
284         char *file = NULL;
285
286         if(!file_info) {
287                 return NULL;
288         }
289
290         if(file_info->file_type == PT_FILE_TMP) {
291                 char *string = strdup(TEMPLATE);
292                 if(!string) {
293                         PT_ERROR("Can't duplicate string with strdup()");
294                         return NULL;
295                 }
296
297                 char *drname = dirname(string);
298                 if(g_mkdir_with_parents(drname, S_IRWXU | S_IRWXG) == -1) {
299                         PT_ERROR("Can't create nested directory path");
300                         PT_IF_FREE_MEM(string);
301                         return NULL;
302                 }
303                 PT_IF_FREE_MEM(string);
304
305                 file = strdup(TEMPLATE);
306                 if (!file) {
307                         PT_ERROR("Can't duplicate string with strdup()");
308                         return NULL;
309                 }
310
311                 umask(MASK_MODE);
312                 int filedesc = mkstemp(file);
313                 if (filedesc == -1) {
314                         PT_ERROR("Can't create temp file");
315                         PT_IF_FREE_MEM(file);
316                         return NULL;
317                 }
318
319                 fd = fdopen(filedesc, "w");
320                 if(!fd) {
321                         PT_ERROR("Call fdopen() failed");
322                         if(close(filedesc)) {
323                                 PT_ERROR("Closing file descriptor fails");
324                         }
325                         int rst = unlink(file);
326                         if(rst) {
327                                 PT_ERROR("Unlink temporary file fails");
328                         }
329                         PT_IF_FREE_MEM(file);
330                         return NULL;
331                 }
332
333         } else {
334                 PT_ERROR("pt_create_file: Not yet fully supported");
335                 return NULL;
336         }
337
338         pt_file *ptfile = (pt_file *)malloc(sizeof(pt_file));
339         if(!ptfile) {
340                 PT_ERROR("Allocating memory fails");
341                 if(fclose(fd)) {
342                         PT_ERROR("File error: %s", strerror(errno));
343                 }
344                 PT_IF_FREE_MEM(file);
345                 return NULL;
346         }
347         memset(ptfile, '\0', sizeof(pt_file));
348
349         ptfile->ptfile = fd;
350         ptfile->ptpath = file;
351         return ptfile;
352 }
353
354 char *reliable_read(int fd)
355 {
356         char *new_buffer;
357         char *buffer = malloc(BUFF_SIZE);
358         if (!buffer) {
359                 PT_ERROR("call malloc() failed: %s", strerror(errno));
360                 return NULL;
361         }
362         memset(buffer, '\0', BUFF_SIZE);
363
364         new_buffer = buffer;
365         ssize_t rst = 0;
366         ssize_t global = 0;
367         size_t count = BUFF_SIZE;
368         size_t new_size = count;
369         while((rst = read(fd, buffer, count)) != -1) {
370                 if(rst > 0) {
371                         global += rst;
372                         count -= rst;
373                         continue;
374                 } else if(rst == 0) {
375                         if (global == new_size) {
376                                 // we didn't read all data
377                                 new_size = BUFF_SIZE + BUFF_SIZE;
378                                 if (!(new_buffer = malloc(new_size))) {
379                                         free(buffer);
380                                         return NULL;
381                                 }
382                                 memset(new_buffer, '\0', new_size);
383                                 strncpy(new_buffer, buffer, BUFF_SIZE);
384                                 free(buffer);
385                                 buffer = new_buffer;
386                         }
387                         break;
388                 }
389         }
390         return buffer;
391 }
392
393 char *pt_exec_ppdc(pt_file *file)
394 {
395         int pipefd[2];
396         char *buffer = NULL;
397
398         if(!file) {
399                 return NULL;
400         }
401
402         if (pipe(pipefd))
403         {
404                 PT_ERROR("pipe fail");
405                 return NULL;
406         }
407
408         pid_t pid;
409         if((pid = fork()) < 0) {
410                 PT_ERROR("Forking process fail");
411                 return NULL;
412         } else if (pid == 0) {
413
414                         if (dup2(pipefd[PIPE_READ], STDIN_FILENO) == -1) {
415                                 return NULL;
416                         }
417
418                         if (dup2(pipefd[PIPE_WRITE], STDOUT_FILENO) == -1) {
419                                 return NULL;
420                         }
421
422                         if (dup2(pipefd[PIPE_WRITE], STDERR_FILENO) == -1) {
423                                 return NULL;
424                         }
425
426                         if(close(pipefd[PIPE_READ])) {
427                                 return NULL;
428                         }
429
430                         // First we remove all locale variables
431                         if(unsetenv("LANG") || unsetenv("LANGUAGE") || unsetenv("LC_ALL")) {
432                                 PT_ERROR("Unsetting locale variables fails");
433                                 return NULL;
434                         }
435
436                         if(!setenv("LC_ALL", "POSIX", true)) {
437                                 PT_INFO("Successfully adjust environment for ppdc");
438                         } else {
439                                 PT_ERROR("Adjust environment for ppdc fails");
440                                 return NULL;
441                         }
442
443                         if (execl("/usr/bin/ppdc", "ppdc", "-v",\
444                                 "-d", ".", file->ptpath, (const char*) NULL)) {
445
446                                 if (execl("/bin/ppdc", "ppdc", "-v",\
447                                         "-d", ".", file->ptpath, (const char*) NULL)) {
448
449                                         PT_ERROR("Executing process fail");
450                                         return NULL;
451                                 }
452                         }
453                         PT_ERROR("Executing process fail");
454                         return NULL;
455         }
456
457         close(pipefd[PIPE_WRITE]);
458
459         int status;
460         pid_t child = wait(&status);
461         if (child != pid) {
462                 return NULL;
463         }
464
465         if(WIFEXITED(status)) {
466                 if (WEXITSTATUS(status) != 0) {
467                         return NULL;
468                 } else {
469                         buffer = reliable_read(pipefd[PIPE_READ]);
470                 }
471         } else {
472                 return NULL;
473         }
474
475         return buffer;
476 }
477
478 pt_file *extract_drv_by_key(drvm drv, const char *key, pt_search_key type)
479 {
480         pt_file *file = NULL;
481         GPtrArray *strings = drv.strings;
482         GPtrArray *models = drv.models;
483
484         guint len = models->len;
485
486         char *name;
487         model *mod;
488         for (int i = 0; i < len; ++i) {
489                 bool correct = false;
490                 mod = g_ptr_array_index(models, i);
491                 if (type == PT_MODELNAME) {
492                         name = g_ptr_array_index(strings, mod->name);
493                         name = filter(name, PT_MODELNAME);
494                         if(name) {
495                                 if(!strcasecmp(key, name)) {
496                                         free(name);
497                                         correct = true;
498                                 } else {
499                                         free(name);
500                                         continue;
501                                 }
502                         } else {
503                                 continue;
504                         }
505                 } else if (type == PT_PRODUCTNAME) {
506                         uint32_t value;
507                         uint32_t prod_len  = (mod->product).len;
508                         int *counter = (mod->product).buffer;
509                         for (int k = 0; k < prod_len; ++k) {
510                                 value = *counter++;
511                                 name = g_ptr_array_index(strings, value);
512                                 name = filter_product(name, PT_PRODUCTNAME);
513                                 if (!name) {
514                                         continue;
515                                 }
516
517                                 if (strcasecmp(key, name)) {
518                                         free(name);
519                                         continue;
520                                 }
521                                 free(name);
522                                 correct = true;
523                                 break;
524                         }
525                 }
526
527                 if (!correct) {
528                         continue;
529                 }
530
531                 pt_file_info *file_info = pt_create_file_info(NULL, NULL, PT_FILE_TMP);
532                 if(!file_info) {
533                 PT_ERROR("Setting file mode fails");
534                         return NULL;
535                 }
536
537                 file = pt_create_file(file_info);
538                 if(!file) {
539                         pt_free_file_info(file_info);
540                         PT_ERROR("Creating file fails");
541                         return NULL;
542                 }
543
544                 char *numstr;
545                 int line = (mod->inform).len;
546                 for (int i = 0; i < line; ++i) {
547                         uint32_t num = (mod->inform).buffer[i];
548                         numstr = g_ptr_array_index(strings, num);
549                         if(fputs(numstr, file->ptfile) == EOF) {
550                                 PT_ERROR("Writing data to temp file failed");
551                                 // FIXME: Here we should free memory
552                                 pt_free_file_info(file_info);
553                                 if(pt_free_file(file, PT_FREE_FILE_DEL)) {
554                                         PT_ERROR("Deleting temporary file fails");
555                                 }
556                                 return NULL;
557                         }
558                 }
559
560                 pt_free_file_info(file_info);
561                 if(pt_sync_file(file)) {
562                         PT_ERROR("Synchronize file with storage device fails");
563                         if(pt_free_file(file, PT_FREE_FILE_DEL)) {
564                                 PT_ERROR("Deleting temporary file fails");
565                         }
566                         return NULL;
567                 }
568                 break;
569         }
570         return file;
571 }
572
573 pt_file *extract_drv_by_model(drvm drv, const char *modelname)
574 {
575         pt_file *file;
576         file = extract_drv_by_key(drv, modelname, PT_MODELNAME);
577         return file;
578 }
579
580 pt_file *extract_drv_by_product(drvm drv, const char *product)
581 {
582         pt_file *file;
583         file = extract_drv_by_key(drv, product, PT_PRODUCTNAME);
584         return file;
585 }
586
587 void pt_free_drvm(drvm *drv)
588 {
589         if(drv)
590         {
591                 if(drv->models) {
592                         GPtrArray *models = drv->models;
593
594                         g_ptr_array_set_free_func(models, pt_free_model);
595                         g_ptr_array_free(models, TRUE);
596                 }
597
598                 if(drv->strings) {
599                         GPtrArray *strings = drv->strings;
600
601                         g_ptr_array_set_free_func(strings, pt_free_strings);
602                         g_ptr_array_free(strings, TRUE);
603                 }
604                 free((void*)drv);
605         }
606 }
607
608 void clean_outstr(outstr *ostr)
609 {
610         if(ostr) {
611                 if(ostr->value) {
612                         free(ostr->value);
613                 }
614         }
615 }
616
617 outstr *filter_string(const char *original)
618 {
619         char *value = NULL;
620         char *begin = NULL, *end = NULL, *word = NULL;
621
622         if(!original) {
623                 PT_ERROR("Argument is NULL");
624                 return NULL;
625         }
626
627         outstr *string = (outstr*)malloc(sizeof(outstr));
628         if(!string) {
629                 PT_ERROR("Allocating memory fails");
630                 return NULL;
631         }
632         memset(string, '\0', sizeof(outstr));
633
634         ptrdiff_t strln = 0;
635         begin = (char *)original;
636
637         unsigned char count = 0;
638
639         while(isblank(*begin)) {
640                 begin++;
641         }
642
643         word = begin;
644
645         while(*begin != '\0') {
646                 if (*begin == '"') {
647                         count++;
648                         begin++;
649                         break;
650                 } else if ((isblank(*begin)) && (count == 0)) {
651                         end = begin;
652                         begin = word;
653                         strln = end - begin;
654                         value = malloc(strln+1);
655                         if (!value) {
656                                 clean_outstr(string);
657                                 free(string);
658                                 PT_ERROR("Can't allocate memory");
659                                 return NULL;
660                         }
661                         memset(value, '\0', strln+1);
662                         strncpy(value, begin, strln);
663                         string->value = value;
664                         string->modified = end;
665                         return string;
666                 } else {
667                         begin++;
668                 }
669         }
670
671         if (count == 0) {
672                 end = begin;
673                 begin = word;
674                 value = malloc(strln+1);
675                 if (!value) {
676                         clean_outstr(string);
677                         free(string);
678                         PT_ERROR("Can't allocate memory");
679                         return NULL;
680                 }
681                 memset(value, '\0', strln+1);
682                 strncpy(value, begin, strln);
683                 string->value = value;
684                 string->modified = end;
685                 return string;
686         } else {
687                 end = begin;
688         }
689
690         while(*end != '\0') {
691                 if (*end == '"') {
692                         count--;
693                         break;
694                 }
695                 end++;
696         }
697
698         strln = end - begin;
699         value = malloc(strln+1);
700         if (!value) {
701                 clean_outstr(string);
702                 free(string);
703                 PT_ERROR("Can't allocate memory");
704                 return NULL;
705         }
706         memset(value, '\0', strln+1);
707         strncpy(value, begin, strln);
708         string->value = value;
709         end++;
710         string->modified = end;
711         return string;
712 }
713
714 char *filter_product(char *original, pt_search_key key)
715 {
716         const char *pname = "Product";
717         const char *attr = "Attribute";
718         outstr *result = NULL;
719
720         if (!original) {
721                 PT_ERROR("original is null");
722                 return NULL;
723         }
724         char *copied = malloc(strlen(original)+1);
725         if (!copied) {
726                 PT_ERROR("Can't allocate memory");
727                 return NULL;
728         }
729
730         char *full_string = copied;
731         char *modified = NULL;
732         char *value = NULL;
733
734         strcpy(copied, original);
735         result = filter_string(copied);
736         if(!result) {
737                 PT_ERROR("Error in processing string");
738                 free(full_string);
739                 return NULL;
740         }
741         modified = result->modified;
742         value = result->value;
743         free(result);
744
745         if (!strncmp(value, attr, strlen(attr))) {
746                 result = filter_string(modified);
747                 if(!result) {
748                         PT_ERROR("Error in processing string");
749                         free(value);
750                         free(full_string);
751                         return NULL;
752                 }
753                 free(value);
754                 modified = result->modified;
755                 value = result->value;
756                 free(result);
757
758                 if(!strncmp(value, pname, strlen(pname))) {
759                         result = filter_string(modified);
760                         if(!result) {
761                                 PT_ERROR("Error in processing string");
762                                 free(value);
763                                 free(full_string);
764                                 return NULL;
765                         }
766                         free(value);
767                         modified = result->modified;
768                         value = result->value;
769                         free(result);
770
771                         result = filter_string(modified);
772                         free(value);
773                         value = result->value;
774                         free(result);
775                 } else {
776                         free(value);
777                         free(full_string);
778                         return NULL;
779                 }
780         } else {
781                 free(value);
782                 free(full_string);
783                 return NULL;
784         }
785
786         free(full_string);
787         return value;
788 }
789
790 char *filter(char *original, pt_search_key key)
791 {
792         static const char *mname = "ModelName";
793         static const char *delim = " \t";
794         static const char *delim_str = "\"";
795         static const char *end = "\n";
796
797         char *value = NULL;
798         char *token = NULL;
799         char *copied = malloc(strlen(original)+1);
800         if (!copied) {
801                 PT_ERROR("Can't allocate memory");
802                 return NULL;
803         }
804         char *full_string = copied;
805
806         strcpy(copied, original);
807         while(isblank(*copied)) {
808                 copied++;
809                 continue;
810         }
811
812         token = strsep(&copied, delim);
813         if (!strcmp(token, mname)) {
814                 token = strsep(&copied, delim_str);
815                 if(!strcmp(token, "")) {
816                         token = strsep(&copied, delim_str);
817                         value = malloc(strlen(token)+1);
818                         if (!value) {
819                                 free(full_string);
820                                 PT_ERROR("Can't allocate memory");
821                                 return NULL;
822                         }
823                         strcpy(value, token);
824                         token = strsep(&copied, end);
825                         while(*token != '\0') {
826                                 if(isblank(*token)) {
827                                         token++;
828                                         continue;
829                                 } else {
830                                         free(full_string);
831                                         free(value);
832                                         PT_DEBUG("String contains unexpected symbols: %s", original);
833                                         return NULL;
834                                 }
835                         }
836                 } else {
837                         free(full_string);
838                         PT_DEBUG("String which contains %s is not correct", original);
839                         return NULL;
840                 }
841         }
842         free(full_string);
843         return value;
844 }
845
846 void pt_free_prod(prod *product)
847 {
848         if(product) {
849                 if(product->buffer) {
850                         free(product->buffer);
851                 }
852         }
853 }
854
855 void pt_free_strings(gpointer data)
856 {
857         if(data) {
858                 free((char*)data);
859         }
860 }
861
862 void pt_free_model(gpointer data)
863 {
864         if(data)
865         {
866                 model *mod = (model *)data;
867                 pt_free_prod(&(mod->product));
868                 pt_free_info(&(mod->inform));
869                 free(mod);
870         }
871 }
872
873 drvm *read_drv(FILE *fd)
874 {
875         size_t result;
876         drvm *drv;
877         GPtrArray *models;
878         GPtrArray *strings;
879
880         drv = (drvm *)calloc(1, sizeof(drvm));
881         if (!drv) {
882                 PT_ERROR("Can't allocate memory");
883                 return NULL;
884         }
885
886         uint32_t len;
887
888         result = fread(&len, sizeof(uint32_t), 1, fd);
889         if (result != 1) {
890                 PT_ERROR("Can't read data from file");
891                 pt_free_drvm(drv);
892                 return NULL;
893         }
894
895         if(len == 0 || len > UINT32_MAX) {
896                 PT_ERROR("Invalid length(%d)", len);
897                 pt_free_drvm(drv);
898                 return NULL;
899         }
900
901         size_t elm_size = sizeof(model*);
902         uint32_t length = len;
903         size_t res_size = length * elm_size;
904
905         models = g_ptr_array_sized_new(length);
906         drv->models = models;
907
908         model *mod;
909         for (int i = 0; i < length; ++i) {
910                 mod = read_model(fd);
911                 g_ptr_array_add(models, mod);
912         }
913
914         g_ptr_array_set_free_func(models, pt_free_model);
915
916         result = fread(&len, sizeof(uint32_t), 1, fd);
917         if (result != 1) {
918                 PT_ERROR("Can't read data from file");
919                 void *ptr = g_ptr_array_free(models, TRUE);
920                 if(ptr) {
921                         PT_ERROR("freeing memory fails");
922                 }
923                 free(drv);
924                 return NULL;
925         }
926
927         if (len == 0 || len > UINT32_MAX) {
928                 PT_ERROR("Invalid length(%d)", len);
929                 pt_free_drvm(drv);
930                 return NULL;
931         }
932
933         elm_size = sizeof(char *);
934         length = len;
935         res_size = length * elm_size;
936         strings = g_ptr_array_sized_new(length);
937         g_ptr_array_set_free_func(strings, pt_free_strings);
938         drv->strings = strings;
939
940         char *string;
941         size_t size_buffer;
942         ssize_t read;
943         for (int i = 0; i < length; ++i) {
944                 string = NULL;
945                 if((read = getline(&string, &size_buffer, fd)) == -1) {
946                         PT_ERROR("Can't read line from file");
947                         void *ptr = g_ptr_array_free(strings, TRUE);
948                         if(ptr) {
949                                 PT_ERROR("freeing memory fails");
950                         }
951                         ptr = g_ptr_array_free(models, TRUE);
952                         if(ptr) {
953                                 PT_ERROR("freeing memory fails");
954                         }
955                         free(drv);
956                         return NULL;
957                 }
958                 g_ptr_array_add(strings, string);
959         }
960
961         return drv;
962 }
963
964 model *read_model(FILE *fd)
965 {
966         model *mod;
967         size_t result;
968         uint32_t length;
969
970         mod = malloc(sizeof(model));
971         uint32_t len;
972         if (!mod) {
973                 PT_ERROR("Can't allocate memory");
974                 return NULL;
975         }
976
977         result = fread(&len, sizeof(uint32_t), 1, fd);
978         if(result != 1) {
979                 PT_ERROR("Can't read data from file");
980                 pt_free_model(mod);
981                 return NULL;
982         }
983
984         length = len;
985         mod->name = length;
986
987         result = fread(&len, sizeof(uint32_t), 1, fd);
988         if(result != 1) {
989                 PT_ERROR("Can't read data from file");
990                 pt_free_model(mod);
991                 return NULL;
992         }
993
994         if(len == 0 || len > UINT32_MAX) {
995                 PT_ERROR("Invalid length(%d)", len);
996                 pt_free_model(mod);
997                 return NULL;
998         }
999
1000         length = len;
1001         if ((length >> 30) > 0)
1002         {
1003                 PT_ERROR("Integer overflow");
1004                 pt_free_model(mod);
1005                 return NULL;
1006         }
1007
1008         uint32_t size_buffer = length * sizeof(uint32_t);
1009
1010         if(!((mod->product).buffer = malloc(size_buffer))) {
1011                 PT_ERROR("Can't allocate memory");
1012                 pt_free_model(mod);
1013                 return NULL;
1014         }
1015         (mod->product).len = length;
1016
1017         result = fread((mod->product).buffer, size_buffer, 1, fd);
1018         if(result != 1) {
1019                 PT_ERROR("Can't read data from file");
1020                 pt_free_model(mod);
1021                 return NULL;
1022         }
1023
1024         // Parse part related to product
1025
1026         result = fread(&len, sizeof(uint32_t), 1, fd);
1027         if(result != 1) {
1028                 PT_ERROR("Can't read data from file");
1029                 pt_free_model(mod);
1030                 return NULL;
1031         }
1032
1033         if(len == 0 || len > UINT32_MAX) {
1034                 PT_ERROR("Invalid length(%d)", len);
1035                 pt_free_model(mod);
1036                 return NULL;
1037         }
1038
1039         length = len;
1040         if ((length>>(32 - sizeof(uint32_t))) > 0)
1041         {
1042                 PT_ERROR("Integer overflow");
1043                 pt_free_model(mod);
1044                 return NULL;
1045         }
1046
1047         size_buffer = length * sizeof(uint32_t);
1048         if(!(mod->inform.buffer = malloc(size_buffer))) {
1049                 PT_ERROR("Can't allocate memory");
1050                 pt_free_model(mod);
1051                 return NULL;
1052         }
1053         mod->inform.len = length;
1054         result = fread(mod->inform.buffer, size_buffer, 1, fd);
1055         if(result != 1) {
1056                 PT_ERROR("Can't read data from file");
1057                 pt_free_model(mod);
1058                 return NULL;
1059         }
1060
1061         return mod;
1062 }
1063
1064 void pt_free_info(info *inf)
1065 {
1066         if(inf) {
1067                 if(inf->buffer) {
1068                         free(inf->buffer);
1069                 }
1070         }
1071 }
1072
1073 pt_dbconfig *pt_tune_db(FILE *file, const char *path)
1074 {
1075         if(!file) {
1076                 PT_ERROR(STR_PAR "%p", file);
1077                 return NULL;
1078         }
1079
1080         if(!path) {
1081                 PT_ERROR(STR_PAR "%p", path);
1082                 return NULL;
1083         }
1084
1085         char *copied_path = strdup(path);
1086         if(!copied_path) {
1087                 PT_ERROR("Allocating memory fail");
1088                 return NULL;
1089         }
1090
1091         int size = get_file_size(copied_path);
1092         if(size == -1) {
1093                 PT_ERROR("Getting info about file fail");
1094                 free(copied_path);
1095                 return NULL;
1096         }
1097
1098         char *buffer = malloc(size);
1099         if (!buffer) {
1100                 PT_ERROR("Allocating memory fail");
1101                 free(copied_path);
1102                 return NULL;
1103         }
1104
1105         int result = setvbuf(file, buffer, _IOFBF,  size);
1106         if (result) {
1107                 PT_ERROR("Tuning buffering operations fail");
1108                 free(copied_path);
1109                 free(buffer);
1110                 return NULL;
1111         }
1112
1113         pt_dbconfig *config;
1114         config = (pt_dbconfig*)malloc(sizeof(pt_dbconfig));
1115         if(!config) {
1116                 PT_ERROR("Allocating memory fail");
1117                 free(copied_path);
1118                 free(buffer);
1119                 return NULL;
1120         }
1121         memset(config, '\0', sizeof(pt_dbconfig));
1122         config->dbfile = file;
1123         config->dbpath = copied_path;
1124         config->dbbuffer = buffer;
1125         return config;
1126 }
1127
1128 void pt_free_config(pt_dbconfig *config)
1129 {
1130         if(!config) {
1131                 PT_ERROR(STR_PTR "%p", config);
1132         } else {
1133                 if(config->dbbuffer) {
1134                         free((void *)config->dbbuffer);
1135                 }
1136                 if(config->dbpath) {
1137                         free((void *)config->dbpath);
1138                 }
1139                 free(config);
1140         }
1141 }
1142
1143 char* pt_extract_ppd(pt_db *database, const char *search, pt_search type)
1144 {
1145         if(!database || !search) {
1146                 PT_ERROR(STR_PAR "%p, %p", database, search);
1147                 return NULL;
1148         }
1149
1150         drvm* dbstruct = database->dbstruct;
1151
1152         if(!dbstruct) {
1153                 PT_ERROR(STR_PTR "%p", dbstruct);
1154                 return NULL;
1155         }
1156
1157         pt_file *file = NULL;
1158         if(type == PT_SEARCH_MODEL) {
1159                 file = extract_drv_by_model(*dbstruct, search);
1160         } else if(type == PT_SEARCH_PROD) {
1161                 file = extract_drv_by_product(*dbstruct, search);
1162         } else if(type == PT_SEARCH_ALL) {
1163                 file = extract_drv_by_model(*dbstruct, search);
1164                 if(!file) {
1165                         file = extract_drv_by_product(*dbstruct, search);
1166                 }
1167         } else {
1168                 PT_ERROR(STR_PAR "%d", type);
1169                 return NULL;
1170         }
1171
1172         if(!file) {
1173                 PT_ERROR("Didn't find \"%s\" in database", search);
1174                 return NULL;
1175         }
1176
1177         char *output = pt_exec_ppdc(file);
1178         if(!output) {
1179                 // Handle error
1180                 PT_ERROR("Executing ppdc fails");
1181                 if(pt_free_file(file, PT_FREE_FILE_DEL)) {
1182                         PT_ERROR("[%s] Can't free memory", search);
1183                 }
1184                 return NULL;
1185         }
1186
1187         if(pt_free_file(file, PT_FREE_FILE_DEL)) {
1188                 PT_ERROR("Freeing memory fails");
1189                 free(output);
1190                 return NULL;
1191         }
1192         return output;
1193 }
1194
1195 void pt_free_dbconfig(pt_dbconfig *dbconfig)
1196 {
1197         if(dbconfig) {
1198                 if(dbconfig->dbbuffer) {
1199                         free((void*)dbconfig->dbbuffer);
1200                 }
1201                 if(dbconfig->dbpath) {
1202                         free((void*)dbconfig->dbpath);
1203                 }
1204                 if(dbconfig->dbfile) {
1205                         fclose(dbconfig->dbfile);
1206                 }
1207         }
1208 }
1209
1210 void pt_free_db(pt_db *database)
1211 {
1212         if(database) {
1213                 if(database->dbconfig) {
1214                         pt_free_dbconfig(database->dbconfig);
1215                 }
1216                 if(database->dbstruct) {
1217                         pt_free_drvm(database->dbstruct);
1218                 }
1219         }
1220 }
1221
1222 pt_db *pt_create_db(const char *path)
1223 {
1224         if(!path) {
1225                 return NULL;
1226         }
1227
1228         FILE *dbfile = fopen(path, "rb");
1229         if (!dbfile) {
1230                 return NULL;
1231         }
1232
1233         pt_dbconfig *config;
1234         config = pt_tune_db(dbfile, path);
1235         if(!config) {
1236                 PT_ERROR("Tuning database fail");
1237                 fclose(dbfile);
1238                 return NULL;
1239         }
1240
1241         drvm *dbstruct = read_drv(dbfile);
1242         if(!dbstruct) {
1243                 pt_free_config(config);
1244                 fclose(dbfile);
1245                 return NULL;
1246         }
1247
1248         pt_db *database = (pt_db*)malloc(sizeof(pt_db));
1249         if(!database) {
1250                 pt_free_config(config);
1251                 pt_free_drvm(dbstruct);
1252                 fclose(dbfile);
1253                 return NULL;
1254         }
1255
1256         database->dbstruct = dbstruct;
1257         database->dbconfig = config;
1258         return database;
1259 }