home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / Unix / extfs_unix.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-31  |  10.7 KB  |  378 lines

  1. /*
  2.  *  extfs_unix.cpp - MacOS file system for access native file system access, Unix specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <unistd.h>
  26. #include <dirent.h>
  27. #include <errno.h>
  28.  
  29. #include "sysdeps.h"
  30. #include "extfs.h"
  31. #include "extfs_defs.h"
  32.  
  33. #define DEBUG 0
  34. #include "debug.h"
  35.  
  36.  
  37. // Default Finder flags
  38. const uint16 DEFAULT_FINDER_FLAGS = kHasBeenInited;
  39.  
  40.  
  41. /*
  42.  *  Initialization
  43.  */
  44.  
  45. void extfs_init(void)
  46. {
  47. }
  48.  
  49.  
  50. /*
  51.  *  Deinitialization
  52.  */
  53.  
  54. void extfs_exit(void)
  55. {
  56. }
  57.  
  58.  
  59. /*
  60.  *  Add component to path name
  61.  */
  62.  
  63. void add_path_component(char *path, const char *component)
  64. {
  65.     int l = strlen(path);
  66.     if (l < MAX_PATH_LENGTH-1 && path[l-1] != '/') {
  67.         path[l] = '/';
  68.         path[l+1] = 0;
  69.     }
  70.     strncat(path, component, MAX_PATH_LENGTH-1);
  71. }
  72.  
  73.  
  74. /*
  75.  *  Finder info and resource forks are kept in helper files
  76.  *
  77.  *  Finder info:
  78.  *    /path/.finf/file
  79.  *  Resource fork:
  80.  *    /path/.rsrc/file
  81.  *
  82.  *  The .finf files store a FInfo/DInfo, followed by a FXInfo/DXInfo
  83.  *  (16+16 bytes)
  84.  */
  85.  
  86. static void make_helper_path(const char *src, char *dest, const char *add, bool only_dir = false)
  87. {
  88.     dest[0] = 0;
  89.  
  90.     // Get pointer to last component of path
  91.     const char *last_part = strrchr(src, '/');
  92.     if (last_part)
  93.         last_part++;
  94.     else
  95.         last_part = src;
  96.  
  97.     // Copy everything before
  98.     strncpy(dest, src, last_part-src);
  99.     dest[last_part-src] = 0;
  100.  
  101.     // Add additional component
  102.     strncat(dest, add, MAX_PATH_LENGTH-1);
  103.  
  104.     // Add last component
  105.     if (!only_dir)
  106.         strncat(dest, last_part, MAX_PATH_LENGTH-1);
  107. }
  108.  
  109. static int create_helper_dir(const char *path, const char *add)
  110. {
  111.     char helper_dir[MAX_PATH_LENGTH];
  112.     make_helper_path(path, helper_dir, add, true);
  113.     if (helper_dir[strlen(helper_dir) - 1] == '/')    // Remove trailing "/"
  114.         helper_dir[strlen(helper_dir) - 1] = 0;
  115.     return mkdir(helper_dir, 0777);
  116. }
  117.  
  118. static int open_helper(const char *path, const char *add, int flag)
  119. {
  120.     char helper_path[MAX_PATH_LENGTH];
  121.     make_helper_path(path, helper_path, add);
  122.  
  123.     if ((flag & O_ACCMODE) == O_RDWR || (flag & O_ACCMODE) == O_WRONLY)
  124.         flag |= O_CREAT;
  125.     int fd = open(helper_path, flag, 0666);
  126.     if (fd < 0) {
  127.         if (errno == ENOENT && (flag & O_CREAT)) {
  128.             // One path component was missing, probably the helper
  129.             // directory. Try to create it and re-open the file.
  130.             int ret = create_helper_dir(path, add);
  131.             if (ret < 0)
  132.                 return ret;
  133.             fd = open(helper_path, flag, 0666);
  134.         }
  135.     }
  136.     return fd;
  137. }
  138.  
  139. static int open_finf(const char *path, int flag)
  140. {
  141.     return open_helper(path, ".finf/", flag);
  142. }
  143.  
  144. static int open_rsrc(const char *path, int flag)
  145. {
  146.     return open_helper(path, ".rsrc/", flag);
  147. }
  148.  
  149.  
  150. /*
  151.  *  Get/set finder info for file/directory specified by full path
  152.  */
  153.  
  154. struct ext2type {
  155.     const char *ext;
  156.     uint32 type;
  157.     uint32 creator;
  158. };
  159.  
  160. static const ext2type e2t_translation[] = {
  161.     {".Z", FOURCC('Z','I','V','M'), FOURCC('L','Z','I','V')},
  162.     {".gz", FOURCC('G','z','i','p'), FOURCC('G','z','i','p')},
  163.     {".hqx", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
  164.     {".bin", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
  165.     {".pdf", FOURCC('P','D','F',' '), FOURCC('C','A','R','O')},
  166.     {".ps", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')},
  167.     {".sit", FOURCC('S','I','T','!'), FOURCC('S','I','T','x')},
  168.     {".tar", FOURCC('T','A','R','F'), FOURCC('T','A','R',' ')},
  169.     {".uu", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
  170.     {".uue", FOURCC('T','E','X','T'), FOURCC('S','I','T','x')},
  171.     {".zip", FOURCC('Z','I','P',' '), FOURCC('Z','I','P',' ')},
  172.     {".8svx", FOURCC('8','S','V','X'), FOURCC('S','N','D','M')},
  173.     {".aifc", FOURCC('A','I','F','C'), FOURCC('T','V','O','D')},
  174.     {".aiff", FOURCC('A','I','F','F'), FOURCC('T','V','O','D')},
  175.     {".au", FOURCC('U','L','A','W'), FOURCC('T','V','O','D')},
  176.     {".mid", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')},
  177.     {".midi", FOURCC('M','I','D','I'), FOURCC('T','V','O','D')},
  178.     {".mp2", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')},
  179.     {".mp3", FOURCC('M','P','G',' '), FOURCC('T','V','O','D')},
  180.     {".wav", FOURCC('W','A','V','E'), FOURCC('T','V','O','D')},
  181.     {".bmp", FOURCC('B','M','P','f'), FOURCC('o','g','l','e')},
  182.     {".gif", FOURCC('G','I','F','f'), FOURCC('o','g','l','e')},
  183.     {".lbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')},
  184.     {".ilbm", FOURCC('I','L','B','M'), FOURCC('G','K','O','N')},
  185.     {".jpg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')},
  186.     {".jpeg", FOURCC('J','P','E','G'), FOURCC('o','g','l','e')},
  187.     {".pict", FOURCC('P','I','C','T'), FOURCC('o','g','l','e')},
  188.     {".png", FOURCC('P','N','G','f'), FOURCC('o','g','l','e')},
  189.     {".sgi", FOURCC('.','S','G','I'), FOURCC('o','g','l','e')},
  190.     {".tga", FOURCC('T','P','I','C'), FOURCC('o','g','l','e')},
  191.     {".tif", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')},
  192.     {".tiff", FOURCC('T','I','F','F'), FOURCC('o','g','l','e')},
  193.     {".htm", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')},
  194.     {".html", FOURCC('T','E','X','T'), FOURCC('M','O','S','S')},
  195.     {".txt", FOURCC('T','E','X','T'), FOURCC('t','t','x','t')},
  196.     {".rtf", FOURCC('T','E','X','T'), FOURCC('M','S','W','D')},
  197.     {".c", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  198.     {".C", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  199.     {".cc", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  200.     {".cpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  201.     {".cxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  202.     {".h", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  203.     {".hh", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  204.     {".hpp", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  205.     {".hxx", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  206.     {".s", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  207.     {".S", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  208.     {".i", FOURCC('T','E','X','T'), FOURCC('R','*','c','h')},
  209.     {".mpg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')},
  210.     {".mpeg", FOURCC('M','P','E','G'), FOURCC('T','V','O','D')},
  211.     {".mov", FOURCC('M','o','o','V'), FOURCC('T','V','O','D')},
  212.     {".fli", FOURCC('F','L','I',' '), FOURCC('T','V','O','D')},
  213.     {".avi", FOURCC('V','f','W',' '), FOURCC('T','V','O','D')},
  214.     {".qxd", FOURCC('X','D','O','C'), FOURCC('X','P','R','3')},
  215.     {".hfv", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')},
  216.     {".dsk", FOURCC('D','D','i','m'), FOURCC('d','d','s','k')},
  217.     {".img", FOURCC('r','o','h','d'), FOURCC('d','d','s','k')},
  218.     {NULL, 0, 0}    // End marker
  219. };
  220.  
  221. void get_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir)
  222. {
  223.     // Set default finder info
  224.     Mac_memset(finfo, 0, SIZEOF_FInfo);
  225.     if (fxinfo)
  226.         Mac_memset(fxinfo, 0, SIZEOF_FXInfo);
  227.     WriteMacInt16(finfo + fdFlags, DEFAULT_FINDER_FLAGS);
  228.     WriteMacInt32(finfo + fdLocation, (uint32)-1);
  229.  
  230.     // Read Finder info file
  231.     int fd = open_finf(path, O_RDONLY);
  232.     if (fd >= 0) {
  233.         ssize_t actual = read(fd, Mac2HostAddr(finfo), SIZEOF_FInfo);
  234.         if (fxinfo)
  235.             actual += read(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo);
  236.         close(fd);
  237.         if (actual >= SIZEOF_FInfo)
  238.             return;
  239.     }
  240.  
  241.     // No Finder info file, translate file name extension to MacOS type/creator
  242.     if (!is_dir) {
  243.         int path_len = strlen(path);
  244.         for (int i=0; e2t_translation[i].ext; i++) {
  245.             int ext_len = strlen(e2t_translation[i].ext);
  246.             if (path_len < ext_len)
  247.                 continue;
  248.             if (!strcmp(path + path_len - ext_len, e2t_translation[i].ext)) {
  249.                 WriteMacInt32(finfo + fdType, e2t_translation[i].type);
  250.                 WriteMacInt32(finfo + fdCreator, e2t_translation[i].creator);
  251.                 break;
  252.             }
  253.         }
  254.     }
  255. }
  256.  
  257. void set_finfo(const char *path, uint32 finfo, uint32 fxinfo, bool is_dir)
  258. {
  259.     // Open Finder info file
  260.     int fd = open_finf(path, O_RDWR);
  261.     if (fd < 0)
  262.         return;
  263.  
  264.     // Write file
  265.     write(fd, Mac2HostAddr(finfo), SIZEOF_FInfo);
  266.     if (fxinfo)
  267.         write(fd, Mac2HostAddr(fxinfo), SIZEOF_FXInfo);
  268.     close(fd);
  269. }
  270.  
  271.  
  272. /*
  273.  *  Resource fork emulation functions
  274.  */
  275.  
  276. uint32 get_rfork_size(const char *path)
  277. {
  278.     // Open resource file
  279.     int fd = open_rsrc(path, O_RDONLY);
  280.     if (fd < 0)
  281.         return 0;
  282.  
  283.     // Get size
  284.     off_t size = lseek(fd, 0, SEEK_END);
  285.     
  286.     // Close file and return size
  287.     close(fd);
  288.     return size < 0 ? 0 : size;
  289. }
  290.  
  291. int open_rfork(const char *path, int flag)
  292. {
  293.     return open_rsrc(path, flag);
  294. }
  295.  
  296. void close_rfork(const char *path, int fd)
  297. {
  298.     close(fd);
  299. }
  300.  
  301.  
  302. /*
  303.  *  Read "length" bytes from file to "buffer",
  304.  *  returns number of bytes read (or -1 on error)
  305.  */
  306.  
  307. ssize_t extfs_read(int fd, void *buffer, size_t length)
  308. {
  309.     return read(fd, buffer, length);
  310. }
  311.  
  312.  
  313. /*
  314.  *  Write "length" bytes from "buffer" to file,
  315.  *  returns number of bytes written (or -1 on error)
  316.  */
  317.  
  318. ssize_t extfs_write(int fd, void *buffer, size_t length)
  319. {
  320.     return write(fd, buffer, length);
  321. }
  322.  
  323.  
  324. /*
  325.  *  Remove file/directory (and associated helper files),
  326.  *  returns false on error (and sets errno)
  327.  */
  328.  
  329. bool extfs_remove(const char *path)
  330. {
  331.     // Remove helpers first, don't complain if this fails
  332.     char helper_path[MAX_PATH_LENGTH];
  333.     make_helper_path(path, helper_path, ".finf/", false);
  334.     remove(helper_path);
  335.     make_helper_path(path, helper_path, ".rsrc/", false);
  336.     remove(helper_path);
  337.  
  338.     // Now remove file or directory (and helper directories in the directory)
  339.     if (remove(path) < 0) {
  340.         if (errno == EISDIR || errno == ENOTEMPTY) {
  341.             helper_path[0] = 0;
  342.             strncpy(helper_path, path, MAX_PATH_LENGTH-1);
  343.             add_path_component(helper_path, ".finf");
  344.             rmdir(helper_path);
  345.             helper_path[0] = 0;
  346.             strncpy(helper_path, path, MAX_PATH_LENGTH-1);
  347.             add_path_component(helper_path, ".rsrc");
  348.             rmdir(helper_path);
  349.             return rmdir(path) == 0;
  350.         } else
  351.             return false;
  352.     }
  353.     return true;
  354. }
  355.  
  356.  
  357. /*
  358.  *  Rename/move file/directory (and associated helper files),
  359.  *  returns false on error (and sets errno)
  360.  */
  361.  
  362. bool extfs_rename(const char *old_path, const char *new_path)
  363. {
  364.     // Rename helpers first, don't complain if this fails
  365.     char old_helper_path[MAX_PATH_LENGTH], new_helper_path[MAX_PATH_LENGTH];
  366.     make_helper_path(old_path, old_helper_path, ".finf/", false);
  367.     make_helper_path(new_path, new_helper_path, ".finf/", false);
  368.     create_helper_dir(new_path, ".finf/");
  369.     rename(old_helper_path, new_helper_path);
  370.     make_helper_path(old_path, old_helper_path, ".rsrc/", false);
  371.     make_helper_path(new_path, new_helper_path, ".rsrc/", false);
  372.     create_helper_dir(new_path, ".rsrc/");
  373.     rename(old_helper_path, new_helper_path);
  374.  
  375.     // Now rename file
  376.     return rename(old_path, new_path) == 0;
  377. }
  378.