Add copyright to all source files.
[lms] / lightmediascanner / src / lib / lightmediascanner_db_common.c
1 /**
2  * Copyright (C) 2007 by INdT
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  *
18  * @author Gustavo Sverzut Barbieri <gustavo.barbieri@openbossa.org>
19  */
20
21 #include "lightmediascanner_db_private.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 #if SQLITE_VERSION_NUMBER < 3003009
27 int
28 sqlite3_prepare_v2(sqlite3 *db, const char *sql, int len, sqlite3_stmt **stmt, const char **tail)
29 {
30     return sqlite3_prepare(db, sql, len, stmt, tail);
31 }
32 #endif /* SQLITE_VERSION_NUMBER < 3003009 */
33
34 #if SQLITE_VERSION_NUMBER < 3003007
35 int
36 sqlite3_clear_bindings(sqlite3_stmt *stmt)
37 {
38     int i, last;
39     int rc;
40
41     rc = SQLITE_OK;
42     last = sqlite3_bind_parameter_count(stmt);
43     for(i = 1; rc == SQLITE_OK && i <= last; i++) {
44         rc = sqlite3_bind_null(stmt, i);
45     }
46     return rc;
47 }
48 #endif /* SQLITE_VERSION_NUMBER < 3003007 */
49
50 #if SQLITE_VERSION_NUMBER < 3003008
51 /* Until 3.3.8 it doesn't support CREATE TRIGGER IF NOT EXISTS, so
52  * just ignore errors :-(
53  */
54 int
55 lms_db_create_trigger_if_not_exists(sqlite3 *db, const char *sql)
56 {
57     char *errmsg, *query;
58     int r, sql_len, prefix_len;
59
60     prefix_len = sizeof("CREATE TRIGGER ") - 1;
61     sql_len = strlen(sql);
62     query = malloc((prefix_len + sql_len + 1) * sizeof(char));
63     if (!query)
64         return -1;
65
66     memcpy(query, "CREATE TRIGGER ", prefix_len);
67     memcpy(query + prefix_len, sql, sql_len + 1);
68     r = sqlite3_exec(db, query, NULL, NULL, &errmsg);
69     free(query);
70     if (r != SQLITE_OK)
71         sqlite3_free(errmsg);
72     return 0;
73 }
74 #else /* SQLITE_VERSION_NUMBER < 3003008 */
75 int
76 lms_db_create_trigger_if_not_exists(sqlite3 *db, const char *sql)
77 {
78     char *errmsg, *query;
79     int r, sql_len, prefix_len;
80
81     prefix_len = sizeof("CREATE TRIGGER IF NOT EXISTS ") - 1;
82     sql_len = strlen(sql);
83     query = malloc((prefix_len + sql_len + 1) * sizeof(char));
84     if (!query)
85         return -1;
86
87     memcpy(query, "CREATE TRIGGER IF NOT EXISTS ", prefix_len);
88     memcpy(query + prefix_len, sql, sql_len + 1);
89     r = sqlite3_exec(db, query, NULL, NULL, &errmsg);
90     free(query);
91     if (r != SQLITE_OK) {
92         fprintf(stderr, "ERROR: could not create trigger: %s\n", errmsg);
93         sqlite3_free(errmsg);
94         return -2;
95     }
96     return 0;
97 }
98 #endif /* SQLITE_VERSION_NUMBER < 3003008 */
99
100 sqlite3_stmt *
101 lms_db_compile_stmt(sqlite3 *db, const char *sql)
102 {
103     sqlite3_stmt *stmt;
104
105     if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) != SQLITE_OK)
106         fprintf(stderr, "ERROR: could not prepare \"%s\": %s\n", sql,
107                 sqlite3_errmsg(db));
108
109     return stmt;
110 }
111
112 int
113 lms_db_finalize_stmt(sqlite3_stmt *stmt, const char *name)
114 {
115     int r;
116
117     r = sqlite3_finalize(stmt);
118     if (r != SQLITE_OK) {
119         fprintf(stderr, "ERROR: could not finalize %s statement: #%d\n",
120                 name, r);
121         return -1;
122     }
123
124     return 0;
125 }
126
127 int
128 lms_db_reset_stmt(sqlite3_stmt *stmt)
129 {
130     int r, ret;
131
132     ret = r = sqlite3_reset(stmt);
133     if (r != SQLITE_OK)
134         fprintf(stderr, "ERROR: could not reset SQL statement: #%d\n", r);
135
136     r = sqlite3_clear_bindings(stmt);
137     ret += r;
138     if (r != SQLITE_OK)
139         fprintf(stderr, "ERROR: could not clear SQL: #%d\n", r);
140
141     return ret;
142 }
143
144 int
145 lms_db_bind_text(sqlite3_stmt *stmt, int col, const char *text, int len)
146 {
147     int r;
148
149     if (text)
150         r = sqlite3_bind_text(stmt, col, text, len, SQLITE_STATIC);
151     else
152         r = sqlite3_bind_null(stmt, col);
153
154     if (r == SQLITE_OK)
155         return 0;
156     else {
157         sqlite3 *db;
158         const char *err;
159
160         db = sqlite3_db_handle(stmt);
161         err = sqlite3_errmsg(db);
162         fprintf(stderr, "ERROR: could not bind SQL value %d: %s\n", col, err);
163         return -col;
164     }
165 }
166
167 int
168 lms_db_bind_blob(sqlite3_stmt *stmt, int col, const void *blob, int len)
169 {
170     int r;
171
172     if (blob)
173         r = sqlite3_bind_blob(stmt, col, blob, len, SQLITE_STATIC);
174     else
175         r = sqlite3_bind_null(stmt, col);
176
177     if (r == SQLITE_OK)
178         return 0;
179     else {
180         sqlite3 *db;
181         const char *err;
182
183         db = sqlite3_db_handle(stmt);
184         err = sqlite3_errmsg(db);
185         fprintf(stderr, "ERROR: could not bind SQL value %d: %s\n", col, err);
186         return -col;
187     }
188 }
189
190 int
191 lms_db_bind_int64(sqlite3_stmt *stmt, int col, int64_t value)
192 {
193     int r;
194
195     r = sqlite3_bind_int64(stmt, col, value);
196     if (r == SQLITE_OK)
197         return 0;
198     else {
199         sqlite3 *db;
200         const char *err;
201
202         db = sqlite3_db_handle(stmt);
203         err = sqlite3_errmsg(db);
204         fprintf(stderr, "ERROR: could not bind SQL value %d: %s\n", col, err);
205         return -col;
206     }
207 }
208
209 int
210 lms_db_bind_int64_or_null(sqlite3_stmt *stmt, int col, int64_t *p_value)
211 {
212     int r;
213
214     if (p_value)
215         r = sqlite3_bind_int64(stmt, col, *p_value);
216     else
217         r = sqlite3_bind_null(stmt, col);
218     if (r == SQLITE_OK)
219         return 0;
220     else {
221         sqlite3 *db;
222         const char *err;
223
224         db = sqlite3_db_handle(stmt);
225         err = sqlite3_errmsg(db);
226         fprintf(stderr, "ERROR: could not bind SQL value %d: %s\n", col, err);
227         return -col;
228     }
229 }
230
231 int
232 lms_db_bind_int(sqlite3_stmt *stmt, int col, int value)
233 {
234     int r;
235
236     r = sqlite3_bind_int(stmt, col, value);
237     if (r == SQLITE_OK)
238         return 0;
239     else {
240         sqlite3 *db;
241         const char *err;
242
243         db = sqlite3_db_handle(stmt);
244         err = sqlite3_errmsg(db);
245         fprintf(stderr, "ERROR: could not bind SQL value %d: %s\n", col, err);
246         return -col;
247     }
248 }
249
250 int
251 lms_db_bind_double(sqlite3_stmt *stmt, int col, double value)
252 {
253     int r;
254
255     r = sqlite3_bind_double(stmt, col, value);
256     if (r == SQLITE_OK)
257         return 0;
258     else {
259         sqlite3 *db;
260         const char *err;
261
262         db = sqlite3_db_handle(stmt);
263         err = sqlite3_errmsg(db);
264         fprintf(stderr, "ERROR: could not bind SQL value %d: %s\n", col, err);
265         return -col;
266     }
267 }
268
269 int
270 lms_db_table_version_get(sqlite3 *db, const char *table)
271 {
272     int r, version;
273     sqlite3_stmt *stmt;
274
275     stmt = lms_db_compile_stmt(db,
276          "SELECT version FROM lms_internal WHERE tab = ?");
277     if (!stmt)
278         return -1;
279
280     if (lms_db_bind_text(stmt, 1, table, -1) != 0) {
281         version = -1;
282         goto done;
283     }
284
285     r = sqlite3_step(stmt);
286     if (r == SQLITE_DONE)
287         version = 0;
288     else if (r == SQLITE_ROW)
289         version = sqlite3_column_int(stmt, 1);
290     else {
291         version = -1;
292         fprintf(stderr, "ERROR: could not get table '%s' version: %s\n",
293                 table, sqlite3_errmsg(db));
294     }
295
296   done:
297     lms_db_reset_stmt(stmt);
298     lms_db_finalize_stmt(stmt, "table_version_get");
299
300     return version;
301 }
302
303 int
304 lms_db_table_version_set(sqlite3 *db, const char *table, unsigned int version)
305 {
306     int r, ret;
307     sqlite3_stmt *stmt;
308
309     stmt = lms_db_compile_stmt(db,
310         "INSERT OR REPLACE INTO lms_internal (tab, version) VALUES (?, ?)");
311     if (!stmt)
312         return -1;
313
314     ret = lms_db_bind_text(stmt, 1, table, -1);
315     if (ret != 0)
316         goto done;
317
318     ret = lms_db_bind_int(stmt, 2, version);
319     if (ret != 0)
320         goto done;
321
322     r = sqlite3_step(stmt);
323     if (r != SQLITE_DONE) {
324         ret = -1;
325         fprintf(stderr, "ERROR: could not set table '%s' version: %s\n",
326                 table, sqlite3_errmsg(db));
327     }
328
329   done:
330     lms_db_reset_stmt(stmt);
331     lms_db_finalize_stmt(stmt, "table_version_set");
332
333     return ret;
334 }
335
336 int
337 lms_db_table_update(sqlite3 *db, const char *table, unsigned int current_version, unsigned int last_version, const lms_db_table_updater_t *updaters)
338 {
339     if (current_version == last_version)
340         return 0;
341     else if (current_version > last_version) {
342         fprintf(stderr,
343                 "WARNING: current version (%d) of table '%s' is greater than "
344                 "last known version (%d), no updates will be made.\n",
345                 current_version, table, last_version);
346         return 0;
347     }
348
349     for (; current_version < last_version; current_version++) {
350         int r, is_last_run;
351
352         is_last_run = current_version == (last_version - 1);
353         r = updaters[current_version](db, table, current_version, is_last_run);
354         if (r != 0) {
355             fprintf(stderr,
356                     "ERROR: could not update table '%s' from version %d->%d\n",
357                     table, current_version, current_version + 1);
358             return r;
359         }
360         lms_db_table_version_set(db, table, current_version + 1);
361     }
362
363     return 0;
364 }
365
366 int
367 lms_db_table_update_if_required(sqlite3 *db, const char *table, unsigned int last_version, lms_db_table_updater_t *updaters)
368 {
369     int current_version;
370
371     current_version = lms_db_table_version_get(db, table);
372     if (current_version < 0)
373         return -1;
374     else
375         return lms_db_table_update(db, table, current_version, last_version,
376                                    updaters);
377 }
378
379 static int
380 lms_db_cache_find_db(const struct lms_db_cache *cache, const sqlite3 *db)
381 {
382     int i;
383
384     for (i = 0; i < cache->size; i++)
385         if (cache->entries[i].db == db)
386             return i;
387
388     return -1;
389 }
390
391 static int
392 lms_db_cache_resize(struct lms_db_cache *cache, int new_size)
393 {
394     cache->size = new_size;
395     cache->entries = realloc(cache->entries,
396                              cache->size * sizeof(*cache->entries));
397     if (cache->size && !cache->entries) {
398         perror("realloc");
399         cache->size = 0;
400         return -1;
401     }
402
403     return 0;
404 }
405
406 int
407 lms_db_cache_add(struct lms_db_cache *cache, const sqlite3 *db, void *data)
408 {
409     struct lms_db_cache_entry *e;
410     int idx;
411
412     idx = lms_db_cache_find_db(cache, db);
413     if (idx >= 0) {
414         e = cache->entries + idx;
415         if (e->data == data)
416             return 0;
417         else {
418             fprintf(stderr,
419                     "ERROR: cache %p for db %p has another data registered"
420                     ": %p (current is %p)\n", cache, db, e->data, data);
421             return -1;
422         }
423     }
424
425     idx = cache->size;
426     if (lms_db_cache_resize(cache, cache->size + 1) != 0) {
427         return -2;
428     }
429
430     e = cache->entries + idx;
431     e->db = db;
432     e->data = data;
433     return 0;
434 }
435
436 int
437 lms_db_cache_del(struct lms_db_cache *cache, const sqlite3 *db, void *data)
438 {
439     int idx;
440     struct lms_db_cache_entry *e;
441
442     idx = lms_db_cache_find_db(cache, db);
443     if (idx < 0) {
444         fprintf(stderr, "ERROR: no db %p found in cache %p\n", db, cache);
445         return -1;
446     }
447
448     e = cache->entries + idx;
449     if (e->data != data) {
450         fprintf(stderr, "ERROR: data mismatch in request to delete from cache: "
451                 "want %p, has %p, cache %p, db %p\n", data, e->data, cache, db);
452         return -2;
453     }
454
455     for (; idx < cache->size - 1; idx++)
456         cache->entries[idx] = cache->entries[idx + 1];
457
458     return lms_db_cache_resize(cache, cache->size - 1);
459 }
460
461 int
462 lms_db_cache_get(struct lms_db_cache *cache, const sqlite3 *db, void **pdata)
463 {
464     int idx;
465
466     idx = lms_db_cache_find_db(cache, db);
467     if (idx < 0)
468         return -1;
469
470     *pdata = cache->entries[idx].data;
471     return 0;
472 }
473
474 int
475 lms_db_create_core_tables_if_required(sqlite3 *db)
476 {
477     char *errmsg;
478     int r;
479
480     errmsg = NULL;
481     r = sqlite3_exec(db,
482                      "CREATE TABLE IF NOT EXISTS lms_internal ("
483                      "tab TEXT NOT NULL UNIQUE, "
484                      "version INTEGER NOT NULL"
485                      ")",
486                      NULL, NULL, &errmsg);
487     if (r != SQLITE_OK) {
488         fprintf(stderr, "ERROR: could not create 'lms_internal' table: %s\n",
489                 errmsg);
490         sqlite3_free(errmsg);
491         return -1;
492     }
493
494     r = sqlite3_exec(db,
495                      "CREATE TABLE IF NOT EXISTS files ("
496                      "id INTEGER PRIMARY KEY AUTOINCREMENT, "
497                      "path BLOB NOT NULL UNIQUE, "
498                      "mtime INTEGER NOT NULL, "
499                      "dtime INTEGER NOT NULL, "
500                      "size INTEGER NOT NULL"
501                      ")",
502                      NULL, NULL, &errmsg);
503     if (r != SQLITE_OK) {
504         fprintf(stderr, "ERROR: could not create 'files' table: %s\n", errmsg);
505         sqlite3_free(errmsg);
506         return -2;
507     }
508
509     r = sqlite3_exec(db,
510                      "CREATE INDEX IF NOT EXISTS files_path_idx ON files ("
511                      "path"
512                      ")",
513                      NULL, NULL, &errmsg);
514     if (r != SQLITE_OK) {
515         fprintf(stderr, "ERROR: could not create 'files_path_idx' index: %s\n",
516                 errmsg);
517         sqlite3_free(errmsg);
518         return -3;
519     }
520
521     return 0;
522 }
523
524
525 sqlite3_stmt *
526 lms_db_compile_stmt_begin_transaction(sqlite3 *db)
527 {
528     return lms_db_compile_stmt(db, "BEGIN TRANSACTION");
529 }
530
531 int
532 lms_db_begin_transaction(sqlite3_stmt *stmt)
533 {
534     int r, ret;
535
536     ret = 0;
537     r = sqlite3_step(stmt);
538     if (r != SQLITE_DONE) {
539         fprintf(stderr, "ERROR: could not begin transaction: %s\n",
540                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
541         ret = -1;
542     }
543
544     r = sqlite3_reset(stmt);
545     if (r != SQLITE_OK)
546         fprintf(stderr, "ERROR: could not reset SQL statement: %s\n",
547                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
548
549     return ret;
550 }
551
552 sqlite3_stmt *
553 lms_db_compile_stmt_end_transaction(sqlite3 *db)
554 {
555     return lms_db_compile_stmt(db, "COMMIT");
556 }
557
558 int
559 lms_db_end_transaction(sqlite3_stmt *stmt)
560 {
561     int r, ret;
562
563     ret = 0;
564     r = sqlite3_step(stmt);
565     if (r != SQLITE_DONE) {
566         fprintf(stderr, "ERROR: could not end transaction: %s\n",
567                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
568         ret = -1;
569     }
570
571     r = sqlite3_reset(stmt);
572     if (r != SQLITE_OK)
573         fprintf(stderr, "ERROR: could not reset SQL statement: %s\n",
574                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
575
576     return ret;
577 }
578
579 sqlite3_stmt *
580 lms_db_compile_stmt_get_file_info(sqlite3 *db)
581 {
582     return lms_db_compile_stmt(db,
583         "SELECT id, mtime, dtime, size FROM files WHERE path = ?");
584 }
585
586 int
587 lms_db_get_file_info(sqlite3_stmt *stmt, struct lms_file_info *finfo)
588 {
589     int r, ret;
590
591     ret = lms_db_bind_blob(stmt, 1, finfo->path, finfo->path_len);
592     if (ret != 0)
593         goto done;
594
595     r = sqlite3_step(stmt);
596     if (r == SQLITE_DONE) {
597         ret = 1;
598         finfo->id = -1;
599         goto done;
600     }
601
602     if (r != SQLITE_ROW) {
603         fprintf(stderr, "ERROR: could not get file info from table: %s\n",
604                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
605         ret = -2;
606         goto done;
607     }
608
609     finfo->id = sqlite3_column_int64(stmt, 0);
610     finfo->mtime = sqlite3_column_int(stmt, 1);
611     finfo->dtime = sqlite3_column_int(stmt, 2);
612     finfo->size = sqlite3_column_int(stmt, 3);
613     ret = 0;
614
615   done:
616     lms_db_reset_stmt(stmt);
617
618     return ret;
619 }
620
621 sqlite3_stmt *
622 lms_db_compile_stmt_update_file_info(sqlite3 *db)
623 {
624     return lms_db_compile_stmt(db,
625         "UPDATE files SET mtime = ?, dtime = ?, size = ? WHERE id = ?");
626 }
627
628 int
629 lms_db_update_file_info(sqlite3_stmt *stmt, const struct lms_file_info *finfo)
630 {
631     int r, ret;
632
633     ret = lms_db_bind_int(stmt, 1, finfo->mtime);
634     if (ret != 0)
635         goto done;
636
637     ret = lms_db_bind_int(stmt, 2, finfo->dtime);
638     if (ret != 0)
639         goto done;
640
641     ret = lms_db_bind_int(stmt, 3, finfo->size);
642     if (ret != 0)
643         goto done;
644
645     ret = lms_db_bind_int(stmt, 4, finfo->id);
646     if (ret != 0)
647         goto done;
648
649     r = sqlite3_step(stmt);
650     if (r != SQLITE_DONE) {
651         fprintf(stderr, "ERROR: could not update file info: %s\n",
652                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
653         ret = -5;
654         goto done;
655     }
656
657     ret = 0;
658
659   done:
660     lms_db_reset_stmt(stmt);
661
662     return ret;
663 }
664
665 sqlite3_stmt *
666 lms_db_compile_stmt_insert_file_info(sqlite3 *db)
667 {
668     return lms_db_compile_stmt(db,
669         "INSERT INTO files (path, mtime, dtime, size) VALUES(?, ?, ?, ?)");
670 }
671
672 int
673 lms_db_insert_file_info(sqlite3_stmt *stmt, struct lms_file_info *finfo)
674 {
675     int r, ret;
676
677     ret = lms_db_bind_blob(stmt, 1, finfo->path, finfo->path_len);
678     if (ret != 0)
679         goto done;
680
681     ret = lms_db_bind_int(stmt, 2, finfo->mtime);
682     if (ret != 0)
683         goto done;
684
685     ret = lms_db_bind_int(stmt, 3, finfo->dtime);
686     if (ret != 0)
687         goto done;
688
689     ret = lms_db_bind_int(stmt, 4, finfo->size);
690     if (ret != 0)
691         goto done;
692
693     r = sqlite3_step(stmt);
694     if (r != SQLITE_DONE) {
695         fprintf(stderr, "ERROR: could not insert file info: %s\n",
696                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
697         ret = -5;
698         goto done;
699     }
700
701     finfo->id = sqlite3_last_insert_rowid(sqlite3_db_handle(stmt));
702     ret = 0;
703
704   done:
705     lms_db_reset_stmt(stmt);
706
707     return ret;
708 }
709
710 sqlite3_stmt *
711 lms_db_compile_stmt_delete_file_info(sqlite3 *db)
712 {
713     return lms_db_compile_stmt(db, "DELETE FROM files WHERE id = ?");
714 }
715
716 int
717 lms_db_delete_file_info(sqlite3_stmt *stmt, const struct lms_file_info *finfo)
718 {
719     int r, ret;
720
721     ret = lms_db_bind_int64(stmt, 1, finfo->id);
722     if (ret != 0)
723         goto done;
724
725     r = sqlite3_step(stmt);
726     if (r != SQLITE_DONE) {
727         fprintf(stderr, "ERROR: could not delete file info: %s\n",
728                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
729         ret = -2;
730         goto done;
731     }
732     ret = 0;
733
734   done:
735     lms_db_reset_stmt(stmt);
736
737     return ret;
738 }
739
740 sqlite3_stmt *
741 lms_db_compile_stmt_set_file_dtime(sqlite3 *db)
742 {
743     return lms_db_compile_stmt(db, "UPDATE files SET dtime = ? WHERE id = ?");
744 }
745
746 int
747 lms_db_set_file_dtime(sqlite3_stmt *stmt, const struct lms_file_info *finfo)
748 {
749     int r, ret;
750
751     ret = lms_db_bind_int(stmt, 1, finfo->dtime);
752     if (ret != 0)
753         goto done;
754
755     ret = lms_db_bind_int64(stmt, 1, finfo->id);
756     if (ret != 0)
757         goto done;
758
759     r = sqlite3_step(stmt);
760     if (r != SQLITE_DONE) {
761         fprintf(stderr, "ERROR: could not set file dtime: %s\n",
762                 sqlite3_errmsg(sqlite3_db_handle(stmt)));
763         ret = -3;
764         goto done;
765     }
766
767     ret = 0;
768
769   done:
770     lms_db_reset_stmt(stmt);
771
772     return ret;
773 }
774
775 sqlite3_stmt *
776 lms_db_compile_stmt_get_files(sqlite3 *db)
777 {
778     return lms_db_compile_stmt(db,
779         "SELECT id, path, mtime, dtime, size FROM files WHERE path LIKE ?");
780 }
781
782 int
783 lms_db_get_files(sqlite3_stmt *stmt, const char *path, int len)
784 {
785     int ret;
786
787     ret = lms_db_bind_blob(stmt, 1, path, len);
788     return ret;
789 }