support for cadius / nulib2 resource forks

This commit is contained in:
Kelvin Sherlock 2017-07-23 14:04:11 -04:00
parent 4a8fd4d9e8
commit faec01b209
2 changed files with 132 additions and 43 deletions

View File

@ -94,6 +94,97 @@ void throw_errno(const std::string &what) {
}
void write_resource_fork(const std::string &parent_path, int parent_fd, void *data, size_t size) {
#ifdef __sun__
int rfd = openat(parent_fd, XATTR_RESOURCEFORK_NAME, O_XATTR | O_CREAT | O_TRUNC | O_WRONLY, 0666);
if (rfd < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
defer close_fd([rfd](){ close(rfd); });
if (!size) return;
ssize_t ok = write(rfd, data, size);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
#ifdef _WIN32
std::string tmp = parent_path + ":" XATTR_RESOURCEFORK_NAME;
int rfd = open(tmp.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (rfd < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
defer close_fd([rfd](){ close(rfd); });
if (!size) return;
int ok = write(rfd, data, size);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
#ifdef __linux__
int ok = fsetxattr(parent_fd, XATTR_RESOURCEFORK_NAME, data, size, 0);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
#ifdef __APPLE__
int ok;
ok = fremovexattr(parent_fd, XATTR_RESOURCEFORK_NAME, 0);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
if (!size) return;
ok = fsetxattr(parent_fd, XATTR_RESOURCEFORK_NAME, data, size, 0, XATTR_CREATE);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
}
/*
* resource is straight data (cadius, nulib2, etc)
*/
void one_flat_file(const std::string &data, const std::string rsrc) noexcept try {
struct stat rsrc_st;
int ok;
if (_v) fprintf(stdout, "Merging %s & %s\n", rsrc.c_str(), data.c_str());
ok = stat(data.c_str(), &rsrc_st);
if (ok < 0) {
if (errno == ENOENT) {
if (_n) unlink_list.push_back(rsrc);
return;
}
throw_errno("stat");
}
// don't try to do directories.
if (S_ISDIR(rsrc_st.st_mode)) {
if (!_p) unlink_list.push_back(rsrc);
return;
}
int fd = open(data.c_str(), O_RDONLY | O_BINARY);
if (fd < 0) {
if (errno == ENOENT) {
if (_n) unlink_list.push_back(rsrc);
return;
}
throw_errno("open");
}
defer close_fd([fd]{close(fd); });
if (stat(rsrc.c_str(), &rsrc_st) < 0) throw_errno("stat");
if (rsrc_st.st_size == 0) {
// truncate any existing resource fork.
write_resource_fork(data, fd, nullptr, 0);
if (!_p) unlink_list.push_back(rsrc);
return;
}
mapped_file mf(rsrc, mapped_file::readonly, rsrc_st.st_size);
write_resource_fork(data, fd, mf.data(), mf.size());
if (!_p) unlink_list.push_back(rsrc);
} catch (const std::exception &ex) {
_rv = 1;
fprintf(stderr, "Merging %s failed: %s\n", rsrc.c_str(), ex.what());
}
void one_file(const std::string &data, const std::string &rsrc) noexcept try {
struct stat rsrc_st;
@ -202,36 +293,7 @@ void one_file(const std::string &data, const std::string &rsrc) noexcept try {
}
#endif
case AS_RESOURCE: {
#ifdef __sun__
int rfd = openat(fd, XATTR_RESOURCEFORK_NAME, O_XATTR | O_CREAT | O_TRUNC | O_WRONLY, 0666);
if (rfd < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
defer close_fd([rfd](){ close(rfd); });
ssize_t ok = write(rfd, mf.data() + e.entryOffset, e.entryLength);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
//if (ok != e.entryLength) return -1;
#endif
#ifdef _WIN32
std::string tmp = data + ":" XATTR_RESOURCEFORK_NAME;
int rfd = open(tmp.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
if (rfd < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
defer close_fd([rfd](){ close(rfd); });
int ok = write(rfd, mf.data() + e.entryOffset, e.entryLength);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
#ifdef __linux__
int ok = fsetxattr(fd, XATTR_RESOURCEFORK_NAME, mf.data() + e.entryOffset, e.entryLength, 0);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
#ifdef __APPLE__
int ok;
ok = fremovexattr(fd, XATTR_RESOURCEFORK_NAME, 0);
ok = fsetxattr(fd, XATTR_RESOURCEFORK_NAME, mf.data() + e.entryOffset, e.entryLength, 0, XATTR_CREATE);
if (ok < 0) throw_errno(XATTR_RESOURCEFORK_NAME);
#endif
write_resource_fork(data, fd, mf.data()+ e.entryOffset, e.entryLength);
break;
}
@ -281,6 +343,18 @@ void unlink_files(std::vector<std::string> &unlink_list) {
unlink_list.clear();
}
std::string is_raw_resource_fork(const std::string &s) {
auto l = s.length();
if (l > 17 && !strncmp("_ResourceFork.bin", s.data() + l - 17, 17))
return s.substr(0, l - 17);
if (l > 6 && !strncmp("_rsrc_", s.data() + l - 6, 6))
return s.substr(0, l - 6);
return "";
}
void one_dir(std::string dir) noexcept {
DIR *dirp;
@ -340,23 +414,38 @@ void one_dir(std::string dir) noexcept {
}
}
if (name.length() > 2 && name[0] == '.' && name[1] == '_') {
one_file(dir + name.substr(2), dir + name);
continue;
}
/* _ResourceFork.bin or _rsrc_ raw resource data . */
std::string tmp = is_raw_resource_fork(name);
if (!tmp.empty()) {
one_flat_file(dir + tmp, dir + name);
continue;
}
if (!_f && name[0] != '.') {
std::string tmp = dir + name;
#ifdef DT_DIR
if (dp->d_type == DT_DIR)
if (dp->d_type == DT_DIR) {
dir_list.push_back(tmp);
continue;
}
#else
struct stat st;
if (stat(tmp.c_str(), &st) == 0 && S_ISDIR(st.st_mode))
if (stat(tmp.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
dir_list.push_back(tmp);
continue;
}
#endif
}
}
closedir(dirp);
} else {

View File

@ -55,17 +55,17 @@ namespace {
ProDOS Macintosh
File Type Auxiliary Type Creator Type File Type
$00 $0000 pdos BINA
$04 (TXT) $0000 pdos TEXT
$FF (SYS) (any) pdos PSYS
$B3 (S16) $DByz pdos p $B3 $DB $yz
$B3 (S16) (any) pdos PS16
$D7 $0000 pdos MIDI
$D8 $0000 pdos AIFF
$D8 $0001 pdos AIFC
$E0 $0005 dCpy dImg
$FF (SYS) (any) pdos PSYS
$uv $wxyz pdos p $uv $wx $yz
$00 $0000 'pdos' 'BINA'
$04 (TXT) $0000 'pdos' 'TEXT'
$FF (SYS) (any) 'pdos' 'PSYS'
$B3 (S16) $DByz 'pdos' 'p' $B3 $DB $yz
$B3 (S16) (any) 'pdos' 'PS16'
$D7 $0000 'pdos' 'MIDI'
$D8 $0000 'pdos' 'AIFF'
$D8 $0001 'pdos' 'AIFC'
$E0 $0005 'dCpy' 'dImg'
$FF (SYS) (any) 'pdos' 'PSYS'
$uv $wxyz 'pdos' 'p' $uv $wx $yz
mpw standard: