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 #define _LARGEFILE_SOURCE
     25 #define _LARGEFILE64_SOURCE
     26 
     27 #include <sys/stat.h>
     28 #include <sys/syscall.h>
     29 #include <sys/types.h>
     30 #include <fcntl.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <unistd.h>
     34 #include <ctype.h>
     35 
     36 // #include <linux/falloc.h>
     37 #define FALLOC_FL_KEEP_SIZE	0x01
     38 #define FALLOC_FL_PUNCH_HOLE	0x02 /* de-allocates range */
     39 
     40 void usage(void)
     41 {
     42 	printf("Usage: fallocate [-npt] [-o offset] -l length filename\n");
     43 	exit(EXIT_FAILURE);
     44 }
     45 
     46 #define EXABYTES(x)     ((long long)(x) << 60)
     47 #define PETABYTES(x)    ((long long)(x) << 50)
     48 #define TERABYTES(x)    ((long long)(x) << 40)
     49 #define GIGABYTES(x)    ((long long)(x) << 30)
     50 #define MEGABYTES(x)    ((long long)(x) << 20)
     51 #define KILOBYTES(x)    ((long long)(x) << 10)
     52 
     53 long long
     54 cvtnum(char *s)
     55 {
     56 	long long	i;
     57 	char		*sp;
     58 	int		c;
     59 
     60 	i = strtoll(s, &sp, 0);
     61 	if (i == 0 && sp == s)
     62 		return -1LL;
     63 	if (*sp == '\0')
     64 		return i;
     65 	if (sp[1] != '\0')
     66 		return -1LL;
     67 
     68 	c = tolower(*sp);
     69 	switch (c) {
     70 	case 'k':
     71 		return KILOBYTES(i);
     72 	case 'm':
     73 		return MEGABYTES(i);
     74 	case 'g':
     75 		return GIGABYTES(i);
     76 	case 't':
     77 		return TERABYTES(i);
     78 	case 'p':
     79 		return PETABYTES(i);
     80 	case 'e':
     81 		return  EXABYTES(i);
     82 	}
     83 
     84 	return -1LL;
     85 }
     86 
     87 int main(int argc, char **argv)
     88 {
     89 	int	fd;
     90 	char	*fname;
     91 	int	opt;
     92 	loff_t	length = -2LL;
     93 	loff_t	offset = 0;
     94 	int	falloc_mode = 0;
     95 	int	error;
     96 	int	tflag = 0;
     97 
     98 	while ((opt = getopt(argc, argv, "npl:o:t")) != -1) {
     99 		switch(opt) {
    100 		case 'n':
    101 			/* do not change filesize */
    102 			falloc_mode = FALLOC_FL_KEEP_SIZE;
    103 			break;
    104 		case 'p':
    105 			/* punch mode */
    106 			falloc_mode = (FALLOC_FL_PUNCH_HOLE |
    107 				       FALLOC_FL_KEEP_SIZE);
    108 			break;
    109 		case 'l':
    110 			length = cvtnum(optarg);
    111 			break;
    112 		case 'o':
    113 			offset = cvtnum(optarg);
    114 			break;
    115 		case 't':
    116 			tflag++;
    117 			break;
    118 		default:
    119 			usage();
    120 		}
    121 	}
    122 
    123 	if (length == -2LL) {
    124 		printf("Error: no length argument specified\n");
    125 		usage();
    126 	}
    127 
    128 	if (length <= 0) {
    129 		printf("Error: invalid length value specified\n");
    130 		usage();
    131 	}
    132 
    133 	if (offset < 0) {
    134 		printf("Error: invalid offset value specified\n");
    135 		usage();
    136 	}
    137 
    138 	if (tflag && (falloc_mode & FALLOC_FL_KEEP_SIZE)) {
    139 		printf("-n and -t options incompatible\n");
    140 		usage();
    141 	}
    142 
    143 	if (tflag && offset) {
    144 		printf("-n and -o options incompatible\n");
    145 		usage();
    146 	}
    147 
    148 	if (optind == argc) {
    149 		printf("Error: no filename specified\n");
    150 		usage();
    151 	}
    152 
    153 	fname = argv[optind++];
    154 
    155 	/* Should we create the file if it doesn't already exist? */
    156 	fd = open(fname, O_WRONLY|O_LARGEFILE);
    157 	if (fd < 0) {
    158 		perror("Error opening file");
    159 		exit(EXIT_FAILURE);
    160 	}
    161 
    162 	if (tflag)
    163 		error = ftruncate(fd, length);
    164 	else
    165 		error = syscall(SYS_fallocate, fd, falloc_mode, offset, length);
    166 
    167 	if (error < 0) {
    168 		perror("fallocate failed");
    169 		exit(EXIT_FAILURE);
    170 	}
    171 
    172 	close(fd);
    173 	return 0;
    174 }
    175