140 lines
3.1 KiB
C++
140 lines
3.1 KiB
C++
/******************************************************************************
|
|
/
|
|
/ 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);
|
|
}
|