xref: /haiku/src/add-ons/kernel/file_systems/udf/Utils.cpp (revision b8ded2f89783a220c7b3019d48266a682cc79158)
170081c0dSSalvatore Benedetto /*
2c530d46cSJérôme Duval  * Copyright 2012, Jérôme Duval, korli@users.berlios.de.
370081c0dSSalvatore Benedetto  * Copyright 2003, Tyler Dauwalder, tyler@dauwalder.net.
470081c0dSSalvatore Benedetto  * Distributed under the terms of the MIT License.
524ec5f43STyler Dauwalder  */
624ec5f43STyler Dauwalder 
770081c0dSSalvatore Benedetto /*! \file Utils.cpp - Miscellaneous Udf utility functions. */
870081c0dSSalvatore Benedetto 
920d84995SRene Gollent #include "UdfStructures.h"
1024ec5f43STyler Dauwalder #include "Utils.h"
1124ec5f43STyler Dauwalder 
12fb8ce469STyler Dauwalder extern "C" {
13fb8ce469STyler Dauwalder 	extern int32 timezone_offset;
14fb8ce469STyler Dauwalder }
15fb8ce469STyler Dauwalder 
1670081c0dSSalvatore Benedetto /*! \brief Returns "true" if \a value is true, "false" otherwise. */
1770081c0dSSalvatore Benedetto const char*
bool_to_string(bool value)1870081c0dSSalvatore Benedetto bool_to_string(bool value)
1924ec5f43STyler Dauwalder {
2070081c0dSSalvatore Benedetto 	return value ? "true" : "false";
2124ec5f43STyler Dauwalder }
2224ec5f43STyler Dauwalder 
2370081c0dSSalvatore Benedetto 
2470081c0dSSalvatore Benedetto /*! \brief Calculates the UDF crc checksum for the given byte stream.
2570081c0dSSalvatore Benedetto 
2670081c0dSSalvatore Benedetto 	Based on crc code from UDF-2.50 6.5, as permitted.
2770081c0dSSalvatore Benedetto 
2870081c0dSSalvatore Benedetto 	\param data Pointer to the byte stream.
2970081c0dSSalvatore Benedetto 	\param length Length of the byte stream in bytes.
3070081c0dSSalvatore Benedetto 
3170081c0dSSalvatore Benedetto 	\return The crc checksum, or 0 if an error occurred.
3270081c0dSSalvatore Benedetto */
3370081c0dSSalvatore Benedetto uint16
calculate_crc(uint8 * data,uint16 length)3470081c0dSSalvatore Benedetto calculate_crc(uint8 *data, uint16 length)
3524ec5f43STyler Dauwalder {
3670081c0dSSalvatore Benedetto 	uint16 crc = 0;
3770081c0dSSalvatore Benedetto 	if (data) {
3870081c0dSSalvatore Benedetto 		for ( ; length > 0; length--, data++)
3970081c0dSSalvatore Benedetto 			crc = kCrcTable[(crc >> 8 ^ *data) & 0xff] ^ (crc << 8);
4024ec5f43STyler Dauwalder 	}
4170081c0dSSalvatore Benedetto 	return crc;
4270081c0dSSalvatore Benedetto }
4370081c0dSSalvatore Benedetto 
4470081c0dSSalvatore Benedetto 
4570081c0dSSalvatore Benedetto /*! \brief Takes an overloaded ssize_t return value like those returned
4670081c0dSSalvatore Benedetto 	by BFile::Read() and friends, as well as an expected number of bytes,
4770081c0dSSalvatore Benedetto 	and returns B_OK if the byte counts match, or the appropriate error
4870081c0dSSalvatore Benedetto 	code otherwise.
4970081c0dSSalvatore Benedetto */
5070081c0dSSalvatore Benedetto status_t
check_size_error(ssize_t bytesReturned,ssize_t bytesExpected)5170081c0dSSalvatore Benedetto check_size_error(ssize_t bytesReturned, ssize_t bytesExpected)
5270081c0dSSalvatore Benedetto {
5370081c0dSSalvatore Benedetto 	return bytesReturned == bytesExpected
5470081c0dSSalvatore Benedetto 		? B_OK : (bytesReturned >= 0 ? B_IO_ERROR : status_t(bytesReturned));
5570081c0dSSalvatore Benedetto }
5670081c0dSSalvatore Benedetto 
5770081c0dSSalvatore Benedetto 
5870081c0dSSalvatore Benedetto /*! \brief Calculates the block shift amount for the given
5970081c0dSSalvatore Benedetto  	block size, which must be a positive power of 2.
6070081c0dSSalvatore Benedetto */
6170081c0dSSalvatore Benedetto status_t
get_block_shift(uint32 blockSize,uint32 & blockShift)6270081c0dSSalvatore Benedetto get_block_shift(uint32 blockSize, uint32 &blockShift)
6370081c0dSSalvatore Benedetto {
6470081c0dSSalvatore Benedetto 	if (blockSize == 0)
6570081c0dSSalvatore Benedetto 		return B_BAD_VALUE;
6670081c0dSSalvatore Benedetto 	uint32 bitCount = 0;
6770081c0dSSalvatore Benedetto 	uint32 result = 0;
6870081c0dSSalvatore Benedetto 	for (int i = 0; i < 32; i++) {
6970081c0dSSalvatore Benedetto 		// Zero out all bits except bit i
7070081c0dSSalvatore Benedetto 		uint32 block = blockSize & (uint32(1) << i);
7170081c0dSSalvatore Benedetto 		if (block) {
7270081c0dSSalvatore Benedetto 			if (++bitCount > 1)
7370081c0dSSalvatore Benedetto 				return B_BAD_VALUE;
7470081c0dSSalvatore Benedetto 			else
7570081c0dSSalvatore Benedetto 				result = i;
7670081c0dSSalvatore Benedetto 		}
7770081c0dSSalvatore Benedetto 	}
7870081c0dSSalvatore Benedetto 	blockShift = result;
7970081c0dSSalvatore Benedetto 	return B_OK;
8070081c0dSSalvatore Benedetto }
8170081c0dSSalvatore Benedetto 
8224ec5f43STyler Dauwalder 
83c530d46cSJérôme Duval #define EPOCH_YEAR	1970
84c530d46cSJérôme Duval #define MAX_YEAR	69
85c530d46cSJérôme Duval #define SECSPERMIN	60
86c530d46cSJérôme Duval #define MINSPERHOUR	60
87c530d46cSJérôme Duval #define HOURSPERDAY	24
88c530d46cSJérôme Duval #define SECSPERDAY	(SECSPERMIN * MINSPERHOUR * HOURSPERDAY)
89c530d46cSJérôme Duval #define DAYSPERNYEAR	365
90c530d46cSJérôme Duval 
91c530d46cSJérôme Duval status_t
decode_time(timestamp & timestamp,struct timespec & timespec)92c530d46cSJérôme Duval decode_time(timestamp &timestamp, struct timespec &timespec)
93fb8ce469STyler Dauwalder {
9421ea9aeaSTyler Dauwalder 	DEBUG_INIT_ETC(NULL, ("timestamp: (tnt: 0x%x, type: %d, timezone: %d = 0x%x, year: %d, "
95fb8ce469STyler Dauwalder 	           "month: %d, day: %d, hour: %d, minute: %d, second: %d)", timestamp.type_and_timezone(),
96fb8ce469STyler Dauwalder 	           timestamp.type(), timestamp.timezone(),
97fb8ce469STyler Dauwalder 	            timestamp.timezone(),timestamp.year(),
98fb8ce469STyler Dauwalder 	           timestamp.month(), timestamp.day(), timestamp.hour(), timestamp.minute(), timestamp.second()));
99fb8ce469STyler Dauwalder 
100c530d46cSJérôme Duval 	if (timestamp.year() < EPOCH_YEAR || timestamp.year() >= EPOCH_YEAR + MAX_YEAR)
101c530d46cSJérôme Duval 		return B_BAD_VALUE;
102fb8ce469STyler Dauwalder 
103c530d46cSJérôme Duval 	time_t result = 0;
10470081c0dSSalvatore Benedetto 	const int monthLengths[12]
10570081c0dSSalvatore Benedetto 		= { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
106fb8ce469STyler Dauwalder 
107fb8ce469STyler Dauwalder 	int year = timestamp.year();
108fb8ce469STyler Dauwalder 	int month = timestamp.month();
109fb8ce469STyler Dauwalder 	int day = timestamp.day();
110fb8ce469STyler Dauwalder 	int hour = timestamp.hour();
111fb8ce469STyler Dauwalder 	int minute = timestamp.minute();
112fb8ce469STyler Dauwalder 	int second = timestamp.second();
113fb8ce469STyler Dauwalder 
114fb8ce469STyler Dauwalder 	// Range check the timezone offset, then round it down
115fb8ce469STyler Dauwalder 	// to the nearest hour, since no one I know treats timezones
116fb8ce469STyler Dauwalder 	// with a per-minute granularity, and none of the other OSes
117fb8ce469STyler Dauwalder 	// I've looked at appear to either.
118c530d46cSJérôme Duval 	int timezone_offset = 0;
119c530d46cSJérôme Duval 	if (timestamp.type() == 1)
120c530d46cSJérôme Duval 		timezone_offset = timestamp.timezone();
121c530d46cSJérôme Duval 	if (-SECSPERDAY > timezone_offset || timezone_offset > SECSPERDAY)
122fb8ce469STyler Dauwalder 		timezone_offset = 0;
123fb8ce469STyler Dauwalder 	timezone_offset -= timezone_offset % 60;
124fb8ce469STyler Dauwalder 
125fb8ce469STyler Dauwalder 	int previousLeapYears = (year - 1968) / 4;
126fb8ce469STyler Dauwalder 	bool isLeapYear = (year - 1968) % 4 == 0;
127fb8ce469STyler Dauwalder 	if (isLeapYear)
128fb8ce469STyler Dauwalder 		--previousLeapYears;
129fb8ce469STyler Dauwalder 
130fb8ce469STyler Dauwalder 	// Years to days
131c530d46cSJérôme Duval 	result = (year - EPOCH_YEAR) * DAYSPERNYEAR + previousLeapYears;
132fb8ce469STyler Dauwalder 	// Months to days
133fb8ce469STyler Dauwalder 	for (int i = 0; i < month-1; i++) {
134fb8ce469STyler Dauwalder 		result += monthLengths[i];
135fb8ce469STyler Dauwalder 	}
136fb8ce469STyler Dauwalder 	if (month > 2 && isLeapYear)
137fb8ce469STyler Dauwalder 		++result;
138fb8ce469STyler Dauwalder 	// Days to hours
139c530d46cSJérôme Duval 	result = (result + day - 1) * HOURSPERDAY;
140fb8ce469STyler Dauwalder 	// Hours to minutes
141c530d46cSJérôme Duval 	result = (result + hour) * MINSPERHOUR + timezone_offset;
142fb8ce469STyler Dauwalder 	// Minutes to seconds
143c530d46cSJérôme Duval 	result = (result + minute) * SECSPERMIN + second;
144fb8ce469STyler Dauwalder 
145c530d46cSJérôme Duval 	timespec.tv_sec = result;
146c530d46cSJérôme Duval 	timespec.tv_nsec = 1000 * (timestamp.microsecond()
147c530d46cSJérôme Duval 		+ timestamp.hundred_microsecond() * 100
148c530d46cSJérôme Duval 		+ timestamp.centisecond() * 10000);
149c530d46cSJérôme Duval 	return B_OK;
150fb8ce469STyler Dauwalder }
151fb8ce469STyler Dauwalder 
15270081c0dSSalvatore Benedetto 
15370081c0dSSalvatore Benedetto long_address
to_long_address(ino_t id,uint32 length)15470081c0dSSalvatore Benedetto to_long_address(ino_t id, uint32 length)
155f79d99c8STyler Dauwalder {
156*7e5b0f96SJérôme Duval 	TRACE(("udf_to_long_address: ino_t = %" B_PRIdINO ", length = %" B_PRIu32,
157*7e5b0f96SJérôme Duval 		id, length));
15870081c0dSSalvatore Benedetto 	long_address result;
15970081c0dSSalvatore Benedetto 	result.set_block((id >> 16) & 0xffffffff);
16070081c0dSSalvatore Benedetto 	result.set_partition(id & 0xffff);
16170081c0dSSalvatore Benedetto 	result.set_length(length);
16270081c0dSSalvatore Benedetto 	DUMP(result);
16370081c0dSSalvatore Benedetto 	return result;
164f79d99c8STyler Dauwalder }
165f79d99c8STyler Dauwalder 
16670081c0dSSalvatore Benedetto 
16770081c0dSSalvatore Benedetto ino_t
to_vnode_id(long_address address)16870081c0dSSalvatore Benedetto to_vnode_id(long_address address)
169af44f8e6STyler Dauwalder {
17070081c0dSSalvatore Benedetto 	DEBUG_INIT(NULL);
17170081c0dSSalvatore Benedetto 	ino_t result = address.block();
17270081c0dSSalvatore Benedetto 	result <<= 16;
17370081c0dSSalvatore Benedetto 	result |= address.partition();
174*7e5b0f96SJérôme Duval 	TRACE(("block:     %" B_PRIu32 ", 0x%" B_PRIx32 "\n", address.block(),
175*7e5b0f96SJérôme Duval 		address.block()));
176c9334140SSalvatore Benedetto 	TRACE(("partition: %d, 0x%x\n", address.partition(), address.partition()));
177*7e5b0f96SJérôme Duval 	TRACE(("length:    %" B_PRIu32 ", 0x%" B_PRIx32 "\n", address.length(),
178*7e5b0f96SJérôme Duval 		address.length()));
179*7e5b0f96SJérôme Duval 	TRACE(("ino_t:     %" B_PRIdINO "\n", result));
18070081c0dSSalvatore Benedetto 	return result;
181af44f8e6STyler Dauwalder }
182