yaffsfs.c: Fix NULL dereference in yaffs_unmount2_reldev()
[yaffs2.git] / direct / test-framework / yaffs_flexible_file_sim.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2018 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 /*
14  * NAND Simulator for testing YAFFS
15  */
16
17
18 #include "yaffs_flexible_file_sim.h"
19
20 #include "yaffs_guts.h"
21 #include <string.h>
22
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <fcntl.h>
26
27
28 struct sim_data {
29         char *file_name;
30         int handle;
31         uint32_t n_blocks;
32         uint32_t chunks_per_block;
33         uint32_t chunk_size;
34         uint32_t spare_size;
35         uint32_t total_chunk_size;
36         uint32_t total_bytes_per_block;
37         char *buffer;
38 };
39
40 static struct sim_data *dev_to_sim(struct yaffs_dev *dev)
41 {
42         return (struct sim_data *)(dev->driver_context);
43 }
44
45
46 static int yflex_erase_internal(struct sim_data *sim, uint32_t block_id)
47 {
48         int pos;
49
50         pos = sim->total_bytes_per_block * block_id;
51         memset(sim->buffer, 0xff, sim->total_bytes_per_block);
52
53         lseek(sim->handle, pos, SEEK_SET);
54         write(sim->handle, sim->buffer, sim->total_bytes_per_block);
55
56         return YAFFS_OK;
57 }
58
59 #if 0
60 static int yflex_read_internal(struct sim_data *sim,
61                                  uint32_t page_id,
62                                  uint8_t *buffer)
63 {
64         int page_pos = page_id * sim->total_chunk_size;
65
66         lseek(sim->handle, page_pos, SEEK_SET);
67         read(sim->handle, buffer, sim->total_chunk_size);
68
69         return YAFFS_OK;
70 }
71
72 #endif
73
74
75 static int yflex_initialise(struct yaffs_dev *dev)
76 {
77         (void) dev;
78
79         return YAFFS_OK;
80 }
81
82
83 static int yflex_deinitialise(struct yaffs_dev *dev)
84 {
85         (void) dev;
86         return YAFFS_OK;
87 }
88
89 static int yflex_rd_chunk (struct yaffs_dev *dev, int page_id,
90                                           u8 *data, int data_length,
91                                           u8 *spare, int spare_length,
92                                           enum yaffs_ecc_result *ecc_result)
93 {
94         struct sim_data *sim = dev_to_sim(dev);
95         uint32_t page_start;
96
97         page_start = page_id * sim->total_chunk_size;
98
99         if(data) {
100                 lseek(sim->handle, page_start, SEEK_SET);
101                 read(sim->handle, data,data_length);
102         }
103
104         if(spare) {
105                 lseek(sim->handle, page_start + sim->chunk_size, SEEK_SET);
106                 read(sim->handle, spare,spare_length);
107         }
108
109         if (ecc_result)
110                 *ecc_result = YAFFS_ECC_RESULT_NO_ERROR;
111
112         return YAFFS_OK;
113 }
114
115 static int yflex_wr_chunk (struct yaffs_dev *dev, int page_id,
116                              const u8 *data, int data_length,
117                              const u8 *spare, int spare_length)
118 {
119         struct sim_data *sim = dev_to_sim(dev);
120         uint32_t page_start;
121
122         page_start = page_id * sim->total_chunk_size;
123
124         if(data) {
125                 lseek(sim->handle, page_start, SEEK_SET);
126                 write(sim->handle, data,data_length);
127         }
128
129         if(spare) {
130                 lseek(sim->handle, page_start + sim->chunk_size, SEEK_SET);
131                 write(sim->handle, spare, spare_length);
132         }
133
134         return YAFFS_OK;
135 }
136
137
138 static int yflex_erase(struct yaffs_dev *dev, int block_id)
139 {
140         struct sim_data *sim = dev_to_sim(dev);
141
142         return yflex_erase_internal(sim, block_id);
143 }
144
145 static int yflex_check_block_bad(struct yaffs_dev *dev, int block_id)
146 {
147         (void) dev;
148         (void) block_id;
149
150         return YAFFS_OK;
151 }
152
153 static int yflex_mark_block_bad(struct yaffs_dev *dev, int block_id)
154 {
155         (void) dev;
156         (void) block_id;
157
158         return YAFFS_OK;
159 }
160
161 static int yflex_sim_init(struct sim_data *sim)
162 {
163         int h;
164         uint32_t fsize = 0;
165         uint32_t i;
166
167         sim->total_chunk_size = sim->chunk_size + sim->spare_size;
168         sim->total_bytes_per_block = sim->total_chunk_size * sim->chunks_per_block;
169
170         sim->buffer = malloc(sim->total_bytes_per_block);
171
172         h = open(sim->file_name, O_RDWR);
173         if (h >= 0) {
174                 fsize = lseek(h, 0, SEEK_END);
175                 lseek(h, 0, SEEK_SET);
176         }
177
178         if (fsize != sim->total_bytes_per_block * sim->n_blocks) {
179                 /* Need to create the file. */
180                 close(h);
181                 unlink(sim->file_name);
182                 h = open(sim->file_name, O_RDWR | O_CREAT | O_TRUNC, 0666);
183                 sim->handle = h;
184
185                 for (i = 0; i < sim->n_blocks; i++)
186                         yflex_erase_internal(sim, i);
187         } else {
188                 sim->handle = h;
189         }
190
191         return YAFFS_OK;
192 }
193
194
195 struct yaffs_dev *yaffs_flexible_file_sim_create(
196                                 const char *name,
197                                 const char *sim_file_name,
198                                 uint32_t n_blocks,
199                                 uint32_t start_block, uint32_t end_block,
200                                 uint32_t chunks_per_block,
201                                 uint32_t bytes_per_chunk,
202                                 uint32_t bytes_per_spare)
203 {
204         struct sim_data *sim;
205         struct yaffs_dev *dev;
206         struct yaffs_param *p;
207         struct yaffs_driver *d;
208
209         sim = malloc(sizeof(*sim));
210         dev = malloc(sizeof(*dev));
211
212         if(!sim || !dev){
213                 free(sim);
214                 free(dev);
215                 return NULL;
216         }
217         memset(sim, 0, sizeof(*sim));
218         memset(dev, 0, sizeof(*dev));
219
220         /* Set up sim */
221         sim->file_name = strdup(sim_file_name);
222         sim->chunks_per_block = chunks_per_block;
223         sim->chunk_size = bytes_per_chunk;
224         sim->spare_size = bytes_per_spare;
225         sim->n_blocks = n_blocks;
226
227         dev->driver_context= (void *)sim;
228
229         yflex_sim_init(sim);
230
231
232
233         if(start_block >= sim->n_blocks)
234                 start_block = 0;
235         if(end_block == 0 || end_block >= sim->n_blocks)
236                 end_block = sim->n_blocks - 1;
237
238         p = &dev->param;
239         p->name = strdup(name);
240         p->start_block = start_block;
241         p->end_block = end_block;
242         p->total_bytes_per_chunk = bytes_per_chunk;
243         p->spare_bytes_per_chunk = bytes_per_spare;
244         p->chunks_per_block = chunks_per_block;
245         p->n_reserved_blocks = 2;
246         p->use_nand_ecc = 1;
247         p->inband_tags = 0;
248         p->is_yaffs2 = 1;
249         p->n_caches = 10;
250
251         d= &dev->drv;
252         d->drv_initialise_fn = yflex_initialise;
253         d->drv_deinitialise_fn = yflex_deinitialise;
254         d->drv_read_chunk_fn = yflex_rd_chunk;
255         d->drv_write_chunk_fn = yflex_wr_chunk;
256         d->drv_erase_fn = yflex_erase;
257         d->drv_check_bad_fn = yflex_check_block_bad;
258         d->drv_mark_bad_fn = yflex_mark_block_bad;
259
260         yaffs_add_device(dev);
261
262         return dev;
263 }