1//----------------------------------------------------------------------
2//  This software is part of the OpenBeOS distribution and is covered
3//  by the OpenBeOS license.
4//
5//  Copyright (c) 2003 Tyler Dauwalder, tyler@dauwalder.net
6//----------------------------------------------------------------------
7
8/*! \file UdfBuilder.h
9
10	Main UDF image building class interface declarations.
11*/
12
13#ifndef _UDF_BUILDER_H
14#define _UDF_BUILDER_H
15
16#include <Entry.h>
17#include <list>
18#include <Node.h>
19#include <stdarg.h>
20#include <string>
21#include <SupportDefs.h>
22
23#include "Allocator.h"
24#include "FileStream.h"
25#include "MemoryStream.h"
26#include "PhysicalPartitionAllocator.h"
27#include "ProgressListener.h"
28#include "Statistics.h"
29#include "UdfString.h"
30
31/*! \brief Handy struct into which all the interesting information about
32	a processed directory, file, or whatever is placed by the corresponding
33	UdfBuilder::_Process*() function.
34*/
35struct node_data {
36	Udf::long_address icbAddress;			//!< Udf icb address
37	std::list<Udf::long_address> udfData;	//!< Dataspace for node in Udf partition space
38	std::list<Udf::extent_address> isoData;	//!< Dataspace for node in physical space
39};
40
41class UdfBuilder {
42public:
43	UdfBuilder(const char *outputFile, uint32 blockSize, bool doUdf,
44	           const char *udfVolumeName, uint16 udfRevision, bool doIso,
45	           const char *isoVolumeName,
46	           const char *rootDirectory, const ProgressListener &listener,
47	           bool truncate);
48	status_t InitCheck() const;
49	status_t Build();
50private:
51	//! Maximum length of string generated by calls to any _Print*() functions
52	static const int kMaxUpdateStringLength = 1024;
53
54	FileStream& _OutputFile() { return fOutputFile; }
55	uint32 _BlockSize() const { return fBlockSize; }
56	uint32 _BlockShift() const { return fBlockShift; }
57	bool _DoUdf() const { return fDoUdf; }
58	Udf::String& _UdfVolumeName() { return fUdfVolumeName; }
59	uint16 _UdfRevision() const { return fUdfRevision; }
60	uint16 _UdfDescriptorVersion() const { return fUdfDescriptorVersion; }
61	const Udf::entity_id& _UdfDomainId() const { return fUdfDomainId; }
62	bool _DoIso() const { return fDoIso; }
63	Udf::String& _IsoVolumeName() { return fIsoVolumeName; }
64	BEntry& _RootDirectory() { return fRootDirectory; }
65	Allocator& _Allocator() { return fAllocator; }
66	PhysicalPartitionAllocator& _PartitionAllocator() { return fPartitionAllocator; }
67	Statistics& _Stats() { return fStatistics; }
68	time_t _BuildTime() const { return fBuildTime; }
69	Udf::timestamp& _BuildTimeStamp() { return fBuildTimeStamp; }
70	uint64 _NextUniqueId();
71	bool _32BitIdsNoLongerUnique() const { return f32BitIdsNoLongerUnique; }
72
73	void _SetBuildTime(time_t time);
74
75	status_t _FormatString(char *message, const char *formatString, va_list arguments) const;
76	void _PrintError(const char *formatString, ...) const;
77	void _PrintWarning(const char *formatString, ...) const;
78	void _PrintUpdate(VerbosityLevel level, const char *formatString, ...) const;
79
80	status_t _ProcessDirectory(BEntry &entry, const char *path, struct stat stats,
81	                           node_data &node, Udf::long_address parentIcbAddress,
82	                           bool isRootDirectory = false);
83	status_t _ProcessFile(BEntry &entry, const char *path, struct stat stats,
84	                      node_data &node);
85	status_t _ProcessSymlink(BEntry &symlink);
86	status_t _ProcessAttributes(BNode &node);
87
88	template <class FileEntry>
89		status_t _WriteFileEntry(FileEntry *icb, uint8 fileType, uint16 linkCount,
90		                         uint64 dataLength, uint64 objectSize, struct stat stats,
91		                         uint64 uniqueId, uint32 allocationDescriptorsLength,
92		                         Udf::tag_id fileEntryType, Udf::long_address icbAddress,
93		                         Udf::extent_address icbExtent,
94		                         std::list<Udf::long_address> dataAddresses);
95
96	status_t fInitStatus;
97	FileStream fOutputFile;
98	std::string fOutputFilename;
99	uint32 fBlockSize;
100	uint32 fBlockShift;
101	bool fDoUdf;
102	Udf::String fUdfVolumeName;
103	uint16 fUdfRevision;
104	uint16 fUdfDescriptorVersion;
105	const Udf::entity_id &fUdfDomainId;
106	bool fDoIso;
107	Udf::String fIsoVolumeName;
108	BEntry fRootDirectory;
109	std::string fRootDirectoryName;
110	const ProgressListener &fListener;
111	Allocator fAllocator;
112	PhysicalPartitionAllocator fPartitionAllocator;
113	Statistics fStatistics;
114	time_t fBuildTime;
115	Udf::timestamp fBuildTimeStamp;
116	uint64 fNextUniqueId;
117	bool f32BitIdsNoLongerUnique;
118};
119
120template <class FileEntry>
121status_t
122UdfBuilder::_WriteFileEntry(FileEntry *icb, uint8 fileType, uint16 linkCount,
123		                    uint64 dataLength, uint64 objectSize, struct stat stats,
124		                    uint64 uniqueId, uint32 allocationDescriptorsLength,
125		                    Udf::tag_id fileEntryType, Udf::long_address icbAddress,
126		                    Udf::extent_address icbExtent,
127		                    std::list<Udf::long_address> dataAddresses)
128{
129	DEBUG_INIT_ETC("UdfBuilder", ("type: %s", icb->descriptor_name()));
130	status_t error = B_ERROR;
131	Udf::icb_entry_tag &itag = icb->icb_tag();
132	itag.set_prior_recorded_number_of_direct_entries(0);
133	itag.set_strategy_type(Udf::ICB_STRATEGY_SINGLE);
134	memset(itag.strategy_parameters().data, 0,
135	       itag.strategy_parameters().size());
136	itag.set_entry_count(1);
137	itag.reserved() = 0;
138	itag.set_file_type(fileType);
139	itag.parent_icb_location() = kNullLogicalBlock;
140	Udf::icb_entry_tag::flags_accessor &iflags = itag.flags_access();
141	// clear flags, then set those of interest
142	iflags.all_flags = 0;
143	iflags.flags.descriptor_flags = Udf::ICB_DESCRIPTOR_TYPE_LONG;
144	iflags.flags.archive = 1;
145	icb->set_uid(0xffffffff);
146	icb->set_gid(0xffffffff);
147	icb->set_permissions(Udf::OTHER_EXECUTE | Udf::OTHER_READ
148	                    | Udf::GROUP_EXECUTE | Udf::GROUP_READ
149	                    | Udf::USER_EXECUTE | Udf::USER_READ);
150	icb->set_file_link_count(linkCount);
151	icb->set_record_format(0);
152	icb->set_record_display_attributes(0);
153	icb->set_record_length(0);
154	icb->set_information_length(dataLength);
155	icb->set_object_size(objectSize);	// EFE only
156	icb->set_logical_blocks_recorded(_Allocator().BlocksFor(dataLength));
157	icb->access_date_and_time() = Udf::timestamp(stats.st_atime);
158	icb->modification_date_and_time() = Udf::timestamp(stats.st_mtime);
159	icb->creation_date_and_time() = Udf::timestamp(stats.st_crtime);	// EFE only
160	icb->attribute_date_and_time() = icb->creation_date_and_time();
161	icb->set_checkpoint(1);
162	icb->set_reserved(0);	// EFE only
163	icb->extended_attribute_icb() = kNullAddress;
164	icb->stream_directory_icb() = kNullAddress;	// EFE only
165	icb->implementation_id() = Udf::kImplementationId;
166	icb->set_unique_id(uniqueId);
167	icb->set_extended_attributes_length(0);
168	icb->set_allocation_descriptors_length(allocationDescriptorsLength);
169	icb->tag().set_id(fileEntryType);
170	icb->tag().set_version(_UdfDescriptorVersion());
171	icb->tag().set_serial_number(0);
172	icb->tag().set_location(icbAddress.block());
173
174	// write allocation descriptors
175	std::list<Udf::long_address>::iterator a;
176	MemoryStream descriptorStream(icb->allocation_descriptors(),
177	                              allocationDescriptorsLength);
178	error = descriptorStream.InitCheck();
179	if (!error) {
180		for (a = dataAddresses.begin();
181		       a != dataAddresses.end() && error == B_OK;
182		         a++)
183		{
184			PRINT(("Dumping address:\n"));
185			DUMP(*a);
186			Udf::long_address &address = *a;
187			ssize_t bytes = descriptorStream.Write(&address, sizeof(address));
188			error = check_size_error(bytes, sizeof(address));
189		}
190	}
191	icb->tag().set_checksums(*icb, icb->descriptor_size());
192	PDUMP(icb);
193
194	// Write udf icb
195	if (!error) {
196		_PrintUpdate(VERBOSITY_MEDIUM, "udf: Writing icb");
197		// write icb
198		_OutputFile().Seek(off_t(icbExtent.location()) << _BlockShift(), SEEK_SET);
199		PRINT(("position, icbsize: %Ld, %ld\n", _OutputFile().Position(), sizeof(icb)));
200		ssize_t bytes = _OutputFile().Write(icb, _BlockSize());
201		PRINT(("position: %Ld\n", _OutputFile().Position()));
202		error = check_size_error(bytes, _BlockSize());
203		PRINT(("position: %Ld\n", _OutputFile().Position()));
204	}
205	RETURN(error);
206}
207
208#endif	// _UDF_BUILDER_H
209