From 4d334ac5a7da5f8fbbafe41c4ca005dd7b41b54c Mon Sep 17 00:00:00 2001 From: Stian Skjelstad Date: Wed, 4 Dec 2024 08:33:47 +0100 Subject: [PATCH] When filebrowser is scanning archive and one or more of the files needs to be probed, keep one of them in an open state until the scan is complete. This avoids the archive closing its io-file handle due reference count falling to zero if the archive directory listing was cached in ADB. --- filesel/mdb.c | 10 +++++-- filesel/mdb.h | 2 +- filesel/modlist.c | 4 +-- filesel/modlist.h | 2 +- filesel/pfilesel.c | 57 ++++++++++++++++++++++++++-------------- medialib/medialib-scan.c | 15 ++++++++++- 6 files changed, 64 insertions(+), 26 deletions(-) diff --git a/filesel/mdb.c b/filesel/mdb.c index 426c5c61..4a878dc8 100644 --- a/filesel/mdb.c +++ b/filesel/mdb.c @@ -493,7 +493,8 @@ int mdbWriteModuleInfo (uint32_t mdb_ref, struct moduleinfostruct *m) return !retval; } -void mdbScan (struct ocpfile_t *file, uint32_t mdb_ref) +/* if retain is non-zero, do not unref filehandle, but pass it to caller when done */ +void mdbScan (struct ocpfile_t *file, uint32_t mdb_ref, struct ocpfilehandle_t **retain) { DEBUG_PRINT ("mdbScan(file=%p, mdb_ref=0x%08"PRIx32")\n", file, mdb_ref); assert (mdb_ref > 0); @@ -519,7 +520,12 @@ void mdbScan (struct ocpfile_t *file, uint32_t mdb_ref) } mdbGetModuleInfo(&mdbEditBuf, mdb_ref); mdbReadInfo(&mdbEditBuf, f); - f->unref (f); + if (retain) + { + *retain = f; + } else { + f->unref (f); + } mdbWriteModuleInfo(mdb_ref, &mdbEditBuf); } } diff --git a/filesel/mdb.h b/filesel/mdb.h index 9ce707d0..a9de0cc9 100644 --- a/filesel/mdb.h +++ b/filesel/mdb.h @@ -79,7 +79,7 @@ int mdbGetModuleType (uint32_t fileref, struct moduletype *dst); int mdbInfoIsAvailable (uint32_t fileref); // used to be mdbInfoRead int mdbReadInfo(struct moduleinfostruct *m, struct ocpfilehandle_t *f); int mdbWriteModuleInfo(uint32_t fileref, struct moduleinfostruct *m); // returns zero on error -void mdbScan(struct ocpfile_t *file, uint32_t mdb_ref); +void mdbScan(struct ocpfile_t *file, uint32_t mdb_ref, struct ocpfilehandle_t **retain); // if retain is non-zero, do not unref filehandle, but pass it to caller int mdbInit (const struct configAPI_t *configAPI); // returns zero on error void mdbUpdate(void); void mdbClose(void); diff --git a/filesel/modlist.c b/filesel/modlist.c index 7250e232..67b76ede 100644 --- a/filesel/modlist.c +++ b/filesel/modlist.c @@ -185,7 +185,7 @@ void modlist_append_drive (struct modlist *modlist, struct dmDrive *drive) modlist_append (modlist, &entry); } -void modlist_append_file (struct modlist *modlist, struct ocpfile_t *file, int ismod, int prescanhint) +void modlist_append_file (struct modlist *modlist, struct ocpfile_t *file, int ismod, int prescanhint, struct ocpfilehandle_t **retain) { struct modlistentry entry = {{0}}; const char *childpath = 0; @@ -216,7 +216,7 @@ void modlist_append_file (struct modlist *modlist, struct ocpfile_t *file, int i { if (prescanhint && (!mdbInfoIsAvailable(entry.mdb_ref))) { - mdbScan (file, entry.mdb_ref); + mdbScan (file, entry.mdb_ref, retain); entry.flags |= MODLIST_FLAG_SCANNED; } } diff --git a/filesel/modlist.h b/filesel/modlist.h index c01c798c..4c8380fe 100644 --- a/filesel/modlist.h +++ b/filesel/modlist.h @@ -42,7 +42,7 @@ void modlist_append(struct modlist *modlist, struct modlistentry *entry); void modlist_append_dir (struct modlist *modlist, struct ocpdir_t *dir); void modlist_append_dotdot (struct modlist *modlist, struct ocpdir_t *dir); void modlist_append_drive (struct modlist *modlist, struct dmDrive *drive); -void modlist_append_file (struct modlist *modlist, struct ocpfile_t *file, int ismod, int prescanhint); /* if file is stored SOLID, trigger a mdb scan if needed */ +void modlist_append_file (struct modlist *modlist, struct ocpfile_t *file, int ismod, int prescanhint, struct ocpfilehandle_t **retain); /* if file is stored SOLID, trigger a mdb scan if needed */ void modlist_swap(struct modlist *modlist, unsigned int index1, unsigned int index2); void modlist_clear(struct modlist *modlist); diff --git a/filesel/pfilesel.c b/filesel/pfilesel.c index 3c887fc7..11fd457f 100644 --- a/filesel/pfilesel.c +++ b/filesel/pfilesel.c @@ -133,6 +133,8 @@ struct fsReadDir_token_t int cancel_recursive; char *parent_displaydir; + + struct ocpfilehandle_t *fileretain; /* hack to keep one file open in archives, to ensure they remain open while scanning their content */ }; static void fsReadDir_file (void *_token, struct ocpfile_t *file) @@ -172,11 +174,6 @@ static void fsReadDir_file (void *_token, struct ocpfile_t *file) { unsigned int mlTop=plScrHeight/2-2; unsigned int i; - char *oldparent_displaydir; - - /* store the callers directory - we might be running recursive */ - oldparent_displaydir = token->parent_displaydir; - token->parent_displaydir = 0; /* draw a box and information to the display... resize of the display will not be gracefull during a directory scan */ displayvoid(mlTop+1, 5, plScrWidth-10); @@ -202,13 +199,17 @@ static void fsReadDir_file (void *_token, struct ocpfile_t *file) displaystr(mlTop+4, plScrWidth-5, 0x04, "\xd9", 1); } displaystr (mlTop + 1, 5, 0x09, "Scanning content of the given file. Press space to cancel", plScrWidth - 10); - dirdbGetFullname_malloc (dir->dirdb_ref, &token->parent_displaydir, DIRDB_FULLNAME_ENDSLASH); - displaystr_utf8_overflowleft (mlTop + 3, 5, 0x0a, token->parent_displaydir, plScrWidth - 10); + { /* do the actual scan */ + struct fsReadDir_token_t innertoken = *token; + innertoken.parent_displaydir = 0; + innertoken.fileretain = 0; - { /* do the actual scan */ - ocpdirhandle_pt dh = dir->readflatdir_start (dir, fsReadDir_file, token); /* recycle the same token... */ - while (dir->readdir_iterate (dh) && (!token->cancel_recursive)) + dirdbGetFullname_malloc (dir->dirdb_ref, &innertoken.parent_displaydir, DIRDB_FULLNAME_ENDSLASH); + displaystr_utf8_overflowleft (mlTop + 3, 5, 0x0a, innertoken.parent_displaydir, plScrWidth - 10); + + ocpdirhandle_pt dh = dir->readflatdir_start (dir, fsReadDir_file, &innertoken); + while (dir->readdir_iterate (dh) && (!innertoken.cancel_recursive)) { if (poll_framelock()) { @@ -217,7 +218,7 @@ static void fsReadDir_file (void *_token, struct ocpfile_t *file) int key = Console.KeyboardGetChar(); if ((key == ' ') || (key == KEY_EXIT)) { - token->cancel_recursive = 1; + innertoken.cancel_recursive = 1; } if (key == VIRT_KEY_RESIZE) { @@ -227,11 +228,18 @@ static void fsReadDir_file (void *_token, struct ocpfile_t *file) } } } + + free (innertoken.parent_displaydir); + if (innertoken.fileretain) + { + innertoken.fileretain->unref (innertoken.fileretain); + innertoken.fileretain = 0; + } + token->cancel_recursive |= innertoken.cancel_recursive; dir->readdir_cancel (dh); } /* undo the filename displayed */ - free (token->parent_displaydir); token->parent_displaydir = oldparent_displaydir; if (token->parent_displaydir) { displaystr_utf8_overflowleft (mlTop + 3, 5, 0x0a, token->parent_displaydir, plScrWidth - 10); @@ -284,7 +292,7 @@ static void fsReadDir_file (void *_token, struct ocpfile_t *file) if (ismod || // always include if file is an actual module (fsShowAllFiles && (!(token->opt & RD_ISMODONLY)))) // force include if fsShowAllFiles is true, except if RD_ISMODONLY { - modlist_append_file (token->ml, file, ismod, file->compression >= COMPRESSION_SOLID && (file->compression < COMPRESSION_REMOTE)); /* modlist_append() will do refcount on the file */ + modlist_append_file (token->ml, file, ismod, file->compression >= COMPRESSION_SOLID && (file->compression < COMPRESSION_REMOTE), token->fileretain ? 0 : &token->fileretain); /* modlist_append() will do refcount on the file */ } out: free (curext); @@ -342,6 +350,7 @@ int fsReadDir (struct modlist *ml, struct ocpdir_t *dir, const char *mask, unsig token.mask = (char *)mask; #endif token.opt = opt & ~(RD_SUBSORT); + token.fileretain = 0; if ((opt & RD_PUTRSUBS) && dir->readflatdir_start) { @@ -355,6 +364,11 @@ int fsReadDir (struct modlist *ml, struct ocpdir_t *dir, const char *mask, unsig #ifndef FNM_CASEFOLD free (token.mask); #endif + if (token.fileretain) + { + token.fileretain->unref (token.fileretain); + token.fileretain = 0; + } return 0; } while (dir->readdir_iterate (dh)) @@ -377,6 +391,11 @@ int fsReadDir (struct modlist *ml, struct ocpdir_t *dir, const char *mask, unsig #ifndef FNM_CASEFOLD free (token.mask); #endif + if (token.fileretain) + { + token.fileretain->unref (token.fileretain); + token.fileretain = 0; + } if (opt & RD_SUBSORT) { @@ -520,7 +539,7 @@ static void addfiles_file (void *token, struct ocpfile_t *file) } if (fsIsModule(curext)) { - modlist_append_file (playlist, file, 1, 0); /* modlist_append calls file->ref (file); for us */ + modlist_append_file (playlist, file, 1, 0, 0); /* modlist_append calls file->ref (file); for us */ } free (curext); } @@ -3299,7 +3318,7 @@ signed int fsFileSelect(void) int poll = 1; if ((m->file && (m->file->compression < COMPRESSION_REMOTE) && (m->flags & MODLIST_FLAG_ISMOD)) && (!mdbInfoIsAvailable(m->mdb_ref)) && (!(m->flags&MODLIST_FLAG_SCANNED))) { - mdbScan(m->file, m->mdb_ref); + mdbScan(m->file, m->mdb_ref, 0); m->flags |= MODLIST_FLAG_SCANNED; } @@ -3312,7 +3331,7 @@ signed int fsFileSelect(void) { if (!mdbInfoIsAvailable(scanm->mdb_ref)) { - mdbScan(scanm->file, scanm->mdb_ref); + mdbScan(scanm->file, scanm->mdb_ref, 0); scanm->flags |= MODLIST_FLAG_SCANNED; if (poll_framelock()) @@ -3333,7 +3352,7 @@ signed int fsFileSelect(void) { if (!mdbInfoIsAvailable(scanm->mdb_ref)) { - mdbScan(scanm->file, scanm->mdb_ref); + mdbScan(scanm->file, scanm->mdb_ref, 0); scanm->flags |= MODLIST_FLAG_SCANNED; if (poll_framelock()) @@ -3470,7 +3489,7 @@ signed int fsFileSelect(void) mdbEditBuf.modtype.integer.i = mtUnRead; if (!mdbWriteModuleInfo(m->mdb_ref, &mdbEditBuf)) return -1; - mdbScan(m->file, m->mdb_ref); + mdbScan(m->file, m->mdb_ref, 0); m->flags |= MODLIST_FLAG_SCANNED; } break; @@ -3539,7 +3558,7 @@ signed int fsFileSelect(void) /* We delay mdbScan for remote files until this stage */ if (m && m->file && (m->file->compression >= COMPRESSION_REMOTE) && !(m->flags & MODLIST_FLAG_SCANNED)) { - mdbScan (m->file, m->mdb_ref); + mdbScan (m->file, m->mdb_ref, 0); m->flags |= MODLIST_FLAG_SCANNED; } if (win) diff --git a/medialib/medialib-scan.c b/medialib/medialib-scan.c index aa4c2f8f..cc5058a8 100644 --- a/medialib/medialib-scan.c +++ b/medialib/medialib-scan.c @@ -29,6 +29,7 @@ struct scanlist_t int entries; int size; int abort; + struct ocpfilehandle_t *retain; /* hack to keep one file open in archives, to ensure they remain open while scanning their content */ }; static void mlScanDraw(const char *title, struct scanlist_t *token) @@ -193,7 +194,7 @@ static void mlScan_file (void *_token, struct ocpfile_t *file) mdbref = mdbGetModuleReference2 (file->dirdb_ref, file->filesize(file)); if (!mdbInfoIsAvailable (mdbref)) { - mdbScan(file, mdbref); + mdbScan(file, mdbref, token->retain ? 0 : &token->retain); } dirdbMakeMdbRef(file->dirdb_ref, mdbref); @@ -231,6 +232,11 @@ static int mlScan(struct ocpdir_t *dir) if (!handle) { free (token.path); + if (token.retain) + { + token.retain->unref (token.retain); + token.retain = 0; + } return 0; } while (dir->readdir_iterate (handle) && (!token.abort)) @@ -249,5 +255,12 @@ static int mlScan(struct ocpdir_t *dir) free (token.files); free (token.path); + + if (token.retain) + { + token.retain->unref (token.retain); + token.retain = 0; + } + return token.abort; }