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
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
)
26 file
= malloc(sizeof(struct file
), ZONE_NORMAL
);
28 return ERR_PTR(-ENOMEM
);
30 memset(file
, 0, sizeof(struct file
));
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
);
41 list_add_tail(&file
->files
, &fs
->files
);
46 /* assumes that fs->lock is held */
47 static void __free_file(struct file
*file
)
49 list_del(&file
->files
);
53 static int __init_dir(struct fs
*fs
, void *tmp
)
55 struct FST
*fst
= tmp
;
59 ret
= bdev_read_block(fs
->dev
, tmp
, fs
->ADT
.DOP
);
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
))
71 file
= __alloc_file(fs
, &fst
[0]);
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
);
89 struct fs
*edf_mount(struct device
*dev
)
96 page
= alloc_pages(0, ZONE_NORMAL
);
98 return ERR_PTR(-ENOMEM
);
99 tmp
= page_to_addr(page
);
102 fs
= malloc(sizeof(struct fs
), ZONE_NORMAL
);
106 /* First, read & verify the label */
107 ret
= bdev_read_block(dev
, tmp
, EDF_LABEL_BLOCK_NO
);
111 mutex_init(&fs
->lock
, &edf_fs
);
112 INIT_LIST_HEAD(&fs
->files
);
115 memcpy(&fs
->ADT
, tmp
, sizeof(struct ADT
));
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
)))
124 ret
= __init_dir(fs
, tmp
);
128 FIXME("init the ALLOCMAP");
139 struct file
*edf_lookup(struct fs
*fs
, char *fn
, char *ft
)
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
);
166 file
= __alloc_file(fs
, NULL
);
172 for(blk
=0; blk
<fs
->dir
->FST
.ADBC
; blk
++) {
173 fst
= bcache_read(fs
->dir
, 0, blk
);
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
);
195 mutex_unlock(&fs
->lock
);
199 int edf_read_rec(struct file
*file
, char *buf
, u32 recno
)
201 struct fs
*fs
= file
->fs
;
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
)
215 /* reading past the end of file? */
216 if (recno
>= file
->FST
.AIC
)
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
);
236 memcpy(buf
, dbuf
+ off
, flen
);
238 /* the second part of the record */
241 dbuf
= bcache_read(file
, 0, blk
);
247 memcpy(buf
+ flen
, dbuf
, slen
);
249 /* the whole record */
250 dbuf
= bcache_read(file
, 0, blk
);
256 memcpy(buf
, dbuf
+ off
, file
->FST
.LRECL
);
262 mutex_unlock(&file
->lock
);
267 void edf_file_free(struct file
*file
)
269 struct fs
*fs
= file
->fs
;
271 mutex_lock(&fs
->lock
);
273 mutex_unlock(&fs
->lock
);