root/src/apps/soundrecorder/FileUtils.cpp
/******************************************************************************
/
/       File:                   FileUtils.cpp
/
/   Description:        Utility functions for copying file data and attributes.
/
/       Copyright 1998-1999, Be Incorporated, All Rights Reserved
/
******************************************************************************/
#include "FileUtils.h"

#include <algorithm>
#include <new>
#include <stdio.h>
#include <string.h>

#include <fs_attr.h>

#include "AutoDeleter.h"


using std::nothrow;


status_t
CopyFileData(BFile& dst, BFile& src)
{
        struct stat src_stat;
        status_t err = src.GetStat(&src_stat);
        if (err != B_OK) {
                printf("couldn't get stat: %#010" B_PRIx32 "\n", err);
                return err;
        }
                
        size_t bufSize = src_stat.st_blksize;
        if (bufSize == 0)
                bufSize = 32768;
        
        char* buf = new (nothrow) char[bufSize];
        if (buf == NULL)
                return B_NO_MEMORY;
        ArrayDeleter<char> _(buf);
        
        printf("copy data, bufSize = %ld\n", bufSize);
        // copy data
        while (true) {
                ssize_t bytes = src.Read(buf, bufSize);
                if (bytes > 0) {
                        ssize_t result = dst.Write(buf, bytes);
                        if (result != bytes) {
                                fprintf(stderr, "Failed to write %ld bytes: %s\n", bytes,
                                        strerror((status_t)result));
                                if (result < 0)
                                        return (status_t)result;
                                else
                                        return B_IO_ERROR;
                        }
                } else {
                        if (bytes < 0) {
                                fprintf(stderr, "Failed to read file: %s\n", strerror(
                                        (status_t)bytes));
                                return (status_t)bytes;
                        } else {
                                // EOF
                                break;
                        }
                }
        }

        // finish up miscellaneous stat stuff
        dst.SetPermissions(src_stat.st_mode);
        dst.SetOwner(src_stat.st_uid);
        dst.SetGroup(src_stat.st_gid);
        dst.SetModificationTime(src_stat.st_mtime);
        dst.SetCreationTime(src_stat.st_crtime);

        return B_OK;
}


status_t
CopyAttributes(BNode& dst, BNode& src)
{
        // copy attributes
        src.RewindAttrs();
        char attrName[B_ATTR_NAME_LENGTH];
        while (src.GetNextAttrName(attrName) == B_OK) {
                attr_info info;
                if (src.GetAttrInfo(attrName, &info) != B_OK) {
                        fprintf(stderr, "Failed to read info for attribute '%s'\n",
                                attrName);
                        continue;
                }
                // copy one attribute in chunks of 4096 bytes
                size_t size = 4096;
                uint8 buffer[size];
                off_t offset = 0;
                ssize_t read = src.ReadAttr(attrName, info.type, offset, buffer,
                        std::min((off_t)size, info.size));
                if (read < 0) {
                        fprintf(stderr, "Error reading attribute '%s'\n", attrName);
                        return (status_t)read;
                }
                // NOTE: Attributes of size 0 are perfectly valid!
                while (read >= 0) {
                        ssize_t written = dst.WriteAttr(attrName, info.type, offset, 
                                buffer, read);
                        if (written != read) {
                                fprintf(stderr, "Error writing attribute '%s'\n", attrName);
                                if (written < 0)
                                        return (status_t)written;
                                else
                                        return B_IO_ERROR;
                        }
                        offset += read;
                        read = src.ReadAttr(attrName, info.type, offset, buffer,
                                std::min((off_t)size, info.size - offset));
                        if (read < 0) {
                                fprintf(stderr, "Error reading attribute '%s'\n", attrName);
                                return (status_t)read;
                        }
                        if (read == 0)
                                break;
                }
        }

        return B_OK;            
}


status_t
CopyFile(BFile& dst, BFile& src)
{
        status_t err = CopyFileData(dst, src);
        if (err != B_OK)
                return err;
                
        return CopyAttributes(dst, src);
}