Open/close attribute support for xattrs backend
For the xattr/BSD (untyped) attribute backend implement fs_fopen_attr() and fs_close_attr(). A new AttributeDescriptor is created. It is currently used in write_pos() only.
This commit is contained in:
+62
-49
@@ -130,17 +130,17 @@ normalize_dir_path(string path, NodeRef ref, string &normalizedPath)
|
|||||||
status_t error = find_dir_entry(path.c_str(), ref, name, true) ;
|
status_t error = find_dir_entry(path.c_str(), ref, name, true) ;
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// recurse to get the parent dir path, if found
|
// recurse to get the parent dir path, if found
|
||||||
error = normalize_dir_path(path, parentRef, normalizedPath);
|
error = normalize_dir_path(path, parentRef, normalizedPath);
|
||||||
if (error != 0)
|
if (error != 0)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// construct the normalizedPath
|
// construct the normalizedPath
|
||||||
if (normalizedPath.length() > 1) // don't append "/", if parent is root
|
if (normalizedPath.length() > 1) // don't append "/", if parent is root
|
||||||
normalizedPath += '/';
|
normalizedPath += '/';
|
||||||
normalizedPath += name;
|
normalizedPath += name;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,7 +152,7 @@ normalize_dir_path(const char *path, string &normalizedPath)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (stat(path, &st) < 0)
|
if (stat(path, &st) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
return normalize_dir_path(path, NodeRef(st), normalizedPath);
|
return normalize_dir_path(path, NodeRef(st), normalizedPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ normalize_entry_path(const char *path, string &normalizedPath)
|
|||||||
{
|
{
|
||||||
const char *dirPath = NULL;
|
const char *dirPath = NULL;
|
||||||
const char *leafName = NULL;
|
const char *leafName = NULL;
|
||||||
|
|
||||||
string dirPathString;
|
string dirPathString;
|
||||||
if (const char *lastSlash = strrchr(path, '/')) {
|
if (const char *lastSlash = strrchr(path, '/')) {
|
||||||
// found a slash: decompose into dir path and leaf name
|
// found a slash: decompose into dir path and leaf name
|
||||||
@@ -184,7 +184,7 @@ normalize_entry_path(const char *path, string &normalizedPath)
|
|||||||
// catch special case: no leaf, or leaf is a directory
|
// catch special case: no leaf, or leaf is a directory
|
||||||
if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
|
if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0)
|
||||||
return normalize_dir_path(path, normalizedPath);
|
return normalize_dir_path(path, normalizedPath);
|
||||||
|
|
||||||
// normalize the dir path
|
// normalize the dir path
|
||||||
status_t error = normalize_dir_path(dirPath, normalizedPath);
|
status_t error = normalize_dir_path(dirPath, normalizedPath);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
@@ -222,7 +222,7 @@ get_path(const NodeRef *ref, const char *name, string &path)
|
|||||||
DirPathMap::iterator it = sDirPathMap.find(*ref);
|
DirPathMap::iterator it = sDirPathMap.find(*ref);
|
||||||
if (it == sDirPathMap.end())
|
if (it == sDirPathMap.end())
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
path = it->second;
|
path = it->second;
|
||||||
|
|
||||||
// stat the path to check, if it is still valid
|
// stat the path to check, if it is still valid
|
||||||
@@ -250,7 +250,7 @@ get_path(const NodeRef *ref, const char *name, string &path)
|
|||||||
path += '/';
|
path += '/';
|
||||||
path += name;
|
path += name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +272,7 @@ BPrivate::get_path(int fd, const char *name, string &path)
|
|||||||
return error;
|
return error;
|
||||||
|
|
||||||
return ::get_path(&ref, name, path);
|
return ::get_path(&ref, name, path);
|
||||||
|
|
||||||
} else // no descriptor or absolute path
|
} else // no descriptor or absolute path
|
||||||
return ::get_path((NodeRef*)NULL, name, path);
|
return ::get_path((NodeRef*)NULL, name, path);
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ get_path(dev_t device, ino_t directory, const char *name, string &path)
|
|||||||
NodeRef ref;
|
NodeRef ref;
|
||||||
ref.device = device;
|
ref.device = device;
|
||||||
ref.node = directory;
|
ref.node = directory;
|
||||||
|
|
||||||
return get_path(&ref, name, path);
|
return get_path(&ref, name, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,7 +315,7 @@ _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf,
|
|||||||
// copy it back to the user buffer
|
// copy it back to the user buffer
|
||||||
if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
|
if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength)
|
||||||
return B_BUFFER_OVERFLOW;
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,8 +334,8 @@ _kern_create_dir(int fd, const char *path, int perms)
|
|||||||
|
|
||||||
// mkdir
|
// mkdir
|
||||||
if (mkdir(realPath.c_str(), perms) < 0)
|
if (mkdir(realPath.c_str(), perms) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,8 +352,8 @@ _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name,
|
|||||||
|
|
||||||
// mkdir
|
// mkdir
|
||||||
if (mkdir(realPath.c_str(), perms) < 0)
|
if (mkdir(realPath.c_str(), perms) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,7 +382,7 @@ open_dir(const char *path)
|
|||||||
NodeRef ref(st);
|
NodeRef ref(st);
|
||||||
add_dir_path(path, ref);
|
add_dir_path(path, ref);
|
||||||
|
|
||||||
// create descriptor
|
// create descriptor
|
||||||
DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
|
DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref);
|
||||||
return add_descriptor(descriptor);
|
return add_descriptor(descriptor);
|
||||||
}
|
}
|
||||||
@@ -443,7 +443,7 @@ _kern_open_parent_dir(int fd, char *name, size_t nameLength)
|
|||||||
return B_BUFFER_OVERFLOW;
|
return B_BUFFER_OVERFLOW;
|
||||||
|
|
||||||
// open the parent directory
|
// open the parent directory
|
||||||
|
|
||||||
return open_dir(realPath.c_str());
|
return open_dir(realPath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -455,7 +455,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
|
|||||||
if (maxCount <= 0)
|
if (maxCount <= 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
// get the descriptor
|
// get the descriptor
|
||||||
DirectoryDescriptor *descriptor
|
DirectoryDescriptor *descriptor
|
||||||
= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
|
= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
@@ -484,7 +484,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize,
|
|||||||
status_t
|
status_t
|
||||||
_kern_rewind_dir(int fd)
|
_kern_rewind_dir(int fd)
|
||||||
{
|
{
|
||||||
// get the descriptor
|
// get the descriptor
|
||||||
DirectoryDescriptor *descriptor
|
DirectoryDescriptor *descriptor
|
||||||
= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
|
= dynamic_cast<DirectoryDescriptor*>(get_descriptor(fd));
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
@@ -523,7 +523,7 @@ open_file(const char *path, int openMode, int perms)
|
|||||||
status_t error = normalize_entry_path(path, normalizedPath);
|
status_t error = normalize_entry_path(path, normalizedPath);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
descriptor = new SymlinkDescriptor(normalizedPath.c_str());
|
descriptor = new SymlinkDescriptor(normalizedPath.c_str());
|
||||||
} else {
|
} else {
|
||||||
// open the file
|
// open the file
|
||||||
@@ -534,11 +534,11 @@ open_file(const char *path, int openMode, int perms)
|
|||||||
|
|
||||||
descriptor = new FileDescriptor(newFD);
|
descriptor = new FileDescriptor(newFD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cache path, if this is a directory
|
// cache path, if this is a directory
|
||||||
if (exists && S_ISDIR(st.st_mode))
|
if (exists && S_ISDIR(st.st_mode))
|
||||||
add_dir_path(path, NodeRef(st));
|
add_dir_path(path, NodeRef(st));
|
||||||
|
|
||||||
return add_descriptor(descriptor);
|
return add_descriptor(descriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -603,7 +603,7 @@ _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize)
|
|||||||
if (result < 0)
|
if (result < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read
|
// read
|
||||||
ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
|
ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer,
|
||||||
bufferSize);
|
bufferSize);
|
||||||
@@ -629,7 +629,7 @@ _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize)
|
|||||||
if (result < 0)
|
if (result < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// read
|
// read
|
||||||
ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
|
ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer,
|
||||||
bufferSize);
|
bufferSize);
|
||||||
@@ -706,10 +706,10 @@ _kern_read_stat(int fd, const char *path, bool traverseLink,
|
|||||||
Descriptor *descriptor = get_descriptor(fd);
|
Descriptor *descriptor = get_descriptor(fd);
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
return B_FILE_ERROR;
|
return B_FILE_ERROR;
|
||||||
|
|
||||||
return descriptor->GetStat(traverseLink, st);
|
return descriptor->GetStat(traverseLink, st);
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,7 +734,7 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
|
|||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
isSymlink = S_ISLNK(tmpStat.st_mode);
|
isSymlink = S_ISLNK(tmpStat.st_mode);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Descriptor *descriptor = get_descriptor(fd);
|
Descriptor *descriptor = get_descriptor(fd);
|
||||||
if (!descriptor)
|
if (!descriptor)
|
||||||
@@ -743,17 +743,17 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
|
|||||||
if (FileDescriptor *fileFD
|
if (FileDescriptor *fileFD
|
||||||
= dynamic_cast<FileDescriptor*>(descriptor)) {
|
= dynamic_cast<FileDescriptor*>(descriptor)) {
|
||||||
realFD = fileFD->fd;
|
realFD = fileFD->fd;
|
||||||
|
|
||||||
} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
|
} else if (dynamic_cast<DirectoryDescriptor*>(descriptor)) {
|
||||||
error = get_path(fd, NULL, realPath);
|
error = get_path(fd, NULL, realPath);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
} else if (SymlinkDescriptor *linkFD
|
} else if (SymlinkDescriptor *linkFD
|
||||||
= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
|
= dynamic_cast<SymlinkDescriptor*>(descriptor)) {
|
||||||
realPath = linkFD->path;
|
realPath = linkFD->path;
|
||||||
isSymlink = true;
|
isSymlink = true;
|
||||||
|
|
||||||
} else
|
} else
|
||||||
return B_FILE_ERROR;
|
return B_FILE_ERROR;
|
||||||
}
|
}
|
||||||
@@ -762,23 +762,23 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
|
|||||||
// available functions traverse symlinks.
|
// available functions traverse symlinks.
|
||||||
if (isSymlink && !traverseLink)
|
if (isSymlink && !traverseLink)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
if (realFD >= 0) {
|
if (realFD >= 0) {
|
||||||
if (statMask & B_STAT_MODE) {
|
if (statMask & B_STAT_MODE) {
|
||||||
if (fchmod(realFD, st->st_mode) < 0)
|
if (fchmod(realFD, st->st_mode) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statMask & B_STAT_UID) {
|
if (statMask & B_STAT_UID) {
|
||||||
if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
|
if (fchown(realFD, st->st_uid, (gid_t)-1) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statMask & B_STAT_GID) {
|
if (statMask & B_STAT_GID) {
|
||||||
if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
|
if (fchown(realFD, (uid_t)-1, st->st_gid) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statMask & B_STAT_SIZE) {
|
if (statMask & B_STAT_SIZE) {
|
||||||
if (ftruncate(realFD, st->st_size) < 0)
|
if (ftruncate(realFD, st->st_size) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
@@ -790,25 +790,25 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
|
|||||||
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
|
| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) {
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (statMask & B_STAT_MODE) {
|
if (statMask & B_STAT_MODE) {
|
||||||
if (chmod(realPath.c_str(), st->st_mode) < 0)
|
if (chmod(realPath.c_str(), st->st_mode) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statMask & B_STAT_UID) {
|
if (statMask & B_STAT_UID) {
|
||||||
if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
|
if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statMask & B_STAT_GID) {
|
if (statMask & B_STAT_GID) {
|
||||||
if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
|
if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (statMask & B_STAT_SIZE) {
|
if (statMask & B_STAT_SIZE) {
|
||||||
if (truncate(realPath.c_str(), st->st_size) < 0)
|
if (truncate(realPath.c_str(), st->st_size) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
@@ -822,18 +822,18 @@ _kern_write_stat(int fd, const char *path, bool traverseLink,
|
|||||||
if (stat(realPath.c_str(), &oldStat) < 0)
|
if (stat(realPath.c_str(), &oldStat) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
utimbuf buffer;
|
utimbuf buffer;
|
||||||
buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
|
buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime;
|
||||||
buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
|
buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime;
|
||||||
if (utime(realPath.c_str(), &buffer) < 0)
|
if (utime(realPath.c_str(), &buffer) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not supported
|
// not supported
|
||||||
if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
|
if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME))
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -878,7 +878,7 @@ _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
|
|||||||
if (*_bufferSize > 0) {
|
if (*_bufferSize > 0) {
|
||||||
if ((size_t)bytesRead == *_bufferSize)
|
if ((size_t)bytesRead == *_bufferSize)
|
||||||
bytesRead--;
|
bytesRead--;
|
||||||
|
|
||||||
buffer[bytesRead] = '\0';
|
buffer[bytesRead] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -918,7 +918,7 @@ _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath)
|
|||||||
error = get_path(newDir, newPath, realNewPath);
|
error = get_path(newDir, newPath, realNewPath);
|
||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
// rename
|
// rename
|
||||||
if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
|
if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0)
|
||||||
return errno;
|
return errno;
|
||||||
@@ -954,7 +954,7 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
|
|||||||
off_t result = lseek(fd, pos, SEEK_SET);
|
off_t result = lseek(fd, pos, SEEK_SET);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
// read
|
// read
|
||||||
ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
|
ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize);
|
||||||
if (bytesRead < 0) {
|
if (bytesRead < 0) {
|
||||||
@@ -969,12 +969,25 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize)
|
|||||||
ssize_t
|
ssize_t
|
||||||
write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
|
write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize)
|
||||||
{
|
{
|
||||||
|
// If this is an attribute descriptor, let it do the job.
|
||||||
|
AttributeDescriptor* descriptor
|
||||||
|
= dynamic_cast<AttributeDescriptor*>(get_descriptor(fd));
|
||||||
|
if (descriptor != NULL) {
|
||||||
|
status_t error = descriptor->Write(pos, buffer, bufferSize);
|
||||||
|
if (error != B_OK) {
|
||||||
|
errno = error;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// seek
|
// seek
|
||||||
off_t result = lseek(fd, pos, SEEK_SET);
|
off_t result = lseek(fd, pos, SEEK_SET);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
// read
|
// write
|
||||||
ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
|
ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize);
|
||||||
if (bytesWritten < 0) {
|
if (bytesWritten < 0) {
|
||||||
errno = bytesWritten;
|
errno = bytesWritten;
|
||||||
@@ -992,7 +1005,7 @@ readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
|
|||||||
off_t result = lseek(fd, pos, SEEK_SET);
|
off_t result = lseek(fd, pos, SEEK_SET);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
// read
|
// read
|
||||||
ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
|
ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count);
|
||||||
if (bytesRead < 0) {
|
if (bytesRead < 0) {
|
||||||
@@ -1011,7 +1024,7 @@ writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
|
|||||||
off_t result = lseek(fd, pos, SEEK_SET);
|
off_t result = lseek(fd, pos, SEEK_SET);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
// read
|
// read
|
||||||
ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
|
ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count);
|
||||||
if (bytesWritten < 0) {
|
if (bytesWritten < 0) {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ init_attribute_dir_base_dir()
|
|||||||
|
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return initError;
|
return initError;
|
||||||
|
|
||||||
// stat the dir
|
// stat the dir
|
||||||
struct stat st;
|
struct stat st;
|
||||||
initError = B_OK;
|
initError = B_OK;
|
||||||
@@ -44,7 +44,7 @@ init_attribute_dir_base_dir()
|
|||||||
"directory base directory exists, but is no directory!\n");
|
"directory base directory exists, but is no directory!\n");
|
||||||
initError = B_FILE_ERROR;
|
initError = B_FILE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// doesn't exist yet: create it
|
// doesn't exist yet: create it
|
||||||
if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
|
if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0)
|
||||||
@@ -68,7 +68,7 @@ escape_attr_name(const char *name)
|
|||||||
escapedName += "__";
|
escapedName += "__";
|
||||||
else
|
else
|
||||||
escapedName += *name;
|
escapedName += *name;
|
||||||
|
|
||||||
name++;
|
name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,7 +84,7 @@ deescape_attr_name(const char *name)
|
|||||||
return "___";
|
return "___";
|
||||||
}
|
}
|
||||||
name++;
|
name++;
|
||||||
|
|
||||||
string deescapedName;
|
string deescapedName;
|
||||||
while (*name != '\0') {
|
while (*name != '\0') {
|
||||||
if (*name == '_') {
|
if (*name == '_') {
|
||||||
@@ -100,11 +100,11 @@ deescape_attr_name(const char *name)
|
|||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
deescapedName += *name;
|
deescapedName += *name;
|
||||||
|
|
||||||
name++;
|
name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return deescapedName;
|
return deescapedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get_attribute_dir_path
|
// get_attribute_dir_path
|
||||||
@@ -179,7 +179,7 @@ get_attribute_path(NodeRef ref, const char *path, int fd,
|
|||||||
errno = error;
|
errno = error;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct the attribute path
|
// construct the attribute path
|
||||||
attrPath = get_attribute_dir_path(ref) + '/';
|
attrPath = get_attribute_dir_path(ref) + '/';
|
||||||
string attrName(escape_attr_name(attribute));
|
string attrName(escape_attr_name(attribute));
|
||||||
@@ -206,7 +206,7 @@ get_attribute_path_virtual_fd(int fd, const char *attribute, string &attrPath,
|
|||||||
// (i.e. system) file descriptor, which is just as well.
|
// (i.e. system) file descriptor, which is just as well.
|
||||||
string path;
|
string path;
|
||||||
bool pathValid = (get_path(fd, NULL, path) == B_OK);
|
bool pathValid = (get_path(fd, NULL, path) == B_OK);
|
||||||
|
|
||||||
// get the attribute path
|
// get the attribute path
|
||||||
return get_attribute_path(ref, (pathValid ? path.c_str() : NULL),
|
return get_attribute_path(ref, (pathValid ? path.c_str() : NULL),
|
||||||
(pathValid ? -1 : fd), attribute, attrPath, typePath);
|
(pathValid ? -1 : fd), attribute, attrPath, typePath);
|
||||||
@@ -269,7 +269,7 @@ fs_fopen_attr_dir(int fd)
|
|||||||
// (i.e. system) file descriptor, which is just as well.
|
// (i.e. system) file descriptor, which is just as well.
|
||||||
string path;
|
string path;
|
||||||
bool pathValid = (get_path(fd, NULL, path) == B_OK);
|
bool pathValid = (get_path(fd, NULL, path) == B_OK);
|
||||||
|
|
||||||
// get the attribute path
|
// get the attribute path
|
||||||
return open_attr_dir(NodeRef(st), (pathValid ? path.c_str() : NULL),
|
return open_attr_dir(NodeRef(st), (pathValid ? path.c_str() : NULL),
|
||||||
(pathValid ? -1 : fd));
|
(pathValid ? -1 : fd));
|
||||||
@@ -292,8 +292,8 @@ fs_read_attr_dir(DIR *dir)
|
|||||||
entry = readdir(dir);
|
entry = readdir(dir);
|
||||||
if (!entry)
|
if (!entry)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
// ignore administrative entries; the
|
// ignore administrative entries; the
|
||||||
if (entry->d_name[0] == '_') {
|
if (entry->d_name[0] == '_') {
|
||||||
string attrName = deescape_attr_name(entry->d_name);
|
string attrName = deescape_attr_name(entry->d_name);
|
||||||
strcpy(entry->d_name, attrName.c_str());
|
strcpy(entry->d_name, attrName.c_str());
|
||||||
@@ -309,15 +309,15 @@ fs_rewind_attr_dir(DIR *dir)
|
|||||||
rewinddir(dir);
|
rewinddir(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs_open_attr
|
// fs_fopen_attr
|
||||||
int
|
int
|
||||||
fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
|
fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
|
||||||
{
|
{
|
||||||
if (!attribute) {
|
if (!attribute) {
|
||||||
errno = B_BAD_VALUE;
|
errno = B_BAD_VALUE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the attribute path
|
// get the attribute path
|
||||||
string attrPath;
|
string attrPath;
|
||||||
string typePath;
|
string typePath;
|
||||||
@@ -344,7 +344,7 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
|
|||||||
// write the type into the file
|
// write the type into the file
|
||||||
if (write(typeFD, &type, sizeof(type)) < 0)
|
if (write(typeFD, &type, sizeof(type)) < 0)
|
||||||
error = errno;
|
error = errno;
|
||||||
|
|
||||||
close(typeFD);
|
close(typeFD);
|
||||||
|
|
||||||
} else
|
} else
|
||||||
@@ -355,10 +355,10 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
|
|||||||
if (typeFD > 0) {
|
if (typeFD > 0) {
|
||||||
unlink(typePath.c_str());
|
unlink(typePath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
close(attrFD);
|
close(attrFD);
|
||||||
unlink(attrPath.c_str());
|
unlink(attrPath.c_str());
|
||||||
|
|
||||||
errno = error;
|
errno = error;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -395,7 +395,7 @@ fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos,
|
|||||||
errno = error;
|
errno = error;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesRead;
|
return bytesRead;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -421,7 +421,7 @@ fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos,
|
|||||||
errno = error;
|
errno = error;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return bytesWritten;
|
return bytesWritten;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ fs_remove_attr(int fd, const char *attribute)
|
|||||||
errno = B_BAD_VALUE;
|
errno = B_BAD_VALUE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the attribute path
|
// get the attribute path
|
||||||
string attrPath;
|
string attrPath;
|
||||||
string typePath;
|
string typePath;
|
||||||
@@ -446,9 +446,9 @@ fs_remove_attr(int fd, const char *attribute)
|
|||||||
// remove the attribute
|
// remove the attribute
|
||||||
if (unlink(attrPath.c_str()) < 0)
|
if (unlink(attrPath.c_str()) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
unlink(typePath.c_str());
|
unlink(typePath.c_str());
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -474,7 +474,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (lstat(attrPath.c_str(), &st) < 0)
|
if (lstat(attrPath.c_str(), &st) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
attrInfo->size = st.st_size;
|
attrInfo->size = st.st_size;
|
||||||
|
|
||||||
// now open the attribute type file and read the attribute's type
|
// now open the attribute type file and read the attribute's type
|
||||||
@@ -496,7 +496,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -524,14 +524,14 @@ _kern_open_attr_dir(int fd, const char *path)
|
|||||||
if (error != B_OK)
|
if (error != B_OK)
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// open the attr dir
|
// open the attr dir
|
||||||
DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL),
|
DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL),
|
||||||
(path ? -1 : fd));
|
(path ? -1 : fd));
|
||||||
if (!dir)
|
if (!dir)
|
||||||
return errno;
|
return errno;
|
||||||
|
|
||||||
// create descriptor
|
// create descriptor
|
||||||
AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
|
AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref);
|
||||||
return add_descriptor(descriptor);
|
return add_descriptor(descriptor);
|
||||||
}
|
}
|
||||||
@@ -571,7 +571,7 @@ _kern_rename_attr(int fromFile, const char *fromName, int toFile,
|
|||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -452,22 +452,50 @@ fs_rewind_attr_dir(DIR *dir)
|
|||||||
attrDir->RewindDir();
|
attrDir->RewindDir();
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs_open_attr
|
// fs_fopen_attr
|
||||||
int
|
int
|
||||||
fs_open_attr(int fd, const char *attribute, uint32 type, int openMode)
|
fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode)
|
||||||
{
|
{
|
||||||
// not supported ATM
|
if (fd < 0) {
|
||||||
errno = B_BAD_VALUE;
|
errno = B_BAD_VALUE;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeDescriptor* descriptor = new(std::nothrow) AttributeDescriptor(fd,
|
||||||
|
attribute, type, openMode);
|
||||||
|
if (descriptor == NULL) {
|
||||||
|
errno = B_NO_MEMORY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t error = descriptor->Init();
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete descriptor;
|
||||||
|
errno = error;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int attributeFD = add_descriptor(descriptor);
|
||||||
|
if (attributeFD < 0) {
|
||||||
|
delete descriptor;
|
||||||
|
errno = B_NO_MEMORY;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return attributeFD;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs_close_attr
|
// fs_close_attr
|
||||||
int
|
int
|
||||||
fs_close_attr(int fd)
|
fs_close_attr(int fd)
|
||||||
{
|
{
|
||||||
// not supported ATM
|
status_t error = delete_descriptor(fd);
|
||||||
errno = B_BAD_VALUE;
|
if (error != 0) {
|
||||||
return -1;
|
errno = error;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs_read_attr
|
// fs_read_attr
|
||||||
|
|||||||
@@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <fs_attr.h>
|
#include <fs_attr.h>
|
||||||
@@ -250,6 +252,151 @@ SymlinkDescriptor::GetPath(string& path) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - AttributeDescriptor
|
||||||
|
|
||||||
|
|
||||||
|
AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute,
|
||||||
|
uint32 type, int openMode)
|
||||||
|
:
|
||||||
|
fFileFD(dup(fileFD)),
|
||||||
|
fType(type),
|
||||||
|
fOpenMode(openMode),
|
||||||
|
fData(NULL),
|
||||||
|
fDataSize(0)
|
||||||
|
|
||||||
|
{
|
||||||
|
strlcpy(fAttribute, attribute, sizeof(fAttribute));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AttributeDescriptor::~AttributeDescriptor()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AttributeDescriptor::Init()
|
||||||
|
{
|
||||||
|
if (fFileFD < 0)
|
||||||
|
return B_IO_ERROR;
|
||||||
|
|
||||||
|
// stat the attribute
|
||||||
|
attr_info info;
|
||||||
|
if (fs_stat_attr(fFileFD, fAttribute, &info) < 0) {
|
||||||
|
if (errno == B_ENTRY_NOT_FOUND) {
|
||||||
|
if ((fOpenMode & O_CREAT) == 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
// create the attribute
|
||||||
|
if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
|
||||||
|
return errno;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
return errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((fOpenMode & O_TRUNC) == 0) {
|
||||||
|
// truncate the attribute
|
||||||
|
if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0)
|
||||||
|
return errno;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we have to read in the attribute data
|
||||||
|
if (info.size == 0)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
fData = (uint8*)malloc(info.size);
|
||||||
|
if (fData == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fDataSize = info.size;
|
||||||
|
|
||||||
|
ssize_t bytesRead = fs_read_attr(fFileFD, fAttribute, fType, 0, fData,
|
||||||
|
fDataSize);
|
||||||
|
if (bytesRead < 0)
|
||||||
|
return errno;
|
||||||
|
if ((size_t)bytesRead != fDataSize)
|
||||||
|
return B_IO_ERROR;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize)
|
||||||
|
{
|
||||||
|
if (offset < 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if ((fOpenMode & O_ACCMODE) != O_WRONLY
|
||||||
|
&& (fOpenMode & O_ACCMODE) != O_RDWR) {
|
||||||
|
return B_NOT_ALLOWED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we may need to resize the buffer
|
||||||
|
size_t minSize = (size_t)offset + bufferSize;
|
||||||
|
if (minSize > fDataSize) {
|
||||||
|
uint8* data = (uint8*)realloc(fData, minSize);
|
||||||
|
if (data == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if ((size_t)offset > fDataSize)
|
||||||
|
memset(data + offset, 0, offset - fDataSize);
|
||||||
|
|
||||||
|
fData = data;
|
||||||
|
fDataSize = minSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the data and write all of it
|
||||||
|
if (bufferSize == 0)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
memcpy((uint8*)fData + offset, buffer, bufferSize);
|
||||||
|
|
||||||
|
ssize_t bytesWritten = fs_write_attr(fFileFD, fAttribute, fType, 0,
|
||||||
|
fData, fDataSize);
|
||||||
|
if (bytesWritten < 0)
|
||||||
|
return errno;
|
||||||
|
if ((size_t)bytesWritten != fDataSize)
|
||||||
|
return B_IO_ERROR;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AttributeDescriptor::Close()
|
||||||
|
{
|
||||||
|
if (fFileFD < 0)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
close(fFileFD);
|
||||||
|
fFileFD = -1;
|
||||||
|
|
||||||
|
free(fData);
|
||||||
|
fData = NULL;
|
||||||
|
fDataSize = 0;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AttributeDescriptor::Dup(Descriptor*& clone)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
AttributeDescriptor::GetStat(bool traverseLink, struct stat* st)
|
||||||
|
{
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - AttrDirDescriptor
|
// #pragma mark - AttrDirDescriptor
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <StorageDefs.h>
|
||||||
#include <SupportDefs.h>
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
#include "NodeRef.h"
|
#include "NodeRef.h"
|
||||||
@@ -35,7 +36,7 @@ struct Descriptor {
|
|||||||
struct FileDescriptor : Descriptor {
|
struct FileDescriptor : Descriptor {
|
||||||
FileDescriptor(int fd);
|
FileDescriptor(int fd);
|
||||||
virtual ~FileDescriptor();
|
virtual ~FileDescriptor();
|
||||||
|
|
||||||
virtual status_t Close();
|
virtual status_t Close();
|
||||||
virtual status_t Dup(Descriptor *&clone);
|
virtual status_t Dup(Descriptor *&clone);
|
||||||
virtual status_t GetStat(bool traverseLink, struct stat *st);
|
virtual status_t GetStat(bool traverseLink, struct stat *st);
|
||||||
@@ -50,7 +51,7 @@ struct DirectoryDescriptor : Descriptor {
|
|||||||
|
|
||||||
DirectoryDescriptor(DIR *dir, const NodeRef &ref);
|
DirectoryDescriptor(DIR *dir, const NodeRef &ref);
|
||||||
virtual ~DirectoryDescriptor();
|
virtual ~DirectoryDescriptor();
|
||||||
|
|
||||||
virtual status_t Close();
|
virtual status_t Close();
|
||||||
virtual status_t Dup(Descriptor *&clone);
|
virtual status_t Dup(Descriptor *&clone);
|
||||||
virtual status_t GetStat(bool traverseLink, struct stat *st);
|
virtual status_t GetStat(bool traverseLink, struct stat *st);
|
||||||
@@ -71,12 +72,41 @@ struct SymlinkDescriptor : Descriptor {
|
|||||||
virtual status_t GetPath(string& path) const;
|
virtual status_t GetPath(string& path) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// AttributeDescriptor
|
||||||
|
struct AttributeDescriptor : Descriptor {
|
||||||
|
AttributeDescriptor(int fileFD,
|
||||||
|
const char* attribute, uint32 type,
|
||||||
|
int openMode);
|
||||||
|
virtual ~AttributeDescriptor();
|
||||||
|
|
||||||
|
status_t Init();
|
||||||
|
status_t Write(off_t offset, const void* buffer,
|
||||||
|
size_t bufferSize);
|
||||||
|
|
||||||
|
int FileFD() const { return fFileFD; }
|
||||||
|
const char* Attribute() const { return fAttribute; }
|
||||||
|
uint32 Type() const { return fType; }
|
||||||
|
int OpenMode() const { return fOpenMode; }
|
||||||
|
|
||||||
|
virtual status_t Close();
|
||||||
|
virtual status_t Dup(Descriptor*& clone);
|
||||||
|
virtual status_t GetStat(bool traverseLink, struct stat* st);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fFileFD;
|
||||||
|
char fAttribute[B_ATTR_NAME_LENGTH];
|
||||||
|
uint32 fType;
|
||||||
|
int fOpenMode;
|
||||||
|
uint8* fData;
|
||||||
|
size_t fDataSize;
|
||||||
|
};
|
||||||
|
|
||||||
// AttrDirDescriptor
|
// AttrDirDescriptor
|
||||||
struct AttrDirDescriptor : DirectoryDescriptor {
|
struct AttrDirDescriptor : DirectoryDescriptor {
|
||||||
|
|
||||||
AttrDirDescriptor(DIR *dir, const NodeRef &ref);
|
AttrDirDescriptor(DIR *dir, const NodeRef &ref);
|
||||||
virtual ~AttrDirDescriptor();
|
virtual ~AttrDirDescriptor();
|
||||||
|
|
||||||
virtual status_t Close();
|
virtual status_t Close();
|
||||||
virtual status_t Dup(Descriptor *&clone);
|
virtual status_t Dup(Descriptor *&clone);
|
||||||
virtual status_t GetStat(bool traverseLink, struct stat *st);
|
virtual status_t GetStat(bool traverseLink, struct stat *st);
|
||||||
|
|||||||
Reference in New Issue
Block a user