Pe * pe_begin(int fildes, Pe_Cmd cmd, Pe *ref) { Pe *retval = NULL; if (ref != NULL) { rwlock_rdlock(ref->lock); } else if (fcntl(fildes, F_GETFL) == -1 && errno == EBADF) { __libpe_seterrno(PE_E_INVALID_FILE); return NULL; } switch (cmd) { case PE_C_NULL: break; case PE_C_READ_MMAP_PRIVATE: if (ref != NULL && ref->cmd != PE_C_READ_MMAP_PRIVATE) { __libpe_seterrno(PE_E_INVALID_CMD); break; } /* fall through */ case PE_C_READ: case PE_C_READ_MMAP: if (ref != NULL) retval = dup_pe(fildes, cmd, ref); else retval = read_file(fildes, ~((size_t)0), cmd, NULL); break; case PE_C_RDWR: case PE_C_RDWR_MMAP: if (ref != NULL) { if (ref->cmd != PE_C_RDWR && ref->cmd != PE_C_RDWR_MMAP && ref->cmd != PE_C_WRITE && ref->cmd != PE_C_WRITE_MMAP) { __libpe_seterrno(PE_E_INVALID_CMD); retval = NULL; } } else { retval = read_file(fildes, ~((size_t) 0), cmd, NULL); } break; case PE_C_WRITE: case PE_C_WRITE_MMAP: retval = write_file(fildes, cmd); break; default: __libpe_seterrno(PE_E_INVALID_CMD); break; } if (ref != NULL) rwlock_unlock(ref->lock); return retval; }
static off_t write_file(Pe *pe, off_t size, size_t shnum) { struct stat st; if (fstat(pe->fildes, &st) != 0) { __libpe_seterrno(PE_E_WRITE_ERROR); return -1; } if (pe->parent == NULL && (pe->maximum_size == ~((size_t)0) || (size_t)size > pe->maximum_size) && ftruncate(pe->fildes, size) != 0) { __libpe_seterrno(PE_E_WRITE_ERROR); return -1; } if (pe->map_address == NULL && pe->cmd == PE_C_WRITE_MMAP) { pe->map_address = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, pe->fildes, 0); if (pe->map_address == MAP_FAILED) pe->map_address = NULL; } if (pe->map_address != NULL) { if (__pe_updatemmap(pe, shnum) != 0) size = -1; } else { if (__pe_updatefile(pe, shnum) != 0) size = -1; } if (size != -1 && pe->parent == NULL && pe->maximum_size != ~((size_t)0) && (size_t)size < pe->maximum_size && ftruncate(pe->fildes, size) != 0) { __libpe_seterrno(PE_E_WRITE_ERROR); size = -1; } if (size != -1 && (st.st_mode & (S_ISUID | S_ISGID)) && (fchmod(pe->fildes, st.st_mode) != 0)) { __libpe_seterrno(PE_E_WRITE_ERROR); size = -1; } if (size != -1 && pe->parent == NULL) pe->maximum_size = size; return size; }
loff_t pe_update(Pe *pe, Pe_Cmd cmd) { if (cmd != PE_C_NULL && cmd != PE_C_WRITE && cmd != PE_C_WRITE_MMAP) { __libpe_seterrno(PE_E_INVALID_CMD); return -1; } if (pe == NULL) return -1; if (pe->kind != PE_K_PE_EXE && pe->kind != PE_K_PE64_EXE && pe->kind != PE_K_PE_OBJ && pe->kind != PE_K_PE64_OBJ && pe->kind != PE_K_PE_ROM) { __libpe_seterrno(PE_E_INVALID_HANDLE); return -1; } size_t shnum = (pe->state.pe.scns_last->cnt == 0 ? 0 : 1 + pe->state.pe.scns_last->data[ pe->state.pe.scns_last->cnt - 1].index); off_t size = __pe_updatenull(pe, shnum); if (size != -1 && (cmd == PE_C_WRITE || PE_C_WRITE_MMAP)) { if (pe->cmd != PE_C_RDWR && pe->cmd != PE_C_RDWR_MMAP && pe->cmd != PE_C_WRITE && pe->cmd != PE_C_WRITE_MMAP) { __libpe_seterrno(PE_E_UPDATE_RO); size = -1; } else if (pe->fildes == -1) { __libpe_seterrno(PE_E_FD_DISABLED); size = -1; } else { size = write_file(pe, size, shnum); } } return size; }
static Pe * dup_pe(int fildes, Pe_Cmd cmd, Pe *ref) { if (fildes == -1) { fildes = ref->fildes; } else if (ref->fildes != -1 && fildes != ref->fildes) { __libpe_seterrno(PE_E_FD_MISMATCH); return NULL; } if (ref->cmd != PE_C_READ && ref->cmd != PE_C_READ_MMAP && ref->cmd != PE_C_WRITE && ref->cmd != PE_C_WRITE_MMAP && ref->cmd != PE_C_RDWR && ref->cmd != PE_C_RDWR_MMAP && ref->cmd != PE_C_READ_MMAP_PRIVATE) { __libpe_seterrno(PE_E_INVALID_OP); return NULL; } /* for now, just increment the refcount and return the same object */ ref->ref_count++; return ref; }
static struct pe_hdr * __pe_getpehdr_rdlock(Pe *pe, struct pe_hdr *dest) { struct pe_hdr *result = NULL; if (!pe) return NULL; if (pe->state.pe.pehdr == NULL) { __libpe_seterrno(PE_E_WRONG_ORDER_PEHDR); } else { memcpy(dest, pe->state.pe.pehdr, sizeof(*dest)); result = dest; } return result; }
struct section_header * pe_getshdr(Pe_Scn *scn, struct section_header *dst) { struct section_header *result = NULL; if (scn == NULL) return NULL; if (dst == NULL) { __libpe_seterrno(PE_E_INVALID_OPERAND); return NULL; } result = memcpy(dst, scn->shdr, sizeof(*dst)); return result; }
int __pe_updatefile(Pe *pe, size_t shnum) { __libpe_seterrno(PE_E_UNKNOWN_ERROR); return 1; }