/* ---------------------------------------------------------------------- * RandomAccess * * returns 0 if random access, error code otherwise */ static rc_t CC KWGAEncFileRandomAccess (const KWGAEncFile *self) { assert (self != NULL); assert (self->encrypted != NULL); return KFileRandomAccess (self->encrypted); }
/* ---------------------------------------------------------------------- * RandomAccess * * returns 0 if random access, error code otherwise */ static rc_t CC KCounterFileRandomAccess (const KCounterFile *self) { assert (self != NULL); assert (self->original != NULL); return KFileRandomAccess (self->original); }
/* ---------------------------------------------------------------------- * RandomAccess * * returns 0 if random access, error code otherwise * * Update needs to be able to seek both original and copy while read * only needs to be able to seek the original. */ static rc_t CC KSubFileRandomAccess (const KSubFile *self) { assert (self != NULL); return KFileRandomAccess (self->original); }
static rc_t CC KHttpUndyingFileRandomAccess(const KHttpUndyingFile *self) { return KFileRandomAccess(GetUnderlyingFile(self)); }
static rc_t CC KBufWriteFileRandomAccess ( const KBufWriteFile *self ) { return KFileRandomAccess ( self -> f ); }
static rc_t CC KLoaderFile_RandomAccess(const KLoaderFile *self) { return KFileRandomAccess(self ? self->kfile : NULL); }
/* not KDB specific - just uses vfs/krypto/kfs objects */ static rc_t KDBOpenFileAsDirectory (const KDirectory * dir, const char * path, const KDirectory ** pdir, uint32_t rcobj) { const KFile * file; const KFile * f; const KDirectory * ldir; bool encrypted = false; rc_t rc; *pdir = NULL; rc = KDirectoryOpenFileRead (dir, &file, path); if (rc == 0) { rc = KFileRandomAccess(file); if (rc) rc = RC (rcDB, rcMgr, rcOpening, rcobj, rcUnsupported); else { size_t tz; char tbuff [4096]; char pbuff [4096 + 1]; rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz); if (rc == 0) { if (KFileIsEnc (tbuff, tz) == 0) { encrypted = true; rc = KDBOpenFileGetPassword (pbuff, sizeof (pbuff) - 1); if (rc == 0) { KKey key; rc = KKeyInitRead (&key, kkeyAES128, pbuff, string_size (pbuff)); if (rc == 0) { rc = KEncFileMakeRead (&f, file, &key); if (rc == 0) { /* KEncFileMakeRead adds a reference */ KFileRelease (file); file = f; rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz); } } } } else if (KFileIsWGAEnc (tbuff, tz) == 0) { encrypted = true; rc = KDBOpenFileGetPassword (pbuff, sizeof (pbuff) - 1); if (rc == 0) { rc = KFileMakeWGAEncRead (&f, file, pbuff, string_size (pbuff)); if (rc == 0) { /* KFileMakeWGAEncRead adds a reference */ KFileRelease (file); file = f; rc = KFileReadAll (file, 0, tbuff, sizeof tbuff, &tz); } } } /* else not a handled encryption or unencrypted: we can't distinguish too much */ if (rc == 0) { if (KFileIsSRA (tbuff, tz) == 0) { rc = KDirectoryOpenSraArchiveReadUnbounded_silent_preopened (dir, &ldir, false, file, path); } else { rc = KDirectoryOpenTarArchiveRead_silent_preopened (dir, &ldir, false, file, path); } /* not an archive type we handle or a bad archive */ if (rc) { if (encrypted) rc = RC ( rcDB, rcMgr, rcOpening, rcEncryptionKey, rcIncorrect ); else rc = RC ( rcDB, rcMgr, rcOpening, rcPath, rcIncorrect ); } else { /* * release our ownership of the KFile that but archive will * keep theirs */ KFileRelease (file); *pdir = ldir; return 0; } } } } KFileRelease (file); } return rc; }
/* MakeRead * make a queue file for reading-ahead on background thread * * when the file is created, a background thread is started * that begins reading from "src" at position "pos", into * buffers of size "buffer_size". each buffer is pushed into * a cross-thread queue where it is consumed by the reading * thread. * * the background thread is throttled by queue capacity - determined * by "queue_bytes" and "block_size", such that if the queue is full, * the thread will sleep. the consumer thread is also throttled by the * queue in that it will sleep if the queue is empty with pending data. * * the background thread will exit upon reaching end of file, * upon a permanent error, or if the queue is sealed by the consumer * thread. * * when the file is collected in response to a release message, * the queue will be sealed against further inserts, pending buffers * will be discarded, the background thread will be joined, and * the source file will be released. * * the intended usage is serial reading of the file. reads * may only progress forward, i.e. backing up is not permitted. * * "qf" [ OUT ] - return parameter for queue file * * "pos" [ IN ] - starting position for reads from "src". * NB - "src" must support being addressed at this position. * * "src" [ IN ] - source file for read-ahead on background thread. * must have read permissions. * * "queue_bytes" [ IN ] - the read-ahead limit of the background * thread, in bytes. this is the amount of data that will be queued * for the consumer thread before the bg thread sleeps. * * "block_size" [ IN, DEFAULT ZERO ] - optional parameter giving * desired block size when reading from "src". this may be used * to tune reading for source data, e.g. 64K blocks for gzip. */ LIB_EXPORT rc_t CC KQueueFileMakeRead ( const KFile **qfp, uint64_t pos, const KFile *src, size_t queue_bytes, size_t block_size, uint32_t timeout_ms ) { rc_t rc; if ( qfp == NULL ) rc = RC ( rcApp, rcFile, rcConstructing, rcParam, rcNull ); else { if ( src == NULL ) rc = RC ( rcApp, rcFile, rcConstructing, rcFile, rcNull ); else if ( ! src -> read_enabled ) { if ( src -> write_enabled ) rc = RC ( rcApp, rcFile, rcConstructing, rcFile, rcWriteonly ); else rc = RC ( rcApp, rcFile, rcConstructing, rcFile, rcNoPerm ); } else if ( pos == 0 || ( rc = KFileRandomAccess ( src ) ) == 0 ) { KQueueFile *qf = malloc ( sizeof * qf ); if ( qf == NULL ) rc = RC ( rcApp, rcFile, rcConstructing, rcMemory, rcExhausted ); else { rc = KFileInit ( & qf -> dad, ( const KFile_vt* ) & KQueueFileRead_vt_v1, "KQueueFile", "no-name", true, false ); if ( rc == 0 ) { qf -> f = ( KFile* ) src; rc = KFileAddRef ( src ); if ( rc == 0 ) { uint32_t capacity; /* zero block size means default */ if ( block_size == 0 ) block_size = DEFAULT_BLOCK_SIZE; /* queue capacity is expressed in bytes originally translate to buffer count */ capacity = ( queue_bytes + block_size - 1 ) / block_size; if ( capacity == 0 ) capacity = 1; /* actual capacity will be a power of 2 */ rc = KQueueMake ( & qf -> q, capacity ); if ( rc == 0 ) { /* capture current size if supported */ qf -> rc_from_size_on_open = KFileSize ( src, & qf -> apparent_size ); /* starting position for read */ qf -> start_pos = pos; /* requested buffer size */ qf -> b = NULL; qf -> bsize = block_size; /* timeout */ qf -> timeout_ms = timeout_ms == 0 ? DEFAULT_TIMEOUT_MS : timeout_ms; /* finally, start the background thread */ rc = KThreadMake ( & qf -> t, KQueueFileRunRead, qf ); if ( rc == 0 ) { * qfp = & qf -> dad; return 0; } KQueueRelease ( qf -> q ); } KFileRelease ( qf -> f ); } } free ( qf ); } } * qfp = NULL; } return rc; }