summaryrefslogtreecommitdiff
path: root/src/user/knob/file.c
blob: 8d7a327cc7e315e34bdd815996c41000bab86395 (plain) (blame)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include <knob/format.h>
#include <knob/block.h>
#include <knob/panic.h>
#include <knob/heap.h>

#include <pland/syscall.h>
#include <pland/pcrt.h>

struct ofl_node {
  struct ofl_node *next;
  struct ofl_node *prev;
  _file_handle_t handle;
};

static struct ofl_node *head_ofl_node = 0;

static void _close_all_files() {
  for (struct ofl_node *i = head_ofl_node; i; i = i->next)
    _close_file(i->handle);
}

BEFORE_QUIT(_close_all_files)

struct file {
  struct ofl_node *node;
  _file_handle_t handle;
  uint32_t position;
  uint32_t length;
};

struct file *open_file(const char *path) {
  _file_handle_t h = _open_file(0, path);
  if (!h)
    return 0;

  struct ofl_node *new_node = get_block(sizeof(struct ofl_node));
  new_node->next = head_ofl_node;
  new_node->prev = 0;
  new_node->handle = h;
  if (head_ofl_node)
    head_ofl_node->prev = new_node;
  head_ofl_node = new_node;

  struct file *f = get_block(sizeof(struct file));
  f->node = new_node;
  f->handle = h;
  f->position = 0;
  f->length = _file_size(h);

  return f;
}

void close_file(struct file *f) {
  _close_file(f->handle);
  struct ofl_node *n = f->node;
  if (n->next)
    n->next->prev = n->prev;
  if (n->prev)
    n->prev->next = n->next;
  if (n == head_ofl_node)
    head_ofl_node = n->next;
  free_block(n);
  free_block(f);
}

uint32_t read_from_file(struct file *f, uint32_t max, void *buf) {
  if (f->position + max > f->length)
    max = f->length - f->position;

  uint32_t read = _file_read(f->handle, f->position, max, buf);

  f->position += read;
  return read;
}

uint32_t write_to_file(struct file *f, uint32_t max, void *buf) {
  if (f->position + max > f->length)
    _set_file_size(f->handle, f->length = f->position + max);

  uint32_t written = _file_write(f->handle, f->position, max, buf);

  f->position += written;
  return written;
}

//return value and max_length don't include null terminator
uint32_t read_line_from_file(struct file *f, char *sz, uint32_t max_length) {
  uint8_t i;
  for (i = 0; i < max_length; ++i) {
    char byte;
    if (!read_from_file(f, 1, &byte) || (byte == '\n'))
      break;
    sz[i] = byte;
  }
  sz[i] = '\0';
  return i;
}

uint32_t seek_file_to(struct file *f, uint32_t to) {
  if (to > f->length)
    to = f->length;
  return f->position = to;
}

int32_t seek_file_by(struct file *f, int32_t by) {
  uint32_t old = f->position;
  uint32_t to = old + by > f->length ? f->length : old + by;
  f->position = to;
  return to - old;
}

__attribute__ ((pure))
uint32_t file_size(struct file *f) {
  return f->length;
}

void trunc_file(struct file *f) {
  _set_file_size(f->handle, f->length = f->position);
}

//return value must be manually freed, unless it is a null pointer
_dir_info_entry_t *get_directory_info(const char *path, uint32_t *count_out) {
  uint32_t count = _count_of_dir(0, path);
  if (!count) {
    *count_out = 0;
    return 0;
  }

  _dir_info_entry_t *buffer = get_block(count * sizeof(_dir_info_entry_t));
  *count_out = _enumerate_dir(0, path, buffer, count);
  return buffer;
}