Back to index

avfs  1.0.1
oper.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     Copyright (C) 2006  Ralf Hoffmann (ralf@boomerangsworld.de)
00005 
00006     This program can be distributed under the terms of the GNU GPL.
00007     See the file COPYING.
00008 */
00009 
00010 #include "oper.h"
00011 #include "operutil.h"
00012 #include "internal.h"
00013 #include <stdlib.h>
00014 
00015 static int check_file_access(vfile *vf, int access)
00016 {
00017     if((vf->flags & AVO_DIRECTORY) != 0)
00018         return -EBADF;
00019 
00020     access = (access + 1) & AVO_ACCMODE;
00021     if(((vf->flags + 1) & access) == 0)
00022         return -EBADF;
00023     
00024     return 0;
00025 }
00026 
00027 int av_file_open(vfile *vf, ventry *ve, int flags, avmode_t mode)
00028 {
00029     int res;
00030     struct avfs *avfs = ve->mnt->avfs;
00031 
00032     res = av_copy_vmount(ve->mnt, &vf->mnt);
00033     if(res < 0)
00034        return res;
00035 
00036     if((flags & AVO_EXCL) != 0 && (flags & AVO_CREAT) == 0)
00037         flags &= ~AVO_EXCL;
00038 
00039     if((flags & AVO_TRUNC) != 0 && !AV_ISWRITE(flags)) {
00040         if((flags & AVO_ACCMODE) == AVO_RDONLY)
00041             flags = (flags & ~AVO_ACCMODE) | AVO_RDWR;
00042         else
00043             flags = (flags & ~AVO_ACCMODE) | AVO_WRONLY;
00044     }        
00045 
00046     AVFS_LOCK(avfs);
00047     res = avfs->open(ve, flags, (mode & 07777), &vf->data);
00048     AVFS_UNLOCK(avfs);
00049     if(res < 0) {
00050        av_free_vmount(vf->mnt);
00051         vf->mnt = NULL;
00052         return res;
00053     }
00054 
00055     vf->ptr = 0;
00056     vf->flags = flags;
00057 
00058     return 0;
00059 }
00060 
00061 int av_file_close(vfile *vf)
00062 {
00063     int res;
00064     struct avfs *avfs = vf->mnt->avfs;
00065 
00066     AVFS_LOCK(avfs);
00067     res = avfs->close(vf);
00068     AVFS_UNLOCK(avfs);
00069 
00070     av_free_vmount(vf->mnt);
00071     vf->mnt = NULL;
00072 
00073     return res;
00074 }
00075 
00076 avssize_t av_file_read(vfile *vf, char *buf, avsize_t nbyte)
00077 {
00078     int res;
00079 
00080     res = check_file_access(vf, AVO_RDONLY);
00081     if(res == 0) {
00082         struct avfs *avfs = vf->mnt->avfs;
00083 
00084         AVFS_LOCK(avfs);
00085         res = avfs->read(vf, buf, nbyte);
00086         AVFS_UNLOCK(avfs);
00087     }
00088 
00089     return res;
00090 }
00091 
00092 /* read, specifying offset into file */
00093 avssize_t av_file_pread(vfile *vf, char *buf, avsize_t nbyte, avoff_t offset)
00094 {
00095     int res;
00096     
00097     res = check_file_access(vf, AVO_RDONLY);
00098     if(res == 0) {
00099         avoff_t sres;
00100         struct avfs *avfs = vf->mnt->avfs;
00101 
00102         AVFS_LOCK(avfs);
00103         sres = avfs->lseek(vf, offset, AVSEEK_SET);
00104         if(sres < 0)
00105             res = sres;
00106         else
00107             res = avfs->read(vf, buf, nbyte);
00108         AVFS_UNLOCK(avfs);
00109     }
00110 
00111     return res;
00112 }
00113 
00114 avssize_t av_file_write(vfile *vf, const char *buf, avsize_t nbyte)
00115 {
00116     int res;
00117 
00118     res = check_file_access(vf, AVO_WRONLY);
00119     if(res == 0) {
00120         struct avfs *avfs = vf->mnt->avfs;
00121         
00122         AVFS_LOCK(avfs);
00123         res = avfs->write(vf, buf, nbyte);
00124         AVFS_UNLOCK(avfs);
00125     }
00126     
00127     return res;
00128 }
00129 
00130 /* write, specifying offset into file */
00131 avssize_t av_file_pwrite(vfile *vf, const char *buf, avsize_t nbyte,
00132                          avoff_t offset)
00133 {
00134     int res;
00135 
00136     res = check_file_access(vf, AVO_WRONLY);
00137     if(res == 0) {
00138         avoff_t sres;
00139         struct avfs *avfs = vf->mnt->avfs;
00140 
00141         AVFS_LOCK(avfs);
00142         sres = avfs->lseek(vf, offset, AVSEEK_SET);
00143         if(sres < 0)
00144             res = sres;
00145         else
00146             res = avfs->write(vf, buf, nbyte);
00147         AVFS_UNLOCK(avfs);
00148     }
00149 
00150     return res;
00151 }
00152 
00153 int av_file_truncate(vfile *vf, avoff_t length)
00154 {
00155     int res;
00156     struct avfs *avfs = vf->mnt->avfs;
00157 
00158     if(length < 0)
00159         return -EINVAL;
00160 
00161     res = check_file_access(vf, AVO_WRONLY);
00162     if(res == 0) {
00163         AVFS_LOCK(avfs);
00164         res = avfs->truncate(vf, length);
00165         AVFS_UNLOCK(avfs);
00166     }
00167 
00168     return res;
00169 }
00170 
00171 int av_file_getattr(vfile *vf, struct avstat *buf, int attrmask)
00172 {
00173     int res;
00174     struct avfs *avfs = vf->mnt->avfs;
00175     
00176     AVFS_LOCK(avfs);
00177     res = avfs->getattr(vf, buf, attrmask);
00178     AVFS_UNLOCK(avfs);
00179 
00180     return res;
00181 }
00182 
00183 int av_file_setattr(vfile *vf, struct avstat *buf, int attrmask)
00184 {
00185     int res;
00186     struct avfs *avfs = vf->mnt->avfs;
00187 
00188     AVFS_LOCK(avfs);
00189     res = avfs->setattr(vf, buf, attrmask);
00190     AVFS_UNLOCK(avfs);
00191 
00192     return res;
00193 }
00194 
00195 avoff_t av_file_lseek(vfile *vf, avoff_t offset, int whence)
00196 {
00197     avoff_t res;
00198     struct avfs *avfs = vf->mnt->avfs;
00199     
00200     AVFS_LOCK(avfs);
00201     res = avfs->lseek(vf, offset, whence);
00202     AVFS_UNLOCK(avfs);
00203 
00204     return res;
00205 }
00206 
00207 static void file_destroy(vfile *vf)
00208 {
00209     if(vf->mnt != NULL)
00210         av_file_close(vf);
00211         
00212     AV_FREELOCK(vf->lock);
00213 }
00214 
00215 int av_open(ventry *ve, int flags, avmode_t mode, vfile **resp)
00216 {
00217     int res;
00218     vfile *vf;
00219 
00220     AV_NEW_OBJ(vf, file_destroy);
00221     AV_INITLOCK(vf->lock);
00222     res = av_file_open(vf, ve, flags, mode);
00223     if(res < 0) {
00224         AV_FREELOCK(vf->lock);
00225         av_unref_obj(vf);
00226     }
00227     else 
00228         *resp = vf;
00229 
00230     return res;
00231 }
00232 
00233 /* You only need to call this if you need the return value of close.
00234    Otherwise it is enough to unreferece the vfile
00235 */
00236 int av_close(vfile *vf)
00237 {
00238     int res = 0;
00239 
00240     if(vf != NULL) {
00241         res = av_file_close(vf);
00242         av_unref_obj(vf);
00243     }
00244 
00245     return res;
00246 }
00247 
00248 avssize_t av_read(vfile *vf, char *buf, avsize_t nbyte)
00249 {
00250     avssize_t res;
00251 
00252     AV_LOCK(vf->lock);
00253     res = av_file_read(vf, buf, nbyte);
00254     AV_UNLOCK(vf->lock);
00255 
00256     return res;
00257 }
00258 
00259 avssize_t av_pread(vfile *vf, char *buf, avsize_t nbyte, avoff_t offset)
00260 {
00261     avssize_t res;
00262 
00263     AV_LOCK(vf->lock);
00264     res = av_file_pread(vf, buf, nbyte, offset);
00265     AV_UNLOCK(vf->lock);
00266 
00267     return res;
00268 }
00269 
00270 avssize_t av_write(vfile *vf, const char *buf, avsize_t nbyte)
00271 {
00272     avssize_t res;
00273 
00274     AV_LOCK(vf->lock);
00275     res = av_file_write(vf, buf, nbyte);
00276     AV_UNLOCK(vf->lock);
00277 
00278     return res;
00279 }
00280 
00281 avssize_t av_pwrite(vfile *vf, const char *buf, avsize_t nbyte,
00282                       avoff_t offset)
00283 {
00284     avssize_t res;
00285 
00286     AV_LOCK(vf->lock);
00287     res = av_file_pwrite(vf, buf, nbyte, offset);
00288     AV_UNLOCK(vf->lock);
00289 
00290     return res;
00291 }
00292 
00293 avoff_t av_lseek(vfile *vf, avoff_t offset, int whence)
00294 {
00295     avoff_t res;
00296 
00297     AV_LOCK(vf->lock);
00298     res = av_file_lseek(vf, offset, whence);
00299     AV_UNLOCK(vf->lock);
00300     
00301     return res;
00302 }
00303 
00304 int av_ftruncate(vfile *vf, avoff_t length)
00305 {
00306     int res;
00307 
00308     AV_LOCK(vf->lock);
00309     res = av_file_truncate(vf, length);
00310     AV_UNLOCK(vf->lock);
00311 
00312     return res;
00313 }
00314 
00315 int av_fgetattr(vfile *vf, struct avstat *buf, int attrmask)
00316 {
00317     int res;
00318     
00319     AV_LOCK(vf->lock);
00320     res = av_file_getattr(vf, buf, attrmask);
00321     AV_UNLOCK(vf->lock);
00322 
00323     return res;
00324 }
00325 
00326 int av_fsetattr(vfile *vf, struct avstat *buf, int attrmask)
00327 {
00328     int res;
00329 
00330     AV_LOCK(vf->lock);
00331     res = av_file_setattr(vf, buf, attrmask);
00332     AV_UNLOCK(vf->lock);
00333 
00334     return res;
00335 }
00336 
00337 int av_getattr(ventry *ve, struct avstat *buf, int attrmask, int flags)
00338 {
00339     int res;
00340     vfile vf;
00341 
00342     res = av_file_open(&vf, ve, AVO_NOPERM | flags, 0);
00343     if(res == 0) {
00344         res = av_file_getattr(&vf, buf, attrmask);
00345         av_file_close(&vf);
00346     }
00347 
00348     return res;
00349 }
00350 
00351 int av_access(ventry *ve, int amode)
00352 {
00353     int res;
00354     struct avfs *avfs = ve->mnt->avfs;
00355     
00356     AVFS_LOCK(avfs);
00357     res = avfs->access(ve, amode);
00358     AVFS_UNLOCK(avfs);
00359 
00360     return res;
00361 }
00362 
00363 static int count_components(const char *p)
00364 {
00365     int ctr;
00366 
00367     for (; *p == '/'; p++);
00368     for (ctr = 0; *p; ctr++) {
00369         for (; *p && *p != '/'; p++);
00370         for (; *p == '/'; p++);
00371     }
00372     return ctr;
00373 }
00374 
00375 static void strip_common(const char **sp, const char **tp)
00376 {
00377     const char *s = *sp;
00378     const char *t = *tp;
00379     do {
00380         for (; *s == '/'; s++);
00381         for (; *t == '/'; t++);
00382         *tp = t;
00383         *sp = s;
00384         for (; *s == *t && *s && *s != '/'; s++, t++);
00385     } while ((*s == *t && *s) || (!*s && *t == '/') || (*s == '/' && !*t));
00386 }
00387 
00388 static void transform_symlink(const char *path, const char *linkdest, char **linkp)
00389 {
00390     const char *l = linkdest;
00391     char *newlink;
00392     char *s;
00393     int dotdots;
00394     int i;
00395     
00396     /* TODO: possible improvement:
00397      * absolute symlinks in archives (mount points in general)
00398      * could be interpreted with the mount point as root directory
00399      * do make this work the base path should be removed from the path var
00400      */
00401     /* const char *b = base_path; */
00402 
00403     if (linkp == NULL)
00404         return;
00405     
00406     *linkp = NULL;
00407 
00408     if (l[0] != '/' || path[0] != '/')
00409         return;
00410 
00411     /* strip_common(&path, &b);
00412        if (*b)
00413        return;
00414     */
00415 
00416     strip_common(&l, &path);
00417 
00418     dotdots = count_components(path);
00419     if (!dotdots)
00420         return;
00421     dotdots--;
00422 
00423     newlink = malloc(dotdots * 3 + strlen(l) + 2);
00424     if (!newlink) {
00425         av_log(AVLOG_ERROR, "transform_symlink: memory allocation failed");
00426         exit(1);
00427     }
00428     for (s = newlink, i = 0; i < dotdots; i++, s += 3)
00429         strcpy(s, "../");
00430 
00431     if (l[0])
00432         strcpy(s, l);
00433     else if (!dotdots)
00434         strcpy(s, ".");
00435     else
00436         s[0] = '\0';
00437 
00438     *linkp = newlink;
00439 }
00440 
00441 int av_readlink(ventry *ve, char **bufp)
00442 {
00443     int res;
00444     struct avfs *avfs = ve->mnt->avfs;
00445 
00446     AVFS_LOCK(avfs);
00447     res = avfs->readlink(ve, bufp);
00448     AVFS_UNLOCK(avfs);
00449     
00450     if(res == 0) {
00451         if(*bufp[0] == '/' && av_get_symlink_rewrite() == 1) {
00452             char *rel_link = NULL;
00453             char *path = NULL;
00454             int res2;
00455             
00456             res2 = av_generate_path(ve, &path);
00457             if(res2 == 0) {
00458                 transform_symlink(path, *bufp, &rel_link);
00459                 if(rel_link != NULL) {
00460                     free(*bufp);
00461                     *bufp = rel_link;
00462                 }
00463                 av_free(path);
00464             }
00465         }
00466     }
00467 
00468     return res;
00469 }
00470 
00471 
00472 int av_unlink(ventry *ve)
00473 {
00474     int res;
00475     struct avfs *avfs = ve->mnt->avfs;
00476     
00477     AVFS_LOCK(avfs);
00478     res = avfs->unlink(ve);
00479     AVFS_UNLOCK(avfs);
00480 
00481     return res;
00482 }
00483 
00484 int av_rmdir(ventry *ve)
00485 {
00486     int res;
00487     struct avfs *avfs = ve->mnt->avfs;
00488     
00489     AVFS_LOCK(avfs);
00490     res = avfs->rmdir(ve);
00491     AVFS_UNLOCK(avfs);
00492     
00493     return res;
00494 }
00495 
00496 int av_mkdir(ventry *ve, avmode_t mode)
00497 {
00498     int res;
00499     struct avfs *avfs = ve->mnt->avfs;
00500     
00501     AVFS_LOCK(avfs);
00502     res = avfs->mkdir(ve, (mode & 07777));
00503     AVFS_UNLOCK(avfs);
00504     
00505     return res;
00506 }
00507 
00508 int av_mknod(ventry *ve, avmode_t mode, avdev_t dev)
00509 {
00510     int res;
00511     struct avfs *avfs = ve->mnt->avfs;
00512     
00513     AVFS_LOCK(avfs);
00514     res = avfs->mknod(ve, mode, dev);
00515     AVFS_UNLOCK(avfs);
00516     
00517     return res;
00518 }
00519 
00520 int av_symlink(const char *path, ventry *newve)
00521 {
00522     int res;
00523     struct avfs *avfs = newve->mnt->avfs;
00524     
00525     AVFS_LOCK(avfs);
00526     res = avfs->symlink(path, newve);
00527     AVFS_UNLOCK(avfs);
00528     
00529     return res;
00530 }
00531 
00532 static int compare_mount(struct avmount *mnt1, struct avmount *mnt2)
00533 {
00534     int res;
00535     ventry tmpve;
00536     char *path1;
00537     char *path2;
00538 
00539     /* FIXME: checking should be done mount per mount, not with
00540        av_generate_path() */
00541 
00542     tmpve.data = NULL;
00543     tmpve.mnt = mnt1;
00544     res = av_generate_path(&tmpve, &path1);
00545     if(res == 0) {
00546         tmpve.mnt = mnt2;
00547         res = av_generate_path(&tmpve, &path2);
00548         if(res == 0) {
00549             if(strcmp(path1, path2) != 0) 
00550                 res = -EXDEV;
00551 
00552             av_free(path2);
00553         }
00554         av_free(path1);
00555     }
00556 
00557     return res;
00558 }
00559 
00560 int av_rename(ventry *ve, ventry *newve)
00561 {
00562     int res;
00563 
00564     res = compare_mount(ve->mnt, newve->mnt);
00565     if(res == 0) {
00566         struct avfs *avfs = ve->mnt->avfs;
00567         
00568         AVFS_LOCK(avfs);
00569         res = avfs->rename(ve, newve);
00570         AVFS_UNLOCK(avfs);
00571     }
00572     
00573     return res;
00574 }
00575 
00576 int av_link(ventry *ve, ventry *newve)
00577 {
00578     int res;
00579 
00580     res = compare_mount(ve->mnt, newve->mnt);
00581     if(res == 0) {
00582         struct avfs *avfs = ve->mnt->avfs;
00583         
00584         AVFS_LOCK(avfs);
00585         res = avfs->link(ve, newve);
00586         AVFS_UNLOCK(avfs);
00587     }
00588     
00589     return res;
00590 }
00591