* Implemented attribute handling - you can change them, but they are not stored yet.
* Implemented CDDB ID computation (that's what BeOS's cdda-fs is using). * Some other minor changes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21144 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -7,4 +7,5 @@ UsePrivateHeaders [ FDirName storage ] ;
|
|||||||
KernelAddon cdda :
|
KernelAddon cdda :
|
||||||
kernel_interface.cpp
|
kernel_interface.cpp
|
||||||
cdda.cpp
|
cdda.cpp
|
||||||
|
cddb.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ is_garbage(char c)
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
sanitize_string(char *string)
|
sanitize_string(char *&string)
|
||||||
{
|
{
|
||||||
if (string == NULL)
|
if (string == NULL)
|
||||||
return;
|
return;
|
||||||
@@ -78,6 +78,12 @@ sanitize_string(char *string)
|
|||||||
while (length > 1 && isspace(string[length - 1])) {
|
while (length > 1 && isspace(string[length - 1])) {
|
||||||
string[--length] = '\0';
|
string[--length] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!string[0]) {
|
||||||
|
// free string if it's empty
|
||||||
|
free(string);
|
||||||
|
string = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -127,7 +133,13 @@ sanitize_album(cdtext &text)
|
|||||||
cut_string(text.album, text.artist);
|
cut_string(text.album, text.artist);
|
||||||
sanitize_string(text.album);
|
sanitize_string(text.album);
|
||||||
|
|
||||||
if ((text.artist == NULL || !text.artist[0]) && text.album != NULL) {
|
if (text.album != NULL && !strcasecmp(text.album, "My CD")) {
|
||||||
|
// don't laugh, people really do that!
|
||||||
|
free(text.album);
|
||||||
|
text.album = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((text.artist == NULL || text.artist[0] == NULL) && text.album != NULL) {
|
||||||
// try to extract artist from album
|
// try to extract artist from album
|
||||||
char *space = strstr(text.album, " ");
|
char *space = strstr(text.album, " ");
|
||||||
if (space != NULL) {
|
if (space != NULL) {
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "cddb.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int32
|
||||||
|
cddb_sum(int32 n)
|
||||||
|
{
|
||||||
|
int32 result = 0;
|
||||||
|
|
||||||
|
while (n > 0) {
|
||||||
|
result = result + (n % 10);
|
||||||
|
n = n / 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - exported functions
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Computes the CD Disc ID as specified in the FreeDB how-to (code taken from there).
|
||||||
|
*/
|
||||||
|
uint32
|
||||||
|
compute_cddb_disc_id(scsi_toc_toc &toc)
|
||||||
|
{
|
||||||
|
int32 numTracks = toc.last_track + 1 - toc.first_track;
|
||||||
|
uint32 n = 0;
|
||||||
|
|
||||||
|
for (int32 i = 0; i < numTracks; i++) {
|
||||||
|
n = n + cddb_sum((toc.tracks[i].start.time.minute * 60)
|
||||||
|
+ toc.tracks[i].start.time.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 t = ((toc.tracks[numTracks].start.time.minute * 60)
|
||||||
|
+ toc.tracks[numTracks].start.time.second)
|
||||||
|
- ((toc.tracks[0].start.time.minute * 60)
|
||||||
|
+ toc.tracks[0].start.time.second);
|
||||||
|
|
||||||
|
return (n % 0xff) << 24 | t << 8 | numTracks;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef CDDB_H
|
||||||
|
#define CDDB_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <bus/scsi/scsi_cmds.h>
|
||||||
|
|
||||||
|
|
||||||
|
uint32 compute_cddb_disc_id(scsi_toc_toc &toc);
|
||||||
|
|
||||||
|
#endif // CDDB_H
|
||||||
@@ -10,8 +10,11 @@
|
|||||||
#include <fs_info.h>
|
#include <fs_info.h>
|
||||||
#include <fs_interface.h>
|
#include <fs_interface.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <Mime.h>
|
||||||
|
#include <TypeConstants.h>
|
||||||
|
|
||||||
#include <util/kernel_cpp.h>
|
#include <util/kernel_cpp.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -29,10 +32,14 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
class Volume;
|
class Attribute;
|
||||||
class Inode;
|
class Inode;
|
||||||
|
struct attr_cookie;
|
||||||
struct dir_cookie;
|
struct dir_cookie;
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<Attribute> AttributeList;
|
||||||
|
typedef DoublyLinkedList<attr_cookie> AttrCookieList;
|
||||||
|
|
||||||
class Volume {
|
class Volume {
|
||||||
public:
|
public:
|
||||||
Volume(mount_id id);
|
Volume(mount_id id);
|
||||||
@@ -73,6 +80,29 @@ class Volume {
|
|||||||
Inode *fFirstEntry;
|
Inode *fFirstEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Attribute : public DoublyLinkedListLinkImpl<Attribute> {
|
||||||
|
public:
|
||||||
|
Attribute(const char *name, type_code type);
|
||||||
|
~Attribute();
|
||||||
|
|
||||||
|
status_t InitCheck() const { return fName != NULL ? B_OK : B_NO_MEMORY; }
|
||||||
|
status_t SetTo(const char *name, type_code type);
|
||||||
|
void SetType(type_code type) { fType = type; }
|
||||||
|
|
||||||
|
status_t ReadAt(off_t offset, uint8 *buffer, size_t *_length);
|
||||||
|
status_t WriteAt(off_t offset, const uint8 *buffer, size_t *_length);
|
||||||
|
void Truncate();
|
||||||
|
|
||||||
|
const char *Name() const { return fName; }
|
||||||
|
size_t Size() const { return fSize; }
|
||||||
|
type_code Type() const { return fType; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
char *fName;
|
||||||
|
type_code fType;
|
||||||
|
uint8 *fData;
|
||||||
|
size_t fSize;
|
||||||
|
};
|
||||||
|
|
||||||
class Inode {
|
class Inode {
|
||||||
public:
|
public:
|
||||||
@@ -103,6 +133,18 @@ class Inode {
|
|||||||
off_t Size() const
|
off_t Size() const
|
||||||
{ return fFrameCount * kFrameSize /* + WAV header */; }
|
{ return fFrameCount * kFrameSize /* + WAV header */; }
|
||||||
|
|
||||||
|
Attribute *FindAttribute(const char *name) const;
|
||||||
|
status_t AddAttribute(const char *name, type_code type,
|
||||||
|
const uint8 *data = 0, size_t length = 0);
|
||||||
|
status_t AddAttribute(const char *name, type_code type,
|
||||||
|
const char *string);
|
||||||
|
status_t AddAttribute(const char *name, int32 value);
|
||||||
|
status_t RemoveAttribute(const char *name);
|
||||||
|
|
||||||
|
void AddAttrCookie(attr_cookie *cookie);
|
||||||
|
void RemoveAttrCookie(attr_cookie *cookie);
|
||||||
|
void RewindAttrCookie(attr_cookie *cookie);
|
||||||
|
|
||||||
Inode *Next() const { return fNext; }
|
Inode *Next() const { return fNext; }
|
||||||
void SetNext(Inode *inode) { fNext = inode; }
|
void SetNext(Inode *inode) { fNext = inode; }
|
||||||
|
|
||||||
@@ -117,12 +159,13 @@ class Inode {
|
|||||||
time_t fModificationTime;
|
time_t fModificationTime;
|
||||||
off_t fStartFrame;
|
off_t fStartFrame;
|
||||||
off_t fFrameCount;
|
off_t fFrameCount;
|
||||||
|
AttributeList fAttributes;
|
||||||
|
AttrCookieList fAttrCookies;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct dir_cookie {
|
struct dir_cookie {
|
||||||
Inode *current;
|
Inode *current;
|
||||||
int state; // iteration state
|
int state; // iteration state
|
||||||
};
|
};
|
||||||
|
|
||||||
// directory iteration states
|
// directory iteration states
|
||||||
@@ -133,8 +176,12 @@ enum {
|
|||||||
ITERATION_STATE_BEGIN = ITERATION_STATE_DOT,
|
ITERATION_STATE_BEGIN = ITERATION_STATE_DOT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct attr_cookie : DoublyLinkedListLinkImpl<attr_cookie> {
|
||||||
|
Attribute *current;
|
||||||
|
};
|
||||||
|
|
||||||
struct file_cookie {
|
struct file_cookie {
|
||||||
int open_mode;
|
int open_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -212,6 +259,7 @@ Volume::Mount(const char* device)
|
|||||||
scsi_cd_msf& next = toc->tracks[i + 1].start.time;
|
scsi_cd_msf& next = toc->tracks[i + 1].start.time;
|
||||||
// the last track is always lead-out
|
// the last track is always lead-out
|
||||||
scsi_cd_msf& start = toc->tracks[i].start.time;
|
scsi_cd_msf& start = toc->tracks[i].start.time;
|
||||||
|
int32 track = i + 1;
|
||||||
|
|
||||||
off_t startFrame = start.minute * kFramesPerMinute
|
off_t startFrame = start.minute * kFramesPerMinute
|
||||||
+ start.second * kFramesPerSecond + start.frame;
|
+ start.second * kFramesPerSecond + start.frame;
|
||||||
@@ -219,18 +267,43 @@ Volume::Mount(const char* device)
|
|||||||
+ next.second * kFramesPerSecond + next.frame
|
+ next.second * kFramesPerSecond + next.frame
|
||||||
- startFrame;
|
- startFrame;
|
||||||
|
|
||||||
if (text.titles[i] != NULL && text.titles[i]) {
|
const char *artist = text.artists[i] != NULL
|
||||||
if (text.artists[i] != NULL && text.artists[i]) {
|
? text.artists[i] : text.artist;
|
||||||
snprintf(title, sizeof(title), "%02ld. %s - %s.wav", i + 1,
|
|
||||||
|
if (text.titles[i] != NULL) {
|
||||||
|
if (artist != NULL) {
|
||||||
|
snprintf(title, sizeof(title), "%02ld. %s - %s.wav", track,
|
||||||
text.artists[i], text.titles[i]);
|
text.artists[i], text.titles[i]);
|
||||||
} else {
|
} else {
|
||||||
snprintf(title, sizeof(title), "%02ld. %s.wav", i + 1,
|
snprintf(title, sizeof(title), "%02ld. %s.wav", track,
|
||||||
text.titles[i]);
|
text.titles[i]);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
snprintf(title, sizeof(title), "%02ld.wav", i + 1);
|
snprintf(title, sizeof(title), "%02ld.wav", track);
|
||||||
|
|
||||||
_CreateNode(fRootNode, title, startFrame, frames, S_IFREG | 0444);
|
// remove '/' from title
|
||||||
|
for (int32 j = 0; title[j]; j++) {
|
||||||
|
if (title[j] == '/')
|
||||||
|
title[j] = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
Inode *inode = _CreateNode(fRootNode, title, startFrame, frames,
|
||||||
|
S_IFREG | 0444);
|
||||||
|
if (inode == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// add attributes
|
||||||
|
|
||||||
|
inode->AddAttribute("Audio:Artist", B_STRING_TYPE, artist);
|
||||||
|
inode->AddAttribute("Audio:Title", B_STRING_TYPE, text.titles[i]);
|
||||||
|
inode->AddAttribute("Audio:Genre", B_STRING_TYPE, text.genre);
|
||||||
|
inode->AddAttribute("Audio:Track", track);
|
||||||
|
|
||||||
|
snprintf(title, sizeof(title), "%02lu:%02lu",
|
||||||
|
uint32(inode->FrameCount() / kFramesPerMinute),
|
||||||
|
uint32((inode->FrameCount() % kFramesPerMinute) / kFramesPerSecond));
|
||||||
|
inode->AddAttribute("Audio:Length", B_STRING_TYPE, title);
|
||||||
|
inode->AddAttribute("BEOS:TYPE", B_MIME_STRING_TYPE, "audio/x-wav");
|
||||||
}
|
}
|
||||||
|
|
||||||
free(toc);
|
free(toc);
|
||||||
@@ -330,6 +403,116 @@ Volume::SetName(const char *name)
|
|||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
Attribute::Attribute(const char *name, type_code type)
|
||||||
|
:
|
||||||
|
fName(NULL),
|
||||||
|
fType(0),
|
||||||
|
fData(NULL),
|
||||||
|
fSize(0)
|
||||||
|
{
|
||||||
|
SetTo(name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Attribute::~Attribute()
|
||||||
|
{
|
||||||
|
free(fName);
|
||||||
|
free(fData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Attribute::SetTo(const char *name, type_code type)
|
||||||
|
{
|
||||||
|
if (name == NULL || !name[0])
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
name = strdup(name);
|
||||||
|
if (name == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
free(fName);
|
||||||
|
|
||||||
|
fName = (char *)name;
|
||||||
|
fType = type;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Attribute::ReadAt(off_t offset, uint8 *buffer, size_t *_length)
|
||||||
|
{
|
||||||
|
size_t length = *_length;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (offset >= length) {
|
||||||
|
*_length = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
if (offset + length > fSize)
|
||||||
|
length = fSize - offset;
|
||||||
|
|
||||||
|
if (user_memcpy(buffer, fData + offset, length) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
*_length = length;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Attribute::WriteAt(off_t offset, const uint8 *buffer, size_t *_length)
|
||||||
|
{
|
||||||
|
size_t length = *_length;
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
// we limit the attribute size to something reasonable
|
||||||
|
off_t end = offset + length;
|
||||||
|
if (end > 65536) {
|
||||||
|
end = 65536;
|
||||||
|
length = end - offset;
|
||||||
|
}
|
||||||
|
if (offset > end) {
|
||||||
|
*_length = 0;
|
||||||
|
return E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (end > fSize) {
|
||||||
|
// make room in the data stream
|
||||||
|
uint8 *data = (uint8 *)realloc(fData, end);
|
||||||
|
if (data == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (fSize < offset)
|
||||||
|
memset(data + fSize, 0, offset - fSize);
|
||||||
|
|
||||||
|
fData = data;
|
||||||
|
fSize = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (user_memcpy(fData + offset, buffer, length) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
|
||||||
|
*_length = length;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Attribute::Truncate()
|
||||||
|
{
|
||||||
|
free(fData);
|
||||||
|
fData = NULL;
|
||||||
|
fSize = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
Inode::Inode(Volume *volume, Inode *parent, const char *name, off_t start,
|
Inode::Inode(Volume *volume, Inode *parent, const char *name, off_t start,
|
||||||
off_t frames, int32 type)
|
off_t frames, int32 type)
|
||||||
:
|
:
|
||||||
@@ -383,6 +566,150 @@ Inode::SetName(const char* name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Attribute *
|
||||||
|
Inode::FindAttribute(const char *name) const
|
||||||
|
{
|
||||||
|
if (name == NULL || !name[0])
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
AttributeList::ConstIterator iterator = fAttributes.GetIterator();
|
||||||
|
|
||||||
|
while (iterator.HasNext()) {
|
||||||
|
Attribute *attribute = iterator.Next();
|
||||||
|
if (!strcmp(attribute->Name(), name))
|
||||||
|
return attribute;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::AddAttribute(const char *name, type_code type,
|
||||||
|
const uint8 *data, size_t length)
|
||||||
|
{
|
||||||
|
if (FindAttribute(name) != NULL)
|
||||||
|
return B_NAME_IN_USE;
|
||||||
|
|
||||||
|
Attribute *attribute = new Attribute(name, type);
|
||||||
|
status_t status = attribute != NULL ? B_OK : B_NO_MEMORY;
|
||||||
|
if (status == B_OK)
|
||||||
|
status = attribute->InitCheck();
|
||||||
|
if (status == B_OK && data != NULL && length != 0)
|
||||||
|
status = attribute->WriteAt(0, data, &length);
|
||||||
|
if (status < B_OK) {
|
||||||
|
delete attribute;
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
fAttributes.Add(attribute);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::AddAttribute(const char *name, type_code type,
|
||||||
|
const char *string)
|
||||||
|
{
|
||||||
|
if (string == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return AddAttribute(name, type, (const uint8 *)string,
|
||||||
|
strlen(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::AddAttribute(const char *name, int32 value)
|
||||||
|
{
|
||||||
|
return AddAttribute(name, B_INT32_TYPE, (const uint8 *)&value,
|
||||||
|
sizeof(int32));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
Inode::RemoveAttribute(const char *name)
|
||||||
|
{
|
||||||
|
if (name == NULL || !name[0])
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
AttributeList::Iterator iterator = fAttributes.GetIterator();
|
||||||
|
|
||||||
|
while (iterator.HasNext()) {
|
||||||
|
Attribute *attribute = iterator.Next();
|
||||||
|
if (!strcmp(attribute->Name(), name)) {
|
||||||
|
// look for attribute in cookies
|
||||||
|
AttrCookieList::Iterator i = fAttrCookies.GetIterator();
|
||||||
|
while (i.HasNext()) {
|
||||||
|
attr_cookie *cookie = i.Next();
|
||||||
|
if (cookie->current == attribute)
|
||||||
|
cookie->current = attribute->GetDoublyLinkedListLink()->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator.Remove();
|
||||||
|
delete attribute;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Inode::AddAttrCookie(attr_cookie *cookie)
|
||||||
|
{
|
||||||
|
fAttrCookies.Add(cookie);
|
||||||
|
RewindAttrCookie(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Inode::RemoveAttrCookie(attr_cookie *cookie)
|
||||||
|
{
|
||||||
|
fAttrCookies.Remove(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Inode::RewindAttrCookie(attr_cookie *cookie)
|
||||||
|
{
|
||||||
|
cookie->current = fAttributes.First();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
fill_stat_buffer(Volume *volume, Inode *inode, Attribute *attribute,
|
||||||
|
struct stat &stat)
|
||||||
|
{
|
||||||
|
stat.st_dev = volume->ID();
|
||||||
|
stat.st_ino = inode->ID();
|
||||||
|
|
||||||
|
if (attribute != NULL) {
|
||||||
|
stat.st_size = attribute->Size();
|
||||||
|
stat.st_mode = S_ATTR | 0666;
|
||||||
|
stat.st_type = attribute->Type();
|
||||||
|
} else {
|
||||||
|
stat.st_size = inode->Size();
|
||||||
|
stat.st_mode = inode->Type();
|
||||||
|
stat.st_type = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stat.st_nlink = 1;
|
||||||
|
stat.st_blksize = 2048;
|
||||||
|
|
||||||
|
stat.st_uid = inode->UserID();
|
||||||
|
stat.st_gid = inode->GroupID();
|
||||||
|
|
||||||
|
stat.st_atime = time(NULL);
|
||||||
|
stat.st_mtime = stat.st_ctime = inode->ModificationTime();
|
||||||
|
stat.st_crtime = inode->CreationTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - module API
|
// #pragma mark - module API
|
||||||
|
|
||||||
|
|
||||||
@@ -636,21 +963,7 @@ cdda_read_stat(fs_volume _volume, fs_vnode _node, struct stat *stat)
|
|||||||
|
|
||||||
TRACE(("cdda_read_stat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(), stat));
|
TRACE(("cdda_read_stat: vnode %p (0x%Lx), stat %p\n", inode, inode->ID(), stat));
|
||||||
|
|
||||||
stat->st_dev = volume->ID();
|
fill_stat_buffer(volume, inode, NULL, *stat);
|
||||||
stat->st_ino = inode->ID();
|
|
||||||
|
|
||||||
stat->st_size = inode->Size();
|
|
||||||
stat->st_mode = inode->Type();
|
|
||||||
|
|
||||||
stat->st_nlink = 1;
|
|
||||||
stat->st_blksize = 2048;
|
|
||||||
|
|
||||||
stat->st_uid = inode->UserID();
|
|
||||||
stat->st_gid = inode->GroupID();
|
|
||||||
|
|
||||||
stat->st_atime = time(NULL);
|
|
||||||
stat->st_mtime = stat->st_ctime = inode->ModificationTime();
|
|
||||||
stat->st_crtime = inode->CreationTime();
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -813,6 +1126,228 @@ cdda_free_dir_cookie(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - attribute functions
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_open_attr_dir(fs_volume _volume, fs_vnode _vnode, fs_cookie *_cookie)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_vnode;
|
||||||
|
|
||||||
|
attr_cookie *cookie = new attr_cookie;
|
||||||
|
if (cookie == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
inode->AddAttrCookie(cookie);
|
||||||
|
*_cookie = cookie;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_close_attr_dir(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_free_attr_dir_cookie(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_vnode;
|
||||||
|
attr_cookie *cookie = (attr_cookie *)_cookie;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
inode->RemoveAttrCookie(cookie);
|
||||||
|
delete cookie;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_rewind_attr_dir(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_vnode;
|
||||||
|
attr_cookie *cookie = (attr_cookie *)_cookie;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
inode->RewindAttrCookie(cookie);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_read_attr_dir(fs_volume _volume, fs_vnode _vnode, fs_cookie _cookie,
|
||||||
|
struct dirent *dirent, size_t bufferSize, uint32 *_num)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_vnode;
|
||||||
|
attr_cookie *cookie = (attr_cookie *)_cookie;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
Attribute *attribute = cookie->current;
|
||||||
|
|
||||||
|
if (attribute == NULL) {
|
||||||
|
*_num = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t length = strlcpy(dirent->d_name, attribute->Name(), bufferSize);
|
||||||
|
dirent->d_dev = volume->ID();
|
||||||
|
dirent->d_ino = inode->ID();
|
||||||
|
dirent->d_reclen = sizeof(struct dirent) + length;
|
||||||
|
|
||||||
|
cookie->current = attribute->GetDoublyLinkedListLink()->next;
|
||||||
|
*_num = 1;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_create_attr(fs_volume _volume, fs_vnode _node, const char *name,
|
||||||
|
uint32 type, int openMode, fs_cookie *_cookie)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
Attribute *attribute = inode->FindAttribute(name);
|
||||||
|
if (attribute == NULL) {
|
||||||
|
status_t status = inode->AddAttribute(name, type);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
} else if ((openMode & O_EXCL) == 0) {
|
||||||
|
attribute->SetType(type);
|
||||||
|
} else
|
||||||
|
return B_FILE_EXISTS;
|
||||||
|
|
||||||
|
*_cookie = strdup(name);
|
||||||
|
if (*_cookie == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_open_attr(fs_volume _volume, fs_vnode _node, const char *name,
|
||||||
|
int openMode, fs_cookie *_cookie)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
Attribute *attribute = inode->FindAttribute(name);
|
||||||
|
if (attribute == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
*_cookie = strdup(name);
|
||||||
|
if (*_cookie == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_close_attr(fs_volume _fs, fs_vnode _file, fs_cookie cookie)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_free_attr_cookie(fs_volume _fs, fs_vnode _file, fs_cookie cookie)
|
||||||
|
{
|
||||||
|
free(cookie);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_read_attr(fs_volume _volume, fs_vnode _node, fs_cookie _cookie,
|
||||||
|
off_t offset, void *buffer, size_t *_length)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
Attribute *attribute = inode->FindAttribute((const char *)_cookie);
|
||||||
|
if (attribute == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
return attribute->ReadAt(offset, (uint8 *)buffer, _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_write_attr(fs_volume _volume, fs_vnode _file, fs_cookie _cookie,
|
||||||
|
off_t offset, const void *buffer, size_t *_length)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_file;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
Attribute *attribute = inode->FindAttribute((const char *)_cookie);
|
||||||
|
if (attribute == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
return attribute->WriteAt(offset, (uint8 *)buffer, _length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_read_attr_stat(fs_volume _volume, fs_vnode _file, fs_cookie _cookie,
|
||||||
|
struct stat *stat)
|
||||||
|
{
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_file;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
Attribute *attribute = inode->FindAttribute((const char *)_cookie);
|
||||||
|
if (attribute == NULL)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
fill_stat_buffer(volume, inode, attribute, *stat);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_write_attr_stat(fs_volume _volume, fs_vnode file, fs_cookie cookie,
|
||||||
|
const struct stat *stat, int statMask)
|
||||||
|
{
|
||||||
|
return EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
cdda_remove_attr(fs_volume _volume, fs_vnode _node, const char *name)
|
||||||
|
{
|
||||||
|
if (name == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
Volume *volume = (Volume *)_volume;
|
||||||
|
Inode *inode = (Inode *)_node;
|
||||||
|
|
||||||
|
Locker _(volume->Lock());
|
||||||
|
|
||||||
|
return inode->RemoveAttribute(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
cdda_std_ops(int32 op, ...)
|
cdda_std_ops(int32 op, ...)
|
||||||
{
|
{
|
||||||
@@ -873,7 +1408,7 @@ static file_system_module_info sCDDAFileSystem = {
|
|||||||
NULL, // fs_symlink()
|
NULL, // fs_symlink()
|
||||||
NULL, // fs_link()
|
NULL, // fs_link()
|
||||||
NULL, // fs_unlink()
|
NULL, // fs_unlink()
|
||||||
NULL, // fs_rename()
|
&cdda_rename,
|
||||||
|
|
||||||
NULL, // fs_access()
|
NULL, // fs_access()
|
||||||
&cdda_read_stat,
|
&cdda_read_stat,
|
||||||
@@ -896,7 +1431,6 @@ static file_system_module_info sCDDAFileSystem = {
|
|||||||
&cdda_read_dir,
|
&cdda_read_dir,
|
||||||
&cdda_rewind_dir,
|
&cdda_rewind_dir,
|
||||||
|
|
||||||
#if 0
|
|
||||||
// attribute directory operations
|
// attribute directory operations
|
||||||
&cdda_open_attr_dir,
|
&cdda_open_attr_dir,
|
||||||
&cdda_close_attr_dir,
|
&cdda_close_attr_dir,
|
||||||
@@ -914,9 +1448,8 @@ static file_system_module_info sCDDAFileSystem = {
|
|||||||
|
|
||||||
&cdda_read_attr_stat,
|
&cdda_read_attr_stat,
|
||||||
&cdda_write_attr_stat,
|
&cdda_write_attr_stat,
|
||||||
&cdda_rename_attr,
|
NULL, // fs_rename_attr()
|
||||||
&cdda_remove_attr,
|
&cdda_remove_attr,
|
||||||
#endif
|
|
||||||
|
|
||||||
// the other operations are not yet supported (indices, queries)
|
// the other operations are not yet supported (indices, queries)
|
||||||
NULL,
|
NULL,
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ SimpleTest cdda_text
|
|||||||
:
|
:
|
||||||
cdda_text.cpp
|
cdda_text.cpp
|
||||||
cdda.cpp
|
cdda.cpp
|
||||||
|
cddb.cpp
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include "cdda.h"
|
#include "cdda.h"
|
||||||
|
#include "cddb.h"
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -36,7 +37,8 @@ main(int argc, char** argv)
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
uint8 buffer[1024];
|
uint8 buffer[1024];
|
||||||
if (read_table_of_contents(fd, (scsi_toc_toc*)buffer, sizeof(buffer)) < 0) {
|
scsi_toc_toc *toc = (scsi_toc_toc *)buffer;
|
||||||
|
if (read_table_of_contents(fd, toc, sizeof(buffer)) < 0) {
|
||||||
fprintf(stderr, "%s: Retrieving TOC failed", __progname);
|
fprintf(stderr, "%s: Retrieving TOC failed", __progname);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -44,5 +46,8 @@ main(int argc, char** argv)
|
|||||||
cdtext text;
|
cdtext text;
|
||||||
read_cdtext(fd, text);
|
read_cdtext(fd, text);
|
||||||
|
|
||||||
|
uint32 id = compute_cddb_disc_id(*toc);
|
||||||
|
printf("CDDB disc ID: %lx\n", id);
|
||||||
|
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user