1/* trunc.c: Set the size of an existing file, or create a file of a
2 *          specified size.
3 *
4 * Copyright (C) 2008 Micah J. Cowan
5 *
6 * Copying and distribution of this file, with or without modification,
7 * are permitted in any medium without royalty provided the copyright
8 * notice and this notice are preserved. */
9
10#include <errno.h>
11#include <fcntl.h>
12#include <sys/stat.h>
13#include <unistd.h>
14#include <stdlib.h>
15#include <stdio.h>
16
17#define PROGRAM_NAME  "trunc"
18
19void
20usage (FILE *f)
21{
22  fputs (
23PROGRAM_NAME " [-c] file sz\n\
24\n\
25Set the filesize of FILE to SIZE.\n\
26\n\
27  -c: create FILE if it doesn't exist.\n\
28\n\
29  Multiplier suffixes for SIZE (case-insensitive):\n\
30      k: SIZE * 1024\n\
31      m: SIZE * 1024 * 1024\n", f);
32}
33
34off_t
35get_size (const char str[])
36{
37  unsigned long val;
38  int suffix;
39  char *end;
40
41  errno = 0;
42  val = strtoul(str, &end, 10);
43  if (end == str)
44    {
45      fputs (PROGRAM_NAME ": size is not a number.\n", stderr);
46      usage (stderr);
47      exit (EXIT_FAILURE);
48    }
49  else if (errno == ERANGE
50           || (unsigned long)(off_t)val != val)
51    {
52      fputs (PROGRAM_NAME ": size is out of range.\n", stderr);
53      exit (EXIT_FAILURE);
54    }
55
56  suffix = tolower ((unsigned char) end[0]);
57  if (suffix == 'k')
58    {
59      val *= 1024;
60    }
61  else if (suffix == 'm')
62    {
63      val *= 1024 * 1024;
64    }
65
66  return val;
67}
68
69int
70main (int argc, char *argv[])
71{
72  const char *fname;
73  const char *szstr;
74  off_t      sz;
75  int        create = 0;
76  int        option;
77  int        fd;
78
79#ifdef ENABLE_NLS
80  /* Set the current locale.  */
81  setlocale (LC_ALL, "");
82  /* Set the text message domain.  */
83  bindtextdomain ("wget", LOCALEDIR);
84  textdomain ("wget");
85#endif /* ENABLE_NLS */
86
87  /* Parse options. */
88  while ((option = getopt (argc, argv, "c")) != -1)
89    {
90      switch (option) {
91        case 'c':
92          create = 1;
93          break;
94        case '?':
95          fprintf (stderr, PROGRAM_NAME ": Unrecognized option `%c'.\n\n",
96                   optopt);
97          usage (stderr);
98          exit (EXIT_FAILURE);
99        default:
100          /* We shouldn't reach here. */
101          abort();
102      }
103    }
104
105  if (argv[optind] == NULL
106      || argv[optind+1] == NULL
107      || argv[optind+2] != NULL)
108    {
109      usage (stderr);
110      exit (EXIT_FAILURE);
111    }
112
113  fname = argv[optind];
114  szstr = argv[optind+1];
115
116  sz = get_size(szstr);
117  if (create)
118    {
119      mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
120      fd = open(fname, O_WRONLY | O_CREAT, mode);
121    }
122  else
123    {
124      fd = open(fname, O_WRONLY);
125    }
126
127  if (fd == -1)
128    {
129      perror (PROGRAM_NAME ": open");
130      exit (EXIT_FAILURE);
131    }
132
133  if (ftruncate(fd, sz) == -1)
134    {
135      perror (PROGRAM_NAME ": truncate");
136      exit (EXIT_FAILURE);
137    }
138
139  if (close (fd) < 0)
140    {
141      perror (PROGRAM_NAME ": close");
142      exit (EXIT_FAILURE);
143    }
144
145  return 0;
146}
147