all repos — acme @ main

fork of the acme editor from plan9port - keybinds, tweaks, config.h, etc

disk.c (raw)

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <u.h>
#include <libc.h>
#include <draw.h>
#include <thread.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
#include "libframe/frame.h"
#include <fcall.h>
#include <plumb.h>
#include <libsec.h>
#include "dat.h"
#include "fns.h"

static Block* blist;

int tempfile(void) {
  char buf[128];
  int i, fd;

  snprint(buf, sizeof buf, "/tmp/X%d.%.4sacme", getpid(), getuser());
  for (i = 'A'; i <= 'Z'; i++) {
    buf[5] = i;
    if (access(buf, AEXIST) == 0)
      continue;
    fd = create(buf, ORDWR | ORCLOSE | OCEXEC, 0600);
    if (fd >= 0)
      return fd;
  }
  return -1;
}

Disk* diskinit() {
  Disk* d;

  d = emalloc(sizeof(Disk));
  d->fd = tempfile();
  if (d->fd < 0) {
    fprint(2, "acme: can't create temp file: %r\n");
    threadexitsall("diskinit");
  }
  return d;
}

static uint ntosize(uint n, uint* ip) {
  uint size;

  if (n > Maxblock)
    error("internal error: ntosize");
  size = n;
  if (size & (Blockincr - 1))
    size += Blockincr - (size & (Blockincr - 1));
  /* last bucket holds blocks of exactly Maxblock */
  if (ip)
    *ip = size / Blockincr;
  return size * sizeof(Rune);
}

Block* disknewblock(Disk* d, uint n) {
  uint i, j, size;
  Block* b;

  size = ntosize(n, &i);
  b = d->free[i];
  if (b)
    d->free[i] = b->u.next;
  else {
    /* allocate in chunks to reduce malloc overhead */
    if (blist == nil) {
      blist = emalloc(100 * sizeof(Block));
      for (j = 0; j < 100 - 1; j++)
        blist[j].u.next = &blist[j + 1];
    }
    b = blist;
    blist = b->u.next;
    b->addr = d->addr;
    if (d->addr + size < d->addr) {
      error("temp file overflow");
    }
    d->addr += size;
  }
  b->u.n = n;
  return b;
}

void diskrelease(Disk* d, Block* b) {
  uint i;

  ntosize(b->u.n, &i);
  b->u.next = d->free[i];
  d->free[i] = b;
}

void diskwrite(Disk* d, Block** bp, Rune* r, uint n) {
  int size, nsize;
  Block* b;

  b = *bp;
  size = ntosize(b->u.n, nil);
  nsize = ntosize(n, nil);
  if (size != nsize) {
    diskrelease(d, b);
    b = disknewblock(d, n);
    *bp = b;
  }
  if (pwrite(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
    error("write error to temp file");
  b->u.n = n;
}

void diskread(Disk* d, Block* b, Rune* r, uint n) {
  if (n > b->u.n)
    error("internal error: diskread");

  ntosize(b->u.n, nil);
  if (pread(d->fd, r, n * sizeof(Rune), b->addr) != n * sizeof(Rune))
    error("read error from temp file");
}