Exemple #1
0
HFSCatalogNodeID newFolder(const char* pathName, Volume* volume) {
  HFSPlusCatalogFolder* parentFolder;
  HFSPlusCatalogFolder folder;
  HFSPlusCatalogKey key;
  HFSPlusCatalogThread thread;
  
  uint32_t newFolderID;
  
  int threadLength;
  
  char* path;
  char* name;
  char* curChar;
  char* lastSeparator;
  
  path = strdup(pathName);
  
  curChar = path;
  lastSeparator = NULL;
  
  while((*curChar) != '\0') {
    if((*curChar) == '/')
      lastSeparator = curChar;
    curChar++;
  }
  
  if(lastSeparator == NULL) {
    parentFolder = (HFSPlusCatalogFolder*) getRecordFromPath("/", volume, NULL, NULL);
    name = path;
  } else {
    name = lastSeparator + 1;
    *lastSeparator = '\0';
    parentFolder = (HFSPlusCatalogFolder*) getRecordFromPath(path, volume, NULL, NULL);  
  }

  if(parentFolder == NULL || parentFolder->recordType != kHFSPlusFolderRecord) {
    free(path);
    free(parentFolder);
    return FALSE;
  }
  
  newFolderID = volume->volumeHeader->nextCatalogID++;
  volume->volumeHeader->folderCount++;
  
  folder.recordType = kHFSPlusFolderRecord;
  folder.flags = kHFSHasFolderCountMask;
  folder.valence = 0;
  folder.folderID = newFolderID;
  folder.createDate = UNIX_TO_APPLE_TIME(time(NULL));
  folder.contentModDate = folder.createDate;
  folder.attributeModDate = folder.createDate;
  folder.accessDate = folder.createDate;
  folder.backupDate = folder.createDate;
  folder.permissions.ownerID = parentFolder->permissions.ownerID;
  folder.permissions.groupID = parentFolder->permissions.groupID;
  folder.permissions.adminFlags = 0;
  folder.permissions.ownerFlags = 0;
  folder.permissions.fileMode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
  folder.permissions.special.iNodeNum = 0;
  memset(&folder.userInfo, 0, sizeof(folder.userInfo));
  memset(&folder.finderInfo, 0, sizeof(folder.finderInfo));
  folder.textEncoding = 0;
  folder.folderCount = 0;
  
  key.parentID = parentFolder->folderID;
  ASCIIToUnicode(name, &key.nodeName);
  key.keyLength = sizeof(key.parentID) + STR_SIZE(key.nodeName);
  
  thread.recordType = kHFSPlusFolderThreadRecord;
  thread.reserved = 0;
  thread.parentID = parentFolder->folderID;
  ASCIIToUnicode(name, &thread.nodeName);
  threadLength = sizeof(thread.recordType) + sizeof(thread.reserved) + sizeof(thread.parentID) + STR_SIZE(thread.nodeName);
  flipCatalogThread(&thread, TRUE);
  flipCatalogFolder(&folder);
  
  ASSERT(addToBTree(volume->catalogTree, (BTKey*)(&key), sizeof(HFSPlusCatalogFolder), (unsigned char *)(&folder)), "addToBTree");
  key.nodeName.length = 0;
  key.parentID = newFolderID;
  key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
  ASSERT(addToBTree(volume->catalogTree, (BTKey*)(&key), threadLength, (unsigned char *)(&thread)), "addToBTree");
  
  parentFolder->folderCount++;
  parentFolder->valence++;
  updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder);
  
  updateVolume(volume);
  
  free(parentFolder);
  free(path);
  
  return newFolderID;
}
Exemple #2
0
int move(const char* source, const char* dest, Volume* volume) {
  HFSPlusCatalogRecord* srcRec;
  HFSPlusCatalogFolder* srcFolderRec;
  HFSPlusCatalogFolder* destRec;
  char* destPath;
  char* destName;
  char* curChar;
  char* lastSeparator;
  
  int i;
  int threadLength;

  HFSPlusCatalogKey srcKey;
  HFSPlusCatalogKey destKey;
  HFSPlusCatalogThread* thread;
  
  srcRec = getRecordFromPath3(source, volume, NULL, &srcKey, TRUE, FALSE, kHFSRootFolderID);
  if(srcRec == NULL) {
    free(srcRec);
    return FALSE;
  }
  
  srcFolderRec = (HFSPlusCatalogFolder*) getRecordByCNID(srcKey.parentID, volume);
    
  if(srcFolderRec == NULL || srcFolderRec->recordType != kHFSPlusFolderRecord) {
    free(srcRec);
    free(srcFolderRec);
    return FALSE;
  }
    
  destPath = strdup(dest);
  
  curChar = destPath;
  lastSeparator = NULL;
  
  while((*curChar) != '\0') {
    if((*curChar) == '/')
      lastSeparator = curChar;
    curChar++;
  }
  
  if(lastSeparator == NULL) {
    destRec = (HFSPlusCatalogFolder*) getRecordFromPath("/", volume, NULL, NULL);
    destName = destPath;
  } else {
    destName = lastSeparator + 1;
    *lastSeparator = '\0';
    destRec = (HFSPlusCatalogFolder*) getRecordFromPath(destPath, volume, NULL, NULL);
    
    if(destRec == NULL || destRec->recordType != kHFSPlusFolderRecord) {
      free(destPath);
      free(srcRec);
      free(destRec);
      free(srcFolderRec);
      return FALSE;
    }
  }
  
  removeFromBTree(volume->catalogTree, (BTKey*)(&srcKey));
  
  srcKey.nodeName.length = 0;
  if(srcRec->recordType == kHFSPlusFolderRecord) {
    srcKey.parentID = ((HFSPlusCatalogFolder*)srcRec)->folderID;
  } else if(srcRec->recordType == kHFSPlusFileRecord) {
    srcKey.parentID = ((HFSPlusCatalogFile*)srcRec)->fileID;
  } else {
    /* unexpected */
    return FALSE;
  }
  srcKey.keyLength = sizeof(srcKey.parentID) + sizeof(srcKey.nodeName.length);
  
  removeFromBTree(volume->catalogTree, (BTKey*)(&srcKey));
  

  destKey.nodeName.length = strlen(destName);

  threadLength = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (sizeof(uint16_t) * destKey.nodeName.length);
  thread = (HFSPlusCatalogThread*) malloc(threadLength);
  thread->reserved = 0;
  destKey.parentID = destRec->folderID;
  thread->parentID = destKey.parentID;  
  thread->nodeName.length = destKey.nodeName.length;
  for(i = 0; i < destKey.nodeName.length; i++) {
    destKey.nodeName.unicode[i] = destName[i];
    thread->nodeName.unicode[i] = destName[i];
  }
  
  destKey.keyLength = sizeof(uint32_t) + sizeof(uint16_t) + (sizeof(uint16_t) * destKey.nodeName.length);
  
  switch(srcRec->recordType) {
    case kHFSPlusFolderRecord:
      thread->recordType = kHFSPlusFolderThreadRecord;
      flipCatalogFolder((HFSPlusCatalogFolder*)srcRec);
      addToBTree(volume->catalogTree, (BTKey*)(&destKey), sizeof(HFSPlusCatalogFolder), (unsigned char *)(srcRec));
      break;
      
    case kHFSPlusFileRecord:
      thread->recordType = kHFSPlusFileThreadRecord;
      flipCatalogFile((HFSPlusCatalogFile*)srcRec);
      addToBTree(volume->catalogTree, (BTKey*)(&destKey), sizeof(HFSPlusCatalogFile), (unsigned char *)(srcRec));
      break;
  }
  
  destKey.nodeName.length = 0;
  destKey.parentID = srcKey.parentID;
  destKey.keyLength = sizeof(destKey.parentID) + sizeof(destKey.nodeName.length);
  
  flipCatalogThread(thread, TRUE);
  addToBTree(volume->catalogTree, (BTKey*)(&destKey), threadLength, (unsigned char *)(thread));
    
  /* adjust valence */
  srcFolderRec->valence--;
  updateCatalog(volume, (HFSPlusCatalogRecord*) srcFolderRec);
  destRec->valence++;
  updateCatalog(volume, (HFSPlusCatalogRecord*) destRec);
  
  free(thread);
  free(destPath);
  free(srcRec);
  free(destRec);
  free(srcFolderRec);
      
  return TRUE;
}
Exemple #3
0
int removeFile(const char* fileName, Volume* volume) {
  HFSPlusCatalogRecord* record;
  HFSPlusCatalogKey key;
  io_func* io;
  HFSPlusCatalogFolder* parentFolder;

  record = getRecordFromPath3(fileName, volume, NULL, &key, TRUE, FALSE, kHFSRootFolderID);
  if(record != NULL) {
    parentFolder = (HFSPlusCatalogFolder*) getRecordByCNID(key.parentID, volume);
    if(parentFolder != NULL) {
	if(parentFolder->recordType != kHFSPlusFolderRecord) {
		ASSERT(FALSE, "parent not folder");
		free(parentFolder);
		return FALSE;
	}
    } else {
	ASSERT(FALSE, "can't find parent");
	return FALSE;
    }

    if(record->recordType == kHFSPlusFileRecord) {
      io = openRawFile(((HFSPlusCatalogFile*)record)->fileID, &((HFSPlusCatalogFile*)record)->dataFork, record, volume);
      allocate((RawFile*)io->data, 0);
      CLOSE(io);

      removeFromBTree(volume->catalogTree, (BTKey*)(&key));
      
      key.nodeName.length = 0;
      key.parentID = ((HFSPlusCatalogFile*)record)->fileID;
      key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
      removeFromBTree(volume->catalogTree, (BTKey*)(&key));
      
      volume->volumeHeader->fileCount--;
    } else {
      if(((HFSPlusCatalogFolder*)record)->valence > 0) {
		free(record);
		free(parentFolder);
		ASSERT(FALSE, "folder not empty");
        return FALSE;
      } else {
        removeFromBTree(volume->catalogTree, (BTKey*)(&key));
        
        key.nodeName.length = 0;
        key.parentID = ((HFSPlusCatalogFolder*)record)->folderID;
        key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length);
        removeFromBTree(volume->catalogTree, (BTKey*)(&key));
      }
      
	  parentFolder->folderCount--;
      volume->volumeHeader->folderCount--;
    }
    parentFolder->valence--;
    updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder);
    updateVolume(volume);

	free(record);
	free(parentFolder);
	
    return TRUE;
  } else {
	free(parentFolder);
	ASSERT(FALSE, "cannot find record");
    return FALSE;
  }
}
Exemple #4
0
int allocate(RawFile* rawFile, off_t size) {
	unsigned char* zeros;
	Volume* volume;
	HFSPlusForkData* forkData;
	uint32_t blocksNeeded;
	uint32_t blocksToAllocate;
	Extent* extent;
	Extent* lastExtent;

	uint32_t curBlock;

	volume = rawFile->volume;
	forkData = rawFile->forkData;
	extent = rawFile->extents;

	blocksNeeded = ((uint64_t)size / (uint64_t)volume->volumeHeader->blockSize) + (((size % volume->volumeHeader->blockSize) == 0) ? 0 : 1);

	if(blocksNeeded > forkData->totalBlocks) {
		zeros = (unsigned char*) malloc(volume->volumeHeader->blockSize);
		memset(zeros, 0, volume->volumeHeader->blockSize);

		blocksToAllocate = blocksNeeded - forkData->totalBlocks;

		if(blocksToAllocate > volume->volumeHeader->freeBlocks) {
			return FALSE;
		}

		lastExtent = NULL;
		while(extent != NULL) {
			lastExtent = extent;
			extent = extent->next;
		}

		if(lastExtent == NULL) {
			rawFile->extents = (Extent*) malloc(sizeof(Extent));
			lastExtent = rawFile->extents;
			lastExtent->blockCount = 0;
			lastExtent->next = NULL;
			curBlock = volume->volumeHeader->nextAllocation;
		} else {
			curBlock = lastExtent->startBlock + lastExtent->blockCount;
		}

		while(blocksToAllocate > 0) {
			if(isBlockUsed(volume, curBlock)) {
				if(lastExtent->blockCount > 0) {
					lastExtent->next = (Extent*) malloc(sizeof(Extent));
					lastExtent = lastExtent->next;
					lastExtent->blockCount = 0;
					lastExtent->next = NULL;
				}
				curBlock = volume->volumeHeader->nextAllocation;
				volume->volumeHeader->nextAllocation++;
				if(volume->volumeHeader->nextAllocation >= volume->volumeHeader->totalBlocks) {
					volume->volumeHeader->nextAllocation = 0;
				}
			} else {
				if(lastExtent->blockCount == 0) {
					lastExtent->startBlock = curBlock;
				}

				/* zero out allocated block */
				ASSERT(WRITE(volume->image, ((uint64_t)curBlock) * volume->volumeHeader->blockSize, volume->volumeHeader->blockSize, zeros), "WRITE");

				setBlockUsed(volume, curBlock, TRUE);
				volume->volumeHeader->freeBlocks--;
				blocksToAllocate--;
				curBlock++;
				lastExtent->blockCount++;

				if(curBlock >= volume->volumeHeader->totalBlocks) {
					curBlock = volume->volumeHeader->nextAllocation;
				}
			}
		}

		free(zeros);
	} else if(blocksNeeded < forkData->totalBlocks) {
		blocksToAllocate = blocksNeeded;

		lastExtent = NULL;

		while(blocksToAllocate > 0) {
			if(blocksToAllocate > extent->blockCount) {
				blocksToAllocate -= extent->blockCount;
				lastExtent = extent;
				extent = extent->next;
			} else {
				break;
			}
		}


		if(blocksToAllocate == 0 && lastExtent != NULL) {
			// snip the extent list here, since we don't need the rest
			lastExtent->next = NULL;
		} else if(blocksNeeded == 0) {
			rawFile->extents = NULL;
		}

		do {
			for(curBlock = (extent->startBlock + blocksToAllocate); curBlock < (extent->startBlock + extent->blockCount); curBlock++) {
				setBlockUsed(volume, curBlock, FALSE);
				volume->volumeHeader->freeBlocks++;
			}
			lastExtent = extent;
			extent = extent->next;

			if(blocksToAllocate == 0)
			{ 
				free(lastExtent);
			} else {
				lastExtent->next = NULL;
				lastExtent->blockCount = blocksToAllocate;
			}

			blocksToAllocate = 0;
		} while(extent != NULL);
	}

	writeExtents(rawFile);

	forkData->logicalSize = size;
	forkData->totalBlocks = blocksNeeded;

	updateVolume(rawFile->volume);

	if(rawFile->catalogRecord != NULL) {
		updateCatalog(rawFile->volume, rawFile->catalogRecord);
	}

	return TRUE;
}