"Fossies" - the Fresh Open Source Software Archive

Member "ntfs-3g_ntfsprogs-2017.3.23/libntfs-3g/object_id.c" (23 Mar 2017, 16141 Bytes) of package /linux/misc/ntfs-3g_ntfsprogs-2017.3.23.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "object_id.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3g_ntfsprogs-2016.2.22_vs_3g_ntfsprogs-2017.3.23.

    1 /**
    2  * object_id.c - Processing of object ids
    3  *
    4  *  This module is part of ntfs-3g library
    5  *
    6  * Copyright (c) 2009 Jean-Pierre Andre
    7  *
    8  * This program/include file is free software; you can redistribute it and/or
    9  * modify it under the terms of the GNU General Public License as published
   10  * by the Free Software Foundation; either version 2 of the License, or
   11  * (at your option) any later version.
   12  *
   13  * This program/include file is distributed in the hope that it will be
   14  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
   15  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  * GNU General Public License for more details.
   17  *
   18  * You should have received a copy of the GNU General Public License
   19  * along with this program (in the main directory of the NTFS-3G
   20  * distribution in the file COPYING); if not, write to the Free Software
   21  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22  */
   23 
   24 #ifdef HAVE_CONFIG_H
   25 #include "config.h"
   26 #endif
   27 
   28 #ifdef HAVE_STDLIB_H
   29 #include <stdlib.h>
   30 #endif
   31 #ifdef HAVE_ERRNO_H
   32 #include <errno.h>
   33 #endif
   34 #ifdef HAVE_STRING_H
   35 #include <string.h>
   36 #endif
   37 #ifdef HAVE_SYS_STAT_H
   38 #include <sys/stat.h>
   39 #endif
   40 #ifdef HAVE_SYS_SYSMACROS_H
   41 #include <sys/sysmacros.h>
   42 #endif
   43 
   44 #include "compat.h"
   45 #include "types.h"
   46 #include "debug.h"
   47 #include "attrib.h"
   48 #include "inode.h"
   49 #include "dir.h"
   50 #include "volume.h"
   51 #include "mft.h"
   52 #include "index.h"
   53 #include "lcnalloc.h"
   54 #include "object_id.h"
   55 #include "logging.h"
   56 #include "misc.h"
   57 #include "xattrs.h"
   58 
   59 /*
   60  *          Endianness considerations
   61  *
   62  *  According to RFC 4122, GUIDs should be printed with the most
   63  *  significant byte first, and the six fields be compared individually
   64  *  for ordering. RFC 4122 does not define the internal representation.
   65  *
   66  *  Here we always copy disk images with no endianness change,
   67  *  and, for indexing, GUIDs are compared as if they were a sequence
   68  *  of four unsigned 32 bit integers.
   69  *
   70  * --------------------- begin from RFC 4122 ----------------------
   71  * Consider each field of the UUID to be an unsigned integer as shown
   72  * in the table in section Section 4.1.2.  Then, to compare a pair of
   73  * UUIDs, arithmetically compare the corresponding fields from each
   74  * UUID in order of significance and according to their data type.
   75  * Two UUIDs are equal if and only if all the corresponding fields
   76  * are equal.
   77  *
   78  * UUIDs, as defined in this document, can also be ordered
   79  * lexicographically.  For a pair of UUIDs, the first one follows the
   80  * second if the most significant field in which the UUIDs differ is
   81  * greater for the first UUID.  The second precedes the first if the
   82  * most significant field in which the UUIDs differ is greater for
   83  * the second UUID.
   84  *
   85  * The fields are encoded as 16 octets, with the sizes and order of the
   86  * fields defined above, and with each field encoded with the Most
   87  * Significant Byte first (known as network byte order).  Note that the
   88  * field names, particularly for multiplexed fields, follow historical
   89  * practice.
   90  *
   91  * 0                   1                   2                   3
   92  *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
   93  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   94  * |                          time_low                             |
   95  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   96  * |       time_mid                |         time_hi_and_version   |
   97  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
   98  * |clk_seq_hi_res |  clk_seq_low  |         node (0-1)            |
   99  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  100  * |                         node (2-5)                            |
  101  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  102  *
  103  * ---------------------- end from RFC 4122 -----------------------
  104  */
  105 
  106 typedef struct {
  107     union {
  108         /* alignment may be needed to evaluate collations */
  109         u32 alignment;
  110         GUID guid;
  111     } object_id;
  112 } OBJECT_ID_INDEX_KEY;
  113 
  114 typedef struct {
  115     le64 file_id;
  116     GUID birth_volume_id;
  117     GUID birth_object_id;
  118     GUID domain_id;
  119 } OBJECT_ID_INDEX_DATA; // known as OBJ_ID_INDEX_DATA
  120 
  121 struct OBJECT_ID_INDEX {        /* index entry in $Extend/$ObjId */
  122     INDEX_ENTRY_HEADER header;
  123     OBJECT_ID_INDEX_KEY key;
  124     OBJECT_ID_INDEX_DATA data;
  125 } ;
  126 
  127 static ntfschar objid_index_name[] = { const_cpu_to_le16('$'),
  128                      const_cpu_to_le16('O') };
  129 
  130 /*
  131  *          Set the index for a new object id
  132  *
  133  *  Returns 0 if success
  134  *      -1 if failure, explained by errno
  135  */
  136 
  137 static int set_object_id_index(ntfs_inode *ni, ntfs_index_context *xo,
  138             const OBJECT_ID_ATTR *object_id)
  139 {
  140     struct OBJECT_ID_INDEX indx;
  141     u64 file_id_cpu;
  142     le64 file_id;
  143     le16 seqn;
  144 
  145     seqn = ni->mrec->sequence_number;
  146     file_id_cpu = MK_MREF(ni->mft_no,le16_to_cpu(seqn));
  147     file_id = cpu_to_le64(file_id_cpu);
  148     indx.header.data_offset = const_cpu_to_le16(
  149                     sizeof(INDEX_ENTRY_HEADER)
  150                     + sizeof(OBJECT_ID_INDEX_KEY));
  151     indx.header.data_length = const_cpu_to_le16(
  152                     sizeof(OBJECT_ID_INDEX_DATA));
  153     indx.header.reservedV = const_cpu_to_le32(0);
  154     indx.header.length = const_cpu_to_le16(
  155                     sizeof(struct OBJECT_ID_INDEX));
  156     indx.header.key_length = const_cpu_to_le16(
  157                     sizeof(OBJECT_ID_INDEX_KEY));
  158     indx.header.flags = const_cpu_to_le16(0);
  159     indx.header.reserved = const_cpu_to_le16(0);
  160 
  161     memcpy(&indx.key.object_id,object_id,sizeof(GUID));
  162 
  163     indx.data.file_id = file_id;
  164     memcpy(&indx.data.birth_volume_id,
  165             &object_id->birth_volume_id,sizeof(GUID));
  166     memcpy(&indx.data.birth_object_id,
  167             &object_id->birth_object_id,sizeof(GUID));
  168     memcpy(&indx.data.domain_id,
  169             &object_id->domain_id,sizeof(GUID));
  170     ntfs_index_ctx_reinit(xo);
  171     return (ntfs_ie_add(xo,(INDEX_ENTRY*)&indx));
  172 }
  173 
  174 /*
  175  *      Open the $Extend/$ObjId file and its index
  176  *
  177  *  Return the index context if opened
  178  *      or NULL if an error occurred (errno tells why)
  179  *
  180  *  The index has to be freed and inode closed when not needed any more.
  181  */
  182 
  183 static ntfs_index_context *open_object_id_index(ntfs_volume *vol)
  184 {
  185     u64 inum;
  186     ntfs_inode *ni;
  187     ntfs_inode *dir_ni;
  188     ntfs_index_context *xo;
  189 
  190         /* do not use path_name_to inode - could reopen root */
  191     dir_ni = ntfs_inode_open(vol, FILE_Extend);
  192     ni = (ntfs_inode*)NULL;
  193     if (dir_ni) {
  194         inum = ntfs_inode_lookup_by_mbsname(dir_ni,"$ObjId");
  195         if (inum != (u64)-1)
  196             ni = ntfs_inode_open(vol, inum);
  197         ntfs_inode_close(dir_ni);
  198     }
  199     if (ni) {
  200         xo = ntfs_index_ctx_get(ni, objid_index_name, 2);
  201         if (!xo) {
  202             ntfs_inode_close(ni);
  203         }
  204     } else
  205         xo = (ntfs_index_context*)NULL;
  206     return (xo);
  207 }
  208 
  209 
  210 /*
  211  *      Merge object_id data stored in the index into
  212  *  a full object_id struct.
  213  *
  214  *  returns 0 if merging successful
  215  *      -1 if no data could be merged. This is generally not an error
  216  */
  217 
  218 static int merge_index_data(ntfs_inode *ni,
  219             const OBJECT_ID_ATTR *objectid_attr,
  220             OBJECT_ID_ATTR *full_objectid)
  221 {
  222     OBJECT_ID_INDEX_KEY key;
  223     struct OBJECT_ID_INDEX *entry;
  224     ntfs_index_context *xo;
  225     ntfs_inode *xoni;
  226     int res;
  227 
  228     res = -1;
  229     xo = open_object_id_index(ni->vol);
  230     if (xo) {
  231         memcpy(&key.object_id,objectid_attr,sizeof(GUID));
  232         if (!ntfs_index_lookup(&key,
  233                 sizeof(OBJECT_ID_INDEX_KEY), xo)) {
  234             entry = (struct OBJECT_ID_INDEX*)xo->entry;
  235             /* make sure inode numbers match */
  236             if (entry
  237                 && (MREF(le64_to_cpu(entry->data.file_id))
  238                     == ni->mft_no)) {
  239                 memcpy(&full_objectid->birth_volume_id,
  240                         &entry->data.birth_volume_id,
  241                         sizeof(GUID));
  242                 memcpy(&full_objectid->birth_object_id,
  243                         &entry->data.birth_object_id,
  244                         sizeof(GUID));
  245                 memcpy(&full_objectid->domain_id,
  246                         &entry->data.domain_id,
  247                         sizeof(GUID));
  248                 res = 0;
  249             }
  250         }
  251         xoni = xo->ni;
  252         ntfs_index_ctx_put(xo);
  253         ntfs_inode_close(xoni);
  254     }
  255     return (res);
  256 }
  257 
  258 
  259 /*
  260  *      Remove an object id index entry if attribute present
  261  *
  262  *  Returns the size of existing object id
  263  *          (the existing object_d is returned)
  264  *      -1 if failure, explained by errno
  265  */
  266 
  267 static int remove_object_id_index(ntfs_attr *na, ntfs_index_context *xo,
  268                 OBJECT_ID_ATTR *old_attr)
  269 {
  270     OBJECT_ID_INDEX_KEY key;
  271     struct OBJECT_ID_INDEX *entry;
  272     s64 size;
  273     int ret;
  274 
  275     ret = na->data_size;
  276     if (ret) {
  277             /* read the existing object id attribute */
  278         size = ntfs_attr_pread(na, 0, sizeof(GUID), old_attr);
  279         if (size >= (s64)sizeof(GUID)) {
  280             memcpy(&key.object_id,
  281                 &old_attr->object_id,sizeof(GUID));
  282             if (!ntfs_index_lookup(&key,
  283                     sizeof(OBJECT_ID_INDEX_KEY), xo)) {
  284                 entry = (struct OBJECT_ID_INDEX*)xo->entry;
  285                 memcpy(&old_attr->birth_volume_id,
  286                     &entry->data.birth_volume_id,
  287                     sizeof(GUID));
  288                 memcpy(&old_attr->birth_object_id,
  289                     &entry->data.birth_object_id,
  290                     sizeof(GUID));
  291                 memcpy(&old_attr->domain_id,
  292                     &entry->data.domain_id,
  293                     sizeof(GUID));
  294                 if (ntfs_index_rm(xo))
  295                     ret = -1;
  296             }
  297         } else {
  298             ret = -1;
  299             errno = ENODATA;
  300         }
  301     }
  302     return (ret);
  303 }
  304 
  305 
  306 /*
  307  *      Update the object id and index
  308  *
  309  *  The object_id attribute should have been created and the
  310  *  non-duplication of the GUID should have been checked before.
  311  *
  312  *  Returns 0 if success
  313  *      -1 if failure, explained by errno
  314  *  If could not remove the existing index, nothing is done,
  315  *  If could not write the new data, no index entry is inserted
  316  *  If failed to insert the index, data is removed
  317  */
  318 
  319 static int update_object_id(ntfs_inode *ni, ntfs_index_context *xo,
  320             const OBJECT_ID_ATTR *value, size_t size)
  321 {
  322     OBJECT_ID_ATTR old_attr;
  323     ntfs_attr *na;
  324     int oldsize;
  325     int written;
  326     int res;
  327 
  328     res = 0;
  329 
  330     na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
  331     if (na) {
  332 
  333             /* remove the existing index entry */
  334         oldsize = remove_object_id_index(na,xo,&old_attr);
  335         if (oldsize < 0)
  336             res = -1;
  337         else {
  338             /* resize attribute */
  339             res = ntfs_attr_truncate(na, (s64)sizeof(GUID));
  340                 /* write the object_id in attribute */
  341             if (!res && value) {
  342                 written = (int)ntfs_attr_pwrite(na,
  343                     (s64)0, (s64)sizeof(GUID),
  344                     &value->object_id);
  345                 if (written != (s64)sizeof(GUID)) {
  346                     ntfs_log_error("Failed to update "
  347                             "object id\n");
  348                     errno = EIO;
  349                     res = -1;
  350                 }
  351             }
  352                 /* write index part if provided */
  353             if (!res
  354                 && ((size < sizeof(OBJECT_ID_ATTR))
  355                  || set_object_id_index(ni,xo,value))) {
  356                 /*
  357                  * If cannot index, try to remove the object
  358                  * id and log the error. There will be an
  359                  * inconsistency if removal fails.
  360                  */
  361                 ntfs_attr_rm(na);
  362                 ntfs_log_error("Failed to index object id."
  363                         " Possible corruption.\n");
  364             }
  365         }
  366         ntfs_attr_close(na);
  367         NInoSetDirty(ni);
  368     } else
  369         res = -1;
  370     return (res);
  371 }
  372 
  373 /*
  374  *      Add a (dummy) object id to an inode if it does not exist
  375  *
  376  *  returns 0 if attribute was inserted (or already present)
  377  *      -1 if adding failed (explained by errno)
  378  */
  379 
  380 static int add_object_id(ntfs_inode *ni, int flags)
  381 {
  382     int res;
  383     u8 dummy;
  384 
  385     res = -1; /* default return */
  386     if (!ntfs_attr_exist(ni,AT_OBJECT_ID, AT_UNNAMED,0)) {
  387         if (!(flags & XATTR_REPLACE)) {
  388             /*
  389              * no object id attribute : add one,
  390              * apparently, this does not feed the new value in
  391              * Note : NTFS version must be >= 3
  392              */
  393             if (ni->vol->major_ver >= 3) {
  394                 res = ntfs_attr_add(ni, AT_OBJECT_ID,
  395                         AT_UNNAMED, 0, &dummy, (s64)0);
  396                 NInoSetDirty(ni);
  397             } else
  398                 errno = EOPNOTSUPP;
  399         } else
  400             errno = ENODATA;
  401     } else {
  402         if (flags & XATTR_CREATE)
  403             errno = EEXIST;
  404         else
  405             res = 0;
  406     }
  407     return (res);
  408 }
  409 
  410 
  411 /*
  412  *      Delete an object_id index entry
  413  *
  414  *  Returns 0 if success
  415  *      -1 if failure, explained by errno
  416  */
  417 
  418 int ntfs_delete_object_id_index(ntfs_inode *ni)
  419 {
  420     ntfs_index_context *xo;
  421     ntfs_inode *xoni;
  422     ntfs_attr *na;
  423     OBJECT_ID_ATTR old_attr;
  424     int res;
  425 
  426     res = 0;
  427     na = ntfs_attr_open(ni, AT_OBJECT_ID, AT_UNNAMED, 0);
  428     if (na) {
  429             /*
  430              * read the existing object id
  431              * and un-index it
  432              */
  433         xo = open_object_id_index(ni->vol);
  434         if (xo) {
  435             if (remove_object_id_index(na,xo,&old_attr) < 0)
  436                 res = -1;
  437             xoni = xo->ni;
  438             ntfs_index_entry_mark_dirty(xo);
  439             NInoSetDirty(xoni);
  440             ntfs_index_ctx_put(xo);
  441             ntfs_inode_close(xoni);
  442         }
  443         ntfs_attr_close(na);
  444     }
  445     return (res);
  446 }
  447 
  448 
  449 /*
  450  *      Get the ntfs object id into an extended attribute
  451  *
  452  *  If present, the object_id from the attribute and the GUIDs
  453  *  from the index are returned (formatted as OBJECT_ID_ATTR)
  454  *
  455  *  Returns the global size (can be 0, 16 or 64)
  456  *      and the buffer is updated if it is long enough
  457  */
  458 
  459 int ntfs_get_ntfs_object_id(ntfs_inode *ni, char *value, size_t size)
  460 {
  461     OBJECT_ID_ATTR full_objectid;
  462     OBJECT_ID_ATTR *objectid_attr;
  463     s64 attr_size;
  464     int full_size;
  465 
  466     full_size = 0;  /* default to no data and some error to be defined */
  467     if (ni) {
  468         objectid_attr = (OBJECT_ID_ATTR*)ntfs_attr_readall(ni,
  469             AT_OBJECT_ID,(ntfschar*)NULL, 0, &attr_size);
  470         if (objectid_attr) {
  471                 /* restrict to only GUID present in attr */
  472             if (attr_size == sizeof(GUID)) {
  473                 memcpy(&full_objectid.object_id,
  474                         objectid_attr,sizeof(GUID));
  475                 full_size = sizeof(GUID);
  476                     /* get data from index, if any */
  477                 if (!merge_index_data(ni, objectid_attr,
  478                         &full_objectid)) {
  479                     full_size = sizeof(OBJECT_ID_ATTR);
  480                 }
  481                 if (full_size <= (s64)size) {
  482                     if (value)
  483                         memcpy(value,&full_objectid,
  484                             full_size);
  485                     else
  486                         errno = EINVAL;
  487                 }
  488             } else {
  489             /* unexpected size, better return unsupported */
  490                 errno = EOPNOTSUPP;
  491                 full_size = 0;
  492             }
  493             free(objectid_attr);
  494         } else
  495             errno = ENODATA;
  496     }
  497     return (full_size ? (int)full_size : -errno);
  498 }
  499 
  500 /*
  501  *      Set the object id from an extended attribute
  502  *
  503  *  If the size is 64, the attribute and index are set.
  504  *  else if the size is not less than 16 only the attribute is set.
  505  *  The object id index is set accordingly.
  506  *
  507  *  Returns 0, or -1 if there is a problem
  508  */
  509 
  510 int ntfs_set_ntfs_object_id(ntfs_inode *ni,
  511             const char *value, size_t size, int flags)
  512 {
  513     OBJECT_ID_INDEX_KEY key;
  514     ntfs_inode *xoni;
  515     ntfs_index_context *xo;
  516     int res;
  517 
  518     res = 0;
  519     if (ni && value && (size >= sizeof(GUID))) {
  520         xo = open_object_id_index(ni->vol);
  521         if (xo) {
  522             /* make sure the GUID was not used somewhere */
  523             memcpy(&key.object_id, value, sizeof(GUID));
  524             if (ntfs_index_lookup(&key,
  525                     sizeof(OBJECT_ID_INDEX_KEY), xo)) {
  526                 ntfs_index_ctx_reinit(xo);
  527                 res = add_object_id(ni, flags);
  528                 if (!res) {
  529                         /* update value and index */
  530                     res = update_object_id(ni,xo,
  531                         (const OBJECT_ID_ATTR*)value,
  532                         size);
  533                 }
  534             } else {
  535                     /* GUID is present elsewhere */
  536                 res = -1;
  537                 errno = EEXIST;
  538             }
  539             xoni = xo->ni;
  540             ntfs_index_entry_mark_dirty(xo);
  541             NInoSetDirty(xoni);
  542             ntfs_index_ctx_put(xo);
  543             ntfs_inode_close(xoni);
  544         } else {
  545             res = -1;
  546         }
  547     } else {
  548         errno = EINVAL;
  549         res = -1;
  550     }
  551     return (res ? -1 : 0);
  552 }
  553 
  554 /*
  555  *      Remove the object id
  556  *
  557  *  Returns 0, or -1 if there is a problem
  558  */
  559 
  560 int ntfs_remove_ntfs_object_id(ntfs_inode *ni)
  561 {
  562     int res;
  563     int olderrno;
  564     ntfs_attr *na;
  565     ntfs_inode *xoni;
  566     ntfs_index_context *xo;
  567     int oldsize;
  568     OBJECT_ID_ATTR old_attr;
  569 
  570     res = 0;
  571     if (ni) {
  572         /*
  573          * open and delete the object id
  574          */
  575         na = ntfs_attr_open(ni, AT_OBJECT_ID,
  576             AT_UNNAMED,0);
  577         if (na) {
  578             /* first remove index (old object id needed) */
  579             xo = open_object_id_index(ni->vol);
  580             if (xo) {
  581                 oldsize = remove_object_id_index(na,xo,
  582                         &old_attr);
  583                 if (oldsize < 0) {
  584                     res = -1;
  585                 } else {
  586                     /* now remove attribute */
  587                     res = ntfs_attr_rm(na);
  588                     if (res
  589                         && (oldsize > (int)sizeof(GUID))) {
  590                     /*
  591                      * If we could not remove the
  592                      * attribute, try to restore the
  593                      * index and log the error. There
  594                      * will be an inconsistency if
  595                      * the reindexing fails.
  596                      */
  597                         set_object_id_index(ni, xo,
  598                             &old_attr);
  599                         ntfs_log_error(
  600                         "Failed to remove object id."
  601                         " Possible corruption.\n");
  602                     }
  603                 }
  604 
  605                 xoni = xo->ni;
  606                 ntfs_index_entry_mark_dirty(xo);
  607                 NInoSetDirty(xoni);
  608                 ntfs_index_ctx_put(xo);
  609                 ntfs_inode_close(xoni);
  610             }
  611             olderrno = errno;
  612             ntfs_attr_close(na);
  613                     /* avoid errno pollution */
  614             if (errno == ENOENT)
  615                 errno = olderrno;
  616         } else {
  617             errno = ENODATA;
  618             res = -1;
  619         }
  620         NInoSetDirty(ni);
  621     } else {
  622         errno = EINVAL;
  623         res = -1;
  624     }
  625     return (res ? -1 : 0);
  626 }