MythTV  0.26-pre
fileringbuffer.cpp
Go to the documentation of this file.
00001 #include <cstdlib>
00002 #include <cerrno>
00003 
00004 // POSIX C headers
00005 #include <sys/types.h>
00006 #include <sys/time.h>
00007 #include <unistd.h>
00008 #include <fcntl.h>
00009 
00010 #include <QFileInfo>
00011 #include <QDir>
00012 
00013 #include "ThreadedFileWriter.h"
00014 #include "fileringbuffer.h"
00015 #include "mythcontext.h"
00016 #include "remotefile.h"
00017 #include "mythconfig.h" // gives us HAVE_POSIX_FADVISE
00018 #include "compat.h"
00019 #include "mythmiscutil.h"
00020 
00021 #if HAVE_POSIX_FADVISE < 1
00022 static int posix_fadvise(int, off_t, off_t, int) { return 0; }
00023 #define POSIX_FADV_SEQUENTIAL 0
00024 #define POSIX_FADV_WILLNEED 0
00025 #define POSIX_FADV_DONTNEED 0
00026 #endif
00027 
00028 #ifndef O_STREAMING
00029 #define O_STREAMING 0
00030 #endif
00031 
00032 #ifndef O_LARGEFILE
00033 #define O_LARGEFILE 0
00034 #endif
00035 
00036 #ifndef O_BINARY
00037 #define O_BINARY 0
00038 #endif
00039 
00040 #define LOC      QString("FileRingBuf(%1): ").arg(filename)
00041 
00042 FileRingBuffer::FileRingBuffer(const QString &lfilename,
00043                                bool write, bool readahead, int timeout_ms)
00044   : RingBuffer(kRingBuffer_File)
00045 {
00046     startreadahead = readahead;
00047     safefilename = lfilename;
00048     filename = lfilename;
00049 
00050     if (write)
00051     {
00052         if (filename.startsWith("myth://"))
00053         {
00054             remotefile = new RemoteFile(filename, true);
00055             if (!remotefile->isOpen())
00056             {
00057                 LOG(VB_GENERAL, LOG_ERR,
00058                     QString("RingBuffer::RingBuffer(): Failed to open "
00059                             "remote file (%1) for write").arg(filename));
00060                 delete remotefile;
00061                 remotefile = NULL;
00062             }
00063             else
00064                 writemode = true;
00065         }
00066         else
00067         {
00068             tfw = new ThreadedFileWriter(
00069                 filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644);
00070 
00071             if (!tfw->Open())
00072             {
00073                 delete tfw;
00074                 tfw = NULL;
00075             }
00076             else
00077                 writemode = true;
00078         }
00079     }
00080     else if (timeout_ms >= 0)
00081     {
00082         OpenFile(filename, timeout_ms);
00083     }
00084 }
00085 
00086 FileRingBuffer::~FileRingBuffer()
00087 {
00088     rwlock.lockForWrite();
00089 
00090     if (remotefile)
00091     {
00092         delete remotefile;
00093         remotefile = NULL;
00094     }
00095 
00096     if (tfw)
00097     {
00098         delete tfw;
00099         tfw = NULL;
00100     }
00101 
00102     if (fd2 >= 0)
00103     {
00104         close(fd2);
00105         fd2 = -1;
00106     }
00107 
00108     rwlock.unlock();
00109 }
00110 
00115 static bool check_permissions(const QString &filename)
00116 {
00117     QFileInfo fileInfo(filename);
00118     if (fileInfo.exists() && !fileInfo.isReadable())
00119     {
00120         LOG(VB_GENERAL, LOG_ERR, LOC +
00121                 "File exists but is not readable by MythTV!");
00122         return false;
00123     }
00124     return true;
00125 }
00126 
00127 static bool is_subtitle_possible(const QString &extension)
00128 {
00129     QMutexLocker locker(&RingBuffer::subExtLock);
00130     bool no_subtitle = false;
00131     for (uint i = 0; i < (uint)RingBuffer::subExtNoCheck.size(); i++)
00132     {
00133         if (extension.contains(RingBuffer::subExtNoCheck[i].right(3)))
00134         {
00135             no_subtitle = true;
00136             break;
00137         }
00138     }
00139     return !no_subtitle;
00140 }
00141 
00142 static QString local_sub_filename(QFileInfo &fileInfo)
00143 {
00144     // Subtitle handling
00145     QString vidFileName = fileInfo.fileName();
00146     QString dirName = fileInfo.absolutePath();
00147 
00148     QString baseName = vidFileName;
00149     int suffixPos = vidFileName.lastIndexOf(QChar('.'));
00150     if (suffixPos > 0)
00151         baseName = vidFileName.left(suffixPos);
00152 
00153     QStringList el;
00154     {
00155         // The dir listing does not work if the filename has the
00156         // following chars "[]()" so we convert them to the wildcard '?'
00157         const QString findBaseName = baseName
00158             .replace("[", "?")
00159             .replace("]", "?")
00160             .replace("(", "?")
00161             .replace(")", "?");
00162 
00163         QMutexLocker locker(&RingBuffer::subExtLock);
00164         QStringList::const_iterator eit = RingBuffer::subExt.begin();
00165         for (; eit != RingBuffer::subExt.end(); ++eit)
00166             el += findBaseName + *eit;
00167     }
00168 
00169     // Some Qt versions do not accept paths in the search string of
00170     // entryList() so we have to set the dir first
00171     QDir dir;
00172     dir.setPath(dirName);
00173 
00174     const QStringList candidates = dir.entryList(el);
00175 
00176     QStringList::const_iterator cit = candidates.begin();
00177     for (; cit != candidates.end(); ++cit)
00178     {
00179         QFileInfo fi(dirName + "/" + *cit);
00180         if (fi.exists() && (fi.size() >= kReadTestSize))
00181             return fi.absoluteFilePath();
00182     }
00183 
00184     return QString::null;
00185 }
00186 
00187 bool FileRingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
00188 {
00189     LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("OpenFile(%1, %2 ms)")
00190             .arg(lfilename).arg(retry_ms));
00191 
00192     rwlock.lockForWrite();
00193 
00194     filename = lfilename;
00195     safefilename = lfilename;
00196 
00197     if (remotefile)
00198     {
00199         delete remotefile;
00200         remotefile = NULL;
00201     }
00202 
00203     if (fd2 >= 0)
00204     {
00205         close(fd2);
00206         fd2 = -1;
00207     }
00208 
00209     bool is_local = 
00210         (filename.left(4) != "/dev") &&
00211         ((filename.left(1) == "/") || QFile::exists(filename));
00212 
00213     if (is_local)
00214     {
00215         char buf[kReadTestSize];
00216         int lasterror = 0;
00217 
00218         MythTimer openTimer;
00219         openTimer.start();
00220 
00221         uint openAttempts = 0;
00222         do
00223         {
00224             openAttempts++;
00225             lasterror = 0;
00226 
00227             fd2 = open(filename.toLocal8Bit().constData(),
00228                        O_RDONLY|O_LARGEFILE|O_STREAMING|O_BINARY);
00229 
00230             if (fd2 < 0)
00231             {
00232                 if (!check_permissions(filename))
00233                 {
00234                     lasterror = 3;
00235                     break;
00236                 }
00237 
00238                 lasterror = 1;
00239                 usleep(10 * 1000);
00240             }
00241             else
00242             {
00243                 int ret = read(fd2, buf, kReadTestSize);
00244                 if (ret != (int)kReadTestSize)
00245                 {
00246                     lasterror = 2;
00247                     close(fd2);
00248                     fd2 = -1;
00249                     if (oldfile)
00250                         break; // if it's an old file it won't grow..
00251                     usleep(10 * 1000);
00252                 }
00253                 else
00254                 {
00255                     if (0 == lseek(fd2, 0, SEEK_SET))
00256                     {
00257                         posix_fadvise(fd2, 0, 0,        POSIX_FADV_SEQUENTIAL);
00258                         posix_fadvise(fd2, 0, 128*1024, POSIX_FADV_WILLNEED);
00259                         lasterror = 0;
00260                         break;
00261                     }
00262                     lasterror = 4;
00263                     close(fd2);
00264                     fd2 = -1;
00265                 }
00266             }
00267         }
00268         while ((uint)openTimer.elapsed() < retry_ms);
00269 
00270         switch (lasterror)
00271         {
00272             case 0:
00273             {
00274                 QFileInfo fi(filename);
00275                 oldfile = fi.lastModified()
00276                     .secsTo(QDateTime::currentDateTime()) > 60;
00277                 QString extension = fi.completeSuffix().toLower();
00278                 if (is_subtitle_possible(extension))
00279                     subtitlefilename = local_sub_filename(fi);
00280                 break;
00281             }
00282             case 1:
00283                 LOG(VB_GENERAL, LOG_ERR, LOC +
00284                         QString("OpenFile(): Could not open."));
00285                 break;
00286             case 2:
00287                 LOG(VB_GENERAL, LOG_ERR, LOC +
00288                         QString("OpenFile(): File too small (%1B).")
00289                         .arg(QFileInfo(filename).size()));
00290                 break;
00291             case 3:
00292                 LOG(VB_GENERAL, LOG_ERR, LOC +
00293                         "OpenFile(): Improper permissions.");
00294                 break;
00295             case 4:
00296                 LOG(VB_GENERAL, LOG_ERR, LOC +
00297                         "OpenFile(): Cannot seek in file.");
00298                 break;
00299             default:
00300                 break;
00301         }
00302         LOG(VB_FILE, LOG_INFO, 
00303             LOC + QString("OpenFile() made %1 attempts in %2 ms")
00304                 .arg(openAttempts).arg(openTimer.elapsed()));
00305 
00306     }
00307     else
00308     {
00309         QString tmpSubName = filename;
00310         QString dirName  = ".";
00311 
00312         int dirPos = filename.lastIndexOf(QChar('/'));
00313         if (dirPos > 0)
00314         {
00315             tmpSubName = filename.mid(dirPos + 1);
00316             dirName = filename.left(dirPos);
00317         }
00318 
00319         QString baseName  = tmpSubName;
00320         QString extension = tmpSubName;
00321         QStringList auxFiles;
00322 
00323         int suffixPos = tmpSubName.lastIndexOf(QChar('.'));
00324         if (suffixPos > 0)
00325         {
00326             baseName = tmpSubName.left(suffixPos);
00327             extension = tmpSubName.right(suffixPos-1);
00328             if (is_subtitle_possible(extension))
00329             {
00330                 QMutexLocker locker(&subExtLock);
00331                 QStringList::const_iterator eit = subExt.begin();
00332                 for (; eit != subExt.end(); ++eit)
00333                     auxFiles += baseName + *eit;
00334             }
00335         }
00336 
00337         remotefile = new RemoteFile(filename, false, true,
00338                                     retry_ms, &auxFiles);
00339         if (!remotefile->isOpen())
00340         {
00341             LOG(VB_GENERAL, LOG_ERR, LOC +
00342                     QString("RingBuffer::RingBuffer(): Failed to open remote "
00343                             "file (%1)").arg(filename));
00344             delete remotefile;
00345             remotefile = NULL;
00346         }
00347         else
00348         {
00349             QStringList aux = remotefile->GetAuxiliaryFiles();
00350             if (aux.size())
00351                 subtitlefilename = dirName + "/" + aux[0];
00352         }
00353     }
00354 
00355     setswitchtonext = false;
00356     ateof = false;
00357     commserror = false;
00358     numfailures = 0;
00359 
00360     rawbitrate = 8000;
00361     CalcReadAheadThresh();
00362 
00363     bool ok = fd2 >= 0 || remotefile;
00364 
00365     rwlock.unlock();
00366 
00367     return ok;
00368 }
00369 
00370 bool FileRingBuffer::ReOpen(QString newFilename)
00371 {
00372     if (!writemode)
00373     {
00374         LOG(VB_GENERAL, LOG_ERR, LOC + "Tried to ReOpen a read only file.");
00375         return false;
00376     }
00377 
00378     bool result = false;
00379 
00380     rwlock.lockForWrite();
00381 
00382     if (tfw && tfw->ReOpen(newFilename))
00383         result = true;
00384     else if (remotefile && remotefile->ReOpen(newFilename))
00385         result = true;
00386 
00387     if (result)
00388     {
00389         filename = newFilename;
00390         poslock.lockForWrite();
00391         writepos = 0;
00392         poslock.unlock();
00393     }
00394 
00395     rwlock.unlock();
00396     return result;
00397 }
00398 
00399 bool FileRingBuffer::IsOpen(void) const
00400 {
00401     rwlock.lockForRead();
00402     bool ret = tfw || (fd2 > -1) || remotefile;
00403     rwlock.unlock();
00404     return ret;
00405 }
00406 
00418 int FileRingBuffer::safe_read(int fd, void *data, uint sz)
00419 {
00420     int ret;
00421     unsigned tot = 0;
00422     unsigned errcnt = 0;
00423     unsigned zerocnt = 0;
00424 
00425     if (fd2 < 0)
00426     {
00427         LOG(VB_GENERAL, LOG_ERR, LOC +
00428                 "Invalid file descriptor in 'safe_read()'");
00429         return 0;
00430     }
00431 
00432     if (stopreads)
00433         return 0;
00434 
00435     while (tot < sz)
00436     {
00437         ret = read(fd2, (char *)data + tot, sz - tot);
00438         if (ret < 0)
00439         {
00440             if (errno == EAGAIN)
00441                 continue;
00442 
00443             LOG(VB_GENERAL, LOG_ERR,
00444                 LOC + "File I/O problem in 'safe_read()'" + ENO);
00445 
00446             errcnt++;
00447             numfailures++;
00448             if (errcnt == 3)
00449                 break;
00450         }
00451         else if (ret > 0)
00452         {
00453             tot += ret;
00454         }
00455 
00456         if (oldfile)
00457             break;
00458 
00459         if (ret == 0) // EOF returns 0
00460         {
00461             if (tot > 0)
00462                 break;
00463 
00464             zerocnt++;
00465 
00466             // 0.36 second timeout for livetvchain with usleep(60000),
00467             // or 2.4 seconds if it's a new file less than 30 minutes old.
00468             if (zerocnt >= (livetvchain ? 6 : 40))
00469             {
00470                 break;
00471             }
00472         }
00473         if (stopreads)
00474             break;
00475         if (tot < sz)
00476             usleep(60000);
00477     }
00478     return tot;
00479 }
00480 
00489 int FileRingBuffer::safe_read(RemoteFile *rf, void *data, uint sz)
00490 {
00491     int ret = rf->Read(data, sz);
00492     if (ret < 0)
00493     {
00494         LOG(VB_GENERAL, LOG_ERR, LOC +
00495             "safe_read(RemoteFile* ...): read failed");
00496             
00497         poslock.lockForRead();
00498         rf->Seek(internalreadpos - readAdjust, SEEK_SET);
00499         poslock.unlock();
00500         numfailures++;
00501     }
00502     else if (ret == 0)
00503     {
00504         LOG(VB_FILE, LOG_INFO, LOC +
00505             "safe_read(RemoteFile* ...): at EOF");
00506     }
00507 
00508     return ret;
00509 }
00510 
00511 long long FileRingBuffer::GetReadPosition(void) const
00512 {
00513     poslock.lockForRead();
00514     long long ret = readpos;
00515     poslock.unlock();
00516     return ret;
00517 }
00518 
00519 long long FileRingBuffer::GetRealFileSize(void) const
00520 {
00521     rwlock.lockForRead();
00522     long long ret = -1;
00523     if (remotefile)
00524         ret = remotefile->GetFileSize();
00525     else
00526         ret = QFileInfo(filename).size();
00527     rwlock.unlock();
00528     return ret;
00529 }
00530 
00531 long long FileRingBuffer::Seek(long long pos, int whence, bool has_lock)
00532 {
00533     LOG(VB_FILE, LOG_INFO, LOC + QString("Seek(%1,%2,%3)")
00534             .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET":
00535                           ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END"))
00536             .arg(has_lock?"locked":"unlocked"));
00537 
00538     long long ret = -1;
00539 
00540     StopReads();
00541 
00542     // lockForWrite takes priority over lockForRead, so this will
00543     // take priority over the lockForRead in the read ahead thread.
00544     if (!has_lock)
00545         rwlock.lockForWrite();
00546 
00547     StartReads();
00548 
00549     if (writemode)
00550     {
00551         ret = WriterSeek(pos, whence, true);
00552         if (!has_lock)
00553             rwlock.unlock();
00554         return ret;
00555     }
00556 
00557     poslock.lockForWrite();
00558 
00559     // Optimize no-op seeks
00560     if (readaheadrunning &&
00561         ((whence == SEEK_SET && pos == readpos) ||
00562          (whence == SEEK_CUR && pos == 0)))
00563     {
00564         ret = readpos;
00565 
00566         poslock.unlock();
00567         if (!has_lock)
00568             rwlock.unlock();
00569 
00570         return ret;
00571     }
00572 
00573     // only valid for SEEK_SET & SEEK_CUR
00574     long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;
00575 
00576 #if 1
00577     // Optimize short seeks where the data for
00578     // them is in our ringbuffer already.
00579     if (readaheadrunning &&
00580         (SEEK_SET==whence || SEEK_CUR==whence))
00581     {
00582         rbrlock.lockForWrite();
00583         rbwlock.lockForRead();
00584         LOG(VB_FILE, LOG_INFO, LOC +
00585             QString("Seek(): rbrpos: %1 rbwpos: %2"
00586                     "\n\t\t\treadpos: %3 internalreadpos: %4")
00587                 .arg(rbrpos).arg(rbwpos)
00588                 .arg(readpos).arg(internalreadpos));
00589         bool used_opt = false;
00590         if ((new_pos < readpos))
00591         {
00592             int min_safety = max(fill_min, readblocksize);
00593             int free = ((rbwpos >= rbrpos) ?
00594                         rbrpos + bufferSize : rbrpos) - rbwpos;
00595             int internal_backbuf =
00596                 (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos;
00597             internal_backbuf = min(internal_backbuf, free - min_safety);
00598             long long sba = readpos - new_pos;
00599             LOG(VB_FILE, LOG_INFO, LOC +
00600                 QString("Seek(): internal_backbuf: %1 sba: %2")
00601                     .arg(internal_backbuf).arg(sba));
00602             if (internal_backbuf >= sba)
00603             {
00604                 rbrpos = (rbrpos>=sba) ? rbrpos - sba :
00605                     bufferSize + rbrpos - sba;
00606                 used_opt = true;
00607                 LOG(VB_FILE, LOG_INFO, LOC +
00608                     QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2"
00609                                 "\n\t\t\treadpos: %3 internalreadpos: %4")
00610                         .arg(rbrpos).arg(rbwpos)
00611                         .arg(new_pos).arg(internalreadpos));
00612             }
00613         }
00614         else if ((new_pos >= readpos) && (new_pos <= internalreadpos))
00615         {
00616             rbrpos = (rbrpos + (new_pos - readpos)) % bufferSize;
00617             used_opt = true;
00618             LOG(VB_FILE, LOG_INFO, LOC +
00619                 QString("Seek(): OPT2 rbrpos: %1 sba: %2")
00620                     .arg(rbrpos).arg(readpos - new_pos));
00621         }
00622         rbwlock.unlock();
00623         rbrlock.unlock();
00624 
00625         if (used_opt)
00626         {
00627             if (ignorereadpos >= 0)
00628             {
00629                 // seek should always succeed since we were at this position
00630                 int ret;
00631                 if (remotefile)
00632                     ret = remotefile->Seek(internalreadpos, SEEK_SET);
00633                 else
00634                 {
00635                     ret = lseek64(fd2, internalreadpos, SEEK_SET);
00636                     posix_fadvise(fd2, internalreadpos,
00637                                   128*1024, POSIX_FADV_WILLNEED);
00638                 }
00639                 LOG(VB_FILE, LOG_INFO, LOC +
00640                     QString("Seek to %1 from ignore pos %2 returned %3")
00641                         .arg(internalreadpos).arg(ignorereadpos).arg(ret));
00642                 ignorereadpos = -1;
00643             }
00644             // if we are seeking forward we may now be too close to the
00645             // end, so we need to recheck if reads are allowed.
00646             if (new_pos > readpos)
00647             {
00648                 ateof = false;
00649                 readsallowed = false;
00650             }
00651             readpos = new_pos;
00652             poslock.unlock();
00653             generalWait.wakeAll();
00654             if (!has_lock)
00655                 rwlock.unlock();
00656             return new_pos;
00657         }
00658     }
00659 #endif
00660 
00661 #if 1
00662     // This optimizes the seek end-250000, read, seek 0, read portion 
00663     // of the pattern ffmpeg performs at the start of playback to
00664     // determine the pts.
00665     // If the seek is a SEEK_END or is a seek where the position
00666     // changes over 100 MB we check the file size and if the
00667     // destination point is within 300000 bytes of the end of
00668     // the file we enter a special mode where the read ahead
00669     // buffer stops reading data and all reads are made directly
00670     // until another seek is performed. The point of all this is
00671     // to avoid flushing out the buffer that still contains all
00672     // the data the final seek 0, read will need just to read the
00673     // last 250000 bytes. A further optimization would be to buffer
00674     // the 250000 byte read, which is currently performed in 32KB
00675     // blocks (inefficient with RemoteFile).
00676     if ((remotefile || fd2 >= 0) && (ignorereadpos < 0))
00677     {
00678         long long off_end = 0xDEADBEEF;
00679         if (SEEK_END == whence)
00680         {
00681             off_end = pos;
00682             if (remotefile)
00683             {
00684                 new_pos = remotefile->GetFileSize() - off_end;
00685             }
00686             else
00687             {
00688                 QFileInfo fi(filename);
00689                 new_pos = fi.size() - off_end;
00690             }
00691         }
00692         else
00693         {
00694             if (remotefile)
00695             {
00696                 off_end = remotefile->GetFileSize() - new_pos;
00697             }
00698             else
00699             {
00700                 QFileInfo fi(filename);
00701                 off_end = fi.size() - new_pos;
00702             }
00703         }
00704 
00705         if (off_end != 0xDEADBEEF)
00706         {
00707             LOG(VB_FILE, LOG_INFO, LOC +
00708                 QString("Seek(): Offset from end: %1").arg(off_end));
00709         }
00710 
00711         if (off_end == 250000)
00712         {
00713             LOG(VB_FILE, LOG_INFO, LOC +
00714                 QString("Seek(): offset from end: %1").arg(off_end) +
00715                 "\n\t\t\t -- ignoring read ahead thread until next seek.");
00716 
00717             ignorereadpos = new_pos;
00718             errno = EINVAL;
00719             long long ret;
00720             if (remotefile)
00721                 ret = remotefile->Seek(ignorereadpos, SEEK_SET);
00722             else
00723                 ret = lseek64(fd2, ignorereadpos, SEEK_SET);
00724 
00725             if (ret < 0)
00726             {
00727                 int tmp_eno = errno;
00728                 QString cmd = QString("Seek(%1, SEEK_SET) ign ")
00729                     .arg(ignorereadpos);
00730 
00731                 ignorereadpos = -1;
00732 
00733                 LOG(VB_GENERAL, LOG_ERR, LOC + cmd + " Failed" + ENO);
00734 
00735                 // try to return to former position..
00736                 if (remotefile)
00737                     ret = remotefile->Seek(internalreadpos, SEEK_SET);
00738                 else
00739                     ret = lseek64(fd2, internalreadpos, SEEK_SET);
00740                 if (ret < 0)
00741                 {
00742                     QString cmd = QString("Seek(%1, SEEK_SET) int ")
00743                         .arg(internalreadpos);
00744                     LOG(VB_GENERAL, LOG_ERR, LOC + cmd + " Failed" + ENO);
00745                 }
00746                 else
00747                 {
00748                     QString cmd = QString("Seek(%1, %2) int ")
00749                         .arg(internalreadpos)
00750                         .arg((SEEK_SET == whence) ? "SEEK_SET" :
00751                              ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));
00752                     LOG(VB_GENERAL, LOG_ERR, LOC + cmd + " succeeded");
00753                 }
00754                 ret = -1;
00755                 errno = tmp_eno;
00756             }
00757             else
00758             {
00759                 ateof = false;
00760                 readsallowed = false;
00761             }
00762 
00763             poslock.unlock();
00764 
00765             generalWait.wakeAll();
00766 
00767             if (!has_lock)
00768                 rwlock.unlock();
00769 
00770             return ret;
00771         }
00772     }
00773 #endif
00774 
00775     // Here we perform a normal seek. When successful we
00776     // need to call ResetReadAhead(). A reset means we will
00777     // need to refill the buffer, which takes some time.
00778     if (remotefile)
00779     {
00780         ret = remotefile->Seek(pos, whence, readpos);
00781         if (ret<0)
00782             errno = EINVAL;
00783     }
00784     else
00785     {
00786         ret = lseek64(fd2, pos, whence);
00787     }
00788 
00789     if (ret >= 0)
00790     {
00791         readpos = ret;
00792         
00793         ignorereadpos = -1;
00794 
00795         if (readaheadrunning)
00796             ResetReadAhead(readpos);
00797 
00798         readAdjust = 0;
00799     }
00800     else
00801     {
00802         QString cmd = QString("Seek(%1, %2)").arg(pos)
00803             .arg((whence == SEEK_SET) ? "SEEK_SET" :
00804                  ((whence == SEEK_CUR) ? "SEEK_CUR" : "SEEK_END"));
00805         LOG(VB_GENERAL, LOG_ERR, LOC + cmd + " Failed" + ENO);
00806     }
00807 
00808     poslock.unlock();
00809 
00810     generalWait.wakeAll();
00811 
00812     if (!has_lock)
00813         rwlock.unlock();
00814 
00815     return ret;
00816 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends