/* vi:set tabstop=2 cindent shiftwidth=2: */ /* * libvxfs - library for reading Veritas Journaled FileSystem (VxFS) * Copyright (c) 1999 Martin Hinner * * dir.c: VxFS directory routines * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id$ */ #include #include #include #include static void filldir (VXDIR * dir, char *name, int namelen, int ino) { struct vxdirent *dirent; #if 1 /* XXX: Fixme! Why does vxopendir() pass sometimes NULL name ? */ if (namelen == 0) return ; #endif dirent = (struct vxdirent *) malloc (sizeof (struct vxdirent)); dirent->next = dir->first; memcpy (dirent->name, name, namelen>255?255:namelen); if (namelen>254) dirent->name[255] = 0; dirent->name[namelen] = 0; dirent->inode = ino; dir->first = dirent; if (vxdebug) printf ("filldir(name=%s);\n", dirent->name); } VXDIR * vxopendir (struct vxfs_inode *ino) { int i; void *block; struct vxfs_dirblk *dirblk; struct vxfs_direct *direct; VXDIR *dir; if (vxdebug) printf ("vxopendir()\n"); if (!VXFS_ISDIR (ino)) { if (vxverbose) fprintf (stderr, "Not a directory\n"); return 0; } dir = (VXDIR *) malloc (sizeof (VXDIR)); if (!dir) { if (vxverbose) fprintf (stderr, "vxreaddir: Not enough memory\n"); return 0; } dir->first = dir->current = 0; filldir (dir, "..", 2, ino->ftarea.dotdot); for (i = 0; i < (ino->size + vxbsize - 1) / vxbsize; i++) { block = vxiread (ino, i, 1); if (!block) { if (vxverbose) printf ("Unable to read blk\n"); continue; } dirblk = (struct vxfs_dirblk *) block; direct = (struct vxfs_direct *) ((char *) block + (2 * dirblk->nhash) + 4); while ((char *) direct <= (char *) block + (ino->size > vxbsize ? vxbsize : ino->size) && direct->reclen != 0 && (((char *)direct + direct->reclen) <= (char *) block + (ino->size > vxbsize ? vxbsize : ino->size))) { #if 0 printf("FILE=[%*.*s] %u [namelen=%u, reclen=%u]\n", direct->namelen,direct->namelen,direct->name, direct->ino,direct->namelen, direct->reclen); #endif if (direct->ino) filldir (dir, direct->name, direct->namelen, direct->ino); direct = (char *) direct + direct->reclen; } free (block); } dir->current = dir->first; return dir; } struct vxdirent * vxreaddir (VXDIR * dir) { if (!dir->current) return 0; return dir->current = dir->current->next; } void vxrewinddir (VXDIR * dir) { dir->current = dir->first; } int vxclosedir (VXDIR * dir) { struct vxdirent *dirent; if (!dir) return 0; while (dir->current != NULL) { dirent = dir->current; dir->current = dirent->next; free (dirent); } free (dir); return 0; } int vxlookup (const char *filename) { VXDIR *dir; char *origname, *name, *str, c; struct vxdirent *dirent; int ino; int found; struct vxfs_inode *inode; char *symlink; char *symlinkpath; if (vxdebug) printf ("vxlookup(filename=\"%s\");\n", filename); name = strdup (filename); origname = name; ino = 2; while (*name) { while (*name == '/') name++; str = name; while (*str != '/' && *str) str++; c = *str; *str = 0; if (!strcmp (name, "") || !strcmp (name, ".")) { *str = c; name = str; continue; } inode = vxiget (ino); if (!inode) { if (vxverbose) fprintf (stderr, "vxlookup: Unable to get inode %u\n", ino); free (origname); return -1; } dir = vxopendir (inode); if (!dir) { if (vxverbose) fprintf (stderr, "vxlookup: Unable to get open directory %s\n", origname); free (origname); return -1; } found = 0; while ((dirent = vxreaddir (dir)) != NULL) { if (!strcmp (dirent->name, name)) { ino = dirent->inode; found = 1; break; } } vxclosedir (dir); vxiput (inode); if (!found) { free (origname); return -1; } *str = c; /* Find symlink inode */ inode = vxiget(ino); if (VXFS_ISLNK(inode)) { symlink = vxiread(inode,0,inode->blocks>0?inode->blocks:1); if (symlink == 0) { if (vxverbose) fprintf (stderr, "vxlookup: Broken symlink\n"); return -1; } symlink[inode->size] = 0; vxiput(inode); if (symlink[0] == '/' || /* Absolute symlink */ name == origname /* We are in root directory */ ) { symlinkpath = strdup(symlink); }else { c = *(name-1); *(name-1) = 0; symlinkpath = (char *)malloc(strlen(symlink) + strlen(origname) + 2); if (!symlinkpath) { if (vxverbose) fprintf(stderr, "vxlookup: Error allocating space for symlink\n"); return -1; } strcpy(symlinkpath,origname); *(name-1) = c; strcat(symlinkpath,"/"); strcat(symlinkpath,symlink); } ino = vxlookup(symlinkpath); if (ino < 0) { if (vxverbose) fprintf (stderr, "vxlookup: Broken symlink %s\n", symlink); free(symlink); free(symlinkpath); return -1; } } name = str; } free (origname); return ino; }