1214921Scognet/* $NetBSD: cd9660_archimedes.c,v 1.1 2009/01/10 22:06:29 bjh21 Exp $ */
2214921Scognet
3214921Scognet/*-
4214921Scognet * Copyright (c) 1998, 2009 Ben Harris
5214921Scognet * All rights reserved.
6214921Scognet *
7214921Scognet * Redistribution and use in source and binary forms, with or without
8214921Scognet * modification, are permitted provided that the following conditions
9214921Scognet * are met:
10214921Scognet * 1. Redistributions of source code must retain the above copyright
11214921Scognet *    notice, this list of conditions and the following disclaimer.
12214921Scognet * 2. Redistributions in binary form must reproduce the above copyright
13214921Scognet *    notice, this list of conditions and the following disclaimer in the
14214921Scognet *    documentation and/or other materials provided with the distribution.
15214921Scognet * 3. The name of the author may not be used to endorse or promote products
16214921Scognet *    derived from this software without specific prior written permission.
17214921Scognet *
18214921Scognet * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19214921Scognet * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20214921Scognet * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21214921Scognet * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22214921Scognet * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23214921Scognet * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24214921Scognet * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25214921Scognet * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26214921Scognet * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27214921Scognet * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28214921Scognet */
29214921Scognet/*
30214921Scognet * cd9660_archimedes.c - support for RISC OS "ARCHIMEDES" extension
31214921Scognet *
32214921Scognet * RISC OS CDFS looks for a special block at the end of the System Use
33214921Scognet * Field for each file.  If present, this contains the RISC OS load
34214921Scognet * and exec address (used to hold the file timestamp and type), the
35214921Scognet * file attributes, and a flag indicating whether the first character
36214921Scognet * of the filename should be replaced with '!' (since many special
37214921Scognet * RISC OS filenames do).
38214921Scognet */
39214921Scognet
40214921Scognet#include <sys/cdefs.h>
41214921Scognet__FBSDID("$FreeBSD: releng/10.2/usr.sbin/makefs/cd9660/cd9660_archimedes.c 214921 2010-11-07 16:05:04Z cognet $");
42214921Scognet
43214921Scognet#include <assert.h>
44214921Scognet#include <stdint.h>
45214921Scognet#include <stdio.h>
46214921Scognet#include <string.h>
47214921Scognet
48214921Scognet#include "makefs.h"
49214921Scognet#include "cd9660.h"
50214921Scognet#include "cd9660_archimedes.h"
51214921Scognet
52214921Scognet/*
53214921Scognet * Convert a Unix time_t (non-leap seconds since 1970-01-01) to a RISC
54214921Scognet * OS time (non-leap(?) centiseconds since 1900-01-01(?)).
55214921Scognet */
56214921Scognet
57214921Scognetstatic u_int64_t
58214921Scognetriscos_date(time_t unixtime)
59214921Scognet{
60214921Scognet	u_int64_t base;
61214921Scognet
62214921Scognet	base = 31536000ULL * 70 + 86400 * 17;
63214921Scognet	return (((u_int64_t)unixtime) + base)*100;
64214921Scognet}
65214921Scognet
66214921Scognet/*
67214921Scognet * Add "ARCHIMEDES" metadata to a node if that seems appropriate.
68214921Scognet *
69214921Scognet * We touch regular files with names matching /,[0-9a-f]{3}$/ and
70214921Scognet * directories matching /^!/.
71214921Scognet */
72214921Scognetstatic void
73214921Scognetarchimedes_convert_node(cd9660node *node)
74214921Scognet{
75214921Scognet	struct ISO_ARCHIMEDES *arc;
76214921Scognet	size_t len;
77214921Scognet	int type = -1;
78214921Scognet	uint64_t stamp;
79214921Scognet
80214921Scognet	if (node->su_tail_data != NULL)
81214921Scognet		/* Something else already has the tail. */
82214921Scognet		return;
83214921Scognet
84214921Scognet	len = strlen(node->node->name);
85214921Scognet	if (len < 1) return;
86214921Scognet
87214921Scognet	if (len >= 4 && node->node->name[len-4] == ',')
88214921Scognet		/* XXX should support ,xxx and ,lxa */
89214921Scognet		type = strtoul(node->node->name + len - 3, NULL, 16);
90214921Scognet	if (type == -1 && node->node->name[0] != '!')
91214921Scognet		return;
92214921Scognet	if (type == -1) type = 0;
93214921Scognet
94214921Scognet	assert(sizeof(struct ISO_ARCHIMEDES) == 32);
95214921Scognet	if ((arc = calloc(1, sizeof(struct ISO_ARCHIMEDES))) == NULL) {
96214921Scognet		CD9660_MEM_ALLOC_ERROR("archimedes_convert_node");
97214921Scognet		exit(1);
98214921Scognet	}
99214921Scognet
100214921Scognet	stamp = riscos_date(node->node->inode->st.st_mtime);
101214921Scognet
102214921Scognet	memcpy(arc->magic, "ARCHIMEDES", 10);
103214921Scognet	cd9660_731(0xfff00000 | (type << 8) | (stamp >> 32), arc->loadaddr);
104214921Scognet	cd9660_731(stamp & 0x00ffffffffULL, arc->execaddr);
105214921Scognet	arc->ro_attr = RO_ACCESS_UR | RO_ACCESS_OR;
106214921Scognet	arc->cdfs_attr = node->node->name[0] == '!' ? CDFS_PLING : 0;
107214921Scognet	node->su_tail_data = (void *)arc;
108214921Scognet	node->su_tail_size = sizeof(*arc);
109214921Scognet}
110214921Scognet
111214921Scognet/*
112214921Scognet * Add "ARCHIMEDES" metadata to an entire tree recursively.
113214921Scognet */
114214921Scognetvoid
115214921Scognetarchimedes_convert_tree(cd9660node *node)
116214921Scognet{
117214921Scognet	cd9660node *cn;
118214921Scognet
119214921Scognet	assert(node != NULL);
120214921Scognet
121214921Scognet	archimedes_convert_node(node);
122214921Scognet
123214921Scognet		/* Recurse on children. */
124214921Scognet	TAILQ_FOREACH(cn, &node->cn_children, cn_next_child)
125214921Scognet		archimedes_convert_tree(cn);
126214921Scognet}
127