cp: define a FIXME macro that leaves a sclp message
[hvf.git] / cp / fs / edf.c
blobd327640d4fb23fd6e9e38ba8ae1661f5951ca892
1 /*
2 * (C) Copyright 2007-2011 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
4 * This file is released under the GPLv2. See the COPYING file for more
5 * details.
6 */
8 #include <mutex.h>
9 #include <buddy.h>
10 #include <slab.h>
11 #include <device.h>
12 #include <bdev.h>
13 #include <ebcdic.h>
14 #include <edf.h>
15 #include <bcache.h>
17 static LOCK_CLASS(edf_fs);
18 static LOCK_CLASS(edf_dir);
19 static LOCK_CLASS(edf_file);
21 /* assumes that fs->lock is held */
22 static struct file *__alloc_file(struct fs *fs, struct FST *fst)
24 struct file *file;
26 file = malloc(sizeof(struct file), ZONE_NORMAL);
27 if (!file)
28 return ERR_PTR(-ENOMEM);
30 memset(file, 0, sizeof(struct file));
32 if (fst)
33 memcpy(&file->FST, fst, sizeof(struct FST));
35 INIT_LIST_HEAD(&file->files);
36 INIT_LIST_HEAD(&file->bcache);
37 mutex_init(&file->lock, &edf_file);
39 file->fs = fs;
41 list_add_tail(&file->files, &fs->files);
43 return file;
46 /* assumes that fs->lock is held */
47 static void __free_file(struct file *file)
49 list_del(&file->files);
50 free(file);
53 static int __init_dir(struct fs *fs, void *tmp)
55 struct FST *fst = tmp;
56 struct file *file;
57 int ret;
59 ret = bdev_read_block(fs->dev, tmp, fs->ADT.DOP);
60 if (ret)
61 return ret;
63 if (memcmp(fst[0].FNAME, DIRECTOR_FN, 8) ||
64 memcmp(fst[0].FTYPE, DIRECTOR_FT, 8) ||
65 (fst[0].RECFM != FSTDFIX) ||
66 memcmp(fst[1].FNAME, ALLOCMAP_FN, 8) ||
67 memcmp(fst[1].FTYPE, ALLOCMAP_FT, 8) ||
68 (fst[1].RECFM != FSTDFIX))
69 return -ECORRUPT;
71 file = __alloc_file(fs, &fst[0]);
72 if (IS_ERR(file))
73 return PTR_ERR(file);
75 /* need to override the default lock class */
76 mutex_init(&file->lock, &edf_dir);
78 ret = bcache_add(file, 0, 0, fs->ADT.DOP);
79 if (ret) {
80 __free_file(file);
81 return ret;
84 fs->dir = file;
86 return 0;
89 struct fs *edf_mount(struct device *dev)
91 struct page *page;
92 void *tmp;
93 struct fs *fs;
94 long ret;
96 page = alloc_pages(0, ZONE_NORMAL);
97 if (!page)
98 return ERR_PTR(-ENOMEM);
99 tmp = page_to_addr(page);
101 ret = -ENOMEM;
102 fs = malloc(sizeof(struct fs), ZONE_NORMAL);
103 if (!fs)
104 goto out_free;
106 /* First, read & verify the label */
107 ret = bdev_read_block(dev, tmp, EDF_LABEL_BLOCK_NO);
108 if (ret)
109 goto out_free;
111 mutex_init(&fs->lock, &edf_fs);
112 INIT_LIST_HEAD(&fs->files);
113 fs->dev = dev;
115 memcpy(&fs->ADT, tmp, sizeof(struct ADT));
117 ret = -EINVAL;
118 if ((fs->ADT.IDENT != __ADTIDENT) ||
119 (fs->ADT.DBSIZ != EDF_SUPPORTED_BLOCK_SIZE) ||
120 (fs->ADT.OFFST != 0) ||
121 (fs->ADT.FSTSZ != sizeof(struct FST)))
122 goto out_free;
124 ret = __init_dir(fs, tmp);
125 if (ret)
126 goto out_free;
128 FIXME("init the ALLOCMAP");
130 free_pages(tmp, 0);
131 return fs;
133 out_free:
134 free(fs);
135 free_pages(tmp, 0);
136 return ERR_PTR(ret);
139 struct file *edf_lookup(struct fs *fs, char *fn, char *ft)
141 char __fn[8];
142 char __ft[8];
143 struct file *file;
144 struct FST *fst;
145 u32 blk;
146 int ret;
147 int i;
149 memcpy(__fn, fn, 8);
150 memcpy(__ft, ft, 8);
151 ascii2ebcdic((u8 *) __fn, 8);
152 ascii2ebcdic((u8 *) __ft, 8);
154 mutex_lock(&fs->lock);
156 /* first, check the cache */
157 list_for_each_entry(file, &fs->files, files) {
158 if (!memcmp((char*) file->FST.FNAME, __fn, 8) &&
159 !memcmp((char*) file->FST.FTYPE, __ft, 8)) {
160 mutex_unlock(&fs->lock);
161 return file;
165 /* the slow path */
166 file = __alloc_file(fs, NULL);
167 if (IS_ERR(file)) {
168 ret = PTR_ERR(file);
169 goto out;
172 for(blk=0; blk<fs->dir->FST.ADBC; blk++) {
173 fst = bcache_read(fs->dir, 0, blk);
174 if (IS_ERR(fst)) {
175 ret = PTR_ERR(fst);
176 goto out_free;
179 for(i=0; i<fs->ADT.NFST; i++) {
180 if ((!memcmp(fst[i].FNAME, __fn, 8)) &&
181 (!memcmp(fst[i].FTYPE, __ft, 8))) {
182 memcpy(&file->FST, &fst[i], sizeof(struct FST));
183 mutex_unlock(&fs->lock);
184 return file;
189 ret = -ENOENT;
191 out_free:
192 __free_file(file);
194 out:
195 mutex_unlock(&fs->lock);
196 return ERR_PTR(ret);
199 int edf_read_rec(struct file *file, char *buf, u32 recno)
201 struct fs *fs = file->fs;
202 u32 blk, off;
203 char *dbuf;
204 int ret = -EINVAL;
206 mutex_lock(&file->lock);
208 /* check for unsupported geometry */
209 if (file->FST.NLVL != 0 ||
210 file->FST.PTRSZ != 4 ||
211 file->FST.LRECL > fs->ADT.DBSIZ ||
212 file->FST.RECFM != FSTDFIX)
213 goto out;
215 /* reading past the end of file? */
216 if (recno >= file->FST.AIC)
217 goto out;
219 blk = (recno * file->FST.LRECL) / fs->ADT.DBSIZ;
220 off = (recno * file->FST.LRECL) % fs->ADT.DBSIZ;
222 if ((off + file->FST.LRECL) > fs->ADT.DBSIZ) {
223 int flen = fs->ADT.DBSIZ - off;
224 int slen = file->FST.LRECL - flen;
226 assert(flen < file->FST.LRECL);
227 assert(slen < file->FST.LRECL);
229 /* the first part of the record */
230 dbuf = bcache_read(file, 0, blk);
231 if (IS_ERR(dbuf)) {
232 ret = PTR_ERR(dbuf);
233 goto out;
236 memcpy(buf, dbuf + off, flen);
238 /* the second part of the record */
239 blk++;
241 dbuf = bcache_read(file, 0, blk);
242 if (IS_ERR(dbuf)) {
243 ret = PTR_ERR(dbuf);
244 goto out;
247 memcpy(buf + flen, dbuf, slen);
248 } else {
249 /* the whole record */
250 dbuf = bcache_read(file, 0, blk);
251 if (IS_ERR(dbuf)) {
252 ret = PTR_ERR(dbuf);
253 goto out;
256 memcpy(buf, dbuf + off, file->FST.LRECL);
259 ret = 0;
261 out:
262 mutex_unlock(&file->lock);
264 return ret;
267 void edf_file_free(struct file *file)
269 struct fs *fs = file->fs;
271 mutex_lock(&fs->lock);
272 __free_file(file);
273 mutex_unlock(&fs->lock);