Back to index

avfs  1.0.1
archutil.c
Go to the documentation of this file.
00001 /*
00002     AVFS: A Virtual File System Library
00003     Copyright (C) 2000-2001  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 "archint.h"
00010 
00011 static void archnode_destroy(struct archnode *nod)
00012 {
00013     av_free(nod->linkname);
00014     av_unref_obj(nod->data);
00015 }
00016 
00017 struct archnode *av_arch_new_node(struct archive *arch, struct entry *ent,
00018                                   int isdir)
00019 {
00020     struct archnode *nod;
00021 
00022     nod = (struct archnode *) av_namespace_get(ent);
00023     if(nod != NULL) {
00024         av_unref_obj(nod);
00025         av_unref_obj(ent);
00026     }
00027 
00028     AV_NEW_OBJ(nod, archnode_destroy);
00029 
00030     av_default_stat(&nod->st);
00031     nod->linkname = NULL;
00032     nod->offset = 0;
00033     nod->realsize = 0;
00034     nod->data = NULL;
00035     nod->flags = 0;
00036     nod->numopen = 0;
00037 
00038     /* FIXME: This scheme will allocate the same device to a tar file
00039        inside a tarfile. While this is not fatal, 'find -xdev' would not do
00040        what is expected.  */
00041 
00042     nod->st.dev = arch->avfs->dev;
00043     nod->st.ino = av_new_ino(arch->avfs);
00044 
00045     nod->st.mode = 0644 | AV_IFREG;
00046     nod->st.uid = arch->st.uid;
00047     nod->st.gid = arch->st.gid;
00048     nod->st.mtime = arch->st.mtime;
00049     nod->st.atime = nod->st.mtime;
00050     nod->st.ctime = nod->st.mtime;
00051     if(!isdir)
00052         nod->st.nlink = 1;
00053     else {
00054         struct entry *parent;
00055         struct archnode *parnod;
00056 
00057         nod->st.nlink = 2;        
00058         parent = av_namespace_parent(ent);
00059         if(parent != NULL) {
00060             parnod = (struct archnode *) av_namespace_get(parent);
00061             if(parnod != NULL) 
00062                 parnod->st.nlink ++;
00063 
00064             av_unref_obj(parent);
00065         }
00066     }
00067 
00068     av_namespace_set(ent, nod);
00069     av_ref_obj(ent);
00070 
00071     return nod;
00072 }
00073 
00074 void av_arch_del_node(struct entry *ent)
00075 {
00076     struct archnode *nod;
00077 
00078     nod = (struct archnode *) av_namespace_get(ent);
00079     av_namespace_set(ent, NULL);
00080     av_unref_obj(nod);
00081     av_unref_obj(ent);
00082 }
00083 
00084 struct archnode *av_arch_default_dir(struct archive *arch, struct entry *ent)
00085 {
00086     struct archnode *nod;
00087     avmode_t mode;
00088 
00089     nod = av_arch_new_node(arch, ent, 1);
00090 
00091     mode = (arch->st.mode & 0777) | AV_IFDIR;
00092     if (mode & 0400) mode |= 0100;
00093     if (mode & 0040) mode |= 0010;
00094     if (mode & 0004) mode |= 0001;
00095 
00096     nod->st.mode = mode;
00097     nod->flags |= ANOF_AUTODIR;
00098 
00099     return nod;
00100 }
00101 
00102 struct entry *av_arch_resolve(struct archive *arch, const char *path,
00103                               int create, int flags)
00104 {
00105     struct entry *ent;
00106     char *s, *p;
00107     char *pathdup = av_strdup(path);
00108 
00109     p = pathdup;
00110     ent = av_namespace_subdir(arch->ns, NULL);
00111     while(1) {
00112         struct entry *next;
00113         struct archnode *nod;
00114         char c;
00115 
00116         for(;*p == '/'; p++);
00117         for(s = p; *s && *s != '/'; s++);
00118         c = *s;
00119         *s = '\0';
00120         if(!*p)
00121             break;
00122 
00123         nod = (struct archnode *) av_namespace_get(ent);
00124         if(nod == NULL) {
00125             if(!create) {
00126                 av_unref_obj(ent);
00127                 ent = NULL;
00128                 break;
00129             }
00130             av_arch_default_dir(arch, ent);
00131             av_namespace_setflags(ent, flags, 0);
00132         }
00133         else if(!AV_ISDIR(nod->st.mode)) {
00134             if(create) 
00135                 av_log(AVLOG_WARNING,
00136                        "ARCH: cannot create %s: Not a directory", path);
00137             av_unref_obj(ent);
00138             ent = NULL;
00139             break;
00140         }
00141         
00142         next = av_namespace_lookup_all(arch->ns, ent, p);
00143         if(next != NULL) {
00144             av_unref_obj(ent);
00145             ent = next;
00146         }
00147         
00148         *s = c;
00149         p = s;
00150     }
00151 
00152     av_free(pathdup);
00153 
00154     return ent;
00155 }
00156 
00157 int av_arch_isroot(struct archive *arch, struct entry *ent)
00158 {
00159     int res;
00160     struct entry *root;
00161     
00162     root = av_namespace_subdir(arch->ns, NULL);
00163     if(root == ent)
00164         res = 1;
00165     else
00166         res = 0;
00167 
00168     av_unref_obj(root);
00169     
00170     return res;
00171 }
00172 
00173 struct entry *av_arch_create(struct archive *arch, const char *path, int flags)
00174 {
00175     struct archnode *nod;
00176     struct entry *ent;
00177 
00178     ent = av_arch_resolve(arch, path, 1, flags);
00179     if(ent == NULL)
00180         return NULL;
00181 
00182     if(av_arch_isroot(arch, ent)) {
00183         av_log(AVLOG_WARNING, "Empty filename");
00184         av_unref_obj(ent);
00185         return NULL;
00186     }
00187     
00188     nod = (struct archnode *) av_namespace_get(ent);
00189     if(nod != NULL) {
00190         av_log(AVLOG_WARNING, "Entry for %s already exists", path);
00191         av_unref_obj(ent);
00192         return NULL;
00193     }
00194 
00195     av_namespace_setflags(ent, flags, 0);
00196 
00197     return ent;
00198 }