fsshuffle.c
2.72 KB
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
#include <PR/bcp.h>
#include "os.h"
#include "os_bbfs.h"
#include "os_bbcard.h"
#include "bbint.h"
#define SHUFFLE_SIZE 32
s32
osBbFShuffle(s32 sfd, s32 dfd, s32 release, void* buf, u32 len) {
BbFat16* fat;
s32 rv = BBFS_ERR_INVALID;
BbInode* si, * di;
int b, prev, n, i;
u16 blocks[SHUFFLE_SIZE];
#ifdef _DEBUG
if ((u32)buf&15) return rv;
#endif
if (sfd < 0 || sfd >= BB_INODE16_ENTRIES || dfd < 0 || dfd >= BB_INODE16_ENTRIES) return rv;
if ((rv = __osBbFsGetAccess()) < 0) return rv;
fat = __osBbFat;
si = fat->inode+sfd;
di = fat->inode+dfd;
rv = BBFS_ERR_INVALID;
if (!si->type || !di->type) goto error;
if (len == 0) goto error;
if (len & (BB_FL_BLOCK_SIZE-1)) goto error;
if (len > si->size) goto error;
n = len / BB_FL_BLOCK_SIZE;
if (len == 0) {
rv = 0;
goto error;
}
for(i = 0; i < n; i += SHUFFLE_SIZE) {
int l = (n-i < SHUFFLE_SIZE) ? n-i : SHUFFLE_SIZE, j = 0;
int stop;
/* start allocation at end of destination file */
for(prev = b = di->block; b != BB_FAT_LAST; b = BB_FAT16_NEXT(fat,b))
prev = b;
if (prev != BB_FAT_LAST)
b = prev+1;
else
b = BB_FL_BYTE_TO_BLOCK(BB_SYSTEM_AREA_SIZE);
stop = b;
while(j < l) {
while(BB_FAT16_NEXT(fat,b) != BB_FAT_AVAIL) {
b++;
if (b >= __osBbFsBlocks)
b = BB_FL_BYTE_TO_BLOCK(BB_SYSTEM_AREA_SIZE);
/*XXXblythe handle no more blocks case*/
if (b == stop) {
rv = BBFS_ERR_SPACE;
goto error;
}
}
blocks[j++] = b++;
}
/* write blocks to end of dfd */
if ((rv = osBbCardEraseBlocks(0, blocks, l)) < 0 ||
(rv = osBbCardWriteBlocks(0, blocks, l, buf, 0)) < 0) {
if (rv != BBFS_ERR_FAIL) goto error;
/* determine which blocks are bad, by repeating one at a time */
for(j = 0; j < l; j++) {
u16 b = blocks[j];
retry:
if ((rv = osBbCardEraseBlock(0, b)) < 0 ||
(rv = osBbCardWriteBlock(0, b, buf+i*BB_FL_BLOCK_SIZE, 0)) < 0) {
if (rv != BBFS_ERR_FAIL ||
(b = __osBbFReallocBlock(di, b, BB_FAT_BAD)) == BB_FAT_BAD) goto error;
goto retry;
}
blocks[j] = b;
}
}
/* append block list to end of dfd */
j = 0;
if (prev == BB_FAT_LAST) {
di->block = blocks[j];
prev = blocks[j++];
}
for(; j < l; j++) {
BB_FAT16_NEXT(fat, prev) = blocks[j];
prev = blocks[j];
}
BB_FAT16_NEXT(fat, prev) = BB_FAT_LAST;
if (release) {
/* release blocks from beginning of sfd */
b = si->block;
for(j = 0; j < l; j++) {
u16 o = BB_FAT16_NEXT(fat,b);
BB_FAT16_NEXT(fat,b) = BB_FAT_AVAIL;
b = o;
}
si->block = b;
si->size -= l*BB_FL_BLOCK_SIZE;
}
buf += BB_FL_BLOCK_SIZE*l;
di->size += BB_FL_BLOCK_SIZE*l;
}
rv = __osBbFsSync(0);
error:
__osBbFsRelAccess();
return rv;
}