/* Writable * examines a directory structure for any "lock" files */ rc_t KDBWritable ( const KDirectory *dir, const char *path ) { uint32_t access; rc_t rc; /* protect us from bad parameters */ if (dir == NULL) return RC (rcDB, rcPath, rcAccessing, rcDirectory, rcNull); if (path == NULL) return RC (rcDB, rcPath, rcAccessing, rcPath, rcNull); /* we have to be able to check the access if it is to be writable */ rc = KDirectoryAccess ( dir, & access, "%s", path ); if ( rc == 0 ) { /* if there is a lock (or deprecated sealed) file in this directory */ switch ( KDirectoryPathType ( dir, "%s/lock", path ) ) { case kptFile: case kptFile | kptAlias: rc = RC ( rcDB, rcPath, rcAccessing, rcLock, rcLocked ); break; case kptNotFound: /* much simpler handling for the sealed file */ switch ( KDirectoryPathType ( dir, "%s/sealed", path ) ) { case kptFile: case kptFile | kptAlias: rc = RC ( rcDB, rcPath, rcAccessing, rcLock, rcLocked ); break; case kptNotFound: /* check if there are no write permissions */ if ( ( access & 0222 ) == 0 ) rc = RC ( rcDB, rcPath, rcAccessing, rcPath, rcReadonly ); /* else rc is still 0 from VAccess */ } break; case kptBadPath: /* likely to be a non-driectory or something */ rc = RC ( rcDB, rcPath, rcAccessing, rcPath, rcInvalid); break; default: /* an illegal type of object named "lock" is in this directory * which will block the ability to lock it */ rc = RC ( rcDB, rcPath, rcAccessing, rcPath, rcIncorrect ); } } return rc; }
/* * copies top/inname (a directory) * to targettop/outname, i.e. creates outname as a copy of that directory. */ rc_t CopyDirectoryToExistingDirectory( const KDirectory *top, const char *inname, KDirectory *targettop, const char *outname ) { rc_t rc; uint32_t mode; const KDirectory *source; KDirectory *dest; rc = KDirectoryOpenDirRead(top, &source, true, "%s", (const char *)inname); if (rc != 0) { LOGERR ( klogInt, rc, "can't open input directory" ); return rc; } mode = DEFAULT_DIR_MODE; rc = KDirectoryAccess( top, &mode, "%s", inname); if (rc != 0) { LOGERR ( klogInt, rc, inname ); return rc; } rc = KDirectoryCreateDir( targettop, mode, kcmOpen, "%s", outname ); if (rc != 0) { LOGERR ( klogInt, rc, "can't create output directory" ); return rc; } if (clobber_protections) { KDirectorySetAccess( targettop, false, mode, 0777, "%s", outname); } rc = KDirectoryOpenDirUpdate(targettop, &dest, true, "%s", outname); if (rc != 0) { LOGERR ( klogInt, rc, "can't open directory for write" ); return rc; } CopyDirectoryFiles(source, dest); CopyDirectoryDirectories( source, dest ); KDirectoryRelease( dest ); KDirectoryRelease( source ); return 0; }
rc_t CopyDirectoryDirectories( const KDirectory *source, KDirectory *dest ) { rc_t rc; KNamelist *list; const char *name; int i; uint32_t count; uint32_t mode; uint32_t pathtype; KDirectoryList( source, &list, PathIsDir, NULL, "."); KNamelistCount(list, &count); for (i=0; i<count; i++) { KNamelistGet(list, i, &name); /* fprintf(stderr, "Creating directory %s\n", name); */ mode = DEFAULT_DIR_MODE; rc = KDirectoryAccess( source, &mode, "%s", name); if (rc != 0) { LOGERR ( klogInt, rc, name ); return rc; } pathtype = KDirectoryPathType( dest, "%s", name ); if ((pathtype & ~kptAlias) == kptNotFound) { rc = KDirectoryCreateDir( dest, mode, kcmOpen, "%s", name ); if (rc != 0) { LOGERR ( klogInt, rc, name ); return rc; } } else if ((pathtype & ~kptAlias) == kptDir) { if (clobber_protections) { KDirectorySetAccess( dest, false, mode, 0777, "%s", name); } } CopyDirectoryToExistingDirectory( source, name, dest, (char *)name); } return 0; }
rc_t CopyMode( const KDirectory *source, const char *sourcename, KDirectory *target, char *targetname ) { /* Make sure they both exist and are the same type */ uint32_t src_pathtype; uint32_t dest_pathtype; uint32_t mode; rc_t rc; src_pathtype = KDirectoryPathType( source, "%s", sourcename ); dest_pathtype = KDirectoryPathType( target, "%s", targetname ); if ((src_pathtype & ~kptAlias) != (dest_pathtype & ~kptAlias)) { return -1; } rc = KDirectoryAccess( source, &mode, "%s", sourcename ); if (rc != 0) { LOGERR ( klogInt, rc, sourcename ); return rc; } KDirectorySetAccess( target, false, mode, 0777, "%s", targetname ); return 0; }
static rc_t FileToFile (const KDirectory * sd, const char * source, KDirectory *dd, const char * dest_, bool try_rename, char * base) { const KFile * infile; rc_t rc; uint32_t access; KTime_t date; bool is_tmp; char dest [MY_MAX_PATH + sizeof EncExt]; strcpy (dest, dest_); if (try_rename) NameFixUp (dest); if ((sd == dd) && (strcmp (source, dest) == 0)) return FileInPlace (dd, dest, try_rename); if (base == NULL) STSMSG (1, ("%scrypting file %s to %s", De, source, dest)); else STSMSG (1, ("%scrypting file %s to %s/%s", De, source, base, dest)); /* * A Hack to make stdin/stout work within KFS */ if (UseStdin) { const KFile * iinfile; rc = KFileMakeStdIn (&iinfile); if (rc == 0) { rc = KBufReadFileMakeRead (&infile, iinfile, 64 * 1024); KFileRelease (iinfile); if (rc == 0) { access = 0640; date = 0; goto stdin_shortcut; } LOGERR (klogErr, rc, "error wrapping stdin"); return rc; } } rc = 0; is_tmp = IsTmpFile (source); if (is_tmp) { TmpFoundFlag = true; if (ForceFlag) ; /* LOG OVERWRITE */ else ; /* LOG TMP */ } if (!is_tmp || ForceFlag) { rc = KDirectoryAccess (sd, &access, "%s", source); if (rc) LOGERR (klogErr, rc, "Error check permission of source"); else { rc = KDirectoryDate (sd, &date, "%s", source); if (rc) LOGERR (klogErr, rc, "Error check date of source"); else { rc = KDirectoryOpenFileRead (sd, &infile, "%s", source); if (rc) PLOGERR (klogErr, (klogErr, rc, "Error opening source file '$(S)'", "S=%s", source)); else { EncScheme scheme; stdin_shortcut: rc = EncryptionTypeCheck (infile, source, &scheme); if (rc == 0) { KFile * outfile; uint32_t kcm; /* * Hack to support stdout before VFS is complete enough to use here */ if (UseStdout) { rc = KFileMakeStdOut (&outfile); if (rc) LOGERR (klogErr, rc, "error wrapping stdout"); } else { kcm = ForceFlag ? kcmInit|kcmParents : kcmCreate|kcmParents; rc = KDirectoryCreateFile (dd, &outfile, false, 0600, kcm, "%s", dest); if (rc) PLOGERR (klogErr,(klogErr, rc, "error opening output '$(O)'", "O=%s", dest)); } if (rc == 0) { const KFile * Infile; KFile * Outfile; rc = CryptFile (infile, &Infile, outfile, &Outfile, scheme); if (rc == 0) { rc = CopyFile (Infile, Outfile, source, dest); if (rc == 0) { if (UseStdin || UseStdout) ; else { rc = KDirectorySetAccess (dd, false, access, 0777, "%s", dest); if (rc == 0 && date != 0) rc = KDirectorySetDate (dd, false, date, "%s", dest); } } KFileRelease (Infile); KFileRelease (Outfile); } KFileRelease (outfile); } } KFileRelease (infile); } } } } return rc; }
static rc_t FileInPlace (KDirectory * cwd, const char * leaf, bool try_rename) { rc_t rc; bool is_tmp; STSMSG (1, ("%scrypting file in place %s",De,leaf)); rc = 0; is_tmp = IsTmpFile (leaf); if (is_tmp) { STSMSG (1, ("%s is a vdb-decrypt/vdb-encrypt temporary file and will " "be ignored", leaf)); TmpFoundFlag = true; if (ForceFlag) ; /* LOG OVERWRITE */ else ; /* LOG TMP */ } if (!is_tmp || ForceFlag) { char temp [MY_MAX_PATH]; rc = KDirectoryResolvePath (cwd, false, temp, sizeof temp, ".%s%s", leaf, TmpExt); if (rc) PLOGERR (klogErr, (klogErr, rc, "unable to resolve '.$(S)$(E)'", "S=%s,E=%s",leaf,TmpExt)); else { KPathType kpt; uint32_t kcm; kcm = kcmCreate|kcmParents; kpt = KDirectoryPathType (cwd, temp); if (kpt != kptNotFound) { /* log busy */ if (ForceFlag) { kcm = kcmInit|kcmParents; /* log force */ kpt = kptNotFound; } } if (kpt == kptNotFound) { const KFile * infile; rc = KDirectoryOpenFileRead (cwd, &infile, "%s", leaf); if (rc) PLOGERR (klogErr, (klogErr, rc, "Unable to resolve '$(F)'", "F=%s",leaf)); else { EncScheme scheme; rc = EncryptionTypeCheck (infile, leaf, &scheme); if (rc == 0) { ArcScheme ascheme; bool changed; bool do_this_file; char new_name [MY_MAX_PATH + sizeof EncExt]; do_this_file = DoThisFile (infile, scheme, &ascheme); strcpy (new_name, leaf); if (try_rename) changed = NameFixUp (new_name); else changed = false; /* KOutMsg ("### %d \n", changed); */ if (!do_this_file) { if (changed) { STSMSG (1, ("renaming %s to %s", leaf, new_name)); rc = KDirectoryRename (cwd, false, leaf, new_name); } else STSMSG (1, ("skipping %s",leaf)); } else { KFile * outfile; rc = KDirectoryCreateExclusiveAccessFile (cwd, &outfile, false, 0600, kcm, temp); if (rc) ; else { const KFile * Infile; KFile * Outfile; rc = CryptFile (infile, &Infile, outfile, &Outfile, scheme); if (rc == 0) { STSMSG (1, ("copying %s to %s", leaf, temp)); rc = CopyFile (Infile, Outfile, leaf, temp); if (rc == 0) { uint32_t access; KTime_t date; rc = KDirectoryAccess (cwd, &access, "%s", leaf); if (rc == 0) rc = KDirectoryDate (cwd, &date, "%s", leaf); KFileRelease (infile); KFileRelease (outfile); KFileRelease (Infile); KFileRelease (Outfile); if (rc == 0) { STSMSG (1, ("renaming %s to %s", temp, new_name)); rc = KDirectoryRename (cwd, true, temp, new_name); if (rc) LOGERR (klogErr, rc, "error renaming"); else { if (changed) KDirectoryRemove (cwd, false, "%s", leaf); /*rc =*/ KDirectorySetAccess (cwd, false, access, 0777, "%s", new_name); KDirectorySetDate (cwd, false, date, "%s", new_name); /* gonna ignore an error here I think */ return rc; } } } } KFileRelease (outfile); } } } KFileRelease (infile); } } } } return rc; }
static rc_t CC list_action (const KDirectory * dir, const char * path, void * _adata) { rc_t rc; list_adata * data; list_item * item; KPathType type; uint32_t access; uint64_t size; uint64_t loc; KTime_t mtime; size_t pathlen; size_t linklen; char link [2 * 4096]; /* we'll truncate? */ rc = 0; data = _adata; loc = size = 0; pathlen = strlen (path); type = KDirectoryPathType (dir, path); if (type & kptAlias) { rc = KDirectoryVResolveAlias (dir, false, link, sizeof (link), path, NULL); if (rc == 0) linklen = strlen (link); } else { linklen = 0; switch (type & ~kptAlias) { case kptNotFound: rc = RC (rcExe, rcDirectory, rcAccessing, rcPath, rcNotFound); break; case kptBadPath: rc = RC (rcExe, rcDirectory, rcAccessing, rcPath, rcInvalid); break; case kptZombieFile: if ( ! long_list ) return 0; data->has_zombies = true; case kptFile: rc = KDirectoryFileSize (dir, &size, path); if (rc == 0) { if (size > data->max_size) data->max_size = size; rc = KDirectoryFileLocator (dir, &loc, path); if ((rc == 0) && (loc > data->max_loc)) data->max_loc = loc; } break; case kptDir: break; case kptCharDev: case kptBlockDev: case kptFIFO: /* shouldn't get here */ return 0; } } if (rc == 0) { rc = KDirectoryAccess (dir, &access, "%s", path); if (rc == 0) { rc = KDirectoryDate (dir, &mtime, "%s", path); if (rc == 0) { item = malloc (sizeof (*item) + pathlen + linklen + 2); /* usually one too many */ if (item == NULL) { rc = RC (rcExe, rcNoTarg, rcAllocating, rcMemory, rcExhausted); } else { item->type = type; item->access = access; item->size = size; item->loc = loc; item->mtime = mtime; item->path = (char *)(item+1); strcpy (item->path, path); if (type & kptAlias) { item->link = item->path + pathlen + 1; strcpy (item->link, link); } else item->link = NULL; DLListPushHead (&data->list, &item->dad); if (type == kptDir) rc = step_through_dir (dir, path, data->filter, data->fdata, list_action, data); } } } } return rc; }
/* HomeDirectory * returns a KDirectory where the binary for a given function is located * * "dir" [ OUT ] - return parameter for home directory ( read-only ), if found * * "func" [ IN ] - function pointer within binary to be located */ LIB_EXPORT rc_t CC KDyldHomeDirectory ( const KDyld *self, const KDirectory **dir, fptr_t func ) { rc_t rc; if ( dir == NULL ) rc = RC ( rcFS, rcDylib, rcSearching, rcParam, rcNull ); else { * dir = NULL; if ( self == NULL ) rc = RC ( rcFS, rcDylib, rcSearching, rcSelf, rcNull ); else if ( func == NULL ) rc = RC ( rcFS, rcDylib, rcSearching, rcFunction, rcNull ); else { Dl_info info; memset ( & info, 0, sizeof info ); if ( dladdr ( ( void* ) func, & info ) == 0 ) rc = RC ( rcFS, rcDylib, rcSearching, rcFunction, rcNotFound ); else { KDirectory *wd; rc = KDirectoryNativeDir ( & wd ); if ( rc == 0 ) { /* turn this into a real path */ const KSysDir *sdir = KDirectoryGetSysDir ( wd ); if ( sdir == NULL ) rc = RC ( rcFS, rcDylib, rcSearching, rcDirectory, rcIncorrect ); else { /* "dladdr" will return a simple name rather than a path when the address is within the application itself and the application was found using PATH. this is brilliant design at its best. */ char thanks_for_brilliant_APIs [ PATH_MAX ]; const char *dli_fname = info . dli_fname; /* check for a path rather than a name */ const char *last_slash = strrchr ( info . dli_fname, '/' ); if ( last_slash == NULL ) { /* simple name - get PATH */ const char *PATH = getenv ( "PATH" ); rc = RC ( rcFS, rcDylib, rcSearching, rcPath, rcNotFound ); if ( PATH != NULL ) { /* loop over PATH */ const char *path_start, *path_end; for ( path_start = PATH;; path_start = path_end + 1 ) { /* look for non-empty directory */ path_end = strchr ( path_start, ':' ); if ( path_start != path_end && path_start [ 0 ] != 0 ) { rc_t rc2; uint32_t path_type; /* handle last element in list */ if ( path_end == NULL ) last_slash = path_start + strlen ( path_start ); else for ( last_slash = path_end; last_slash > path_start; -- last_slash ) { if ( last_slash [ -1 ] != '/' ) break; } /* create possible path, using up to ':' */ rc2 = string_printf ( thanks_for_brilliant_APIs, sizeof thanks_for_brilliant_APIs, NULL, "%.*s/%s", ( int ) ( last_slash - path_start ), path_start, dli_fname ); /* if failed to create path string */ if ( rc2 != 0 ) break; /* check path against working directory */ path_type = KDirectoryPathType ( wd, thanks_for_brilliant_APIs ); if ( ( path_type & ~ kptAlias ) == kptFile ) { uint32_t access = 0; rc = KDirectoryAccess ( wd, & access, thanks_for_brilliant_APIs ); if ( rc != 0 ) break; /* try to do a quick check that the file can be executed. but it could fail to do the right guess. */ if ( access & 0100 || access & 0010 || access & 0001 ) { /* this is a file, which can be assumed to be an executable */ dli_fname = thanks_for_brilliant_APIs; last_slash = & thanks_for_brilliant_APIs [ last_slash - path_start ]; rc = 0; break; } } } /* exit if no more paths */ if ( path_end == NULL ) break; } } } if ( rc == 0 ) { char real [ PATH_MAX ]; rc = KSysDirRealPath ( sdir, real, sizeof real, "%.*s" , ( int ) ( last_slash - dli_fname ), dli_fname ); if ( rc == 0 ) rc = KDirectoryOpenDirRead ( wd, dir, false, real ); DBGMSG(DBG_KFS, DBG_FLAG(DBG_KFS_DIR), ("%s: %R path is '%s'\n", __func__, rc, real)); } } KDirectoryRelease ( wd ); } } } } return rc; }
static rc_t list_action (const KDirectory * dir, const char * path, void * _adata) { rc_t rc = 0; list_adata * data = _adata; list_item * item = NULL; KPathType type = KDirectoryPathType (dir, "%s", path); size_t pathlen = strlen (path); size_t linklen = 0; char link [2 * 4096]; /* we'll truncate? */ if (type & kptAlias) { rc = KDirectoryVResolveAlias (dir, false, link, sizeof (link), path, NULL); if (rc == 0) linklen = strlen (link); } if (rc == 0) { item = calloc (sizeof (*item) + pathlen + linklen + 2, 1); /* usually one too many */ if (item == NULL) { rc = RC (rcExe, rcNoTarg, rcAllocating, rcMemory, rcExhausted); } else { do { item->path = (char *)(item+1); strcpy (item->path, path); item->type = type; rc = KDirectoryAccess (dir, &item->access, "%s", path); if (rc) break; rc = KDirectoryDate (dir, &item->mtime, "%s", path); if (rc) break; if (type & kptAlias) { item->link = item->path + pathlen + 1; strcpy (item->link, link); } else switch (type & ~kptAlias) { case kptNotFound: rc = RC (rcExe, rcDirectory, rcAccessing, rcPath, rcNotFound); break; case kptBadPath: rc = RC (rcExe, rcDirectory, rcAccessing, rcPath, rcInvalid); break; case kptZombieFile: data->has_zombies = true; case kptFile: rc = KDirectoryFileSize (dir, &item->size, "%s", path); if (rc == 0) rc = KDirectoryFileLocator (dir, &item->loc, "%s", path); DBGMSG (DBG_APP, 1, ("%s: found file %s size %lu at %lu\n", __func__, item->path, item->size, item->loc)); break; case kptDir: DBGMSG (DBG_APP, 1, ("%s: found directory %s\n", __func__, item->path)); break; default: DBGMSG (DBG_APP, 1, ("%s: found unknown %s\n", __func__, item->path)); break; } } while (0); } } if (rc == 0) { VectorAppend (&data->list, NULL, item); VectorInsert (&data->sort, item, NULL, list_item_cmp); if (type == kptDir) rc = step_through_dir (dir, path, list_action, data); } return rc; }
rc_t CopyFileToFile( const KDirectory *top, const char *inname, KDirectory *targettop, const char *outname ) { const KFile *in = NULL; KFile *out = NULL; KFile *md5file = NULL; KMD5File *md5out = NULL; KMD5SumFmt *md5sumfmt = NULL; char md5filename[1024]; rc_t rc = 0; uint32_t mode = 0; uint32_t pathtype = 0; uint32_t failed = 0; if (PathIsMD5File(top, inname)) { /* Skip it */ return 0; } rc = KDirectoryOpenFileRead( top, &in, "%s", inname ); if (rc != 0) { failed = rc; goto FAIL; } mode = DEFAULTMODE; rc = KDirectoryAccess( top, &mode, inname); if (rc != 0) { failed = rc; goto FAIL; } /* * Not sure here -- does kcmInit re-initialize the file mode as we specify? * Or does it preserve the existing mode (and do we want it to)? */ if (clobber_protections) { pathtype = KDirectoryPathType( targettop, "%s", outname ); if ((pathtype & ~kptAlias) == kptFile) { rc = KDirectorySetAccess( targettop, false, mode, 0777, "%s", outname); if (rc != 0) { failed = rc; goto FAIL; } } } rc = KDirectoryCreateFile( targettop, &out, false, mode, (force? kcmInit: kcmCreate), "%s", outname ); if (rc != 0) { failed = rc; goto FAIL; } sprintf(md5filename, "%s.md5", outname); rc = KDirectoryCreateFile( targettop, &md5file, false, DEFAULTMODE, (force? kcmInit: kcmCreate), "%s", md5filename); if (rc != 0) { failed = rc; goto FAIL; } rc = KMD5SumFmtMakeUpdate( &md5sumfmt, md5file); if (rc != 0) { failed = rc; goto FAIL; } rc = KMD5FileMakeWrite( &md5out, out, md5sumfmt, outname ); if (rc != 0) { failed = rc; goto FAIL; } { uint64_t rpos = 0; uint64_t wpos = 0; size_t numread; while (true) { rc = KFileRead( in, rpos, buffer, BUFSIZE, &numread ); /* fprintf(stderr, "Read %d bytes.\n", numread); */ if (rc == 0 && numread == 0) break; if (rc != 0) { failed = rc; goto FAIL; } rpos += numread; { size_t numwritten = 0; int written = 0; while (written < numread) { rc = KFileWrite( (KFile *)md5out, wpos, buffer+written, numread-written, &numwritten ); if (rc != 0) { failed = rc; break; } if (numwritten == 0) { fprintf(stderr, "Didn't write anything.\n"); failed = -1; goto FAIL; } wpos += numwritten; written += numwritten; } } } } /* Success also, check the value of failed to see if failed */ FAIL: if (NULL != md5out) { KFileRelease((KFile *)md5out); md5out = NULL; } /*KFileRelease(out); */ if (NULL != md5sumfmt) { KMD5SumFmtRelease(md5sumfmt); md5sumfmt = NULL; } /* KFileRelease(md5file); */ if (NULL != in) { KFileRelease(in); in = NULL; } /* KDirectoryRelease(top); */ if (failed) { KDirectoryRemove( targettop, false, "%s", md5filename ); KDirectoryRemove( targettop, false, "%s", outname); } return failed; }