]> git.saurik.com Git - apple/boot.git/blobdiff - i386/libsaio/ufs.c
boot-132.tar.gz
[apple/boot.git] / i386 / libsaio / ufs.c
index 059a133b5d1cda3d5a89fa567063261dc04a2976..ec8c060b1cc1e760b81929991fa491393641f7e7 100644 (file)
@@ -1,10 +1,10 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * The contents of this file constitute Original Code as defined in and
- * are subject to the Apple Public Source License Version 1.1 (the
+ * are subject to the Apple Public Source License Version 2.0 (the
  * "License").  You may not use this file except in compliance with the
  * License.  Please obtain a copy of the License at
  * http://www.apple.com/publicsource and read it before using this file.
 
 #include <sl.h>
 
+#include "ufs.h"
 #include "ufs_byteorder.h"
 
+#if !defined(MAXNAMLEN) && defined(UFSMAXNAMLEN)
+#define MAXNAMLEN UFSMAXNAMLEN
+#endif
+
 typedef struct dinode Inode, *InodePtr;
 
 // Private function prototypes
@@ -46,18 +51,21 @@ static long FindFileInDir(char *fileName, long *flags,
                           InodePtr fileInode, InodePtr dirInode);
 static char *ReadFileBlock(InodePtr fileInode, long fragNum, long blockOffset,
                            long length, char *buffer, long cache);
-static long ReadFile(InodePtr fileInode, long *length);
+static long ReadFile(InodePtr fileInode, unsigned long *length, void *base, long offset);
 
 #define kDevBlockSize (0x200)    // Size of each disk block.
-#define kDiskLableBlock (15)     // Block the DL is in.
+#define kDiskLabelBlock (15)     // Block the DL is in.
 
 #ifdef __i386__
 
 static CICell    gCurrentIH;
 static long long gPartitionBase;
-static char      *gDLBuf;
+static char      *gULBuf;
 static char      *gFSBuf;
 static struct fs *gFS;
+#if !BOOT1
+static struct ufslabel  gUFSLabel;   // for UUID
+#endif
 static long      gBlockSize;
 static long      gFragSize;
 static long      gFragsPerBlock;
@@ -74,6 +82,9 @@ static long long gPartitionBase;
 static char      gDLBuf[8192];
 static char      gFSBuf[SBSIZE];
 static struct fs *gFS;
+#if !BOOT1
+static struct ufslabel  gUFSLabel;   // for UUID
+#endif
 static long      gBlockSize;
 static long      gFragSize;
 static long      gFragsPerBlock;
@@ -91,6 +102,10 @@ static InodePtr  gFileInodePtr = &_gFileInode;
 
 long UFSInitPartition( CICell ih )
 {
+#if !BOOT1
+    long ret;
+#endif
+
     if (ih == gCurrentIH) {
 #ifdef __i386__
         CacheInit(ih, gBlockSize);
@@ -98,24 +113,36 @@ long UFSInitPartition( CICell ih )
         return 0;
     }
 
+#if !BOOT1
     verbose("UFSInitPartition: %x\n", ih);
+#endif
 
     gCurrentIH = 0;
 
 #ifdef __i386__
-    if (!gDLBuf) gDLBuf = (char *) malloc(8192);
+    if (!gULBuf) gULBuf = (char *) malloc(UFS_LABEL_SIZE);
     if (!gFSBuf) gFSBuf = (char *) malloc(SBSIZE);
     if (!gTempName) gTempName = (char *) malloc(MAXNAMLEN + 1);
     if (!gTempName2) gTempName2 = (char *) malloc(MAXNAMLEN + 1);
     if (!gRootInodePtr) gRootInodePtr = (InodePtr) malloc(sizeof(Inode));
     if (!gFileInodePtr) gFileInodePtr = (InodePtr) malloc(sizeof(Inode));
-    if (!gDLBuf || !gFSBuf || !gTempName || !gTempName2 ||
+    if (!gULBuf || !gFSBuf || !gTempName || !gTempName2 ||
         !gRootInodePtr || !gFileInodePtr) return -1;
 #endif
 
     // Assume there is no Disk Label
     gPartitionBase = 0;
 
+#if !BOOT1
+    // read the disk label to get the UUID
+    // (rumor has it that UFS headers can be either-endian on disk; hopefully
+    // that isn't true for this UUID field).
+    Seek(ih, gPartitionBase + UFS_LABEL_OFFSET);
+    ret = Read(ih, (long)&gUFSLabel, UFS_LABEL_SIZE);
+    if(ret != 0)
+        bzero(&gUFSLabel, UFS_LABEL_SIZE);
+#endif /* !BOOT1 */
+
     // Look for the Super Block
     Seek(ih, gPartitionBase + SBOFF);
     Read(ih, (long)gFSBuf, SBSIZE);
@@ -124,37 +151,7 @@ long UFSInitPartition( CICell ih )
     byte_swap_superblock(gFS);
 
     if (gFS->fs_magic != FS_MAGIC) {
-#ifdef __i386__
-        return -1;  // not yet for Intel
-#else  /* !__i386__ */
-        disk_label_t *dl;
-        partition_t  *part;
-
-        // Did not find it... Look for the Disk Label.
-        // Look for the Disk Label
-        Seek(ih, 1ULL * kDevBlockSize * kDiskLableBlock);
-        Read(ih, (long)gDLBuf, 8192);
-    
-        dl = (disk_label_t *)gDLBuf;
-        byte_swap_disklabel_in(dl);
-    
-        if (dl->dl_version != DL_VERSION) {
-            return -1;
-        }
-    
-        part = &dl->dl_part[0];
-        gPartitionBase = (1ULL * (dl->dl_front + part->p_base) * dl->dl_secsize) -
-                         (1ULL * (dl->dl_label_blkno - kDiskLableBlock) * kDevBlockSize);
-    
-        // Re-read the Super Block.
-        Seek(ih, gPartitionBase + SBOFF);
-        Read(ih, (long)gFSBuf, SBSIZE);
-
-        gFS = (struct fs *)gFSBuf;
-        if (gFS->fs_magic != FS_MAGIC) {
-            return -1;
-        }
-#endif /* !__i386__ */
+        return -1;
     }
 
     // Calculate the block size and set up the block cache.
@@ -173,13 +170,34 @@ long UFSInitPartition( CICell ih )
     return 0;
 }
 
+#if !BOOT1
+
+long UFSGetUUID(CICell ih, char *uuidStr)
+{
+  long long uuid = gUFSLabel.ul_uuid;
+
+  if (UFSInitPartition(ih) == -1) return -1;
+  if (uuid == 0LL)  return -1;
+
+  return CreateUUIDString((uint8_t*)(&uuid), sizeof(uuid), uuidStr);
+}
+
+#endif /* !BOOT1 */
+
 long UFSLoadFile( CICell ih, char * filePath )
 {
-    long ret, length, flags;
+    return UFSReadFile(ih, filePath, (void *)gFSLoadAddress, 0, 0);
+}
 
-    if (UFSInitPartition(ih) == -1) return -1;
+long UFSReadFile( CICell ih, char * filePath, void * base, unsigned long offset, unsigned long length )
+{
+    long ret, flags;
 
+#if !BOOT1
     verbose("Loading UFS file: [%s] from %x.\n", filePath, (unsigned)ih);
+#endif
+
+    if (UFSInitPartition(ih) == -1) return -1;
 
     // Skip one or two leading '/'.
     if (*filePath == '/') filePath++;
@@ -188,26 +206,25 @@ long UFSLoadFile( CICell ih, char * filePath )
     ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
     if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
 
-#if 0
-    // System.config/Default.table will fail this check.
-    // Turn this back on when usage of System.config is deprecated.
-    if (flags & (kOwnerNotRoot | kPermGroupWrite | kPermOtherWrite)) return -1;
-#endif
-
-    ret = ReadFile(gFileInodePtr, &length);
+    ret = ReadFile(gFileInodePtr, &length, base, offset);
     if (ret == -1) return -1;
     
     return length;
 }
 
+#ifndef BOOT1
+
 long UFSGetDirEntry( CICell ih, char * dirPath, long * dirIndex,
-                     char ** name, long * flags, long * time )
+                     char ** name, long * flags, long * time,
+                     FinderInfo * finderInfo, long * infoValid)
 {
     long  ret, fileInodeNum, dirFlags;
     Inode tmpInode;
 
     if (UFSInitPartition(ih) == -1) return -1;
 
+    if (infoValid) *infoValid = 0;
+
     // Skip a leading '/' if present
     if (*dirPath == '/') dirPath++;
     if (*dirPath == '/') dirPath++;
@@ -224,6 +241,52 @@ long UFSGetDirEntry( CICell ih, char * dirPath, long * dirIndex,
     return 0;
 }
 
+void
+UFSGetDescription(CICell ih, char *str, long strMaxLen)
+{
+    if (UFSInitPartition(ih) == -1) { return; }
+
+    struct ufslabel *ul;
+
+    // Look for the Disk Label
+    Seek(ih, 1ULL * UFS_LABEL_OFFSET);
+    Read(ih, (long)gULBuf, UFS_LABEL_SIZE);
+    
+    ul = (struct ufslabel *)gULBuf;
+    
+    unsigned char magic_bytes[] = UFS_LABEL_MAGIC;
+    int i;
+    unsigned char *p = (unsigned char *)&ul->ul_magic;
+    
+    for (i=0; i<sizeof(magic_bytes); i++, p++) {
+        if (*p != magic_bytes[i])
+            return;
+    }
+    strncpy(str, (const char *)ul->ul_name, strMaxLen);
+}
+
+long
+UFSGetFileBlock(CICell ih, char *filePath, unsigned long long *firstBlock)
+{
+    long ret, flags;
+
+    if (UFSInitPartition(ih) == -1) return -1;
+
+    // Skip one or two leading '/'.
+    if (*filePath == '/') filePath++;
+    if (*filePath == '/') filePath++;
+
+    ret = ResolvePathToInode(filePath, &flags, gFileInodePtr, gRootInodePtr);
+    if ((ret == -1) || ((flags & kFileTypeMask) != kFileTypeFlat)) return -1;
+
+    *firstBlock = (gPartitionBase + 1ULL * gFileInodePtr->di_db[0] * gBlockSize) / 512ULL;
+
+    return 0;
+}
+
+
+#endif /* !BOOT1 */
+
 // Private functions
 
 static char * ReadBlock( long fragNum, long blockOffset, long length,
@@ -292,7 +355,7 @@ static long ResolvePathToInode( char * filePath, long * flags,
     // Copy the file name to gTempName
     cnt = 0;
     while ((filePath[cnt] != '/') && (filePath[cnt] != '\0')) cnt++;
-    strncpy(gTempName, filePath, cnt);
+    strlcpy(gTempName, filePath, cnt+1);
 
     // Move restPath to the right place.
     if (filePath[cnt] != '\0') cnt++;
@@ -338,7 +401,7 @@ static long ReadDirEntry( InodePtr dirInode, long * fileInodeNum,
     }
 
     *fileInodeNum = dir->d_ino;
-    *name = strncpy(gTempName2, dir->d_name, dir->d_namlen);
+    *name = strlcpy(gTempName2, dir->d_name, dir->d_namlen+1);
 
     return 0;
 }
@@ -418,29 +481,41 @@ static char * ReadFileBlock( InodePtr fileInode, long fragNum, long blockOffset,
     return buffer;
 }
 
-static long ReadFile( InodePtr fileInode, long * length )
+static long ReadFile( InodePtr fileInode, unsigned long * length, void * base, long offset )
 {
-    long bytesLeft, curSize, curFrag = 0;
-    char *buffer, *curAddr = (char *)kLoadAddr;
+    long bytesLeft, curSize, curFrag;
+    char *buffer, *curAddr = (char *)base;
 
-#ifdef __i386__
-    curAddr = gFSLoadAddress;
-#endif
+    bytesLeft = fileInode->di_size;
+
+    if (offset > bytesLeft) {
+        printf("Offset is too large.\n");
+        return -1;
+    }
 
-    bytesLeft = *length = fileInode->di_size;
+    if ((*length == 0) || ((offset + *length) > bytesLeft)) {
+        *length = bytesLeft - offset;
+    }
 
-    if (*length > kLoadSize) {
+    if (bytesLeft > kLoadSize) {
         printf("File is too large.\n");
         return -1;
     }
 
+    bytesLeft = *length;
+    curFrag = (offset / gBlockSize) * gFragsPerBlock;
+    offset %= gBlockSize;
+
     while (bytesLeft) {
-        if (bytesLeft > gBlockSize) curSize = gBlockSize;
-        else curSize = bytesLeft;
+        curSize = gBlockSize;
+        if (curSize > bytesLeft) curSize = bytesLeft;
+        if ((offset + curSize) > gBlockSize) curSize = (gBlockSize - offset);
 
-        buffer = ReadFileBlock(fileInode, curFrag, 0, curSize, curAddr, 0);
+        buffer = ReadFileBlock(fileInode, curFrag, offset, curSize, curAddr, 0);
         if (buffer == 0) break;
 
+        if (offset != 0) offset = 0;
+
         curFrag += gFragsPerBlock;
         curAddr += curSize;
         bytesLeft -= curSize;