direc.c (4245B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <libsec.h> 5 6 #include "iso9660.h" 7 8 void 9 mkdirec(Direc *direc, XDir *d) 10 { 11 memset(direc, 0, sizeof(Direc)); 12 direc->name = atom(d->name); 13 direc->uid = atom(d->uid); 14 direc->gid = atom(d->gid); 15 direc->uidno = d->uidno; 16 direc->gidno = d->gidno; 17 direc->mode = d->mode; 18 direc->length = d->length; 19 direc->mtime = d->mtime; 20 direc->atime = d->atime; 21 direc->ctime = d->ctime; 22 direc->symlink = d->symlink; 23 } 24 25 static int 26 strecmp(char *a, char *ea, char *b) 27 { 28 int r; 29 30 if((r = strncmp(a, b, ea-a)) != 0) 31 return r; 32 33 if(b[ea-a] == '\0') 34 return 0; 35 return 1; 36 } 37 38 /* 39 * Binary search a list of directories for the 40 * entry with name name. 41 * If no entry is found, return a pointer to 42 * where a new such entry would go. 43 */ 44 static Direc* 45 dbsearch(char *name, int nname, Direc *d, int n) 46 { 47 int i; 48 49 while(n > 0) { 50 i = strecmp(name, name+nname, d[n/2].name); 51 if(i < 0) 52 n = n/2; 53 else if(i > 0) { 54 d += n/2+1; 55 n -= (n/2+1); 56 } else 57 return &d[n/2]; 58 } 59 return d; 60 } 61 62 /* 63 * Walk to name, starting at d. 64 */ 65 Direc* 66 walkdirec(Direc *d, char *name) 67 { 68 char *p, *nextp, *slashp; 69 Direc *nd; 70 71 for(p=name; p && *p; p=nextp) { 72 if((slashp = strchr(p, '/')) != nil) 73 nextp = slashp+1; 74 else 75 nextp = slashp = p+strlen(p); 76 77 nd = dbsearch(p, slashp-p, d->child, d->nchild); 78 if(nd >= d->child+d->nchild || strecmp(p, slashp, nd->name) != 0) 79 return nil; 80 d = nd; 81 } 82 return d; 83 } 84 85 /* 86 * Add the file ``name'' with attributes d to the 87 * directory ``root''. Name may contain multiple 88 * elements; all but the last must exist already. 89 * 90 * The child lists are kept sorted by utfname. 91 */ 92 Direc* 93 adddirec(Direc *root, char *name, XDir *d) 94 { 95 char *p; 96 Direc *nd; 97 int off; 98 99 if(name[0] == '/') 100 name++; 101 if((p = strrchr(name, '/')) != nil) { 102 *p = '\0'; 103 root = walkdirec(root, name); 104 if(root == nil) { 105 sysfatal("error in proto file: no entry for /%s but /%s/%s\n", name, name, p+1); 106 return nil; 107 } 108 *p = '/'; 109 p++; 110 } else 111 p = name; 112 113 nd = dbsearch(p, strlen(p), root->child, root->nchild); 114 off = nd - root->child; 115 if(off < root->nchild && strcmp(nd->name, p) == 0) { 116 if ((d->mode & DMDIR) == 0) 117 fprint(2, "warning: proto lists %s twice\n", name); 118 return nil; 119 } 120 121 if(root->nchild%Ndirblock == 0) { 122 root->child = erealloc(root->child, (root->nchild+Ndirblock)*sizeof(Direc)); 123 nd = root->child + off; 124 } 125 126 memmove(nd+1, nd, (root->nchild - off)*sizeof(Direc)); 127 mkdirec(nd, d); 128 nd->name = atom(p); 129 root->nchild++; 130 return nd; 131 } 132 133 /* 134 * Copy the tree src into dst. 135 */ 136 void 137 copydirec(Direc *dst, Direc *src) 138 { 139 int i, n; 140 141 *dst = *src; 142 143 if((src->mode & DMDIR) == 0) 144 return; 145 146 n = (src->nchild + Ndirblock - 1); 147 n -= n%Ndirblock; 148 dst->child = emalloc(n*sizeof(Direc)); 149 150 n = dst->nchild; 151 for(i=0; i<n; i++) 152 copydirec(&dst->child[i], &src->child[i]); 153 } 154 155 /* 156 * Turn the Dbadname flag on for any entries 157 * that have non-conforming names. 158 */ 159 static void 160 _checknames(Direc *d, int (*isbadname)(char*), int isroot) 161 { 162 int i; 163 164 if(!isroot && isbadname(d->name)) 165 d->flags |= Dbadname; 166 167 if(strcmp(d->name, "_conform.map") == 0) 168 d->flags |= Dbadname; 169 170 for(i=0; i<d->nchild; i++) 171 _checknames(&d->child[i], isbadname, 0); 172 } 173 174 void 175 checknames(Direc *d, int (*isbadname)(char*)) 176 { 177 _checknames(d, isbadname, 1); 178 } 179 180 /* 181 * Set the names to conform to 8.3 182 * by changing them to numbers. 183 * Plan 9 gets the right names from its 184 * own directory entry. 185 * 186 * We used to write a _conform.map file to translate 187 * names. Joliet should take care of most of the 188 * interoperability with other systems now. 189 */ 190 void 191 convertnames(Direc *d, char* (*cvt)(char*, char*)) 192 { 193 int i; 194 char new[1024]; 195 196 if(d->flags & Dbadname) 197 cvt(new, conform(d->name, d->mode & DMDIR)); 198 else 199 cvt(new, d->name); 200 d->confname = atom(new); 201 202 for(i=0; i<d->nchild; i++) 203 convertnames(&d->child[i], cvt); 204 } 205 206 /* 207 * Sort a directory with a given comparison function. 208 * After this is called on a tree, adddirec should not be, 209 * since the entries may no longer be sorted as adddirec expects. 210 */ 211 void 212 dsort(Direc *d, int (*cmp)(const void*, const void*)) 213 { 214 int i, n; 215 216 n = d->nchild; 217 qsort(d->child, n, sizeof(d[0]), cmp); 218 219 for(i=0; i<n; i++) 220 dsort(&d->child[i], cmp); 221 }