int KDBPathType ( const KDirectory *dir, bool *pHasZombies, const char *path ) { const char *leaf, *parent; rc_t rc; int type = KDirectoryPathType ( dir, "%s", path ); if (pHasZombies) *pHasZombies = false; switch ( type ) { case kptDir: case kptDir | kptAlias: type = KDBPathTypeDir (dir, type, pHasZombies, path); break; case kptFile: case kptFile | kptAlias: { /* if we hit a file first try it as an archive */ const KDirectory * ldir; rc = KDirectoryOpenSraArchiveRead_silent ( dir, &ldir, false, "%s", path ); #if SUPPORT_KDB_TAR if ( rc != 0 ) rc = KDirectoryOpenTarArchiveRead_silent ( dir, &ldir, false, "%s", path ); #endif /* it was an archive so recur */ if ( rc == 0 ) { /* recheck this newly opened directory for KDB/KFS type */ int type2; type2 = KDBPathType ( ldir, NULL, "." ); if ((type2 != kptDir) || (type != (kptDir|kptAlias))) type = type2; KDirectoryRelease (ldir); } /* it was not an archive so see if it it's an idx file */ else { leaf = strrchr ( path, '/' ); if ( leaf != NULL ) { parent = string_rchr ( path, leaf - path, '/' ); if ( parent ++ == NULL ) parent = path; if ( memcmp ( parent, "idx/", 4 ) == 0 ) type += kptIndex - kptFile; } } break; } } return type; }
static rc_t KDBOpenPathTypeReadInt ( const KDBManager * mgr, const KDirectory * dir, const char * path, const KDirectory ** pdir, int * type, int pathtype, uint32_t rcobj, bool try_srapath ) { VFSManager * vmgr = mgr->vfsmgr; const KDirectory * ldir = NULL; rc_t rc = 0; /* object relative opens can be done using KFS - we hacked in VFS after all */ if (! try_srapath) { rc = KDirectoryOpenDirUpdate ((KDirectory*)dir, (KDirectory**)pdir, false, path); if ((rc) && (GetRCState(rc) != rcNotFound)) rc = KDirectoryOpenDirRead (dir, pdir, false, path); } else { VPath * vpath; /* * We've got to decide if the path coming in is a full or relative * path and if relative make it relative to dir or possibly its a srapath * accession * */ rc = VPathMakeDirectoryRelative ( &vpath, dir, path ); if ( rc == 0 ) { rc = VFSManagerOpenDirectoryReadDirectoryRelativeDecrypt ( vmgr, dir, &ldir, vpath ); if ( rc == 0 ) { *type = (~kptAlias) & KDBPathType ( ldir, NULL, "." ); /* just a directory, not a kdb type */ if ( *type == kptDir ) rc = RC (rcDB, rcMgr, rcOpening, rcPath, rcIncorrect); else if ( *type != pathtype ) { KDirectoryRelease( ldir ); rc = RC ( rcDB, rcMgr, rcOpening, rcobj, rcIncorrect ); } else { if ( pdir != NULL ) *pdir = ldir; else KDirectoryRelease( ldir ); } } VPathRelease ( vpath ); } } return rc; }
LIB_EXPORT int CC KDBManagerVPathType ( const KDBManager * self, const char *path, va_list args ) { if ( self != NULL ) { char full [ 4096 ]; rc_t rc = KDirectoryVResolvePath ( self -> wd, false, full, sizeof full, path, args ); if ( rc == 0 ) return KDBPathType ( /*self,*/ self -> wd, NULL, full ); } return kptBadPath; }
LIB_EXPORT rc_t CC KDBManagerVPathOpenRemoteDBRead ( struct KDBManager const * self, struct KDatabase const ** p_db, struct VPath const * remote, struct VPath const * cache ) { if ( self == NULL ) return RC ( rcDB, rcDatabase, rcAccessing, rcSelf, rcNull ); if ( p_db == NULL ) return RC ( rcDB, rcDatabase, rcAccessing, rcParam, rcNull ); if ( remote == NULL ) return RC ( rcDB, rcDatabase, rcAccessing, rcParam, rcNull ); /* cache == NULL is OK */ { /* vpath has already been resolved and is known to be a remote URL. Open it if it is a database; use the provided cache; avoid an additional round of resolution */ const KDirectory *dir; rc_t rc = VFSManagerOpenDirectoryReadDecryptRemote( self -> vfsmgr, &dir, remote, cache ); if ( rc == 0 ) { if ( ( (~kptAlias) & KDBPathType ( dir, NULL, "." ) ) != kptDatabase ) { rc = RC ( rcDB, rcMgr, rcOpening, rcDatabase, rcIncorrect ); } else { KDatabase *db; /* allocate a new guy */ rc = KDatabaseMakeVPath ( & db, dir, remote, NULL, true ); if ( rc == 0 ) { rc = KDBManagerInsertDatabase ( ( KDBManager* ) self, db ); if ( rc == 0 ) { * p_db = db; return 0; } free (db); } } KDirectoryRelease ( dir ); } return rc; } }
LIB_EXPORT rc_t CC KDBManagerVPathOpenLocalDBRead ( struct KDBManager const * self, struct KDatabase const ** p_db, struct VPath const * vpath ) { if ( self == NULL ) return RC ( rcDB, rcDatabase, rcAccessing, rcSelf, rcNull ); if ( p_db == NULL ) return RC ( rcDB, rcDatabase, rcAccessing, rcParam, rcNull ); if ( vpath == NULL ) return RC ( rcDB, rcDatabase, rcAccessing, rcParam, rcNull ); { /* vpath has already been resolved and is known to be a local path. open it if it is a database; avoid an additional round of resolution */ const KDirectory *dir; rc_t rc = VFSManagerOpenDirectoryReadDirectoryRelativeDecrypt ( self -> vfsmgr, self -> wd, &dir, vpath ); if ( rc == 0 ) { if ( ( (~kptAlias) & KDBPathType ( dir, NULL, "." ) ) != kptDatabase ) { rc = RC ( rcDB, rcMgr, rcOpening, rcDatabase, rcIncorrect ); } else { KDatabase *db; rc = KDatabaseMakeVPath ( & db, dir, vpath, NULL, true ); if ( rc == 0 ) { rc = KDBManagerInsertDatabase ( ( KDBManager* ) self, db ); if ( rc == 0 ) { * p_db = db; return 0; } free (db); } } KDirectoryRelease ( dir ); } return rc; } }
/* Writable * returns 0 if object is writable * or a reason why if not * * "path" [ IN ] - NUL terminated path * * TBD: Better reasons for non local paths */ static rc_t KDBManagerWritableInt ( const KDirectory * dir, const char * path ) { rc_t rc; int type = KDBPathType ( /*NULL,*/ dir, NULL, path ) & ~ kptAlias; switch ( type ) { case kptDatabase: case kptTable: case kptPrereleaseTbl: case kptColumn: rc = KDBWritable ( dir, path ); break; case kptIndex: case kptMetadata: /* a wrong database type */ rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcIncorrect ); break; #if 0 /*TBD - eventually we need to check for an archive here */ case kptFile: /* check if this is an archive .tar or .sra and return rcReadonly if it is */ #endif case kptNotFound: rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcNotFound ); break; case kptBadPath: rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcInvalid ); break; default: rc = RC ( rcDB, rcMgr, rcAccessing, rcPath, rcIncorrect ); } return rc; }
/* OpenDBUpdate * VOpenDBUpdate * open a database for read/write * * "db" [ OUT ] - return parameter for newly opened database * * "path" [ IN ] - NUL terminated string in * wd-native character set giving path to database */ static rc_t KDBManagerVOpenDBUpdateInt ( KDBManager *self, KDatabase **db, KDirectory *wd, const char *path, va_list args ) { char dbpath [ 4096 ]; rc_t rc = KDirectoryVResolvePath ( wd, true, dbpath, sizeof dbpath, path, args ); if ( rc == 0 ) { KSymbol * sym; KFile *f; KMD5SumFmt * md5 = NULL; /* if already open, refuse */ sym = KDBManagerOpenObjectFind (self, dbpath); if (sym != NULL) { rc_t obj; switch (sym->type) { default: obj = rcPath; break; case kptDatabase: obj = rcDatabase; break; case kptTable: obj = rcTable; break; case kptColumn: obj = rcColumn; break; case kptIndex: obj = rcIndex; break; case kptMetadata: obj = rcMetadata; break; } return RC ( rcDB, rcMgr, rcOpening, obj, rcBusy ); } /* only open existing dbs */ switch (KDBPathType ( /*self,*/ wd, NULL, dbpath ) ) { case kptNotFound: return RC ( rcDB, rcMgr, rcOpening, rcDatabase, rcNotFound ); case kptBadPath: return RC ( rcDB, rcMgr, rcOpening, rcPath, rcInvalid ); case kptFile: case kptFile | kptAlias: /* if we find a file, vary the failure if it is an archive that is a database * or a non related file */ if ( KDBOpenPathTypeRead ( self, wd, dbpath, NULL, kptDatabase, NULL, false ) == 0 ) return RC ( rcDB, rcMgr, rcOpening, rcDirectory, rcUnauthorized ); /* fall through */ default: return RC ( rcDB, rcMgr, rcOpening, rcPath, rcIncorrect ); case kptDatabase: case kptDatabase | kptAlias: break; } /* test now for locked directory */ rc = KDBWritable (wd, dbpath); switch (GetRCState (rc)) { default: #if 0 return RC ( rcDB, rcMgr, rcOpening, rcDatabase, rcNoPerm ); /* TBD: better state? */ #endif case rcLocked: return RC ( rcDB, rcMgr, rcOpening, rcDatabase, rcLocked ); case rcReadonly: return RC ( rcDB, rcMgr, rcOpening, rcDatabase, rcReadonly ); case 0: rc = 0; break; } rc = KDirectoryOpenFileWrite ( wd, &f, true, "%s/md5", dbpath ); if ( rc == 0 ) { rc = KMD5SumFmtMakeUpdate ( & md5, f ); if ( rc != 0 ) KFileRelease ( f ); } else if ( GetRCState ( rc ) == rcNotFound ) rc = 0; if ( rc == 0 ) rc = KDBManagerMakeDBUpdate ( self, db, wd, dbpath, md5 ); KMD5SumFmtRelease ( md5 ); } return rc; }
/* CreateDB * VCreateDB * create a new or open an existing database * * "db" [ OUT ] - return parameter for newly opened database * * "cmode" [ IN ] - creation mode * * "path" [ IN ] - NUL terminated string in * wd-native character set giving path to database */ static rc_t KDBManagerVCreateDBInt ( KDBManager *self, KDatabase **db, KDirectory *wd, KCreateMode cmode, const char *path, va_list args ) { char dbpath [ 4096 ]; rc_t rc = KDirectoryVResolvePath ( wd, true, dbpath, sizeof dbpath, path, args ); if ( rc == 0 ) { /* we won't try accession resolution here */ int type = KDBPathType ( /*NULL,*/ wd, NULL, dbpath ); switch ( type ) { case kptNotFound: /* first good path */ break; case kptBadPath: return RC ( rcDB, rcMgr, rcCreating, rcPath, rcInvalid ); case kptDatabase: case kptDatabase | kptAlias: /* found so is not good if we want to create new and not * clear/init or open old */ if ((cmode & kcmValueMask) == kcmCreate) return RC ( rcDB, rcMgr, rcCreating, rcDatabase, rcExists ); if (KDBManagerOpenObjectBusy (self, dbpath)) return RC ( rcDB, rcMgr, rcCreating, rcDatabase, rcBusy ); /* test now for locked directory */ rc = KDBWritable ( wd, dbpath ); if (rc) { switch (GetRCState(rc)) { default: return rc; case rcLocked: return RC ( rcDB, rcMgr, rcCreating, rcDatabase, rcLocked ); case rcReadonly: return RC ( rcDB, rcMgr, rcCreating, rcDatabase, rcReadonly ); case rcNotFound: /* not found is good but probably unreachable */ break; case 0: rc = 0; break; } } /* second good path */ break; case kptTable: case kptTable | kptAlias: return RC (rcDB, rcMgr, rcCreating, rcTable, rcExists); case kptColumn: case kptColumn | kptAlias: return RC (rcDB, rcMgr, rcCreating, rcColumn, rcExists); case kptIndex: case kptIndex | kptAlias: return RC (rcDB, rcMgr, rcCreating, rcIndex, rcExists); case kptMetadata: case kptMetadata | kptAlias: return RC (rcDB, rcMgr, rcCreating, rcMetadata, rcExists); case kptFile: case kptFile | kptAlias: /* if we find a file, vary the failure if it is an archive that is a database * or a non related file */ if ( KDBOpenPathTypeRead ( self, wd, dbpath, NULL, kptDatabase, NULL, false ) == 0 ) return RC ( rcDB, rcMgr, rcCreating, rcDirectory, rcUnauthorized ); /* fall through */ default: return RC ( rcDB, rcMgr, rcCreating, rcPath, rcIncorrect ); } /* [re]create directory */ rc = KDirectoryCreateDir ( wd, 0775, cmode, "%s", dbpath ); if (rc == 0) /* create tbl subdirectory as required for db */ rc = KDirectoryCreateDir ( wd, 0775, kcmOpen, "%s/tbl", dbpath ); if ( rc == 0 ) { KMD5SumFmt *md5 = NULL; if ( ( cmode & kcmMD5 ) != 0 ) { KFile * f; /* if needed create the md5 digest file */ rc = KDirectoryCreateFile ( wd, &f, true, 0664, kcmOpen, "%s/md5", dbpath ); if ( rc == 0 ) { /* create a formatter around file formatter will own "f" afterward */ rc = KMD5SumFmtMakeUpdate ( & md5, f ); /* if failed to create formatter, release "f" */ if ( rc != 0 ) KFileRelease ( f ); } } if ( rc == 0 ) rc = KDBManagerMakeDBUpdate ( self, db, wd, dbpath, md5 ); KMD5SumFmtRelease ( md5 ); } } return rc; }