aboutsummaryrefslogtreecommitdiff
path: root/toys/other/truncate.c
blob: bfe1f10cf13047ebd26818f9a3f4df8001567443 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* truncate.c - set file length, extending sparsely if necessary
 *
 * Copyright 2011 Rob Landley <rob@landley.net>

USE_TRUNCATE(NEWTOY(truncate, "<1s:|c", TOYFLAG_BIN))

config TRUNCATE
  bool "truncate"
  default y
  help
    usage: truncate [-c] -s SIZE file...

    Set length of file(s), extending sparsely if necessary.

    -c	Don't create file if it doesn't exist.
    -s	New size (with optional prefix and suffix)

    SIZE prefix: + add, - subtract, < shrink to, > expand to,
                 / multiple rounding down, % multiple rounding up
    SIZE suffix: k=1024, m=1024^2, g=1024^3, t=1024^4, p=1024^5, e=1024^6
*/

#define FOR_truncate
#include "toys.h"

GLOBALS(
  char *s;

  long size;
  int type;
)

static void do_truncate(int fd, char *name)
{
  long long size;

  if (fd<0) return;

  if (TT.type == -1) size = TT.size;
  else {
    size = fdlength(fd);
    if (TT.type<2) size += TT.size*(1-(2*TT.type));
    else if (TT.type<4) {
      if ((TT.type==2) ? (size <= TT.size) : (size >= TT.size)) return;
      size = TT.size;
    } else {
      size = (size+(TT.type-4)*(TT.size-1))/TT.size;
      size *= TT.size;
    }
  }
  if (ftruncate(fd, size)) perror_msg("'%s' to '%lld'", name, size);
}

void truncate_main(void)
{
  int cr = !(toys.optflags&1);

  if (-1 != (TT.type = stridx("+-<>/%", *TT.s))) TT.s++;
  TT.size = atolx(TT.s);

  // Create files with mask rwrwrw.
  // Nonexistent files are only an error if we're supposed to create them.
  loopfiles_rw(toys.optargs, O_WRONLY|O_CLOEXEC|(cr ? O_CREAT : 0), 0666, cr,
    do_truncate);
}