Back to index

avfs  1.0.1
local.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 2000  Miklos Szeredi <miklos@szeredi.hu>
00004 
00005     This program can be distributed under the terms of the GNU GPL.
00006     See the file COPYING.
00007 */
00008 
00009 #include "local.h"
00010 #include "version.h"
00011 
00012 #include <unistd.h>
00013 #include <fcntl.h>
00014 #include <dirent.h>
00015 #include <utime.h>
00016 #include <stdio.h>
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 
00020 struct localfile {
00021     int fd;
00022     DIR *dirp;
00023     avoff_t entctr;
00024     char *path;
00025 };
00026 
00027 static struct localfile *local_vfile_file(vfile *vf)
00028 {
00029     return (struct localfile *) vf->data;
00030 }
00031 
00032 static int avoflags_to_oflags(int avflags)
00033 {
00034     int flags;
00035   
00036     flags = avflags & AVO_ACCMODE;
00037     if(avflags & AVO_CREAT)    flags |= O_CREAT;
00038     if(avflags & AVO_EXCL)     flags |= O_EXCL;
00039     if(avflags & AVO_TRUNC)    flags |= O_TRUNC;
00040     if(avflags & AVO_APPEND)   flags |= O_APPEND;
00041     if(avflags & AVO_NONBLOCK) flags |= O_NONBLOCK;
00042 #ifdef O_SYNC
00043     if(avflags & AVO_SYNC)     flags |= O_SYNC;
00044 #endif
00045 
00046     return flags;
00047 }
00048 
00049 static int local_open(ventry *ve, int flags, avmode_t mode, void **resp)
00050 {
00051     struct localfile *fi;
00052     const char *path = (char *) ve->data;
00053     int fd;
00054     DIR *dirp;
00055     
00056     fd = -1;
00057     dirp = NULL;
00058     if((flags & AVO_ACCMODE) != AVO_NOPERM) {
00059         if(!(flags & AVO_DIRECTORY))
00060             fd = open(path, avoflags_to_oflags(flags), mode);
00061         else
00062             dirp = opendir(path);
00063 
00064         if(fd == -1 && dirp == NULL)
00065             return -errno;
00066         
00067         if(fd != -1)
00068             av_registerfd(fd);
00069     }
00070     
00071     AV_NEW(fi);
00072 
00073     fi->fd = fd;
00074     fi->dirp = dirp;
00075     fi->entctr = 0;
00076     fi->path = av_strdup(path);
00077 
00078     *resp = fi;
00079 
00080     return 0;
00081 }
00082 
00083 static int local_close(vfile *vf)
00084 {
00085     int res = 0;
00086     struct localfile *fi = local_vfile_file(vf);
00087 
00088     if(fi->fd != -1)
00089         res = close(fi->fd);
00090     if(fi->dirp != NULL)
00091         res = closedir(fi->dirp);
00092     
00093     if(res == -1)
00094         res = -errno;
00095 
00096     av_free(fi->path);
00097     av_free(fi);
00098 
00099     return res;
00100 }
00101 
00102 
00103 static avssize_t local_read(vfile *vf, char *buf, avsize_t nbyte)
00104 {
00105     avssize_t res;
00106     struct localfile *fi = local_vfile_file(vf);
00107 
00108     res = read(fi->fd, buf, nbyte);
00109     if(res == -1)
00110         return -errno;
00111 
00112     vf->ptr += res;
00113     
00114     return res;
00115 }
00116 
00117 static avssize_t local_write(vfile *vf, const char *buf, avsize_t nbyte)
00118 {
00119     avssize_t res;
00120     struct localfile *fi = local_vfile_file(vf);
00121 
00122     res = write(fi->fd, buf, nbyte);
00123     if(res == -1)
00124         return -errno;
00125 
00126     /* NOTE: ptr will go astray if file is opened with O_APPEND */
00127     vf->ptr += res;
00128 
00129     return res;
00130 }
00131 
00132 static avoff_t local_lseek(vfile *vf, avoff_t offset, int whence)
00133 {
00134     avoff_t res;
00135     struct localfile *fi = local_vfile_file(vf);
00136 
00137     res = lseek(fi->fd, offset, whence);
00138     if(res == -1)
00139         return -errno;
00140     
00141     vf->ptr = res;
00142 
00143     return res;
00144 }
00145 
00146 static int local_readdir(vfile *vf, struct avdirent *buf)
00147 {
00148     struct dirent *de;
00149     struct localfile *fi = local_vfile_file(vf);
00150 
00151     if(vf->ptr < fi->entctr) {
00152        rewinddir(fi->dirp);
00153        fi->entctr = 0;
00154     }
00155 
00156     do {
00157        errno = 0;
00158        de = readdir(fi->dirp);
00159        if(de == NULL)
00160             return -errno;
00161 
00162        fi->entctr ++;
00163     } while(vf->ptr >= fi->entctr);
00164 
00165     buf->name = av_strdup(de->d_name);
00166     buf->ino = de->d_ino;
00167 #ifdef HAVE_D_TYPE
00168     buf->type = de->d_type;
00169 #else
00170     buf->type = 0;
00171 #endif
00172     vf->ptr ++;
00173 
00174     return 1;
00175 }
00176 
00177 static int local_truncate(vfile *vf, avoff_t length)
00178 {
00179     int res;
00180     struct localfile *fi = local_vfile_file(vf);
00181     
00182     if(fi->fd != -1)
00183         res = ftruncate(fi->fd, length);
00184     else
00185         res = truncate(fi->path, length);
00186 
00187     if(res == -1)
00188         return -errno;
00189 
00190     return 0;
00191 }
00192 
00193 static void stat_to_avstat(struct avstat *vbuf, struct stat *lbuf)
00194 {
00195     vbuf->dev        = lbuf->st_dev;
00196     vbuf->ino        = lbuf->st_ino;
00197     vbuf->mode       = lbuf->st_mode;
00198     vbuf->nlink      = lbuf->st_nlink;
00199     vbuf->uid        = lbuf->st_uid;
00200     vbuf->gid        = lbuf->st_gid;
00201     vbuf->rdev       = lbuf->st_rdev;
00202     vbuf->size       = lbuf->st_size;
00203     vbuf->blksize    = lbuf->st_blksize;
00204     vbuf->blocks     = lbuf->st_blocks;
00205     vbuf->atime.sec  = lbuf->st_atime;
00206     vbuf->atime.nsec = 0;
00207     vbuf->mtime.sec  = lbuf->st_mtime;
00208     vbuf->mtime.nsec = 0;
00209     vbuf->ctime.sec  = lbuf->st_ctime;
00210     vbuf->ctime.nsec = 0;
00211 }
00212 
00213 
00214 static int local_getattr(vfile *vf, struct avstat *buf, int attrmask)
00215 {
00216     int res;
00217     struct stat stbuf;
00218     struct localfile *fi = local_vfile_file(vf);
00219 
00220     if(fi->fd != -1)
00221         res = fstat(fi->fd, &stbuf);
00222     else if((vf->flags & AVO_NOFOLLOW) != 0)
00223         res = lstat(fi->path, &stbuf);
00224     else
00225         res = stat(fi->path, &stbuf);
00226 
00227     if(res == -1)
00228         return -errno;
00229     
00230     stat_to_avstat(buf, &stbuf);
00231     return 0;
00232 }
00233 
00234 static int local_set_time(struct localfile *fi, const struct avstat *buf,
00235                           int attrmask)
00236 {
00237     struct utimbuf utbuf;
00238     
00239     utbuf.actime = buf->atime.sec;
00240     utbuf.modtime  = buf->mtime.sec;
00241     
00242     if(!(attrmask & AVA_ATIME))
00243         utbuf.actime = utbuf.modtime;
00244     if(!(attrmask & AVA_MTIME))
00245         utbuf.modtime = utbuf.actime;
00246     
00247     return utime(fi->path, &utbuf);
00248 }
00249 
00250 static int local_set_mode(struct localfile *fi, avmode_t mode)
00251 {
00252     if(fi->fd != -1)
00253         return  fchmod(fi->fd, mode);
00254     else
00255         return chmod(fi->path, mode);
00256 }
00257 
00258 static int local_set_ugid(struct localfile *fi, const struct avstat *buf,
00259                           int attrmask, int flags)
00260 {
00261     uid_t uid = (uid_t) -1;
00262     gid_t gid = (gid_t) -1;
00263     
00264     if((attrmask & AVA_UID) != 0)
00265         uid = buf->uid;
00266     if((attrmask & AVA_GID) != 0)
00267         gid = buf->gid;
00268     
00269     if(fi->fd != -1)
00270         return fchown(fi->fd, uid, gid);
00271     else if((flags & AVO_NOFOLLOW) != 0)
00272         return lchown(fi->path, uid, gid);
00273     else
00274         return chown(fi->path, uid, gid);
00275 }
00276 
00277 static int local_setattr(vfile *vf, struct avstat *buf, int attrmask)
00278 {
00279     int res = 0;
00280     struct localfile *fi = local_vfile_file(vf);
00281 
00282     if((attrmask & (AVA_ATIME | AVA_MTIME)) != 0) 
00283         res = local_set_time(fi, buf, attrmask);
00284     if((attrmask & AVA_MODE) != 0)
00285         res = local_set_mode(fi, buf->mode);
00286     if((attrmask & (AVA_UID | AVA_GID)) != 0)
00287         res = local_set_ugid(fi, buf, attrmask, vf->flags);
00288 
00289     if(res == -1)
00290         return -errno;
00291 
00292     return 0;
00293 }
00294 
00295 static int local_access(ventry *ve, int amode)
00296 {
00297     int res;
00298     const char *path = (char *) ve->data;
00299     
00300     res = access(path, amode);
00301     if(res == -1)
00302         return -errno;
00303 
00304     return 0;
00305 }
00306 
00307 static int local_readlink(ventry *ve, char **bufp)
00308 {
00309     int res;
00310     unsigned int bufsize;
00311     char *buf;
00312     const char *path = (char *) ve->data;
00313     
00314     bufsize = 0;
00315     buf = NULL;
00316     do {
00317         bufsize += 1024;
00318         buf = av_realloc(buf, bufsize + 1);
00319         res = readlink(path, buf, bufsize);
00320         if(res == -1) {
00321             av_free(buf);
00322             return -errno;
00323         }
00324     } while(res >= bufsize);
00325     
00326     buf[res] = '\0';
00327     *bufp = buf;
00328 
00329     return 0;
00330 }
00331 
00332 static int local_unlink(ventry *ve)
00333 {
00334     int res;
00335     char *path = (char *) ve->data;
00336 
00337     res = unlink(path);
00338     if(res == -1)
00339         return -errno;
00340 
00341     return 0;
00342 }
00343 
00344 static int local_rmdir(ventry *ve)
00345 {
00346     int res;
00347     char *path = (char *) ve->data;
00348 
00349     res = rmdir(path);
00350     if(res == -1)
00351         return -errno;
00352 
00353     return 0;
00354 }
00355 
00356 static int local_mkdir(ventry *ve, avmode_t mode)
00357 {
00358     int res;
00359     char *path = (char *) ve->data;
00360 
00361     res = mkdir(path, mode);
00362     if(res == -1)
00363         return -errno;
00364 
00365     return 0;
00366 }
00367 
00368 static int local_mknod(ventry *ve, avmode_t mode, avdev_t dev)
00369 {
00370     int res;
00371     char *path = (char *) ve->data;
00372 
00373     res = mknod(path, mode, dev);
00374     if(res == -1)
00375         return -errno;
00376 
00377     return 0;
00378 }
00379 
00380 static int local_rename(ventry *ve, ventry *newve)
00381 {
00382     int res;
00383     char *path = (char *) ve->data;
00384     char *newpath = (char *) newve->data;
00385 
00386     res = rename(path, newpath);
00387     if(res == -1)
00388         return -errno;
00389 
00390     return 0;
00391 }
00392 
00393 static int local_link(ventry *ve, ventry *newve)
00394 {
00395     int res;
00396     char *path = (char *) ve->data;
00397     char *newpath = (char *) newve->data;
00398 
00399     res = link(path, newpath);
00400     if(res == -1)
00401         return -errno;
00402 
00403     return 0;
00404 }
00405 
00406 static int local_symlink(const char *path, ventry *newve)
00407 {
00408     int res;
00409     char *newpath = (char *) newve->data;
00410 
00411     res = symlink(path, newpath);
00412     if(res == -1)
00413         return -errno;
00414 
00415     return 0;
00416 }
00417 
00418 static int local_lookup(ventry *ve, const char *name, void **newp)
00419 {
00420     char *path = (char *) ve->data;
00421 
00422     
00423     if(path == NULL) {
00424         /* You can't access the local handler directly*/
00425         return -ENOENT;
00426     }
00427     else if(name != NULL) {
00428         if(path[0] == '/' && path[1] == '\0' && name[0] == '/')
00429             path[0] = '\0';
00430         path = av_stradd(path, name, NULL);
00431     }
00432     else {
00433         char *s;
00434         s = strrchr(path, AV_DIR_SEP_CHAR);
00435         if(s == NULL) {
00436             path[0] = '\0';
00437             path = av_stradd(path, ".", NULL);
00438         }
00439         else if(s != path)
00440             s[0] = '\0';
00441         else
00442             s[1] = '\0';
00443     }
00444 
00445     *newp = path;
00446     
00447     return 0;
00448 }
00449 
00450 int av_init_module_local()
00451 {
00452     int res;
00453     int flags = AVF_NEEDSLASH | AVF_NOLOCK;
00454     struct avfs *avfs;
00455 
00456     res = av_new_avfs("local", NULL, AV_VER, flags, NULL, &avfs);
00457     if(res < 0)
00458         return res;
00459 
00460     avfs->lookup     = local_lookup;
00461 
00462     avfs->open       = local_open;
00463     avfs->close      = local_close;
00464     avfs->read       = local_read;
00465     avfs->write      = local_write;
00466     avfs->lseek      = local_lseek;
00467     avfs->readdir    = local_readdir;
00468     avfs->access     = local_access;
00469     avfs->getattr    = local_getattr;
00470     avfs->setattr    = local_setattr;
00471     avfs->readlink   = local_readlink;
00472     avfs->unlink     = local_unlink;
00473     avfs->rmdir      = local_rmdir;
00474     avfs->mkdir      = local_mkdir;
00475     avfs->mknod      = local_mknod;
00476     avfs->rename     = local_rename;
00477     avfs->link       = local_link;
00478     avfs->symlink    = local_symlink;
00479     avfs->truncate   = local_truncate;
00480 
00481     av_add_avfs(avfs);
00482     
00483     return 0;
00484 }