Changes by: mattjf
Update of /cvsroot/linux-ntfs/linux-ntfs/ntfstools
In directory usw-pr-cvs1:/tmp/cvs-serv23740/ntfstools
Modified Files:
ntfslabel.c
Log Message:
Code cleanup.
Removed check_mount() and added a generic ntfs_check_if_mounted()
function to the library
Better error checking
Index: ntfslabel.c
===================================================================
RCS file: /cvsroot/linux-ntfs/linux-ntfs/ntfstools/ntfslabel.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -U2 -r1.5 -r1.6
--- ntfslabel.c 21 Apr 2002 10:11:36 -0000 1.5
+++ ntfslabel.c 23 Apr 2002 08:25:41 -0000 1.6
@@ -44,5 +44,4 @@
-#define NTFS_MF_MOUNTED 1
const char *EXEC_NAME = "ntfslabel";
@@ -53,14 +52,15 @@
void change_label(const char *dev, const char *label);
-void print_label(const char *dev)
-{
- vol = ntfs_mount(dev, MS_RDONLY);
- if (!vol) {
- perror("ntfs_mount() failed");
- exit(1);
- }
- printf("%s\n", vol->vol_name);
- ntfs_umount(vol, 0);
-}
+int check_mount(const char *file);
+
+int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a, const __u32 new_vsize);
+
+void print_label(const char *dev);
+
+int insert_resident_attr_in_mft_record(MFT_RECORD *m, const ATTR_TYPES type,
+ const char *name, __u32 name_len, const IGNORE_CASE_BOOL ic,
+ const ATTR_FLAGS flags, const RESIDENT_ATTR_FLAGS res_flags,
+ const char *val, const __u32 val_len);
+
int main(int argc, char **argv)
@@ -90,13 +90,59 @@
return 0;
}
+
+
+
+/**
+ * print_label - display the current label on a device
+ * @dev: the device to read label
+ *
+ * print_label will first verify the device is a valid block
+ * device, and will exit with error INVALID_BLOCK_DEVICE if
+ * it is not.
+ **/
+ void print_label(const char *dev){
+
+ int err;
+
+ /* We should first make sure it is a valid block device */
+ err = ntfs_check_if_mounted(dev);
+ if (err == -1){
+ if(errno = ENODEV){
+ printf("Error: %s is not a valid block device!\n",dev);
+ exit(1);
+ }
+ }
+
+
+ vol = ntfs_mount(dev, MS_RDONLY);
+
+ if (!vol){
+ printf("ntfs_mount() on device %s failed!\n",dev);
+ exit(1);
+ }
+
+ printf("%s\n", vol->vol_name);
+ ntfs_umount(vol, 0);
+}
+
+
-int check_mount(const char *file);
-int resize_resident_attribute_value(MFT_RECORD *m, ATTR_RECORD *a,
- const __u32 new_vsize);
+
+/**
+ * change_label - change the current label on a device
+ * @dev: the device to read label
+ * @label: the new label
+ *
+ * change_label will first verify the device is a valid block
+ * device, and will exit with error INVALID_BLOCK_DEVICE if
+ * it is not. it will also verify the device is not currently
+ * mounted and exit with error NTFS_MF_MOUNTED if it is
+ **/
void change_label(const char *dev, const char *label)
{
+
MFT_RECORD *mrec = NULL;
- MFT_REF mref;
+ MFT_REF mref;
ATTR_RECORD *a;
ntfs_attr_search_ctx *ctx = NULL;
@@ -104,6 +150,20 @@
printf("now changing label - FIXME: Not implemented yet!\n");
+
/*First we need to make sure the device is not mounted*/
- check_mount(dev); /* check_mount() will handle exiting */
+ err = ntfs_check_if_mounted(dev);
+
+ if (err == -1){
+ if(errno == ENODEV){
+ printf("Error: %s is not a valid block device!\n",dev);
+ exit(1);
+ }
+ }
+ if (err == 1){
+ printf("Error: %s is already mounted!\n",dev);
+ exit(1);
+ }
+
+
vol = ntfs_mount(dev,MS_RDONLY);
@@ -138,54 +198,36 @@
}
- resize_resident_attribute_value(mrec, a, strlen(label));
-
-
-
-
- }
+ if (resize_resident_attribute_value(mrec, a, strlen(label))){
+ printf("Error: Cannot resize resident attribute!\n");
+ exit(1);
+ }
-}
-
-
-
-
-/* Only check if the mount is readonly when it's the root filesystem. */
-int check_mntent(const char *file)
-{
- FILE *m_f;
- struct mntent *mnt;
- int m_fd;
-
- if (!(m_f = setmntent(MOUNTED, "r")))
- return -errno;
- while ((mnt = getmntent(m_f)))
- if (!strcmp(file, mnt->mnt_fsname))
- break;
- endmntent(m_f);
- if (!mnt)
- return 0;
- else
- return NTFS_MF_MOUNTED;
+ if (insert_resident_attr_in_mft_record(mrec,AT_VOLUME_NAME,NULL,0,0,0,0,
+ (char*)label,strlen(label))){
+ printf("Error: Cannot modify resident attribute!\n");
+ exit(1);
+ }
-}
+
+ if (ntfs_write_mft_record(vol,mref,mrec)){
+ printf("Error: Cannot write MFT Record to disk!\n");
+
+ if(errno == EINVAL)
+ printf("EINVAL\n");
+ if(errno == EBADF)
+ printf("EBADF\n");
+ if(errno == ESPIPE)
+ printf("ESPIPE\n");
+ if(errno == EIO)
+ printf("EIO\n");
-int check_mount(const char *dev)
-{
- int r;
- struct stat sbuf;
-
- /* First verify we are dealing with a valid block device. */
- if (stat(dev, &sbuf) == -1) {
- fprintf(stderr, "Error: device %s is not a valid block "
- "device.\n", dev);
- exit(1);
+ exit(1);
+ }
}
+
+
+}
- if ((r = check_mntent(dev))) {
- printf("Error: device %s is currently mounted.\n", dev);
- exit(1);
- }
-}
@@ -218,3 +260,179 @@
a->value_length = cpu_to_le32(new_vsize);
return 0;
+}
+
+
+
+
+int stoucs(uchar_t *dest, const char *src, int maxlen)
+{
+ char c;
+ int i;
+
+ /* Need two bytes for null terminator. */
+ maxlen -= 2;
+ for (i = 0; i < maxlen; i++) {
+ c = src[i];
+ if (!c)
+ break;
+ dest[i] = cpu_to_le16(c);
+ }
+ dest[i] = cpu_to_le16('\0');
+ return i;
+}
+
+
+
+/**
+ * make_room_for_attribute - make room for an attribute inside an mft record
+ * @m: mft record
+ * @pos: position at which to make space
+ * @size: byte size to make available at this position
+ *
+ * @pos points to the attribute in front of which we want to make space.
+ *
+ * Return 0 on success or -errno on error. Possible error codes are:
+ *
+ * -ENOSPC There is not enough space available to complete
+ * operation. The caller has to make space before calling
+ * this.
+ * -EINVAL Can only occur if mkntfs was compiled with -DEBUG. Means
+ * the input parameters were faulty.
+ */
+int make_room_for_attribute(MFT_RECORD *m, char *pos, const __u32 size)
+{
+ __u32 biu;
+
+ if (!size)
+ return 0;
+#ifdef DEBUG
+ /*
+ * Rigorous consistency checks. Always return -EINVAL even if more
+ * appropriate codes exist for simplicity of parsing the return value.
+ */
+ if (size != ((size + 7) & ~7)) {
+ Eprintf("make_room_for_attribute() received non 8-byte aligned"
+ "size.\n");
+ return -EINVAL;
+ }
+ if (!m || !pos)
+ return -EINVAL;
+ if (pos < (char*)m || pos + size < (char*)m ||
+ pos > (char*)m + le32_to_cpu(m->bytes_allocated) ||
+ pos + size > (char*)m + le32_to_cpu(m->bytes_allocated))
+ return -EINVAL;
+ /* The -8 is for the attribute terminator. */
+ if (pos - (char*)m > le32_to_cpu(m->bytes_in_use) - 8)
+ return -EINVAL;
+#endif
+ biu = le32_to_cpu(m->bytes_in_use);
+ /* Do we have enough space? */
+ if (biu + size > le32_to_cpu(m->bytes_allocated))
+ return -ENOSPC;
+ /* Move everything after pos to pos + size. */
+ memmove(pos + size, pos, biu - (pos - (char*)m));
+ /* Update mft record. */
+ m->bytes_in_use = cpu_to_le32(biu + size);
+ return 0;
+}
+
+
+/* Return 0 on success and -errno on error. */
+int insert_resident_attr_in_mft_record(MFT_RECORD *m, const ATTR_TYPES type,
+ const char *name, __u32 name_len, const IGNORE_CASE_BOOL ic,
+ const ATTR_FLAGS flags, const RESIDENT_ATTR_FLAGS res_flags,
+ const char *val, const __u32 val_len)
+{
+ ntfs_attr_search_ctx *ctx;
+ ATTR_RECORD *a;
+ int asize, err, i;
+ uchar_t *uname;
+/*
+ if (base record)
+ lookup_attr();
+ else
+*/
+ if (name_len) {
+ i = (name_len + 1) * sizeof(uchar_t);
+ uname = (uchar_t*)calloc(1, i);
+ name_len = stoucs(uname, name, i);
+ if (name_len > 0xff)
+ return -ENAMETOOLONG;
+ } else
+ uname = NULL;
+ /* Check if the attribute is already there. */
+ ctx = ntfs_get_attr_search_ctx(NULL, m);
+ if (!ctx) {
+ printf("Failed to allocate attribute search context.\n");
+ err = -ENOMEM;
+ goto err_out;
+ }
+ if (ic == IGNORE_CASE) {
+ printf("FIXME: Hit unimplemented code path #3.\n");
+ err = -ENOTSUP;
+ goto err_out;
+ }
+ if (!ntfs_lookup_attr(type, uname, name_len, ic, 0, val, val_len,
+ ctx)) {
+ err = -EEXIST;
+ goto err_out;
+ }
+ if (errno != ENOENT) {
+ printf("Corrupt inode.\n");
+ err = -errno;
+ goto err_out;
+ }
+ a = ctx->attr;
+ /* sizeof(resident attribute record header) == 24 */
+ asize = ((24 + ((name_len + 7) & ~7) + val_len) + 7) & ~7;
+ err = make_room_for_attribute(m, (char*)a, asize);
+ if (err == -ENOSPC) {
+ // FIXME: Make space! (AIA)
+ // can we make it non-resident? if yes, do that.
+ // does it fit now? yes -> do it.
+ // m's $DATA or $BITMAP+$INDEX_ALLOCATION resident?
+ // yes -> make non-resident
+ // does it fit now? yes -> do it.
+ // make all attributes non-resident
+ // does it fit now? yes -> do it.
+ // m is a base record? yes -> allocate extension record
+ // does the new attribute fit in there? yes -> do it.
+ // split up run_list into extents and place each in an extension
+ // record.
+ // FIXME: the check for needing extension records should be
+ // earlier on as it is very quick: asize > m->bytes_allocated?
+ err = -ENOTSUP;
+ goto err_out;
+ }
+#ifdef DEBUG
+ if (err == -EINVAL) {
+ fprintf(stderr, "BUG(): in insert_resident_attribute_in_mft_"
+ "record(): make_room_for_attribute() returned "
+ "error: EINVAL!\n");
+ goto err_out;
+ }
+#endif
+ a->type = type;
+ a->length = cpu_to_le32(asize);
+ a->non_resident = 0;
+ a->name_length = name_len;
+ a->name_offset = cpu_to_le16(24);
+ a->flags = cpu_to_le16(flags);
+ a->instance = m->next_attr_instance;
+ m->next_attr_instance = cpu_to_le16((le16_to_cpu(m->next_attr_instance)
+ + 1) & 0xffff);
+ a->value_length = cpu_to_le32(val_len);
+ a->value_offset = cpu_to_le16(24 + ((name_len + 7) & ~7));
+ a->resident_flags = res_flags;
+ a->reservedR = 0;
+ if (name_len)
+ memcpy((char*)a + 24, uname, name_len << 1);
+ if (val_len)
+ memcpy((char*)a + le16_to_cpu(a->value_offset), val, val_len);
+err_out:
+ if (ctx)
+ ntfs_put_attr_search_ctx(ctx);
+ if (uname)
+ free(uname);
+ return err;
}
|