static int ioctl2AddSub(hdd_file_slot_t *fileSlot, char *argp) { int rv; u32 device=fileSlot->f->unit; apa_params_t params; u32 emptyBlocks[32]; apa_cache_t *clink; u32 sector=0; u32 length; if(!(fileSlot->f->mode & O_WRONLY)) return -EACCES; if(!(fileSlot->nsub < APA_MAXSUB)) return -EFBIG; memset(¶ms, 0, sizeof(apa_params_t)); if((rv=fioPartitionSizeLookUp(argp)) < 0) return rv; params.size=rv; params.flags=APA_FLAG_SUB; params.type=fileSlot->type; params.main=fileSlot->parts[0].start; params.number=fileSlot->nsub+1; if((rv=hddCheckPartitionMax(device, params.size)) < 0) return rv; // walk all looking for any empty blocks memset(&emptyBlocks, 0, sizeof(emptyBlocks)); clink=apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &rv); while(clink){ sector=clink->sector; apaAddEmptyBlock(clink->header, emptyBlocks); clink=apaGetNextHeader(clink, &rv); } if(rv!=0) return rv; if(!(clink=hddAddPartitionHere(device, ¶ms, emptyBlocks, sector, &rv))) return rv; sector=clink->header->start; length=clink->header->length; apaCacheFree(clink); if(!(clink=apaCacheGetHeader(device, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv))) return rv; clink->header->subs[clink->header->nsub].start=sector; clink->header->subs[clink->header->nsub].length=length; clink->header->nsub++; fileSlot->nsub++; fileSlot->parts[fileSlot->nsub].start=sector; fileSlot->parts[fileSlot->nsub].length=length; clink->flags|=APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); apaCacheFree(clink); return rv; }
apa_cache_t *apaInsertPartition(s32 device, const apa_params_t *params, u32 sector, int *err) { // Adds a new partition using an empty block. apa_cache_t *clink_empty; apa_cache_t *clink_this; apa_cache_t *clink_next; if ((clink_this = apaCacheGetHeader(device, sector, APA_IO_MODE_READ, err)) == 0) return 0; while (clink_this->header->length != params->size) { if ((clink_next = apaCacheGetHeader(device, clink_this->header->next, APA_IO_MODE_READ, err)) == NULL) { // Get next partition apaCacheFree(clink_this); return 0; } clink_this->header->length >>= 1; clink_empty = apaRemovePartition(device, (clink_this->header->start + clink_this->header->length), clink_this->header->next, clink_this->header->start, clink_this->header->length); clink_this->header->next = clink_empty->header->start; clink_this->flags |= APA_CACHE_FLAG_DIRTY; clink_next->header->prev = clink_empty->header->start; clink_next->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); apaCacheFree(clink_empty); apaCacheFree(clink_next); } apaCacheFree(clink_this); clink_this = apaFillHeader(device, params, clink_this->header->start, clink_this->header->next, clink_this->header->prev, params->size, err); apaCacheFlushAllDirty(device); return clink_this; }
static int ioctl2DeleteLastSub(hdd_file_slot_t *fileSlot) { int rv; u32 device=fileSlot->f->unit; apa_cache_t *mainPart; apa_cache_t *subPart; if(!(fileSlot->f->mode & O_WRONLY)) return -EACCES; if(fileSlot->nsub==0) return -ENOENT; if(!(mainPart=apaCacheGetHeader(device, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv))) return rv; if((subPart=apaCacheGetHeader(device, mainPart->header->subs[mainPart->header->nsub-1].start, APA_IO_MODE_READ, &rv))) { fileSlot->nsub--; mainPart->header->nsub--; mainPart->flags|=APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); rv=apaDelete(subPart); } apaCacheFree(mainPart); return rv; }
int hddDread(iop_file_t *f, iox_dirent_t *dirent) { int rv; hdd_file_slot_t *fileSlot=f->privdata; apa_cache_t *clink; if(!(f->mode & O_DIROPEN)) return -ENOTDIR; if(fileSlot->parts[0].start==-1) return 0;// end :) WaitSema(fioSema); if((clink=apaCacheGetHeader(f->unit, fileSlot->parts[0].start, APA_IO_MODE_READ, &rv)) && clink->header->length) { if(clink->header->flags & APA_FLAG_SUB) { // if sub get id from main header... apa_cache_t *cmain=apaCacheGetHeader(f->unit, clink->header->main, APA_IO_MODE_READ, &rv); if(cmain!=NULL){ /* This was the SONY original, which didn't do bounds-checking: rv=strlen(cmain->header->id); strcpy(dirent->name, cmain->header->id); */ strncpy(dirent->name, cmain->header->id, APA_IDMAX); dirent->name[APA_IDMAX] = '\0'; rv=strlen(dirent->name); apaCacheFree(cmain); } } else { /* This was the SONY original, which didn't do bounds-checking: rv=strlen(clink->header->id); strcpy(dirent->name, clink->header->id); */ strncpy(dirent->name, clink->header->id, APA_IDMAX); dirent->name[APA_IDMAX] = '\0'; rv=strlen(dirent->name); } fioGetStatFiller(clink, &dirent->stat); if(clink->header->next==0) fileSlot->parts[0].start=-1; // mark end else fileSlot->parts[0].start=clink->header->next;// set next apaCacheFree(clink); } SignalSema(fioSema); return rv; }
apa_cache_t *apaFillHeader(s32 device, const apa_params_t *params, u32 start, u32 next, u32 prev, u32 length, int *err) { // used for making a new partition apa_cache_t *clink; if (!(clink = apaCacheGetHeader(device, start, APA_IO_MODE_WRITE, err))) return NULL; memset(clink->header, 0, sizeof(apa_header_t)); clink->header->magic = APA_MAGIC; clink->header->start = start; clink->header->next = next; clink->header->prev = prev; clink->header->length = length; clink->header->type = params->type; clink->header->flags = params->flags; clink->header->modver = APA_MODVER; memcpy(clink->header->id, params->id, APA_IDMAX); if (params->flags & APA_FLAG_SUB) { clink->header->main = params->main; clink->header->number = params->number; } else { if (strncmp(clink->header->id, "_tmp", APA_IDMAX) != 0) { memcpy(clink->header->rpwd, params->rpwd, APA_PASSMAX); memcpy(clink->header->fpwd, params->fpwd, APA_PASSMAX); } } apaGetTime(&clink->header->created); clink->flags |= APA_CACHE_FLAG_DIRTY; return clink; }
int apaGetPartErrorName(s32 device, char *name) { u32 lba; int rv = 0; apa_cache_t *clink; if ((rv = apaGetPartErrorSector(device, APA_SECTOR_PART_ERROR, &lba)) <= 0) return rv; if (!(clink = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &rv))) return rv; while (clink) { if (clink->header->type != APA_TYPE_FREE && !(clink->header->flags & APA_CACHE_FLAG_DIRTY) && clink->header->start == lba) { if (name) { strncpy(name, clink->header->id, APA_IDMAX - 1); name[APA_IDMAX - 1] = '\0'; } apaCacheFree(clink); return 1; } clink = apaGetNextHeader(clink, &rv); } // clear error if no errors and partitions was not found... if (rv == 0) apaSetPartErrorSector(device, 0); return rv; }
int apaDelete(apa_cache_t *clink) { int rv = 0; apa_cache_t *clink_mbr; u32 device = clink->device; u32 start = clink->header->start; int i; if (!start) { apaCacheFree(clink); return -EACCES; } if (clink->header->next == 0) { if ((clink_mbr = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &rv)) == NULL) { apaCacheFree(clink); return rv; } do { apaCacheFree(clink); if ((clink = apaCacheGetHeader(clink->device, clink->header->prev, APA_IO_MODE_READ, &rv)) == NULL) return 0; clink->header->next = 0; clink->flags |= APA_CACHE_FLAG_DIRTY; clink_mbr->header->prev = clink->header->start; clink_mbr->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); } while (clink->header->type == 0); apaCacheFree(clink_mbr); } else { u32 length = clink->header->length; for (i = 0; i < 2; i++) { if ((clink = apaDeleteFixPrev(clink, &rv)) == NULL) return 0; if ((clink = apaDeleteFixNext(clink, &rv)) == NULL) return 0; } if (clink->header->start == start && clink->header->length == length) { apaMakeEmpty(clink); apaCacheFlushAllDirty(clink->device); } } apaCacheFree(clink); return rv; }
apa_cache_t *apaDeleteFixNext(apa_cache_t *clink, int *err) { apa_header_t *header = clink->header; u32 length = header->length; u32 saved_length = header->length; u32 lnext = header->next; apa_cache_t *clink1; apa_cache_t *clink2; u32 device = clink->device; u32 tmp; while (lnext != 0) { if (!(clink1 = apaCacheGetHeader(device, lnext, APA_IO_MODE_READ, err))) { apaCacheFree(clink); return 0; } header = clink1->header; tmp = header->length + length; if (header->type != 0) { apaCacheFree(clink1); break; } if ((clink->header->start % tmp) != 0 || ((tmp - 1) & tmp)) { apaCacheFree(clink1); break; } length = tmp; apaCacheFree(clink1); lnext = header->next; } if (length != saved_length) { if (!(clink2 = apaCacheGetHeader(device, lnext, APA_IO_MODE_READ, err))) { apaCacheFree(clink); return NULL; } clink->header->length = length; clink->header->next = lnext; apaMakeEmpty(clink); clink2->header->prev = clink->header->start; clink2->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); apaCacheFree(clink2); } return clink; }
static int apaOpen(s32 device, hdd_file_slot_t *fileSlot, apa_params_t *params, int mode) { int rv=0; u32 emptyBlocks[32]; apa_cache_t *clink; apa_cache_t *clink2; u32 sector=0; // walk all looking for any empty blocks & look for partition clink=apaCacheGetHeader(device, 0, APA_IO_MODE_READ, &rv); memset(&emptyBlocks, 0, sizeof(emptyBlocks)); while(clink) { sector=clink->sector; if(!(clink->header->flags & APA_FLAG_SUB)) { if(memcmp(clink->header->id, params->id, APA_IDMAX) == 0) break; // found :) } apaAddEmptyBlock(clink->header, emptyBlocks); clink=apaGetNextHeader(clink, &rv); } if(rv!=0) return rv; rv=-ENOENT; if(clink==NULL && (mode & O_CREAT)) { if((rv=hddCheckPartitionMax(device, params->size))>=0) { if((clink=hddAddPartitionHere(device, params, emptyBlocks, sector, &rv))!=NULL) { sector=clink->header->start; clink2=apaCacheAlloc(); memset(clink2->header, 0, sizeof(apa_header_t)); ata_device_sector_io(device, clink2->header, sector+8 , 2, ATA_DIR_WRITE); ata_device_sector_io(device, clink2->header, sector+0x2000, 2, ATA_DIR_WRITE); apaCacheFree(clink2); } } } if(clink==NULL) return rv; fileSlot->parts[0].start=clink->header->start; fileSlot->parts[0].length=clink->header->length; memcpy(&fileSlot->parts[1], &clink->header->subs, APA_MAXSUB*sizeof(apa_sub_t)); fileSlot->type=clink->header->type; fileSlot->nsub=clink->header->nsub; memcpy(&fileSlot->id, &clink->header->id, APA_IDMAX); apaCacheFree(clink); if(apaPassCmp(clink->header->fpwd, params->fpwd)!=0) { rv = (!(mode & O_WRONLY)) ? apaPassCmp(clink->header->rpwd, params->rpwd) : -EACCES; } else rv = 0; return rv; }
apa_cache_t *apaDeleteFixPrev(apa_cache_t *clink, int *err) { apa_cache_t *clink2 = clink; apa_header_t *header = clink2->header; u32 device = clink->device; u32 length = clink->header->length; u32 saved_next = clink->header->next; u32 saved_length = clink->header->length; u32 tmp; while (header->start) { if (!(clink2 = apaCacheGetHeader(device, header->prev, APA_IO_MODE_READ, err))) { apaCacheFree(clink); return NULL; } header = clink2->header; tmp = header->length + length; if (header->type != 0) { apaCacheFree(clink2); break; } if ((header->start % tmp) || (tmp & (tmp - 1))) { apaCacheFree(clink2); break; } length = tmp; apaCacheFree(clink); clink = clink2; } if (length != saved_length) { if (!(clink2 = apaCacheGetHeader(device, saved_next, APA_IO_MODE_READ, err))) { apaCacheFree(clink); return NULL; } clink->header->length = length; clink->header->next = clink->header->start + length; clink2->header->prev = clink->header->start; clink2->flags |= APA_CACHE_FLAG_DIRTY; clink->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); apaCacheFree(clink2); } return clink; }
static int devctlSetOsdMBR(s32 device, hddSetOsdMBR_t *mbrInfo) { int rv; apa_cache_t *clink; if(!(clink=apaCacheGetHeader(device, APA_SECTOR_MBR, APA_IO_MODE_READ, &rv))) return rv; APA_PRINTF( APA_DRV_NAME": mbr start: %ld\n" APA_DRV_NAME": mbr size : %ld\n", mbrInfo->start, mbrInfo->size); clink->header->mbr.osdStart=mbrInfo->start; clink->header->mbr.osdSize=mbrInfo->size; clink->flags|=APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); apaCacheFree(clink); return rv; }
apa_cache_t *apaRemovePartition(s32 device, u32 start, u32 next, u32 prev, u32 length) { apa_cache_t *clink; int err; if ((clink = apaCacheGetHeader(device, start, APA_IO_MODE_WRITE, &err)) == NULL) return NULL; memset(clink->header, 0, sizeof(apa_header_t)); clink->header->magic = APA_MAGIC; clink->header->start = start; clink->header->next = next; clink->header->prev = prev; clink->header->length = length; strcpy(clink->header->id, "__empty"); apaGetTime(&clink->header->created); clink->flags |= APA_CACHE_FLAG_DIRTY; return clink; }
apa_cache_t *apaGetNextHeader(apa_cache_t *clink, int *err) { u32 start = clink->header->start; apaCacheFree(clink); if (!clink->header->next) return NULL; if (!(clink = apaCacheGetHeader(clink->device, clink->header->next, APA_IO_MODE_READ, err))) return NULL; if (start != clink->header->prev) { APA_PRINTF(APA_DRV_NAME ": Warning: Invalid partition information. start != prev\n"); clink->header->prev = start; clink->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(clink->device); } return clink; }
static int apaRemove(s32 device, const char *id, const char *fpwd) { u32 nsub; apa_cache_t *clink; apa_cache_t *clink2; int rv, i; for(i=0;i<apaMaxOpen;i++) // look to see if open { if(hddFileSlots[i].f!=0) { if(memcmp(hddFileSlots[i].id, id, APA_IDMAX)==0) return -EBUSY; } } if(id[0]=='_' && id[1]=='_') return -EACCES; if((clink=apaFindPartition(device, id, &rv))==NULL) return rv; if(apaPassCmp(clink->header->fpwd, fpwd)) { apaCacheFree(clink); return -EACCES; } // remove all subs frist... nsub=clink->header->nsub; clink->header->nsub=0; clink->flags|=APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); for(i=nsub-1;i!=-1;i--) { if((clink2=apaCacheGetHeader(device, clink->header->subs[i].start, APA_IO_MODE_READ, &rv))){ if((rv=apaDelete(clink2))){ apaCacheFree(clink); return rv; } } } if(rv==0) return apaDelete(clink); apaCacheFree(clink); return rv; }
apa_cache_t *apaFindPartition(s32 device, const char *id, int *err) { apa_cache_t *clink; clink = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, err); while (clink) { if (!(clink->header->flags & APA_FLAG_SUB)) { if (memcmp(clink->header->id, id, APA_IDMAX) == 0) return clink; // found } clink = apaGetNextHeader(clink, (int *)err); } if (*err == 0) { *err = -ENOENT; return NULL; //return (apa_cache_t *)-ENOENT; // <-- BUG code tests for NULL only } *err = 0; return NULL; }
apa_cache_t *hddAddPartitionHere(s32 device, const apa_params_t *params, u32 *emptyBlocks, u32 sector, int *err) { apa_cache_t *clink_this; apa_cache_t *clink_next; apa_cache_t *clink_new; apa_header_t *header; u32 i; u32 tmp, some_size, part_end; u32 tempSize; // walk empty blocks in case can use one :) for (i = 0; i < 32; i++) { if ((u32)(1 << i) >= params->size && emptyBlocks[i] != 0) return apaInsertPartition(device, params, emptyBlocks[i], err); } clink_this = apaCacheGetHeader(device, sector, APA_IO_MODE_READ, err); header = clink_this->header; part_end = header->start + header->length; some_size = (part_end % params->size); tmp = some_size ? params->size - some_size : 0; if (hddDevices[device].totalLBA < (part_end + params->size + tmp) //Non-SONY: when dealing with large disks, this check may overflow (therefore, check for overflows!). || (part_end < sector)) { *err = -ENOSPC; apaCacheFree(clink_this); return NULL; } if ((clink_next = apaCacheGetHeader(device, 0, APA_IO_MODE_READ, err)) == NULL) { apaCacheFree(clink_this); return NULL; } tempSize = params->size; while (part_end % params->size) { tempSize = params->size >> 1; while (0x3FFFF < tempSize) { if (!(part_end % tempSize)) { clink_new = apaRemovePartition(device, part_end, 0, clink_this->header->start, tempSize); clink_this->header->next = part_end; clink_this->flags |= APA_CACHE_FLAG_DIRTY; clink_next->header->prev = clink_new->header->start; part_end += tempSize; clink_next->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); apaCacheFree(clink_this); clink_this = clink_new; break; } tempSize >>= 1; } } if ((clink_new = apaFillHeader(device, params, part_end, 0, clink_this->header->start, params->size, err)) != NULL) { clink_this->header->next = part_end; clink_this->flags |= APA_CACHE_FLAG_DIRTY; clink_next->header->prev = clink_new->header->start; clink_next->flags |= APA_CACHE_FLAG_DIRTY; apaCacheFlushAllDirty(device); } apaCacheFree(clink_this); apaCacheFree(clink_next); return clink_new; }
int hddFormat(iop_file_t *f, const char *dev, const char *blockdev, void *arg, int arglen) { int rv=0; apa_cache_t *clink; u32 i; #ifdef APA_FORMAT_MAKE_PARTITIONS apa_params_t params; u32 emptyBlocks[32]; #endif if(f->unit >= 2) return -ENXIO; // clear all errors on hdd clink=apaCacheAlloc(); memset(clink->header, 0, sizeof(apa_header_t)); if(ata_device_sector_io(f->unit, clink->header, APA_SECTOR_SECTOR_ERROR, 1, ATA_DIR_WRITE)){ apaCacheFree(clink); return -EIO; } if(ata_device_sector_io(f->unit, clink->header, APA_SECTOR_PART_ERROR, 1, ATA_DIR_WRITE)){ apaCacheFree(clink); return -EIO; } // clear apa headers for(i=1024*8;i<hddDevices[f->unit].totalLBA;i+=(1024*256)) { ata_device_sector_io(f->unit, clink->header, i, sizeof(apa_header_t)/512, ATA_DIR_WRITE); } apaCacheFree(clink); if((rv=apaJournalReset(f->unit))!=0) return rv; // set up mbr :) if((clink=apaCacheGetHeader(f->unit, 0, APA_IO_MODE_WRITE, &rv))){ apa_header_t *header=clink->header; memset(header, 0, sizeof(apa_header_t)); header->magic=APA_MAGIC; header->length=(1024*256); // 128MB header->type=APA_TYPE_MBR; strcpy(header->id,"__mbr"); #ifdef APA_FORMAT_LOCK_MBR apaEncryptPassword(header->id, header->fpwd, "sce_mbr"); apaEncryptPassword(header->id, header->rpwd, "sce_mbr"); #endif memcpy(header->mbr.magic, apaMBRMagic, sizeof(header->mbr.magic)); header->mbr.version=APA_MBR_VERSION; header->mbr.nsector=0; apaGetTime(&header->created); apaGetTime(&header->mbr.created); header->checksum=apaCheckSum(header); clink->flags|=APA_CACHE_FLAG_DIRTY; apaCacheFlushDirty(clink); ata_device_flush_cache(f->unit); apaCacheFree(clink); hddDevices[f->unit].status=0; hddDevices[f->unit].format=APA_MBR_VERSION; } #ifdef APA_FORMAT_MAKE_PARTITIONS memset(&emptyBlocks, 0, sizeof(emptyBlocks)); memset(¶ms, 0, sizeof(apa_params_t)); params.size=(1024*256); params.type=APA_TYPE_PFS; // add __net, __system.... for(i=0;formatPartList[i];i++) { memset(params.id, 0, APA_IDMAX); strcpy(params.id, formatPartList[i]); if(!(clink=hddAddPartitionHere(f->unit, ¶ms, emptyBlocks, i ? clink->sector : 0, &rv))) return rv; apaCacheFree(clink); params.size<<=1; if(hddDevices[f->unit].partitionMaxSize < params.size) params.size=hddDevices[f->unit].partitionMaxSize; } #endif return rv; }