// StatAttr status_t FileHandle::StatAttr(const char* name, attr_info* info) { if (fFD < 0) return B_BAD_VALUE; return (fs_stat_attr(fFD, name, info) == 0 ? B_OK : errno); }
/*! \brief Fills in the pre-allocated attr_info struct pointed to by \a info with useful information about the attribute specified by \a name. \param name the name of the attribute \param info the attr_info structure to be filled in \return - \c B_OK: Everything went fine. - \c B_BAD_VALUE: \c NULL \a name - \c B_FILE_ERROR: The object is not initialized. - \c B_ENTRY_NOT_FOUND: The node has no attribute \a name. */ status_t BNode::GetAttrInfo(const char *name, struct attr_info *info) const { if (fCStatus != B_OK) return B_FILE_ERROR; if (!name || !info) return B_BAD_VALUE; return (fs_stat_attr(fFd, name, info) < 0) ? errno : B_OK ; }
bool has_rfork_attribute(const char *file) { int fd = open(file, O_RDONLY); if (fd < 0) return false; struct attr_info info; bool result = (fs_stat_attr(fd, ATTR_NAME, &info) == 0); close(fd); return result; }
SDL_RWops *sdl_rw_from_rfork(const char *file, bool writable) { SDL_RWops *rwops = NULL; int fd = open(file, writable ? O_RDWR : O_RDONLY); if (fd < 0) { SDL_SetError("Couldn't open %s", file); return NULL; } else { struct attr_info info; fs_stat_attr(fd, ATTR_NAME, &info); rwops = SDL_AllocRW(); if (rwops == NULL) { close(fd); return NULL; } rfork_data *d = (rfork_data *)malloc(sizeof(struct rfork_data)); if (d == NULL) { free(rwops); close(fd); return NULL; } d->fd = fd; d->current = 0; d->size = info.size; rwops->seek = rfork_seek; rwops->read = rfork_read; rwops->write = rfork_write; rwops->close = rfork_close; rwops->hidden.unknown.data1 = d; return rwops; } }
void PackageWriter::_AddEntry(int dirFD, Entry* entry, const char* fileName) { printf("PackageWriter::_AddEntry(%d, %p, \"%s\")\n", dirFD, entry, fileName); bool isImplicitEntry = entry != NULL && entry->IsImplicit(); // open the node int fd = openat(dirFD, fileName, O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE)); if (fd < 0) { fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n", fileName, strerror(errno)); throw status_t(errno); } FDCloser fdCloser(fd); // stat the node struct stat st; if (fstat(fd, &st) < 0) { fprintf(stderr, "Error: Failed to fstat() file \"%s\": %s\n", fileName, strerror(errno)); throw status_t(errno); } // implicit entries must be directories if (isImplicitEntry && !S_ISDIR(st.st_mode)) { fprintf(stderr, "Error: Non-leaf path component \"%s\" is not a " "directory\n", fileName); throw status_t(B_BAD_VALUE); } // check/translate the node type uint8 fileType; uint32 defaultPermissions; if (S_ISREG(st.st_mode)) { fileType = B_HPKG_FILE_TYPE_FILE; defaultPermissions = B_HPKG_DEFAULT_FILE_PERMISSIONS; } else if (S_ISLNK(st.st_mode)) { fileType = B_HPKG_FILE_TYPE_SYMLINK; defaultPermissions = B_HPKG_DEFAULT_SYMLINK_PERMISSIONS; } else if (S_ISDIR(st.st_mode)) { fileType = B_HPKG_FILE_TYPE_DIRECTORY; defaultPermissions = B_HPKG_DEFAULT_DIRECTORY_PERMISSIONS; } else { // unsupported node type fprintf(stderr, "Error: Unsupported node type, entry: \"%s\"\n", fileName); throw status_t(B_UNSUPPORTED); } // add attribute entry Attribute* entryAttribute = _AddStringAttribute( B_HPKG_ATTRIBUTE_NAME_DIRECTORY_ENTRY, fileName); Stacker<Attribute> entryAttributeStacker(fTopAttribute, entryAttribute); // add stat data if (fileType != B_HPKG_DEFAULT_FILE_TYPE) _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_TYPE, fileType); if (defaultPermissions != uint32(st.st_mode & ALLPERMS)) { _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_PERMISSIONS, uint32(st.st_mode & ALLPERMS)); } _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_ATIME, uint32(st.st_atime)); _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_MTIME, uint32(st.st_mtime)); _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_CRTIME, uint32(st.st_crtime)); // TODO: File user/group! // add file data/symlink path if (S_ISREG(st.st_mode)) { // regular file -- add data if (st.st_size > 0) { FDDataReader dataReader(fd); status_t error = _AddData(dataReader, st.st_size); if (error != B_OK) throw status_t(error); } } else if (S_ISLNK(st.st_mode)) { // symlink -- add link address char path[B_PATH_NAME_LENGTH + 1]; ssize_t bytesRead = readlinkat(dirFD, fileName, path, B_PATH_NAME_LENGTH); if (bytesRead < 0) { fprintf(stderr, "Error: Failed to read symlink \"%s\": %s\n", fileName, strerror(errno)); throw status_t(errno); } path[bytesRead] = '\0'; _AddStringAttribute(B_HPKG_ATTRIBUTE_NAME_SYMLINK_PATH, path); } // add attributes if (DIR* attrDir = fs_fopen_attr_dir(fd)) { CObjectDeleter<DIR, int> attrDirCloser(attrDir, fs_close_attr_dir); while (dirent* entry = readdir(attrDir)) { attr_info attrInfo; if (fs_stat_attr(fd, entry->d_name, &attrInfo) < 0) { fprintf(stderr, "Error: Failed to stat attribute \"%s\" of " "file \"%s\": %s\n", entry->d_name, fileName, strerror(errno)); throw status_t(errno); } // create attribute entry Attribute* attributeAttribute = _AddStringAttribute( B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE, entry->d_name); Stacker<Attribute> attributeAttributeStacker(fTopAttribute, attributeAttribute); // add type _AddAttribute(B_HPKG_ATTRIBUTE_NAME_FILE_ATTRIBUTE_TYPE, (uint32)attrInfo.type); // add data AttributeDataReader dataReader(fd, entry->d_name, attrInfo.type); status_t error = _AddData(dataReader, attrInfo.size); if (error != B_OK) throw status_t(error); } } if (S_ISDIR(st.st_mode)) { // directory -- recursively add children if (isImplicitEntry) { // this is an implicit entry -- just add it's children for (EntryList::ConstIterator it = entry->ChildIterator(); Entry* child = it.Next();) { _AddEntry(fd, child, child->Name()); } } else { // we need to clone the directory FD for fdopendir() int clonedFD = dup(fd); if (clonedFD < 0) { fprintf(stderr, "Error: Failed to dup() directory FD: %s\n", strerror(errno)); throw status_t(errno); } DIR* dir = fdopendir(clonedFD); if (dir == NULL) { fprintf(stderr, "Error: Failed to open directory \"%s\": %s\n", fileName, strerror(errno)); close(clonedFD); throw status_t(errno); } CObjectDeleter<DIR, int> dirCloser(dir, closedir); while (dirent* entry = readdir(dir)) { // skip "." and ".." if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; } _AddEntry(fd, NULL, entry->d_name); } } } }
static status_t catAttr(const char *attribute, const char *fileName, bool keepRaw = false) { int fd = open(fileName, O_RDONLY); if (fd < 0) return errno; attr_info info; if (fs_stat_attr(fd, attribute, &info) < 0) return errno; // limit size of the attribute, only the first 64k will make it on screen off_t size = info.size; bool cut = false; if (size > 64 * 1024) { size = 64 * 1024; cut = true; } char* buffer = (char*)malloc(size); if (!buffer) { fprintf(stderr, "Could not allocate read buffer!\n"); return B_NO_MEMORY; } ssize_t bytesRead = fs_read_attr(fd, attribute, info.type, 0, buffer, size); if (bytesRead < 0) { free(buffer); return errno; } if (bytesRead != size) { fprintf(stderr, "Could only read %ld bytes from attribute!\n", bytesRead); free(buffer); return B_ERROR; } if (keepRaw) { off_t pos = 0; ssize_t written = 0; while (pos < info.size) { // write what we have read so far written = write(STDOUT_FILENO, buffer, bytesRead); // check for write error if (written < bytesRead) { if (written >= 0) { fprintf(stderr, "Could only write %ld bytes to stream!\n", written); written = B_ERROR; } else { fprintf(stderr, "Failed to write to stream: %s\n", strerror(written)); } break; } // read next chunk of data at pos pos += bytesRead; bytesRead = fs_read_attr(fd, attribute, info.type, pos, buffer, size); // check for read error if (bytesRead < size && pos + bytesRead < info.size) { if (bytesRead >= 0) { fprintf(stderr, "Could only read %ld bytes from " "attribute!\n", bytesRead); } else { fprintf(stderr, "Failed to read from attribute: %s\n", strerror(bytesRead)); } written = B_ERROR; break; } } free(buffer); if (written > 0) written = B_OK; return written; } switch (info.type) { case B_INT8_TYPE: printf("%s : int8 : %d\n", fileName, *((int8 *)buffer)); break; case B_UINT8_TYPE: printf("%s : uint8 : %u\n", fileName, *((uint8 *)buffer)); break; case B_INT16_TYPE: printf("%s : int16 : %d\n", fileName, *((int16 *)buffer)); break; case B_UINT16_TYPE: printf("%s : uint16 : %u\n", fileName, *((uint16 *)buffer)); break; case B_INT32_TYPE: printf("%s : int32 : %ld\n", fileName, *((int32 *)buffer)); break; case B_UINT32_TYPE: printf("%s : uint32 : %lu\n", fileName, *((uint32 *)buffer)); break; case B_INT64_TYPE: printf("%s : int64 : %Ld\n", fileName, *((int64 *)buffer)); break; case B_UINT64_TYPE: printf("%s : uint64 : %Lu\n", fileName, *((uint64 *)buffer)); break; case B_FLOAT_TYPE: printf("%s : float : %f\n", fileName, *((float *)buffer)); break; case B_DOUBLE_TYPE: printf("%s : double : %f\n", fileName, *((double *)buffer)); break; case B_BOOL_TYPE: printf("%s : bool : %d\n", fileName, *((unsigned char *)buffer)); break; case B_STRING_TYPE: printf("%s : string : %s\n", fileName, buffer); break; case B_MIME_STRING_TYPE: case 'MSIG': case 'MSDC': case 'MPTH': printf("%s : %s : %s\n", fileName, type_to_string(info.type), buffer); break; case B_MESSAGE_TYPE: { BMessage message; if (!cut && message.Unflatten(buffer) == B_OK) { printf("%s : message :\n", fileName); message.PrintToStream(); break; } // supposed to fall through } default: // The rest of the attributes types are displayed as raw data printf("%s : %s : \n", fileName, type_to_string(info.type)); dumpRawData(buffer, size); break; } free(buffer); return B_OK; }