diff --git a/ChangeLog b/ChangeLog index 610a1b67..152d226d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -71,9 +71,11 @@ xx/xx/2005 - 1.12.2-WIP starting to clone or restore. (Szaka) - Change @type parameter for ntfs_create() to be dev_t rather than internal NTFS_DT_* constants. (Yura) - - Teach ntfs_create() to create special Interix files (charcter and - block devices, FIFOs and sockets). Add @dev parameter to ntfs_create() - for this. (Yura) + - New APIs (dir.[ch]): + ntfs_create_device() for Interix block and character devices + creation. + ntfs_crate_symlink() for Interix symbolic links creation. (Yura) + - Teach ntfs_create() to create Interix FIFOs and sockets. (Yura) - Fix the -u option in ntfsundelete. Instead of a confusing optional parameter, there's a new option -i with a required parameter (Rich) diff --git a/include/ntfs/dir.h b/include/ntfs/dir.h index c6170e4f..8b56c669 100644 --- a/include/ntfs/dir.h +++ b/include/ntfs/dir.h @@ -49,9 +49,15 @@ extern ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent, const char *pathname); extern ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, - dev_t type, dev_t dev); + dev_t type); +extern ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, + ntfschar *name, u8 name_len, dev_t type, dev_t dev); +extern ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, + ntfschar *name, u8 name_len, ntfschar *target, u8 target_len); + extern int ntfs_delete(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len); + extern int ntfs_link(ntfs_inode *ni, ntfs_inode *dir_ni, ntfschar *name, u8 name_len); diff --git a/libntfs/dir.c b/libntfs/dir.c index 811f6fef..8696bde5 100644 --- a/libntfs/dir.c +++ b/libntfs/dir.c @@ -1072,18 +1072,23 @@ err_out: } /** - * ntfs_create - create object on ntfs volume + * __ntfs_create - create object on ntfs volume * @dir_ni: ntfs inode for directory in which create new object * @name: unicode name of new object * @name_len: length of the name in unicode characters * @type: type of the object to create * @dev: major and minor device numbers (obtained from makedev()) + * @target: target in unicode (only for symlinks) + * @target_len: length of target in unicode charcters + * + * Internal, use ntfs_create{_device,_symlink} wrappers instead. * * @type can be: * S_IFREG to create regular file * S_IFDIR to create directory * S_IFBLK to create block device * S_IFCHR to create character device + * S_IFLNK to create symbolic link * S_IFIFO to create FIFO * S_IFSOCK to create socket * other values are invalid. @@ -1094,8 +1099,9 @@ err_out: * Return opened ntfs inode that describes created object on success or NULL * on error with errno set to the error code. */ -ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, - dev_t type, dev_t dev) +static ntfs_inode *__ntfs_create(ntfs_inode *dir_ni, + ntfschar *name, u8 name_len, dev_t type, dev_t dev, + ntfschar *target, u8 target_len) { ntfs_inode *ni; FILE_NAME_ATTR *fn = NULL; @@ -1104,10 +1110,7 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, ntfs_log_trace("Entering.\n"); /* Sanity checks. */ - if (!dir_ni || !name || !name_len || (type != S_IFREG && - type != S_IFDIR && type != S_IFIFO && - type != S_IFSOCK && type != S_IFCHR && - type != S_IFBLK)) { + if (!dir_ni || !name || !name_len) { ntfs_log_error("Invalid arguments."); return NULL; } @@ -1204,6 +1207,21 @@ ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, if (type == S_IFCHR) data->magic = INTX_CHARACTER_DEVICE; break; + case S_IFLNK: + data_len = sizeof(INTX_FILE_TYPES) + + target_len * sizeof(ntfschar); + data = malloc(data_len); + if (!data) { + err = errno; + ntfs_log_error("Not enough memory for " + "content of DATA " + "attribute.\n"); + goto err_out; + } + data->magic = INTX_SYMBOLIC_LINK; + memcpy(data->target, target, + target_len * sizeof(ntfschar)); + break; case S_IFSOCK: data = NULL; data_len = 1; @@ -1278,6 +1296,42 @@ err_out: return NULL; } +/** + * Some wrappers around __ntfs_create() ... + */ + +ntfs_inode *ntfs_create(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, + dev_t type) +{ + if (type != S_IFREG && type != S_IFDIR && type != S_IFIFO && + type != S_IFSOCK) { + ntfs_log_error("Invalid arguments."); + return NULL; + } + return __ntfs_create(dir_ni, name, name_len, type, 0, NULL, 0); +} + +ntfs_inode *ntfs_create_device(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, + dev_t type, dev_t dev) +{ + if (type != S_IFCHR && type != S_IFBLK) { + ntfs_log_error("Invalid arguments."); + return NULL; + } + return __ntfs_create(dir_ni, name, name_len, type, dev, NULL, 0); +} + +ntfs_inode *ntfs_create_symlink(ntfs_inode *dir_ni, ntfschar *name, u8 name_len, + ntfschar *target, u8 target_len) +{ + if (!target || !target_len) { + ntfs_log_error("Invalid arguments."); + return NULL; + } + return __ntfs_create(dir_ni, name, name_len, S_IFLNK, 0, + target, target_len); +} + /** * ntfs_delete - delete file or directory from ntfs volume * @ni: ntfs inode for object to delte diff --git a/ntfsprogs/ntfsmount.c b/ntfsprogs/ntfsmount.c index 0b5a8c67..6cbe2117 100644 --- a/ntfsprogs/ntfsmount.c +++ b/ntfsprogs/ntfsmount.c @@ -516,6 +516,9 @@ static int ntfs_fuse_readdir(const char *path, void *buf, ni = ntfs_pathname_to_inode(vol, NULL, path); if (!ni) return -errno; + if (!strcmp(path, "/")) + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); if (ntfs_readdir(ni, &pos, &fill_ctx, (ntfs_filldir_t)ntfs_fuse_filler)) err = -errno; @@ -703,13 +706,14 @@ static int ntfs_fuse_chmod(const char *path, return -EOPNOTSUPP; } -static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev) +static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev, + const char *target) { char *name; - ntfschar *uname = NULL; + ntfschar *uname = NULL, *utarget = NULL; ntfs_inode *dir_ni = NULL, *ni; char *path; - int res = 0, uname_len; + int res = 0, uname_len, utarget_len; path = strdup(org_path); if (!path) @@ -732,7 +736,25 @@ static int ntfs_fuse_create(const char *org_path, dev_t type, dev_t dev) goto exit; } /* Create object specified in @type. */ - ni = ntfs_create(dir_ni, uname, uname_len, type, dev); + switch (type) { + case S_IFCHR: + case S_IFBLK: + ni = ntfs_create_device(dir_ni, uname, uname_len, type, + dev); + break; + case S_IFLNK: + utarget_len = ntfs_mbstoucs(target, &utarget, 0); + if (utarget_len < 0) { + res = -errno; + goto exit; + } + ni = ntfs_create_symlink(dir_ni, uname, uname_len, + utarget, utarget_len); + break; + default: + ni = ntfs_create(dir_ni, uname, uname_len, type); + break; + } if (ni) ntfs_inode_close(ni); else @@ -741,6 +763,8 @@ exit: free(uname); if (dir_ni) ntfs_inode_close(dir_ni); + if (utarget) + free(utarget); free(path); return res; } @@ -759,7 +783,7 @@ static int ntfs_fuse_create_stream(const char *path, * If such file does not exist, create it and try once * again to add stream to it. */ - res = ntfs_fuse_create(path, S_IFREG, 0); + res = ntfs_fuse_create(path, S_IFREG, 0, NULL); if (!res) return ntfs_fuse_create_stream(path, stream_name, stream_name_len); @@ -790,7 +814,7 @@ static int ntfs_fuse_mknod(const char *org_path, mode_t mode, dev_t dev) goto exit; } if (!stream_name_len) - res = ntfs_fuse_create(path, mode & S_IFMT, dev); + res = ntfs_fuse_create(path, mode & S_IFMT, dev, NULL); else res = ntfs_fuse_create_stream(path, stream_name, stream_name_len); @@ -801,6 +825,14 @@ exit: return res; } +static int ntfs_fuse_symlink(const char *to, const char *from) +{ + if (strchr(from, ':') && /* n/a for named data streams. */ + ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) + return -EINVAL; + return ntfs_fuse_create(from, S_IFLNK, 0, to); +} + static int ntfs_fuse_link(const char *old_path, const char *new_path) { char *name; @@ -965,7 +997,7 @@ static int ntfs_fuse_mkdir(const char *path, { if (strchr(path, ':') && ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) return -EINVAL; /* n/a for named data streams. */ - return ntfs_fuse_create(path, S_IFDIR, 0); + return ntfs_fuse_create(path, S_IFDIR, 0, NULL); } static int ntfs_fuse_rmdir(const char *path) @@ -1302,6 +1334,7 @@ static struct fuse_operations ntfs_fuse_oper = { .statfs = ntfs_fuse_statfs, .chmod = ntfs_fuse_chmod, .mknod = ntfs_fuse_mknod, + .symlink = ntfs_fuse_symlink, .link = ntfs_fuse_link, .unlink = ntfs_fuse_unlink, .rename = ntfs_fuse_rename,