3 #include <glib/gstdio.h>
13 #include "track_cache.h"
15 static const char* cache_directory
= NULL
;
16 static const char cache_file_temp_ending
[] = ".temp";
17 #define DEFAULT_CACHE_DIRECTORY "~/.cache/xwax/track"
19 void track_cache_log(const char* format
, ...)
21 gchar
* wholeMessage
= g_strconcat("Track cache: ", format
, "\n", NULL
);
26 g_vfprintf(stderr
, wholeMessage
, ap
);
32 void track_cache_set_directory(const char* directory
)
34 cache_directory
= directory
;
36 track_cache_log("Set cache directory to \'%s\'", cache_directory
);
39 static gboolean
parse_cache(GOptionContext
*context
, GOptionGroup
*group
, gpointer data
, GError
**error
)
42 track_cache_set_directory(DEFAULT_CACHE_DIRECTORY
);
44 track_cache_set_directory(data
);
48 static GOptionEntry cacheOptions
[] =
50 { "cache", 'c', G_OPTION_FLAG_OPTIONAL_ARG
, G_OPTION_ARG_CALLBACK
, &parse_cache
, "Directory to cache decoded audio files", DEFAULT_CACHE_DIRECTORY
},
54 GOptionGroup
* get_cache_option_group()
56 GOptionGroup
* group
= g_option_group_new
59 "Cache control options",
60 "Show cache control help options",
64 g_option_group_add_entries(group
, cacheOptions
);
68 gboolean
track_cache_is_enabled()
70 return !isempty(cache_directory
);
73 const char* track_cache_get_directory()
75 return cache_directory
;
90 const char* cached_track_get_id(const cached_track
* cache
)
95 void cached_track_set_id(const char* path
, cached_track
* cache
)
97 gchar
* localPath
= g_strdup(path
);
98 char* args
[] = {"./xwax_hash", "get", localPath
, NULL
};
100 GError
* error
= NULL
;
101 gchar
* stdout
= NULL
;
102 gchar
* stderr
= NULL
;
104 gboolean success
= g_spawn_sync
106 NULL
, //working_directory
109 G_SPAWN_SEARCH_PATH
| G_SPAWN_FILE_AND_ARGV_ZERO
, //flags
120 if(success
&& status
== 0)
123 track_cache_log("Successfull retrieved id %s", stdout
);
127 track_cache_log("Could not retrieve id of file %s", path
);
132 cached_track
* cached_track_init(const char* path
)
134 if(!track_cache_is_enabled())
137 cached_track
* cache
= g_new(cached_track
, 1);
138 cached_track_set_id(path
, cache
);
141 if(isempty(cached_track_get_id(cache
)))
144 cache
->path
= g_build_filename(track_cache_get_directory(), cached_track_get_id(cache
), NULL
);
149 int cached_track_file_open(const cached_track
* cache
, int flags
, int perm
)
151 return g_open(cache
->path
, flags
, perm
);
154 int cached_track_file_open_read(const cached_track
* cache
)
156 return cached_track_file_open(cache
, O_RDONLY
| O_NONBLOCK
/*| O_SEQUENTIAL | O_BINARY*/, S_IRUSR
);
159 gchar
* cached_track_file_get_temp_name(const cached_track
* cache
)
161 return g_strconcat(cache
->path
, cache_file_temp_ending
, NULL
);
164 int cached_track_file_open_write(const cached_track
* cache
)
166 gchar
* tempFile
= cached_track_file_get_temp_name(cache
);
167 int fd
= g_open(tempFile
, O_WRONLY
| O_APPEND
| O_NONBLOCK
/*| O_BINARY */ | O_CREAT
| O_TRUNC
, S_IRUSR
| S_IWUSR
);
172 void cached_track_file_close(const int fd
)
177 void cached_track_file_write_close(const cached_track
* cache
, const int fd
)
179 cached_track_file_close(fd
);
180 g_rename(cached_track_file_get_temp_name(cache
), cache
->path
);
183 cache_read
* cache_read_init(const cached_track
* cache
)
185 cache_read
* read
= g_new(cache_read
, 1);
186 read
->fd
= cached_track_file_open_read(cache
);
193 fprintf(stderr
, "EACCES\n");
196 fprintf(stderr
, "EEXIST\n");
199 fprintf(stderr
, "EFAULT\n");
202 fprintf(stderr
, "EISDIR\n");
205 fprintf(stderr
, "ELOOP\n");
208 fprintf(stderr
, "EMFILE\n");
211 fprintf(stderr
, "ENAMETOOLONG\n");
214 fprintf(stderr
, "ENFILE\n");
217 fprintf(stderr
, "ENODEV\n");
220 fprintf(stderr
, "ENOENT\n");
223 fprintf(stderr
, "ENOMEM\n");
226 fprintf(stderr
, "ENOSPC\n");
229 fprintf(stderr
, "ENOTDIR\n");
232 fprintf(stderr
, "ENXIO\n");
235 fprintf(stderr
, "EOVERFLOW\n");
238 fprintf(stderr
, "EPERM\n");
241 fprintf(stderr
, "EROFS\n");
244 fprintf(stderr
, "ETXTBSY\n");
247 fprintf(stderr
, "EWOULDBLOCK\n");
255 read
->file
= fdopen(read
->fd
, "r");
257 track_cache_log("Found in cache");
262 gboolean
cached_track_file_exists(const cached_track
* cache
)
264 return g_file_test(cache
->path
, G_FILE_TEST_EXISTS
| G_FILE_TEST_IS_REGULAR
);
267 cache_read
* cached_track_read(const cached_track
* cache
)
269 if(!track_cache_is_enabled())
275 if(!cached_track_file_exists(cache
))
278 return cache_read_init(cache
);
281 void cached_track_write(const cached_track
* cache
, const struct track_t
*tr
)
283 if(!track_cache_is_enabled())
289 if(cached_track_file_exists(cache
))
292 int fd
= cached_track_file_open_write(cache
);
295 return; //TODO: messup here
297 FILE* fp
= fdopen(fd
, "wa");
299 long bytesLeft
= tr
->bytes
;
301 struct track_block_t
* block
= NULL
;
302 unsigned int byteUse
;
305 //Do not rely on tr->blocks here because it
306 //does only reflect the overall track memory allocation
307 for(guint index
= 0; /*index < tr->block->len &&*/ bytesLeft
> 0; index
++)
309 block
= track_get_block(tr
, index
);
311 byteUse
= track_block_get_used_bytes(tr
, index
);
313 for(guint pcmIndex
= 0; pcmIndex
< byteUse
/ TRACK_PCM_DATA_SIZE
; pcmIndex
++)
315 fwrite(&block
->pcm
[pcmIndex
], 1 , TRACK_PCM_DATA_SIZE
, fp
);
318 bytesLeft
-= byteUse
;
323 cached_track_file_write_close(cache
, fd
);
326 void cached_track_destroy(cached_track
* cache
)
336 int cache_read_get_fd(const cache_read
* read
)
341 int cache_read_block(cache_read
* read
, signed short* pcm
, guint pcmCount
)
343 return fread(pcm
, TRACK_PCM_DATA_SIZE
, pcmCount
, read
->file
) * TRACK_PCM_DATA_SIZE
;
346 void cache_read_destroy(cache_read
* read
)
351 cached_track_file_close(read
->fd
);