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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 * Portions of this source code were derived from Berkeley 4.3 BSD
31 * under license from the Regents of the University of California.
48 * Allocation wrappers. Used to centralize error handling for
52 e_alloc_fail(int flag
)
55 msg(EXTN
, "Out of memory");
61 * Note: unlike the other e_*lloc functions, e_realloc does not zero out the
62 * additional memory it returns. Ensure that you do not trust its contents
66 e_realloc(int flag
, void *old
, size_t newsize
)
68 void *ret
= realloc(old
, newsize
);
71 return (e_alloc_fail(flag
));
78 e_strdup(int flag
, const char *arg
)
80 char *ret
= strdup(arg
);
83 return (e_alloc_fail(flag
));
90 e_valloc(int flag
, size_t size
)
92 void *ret
= valloc(size
);
95 return (e_alloc_fail(flag
));
102 e_zalloc(int flag
, size_t size
)
104 void *ret
= malloc(size
);
107 return (e_alloc_fail(flag
));
110 (void) memset(ret
, 0, size
);
115 * Simple printf() which only support "%s" conversion.
116 * We need secure version of printf since format string can be supplied
120 str_fprintf(FILE *fp
, const char *fmt
, ...)
128 (void) fputc(*s
++, fp
);
133 (void) fputc(*(s
- 1), fp
);
134 (void) fputc(*s
++, fp
);
137 (void) fputs(va_arg(ap
, char *), fp
);
144 * Step through a file discovering and recording pairs of data and hole
145 * offsets. Returns a linked list of data/hole offset pairs of a file.
146 * If there is no holes found, NULL is returned.
148 * Note: According to lseek(2), only filesystems which support
149 * fpathconf(_PC_MIN_HOLE_SIZE) support SEEK_HOLE. For filesystems
150 * that do not supply information about holes, the file will be
151 * represented as one entire data region.
153 static holes_list_t
*
154 get_holes_list(int fd
, off_t filesz
, size_t *countp
)
157 holes_list_t
*hlh
, *hl
, **hlp
;
160 if (filesz
== 0 || fpathconf(fd
, _PC_MIN_HOLE_SIZE
) < 0)
168 while (hole
< filesz
) {
169 if ((data
= lseek(fd
, hole
, SEEK_DATA
)) == -1) {
170 /* no more data till the end of file */
171 if (errno
== ENXIO
) {
174 /* assume data starts from the * beginning */
178 if ((hole
= lseek(fd
, data
, SEEK_HOLE
)) == -1) {
179 /* assume that data ends at the end of file */
182 if (data
== 0 && hole
== filesz
) {
186 hl
= e_zalloc(E_EXIT
, sizeof (holes_list_t
));
189 /* set data and hole */
201 * reset to the beginning, otherwise subsequent read calls would
204 (void) lseek(fd
, 0, SEEK_SET
);
210 * Calculate the real data size in the sparse file.
213 get_compressed_filesz(holes_list_t
*hlh
)
219 for (hl
= hlh
; hl
!= NULL
; hl
= hl
->hl_next
) {
220 size
+= (hl
->hl_hole
- hl
->hl_data
);
226 * Convert val to digit string and put it in str. The next address
227 * of the last digit is returned.
230 put_value(off_t val
, char *str
)
233 char *digp
, dbuf
[ULL_MAX_SIZE
+ 1];
235 dbuf
[ULL_MAX_SIZE
] = '\0';
236 digp
= ulltostr((u_longlong_t
)val
, &dbuf
[ULL_MAX_SIZE
]);
237 len
= &dbuf
[ULL_MAX_SIZE
] - digp
;
238 (void) memcpy(str
, digp
, len
);
244 * Put data/hole offset pair into string in the following
246 * <data> <sp> <hole> <sp>
249 store_sparse_string(holes_list_t
*hlh
, char *str
, size_t *szp
)
255 for (hl
= hlh
; hl
!= NULL
; hl
= hl
->hl_next
) {
256 p
= put_value(hl
->hl_data
, p
);
258 p
= put_value(hl
->hl_hole
, p
);
267 * Convert decimal str into unsigned long long value. The end pointer
271 get_ull_tok(const char *str
, uint64_t *ulp
)
276 while (isspace(*str
))
282 ul
= strtoull(str
, &np
, 10);
283 if (ul
== ULLONG_MAX
&& errno
== ERANGE
)
284 return (NULL
); /* invalid value */
285 if (*np
!= ' ' && *np
!= '\0')
286 return (NULL
); /* invalid input */
293 free_holesdata(holes_info_t
*hi
)
295 holes_list_t
*hl
, *nhl
;
297 for (hl
= hi
->holes_list
; hl
!= NULL
; hl
= nhl
) {
301 hi
->holes_list
= NULL
;
304 hi
->holesdata
= NULL
;
308 * When a hole is detected, non NULL holes_info pointer is returned.
309 * If we are in copy-out mode, holes_list is converted to string (holesdata)
310 * which will be prepended to file contents. The holesdata is a character
311 * string and in the format of:
313 * <data size(%10u)><SP><file size(%llu)><SP>
314 * <SP><data off><SP><hole off><SP><data off><SP><hole off> ...
316 * This string is parsed by parse_holesholes() in copy-in mode to restore
320 get_holes_info(int fd
, off_t filesz
, boolean_t pass_mode
)
324 char *str
, hstr
[MIN_HOLES_HDRSIZE
+ 1];
327 if ((hl
= get_holes_list(fd
, filesz
, &ninfo
)) == NULL
)
330 hi
= e_zalloc(E_EXIT
, sizeof (holes_info_t
));
334 str
= e_zalloc(E_EXIT
,
335 MIN_HOLES_HDRSIZE
+ ninfo
* (ULL_MAX_SIZE
* 2));
337 * Convert into string data, and place it to after
338 * the first 2 fixed entries.
340 store_sparse_string(hl
, str
+ MIN_HOLES_HDRSIZE
, &len
);
343 * Add the first two fixed entries. The size of holesdata
344 * includes '\0' at the end of data
346 (void) sprintf(hstr
, "%10lu %20llu ",
347 (ulong_t
)MIN_HOLES_HDRSIZE
+ len
+ 1, filesz
);
348 (void) memcpy(str
, hstr
, MIN_HOLES_HDRSIZE
);
350 /* calc real file size without holes */
351 hi
->data_size
= get_compressed_filesz(hl
);
353 hi
->holesdata_sz
= MIN_HOLES_HDRSIZE
+ len
+ 1;
359 * The holesdata information is in the following format:
360 * <data size(%10u)><SP><file size(%llu)><SP>
361 * <SP><data off><SP><hole off><SP><data off><SP><hole off> ...
362 * read_holes_header() allocates holes_info_t, and read the first 2
363 * entries (data size and file size). The rest of holesdata is
364 * read by parse_holesdata().
367 read_holes_header(const char *str
, off_t filesz
)
372 hi
= e_zalloc(E_EXIT
, sizeof (holes_info_t
));
374 /* read prepended holes data size */
375 if ((str
= get_ull_tok(str
, &ull
)) == NULL
|| *str
!= ' ') {
380 hi
->holesdata_sz
= (size_t)ull
;
382 /* read original(expanded) file size */
383 if (get_ull_tok(str
, &ull
) == NULL
)
385 hi
->orig_size
= (off_t
)ull
;
388 if (hi
->holesdata_sz
> filesz
||
389 hi
->holesdata_sz
<= MIN_HOLES_HDRSIZE
) {
396 parse_holesdata(holes_info_t
*hi
, const char *str
)
398 holes_list_t
*hl
, **hlp
;
402 /* create hole list */
403 hlp
= &hi
->holes_list
;
404 while (*str
!= '\0') {
405 hl
= e_zalloc(E_EXIT
, sizeof (holes_list_t
));
411 /* read the string token for data */
412 if ((str
= get_ull_tok(str
, &ull
)) == NULL
)
414 hl
->hl_data
= (off_t
)ull
;
416 /* there must be single blank space in between */
420 /* read the string token for hole */
421 if ((str
= get_ull_tok(str
, &ull
)) == NULL
)
423 hl
->hl_hole
= (off_t
)ull
;
426 /* check to see if offset is in ascending order */
428 for (hl
= hi
->holes_list
; hl
!= NULL
; hl
= hl
->hl_next
) {
429 if (loff
>= hl
->hl_data
)
432 /* data and hole can be equal */
433 if (loff
> hl
->hl_hole
)
437 /* The last hole offset should match original file size */
438 if (hi
->orig_size
!= loff
) {
444 hi
->data_size
= get_compressed_filesz(hi
->holes_list
);
450 free_holes_info(holes_info_t
*hi
)