PageRenderTime 42ms CodeModel.GetById 20ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 1ms

/filesystems/unixfs/minixfs/unixfs_minixfs.c

http://macfuse.googlecode.com/
C | 356 lines | 277 code | 73 blank | 6 comment | 57 complexity | d5aa8212550e43fae27e841d061318e3 MD5 | raw file
  1/*
  2 * Minix File System Famiy for MacFUSE
  3 * Copyright (c) 2008 Amit Singh
  4 * http://osxbook.com
  5 */
  6
  7#include "minixfs.h"
  8#include "unixfs_common.h"
  9
 10#include <errno.h>
 11#include <fcntl.h>
 12#include <stdio.h>
 13#include <stdlib.h>
 14#include <string.h>
 15#include <unistd.h>
 16#include <sys/ioctl.h>
 17#include <sys/stat.h>
 18
 19DECL_UNIXFS("Minix", minix);
 20
 21static void*
 22unixfs_internal_init(const char* dmg, uint32_t flags, __unused fs_endian_t fse,
 23                     char** fsname, char** volname)
 24{
 25    int fd = -1;
 26
 27    if ((fd = open(dmg, O_RDONLY)) < 0) {
 28        perror("open");
 29        return NULL;
 30    }
 31
 32    int err;
 33    struct stat stbuf;
 34    struct super_block* sb = (struct super_block*)0;
 35
 36    if ((err = fstat(fd, &stbuf)) != 0) {
 37        perror("fstat");
 38        goto out;
 39    }
 40
 41    if (!S_ISREG(stbuf.st_mode) && !(flags & UNIXFS_FORCE)) {
 42        err = EINVAL;
 43        fprintf(stderr, "%s is not a disk image file\n", dmg);
 44        goto out;
 45    }
 46
 47    if ((err = unixfs_inodelayer_init(sizeof(struct minix_inode_info))) != 0)
 48        goto out;
 49
 50    sb = minixfs_fill_super(fd, (void*)0, 1 /* silent */);
 51    if (!sb) {
 52        err = EINVAL;
 53        goto out;
 54    }
 55
 56    struct minix_sb_info* sbi = minix_sb(sb);
 57
 58    unixfs = sb;
 59    unixfs->s_flags = flags;
 60
 61    (void)minixfs_statvfs(sb, &(unixfs->s_statvfs));
 62
 63    unixfs->s_dentsize = 0;
 64
 65    snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s %s",
 66             unixfs_fstype, (sbi->s_version == MINIX_V3) ? "V3" :
 67             (sbi->s_version == MINIX_V2) ? "V2" :
 68             (sbi->s_version == MINIX_V1) ? "V1" : "??");
 69    snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s (%s)",
 70             unixfs_fstype, (sbi->s_version == MINIX_V3) ? "V3" :
 71             (sbi->s_version == MINIX_V2) ? "V2" :
 72             (sbi->s_version == MINIX_V1) ? "V1" : "??");
 73
 74    *fsname = unixfs->s_fsname;
 75    *volname = unixfs->s_volname;
 76
 77out:
 78    if (err) {
 79        if (fd > 0)
 80            close(fd);
 81        if (sb) {
 82            free(sb);
 83            sb = NULL;
 84        }
 85    }
 86
 87    return sb;
 88}
 89
 90static void
 91unixfs_internal_fini(void* filsys)
 92{
 93    unixfs_inodelayer_fini();
 94
 95    struct super_block* sb = (struct super_block*)filsys;
 96    if (sb) {
 97        struct minix_sb_info* sbi = minix_sb(sb);
 98        if (sbi)
 99            free(sbi);
100        free(sb);
101    }
102}
103
104static off_t
105unixfs_internal_alloc(void)
106{
107    return (off_t)0;
108}
109
110static off_t
111unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
112{
113    off_t result;
114    *error = minixfs_get_block(ip, lblkno, &result);
115    return result;
116}
117
118static int
119unixfs_internal_bread(off_t blkno, char* blkbuf)
120{
121    struct super_block* sb = unixfs;
122
123    if (pread(sb->s_bdev, blkbuf, sb->s_blocksize,
124              blkno * (off_t)(sb->s_blocksize)) != sb->s_blocksize)
125        return EIO;
126
127    return 0;
128}
129
130struct inode*
131unixfs_internal_iget(ino_t ino)
132{
133   if (ino == MACFUSE_ROOTINO)
134        ino = MINIX_ROOT_INO;
135
136   struct super_block* sb = unixfs;
137
138    struct inode* inode = unixfs_inodelayer_iget(ino);
139    if (!inode) {
140        fprintf(stderr, "*** fatal error: no inode for %llu\n", ino);
141        abort();
142    }
143
144    if (inode->I_initialized)
145        return inode;
146
147    inode->I_sb = unixfs;
148    inode->I_blkbits = sb->s_blocksize_bits;
149
150    if (minixfs_iget(sb, inode) != 0) {
151        fprintf(stderr, "major problem: failed to read inode %llu\n", ino);
152        unixfs_inodelayer_ifailed(inode);
153        goto bad_inode;
154    }
155
156    unixfs_inodelayer_isucceeded(inode);
157
158    return inode;
159
160bad_inode:
161    return NULL;
162}
163
164static void
165unixfs_internal_iput(struct inode* ip)
166{
167    unixfs_inodelayer_iput(ip);
168}
169
170static int
171unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
172{
173    if (ino == MACFUSE_ROOTINO)
174        ino = MINIX_ROOT_INO;
175
176    struct inode* ip = unixfs_internal_iget(ino);
177    if (!ip)
178        return ENOENT;
179
180    unixfs_internal_istat(ip, stbuf);
181
182    unixfs_internal_iput(ip);
183
184    return 0;
185}
186
187static void
188unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
189{
190    memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
191}
192
193static int
194unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
195{
196    if (parentino == MACFUSE_ROOTINO)
197        parentino = MINIX_ROOT_INO;
198
199    stbuf->st_ino = ENOENT;
200
201    struct inode* dir = unixfs_internal_iget(parentino);
202    if (!dir)
203        return ENOENT;
204
205    if (!S_ISDIR(dir->I_mode)) {
206        unixfs_internal_iput(dir);
207        return ENOTDIR;
208    }
209
210    int ret = ENOENT;
211
212    unsigned long namelen = strlen(name);
213    unsigned long start, n;
214    unsigned long npages = minix_dir_pages(dir);
215    minix3_dirent* de3;
216    minix_dirent* de;
217    char page[PAGE_SIZE];
218    char* kaddr = NULL;
219
220
221    struct super_block* sb = dir->I_sb;
222    struct minix_sb_info* sbi = minix_sb(sb);
223    unsigned chunk_size = sbi->s_dirsize;
224    struct minix_inode_info* minix_inode = minix_i(dir);
225
226    start = minix_inode->i_dir_start_lookup;
227    if (start >= npages)
228        start = 0;
229    n = start;
230
231    ino_t found_ino = 0;
232
233    do {
234        int error = minixfs_get_page(dir, n, page);
235        if (!error) {
236            kaddr = (char*)page;
237            if (INODE_VERSION(dir) == MINIX_V3) {
238                de3 = (minix3_dirent*)kaddr;
239                kaddr += PAGE_CACHE_SIZE - chunk_size;
240                for (; (char*)de3 <= kaddr; de3++) {
241                    if (!de3->inode)
242                        continue;
243                    if (minix_namecompare(namelen, chunk_size,
244                                          name, de3->name)) {
245                        found_ino = de3->inode;
246                        goto found;
247                    }
248                }
249            } else {
250                de = (minix_dirent*)kaddr;
251                kaddr += PAGE_CACHE_SIZE - chunk_size;
252                for (; (char*)de <= kaddr; de++) {
253                    if (!de->inode)
254                        continue;
255                    if (minix_namecompare(namelen, chunk_size,
256                                          name, de->name)) {
257                        found_ino = de->inode;
258                        goto found;
259                    }
260                }
261            }
262        }
263
264        if (++n >= npages)
265            n = 0;
266    } while (n != start);
267
268found:
269
270    if (found_ino)
271        minix_inode->i_dir_start_lookup = n;
272
273    unixfs_internal_iput(dir);
274
275    if (found_ino)
276        ret = unixfs_internal_igetattr(found_ino, stbuf);
277
278    return ret;
279}
280
281int
282unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
283                             off_t* offset, struct unixfs_direntry* dent)
284{
285    return minixfs_next_direntry(dp, dirbuf, offset, dent);
286
287}
288
289static ssize_t
290unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
291                       int* error)
292{
293    char* p = buf;
294    ssize_t done = 0;
295    ssize_t tomove = 0;
296    ssize_t remaining = nbyte;
297    char page[PAGE_SIZE];
298    sector_t beginpgno = offset >> PAGE_CACHE_SHIFT;
299
300    while (remaining > 0) { /* page sized reads */
301        *error = minixfs_get_page(ip, beginpgno, page);
302        if (*error)
303            break;
304        tomove = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining;
305        memcpy(p, page, tomove);
306        remaining -= tomove;
307        done += tomove;
308        p += tomove;
309        beginpgno++;
310    }
311
312    if ((done == 0) && *error)
313        return -1;
314    
315    return done;
316}
317
318static int
319unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
320{
321    struct inode* ip = unixfs_internal_iget(ino);
322    if (!ip)
323        return ENOENT;
324
325    int error = 0;
326
327    size_t linklen =
328      (ip->I_size > UNIXFS_MAXPATHLEN - 1) ? UNIXFS_MAXPATHLEN - 1: ip->I_size;
329
330    char page[PAGE_SIZE];
331    error = minixfs_get_page(ip, (off_t)0, page);
332    if (error)
333        goto out;
334    memcpy(path, page, linklen);
335
336    path[linklen] = '\0';
337
338out:
339    unixfs_internal_iput(ip);
340
341    return error;
342}
343
344int
345unixfs_internal_sanitycheck(void* filsys, off_t disksize)
346{
347    /* handled elsewhere */
348    return 0;
349}
350
351static int
352unixfs_internal_statvfs(struct statvfs* svb)
353{
354    memcpy(svb, &unixfs->s_statvfs, sizeof(struct statvfs));
355    return 0;
356}