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
;
303 if (hi
->holesdata
!= NULL
)
305 hi
->holesdata
= NULL
;
309 * When a hole is detected, non NULL holes_info pointer is returned.
310 * If we are in copy-out mode, holes_list is converted to string (holesdata)
311 * which will be prepended to file contents. The holesdata is a character
312 * string and in the format of:
314 * <data size(%10u)><SP><file size(%llu)><SP>
315 * <SP><data off><SP><hole off><SP><data off><SP><hole off> ...
317 * This string is parsed by parse_holesholes() in copy-in mode to restore
321 get_holes_info(int fd
, off_t filesz
, boolean_t pass_mode
)
325 char *str
, hstr
[MIN_HOLES_HDRSIZE
+ 1];
328 if ((hl
= get_holes_list(fd
, filesz
, &ninfo
)) == NULL
)
331 hi
= e_zalloc(E_EXIT
, sizeof (holes_info_t
));
335 str
= e_zalloc(E_EXIT
,
336 MIN_HOLES_HDRSIZE
+ ninfo
* (ULL_MAX_SIZE
* 2));
338 * Convert into string data, and place it to after
339 * the first 2 fixed entries.
341 store_sparse_string(hl
, str
+ MIN_HOLES_HDRSIZE
, &len
);
344 * Add the first two fixed entries. The size of holesdata
345 * includes '\0' at the end of data
347 (void) sprintf(hstr
, "%10lu %20llu ",
348 (ulong_t
)MIN_HOLES_HDRSIZE
+ len
+ 1, filesz
);
349 (void) memcpy(str
, hstr
, MIN_HOLES_HDRSIZE
);
351 /* calc real file size without holes */
352 hi
->data_size
= get_compressed_filesz(hl
);
354 hi
->holesdata_sz
= MIN_HOLES_HDRSIZE
+ len
+ 1;
360 * The holesdata information is in the following format:
361 * <data size(%10u)><SP><file size(%llu)><SP>
362 * <SP><data off><SP><hole off><SP><data off><SP><hole off> ...
363 * read_holes_header() allocates holes_info_t, and read the first 2
364 * entries (data size and file size). The rest of holesdata is
365 * read by parse_holesdata().
368 read_holes_header(const char *str
, off_t filesz
)
373 hi
= e_zalloc(E_EXIT
, sizeof (holes_info_t
));
375 /* read prepended holes data size */
376 if ((str
= get_ull_tok(str
, &ull
)) == NULL
|| *str
!= ' ') {
381 hi
->holesdata_sz
= (size_t)ull
;
383 /* read original(expanded) file size */
384 if (get_ull_tok(str
, &ull
) == NULL
)
386 hi
->orig_size
= (off_t
)ull
;
389 if (hi
->holesdata_sz
> filesz
||
390 hi
->holesdata_sz
<= MIN_HOLES_HDRSIZE
) {
397 parse_holesdata(holes_info_t
*hi
, const char *str
)
399 holes_list_t
*hl
, **hlp
;
403 /* create hole list */
404 hlp
= &hi
->holes_list
;
405 while (*str
!= '\0') {
406 hl
= e_zalloc(E_EXIT
, sizeof (holes_list_t
));
412 /* read the string token for data */
413 if ((str
= get_ull_tok(str
, &ull
)) == NULL
)
415 hl
->hl_data
= (off_t
)ull
;
417 /* there must be single blank space in between */
421 /* read the string token for hole */
422 if ((str
= get_ull_tok(str
, &ull
)) == NULL
)
424 hl
->hl_hole
= (off_t
)ull
;
427 /* check to see if offset is in ascending order */
429 for (hl
= hi
->holes_list
; hl
!= NULL
; hl
= hl
->hl_next
) {
430 if (loff
>= hl
->hl_data
)
433 /* data and hole can be equal */
434 if (loff
> hl
->hl_hole
)
438 /* The last hole offset should match original file size */
439 if (hi
->orig_size
!= loff
) {
445 hi
->data_size
= get_compressed_filesz(hi
->holes_list
);
451 free_holes_info(holes_info_t
*hi
)