2 Calf Box, an open source musical instrument.
3 Copyright (C) 2010-2013 Krzysztof Foltman
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #include "config-api.h"
26 #include <sys/types.h>
52 static void remove_item_if(gpointer p
);
54 struct cbox_tarfile
*cbox_tarfile_open(const char *pathname
, GError
**error
)
56 gboolean debug
= cbox_config_get_int("debug", "tarfile", 0);
57 gchar
*canonical
= realpath(pathname
, NULL
);
61 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "cannot determine canonical name of '%s'", pathname
);
64 int fd
= open(canonical
, O_RDONLY
| O_LARGEFILE
);
69 g_set_error(error
, G_FILE_ERROR
, g_file_error_from_errno (errno
), "cannot open '%s'", pathname
);
72 GHashTable
*byname
= NULL
, *byname_nc
= NULL
;
74 byname
= g_hash_table_new(g_str_hash
, g_str_equal
);
75 byname_nc
= g_hash_table_new(g_str_hash
, g_str_equal
);
76 if (!byname
|| !byname_nc
)
79 struct cbox_tarfile
*tf
= calloc(1, sizeof(struct cbox_tarfile
));
83 tf
->items_byname
= byname
;
84 tf
->items_byname_nc
= byname_nc
;
86 tf
->file_pathname
= canonical
;
89 struct tar_record rec
;
90 int nbytes
= read(fd
, &rec
, sizeof(rec
));
91 if (nbytes
!= sizeof(rec
))
94 int len
= sizeof(rec
.name
);
95 while(len
> 0 && (rec
.name
[len
- 1] == ' ' || rec
.name
[len
- 1] == '\0'))
99 memcpy(sizetext
, rec
.size
, 12);
101 unsigned long long size
= strtoll(sizetext
, NULL
, 8);
103 // skip block if name is empty
106 struct cbox_taritem
*ti
= calloc(1, sizeof(struct cbox_taritem
));
109 ti
->filename
= g_strndup(rec
.name
, len
);
110 ti
->filename_nc
= g_utf8_casefold(rec
.name
, len
);
111 if (!ti
->filename
|| !ti
->filename_nc
)
113 ti
->offset
= lseek64(fd
, 0, SEEK_CUR
);
117 // Overwrite old items by the same name and/or same case-folded name
118 remove_item_if(g_hash_table_lookup(tf
->items_byname
, ti
->filename
));
119 remove_item_if(g_hash_table_lookup(tf
->items_byname_nc
, ti
->filename_nc
));
121 g_hash_table_insert(tf
->items_byname
, ti
->filename
, ti
);
122 g_hash_table_insert(tf
->items_byname_nc
, ti
->filename_nc
, ti
);
124 printf("name = %s len = %d offset = %d readsize = %d\n", ti
->filename
, len
, (int)ti
->offset
, (int)size
);
130 g_warning("Could not allocate memory for tar item %s", rec
.name
);
134 g_free(ti
->filename_nc
);
136 g_free(ti
->filename
);
140 lseek64(fd
, (size
+ 511) &~ 511, SEEK_CUR
);
146 g_hash_table_destroy(byname
);
148 g_hash_table_destroy(byname_nc
);
150 g_set_error(error
, CBOX_MODULE_ERROR
, CBOX_MODULE_ERROR_FAILED
, "Cannot allocate memory for tarfile data");
154 void remove_item_if(gpointer p
)
159 struct cbox_taritem
*ti
= p
;
160 // If all references (by name and by case-folded name) gone, remove the item
163 g_free(ti
->filename
);
164 g_free(ti
->filename_nc
);
169 struct cbox_taritem
*cbox_tarfile_get_item_by_name(struct cbox_tarfile
*tarfile
, const char *item_filename
, gboolean ignore_case
)
173 gchar
*folded
= g_utf8_casefold(item_filename
, -1);
174 struct cbox_taritem
*item
= g_hash_table_lookup(tarfile
->items_byname_nc
, folded
);
179 return g_hash_table_lookup(tarfile
->items_byname
, item_filename
);
182 int cbox_tarfile_openitem(struct cbox_tarfile
*tarfile
, struct cbox_taritem
*item
)
184 int fd
= open(tarfile
->file_pathname
, O_RDONLY
| O_LARGEFILE
);
186 lseek64(fd
, item
->offset
, SEEK_SET
);
190 void cbox_tarfile_closeitem(struct cbox_tarfile
*tarfile
, struct cbox_taritem
*item
, int fd
)
196 static void delete_foreach_func(gpointer key
, gpointer value
, gpointer user_data
)
198 struct cbox_taritem
*ti
= value
;
201 g_free(ti
->filename
);
202 g_free(ti
->filename_nc
);
207 void cbox_tarfile_destroy(struct cbox_tarfile
*tf
)
209 g_hash_table_foreach(tf
->items_byname
, delete_foreach_func
, NULL
);
210 g_hash_table_foreach(tf
->items_byname_nc
, delete_foreach_func
, NULL
);
212 g_hash_table_destroy(tf
->items_byname
);
213 g_hash_table_destroy(tf
->items_byname_nc
);
214 free(tf
->file_pathname
);
218 ////////////////////////////////////////////////////////////////////////////////
220 struct cbox_tarpool
*cbox_tarpool_new()
222 struct cbox_tarpool
*pool
= calloc(1, sizeof(struct cbox_tarpool
));
223 pool
->files
= g_hash_table_new(g_str_hash
, g_str_equal
);
227 struct cbox_tarfile
*cbox_tarpool_get_tarfile(struct cbox_tarpool
*pool
, const char *name
, GError
**error
)
229 //gchar *c = realpath(name, NULL);
230 gchar
*c
= g_strdup(name
);
231 struct cbox_tarfile
*tf
= g_hash_table_lookup(pool
->files
, c
);
236 tf
= cbox_tarfile_open(c
, error
);
242 g_hash_table_insert(pool
->files
, c
, tf
);
248 void cbox_tarpool_release_tarfile(struct cbox_tarpool
*pool
, struct cbox_tarfile
*file
)
251 cbox_tarfile_destroy(file
);
254 void cbox_tarpool_destroy(struct cbox_tarpool
*pool
)
256 g_hash_table_destroy(pool
->files
);