/* * extfs_beos.cpp - MacOS file system for access native file system access, BeOS specific stuff * * Basilisk II (C) 1997-2005 Christian Bauer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "sysdeps.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "extfs.h" #include "extfs_defs.h" #define DEBUG 0 #include "debug.h" // Default Finder flags const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited; // Temporary buffer for transfers from/to kernel space const int TMP_BUF_SIZE = 0x10000; static uint8 *tmp_buf = NULL; /* * Initialization */ void extfs_init(void) { // Allocate temporary buffer tmp_buf = new uint8[TMP_BUF_SIZE]; } /* * Deinitialization */ void extfs_exit(void) { // Delete temporary buffer delete[] tmp_buf; } /* * Add component to path name */ void add_path_component(char *path, const char *component) { int l = strlen(path); if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') { path[l] = '/'; path[l+1] = 0; } strncat(path, component, MAX_PATH_LENGTH-1); } /* * Get/set finder info for file/directory specified by full path */ struct mime2type { const char *mime; uint32 type; uint32 creator; bool reversible; // type -> mime translation possible }; static const mime2type m2t_translation[] = { {"application/x-compress", 'ZIVM', 'LZIV', true}, {"application/x-gzip", 'Gzip', 'Gzip', true}, {"application/x-macbinary", 'BINA', '????', false}, {"application/mac-binhex40", 'TEXT', 'SITx', false}, {"application/pdf", 'PDF ', 'CARO', true}, {"application/postscript", 'TEXT', 'ttxt', false}, {"application/x-stuffit", 'SIT!', 'SITx', true}, {"application/x-tar", 'TARF', 'TAR ', true}, {"application/x-uuencode", 'TEXT', 'SITx', false}, {"application/zip", 'ZIP ', 'ZIP ', true}, {"audio/x-8svx", '8SVX', 'SNDM', true}, {"audio/x-aifc", 'AIFC', 'TVOD', true}, {"audio/x-aiff", 'AIFF', 'TVOD', true}, {"audio/basic", 'ULAW', 'TVOD', true}, {"audio/x-midi", 'MIDI', 'TVOD', true}, {"audio/x-mpeg", 'MPG ', 'TVOD', true}, {"audio/x-wav", 'WAVE', 'TVOD', true}, {"image/x-bmp", 'BMPf', 'ogle', true}, {"image/gif", 'GIFf', 'ogle', true}, {"image/x-ilbm", 'ILBM', 'GKON', true}, {"image/jpeg", 'JPEG', 'ogle', true}, {"image/jpeg", 'JFIF', 'ogle', true}, {"image/x-photoshop", '8BPS', '8BIM', true}, {"image/pict", 'PICT', 'ogle', true}, {"image/png", 'PNGf', 'ogle', true}, {"image/x-sgi", '.SGI', 'ogle', true}, {"image/x-targa", 'TPIC', 'ogle', true}, {"image/tiff", 'TIFF', 'ogle', true}, {"text/html", 'TEXT', 'MOSS', false}, {"text/plain", 'TEXT', 'ttxt', true}, {"text/rtf", 'TEXT', 'MSWD', false}, {"text/x-source-code", 'TEXT', 'R*ch', false}, {"video/mpeg", 'MPEG', 'TVOD', true}, {"video/quicktime", 'MooV', 'TVOD', true}, {"video/x-flc", 'FLI ', 'TVOD', true}, {"video/x-msvideo", 'VfW ', 'TVOD', true}, {NULL, 0, 0, false} // End marker }; void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Set default finder info Mac_memset(finfo, 0, SIZEOF_FInfo); if (fxinfo) Mac_memset(fxinfo, 0, SIZEOF_FXInfo); WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS); WriteMacInt32(finfo + fdLocation, (uint32)-1); // Open file int fd = open(path, O_RDONLY); if (fd < 0) return; if (!is_dir) { // Read BeOS MIME type ssize_t actual = fs_read_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, tmp_buf, 256); tmp_buf[255] = 0; if (actual > 0) { // Translate MIME type to MacOS type/creator uint8 mactype[4]; if (sscanf((char *)tmp_buf, "application/x-MacOS-%c%c%c%c", mactype, mactype+1, mactype+2, mactype+3) == 4) { // MacOS style type WriteMacInt32(finfo + fdType, (mactype[0] << 24) | (mactype[1] << 16) | (mactype[2] << 8) | mactype[3]); } else { // MIME string, look in table for (int i=0; m2t_translation[i].mime; i++) { if (!strcmp((char *)tmp_buf, m2t_translation[i].mime)) { WriteMacInt32(finfo + fdType, m2t_translation[i].type); WriteMacInt32(finfo + fdCreator, m2t_translation[i].creator); break; } } } } // Override file type with MACOS:CREATOR attribute if (fs_read_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, tmp_buf, 4) == 4) WriteMacInt32(finfo + fdCreator, (tmp_buf[0] << 24) | (tmp_buf[1] << 16) | (tmp_buf[2] << 8) | tmp_buf[3]); } // Read MACOS:HFS_FLAGS attribute if (fs_read_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, tmp_buf, 2) == 2) WriteMacInt16(finfo + fdFlags, (tmp_buf[0] << 8) | tmp_buf[1]); // Close file close(fd); } void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir) { // Open file int fd = open(path, O_WRONLY); if (fd < 0) return; if (!is_dir) { // Set BEOS:TYPE attribute uint32 type = ReadMacInt32(finfo + fdType); if (type) { for (int i=0; m2t_translation[i].mime; i++) { if (m2t_translation[i].type == type && m2t_translation[i].reversible) { fs_write_attr(fd, "BEOS:TYPE", B_MIME_STRING_TYPE, 0, m2t_translation[i].mime, strlen(m2t_translation[i].mime) + 1); break; } } } // Set MACOS:CREATOR attribute uint32 creator = ReadMacInt32(finfo + fdCreator); if (creator) { tmp_buf[0] = creator >> 24; tmp_buf[1] = creator >> 16; tmp_buf[2] = creator >> 8; tmp_buf[3] = creator; fs_write_attr(fd, "MACOS:CREATOR", B_UINT32_TYPE, 0, tmp_buf, 4); } } // Write MACOS:HFS_FLAGS attribute uint16 flags = ReadMacInt16(finfo + fdFlags); if (flags != DEFAULT_FINDER_FLAGS) { tmp_buf[0] = flags >> 8; tmp_buf[1] = flags; fs_write_attr(fd, "MACOS:HFS_FLAGS", B_UINT16_TYPE, 0, tmp_buf, 2); } else fs_remove_attr(fd, "MACOS:HFS_FLAGS"); // Close file close(fd); } /* * Resource fork emulation functions */ uint32 get_rfork_size(const char *path) { // Open file int fd = open(path, O_RDONLY); if (fd < 0) return 0; // Get size of MACOS:RFORK attribute struct attr_info info; if (fs_stat_attr(fd, "MACOS:RFORK", &info) < 0) info.size = 0; // Close file and return size close(fd); return info.size; } int open_rfork(const char *path, int flag) { // Open original file int fd = open(path, flag); if (fd < 0) return -1; // Open temporary file for resource fork char rname[L_tmpnam]; tmpnam(rname); int rfd = open(rname, O_RDWR | O_CREAT | O_TRUNC, 0666); if (rfd < 0) { close(fd); return -1; } unlink(rname); // File will be deleted when closed // Get size of MACOS:RFORK attribute struct attr_info info; if (fs_stat_attr(fd, "MACOS:RFORK", &info) < 0) info.size = 0; // Copy resource data from attribute to temporary file if (info.size > 0) { // Allocate buffer void *buf = malloc(info.size); if (buf == NULL) { close(rfd); close(fd); return -1; } // Copy data fs_read_attr(fd, "MACOS:RFORK", B_RAW_TYPE, 0, buf, info.size); write(rfd, buf, info.size); lseek(rfd, 0, SEEK_SET); // Free buffer if (buf) free(buf); } // Close original file close(fd); return rfd; } void close_rfork(const char *path, int fd) { if (fd < 0) return; // Get size of temporary file struct stat st; if (fstat(fd, &st) < 0) st.st_size = 0; // Open original file int ofd = open(path, O_WRONLY); if (ofd > 0) { // Copy resource data to MACOS:RFORK attribute if (st.st_size > 0) { // Allocate buffer void *buf = malloc(st.st_size); if (buf == NULL) { close(ofd); close(fd); return; } // Copy data lseek(fd, 0, SEEK_SET); read(fd, buf, st.st_size); fs_write_attr(ofd, "MACOS:RFORK", B_RAW_TYPE, 0, buf, st.st_size); // Free buffer if (buf) free(buf); } else fs_remove_attr(ofd, "MACOS:RFORK"); // Close original file close(ofd); } // Close temporary file close(fd); } /* * Read "length" bytes from file to "buffer", * returns number of bytes read (or -1 on error) */ static inline ssize_t sread(int fd, void *buf, size_t count) { ssize_t res; while ((res = read(fd, buf, count)) == B_INTERRUPTED) ; return res; } ssize_t extfs_read(int fd, void *buffer, size_t length) { // Buffer in kernel space? if ((uint32)buffer < 0x80000000) { // Yes, transfer via buffer ssize_t actual = 0; while (length) { size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; ssize_t res = sread(fd, tmp_buf, transfer_size); if (res < 0) return res; memcpy(buffer, tmp_buf, res); buffer = (void *)((uint8 *)buffer + res); length -= res; actual += res; if (res != transfer_size) return actual; } return actual; } else { // No, transfer directly return sread(fd, buffer, length); } } /* * Write "length" bytes from "buffer" to file, * returns number of bytes written (or -1 on error) */ static inline ssize_t swrite(int fd, void *buf, size_t count) { ssize_t res; while ((res = write(fd, buf, count)) == B_INTERRUPTED) ; return res; } ssize_t extfs_write(int fd, void *buffer, size_t length) { // Buffer in kernel space? if ((uint32)buffer < 0x80000000) { // Yes, transfer via buffer ssize_t actual = 0; while (length) { size_t transfer_size = (length > TMP_BUF_SIZE) ? TMP_BUF_SIZE : length; memcpy(tmp_buf, buffer, transfer_size); ssize_t res = swrite(fd, tmp_buf, transfer_size); if (res < 0) return res; buffer = (void *)((uint8 *)buffer + res); length -= res; actual += res; if (res != transfer_size) return actual; } return actual; } else { // No, transfer directly return swrite(fd, buffer, length); } } /* * Remove file/directory, returns false on error (and sets errno) */ bool extfs_remove(const char *path) { if (remove(path) < 0) { if (errno == EISDIR) return rmdir(path) == 0; else return false; } return true; } /* * Rename/move file/directory, returns false on error (and sets errno) */ bool extfs_rename(const char *old_path, const char *new_path) { return rename(old_path, new_path) == 0; }