Пример #1
0
/* 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;
}
Пример #2
0
/*
 * 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;
}  
Пример #3
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;
}
Пример #4
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;
}
Пример #5
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
/* 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;
}
Пример #9
0
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;
}
Пример #10
0
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;

}