Fix so permission changes in the library are handled (issue #8)

This commit is contained in:
ejurgensen 2014-06-09 23:42:02 +02:00
parent 844a9b43c9
commit 1bd11d2895
3 changed files with 132 additions and 34 deletions

View File

@ -2470,7 +2470,7 @@ db_file_update(struct media_file_info *mfi)
" year = %d, track = %d, total_tracks = %d, disc = %d, total_discs = %d, bpm = %d," \ " year = %d, track = %d, total_tracks = %d, disc = %d, total_discs = %d, bpm = %d," \
" compilation = %d, artwork = %d, rating = %d, seek = %d, data_kind = %d, item_kind = %d," \ " compilation = %d, artwork = %d, rating = %d, seek = %d, data_kind = %d, item_kind = %d," \
" description = %Q, time_modified = %" PRIi64 "," \ " description = %Q, time_modified = %" PRIi64 "," \
" db_timestamp = %" PRIi64 ", sample_count = %" PRIi64 "," \ " db_timestamp = %" PRIi64 ", disabled = %" PRIi64 ", sample_count = %" PRIi64 "," \
" codectype = %Q, idx = %d, has_video = %d," \ " codectype = %Q, idx = %d, has_video = %d," \
" bits_per_sample = %d, album_artist = TRIM(%Q)," \ " bits_per_sample = %d, album_artist = TRIM(%Q)," \
" media_kind = %d, tv_series_name = TRIM(%Q), tv_episode_num_str = TRIM(%Q)," \ " media_kind = %d, tv_series_name = TRIM(%Q), tv_episode_num_str = TRIM(%Q)," \
@ -2500,7 +2500,7 @@ db_file_update(struct media_file_info *mfi)
mfi->year, mfi->track, mfi->total_tracks, mfi->disc, mfi->total_discs, mfi->bpm, mfi->year, mfi->track, mfi->total_tracks, mfi->disc, mfi->total_discs, mfi->bpm,
mfi->compilation, mfi->artwork, mfi->rating, mfi->seek, mfi->data_kind, mfi->item_kind, mfi->compilation, mfi->artwork, mfi->rating, mfi->seek, mfi->data_kind, mfi->item_kind,
mfi->description, (int64_t)mfi->time_modified, mfi->description, (int64_t)mfi->time_modified,
(int64_t)mfi->db_timestamp, mfi->sample_count, (int64_t)mfi->db_timestamp, (int64_t)mfi->disabled, mfi->sample_count,
mfi->codectype, mfi->index, mfi->has_video, mfi->codectype, mfi->index, mfi->has_video,
mfi->bits_per_sample, mfi->album_artist, mfi->bits_per_sample, mfi->album_artist,
mfi->media_kind, mfi->tv_series_name, mfi->tv_episode_num_str, mfi->media_kind, mfi->tv_series_name, mfi->tv_episode_num_str,
@ -3170,7 +3170,7 @@ db_pl_add_item_byid(int plid, int fileid)
int int
db_pl_update(char *title, char *path, int id) db_pl_update(char *title, char *path, int id)
{ {
#define Q_TMPL "UPDATE playlists SET title = '%q', db_timestamp = %" PRIi64 ", path = '%q' WHERE id = %d;" #define Q_TMPL "UPDATE playlists SET title = '%q', db_timestamp = %" PRIi64 ", disabled = 0, path = '%q' WHERE id = %d;"
char *query; char *query;
char *errmsg; char *errmsg;
int ret; int ret;
@ -3949,11 +3949,9 @@ db_watch_delete_bycookie(uint32_t cookie)
#undef Q_TMPL #undef Q_TMPL
} }
int static int
db_watch_get_bywd(struct watch_info *wi) db_watch_get_byquery(struct watch_info *wi, char *query)
{ {
#define Q_TMPL "SELECT * FROM inotify WHERE wd = %d;"
char *query;
sqlite3_stmt *stmt; sqlite3_stmt *stmt;
char **strval; char **strval;
char *cval; char *cval;
@ -3963,13 +3961,6 @@ db_watch_get_bywd(struct watch_info *wi)
int i; int i;
int ret; int ret;
query = sqlite3_mprintf(Q_TMPL, wi->wd);
if (!query)
{
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
return -1;
}
DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query); DPRINTF(E_DBG, L_DB, "Running query '%s'\n", query);
ret = db_blocking_prepare_v2(query, -1, &stmt, NULL); ret = db_blocking_prepare_v2(query, -1, &stmt, NULL);
@ -3982,7 +3973,7 @@ db_watch_get_bywd(struct watch_info *wi)
ret = db_blocking_step(stmt); ret = db_blocking_step(stmt);
if (ret != SQLITE_ROW) if (ret != SQLITE_ROW)
{ {
DPRINTF(E_LOG, L_DB, "Watch wd %d not found\n", wi->wd); DPRINTF(E_WARN, L_DB, "Watch not found: '%s'\n", query);
sqlite3_finalize(stmt); sqlite3_finalize(stmt);
sqlite3_free(query); sqlite3_free(query);
@ -4041,7 +4032,39 @@ db_watch_get_bywd(struct watch_info *wi)
sqlite3_free(query); sqlite3_free(query);
return 0; return 0;
}
int
db_watch_get_bywd(struct watch_info *wi)
{
#define Q_TMPL "SELECT * FROM inotify WHERE wd = %d;"
char *query;
query = sqlite3_mprintf(Q_TMPL, wi->wd);
if (!query)
{
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
return -1;
}
return db_watch_get_byquery(wi, query);
#undef Q_TMPL
}
int
db_watch_get_bypath(struct watch_info *wi)
{
#define Q_TMPL "SELECT * FROM inotify WHERE path = '%q';"
char *query;
query = sqlite3_mprintf(Q_TMPL, wi->path);
if (!query)
{
DPRINTF(E_LOG, L_DB, "Out of memory for query string\n");
return -1;
}
return db_watch_get_byquery(wi, query);
#undef Q_TMPL #undef Q_TMPL
} }

View File

@ -512,6 +512,9 @@ db_watch_delete_bycookie(uint32_t cookie);
int int
db_watch_get_bywd(struct watch_info *wi); db_watch_get_bywd(struct watch_info *wi);
int
db_watch_get_bypath(struct watch_info *wi);
void void
db_watch_mark_bypath(char *path, char *strip, uint32_t cookie); db_watch_mark_bypath(char *path, char *strip, uint32_t cookie);

View File

@ -897,7 +897,7 @@ process_directory(char *path, int flags)
#if defined(__linux__) #if defined(__linux__)
/* Add inotify watch */ /* Add inotify watch */
wi.wd = inotify_add_watch(inofd, path, IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF); wi.wd = inotify_add_watch(inofd, path, IN_ATTRIB | IN_CREATE | IN_DELETE | IN_CLOSE_WRITE | IN_MOVE | IN_DELETE | IN_MOVE_SELF);
if (wi.wd < 0) if (wi.wd < 0)
{ {
DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno)); DPRINTF(E_WARN, L_SCAN, "Could not create inotify watch for %s: %s\n", path, strerror(errno));
@ -1111,16 +1111,47 @@ filescanner(void *arg)
#if defined(__linux__) #if defined(__linux__)
static int
watches_clear(uint32_t wd, char *path)
{
struct watch_enum we;
uint32_t rm_wd;
int ret;
inotify_rm_watch(inofd, wd);
db_watch_delete_bywd(wd);
memset(&we, 0, sizeof(struct watch_enum));
we.match = path;
ret = db_watch_enum_start(&we);
if (ret < 0)
return -1;
while ((db_watch_enum_fetchwd(&we, &rm_wd) == 0) && (rm_wd))
{
inotify_rm_watch(inofd, rm_wd);
}
db_watch_enum_end(&we);
db_watch_delete_bymatch(path);
return 0;
}
/* Thread: scan */ /* Thread: scan */
static void static void
process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie) process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
{ {
struct watch_enum we; struct watch_enum we;
uint32_t rm_wd; uint32_t rm_wd;
char *s;
int flags = 0; int flags = 0;
int ret; int ret;
DPRINTF(E_DBG, L_SCAN, "Directory event: 0x%x, cookie 0x%x, wd %d\n", ie->mask, ie->cookie, wi->wd); DPRINTF(E_SPAM, L_SCAN, "Directory event: 0x%x, cookie 0x%x, wd %d\n", ie->mask, ie->cookie, wi->wd);
if (ie->mask & IN_UNMOUNT) if (ie->mask & IN_UNMOUNT)
{ {
@ -1165,26 +1196,10 @@ process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
* and we can't tell where it's going * and we can't tell where it's going
*/ */
inotify_rm_watch(inofd, ie->wd); ret = watches_clear(ie->wd, path);
db_watch_delete_bywd(ie->wd);
memset(&we, 0, sizeof(struct watch_enum));
we.match = path;
ret = db_watch_enum_start(&we);
if (ret < 0) if (ret < 0)
return; return;
while ((db_watch_enum_fetchwd(&we, &rm_wd) == 0) && (rm_wd))
{
inotify_rm_watch(inofd, rm_wd);
}
db_watch_enum_end(&we);
db_watch_delete_bymatch(path);
db_file_disable_bymatch(path, "", 0); db_file_disable_bymatch(path, "", 0);
db_pl_disable_bymatch(path, "", 0); db_pl_disable_bymatch(path, "", 0);
} }
@ -1213,6 +1228,40 @@ process_inotify_dir(struct watch_info *wi, char *path, struct inotify_event *ie)
ie->mask |= IN_CREATE; ie->mask |= IN_CREATE;
} }
if (ie->mask & IN_ATTRIB)
{
DPRINTF(E_DBG, L_SCAN, "Directory permissions changed (%s): %s\n", wi->path, path);
// Find out if we are already watching the dir (ret will be 0)
s = wi->path;
wi->path = path;
ret = db_watch_get_bypath(wi);
if (ret == 0)
free(wi->path);
wi->path = s;
if (euidaccess(path, (R_OK | X_OK)) < 0)
{
DPRINTF(E_LOG, L_SCAN, "Directory access to '%s' failed: %s\n", path, strerror(errno));
if (ret == 0)
watches_clear(wi->wd, path);
db_file_disable_bymatch(path, "", 0);
db_pl_disable_bymatch(path, "", 0);
}
else if (ret < 0)
{
DPRINTF(E_LOG, L_SCAN, "Directory access to '%s' achieved\n", path);
ie->mask |= IN_CREATE;
}
else
{
DPRINTF(E_INFO, L_SCAN, "Directory event, but '%s' already being watched\n", path);
}
}
if (ie->mask & IN_CREATE) if (ie->mask & IN_CREATE)
{ {
process_directories(path, flags); process_directories(path, flags);
@ -1237,6 +1286,7 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
if (ie->mask & IN_DELETE) if (ie->mask & IN_DELETE)
{ {
DPRINTF(E_DBG, L_SCAN, "File deleted: %s\n", path); DPRINTF(E_DBG, L_SCAN, "File deleted: %s\n", path);
db_file_delete_bypath(path); db_file_delete_bypath(path);
db_pl_delete_bypath(path); db_pl_delete_bypath(path);
} }
@ -1244,13 +1294,33 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
if (ie->mask & IN_MOVED_FROM) if (ie->mask & IN_MOVED_FROM)
{ {
DPRINTF(E_DBG, L_SCAN, "File moved from: %s\n", path); DPRINTF(E_DBG, L_SCAN, "File moved from: %s\n", path);
db_file_disable_bypath(path, path, ie->cookie); db_file_disable_bypath(path, path, ie->cookie);
db_pl_disable_bypath(path, path, ie->cookie); db_pl_disable_bypath(path, path, ie->cookie);
} }
if (ie->mask & IN_ATTRIB)
{
DPRINTF(E_DBG, L_SCAN, "File permissions changed: %s\n", path);
if (euidaccess(path, R_OK) < 0)
{
DPRINTF(E_LOG, L_SCAN, "File access to '%s' failed: %s\n", path, strerror(errno));
db_file_delete_bypath(path);;
}
else if (db_file_id_bypath(path) <= 0)
{
DPRINTF(E_LOG, L_SCAN, "File access to '%s' achieved\n", path);
ie->mask |= IN_CLOSE_WRITE;
}
}
if (ie->mask & IN_MOVED_TO) if (ie->mask & IN_MOVED_TO)
{ {
DPRINTF(E_DBG, L_SCAN, "File moved to: %s\n", path); DPRINTF(E_DBG, L_SCAN, "File moved to: %s\n", path);
ret = db_file_enable_bycookie(ie->cookie, path); ret = db_file_enable_bycookie(ie->cookie, path);
if (ret <= 0) if (ret <= 0)
@ -1268,6 +1338,7 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
if (ie->mask & IN_CREATE) if (ie->mask & IN_CREATE)
{ {
DPRINTF(E_DBG, L_SCAN, "File created: %s\n", path); DPRINTF(E_DBG, L_SCAN, "File created: %s\n", path);
ret = lstat(path, &sb); ret = lstat(path, &sb);
if (ret < 0) if (ret < 0)
{ {
@ -1283,6 +1354,7 @@ process_inotify_file(struct watch_info *wi, char *path, struct inotify_event *ie
if (ie->mask & IN_CLOSE_WRITE) if (ie->mask & IN_CLOSE_WRITE)
{ {
DPRINTF(E_DBG, L_SCAN, "File closed: %s\n", path); DPRINTF(E_DBG, L_SCAN, "File closed: %s\n", path);
ret = lstat(path, &sb); ret = lstat(path, &sb);
if (ret < 0) if (ret < 0)
{ {