1/******************************************************************************
2/
3/	File:			FileUtils.cpp
4/
5/   Description:	Utility functions for copying file data and attributes.
6/
7/	Copyright 1998-1999, Be Incorporated, All Rights Reserved
8/
9******************************************************************************/
10#include "FileUtils.h"
11
12#include <algorithm>
13#include <new>
14#include <stdio.h>
15#include <string.h>
16
17#include <fs_attr.h>
18
19#include "AutoDeleter.h"
20
21
22using std::nothrow;
23
24
25status_t
26CopyFileData(BFile& dst, BFile& src)
27{
28	struct stat src_stat;
29	status_t err = src.GetStat(&src_stat);
30	if (err != B_OK) {
31		printf("couldn't get stat: %#010" B_PRIx32 "\n", err);
32		return err;
33	}
34
35	size_t bufSize = src_stat.st_blksize;
36	if (bufSize == 0)
37		bufSize = 32768;
38
39	char* buf = new (nothrow) char[bufSize];
40	if (buf == NULL)
41		return B_NO_MEMORY;
42	ArrayDeleter<char> _(buf);
43
44	printf("copy data, bufSize = %ld\n", bufSize);
45	// copy data
46	while (true) {
47		ssize_t bytes = src.Read(buf, bufSize);
48		if (bytes > 0) {
49			ssize_t result = dst.Write(buf, bytes);
50			if (result != bytes) {
51				fprintf(stderr, "Failed to write %ld bytes: %s\n", bytes,
52					strerror((status_t)result));
53				if (result < 0)
54					return (status_t)result;
55				else
56					return B_IO_ERROR;
57			}
58		} else {
59			if (bytes < 0) {
60				fprintf(stderr, "Failed to read file: %s\n", strerror(
61					(status_t)bytes));
62				return (status_t)bytes;
63			} else {
64				// EOF
65				break;
66			}
67		}
68	}
69
70	// finish up miscellaneous stat stuff
71	dst.SetPermissions(src_stat.st_mode);
72	dst.SetOwner(src_stat.st_uid);
73	dst.SetGroup(src_stat.st_gid);
74	dst.SetModificationTime(src_stat.st_mtime);
75	dst.SetCreationTime(src_stat.st_crtime);
76
77	return B_OK;
78}
79
80
81status_t
82CopyAttributes(BNode& dst, BNode& src)
83{
84	// copy attributes
85	src.RewindAttrs();
86	char attrName[B_ATTR_NAME_LENGTH];
87	while (src.GetNextAttrName(attrName) == B_OK) {
88		attr_info info;
89		if (src.GetAttrInfo(attrName, &info) != B_OK) {
90			fprintf(stderr, "Failed to read info for attribute '%s'\n",
91				attrName);
92			continue;
93		}
94		// copy one attribute in chunks of 4096 bytes
95		size_t size = 4096;
96		uint8 buffer[size];
97		off_t offset = 0;
98		ssize_t read = src.ReadAttr(attrName, info.type, offset, buffer,
99			std::min((off_t)size, info.size));
100		if (read < 0) {
101			fprintf(stderr, "Error reading attribute '%s'\n", attrName);
102			return (status_t)read;
103		}
104		// NOTE: Attributes of size 0 are perfectly valid!
105		while (read >= 0) {
106			ssize_t written = dst.WriteAttr(attrName, info.type, offset,
107				buffer, read);
108			if (written != read) {
109				fprintf(stderr, "Error writing attribute '%s'\n", attrName);
110				if (written < 0)
111					return (status_t)written;
112				else
113					return B_IO_ERROR;
114			}
115			offset += read;
116			read = src.ReadAttr(attrName, info.type, offset, buffer,
117				std::min((off_t)size, info.size - offset));
118			if (read < 0) {
119				fprintf(stderr, "Error reading attribute '%s'\n", attrName);
120				return (status_t)read;
121			}
122			if (read == 0)
123				break;
124		}
125	}
126
127	return B_OK;
128}
129
130
131status_t
132CopyFile(BFile& dst, BFile& src)
133{
134	status_t err = CopyFileData(dst, src);
135	if (err != B_OK)
136		return err;
137
138	return CopyAttributes(dst, src);
139}
140