1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25
26#pragma ident	"%Z%%M%	%I%	%E% SMI"
27
28/*
29 * libfstyp module for udfs
30 */
31#include <fcntl.h>
32#include <stdio.h>
33#include <errno.h>
34#include <unistd.h>
35#include <locale.h>
36#include <stdlib.h>
37#include <strings.h>
38#include <sys/param.h>
39#include <sys/stat.h>
40#include <sys/time.h>
41#include <sys/types.h>
42#include <sys/file.h>
43#include <libnvpair.h>
44#include <libfstyp_module.h>
45#include <sys/fs/udf_volume.h>
46#include "ud_lib.h"
47
48
49typedef struct fstyp_udfs {
50	int		fd;
51	ud_handle_t	udh;
52	nvlist_t	*attr;
53} fstyp_udfs_t;
54
55static int	is_udfs(fstyp_udfs_t *h);
56static int	print_vds(fstyp_udfs_t *h, struct vds *,
57		FILE *fout, FILE *ferr);
58static int	get_attr(fstyp_udfs_t *h);
59
60int	fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle);
61void	fstyp_mod_fini(fstyp_mod_handle_t handle);
62int	fstyp_mod_ident(fstyp_mod_handle_t handle);
63int	fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp);
64int	fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr);
65
66
67int
68fstyp_mod_init(int fd, off_t offset, fstyp_mod_handle_t *handle)
69{
70	fstyp_udfs_t *h = (fstyp_udfs_t *)handle;
71
72	if (offset != 0) {
73		return (FSTYP_ERR_OFFSET);
74	}
75
76	if ((h = calloc(1, sizeof (fstyp_udfs_t))) == NULL) {
77		return (FSTYP_ERR_NOMEM);
78	}
79	h->fd = fd;
80
81	if (ud_init(h->fd, &h->udh) != 0) {
82		free(h);
83		return (FSTYP_ERR_NOMEM);
84	}
85
86	*handle = (fstyp_mod_handle_t)h;
87	return (0);
88}
89
90void
91fstyp_mod_fini(fstyp_mod_handle_t handle)
92{
93	fstyp_udfs_t *h = (fstyp_udfs_t *)handle;
94
95	if (h->attr == NULL) {
96		nvlist_free(h->attr);
97		h->attr = NULL;
98	}
99	ud_fini(h->udh);
100	free(h);
101}
102
103int
104fstyp_mod_ident(fstyp_mod_handle_t handle)
105{
106	fstyp_udfs_t *h = (fstyp_udfs_t *)handle;
107
108	return (is_udfs(h));
109}
110
111int
112fstyp_mod_get_attr(fstyp_mod_handle_t handle, nvlist_t **attrp)
113{
114	fstyp_udfs_t *h = (fstyp_udfs_t *)handle;
115	int error;
116
117	if (h->attr == NULL) {
118		if (nvlist_alloc(&h->attr, NV_UNIQUE_NAME_TYPE, 0)) {
119			return (FSTYP_ERR_NOMEM);
120		}
121		if ((error = get_attr(h)) != 0) {
122			nvlist_free(h->attr);
123			h->attr = NULL;
124			return (error);
125		}
126	}
127
128	*attrp = h->attr;
129	return (0);
130}
131
132int
133fstyp_mod_dump(fstyp_mod_handle_t handle, FILE *fout, FILE *ferr)
134{
135	fstyp_udfs_t *h = (fstyp_udfs_t *)handle;
136	struct udf *udfs = &h->udh->udfs;
137	int ret;
138
139	(void) fprintf(fout,
140		"Standard Identifier %5s\n", udfs->ecma_id);
141
142	if (udfs->flags & VALID_MVDS) {
143		ret = print_vds(h, &udfs->mvds, fout, ferr);
144	} else {
145		ret = print_vds(h, &udfs->rvds, fout, ferr);
146	}
147
148	return (ret);
149}
150
151
152/*
153 * Assumption is that we will confirm to level-1
154 */
155int
156is_udfs(fstyp_udfs_t *h)
157{
158	struct udf *udfs = &h->udh->udfs;
159	int32_t ret;
160
161	if ((ret = ud_fill_udfs_info(h->udh)) != 0) {
162		return (ret);
163	}
164
165	if ((udfs->flags & VALID_UDFS) == 0) {
166		return (FSTYP_ERR_NO_MATCH);
167	}
168
169	return (0);
170}
171
172/*
173 * For now, only return generic attributes.
174 * Will open an RFE to add native attributes.
175 */
176static int
177get_attr(fstyp_udfs_t *h)
178{
179	struct udf *udfs = &h->udh->udfs;
180	struct vds *v;
181	struct pri_vol_desc *pvd;
182	uint32_t len;
183	uint64_t off;
184	uint8_t *buf;
185	int8_t str[64];
186	int ret = 0;
187
188	v = (udfs->flags & VALID_MVDS) ? &udfs->mvds : &udfs->rvds;
189
190	/* allocate buffer */
191	len = udfs->lbsize;
192	if (v->pvd_len > len) {
193		len = v->pvd_len;
194	}
195	if ((buf = (uint8_t *)malloc(len)) == NULL) {
196		return (FSTYP_ERR_NOMEM);
197	}
198
199	(void) nvlist_add_boolean_value(h->attr, "gen_clean", B_TRUE);
200
201	/* Primary Volume Descriptor */
202	if (v->pvd_len != 0) {
203		off = v->pvd_loc * udfs->lbsize;
204		if (ud_read_dev(h->udh, off, buf, v->pvd_len) != 0) {
205			ret = FSTYP_ERR_IO;
206			goto out;
207		}
208		/* LINTED */
209		pvd = (struct pri_vol_desc *)(uint32_t *)buf;
210
211		ud_convert2local(pvd->pvd_vol_id, str, 32);
212		str[32] = '\0';
213		(void) nvlist_add_string(h->attr, "gen_volume_label", str);
214	}
215
216	ret = 0;
217
218out:
219	free(buf);
220	return (ret);
221}
222
223/* ARGSUSED */
224int
225print_vds(fstyp_udfs_t *h, struct vds *v, FILE *fout, FILE *ferr)
226{
227	struct udf *udfs = &h->udh->udfs;
228	int32_t i;
229	uint32_t len;
230	uint64_t off;
231	uint8_t *buf;
232	int	ret = 0;
233
234	/*
235	 * All descriptors are 512 bytes
236	 * except lvd, usd and lvid
237	 * findout the largest and allocate space
238	 */
239	len = udfs->lbsize;
240	if (v->lvd_len > len) {
241		len = v->lvd_len;
242	}
243	if (v->usd_len > len) {
244		len = v->usd_len;
245	}
246	if (udfs->lvid_len > len) {
247		len = udfs->lvid_len;
248	}
249
250	if ((buf = (uint8_t *)malloc(len)) == NULL) {
251		return (FSTYP_ERR_NOMEM);
252	}
253
254	/*
255	 * Anchor Volume Descriptor
256	 */
257	if (udfs->avdp_len != 0) {
258		off = udfs->avdp_loc * udfs->lbsize;
259		if (ud_read_dev(h->udh, off, buf, udfs->avdp_len) != 0) {
260			ret = FSTYP_ERR_IO;
261			goto out;
262		}
263
264		/* LINTED */
265		print_avd(fout, (struct anch_vol_desc_ptr *)buf);
266	}
267
268	/*
269	 * Primary Volume Descriptor
270	 */
271	if (v->pvd_len != 0) {
272		off = v->pvd_loc * udfs->lbsize;
273		if (ud_read_dev(h->udh, off, buf, v->pvd_len) != 0) {
274			ret = FSTYP_ERR_IO;
275			goto out;
276		}
277
278		/* LINTED */
279		print_pvd(fout, (struct pri_vol_desc *)buf);
280	}
281
282	/*
283	 * Implementation Use descriptor
284	 */
285	if (v->iud_len != 0) {
286		off = v->iud_loc * udfs->lbsize;
287		if (ud_read_dev(h->udh, off, buf, v->iud_len) != 0) {
288			ret = FSTYP_ERR_IO;
289			goto out;
290		}
291
292		/* LINTED */
293		print_iuvd(fout, (struct iuvd_desc *)buf);
294	}
295
296	/*
297	 * Paritions
298	 */
299	for (i = 0; i < h->udh->n_parts; i++) {
300		if (v->part_len[i] != 0) {
301			off = v->part_loc[i] * udfs->lbsize;
302			if (ud_read_dev(h->udh, off, buf,
303			    v->part_len[i]) != 0) {
304				ret = FSTYP_ERR_IO;
305				goto out;
306			}
307
308			/* LINTED */
309			print_part(fout, (struct part_desc *)buf);
310		}
311	}
312
313	/*
314	 * Logical Volume Descriptor
315	 */
316	if (v->lvd_len != 0) {
317		off = v->lvd_loc * udfs->lbsize;
318		if (ud_read_dev(h->udh, off, buf, v->lvd_len) != 0) {
319			ret = FSTYP_ERR_IO;
320			goto out;
321		}
322
323		/* LINTED */
324		print_lvd(fout, (struct log_vol_desc *)buf);
325	}
326
327	/*
328	 * Unallocated Space Descriptor
329	 */
330	if (v->usd_len != 0) {
331		off = v->usd_loc * udfs->lbsize;
332		if (ud_read_dev(h->udh, off, buf, v->usd_len) != 0) {
333			ret = FSTYP_ERR_IO;
334			goto out;
335		}
336
337		/* LINTED */
338		print_usd(fout, (struct unall_spc_desc *)buf);
339	}
340
341	/*
342	 * Logical Volume Integrity Descriptor
343	 */
344	if (udfs->lvid_len != 0) {
345		off = udfs->lvid_loc * udfs->lbsize;
346		if (ud_read_dev(h->udh, off, buf, udfs->lvid_len) != 0) {
347			ret = FSTYP_ERR_IO;
348			goto out;
349		}
350
351		/* LINTED */
352		print_lvid(fout, (struct log_vol_int_desc *)buf);
353	}
354
355	/*
356	 * File Set Descriptor
357	 */
358	if (udfs->fsd_len != 0) {
359		off = udfs->fsd_loc * udfs->lbsize;
360		if (ud_read_dev(h->udh, off, buf, udfs->fsd_len) != 0) {
361			ret = FSTYP_ERR_IO;
362			goto out;
363		}
364
365		/* LINTED */
366		print_fsd(fout, h->udh, (struct file_set_desc *)buf);
367	}
368	ret = 0;
369
370out:
371	free(buf);
372	return (ret);
373}
374