Home | History | Annotate | Download | only in contrib
      1 /*
      2  * fallocate - utility to use the fallocate system call
      3  *
      4  * Copyright (C) 2008 Red Hat, Inc. All rights reserved.
      5  * Written by Eric Sandeen <sandeen (at) redhat.com>
      6  *
      7  * cvtnum routine taken from xfsprogs,
      8  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
      9  *
     10  * This program is free software; you can redistribute it and/or
     11  * modify it under the terms of the GNU General Public License as
     12  * published by the Free Software Foundation.
     13  *
     14  * This program is distributed in the hope that it would be useful,
     15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  * GNU General Public License for more details.
     18  *
     19  * You should have received a copy of the GNU General Public License
     20  * along with this program; if not, write to the Free Software Foundation,
     21  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     22  */
     23 
     24 #ifndef _LARGEFILE_SOURCE
     25 #define _LARGEFILE_SOURCE
     26 #endif
     27 #ifndef _LARGEFILE64_SOURCE
     28 #define _LARGEFILE64_SOURCE
     29 #endif
     30 
     31 #include <sys/stat.h>
     32 #include <sys/syscall.h>
     33 #include <sys/types.h>
     34 #include <fcntl.h>
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <unistd.h>
     38 #include <ctype.h>
     39 
     40 // #include <linux/falloc.h>
     41 #define FALLOC_FL_KEEP_SIZE	0x01
     42 #define FALLOC_FL_PUNCH_HOLE	0x02 /* de-allocates range */
     43 #define FALLOC_FL_COLLAPSE_RANGE	0x08
     44 #define FALLOC_FL_ZERO_RANGE		0x10
     45 
     46 void usage(void)
     47 {
     48 	printf("Usage: fallocate [-npt] [-o offset] -l length filename\n");
     49 	exit(EXIT_FAILURE);
     50 }
     51 
     52 #define EXABYTES(x)     ((long long)(x) << 60)
     53 #define PETABYTES(x)    ((long long)(x) << 50)
     54 #define TERABYTES(x)    ((long long)(x) << 40)
     55 #define GIGABYTES(x)    ((long long)(x) << 30)
     56 #define MEGABYTES(x)    ((long long)(x) << 20)
     57 #define KILOBYTES(x)    ((long long)(x) << 10)
     58 
     59 long long
     60 cvtnum(char *s)
     61 {
     62 	long long	i;
     63 	char		*sp;
     64 	int		c;
     65 
     66 	i = strtoll(s, &sp, 0);
     67 	if (i == 0 && sp == s)
     68 		return -1LL;
     69 	if (*sp == '\0')
     70 		return i;
     71 	if (sp[1] != '\0')
     72 		return -1LL;
     73 
     74 	c = tolower(*sp);
     75 	switch (c) {
     76 	case 'k':
     77 		return KILOBYTES(i);
     78 	case 'm':
     79 		return MEGABYTES(i);
     80 	case 'g':
     81 		return GIGABYTES(i);
     82 	case 't':
     83 		return TERABYTES(i);
     84 	case 'p':
     85 		return PETABYTES(i);
     86 	case 'e':
     87 		return  EXABYTES(i);
     88 	}
     89 
     90 	return -1LL;
     91 }
     92 
     93 int main(int argc, char **argv)
     94 {
     95 	int	fd;
     96 	char	*fname;
     97 	int	opt;
     98 	loff_t	length = -2LL;
     99 	loff_t	offset = 0;
    100 	int	falloc_mode = 0;
    101 	int	error;
    102 	int	tflag = 0;
    103 
    104 	while ((opt = getopt(argc, argv, "npl:o:tzc")) != -1) {
    105 		switch(opt) {
    106 		case 'n':
    107 			/* do not change filesize */
    108 			falloc_mode = FALLOC_FL_KEEP_SIZE;
    109 			break;
    110 		case 'p':
    111 			/* punch mode */
    112 			falloc_mode = (FALLOC_FL_PUNCH_HOLE |
    113 				       FALLOC_FL_KEEP_SIZE);
    114 			break;
    115 		case 'c':
    116 			/* collapse range mode */
    117 			falloc_mode = (FALLOC_FL_COLLAPSE_RANGE |
    118 				       FALLOC_FL_KEEP_SIZE);
    119 			break;
    120 		case 'z':
    121 			/* zero range mode */
    122 			falloc_mode = (FALLOC_FL_ZERO_RANGE |
    123 				       FALLOC_FL_KEEP_SIZE);
    124 			break;
    125 		case 'l':
    126 			length = cvtnum(optarg);
    127 			break;
    128 		case 'o':
    129 			offset = cvtnum(optarg);
    130 			break;
    131 		case 't':
    132 			tflag++;
    133 			break;
    134 		default:
    135 			usage();
    136 		}
    137 	}
    138 
    139 	if (length == -2LL) {
    140 		printf("Error: no length argument specified\n");
    141 		usage();
    142 	}
    143 
    144 	if (length <= 0) {
    145 		printf("Error: invalid length value specified\n");
    146 		usage();
    147 	}
    148 
    149 	if (offset < 0) {
    150 		printf("Error: invalid offset value specified\n");
    151 		usage();
    152 	}
    153 
    154 	if (tflag && (falloc_mode & FALLOC_FL_KEEP_SIZE)) {
    155 		printf("-n and -t options incompatible\n");
    156 		usage();
    157 	}
    158 
    159 	if (tflag && offset) {
    160 		printf("-n and -o options incompatible\n");
    161 		usage();
    162 	}
    163 
    164 	if (optind == argc) {
    165 		printf("Error: no filename specified\n");
    166 		usage();
    167 	}
    168 
    169 	fname = argv[optind++];
    170 
    171 	/* Should we create the file if it doesn't already exist? */
    172 	fd = open(fname, O_WRONLY|O_LARGEFILE);
    173 	if (fd < 0) {
    174 		perror("Error opening file");
    175 		exit(EXIT_FAILURE);
    176 	}
    177 
    178 	if (tflag)
    179 		error = ftruncate(fd, length);
    180 	else
    181 		error = syscall(SYS_fallocate, fd, falloc_mode, offset, length);
    182 
    183 	if (error < 0) {
    184 		perror("fallocate failed");
    185 		exit(EXIT_FAILURE);
    186 	}
    187 
    188 	close(fd);
    189 	return 0;
    190 }
    191