vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / partitioning_systems / atari / atari.cpp
blob5bcc1058a909f1c3dcdea52f9dec7ee857649136
1 /*
2 * Copyright 2003-2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include "atari.h"
9 #include <ByteOrder.h>
10 #include <KernelExport.h>
11 #include <ddm_modules.h>
12 #ifdef _BOOT_MODE
13 # include <boot/partitions.h>
14 #else
15 # include <DiskDeviceTypes.h>
16 #endif
17 #include <util/kernel_cpp.h>
19 #include <unistd.h>
20 #include <string.h>
21 #include <ctype.h>
23 #define SECTSZ 512
25 //#define TRACE_ATARI_PARTITION
26 #ifdef TRACE_ATARI_PARTITION
27 # define TRACE(x) dprintf x
28 #else
29 # define TRACE(x) ;
30 #endif
33 #define ATARI_PARTITION_MODULE_NAME "partitioning_systems/atari/v1"
34 #define ATARI_PARTITION_NAME "Atari Partition Map"
37 #if 0
38 template<typename Type> bool
39 validate_check_sum(Type *type)
41 if (type->SummedLongs() != sizeof(*type) / sizeof(uint32))
42 return false;
44 // check checksum
45 uint32 *longs = (uint32 *)type;
46 uint32 sum = 0;
47 for (uint32 i = 0; i < type->SummedLongs(); i++)
48 sum += B_BENDIAN_TO_HOST_INT32(longs[i]);
50 #ifdef TRACE_ATARI_PARTITION
51 if (sum != 0)
52 TRACE(("search_rdb: check sum is incorrect!\n"));
53 #endif
55 return sum == 0;
57 #endif
60 // #pragma mark -
61 // Atari Root Block public module interface
64 static status_t
65 atari_std_ops(int32 op, ...)
67 switch (op) {
68 case B_MODULE_INIT:
69 case B_MODULE_UNINIT:
70 return B_OK;
73 return B_ERROR;
77 static float
78 atari_identify_partition(int fd, partition_data *partition, void **_cookie)
80 uint8 buffer[512];
81 atari_root_block *arb = (atari_root_block *)buffer;
82 float weight = 0.5;
83 int i;
84 ssize_t bytesRead = read_pos(fd, 0, buffer, sizeof(buffer));
85 if (bytesRead < (ssize_t)sizeof(buffer)) {
86 TRACE(("%s: read error: %ld\n", __FUNCTION__, bytesRead));
87 return B_ERROR;
89 if (partition->offset)
90 return B_ERROR;
92 if (arb->Checksum() == 0x55aa)
93 weight -= 0.1; /* possible but likely a PC sector */
94 if (arb->_reserved_1[1] != 0x00)
95 weight -= 10;
96 /* hope so */
97 if (arb->MaxPartitionSize() < 10)
98 weight -= 20;
100 if ((arb->BadSectorsStart()+arb->BadSectorsCount())*(off_t)SECTSZ > partition->size)
101 return B_ERROR;
103 /* check each partition */
104 for (i = 0; i < 4; i++) {
105 struct atari_partition_entry *p = &arb->partitions[i];
106 if (p->Flags() & ATARI_PART_EXISTS) {
107 /* check for unknown flags */
108 if (p->Flags() & ~ (ATARI_PART_EXISTS|ATARI_PART_BOOTABLE))
109 weight -= 10.0;
110 /* id should be readable */
111 if (!isalnum(p->id[0]))
112 weight -= 1.0;
113 if (!isalnum(p->id[1]))
114 weight -= 1.0;
115 if (!isalnum(p->id[2]))
116 weight -= 1.0;
117 /* make sure partition doesn't overlap bad sector list */
118 if ((arb->BadSectorsStart() < p->Start()) &&
119 ((arb->BadSectorsStart() + arb->BadSectorsCount()) > p->Start()))
120 weight -= 10;
121 if ((p->Start()+p->Size())*(off_t)SECTSZ > partition->size)
122 return B_ERROR;
123 /* should check partitions don't overlap each other... */
124 } else {
125 /* empty partition entry, then it must be all null */
126 if (p->Flags() || p->id[0] || p->id[1] || p->id[2] ||
127 p->Start() || p->Size())
128 weight -= 10.0;
129 else
130 weight += 0.1;
133 /* not exactly sure */
134 if (arb->Checksum() != ATARI_BOOTABLE_MAGIC)
135 weight -= 0.1;
137 if (weight > 1.0)
138 weight = 1.0;
140 if (weight > 0.0) {
141 // copy the root block to a new piece of memory
142 arb = new atari_root_block();
143 memcpy(arb, buffer, sizeof(atari_root_block));
145 *_cookie = (void *)arb;
146 return weight;
149 return B_ERROR;
153 static status_t
154 atari_scan_partition(int fd, partition_data *partition, void *_cookie)
156 TRACE(("atari_scan_partition(cookie = %p)\n", _cookie));
158 atari_root_block &arb = *(atari_root_block *)_cookie;
160 partition->status = B_PARTITION_VALID;
161 partition->flags |= B_PARTITION_PARTITIONING_SYSTEM
162 | B_PARTITION_READ_ONLY;
163 partition->content_size = partition->size;
165 // scan all children
167 uint32 index = 0;
168 status_t status = B_ENTRY_NOT_FOUND;
170 for (index = 0; index < 4; index++) {
171 struct atari_partition_entry *p = &arb.partitions[index];
172 if (!(p->Flags() & ATARI_PART_EXISTS))
173 continue;
174 TRACE(("atari: file system: %.3s\n", p->id));
175 if ((p->Start() + p->Size())*(uint64)SECTSZ > (uint64)partition->size) {
176 TRACE(("atari: child partition exceeds existing space (%Ld bytes)\n", p->Size()*SECTSZ));
177 continue;
179 if (!isalnum(p->id[0]))
180 continue;
181 if (!isalnum(p->id[1]))
182 continue;
183 if (!isalnum(p->id[2]))
184 continue;
186 partition_data *child = create_child_partition(partition->id, index,
187 partition->offset + p->Start() * (uint64)SECTSZ,
188 p->Size() * (uint64)SECTSZ, -1);
189 if (child == NULL) {
190 TRACE(("atari: Creating child at index %ld failed\n", index - 1));
191 return B_ERROR;
193 #warning M68K: use a lookup table ?
194 char type[] = "??? Partition";
195 memcpy(type, p->id, 3);
196 child->type = strdup(type);
197 child->block_size = SECTSZ;
198 status = B_OK;
201 if (status == B_ENTRY_NOT_FOUND)
202 return B_OK;
204 return status;
208 static void
209 atari_free_identify_partition_cookie(partition_data *partition, void *_cookie)
211 delete (atari_root_block *)_cookie;
215 #ifndef _BOOT_MODE
216 static partition_module_info sAtariPartitionModule = {
217 #else
218 partition_module_info gAtariPartitionModule = {
219 #endif
221 ATARI_PARTITION_MODULE_NAME,
223 atari_std_ops
225 "atari", // short_name
226 ATARI_PARTITION_NAME, // pretty_name
227 0, // flags
229 // scanning
230 atari_identify_partition, // identify_partition
231 atari_scan_partition, // scan_partition
232 atari_free_identify_partition_cookie, // free_identify_partition_cookie
233 NULL,
234 // atari_free_partition_cookie, // free_partition_cookie
235 // atari_free_partition_content_cookie, // free_partition_content_cookie
238 #ifndef _BOOT_MODE
239 partition_module_info *modules[] = {
240 &sAtariPartitionModule,
241 NULL
243 #endif