[go: up one dir, main page]

File: io.c

package info (click to toggle)
dosfstools 1.0-15
  • links: PTS
  • area: main
  • in suites: hamm, slink
  • size: 200 kB
  • ctags: 245
  • sloc: ansic: 2,215; makefile: 108
file content (141 lines) | stat: -rw-r--r-- 3,234 bytes parent folder | download
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
133
134
135
136
137
138
139
140
141
/* io.c  -  Virtual disk input/output */

/* Written 1993 by Werner Almesberger */

/*
 * Thu Feb 26 01:15:36 CET 1998: Martin Schulze <joey@infodrom.north.de>
 *	Fixed nasty bug that caused every file with a name like
 *	xxxxxxxx.xxx to be treated as bad name that needed to be fixed.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

#include "dosfsck.h"
#include "common.h"
#include "io.h"


typedef struct _change {
    void *data;
    unsigned int pos;
    int size;
    struct _change *next;
} CHANGE;


static CHANGE *changes,*last;
static int fd,did_change = 0;


void fs_open(char *path,int rw)
{
    if ((fd = open(path,rw ? O_RDWR : O_RDONLY)) < 0)
	pdie("open %s",path);
    changes = last = NULL;
    did_change = 0;
}


void fs_read(unsigned int pos,int size,void *data)
{
    CHANGE *walk;
    int got;

    if (lseek(fd,pos,0) != pos) pdie("Seek to %d",pos);
    if ((got = read(fd,data,size)) < 0) pdie("Read %d bytes at %d",size,pos);
    if (got != size) die("Got %d bytes instead of %d at %d",got,size,pos);
    for (walk = changes; walk; walk = walk->next)
	if (walk->pos < pos+size && walk->pos+walk->size > pos)
	    if (walk->pos < pos)
		memcpy(data,(char *) walk->data+pos-walk->pos,min(size,
		  walk->size-pos+walk->pos));
	    else memcpy((char *) data+walk->pos-pos,walk->data,min(walk->size,
		  size+pos-walk->pos));
}


int fs_test(unsigned int pos,int size)
{
    void *scratch;
    int okay;

    if (lseek(fd,pos,0) != pos) pdie("Seek to %d",pos);
    scratch = alloc(size);
    okay = read(fd,scratch,size) == size;
    free(scratch);
    return okay;
}


void fs_write(unsigned int pos,int size,void *data)
{
    CHANGE *new;
    int did;

    if (write_immed) {
	did_change = 1;
	if (lseek(fd,pos,0) != pos) pdie("Seek to %d",pos);
	if ((did = write(fd,data,size)) == size) return;
	if (did < 0) pdie("Write %d bytes at %d",size,pos);
	die("Wrote %d bytes instead of %d at %d",did,size,pos);
    }
    new = alloc(sizeof(CHANGE));
    new->pos = pos;
    memcpy(new->data = alloc(new->size = size),data,size);
    new->next = NULL;
    if (last) last->next = new;
    else changes = new;
    last = new;
}


static void fs_flush(void)
{
    CHANGE *this;
    int size;

    while (changes) {
	this = changes;
	changes = changes->next;
	if (lseek(fd,this->pos,0) != this->pos)
	    fprintf(stderr,"Seek to %d failed: %s\n  Did not write %d bytes.\n",
	      this->pos,strerror(errno),this->size);
	else if ((size = write(fd,this->data,this->size)) < 0)
		fprintf(stderr,"Writing %d bytes at %d failed: %s\n",this->size,
		  this->pos,strerror(errno));
	    else if (size != this->size)
		    fprintf(stderr,"Wrote %d bytes instead of %d bytes at %d."
		      "\n",size,this->size,this->pos);
	free(this->data);
	free(this);
    }
}


int fs_close(int write)
{
    CHANGE *next;
    int changed;

    changed = !!changes;
    if (write) fs_flush();
    else while (changes) {
	    next = changes->next;
	    free(changes->data);
	    free(changes);
	    changes = next;
	}
    if (close(fd) < 0) pdie("closing file system");
    return changed || did_change;
}


int fs_changed(void)
{
    return !!changes || did_change;
}