xref: /haiku/src/system/kernel/disk_device_manager/UserDataWriter.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
1 // UserDataWriter.cpp
2 
3 #include <util/kernel_cpp.h>
4 #include <ddm_userland_interface.h>
5 #include <Vector.h>
6 
7 #include "UserDataWriter.h"
8 
9 // RelocationEntryList
10 struct UserDataWriter::RelocationEntryList : Vector<addr_t*> {};
11 
12 
13 UserDataWriter::UserDataWriter()
14 	: fBuffer(NULL),
15 	  fBufferSize(0),
16 	  fAllocatedSize(0),
17 	  fRelocationEntries(NULL)
18 {
19 }
20 
21 
22 UserDataWriter::UserDataWriter(user_disk_device_data *buffer,
23 							   size_t bufferSize)
24 	: fBuffer(NULL),
25 	  fBufferSize(0),
26 	  fAllocatedSize(0),
27 	  fRelocationEntries(NULL)
28 {
29 	SetTo(buffer, bufferSize);
30 }
31 
32 
33 UserDataWriter::~UserDataWriter()
34 {
35 	delete fRelocationEntries;
36 }
37 
38 
39 status_t
40 UserDataWriter::SetTo(user_disk_device_data *buffer, size_t bufferSize)
41 {
42 	Unset();
43 	fBuffer = buffer;
44 	fBufferSize = bufferSize;
45 	fAllocatedSize = 0;
46 	if (fBuffer && fBufferSize > 0) {
47 		fRelocationEntries = new(std::nothrow) RelocationEntryList;
48 		if (!fRelocationEntries)
49 			return B_NO_MEMORY;
50 	}
51 	return B_OK;
52 }
53 
54 
55 void
56 UserDataWriter::Unset()
57 {
58 	delete fRelocationEntries;
59 	fBuffer = NULL;
60 	fBufferSize = 0;
61 	fAllocatedSize = 0;
62 	fRelocationEntries = NULL;
63 }
64 
65 
66 void *
67 UserDataWriter::AllocateData(size_t size, size_t align)
68 {
69 	// handles size == 0 gracefully
70 	// get a properly aligned offset
71 	size_t offset = fAllocatedSize;
72 	if (align > 1)
73 		offset = (fAllocatedSize + align - 1) / align * align;
74 	// get the result pointer
75 	void *result = NULL;
76 	if (fBuffer && offset + size <= fBufferSize)
77 		result = (uint8*)fBuffer + offset;
78 	// always update the allocated size, even if there wasn't enough space
79 	fAllocatedSize = offset + size;
80 	return result;
81 }
82 
83 
84 user_partition_data *
85 UserDataWriter::AllocatePartitionData(size_t childCount)
86 {
87 	return (user_partition_data*)AllocateData(
88 		sizeof(user_partition_data)
89 		+ sizeof(user_partition_data*) * ((int32)childCount - 1),
90 		sizeof(int));
91 }
92 
93 
94 user_disk_device_data *
95 UserDataWriter::AllocateDeviceData(size_t childCount)
96 {
97 	return (user_disk_device_data*)AllocateData(
98 		sizeof(user_disk_device_data)
99 		+ sizeof(user_partition_data*) * ((int32)childCount - 1),
100 		sizeof(int));
101 }
102 
103 
104 char *
105 UserDataWriter::PlaceString(const char *str)
106 {
107 	if (!str)
108 		return NULL;
109 	size_t len = strlen(str) + 1;
110 	char *data = (char*)AllocateData(len);
111 	if (data)
112 		memcpy(data, str, len);
113 	return data;
114 }
115 
116 
117 size_t
118 UserDataWriter::AllocatedSize() const
119 {
120 	return fAllocatedSize;
121 }
122 
123 
124 status_t
125 UserDataWriter::AddRelocationEntry(void *address)
126 {
127 	if (fRelocationEntries && (addr_t)address >= (addr_t)fBuffer
128 		&& (addr_t)address < (addr_t)fBuffer + fBufferSize - sizeof(void*)) {
129 		return fRelocationEntries->PushBack((addr_t*)address);
130 	}
131 	return B_ERROR;
132 }
133 
134 
135 status_t
136 UserDataWriter::Relocate(void *address)
137 {
138 	if (!fRelocationEntries || !fBuffer)
139 		return B_BAD_VALUE;
140 	int32 count = fRelocationEntries->Count();
141 	for (int32 i = 0; i < count; i++) {
142 		addr_t *entry = fRelocationEntries->ElementAt(i);
143 		if (*entry)
144 			*entry += (addr_t)address - (addr_t)fBuffer;
145 	}
146 	return B_OK;
147 }
148