PageRenderTime 41ms CodeModel.GetById 18ms app.highlight 18ms RepoModel.GetById 1ms app.codeStats 0ms

/filesystems/unixfs/ufs/unixfs_ufs.c

http://macfuse.googlecode.com/
C | 297 lines | 227 code | 64 blank | 6 comment | 39 complexity | ed57a22eb9ccac464aae8a9389e0a16e MD5 | raw file
  1/*
  2 * UFS for MacFUSE
  3 * Copyright (c) 2008 Amit Singh
  4 * http://osxbook.com
  5 */
  6
  7#include "ufs.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("UFS", ufs);
 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 ufs_inode_info))) != 0)
 48        goto out;
 49
 50    char args[UNIXFS_MNAMELEN];
 51    snprintf(args, UNIXFS_MNAMELEN, "%s", *fsname);
 52    char* c = args;
 53    for (; *c; c++)
 54        *c = tolower(*c);
 55
 56    sb = U_ufs_fill_super(fd, (void*)args, 0 /* silent */);
 57    if (!sb) {
 58        err = EINVAL;
 59        goto out;
 60    }
 61
 62    unixfs = sb;
 63
 64    err = U_ufs_statvfs(sb, &(unixfs->s_statvfs));
 65    if (err)
 66        goto out;
 67
 68    unixfs->s_flags = flags;
 69
 70    unixfs->s_dentsize = 0; /* variable */
 71
 72    snprintf(unixfs->s_volname, UNIXFS_MAXNAMLEN, "%s", unixfs_fstype);
 73    snprintf(unixfs->s_fsname, UNIXFS_MNAMELEN, "%s", *fsname);
 74
 75    *fsname = unixfs->s_fsname;
 76    *volname = unixfs->s_volname;
 77
 78out:
 79    if (err) {
 80        if (fd > 0)
 81            close(fd);
 82        if (sb)
 83            free(sb);
 84    }
 85
 86    return sb;
 87}
 88
 89static void
 90unixfs_internal_fini(void* filsys)
 91{
 92    unixfs_inodelayer_fini();
 93
 94    struct super_block* sb = (struct super_block*)filsys;
 95    if (sb)
 96        free(sb);
 97}
 98
 99static off_t
100unixfs_internal_alloc(void)
101{
102    return (off_t)0;
103}
104
105static off_t
106unixfs_internal_bmap(struct inode* ip, off_t lblkno, int* error)
107{
108    off_t result;
109    *error = U_ufs_get_block(ip, lblkno, &result);
110    return result;
111}
112
113static int
114unixfs_internal_bread(off_t blkno, char* blkbuf)
115{
116    struct super_block* sb = unixfs;
117
118    if (pread(sb->s_bdev, blkbuf, sb->s_blocksize,
119              blkno * (off_t)(sb->s_blocksize)) != sb->s_blocksize)
120        return EIO;
121
122    return 0;
123}
124
125struct inode*
126unixfs_internal_iget(ino_t ino)
127{
128    if (ino == MACFUSE_ROOTINO)
129        ino = UFS_ROOTINO;
130
131    struct inode* inode = unixfs_inodelayer_iget(ino);
132    if (!inode) {
133        fprintf(stderr, "*** fatal error: no inode for %llu\n", ino);
134        abort();
135    }
136
137    if (inode->I_initialized)
138        return inode;
139
140    struct super_block* sb = unixfs;
141    inode->I_ino = ino;
142
143    int error = U_ufs_iget(sb, inode);
144    if (error) {
145        fprintf(stderr, "major problem: failed to read inode %llu\n", ino);
146        unixfs_inodelayer_ifailed(inode);
147        goto bad_inode;
148    }
149
150    unixfs_inodelayer_isucceeded(inode);
151
152    return inode;
153
154bad_inode:
155    return NULL;
156}
157
158static void
159unixfs_internal_iput(struct inode* ip)
160{
161    unixfs_inodelayer_iput(ip);
162}
163
164static int
165unixfs_internal_igetattr(ino_t ino, struct stat* stbuf)
166{
167    if (ino == MACFUSE_ROOTINO)
168        ino = UFS_ROOTINO;
169
170    struct inode* ip = unixfs_internal_iget(ino);
171    if (!ip)
172        return ENOENT;
173
174    unixfs_internal_istat(ip, stbuf);
175
176    unixfs_internal_iput(ip);
177
178    return 0;
179}
180
181static void
182unixfs_internal_istat(struct inode* ip, struct stat* stbuf)
183{
184    memcpy(stbuf, &ip->I_stat, sizeof(struct stat));
185}
186
187static int
188unixfs_internal_namei(ino_t parentino, const char* name, struct stat* stbuf)
189{
190    if (parentino == MACFUSE_ROOTINO)
191        parentino = UFS_ROOTINO;
192
193    int ret = ENOENT;
194    stbuf->st_ino = 0;
195
196    size_t namelen = strlen(name);
197    if (namelen > UFS_MAXNAMLEN)
198        return ENAMETOOLONG;
199
200    struct inode* dir = unixfs_internal_iget(parentino);
201    if (!dir)
202        return ENOENT;
203
204    if (!S_ISDIR(dir->I_mode)) {
205        unixfs_internal_iput(dir);
206        return ENOTDIR;
207    }
208
209    ino_t target = U_ufs_inode_by_name(dir, name);
210    if (target)
211        ret = unixfs_internal_igetattr(target, stbuf);
212
213    unixfs_internal_iput(dir);
214
215    return ret;
216}
217
218int
219unixfs_internal_nextdirentry(struct inode* dp, struct unixfs_dirbuf* dirbuf,
220                             off_t* offset, struct unixfs_direntry* dent)
221{
222    return U_ufs_next_direntry(dp, dirbuf, offset, dent);
223
224}
225
226static ssize_t
227unixfs_internal_pbread(struct inode* ip, char* buf, size_t nbyte, off_t offset,
228                       int* error)
229{
230    char* p = buf;
231    ssize_t done = 0;
232    ssize_t tomove = 0;
233    ssize_t remaining = nbyte;
234    char page[PAGE_SIZE];
235    sector_t beginpgno = offset >> PAGE_CACHE_SHIFT;
236
237    while (remaining > 0) { /* page sized reads */
238        *error = U_ufs_get_page(ip, beginpgno, page);
239        if (*error)
240            break;
241        tomove = (remaining > PAGE_SIZE) ? PAGE_SIZE : remaining;
242        memcpy(p, page, tomove);
243        remaining -= tomove;
244        done += tomove;
245        p += tomove;
246        beginpgno++;
247    }
248
249    if ((done == 0) && *error)
250        return -1;
251    
252    return done;
253}
254
255static int
256unixfs_internal_readlink(ino_t ino, char path[UNIXFS_MAXPATHLEN])
257{
258    struct inode* ip = unixfs_internal_iget(ino);
259    if (!ip)
260        return ENOENT;
261
262    int error = 0;
263
264    size_t linklen =
265        (ip->I_size > UNIXFS_MAXPATHLEN - 1) ? UNIXFS_MAXPATHLEN - 1: ip->I_size;
266
267    if (!ip->I_blocks) { /* fast */
268        struct ufs_inode_info* p = (struct ufs_inode_info*)ip->I_private;
269        memcpy(path, (char*)p->i_u1.i_symlink, sizeof(p->i_u1.i_symlink));
270    } else {
271        char page[PAGE_SIZE];
272        error = U_ufs_get_page(ip, (off_t)0, page);
273        if (error)
274            goto out;
275        memcpy(path, page, linklen);
276    }
277
278    path[linklen] = '\0';
279
280out:
281    unixfs_internal_iput(ip);
282
283    return error;
284}
285
286int
287unixfs_internal_sanitycheck(void* filsys, off_t disksize)
288{
289    /* handled elsewhere */
290    return 0;
291}
292
293static int
294unixfs_internal_statvfs(struct statvfs* svb)
295{
296    return U_ufs_statvfs(unixfs, svb);
297}