2017-03-30 Fred Gleason <fredg@paravelsystems.com>

* Added '--relink-audio' and '--relink-audio-move' commands to
	rddbcheck(8) in 'utils/rddbcheck.cpp' and 'utils/rddbcheck.h'.
This commit is contained in:
Fred Gleason 2017-03-30 10:06:35 -04:00
parent 4342ccd01e
commit 36fa10802a
4 changed files with 177 additions and 3 deletions

View File

@ -15678,3 +15678,6 @@
2017-03-29 Fred Gleason <fredg@paravelsystems.com>
* Modified rddbcheck(8) so as to process a --rehash command after
the inexpensive checks.
2017-03-30 Fred Gleason <fredg@paravelsystems.com>
* Added '--relink-audio' and '--relink-audio-move' commands to
rddbcheck(8) in 'utils/rddbcheck.cpp' and 'utils/rddbcheck.h'.

View File

@ -6,7 +6,7 @@
<refmeta>
<refentrytitle>rddbcheck</refentrytitle>
<manvolnum>8</manvolnum>
<refmiscinfo class='source'>June 2016</refmiscinfo>
<refmiscinfo class='source'>March 2017</refmiscinfo>
<refmiscinfo class='manual'>Linux Audio Manual</refmiscinfo>
</refmeta>
<refnamediv>
@ -47,7 +47,7 @@
</para>
</refsect1>
<refsect1 id='general_options'><title>Options</title>
<refsect1 id='consistency_check_options'><title>Consistency Check Options</title>
<variablelist remap='TP'>
<varlistentry>
<term>
@ -159,9 +159,40 @@
</para>
</listitem>
</varlistentry>
</variablelist>
<refsect1 id='audio_recovery_options'><title>Audio Recovery Options</title>
<variablelist remap='TP'>
<varlistentry>
<term>
<option>--relink-audio=</option><replaceable>dir-name</replaceable>
</term>
<listitem>
<para>
Scan the files in the directory <replaceable>dir-name</replaceable>
and copy/rename them into the Rivendell audio store if their SHA-1
hash matches that for one or more Rivendell cuts.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<option>--relink-audio-move</option>
</term>
<listitem>
<para>
When given along with <option>--relink-audio</option>, move the
audio data to the Rivendell audio store rather than copying it
--i.e. copy the audio data, then delete the original.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id='see_also'><title>See Also</title>
<para>
<citerefentry>

View File

@ -20,10 +20,13 @@
#include <limits.h>
#include <glob.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <math.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <qapplication.h>
@ -57,6 +60,8 @@ MainObject::MainObject(QObject *parent)
check_yes=false;
check_no=false;
QString username="user";
relink_audio="";
relink_audio_move=false;
//
// Read Command Options
@ -82,6 +87,12 @@ MainObject::MainObject(QObject *parent)
if(cmd->key(i)=="--dump-cuts-dir") {
dump_cuts_dir=cmd->value(i);
}
if(cmd->key(i)=="--relink-audio") {
relink_audio=cmd->value(i);
}
if(cmd->key(i)=="--relink-audio-move") {
relink_audio_move=true;
}
if(cmd->key(i)=="--rehash") {
rehash=cmd->value(i);
}
@ -174,6 +185,14 @@ MainObject::MainObject(QObject *parent)
delete q;
}
//
// Recover Audio
//
if(!relink_audio.isEmpty()) {
RelinkAudio(relink_audio);
exit(0);
}
//
// Check for Orphaned Voice Tracks
//
@ -785,6 +804,83 @@ void MainObject::RehashCut(const QString &cutnum)
}
void MainObject::RelinkAudio(const QString &srcdir)
{
QString sql;
RDSqlQuery *q;
QDir dir(srcdir);
if(!dir.exists()) {
fprintf(stderr,"rddbcheck: --relink-audio directory does not exist\n");
exit(256);
}
QStringList files=dir.entryList(QDir::Files|QDir::Readable|QDir::Hidden);
for(unsigned i=0;i<files.size();i++) {
QString filename=dir.path()+"/"+files[i];
QString hash=RDSha1Hash(filename);
QString firstdest;
bool delete_source=true;
sql=QString("select CUTS.CUT_NAME,CART.TITLE from ")+
"CUTS left join CART "+
"on CUTS.CART_NUMBER=CART.NUMBER where "+
"CUTS.SHA1_HASH=\""+RDEscapeString(hash)+"\"";
q=new RDSqlQuery(sql);
while(q->next()) {
printf(" Recovering %06u/%03d [%s]...",
RDCut::cartNumber(q->value(0).toString()),
RDCut::cutNumber(q->value(0).toString()),
(const char *)q->value(1).toString());
fflush(stdout);
if(relink_audio_move) {
unlink(RDCut::pathName(q->value(0).toString()));
if(link(filename,RDCut::pathName(q->value(0).toString()))<0) {
if(errno==EXDEV) {
if(firstdest.isEmpty()) {
if(CopyFile(RDCut::pathName(q->value(0).toString()),filename)) {
firstdest=RDCut::pathName(q->value(0).toString());
}
else {
fprintf(stderr,"unable to copy file \"%s\"\n",
(const char *)filename);
delete_source=false;
}
}
else {
unlink(RDCut::pathName(q->value(0).toString()));
link(firstdest,RDCut::pathName(q->value(0).toString()));
}
}
else {
fprintf(stderr,"unable to move file \"%s\" [%s]\n",
(const char *)filename,strerror(errno));
delete_source=false;
}
}
}
else {
if(firstdest.isEmpty()) {
if(CopyFile(RDCut::pathName(q->value(0).toString()),filename)) {
firstdest=RDCut::pathName(q->value(0).toString());
}
else {
fprintf(stderr,"unable to copy file \"%s\"\n",
(const char *)filename);
}
}
else {
unlink(RDCut::pathName(q->value(0).toString()));
link(firstdest,RDCut::pathName(q->value(0).toString()));
}
}
printf(" done.\n");
}
if(relink_audio_move&&delete_source) {
unlink(filename);
}
}
}
void MainObject::SetCutLength(const QString &cutname,int len)
{
QString sql;
@ -883,6 +979,46 @@ bool MainObject::IsTableLinked(QSqlQuery *name_q,const QString &ext,
}
bool MainObject::CopyFile(const QString &destfile,const QString &srcfile) const
{
int src_fd=-1;
struct stat src_stat;
int dest_fd=-1;
struct stat dest_stat;
int n;
int blksize;
char *data=NULL;
if((src_fd=open(srcfile,O_RDONLY))<0) {
return false;
}
fstat(src_fd,&src_stat);
mode_t mask=umask(S_IRWXO);
if((dest_fd=open(destfile,O_WRONLY|O_CREAT|O_TRUNC,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP))<0) {
close(src_fd);
return false;
}
umask(mask);
fstat(dest_fd,&dest_stat);
blksize=src_stat.st_blksize;
if(dest_stat.st_blksize<blksize) {
blksize=dest_stat.st_blksize;
}
data=(char *)malloc(blksize);
while((n=read(src_fd,data,blksize))!=0) {
write(dest_fd,data,n);
}
free(data);
fchown(dest_fd,150,150); // FIXME: do name lookup!
close(dest_fd);
close(src_fd);
return true;
}
bool MainObject::UserResponse()
{
char c=0;

View File

@ -57,10 +57,12 @@ class MainObject : public QObject
void Rehash(const QString &arg);
void RehashCart(unsigned cartnum);
void RehashCut(const QString &cutnum);
void RelinkAudio(const QString &srcdir);
void SetCutLength(const QString &cutname,int len);
void CleanTables(const QString &ext,QSqlQuery *table_q,QSqlQuery *name_q);
void CleanTables(const QString &ext,QSqlQuery *table_q);
bool IsTableLinked(QSqlQuery *name_q,const QString &ext,const QString &table);
bool CopyFile(const QString &destfile,const QString &srcfile) const;
bool UserResponse();
bool check_yes;
bool check_no;
@ -69,6 +71,8 @@ class MainObject : public QObject
QString rehash;
RDStation *check_station;
RDUser *check_user;
QString relink_audio;
bool relink_audio_move;
};