LCOV - code coverage report
Current view: top level - source3/lib - adouble.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 1170 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 44 0.0 %

          Line data    Source code
       1             : /*
       2             :  * Samba AppleDouble helpers
       3             :  *
       4             :  * Copyright (C) Ralph Boehme, 2019
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify
       7             :  * it under the terms of the GNU General Public License as published by
       8             :  * the Free Software Foundation; either version 3 of the License, or
       9             :  * (at your option) any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful,
      12             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      14             :  * GNU General Public License for more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License
      17             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      18             :  */
      19             : 
      20             : #include "includes.h"
      21             : #include "adouble.h"
      22             : #include "MacExtensions.h"
      23             : #include "string_replace.h"
      24             : #include "smbd/smbd.h"
      25             : #include "system/filesys.h"
      26             : #include "libcli/security/security.h"
      27             : #include "lib/util_macstreams.h"
      28             : #include "auth.h"
      29             : 
      30             : /*
      31             :    "._" AppleDouble Header File Layout:
      32             : 
      33             :          MAGIC          0x00051607
      34             :          VERSION        0x00020000
      35             :          FILLER         0
      36             :          COUNT          2
      37             :      .-- AD ENTRY[0]    Finder Info Entry (must be first)
      38             :   .--+-- AD ENTRY[1]    Resource Fork Entry (must be last)
      39             :   |  |   /////////////
      40             :   |  '-> FINDER INFO    Fixed Size Data (32 Bytes)
      41             :   |      ~~~~~~~~~~~~~  2 Bytes Padding
      42             :   |      EXT ATTR HDR   Fixed Size Data (36 Bytes)
      43             :   |      /////////////
      44             :   |      ATTR ENTRY[0] --.
      45             :   |      ATTR ENTRY[1] --+--.
      46             :   |      ATTR ENTRY[2] --+--+--.
      47             :   |         ...          |  |  |
      48             :   |      ATTR ENTRY[N] --+--+--+--.
      49             :   |      ATTR DATA 0   <-'  |  |  |
      50             :   |      ////////////       |  |  |
      51             :   |      ATTR DATA 1   <----'  |  |
      52             :   |      /////////////         |  |
      53             :   |      ATTR DATA 2   <-------'  |
      54             :   |      /////////////            |
      55             :   |         ...                   |
      56             :   |      ATTR DATA N   <----------'
      57             :   |      /////////////
      58             :   |         ...          Attribute Free Space
      59             :   |
      60             :   '----> RESOURCE FORK
      61             :             ...          Variable Sized Data
      62             :             ...
      63             : */
      64             : 
      65             : /* Number of actually used entries */
      66             : #define ADEID_NUM_XATTR      8
      67             : #define ADEID_NUM_DOT_UND    2
      68             : #define ADEID_NUM_RSRC_XATTR 1
      69             : 
      70             : /* Sizes of relevant entry bits */
      71             : #define ADEDLEN_MAGIC       4
      72             : #define ADEDLEN_VERSION     4
      73             : #define ADEDLEN_FILLER      16
      74             : #define AD_FILLER_TAG       "Netatalk        " /* should be 16 bytes */
      75             : #define AD_FILLER_TAG_OSX   "Mac OS X        " /* should be 16 bytes */
      76             : #define ADEDLEN_NENTRIES    2
      77             : #define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
      78             :                              ADEDLEN_FILLER + ADEDLEN_NENTRIES) /* 26 */
      79             : #define AD_ENTRY_LEN_EID    4
      80             : #define AD_ENTRY_LEN_OFF    4
      81             : #define AD_ENTRY_LEN_LEN    4
      82             : #define AD_ENTRY_LEN (AD_ENTRY_LEN_EID + AD_ENTRY_LEN_OFF + AD_ENTRY_LEN_LEN)
      83             : 
      84             : /* Offsets */
      85             : #define ADEDOFF_MAGIC         0
      86             : #define ADEDOFF_VERSION       (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
      87             : #define ADEDOFF_FILLER        (ADEDOFF_VERSION + ADEDLEN_VERSION)
      88             : #define ADEDOFF_NENTRIES      (ADEDOFF_FILLER + ADEDLEN_FILLER)
      89             : 
      90             : #define ADEDOFF_FINDERI_XATTR    (AD_HEADER_LEN + \
      91             :                                   (ADEID_NUM_XATTR * AD_ENTRY_LEN))
      92             : #define ADEDOFF_COMMENT_XATTR    (ADEDOFF_FINDERI_XATTR    + ADEDLEN_FINDERI)
      93             : #define ADEDOFF_FILEDATESI_XATTR (ADEDOFF_COMMENT_XATTR    + ADEDLEN_COMMENT)
      94             : #define ADEDOFF_AFPFILEI_XATTR   (ADEDOFF_FILEDATESI_XATTR + \
      95             :                                   ADEDLEN_FILEDATESI)
      96             : #define ADEDOFF_PRIVDEV_XATTR    (ADEDOFF_AFPFILEI_XATTR   + ADEDLEN_AFPFILEI)
      97             : #define ADEDOFF_PRIVINO_XATTR    (ADEDOFF_PRIVDEV_XATTR    + ADEDLEN_PRIVDEV)
      98             : #define ADEDOFF_PRIVSYN_XATTR    (ADEDOFF_PRIVINO_XATTR    + ADEDLEN_PRIVINO)
      99             : #define ADEDOFF_PRIVID_XATTR     (ADEDOFF_PRIVSYN_XATTR    + ADEDLEN_PRIVSYN)
     100             : 
     101             : #define ADEDOFF_FINDERI_DOT_UND  (AD_HEADER_LEN + \
     102             :                                   (ADEID_NUM_DOT_UND * AD_ENTRY_LEN))
     103             : #define ADEDOFF_RFORK_DOT_UND    (ADEDOFF_FINDERI_DOT_UND + ADEDLEN_FINDERI)
     104             : 
     105             : #define AD_DATASZ_XATTR (AD_HEADER_LEN + \
     106             :                          (ADEID_NUM_XATTR * AD_ENTRY_LEN) + \
     107             :                          ADEDLEN_FINDERI + ADEDLEN_COMMENT + \
     108             :                          ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + \
     109             :                          ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
     110             :                          ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
     111             : 
     112             : #if AD_DATASZ_XATTR != 402
     113             : #error bad size for AD_DATASZ_XATTR
     114             : #endif
     115             : 
     116             : #define AD_DATASZ_DOT_UND (AD_HEADER_LEN + \
     117             :                            (ADEID_NUM_DOT_UND * AD_ENTRY_LEN) + \
     118             :                            ADEDLEN_FINDERI)
     119             : #if AD_DATASZ_DOT_UND != 82
     120             : #error bad size for AD_DATASZ_DOT_UND
     121             : #endif
     122             : 
     123             : #define AD_XATTR_HDR_MAGIC    0x41545452 /* 'ATTR' */
     124             : #define AD_XATTR_MAX_ENTRIES  1024 /* Some arbitrarily enforced limit */
     125             : #define AD_XATTR_HDR_SIZE     36
     126             : #define AD_XATTR_MAX_HDR_SIZE 65536
     127             : #define ADX_ENTRY_FIXED_SIZE  (4+4+2+1)
     128             : 
     129             : /*
     130             :  * Both struct ad_xattr_header and struct ad_xattr_entry describe the in memory
     131             :  * representation as well as the on-disk format.
     132             :  *
     133             :  * The ad_xattr_header follows the FinderInfo data in the FinderInfo entry if
     134             :  * the length of the FinderInfo entry is larger then 32 bytes. It is then
     135             :  * preceeded with 2 bytes padding.
     136             :  *
     137             :  * Cf: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/vfs/vfs_xattr.c
     138             :  */
     139             : 
     140             : struct ad_xattr_header {
     141             :         uint32_t adx_magic;        /* ATTR_HDR_MAGIC */
     142             :         uint32_t adx_debug_tag;    /* for debugging == file id of owning file */
     143             :         uint32_t adx_total_size;   /* file offset of end of attribute header + entries + data */
     144             :         uint32_t adx_data_start;   /* file offset to attribute data area */
     145             :         uint32_t adx_data_length;  /* length of attribute data area */
     146             :         uint32_t adx_reserved[3];
     147             :         uint16_t adx_flags;
     148             :         uint16_t adx_num_attrs;
     149             : };
     150             : 
     151             : /* On-disk entries are aligned on 4 byte boundaries */
     152             : struct ad_xattr_entry {
     153             :         uint32_t adx_offset;    /* file offset to data */
     154             :         uint32_t adx_length;    /* size of attribute data */
     155             :         uint16_t adx_flags;
     156             :         uint8_t  adx_namelen;   /* included the NULL terminator */
     157             :         char    *adx_name;      /* NULL-terminated UTF-8 name */
     158             : };
     159             : 
     160             : struct ad_entry {
     161             :         size_t ade_off;
     162             :         size_t ade_len;
     163             : };
     164             : 
     165             : struct adouble {
     166             :         files_struct             *ad_fsp;
     167             :         bool                      ad_opened;
     168             :         adouble_type_t            ad_type;
     169             :         uint32_t                  ad_magic;
     170             :         uint32_t                  ad_version;
     171             :         uint8_t                   ad_filler[ADEDLEN_FILLER];
     172             :         struct ad_entry           ad_eid[ADEID_MAX];
     173             :         char                     *ad_data;
     174             :         char                     *ad_rsrc_data;
     175             :         struct ad_xattr_header    adx_header;
     176             :         struct ad_xattr_entry    *adx_entries;
     177             :         char                     *adx_data;
     178             : };
     179             : 
     180             : struct ad_entry_order {
     181             :         uint32_t id, offset, len;
     182             : };
     183             : 
     184             : /* Netatalk AppleDouble metadata xattr */
     185             : static const
     186             : struct ad_entry_order entry_order_meta_xattr[ADEID_NUM_XATTR + 1] = {
     187             :         {ADEID_FINDERI,    ADEDOFF_FINDERI_XATTR,    ADEDLEN_FINDERI},
     188             :         {ADEID_COMMENT,    ADEDOFF_COMMENT_XATTR,    0},
     189             :         {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_XATTR, ADEDLEN_FILEDATESI},
     190             :         {ADEID_AFPFILEI,   ADEDOFF_AFPFILEI_XATTR,   ADEDLEN_AFPFILEI},
     191             :         {ADEID_PRIVDEV,    ADEDOFF_PRIVDEV_XATTR,    0},
     192             :         {ADEID_PRIVINO,    ADEDOFF_PRIVINO_XATTR,    0},
     193             :         {ADEID_PRIVSYN,    ADEDOFF_PRIVSYN_XATTR,    0},
     194             :         {ADEID_PRIVID,     ADEDOFF_PRIVID_XATTR,     0},
     195             :         {0, 0, 0}
     196             : };
     197             : 
     198             : /* AppleDouble resource fork file (the ones prefixed by "._") */
     199             : static const
     200             : struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
     201             :         {ADEID_FINDERI,    ADEDOFF_FINDERI_DOT_UND,  ADEDLEN_FINDERI},
     202             :         {ADEID_RFORK,      ADEDOFF_RFORK_DOT_UND,    0},
     203             :         {0, 0, 0}
     204             : };
     205             : 
     206             : /* Conversion from enumerated id to on-disk AppleDouble id */
     207             : #define AD_EID_DISK(a) (set_eid[a])
     208             : static const uint32_t set_eid[] = {
     209             :         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
     210             :         AD_DEV, AD_INO, AD_SYN, AD_ID
     211             : };
     212             : 
     213             : static char empty_resourcefork[] = {
     214             :         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
     215             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
     216             :         0x54, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73,
     217             :         0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x66, 0x6F,
     218             :         0x72, 0x6B, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E,
     219             :         0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x6C, 0x79,
     220             :         0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x62, 0x6C,
     221             :         0x61, 0x6E, 0x6B, 0x20, 0x20, 0x20, 0x00, 0x00,
     222             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     223             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     224             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     225             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     226             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     227             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     228             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     229             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     230             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     231             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     232             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     233             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     234             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     235             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     236             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     237             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     238             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     239             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     240             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     241             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     242             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     243             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     244             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     245             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     246             :         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
     247             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
     248             :         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
     249             :         0x00, 0x1C, 0x00, 0x1E, 0xFF, 0xFF
     250             : };
     251             : 
     252           0 : size_t ad_getentrylen(const struct adouble *ad, int eid)
     253             : {
     254           0 :         return ad->ad_eid[eid].ade_len;
     255             : }
     256             : 
     257           0 : size_t ad_getentryoff(const struct adouble *ad, int eid)
     258             : {
     259           0 :         return ad->ad_eid[eid].ade_off;
     260             : }
     261             : 
     262           0 : size_t ad_setentrylen(struct adouble *ad, int eid, size_t len)
     263             : {
     264           0 :         return ad->ad_eid[eid].ade_len = len;
     265             : }
     266             : 
     267           0 : size_t ad_setentryoff(struct adouble *ad, int eid, size_t off)
     268             : {
     269           0 :         return ad->ad_eid[eid].ade_off = off;
     270             : }
     271             : 
     272             : /*
     273             :  * All entries besides FinderInfo and resource fork must fit into the
     274             :  * buffer. FinderInfo is special as it may be larger then the default 32 bytes
     275             :  * if it contains marshalled xattrs, which we will fixup that in
     276             :  * ad_convert(). The first 32 bytes however must also be part of the buffer.
     277             :  *
     278             :  * The resource fork is never accessed directly by the ad_data buf.
     279             :  */
     280           0 : static bool ad_entry_check_size(uint32_t eid,
     281             :                                 size_t bufsize,
     282             :                                 uint32_t off,
     283             :                                 uint32_t got_len)
     284             : {
     285             :         struct {
     286             :                 off_t expected_len;
     287             :                 bool fixed_size;
     288             :                 bool minimum_size;
     289           0 :         } ad_checks[] = {
     290             :                 [ADEID_DFORK] = {-1, false, false}, /* not applicable */
     291             :                 [ADEID_RFORK] = {-1, false, false}, /* no limit */
     292             :                 [ADEID_NAME] = {ADEDLEN_NAME, false, false},
     293             :                 [ADEID_COMMENT] = {ADEDLEN_COMMENT, false, false},
     294             :                 [ADEID_ICONBW] = {ADEDLEN_ICONBW, true, false},
     295             :                 [ADEID_ICONCOL] = {ADEDLEN_ICONCOL, false, false},
     296             :                 [ADEID_FILEI] = {ADEDLEN_FILEI, true, false},
     297             :                 [ADEID_FILEDATESI] = {ADEDLEN_FILEDATESI, true, false},
     298             :                 [ADEID_FINDERI] = {ADEDLEN_FINDERI, false, true},
     299             :                 [ADEID_MACFILEI] = {ADEDLEN_MACFILEI, true, false},
     300             :                 [ADEID_PRODOSFILEI] = {ADEDLEN_PRODOSFILEI, true, false},
     301             :                 [ADEID_MSDOSFILEI] = {ADEDLEN_MSDOSFILEI, true, false},
     302             :                 [ADEID_SHORTNAME] = {ADEDLEN_SHORTNAME, false, false},
     303             :                 [ADEID_AFPFILEI] = {ADEDLEN_AFPFILEI, true, false},
     304             :                 [ADEID_DID] = {ADEDLEN_DID, true, false},
     305             :                 [ADEID_PRIVDEV] = {ADEDLEN_PRIVDEV, true, false},
     306             :                 [ADEID_PRIVINO] = {ADEDLEN_PRIVINO, true, false},
     307             :                 [ADEID_PRIVSYN] = {ADEDLEN_PRIVSYN, true, false},
     308             :                 [ADEID_PRIVID] = {ADEDLEN_PRIVID, true, false},
     309             :         };
     310             : 
     311           0 :         if (eid >= ADEID_MAX) {
     312           0 :                 return false;
     313             :         }
     314           0 :         if (got_len == 0) {
     315             :                 /* Entry present, but empty, allow */
     316           0 :                 return true;
     317             :         }
     318           0 :         if (ad_checks[eid].expected_len == 0) {
     319             :                 /*
     320             :                  * Shouldn't happen: implicitly initialized to zero because
     321             :                  * explicit initializer missing.
     322             :                  */
     323           0 :                 return false;
     324             :         }
     325           0 :         if (ad_checks[eid].expected_len == -1) {
     326             :                 /* Unused or no limit */
     327           0 :                 return true;
     328             :         }
     329           0 :         if (ad_checks[eid].fixed_size) {
     330           0 :                 if (ad_checks[eid].expected_len != got_len) {
     331             :                         /* Wrong size fo fixed size entry. */
     332           0 :                         return false;
     333             :                 }
     334             :         } else {
     335           0 :                 if (ad_checks[eid].minimum_size) {
     336           0 :                         if (got_len < ad_checks[eid].expected_len) {
     337             :                                 /*
     338             :                                  * Too small for variable sized entry with
     339             :                                  * minimum size.
     340             :                                  */
     341           0 :                                 return false;
     342             :                         }
     343             :                 } else {
     344           0 :                         if (got_len > ad_checks[eid].expected_len) {
     345             :                                 /* Too big for variable sized entry. */
     346           0 :                                 return false;
     347             :                         }
     348             :                 }
     349             :         }
     350           0 :         if (off + got_len < off) {
     351             :                 /* wrap around */
     352           0 :                 return false;
     353             :         }
     354           0 :         if (off + got_len > bufsize) {
     355             :                 /* overflow */
     356           0 :                 return false;
     357             :         }
     358           0 :         return true;
     359             : }
     360             : 
     361             : /**
     362             :  * Return a pointer to an AppleDouble entry
     363             :  *
     364             :  * Returns NULL if the entry is not present
     365             :  **/
     366           0 : char *ad_get_entry(const struct adouble *ad, int eid)
     367             : {
     368           0 :         size_t bufsize = talloc_get_size(ad->ad_data);
     369           0 :         off_t off = ad_getentryoff(ad, eid);
     370           0 :         size_t len = ad_getentrylen(ad, eid);
     371             :         bool valid;
     372             : 
     373           0 :         valid = ad_entry_check_size(eid, bufsize, off, len);
     374           0 :         if (!valid) {
     375           0 :                 return NULL;
     376             :         }
     377             : 
     378           0 :         if (off == 0 || len == 0) {
     379           0 :                 return NULL;
     380             :         }
     381             : 
     382           0 :         return ad->ad_data + off;
     383             : }
     384             : 
     385             : /**
     386             :  * Get a date
     387             :  **/
     388           0 : int ad_getdate(const struct adouble *ad, unsigned int dateoff, uint32_t *date)
     389             : {
     390           0 :         bool xlate = (dateoff & AD_DATE_UNIX);
     391           0 :         char *p = NULL;
     392             : 
     393           0 :         dateoff &= AD_DATE_MASK;
     394           0 :         p = ad_get_entry(ad, ADEID_FILEDATESI);
     395           0 :         if (p == NULL) {
     396           0 :                 return -1;
     397             :         }
     398             : 
     399           0 :         if (dateoff > AD_DATE_ACCESS) {
     400           0 :             return -1;
     401             :         }
     402             : 
     403           0 :         memcpy(date, p + dateoff, sizeof(uint32_t));
     404             : 
     405           0 :         if (xlate) {
     406           0 :                 *date = AD_DATE_TO_UNIX(*date);
     407             :         }
     408           0 :         return 0;
     409             : }
     410             : 
     411             : /**
     412             :  * Set a date
     413             :  **/
     414           0 : int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
     415             : {
     416           0 :         bool xlate = (dateoff & AD_DATE_UNIX);
     417           0 :         char *p = NULL;
     418             : 
     419           0 :         p = ad_get_entry(ad, ADEID_FILEDATESI);
     420           0 :         if (p == NULL) {
     421           0 :                 return -1;
     422             :         }
     423             : 
     424           0 :         dateoff &= AD_DATE_MASK;
     425           0 :         if (xlate) {
     426           0 :                 date = AD_DATE_FROM_UNIX(date);
     427             :         }
     428             : 
     429           0 :         if (dateoff > AD_DATE_ACCESS) {
     430           0 :                 return -1;
     431             :         }
     432             : 
     433           0 :         memcpy(p + dateoff, &date, sizeof(date));
     434             : 
     435           0 :         return 0;
     436             : }
     437             : 
     438             : 
     439             : /**
     440             :  * Map on-disk AppleDouble id to enumerated id
     441             :  **/
     442           0 : static uint32_t get_eid(uint32_t eid)
     443             : {
     444           0 :         if (eid <= 15) {
     445           0 :                 return eid;
     446             :         }
     447             : 
     448           0 :         switch (eid) {
     449           0 :         case AD_DEV:
     450           0 :                 return ADEID_PRIVDEV;
     451           0 :         case AD_INO:
     452           0 :                 return ADEID_PRIVINO;
     453           0 :         case AD_SYN:
     454           0 :                 return ADEID_PRIVSYN;
     455           0 :         case AD_ID:
     456           0 :                 return ADEID_PRIVID;
     457           0 :         default:
     458           0 :                 break;
     459             :         }
     460             : 
     461           0 :         return 0;
     462             : }
     463             : 
     464             : /*
     465             :  * Move resourcefork data in an AppleDouble file
     466             :  *
     467             :  * This is supposed to make room in an AppleDouble file by moving the
     468             :  * resourcefork data behind the space required for packing additional xattr data
     469             :  * in the extended FinderInfo entry.
     470             :  *
     471             :  * When we're called we're expecting an AppleDouble file with just two entries
     472             :  * (FinderInfo an Resourcefork) and the resourcefork is expected at a fixed
     473             :  * offset of ADEDOFF_RFORK_DOT_UND.
     474             :  */
     475           0 : static bool ad_pack_move_reso(struct vfs_handle_struct *handle,
     476             :                               struct adouble *ad,
     477             :                               files_struct *fsp)
     478             : {
     479             :         size_t reso_len;
     480             :         size_t reso_off;
     481             :         size_t n;
     482             :         bool ok;
     483             : 
     484           0 :         reso_len = ad_getentrylen(ad, ADEID_RFORK);
     485           0 :         reso_off = ad_getentryoff(ad, ADEID_RFORK);
     486             : 
     487           0 :         if (reso_len == 0) {
     488           0 :                 return true;
     489             :         }
     490             : 
     491           0 :         if (ad->ad_rsrc_data == NULL) {
     492             :                 /*
     493             :                  * This buffer is already set when converting a resourcefork
     494             :                  * stream from vfs_streams_depot backend via ad_unconvert(). It
     495             :                  * is NULL with vfs_streams_xattr where the resourcefork stream
     496             :                  * is stored in an AppleDouble sidecar file vy vfs_fruit.
     497             :                  */
     498           0 :                 ad->ad_rsrc_data = talloc_size(ad, reso_len);
     499           0 :                 if (ad->ad_rsrc_data == NULL) {
     500           0 :                         return false;
     501             :                 }
     502             : 
     503           0 :                 n = SMB_VFS_NEXT_PREAD(handle,
     504             :                                        fsp,
     505             :                                        ad->ad_rsrc_data,
     506             :                                        reso_len,
     507             :                                        ADEDOFF_RFORK_DOT_UND);
     508           0 :                 if (n != reso_len) {
     509           0 :                         DBG_ERR("Read on [%s] failed\n",
     510             :                                 fsp_str_dbg(fsp));
     511           0 :                         ok = false;
     512           0 :                         goto out;
     513             :                 }
     514             :         }
     515             : 
     516           0 :         n = SMB_VFS_NEXT_PWRITE(handle,
     517             :                                 fsp,
     518             :                                 ad->ad_rsrc_data,
     519             :                                 reso_len,
     520             :                                 reso_off);
     521           0 :         if (n != reso_len) {
     522           0 :                 DBG_ERR("Write on [%s] failed\n",
     523             :                         fsp_str_dbg(fsp));
     524           0 :                 ok = false;
     525           0 :                 goto out;
     526             :         }
     527             : 
     528           0 :         ok = true;
     529           0 : out:
     530           0 :         return ok;
     531             : }
     532             : 
     533           0 : static bool ad_pack_xattrs(struct vfs_handle_struct *handle,
     534             :                            struct adouble *ad,
     535             :                            files_struct *fsp)
     536             : {
     537           0 :         struct ad_xattr_header *h = &ad->adx_header;
     538             :         size_t oldsize;
     539             :         uint32_t off;
     540             :         uint32_t data_off;
     541             :         uint16_t i;
     542             :         bool ok;
     543             : 
     544           0 :         if (ad->adx_entries == NULL) {
     545             :                 /* No xattrs, nothing to pack */
     546           0 :                 return true;
     547             :         }
     548             : 
     549           0 :         if (fsp == NULL) {
     550           0 :                 DBG_ERR("fsp unexpectedly NULL\n");
     551           0 :                 return false;
     552             :         }
     553             : 
     554           0 :         oldsize = talloc_get_size(ad->ad_data);
     555           0 :         if (oldsize < AD_XATTR_MAX_HDR_SIZE) {
     556           0 :                 ad->ad_data = talloc_realloc(ad,
     557             :                                              ad->ad_data,
     558             :                                              char,
     559             :                                              AD_XATTR_MAX_HDR_SIZE);
     560           0 :                 if (ad->ad_data == NULL) {
     561           0 :                         return false;
     562             :                 }
     563           0 :                 memset(ad->ad_data + oldsize,
     564             :                        0,
     565             :                        AD_XATTR_MAX_HDR_SIZE - oldsize);
     566             :         }
     567             : 
     568             :         /*
     569             :          * First, let's calculate the start of the xattr data area which will be
     570             :          * after the xattr header + header entries.
     571             :          */
     572             : 
     573           0 :         data_off = ad_getentryoff(ad, ADEID_FINDERI);
     574           0 :         data_off += ADEDLEN_FINDERI + AD_XATTR_HDR_SIZE;
     575             :         /* 2 bytes padding */
     576           0 :         data_off += 2;
     577             : 
     578           0 :         for (i = 0; i < h->adx_num_attrs; i++) {
     579           0 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
     580             : 
     581             :                 /* Align on 4 byte boundary */
     582           0 :                 data_off = (data_off + 3) & ~3;
     583             : 
     584           0 :                 data_off += e->adx_namelen + ADX_ENTRY_FIXED_SIZE;
     585           0 :                 if (data_off >= AD_XATTR_MAX_HDR_SIZE) {
     586           0 :                         return false;
     587             :                 }
     588             :         }
     589             : 
     590           0 :         off = ad_getentryoff(ad, ADEID_FINDERI);
     591           0 :         off +=  ADEDLEN_FINDERI + AD_XATTR_HDR_SIZE;
     592             :         /* 2 bytes padding */
     593           0 :         off += 2;
     594             : 
     595           0 :         for (i = 0; i < h->adx_num_attrs; i++) {
     596           0 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
     597             : 
     598             :                 /* Align on 4 byte boundary */
     599           0 :                 off = (off + 3) & ~3;
     600             : 
     601           0 :                 e->adx_offset = data_off;
     602           0 :                 data_off += e->adx_length;
     603             : 
     604           0 :                 DBG_DEBUG("%zu(%s){%zu}: off [%zu] adx_length [%zu] "
     605             :                           "adx_data_off [%zu]\n",
     606             :                           (size_t)i,
     607             :                           e->adx_name,
     608             :                           (size_t)e->adx_namelen,
     609             :                           (size_t)off,
     610             :                           (size_t)e->adx_length,
     611             :                           (size_t)e->adx_offset);
     612             : 
     613           0 :                 if (off + 4 >= AD_XATTR_MAX_HDR_SIZE) {
     614           0 :                         return false;
     615             :                 }
     616           0 :                 RSIVAL(ad->ad_data, off, e->adx_offset);
     617           0 :                 off += 4;
     618             : 
     619           0 :                 if (off + 4 >= AD_XATTR_MAX_HDR_SIZE) {
     620           0 :                         return false;
     621             :                 }
     622           0 :                 RSIVAL(ad->ad_data, off, e->adx_length);
     623           0 :                 off += 4;
     624             : 
     625           0 :                 if (off + 2 >= AD_XATTR_MAX_HDR_SIZE) {
     626           0 :                         return false;
     627             :                 }
     628           0 :                 RSSVAL(ad->ad_data, off, e->adx_flags);
     629           0 :                 off += 2;
     630             : 
     631           0 :                 if (off + 1 >= AD_XATTR_MAX_HDR_SIZE) {
     632           0 :                         return false;
     633             :                 }
     634           0 :                 SCVAL(ad->ad_data, off, e->adx_namelen);
     635           0 :                 off += 1;
     636             : 
     637           0 :                 if (off + e->adx_namelen >= AD_XATTR_MAX_HDR_SIZE) {
     638           0 :                         return false;
     639             :                 }
     640           0 :                 memcpy(ad->ad_data + off, e->adx_name, e->adx_namelen);
     641           0 :                 off += e->adx_namelen;
     642             :         }
     643             : 
     644           0 :         h->adx_data_start = off;
     645           0 :         h->adx_data_length = talloc_get_size(ad->adx_data);
     646           0 :         h->adx_total_size = h->adx_data_start + h->adx_data_length;
     647             : 
     648           0 :         if (talloc_get_size(ad->ad_data) < h->adx_total_size) {
     649           0 :                 ad->ad_data = talloc_realloc(ad,
     650             :                                              ad->ad_data,
     651             :                                              char,
     652             :                                              h->adx_total_size);
     653           0 :                 if (ad->ad_data == NULL) {
     654           0 :                         return false;
     655             :                 }
     656             :         }
     657             : 
     658           0 :         memcpy(ad->ad_data + h->adx_data_start,
     659           0 :                ad->adx_data,
     660           0 :                h->adx_data_length);
     661             : 
     662           0 :         ad_setentrylen(ad,
     663             :                        ADEID_FINDERI,
     664           0 :                        h->adx_total_size - ad_getentryoff(ad, ADEID_FINDERI));
     665             : 
     666           0 :         ad_setentryoff(ad,
     667             :                        ADEID_RFORK,
     668           0 :                        ad_getentryoff(ad, ADEID_FINDERI) +
     669           0 :                        ad_getentrylen(ad, ADEID_FINDERI));
     670             : 
     671           0 :         memcpy(ad->ad_data + ADEDOFF_FILLER, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
     672             : 
     673             :         /*
     674             :          * Rewind, then update the header fields.
     675             :          */
     676             : 
     677           0 :         off = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI;
     678             :         /* 2 bytes padding */
     679           0 :         off += 2;
     680             : 
     681           0 :         RSIVAL(ad->ad_data, off, AD_XATTR_HDR_MAGIC);
     682           0 :         off += 4;
     683           0 :         RSIVAL(ad->ad_data, off, 0);
     684           0 :         off += 4;
     685           0 :         RSIVAL(ad->ad_data, off, h->adx_total_size);
     686           0 :         off += 4;
     687           0 :         RSIVAL(ad->ad_data, off, h->adx_data_start);
     688           0 :         off += 4;
     689           0 :         RSIVAL(ad->ad_data, off, h->adx_data_length);
     690           0 :         off += 4;
     691             : 
     692             :         /* adx_reserved and adx_flags */
     693           0 :         memset(ad->ad_data + off, 0, 3 * 4 + 2);
     694           0 :         off += 3 * 4 + 2;
     695             : 
     696           0 :         RSSVAL(ad->ad_data, off, h->adx_num_attrs);
     697           0 :         off += 2;
     698             : 
     699           0 :         ok = ad_pack_move_reso(handle, ad, fsp);
     700           0 :         if (!ok) {
     701           0 :                 DBG_ERR("Moving resourcefork of [%s] failed\n",
     702             :                         fsp_str_dbg(fsp));
     703           0 :                 return false;
     704             :         }
     705             : 
     706           0 :         return true;
     707             : }
     708             : 
     709             : /**
     710             :  * Pack AppleDouble structure into data buffer
     711             :  **/
     712           0 : static bool ad_pack(struct vfs_handle_struct *handle,
     713             :                     struct adouble *ad,
     714             :                     files_struct *fsp)
     715             : {
     716             :         uint32_t       eid;
     717             :         uint16_t       nent;
     718             :         uint32_t       bufsize;
     719           0 :         uint32_t       offset = 0;
     720             :         bool ok;
     721             : 
     722           0 :         bufsize = talloc_get_size(ad->ad_data);
     723           0 :         if (bufsize < AD_DATASZ_DOT_UND) {
     724           0 :                 DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
     725           0 :                 return false;
     726             :         }
     727             : 
     728           0 :         if (offset + ADEDLEN_MAGIC < offset ||
     729           0 :                         offset + ADEDLEN_MAGIC >= bufsize) {
     730           0 :                 return false;
     731             :         }
     732           0 :         RSIVAL(ad->ad_data, offset, ad->ad_magic);
     733           0 :         offset += ADEDLEN_MAGIC;
     734             : 
     735           0 :         if (offset + ADEDLEN_VERSION < offset ||
     736           0 :                         offset + ADEDLEN_VERSION >= bufsize) {
     737           0 :                 return false;
     738             :         }
     739           0 :         RSIVAL(ad->ad_data, offset, ad->ad_version);
     740           0 :         offset += ADEDLEN_VERSION;
     741             : 
     742           0 :         if (offset + ADEDLEN_FILLER < offset ||
     743           0 :                         offset + ADEDLEN_FILLER >= bufsize) {
     744           0 :                 return false;
     745             :         }
     746           0 :         if (ad->ad_type == ADOUBLE_RSRC) {
     747           0 :                 memcpy(ad->ad_data + offset, AD_FILLER_TAG, ADEDLEN_FILLER);
     748             :         }
     749           0 :         offset += ADEDLEN_FILLER;
     750             : 
     751           0 :         if (offset + ADEDLEN_NENTRIES < offset ||
     752           0 :                         offset + ADEDLEN_NENTRIES >= bufsize) {
     753           0 :                 return false;
     754             :         }
     755           0 :         offset += ADEDLEN_NENTRIES;
     756             : 
     757           0 :         ok = ad_pack_xattrs(handle, ad, fsp);
     758           0 :         if (!ok) {
     759           0 :                 return false;
     760             :         }
     761             : 
     762           0 :         for (eid = 0, nent = 0; eid < ADEID_MAX; eid++) {
     763           0 :                 if (ad->ad_eid[eid].ade_off == 0) {
     764             :                         /*
     765             :                          * ade_off is also used as indicator whether a
     766             :                          * specific entry is used or not
     767             :                          */
     768           0 :                         continue;
     769             :                 }
     770             : 
     771           0 :                 if (offset + AD_ENTRY_LEN_EID < offset ||
     772           0 :                                 offset + AD_ENTRY_LEN_EID >= bufsize) {
     773           0 :                         return false;
     774             :                 }
     775           0 :                 RSIVAL(ad->ad_data, offset, AD_EID_DISK(eid));
     776           0 :                 offset += AD_ENTRY_LEN_EID;
     777             : 
     778           0 :                 if (offset + AD_ENTRY_LEN_OFF < offset ||
     779           0 :                                 offset + AD_ENTRY_LEN_OFF >= bufsize) {
     780           0 :                         return false;
     781             :                 }
     782           0 :                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_off);
     783           0 :                 offset += AD_ENTRY_LEN_OFF;
     784             : 
     785           0 :                 if (offset + AD_ENTRY_LEN_LEN < offset ||
     786           0 :                                 offset + AD_ENTRY_LEN_LEN >= bufsize) {
     787           0 :                         return false;
     788             :                 }
     789           0 :                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_len);
     790           0 :                 offset += AD_ENTRY_LEN_LEN;
     791             : 
     792           0 :                 nent++;
     793             :         }
     794             : 
     795           0 :         if (ADEDOFF_NENTRIES + 2 >= bufsize) {
     796           0 :                 return false;
     797             :         }
     798           0 :         RSSVAL(ad->ad_data, ADEDOFF_NENTRIES, nent);
     799             : 
     800           0 :         return true;
     801             : }
     802             : 
     803           0 : static bool ad_unpack_xattrs(struct adouble *ad)
     804             : {
     805           0 :         struct ad_xattr_header *h = &ad->adx_header;
     806           0 :         size_t bufsize = talloc_get_size(ad->ad_data);
     807           0 :         const char *p = ad->ad_data;
     808             :         uint32_t hoff;
     809             :         uint32_t i;
     810             : 
     811           0 :         if (ad->ad_type != ADOUBLE_RSRC) {
     812           0 :                 return false;
     813             :         }
     814             : 
     815           0 :         if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) {
     816           0 :                 return true;
     817             :         }
     818             : 
     819             :         /*
     820             :          * Ensure the buffer ad->ad_data was allocated by ad_alloc() for an
     821             :          * ADOUBLE_RSRC type (._ AppleDouble file on-disk).
     822             :          */
     823           0 :         if (bufsize != AD_XATTR_MAX_HDR_SIZE) {
     824           0 :                 return false;
     825             :         }
     826             : 
     827             :         /* 2 bytes padding */
     828           0 :         hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2;
     829             : 
     830           0 :         h->adx_magic       = RIVAL(p, hoff + 0);
     831           0 :         h->adx_debug_tag   = RIVAL(p, hoff + 4); /* Not used -> not checked */
     832           0 :         h->adx_total_size  = RIVAL(p, hoff + 8);
     833           0 :         h->adx_data_start  = RIVAL(p, hoff + 12);
     834           0 :         h->adx_data_length = RIVAL(p, hoff + 16);
     835           0 :         h->adx_flags       = RSVAL(p, hoff + 32); /* Not used -> not checked */
     836           0 :         h->adx_num_attrs   = RSVAL(p, hoff + 34);
     837             : 
     838           0 :         if (h->adx_magic != AD_XATTR_HDR_MAGIC) {
     839           0 :                 DBG_ERR("Bad magic: 0x%" PRIx32 "\n", h->adx_magic);
     840           0 :                 return false;
     841             :         }
     842             : 
     843           0 :         if (h->adx_total_size > ad_getentryoff(ad, ADEID_RFORK)) {
     844           0 :                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
     845           0 :                 return false;
     846             :         }
     847           0 :         if (h->adx_total_size > AD_XATTR_MAX_HDR_SIZE) {
     848           0 :                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
     849           0 :                 return false;
     850             :         }
     851             : 
     852           0 :         if (h->adx_data_start < (hoff + AD_XATTR_HDR_SIZE)) {
     853           0 :                 DBG_ERR("Bad start: 0x%" PRIx32 "\n", h->adx_data_start);
     854           0 :                 return false;
     855             :         }
     856             : 
     857           0 :         if ((h->adx_data_start + h->adx_data_length) < h->adx_data_start) {
     858           0 :                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
     859           0 :                 return false;
     860             :         }
     861           0 :         if ((h->adx_data_start + h->adx_data_length) >
     862           0 :             ad->adx_header.adx_total_size)
     863             :         {
     864           0 :                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
     865           0 :                 return false;
     866             :         }
     867             : 
     868           0 :         if (h->adx_num_attrs > AD_XATTR_MAX_ENTRIES) {
     869           0 :                 DBG_ERR("Bad num xattrs: %" PRIu16 "\n", h->adx_num_attrs);
     870           0 :                 return false;
     871             :         }
     872             : 
     873           0 :         if (h->adx_num_attrs == 0) {
     874           0 :                 return true;
     875             :         }
     876             : 
     877           0 :         ad->adx_entries = talloc_zero_array(
     878             :                 ad, struct ad_xattr_entry, h->adx_num_attrs);
     879           0 :         if (ad->adx_entries == NULL) {
     880           0 :                 return false;
     881             :         }
     882             : 
     883           0 :         hoff += AD_XATTR_HDR_SIZE;
     884             : 
     885           0 :         for (i = 0; i < h->adx_num_attrs; i++) {
     886           0 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
     887             : 
     888           0 :                 hoff = (hoff + 3) & ~3;
     889             : 
     890           0 :                 e->adx_offset  = RIVAL(p, hoff + 0);
     891           0 :                 e->adx_length  = RIVAL(p, hoff + 4);
     892           0 :                 e->adx_flags   = RSVAL(p, hoff + 8);
     893           0 :                 e->adx_namelen = *(p + hoff + 10);
     894             : 
     895           0 :                 if (e->adx_offset >= ad->adx_header.adx_total_size) {
     896           0 :                         DBG_ERR("Bad adx_offset: %" PRIx32 "\n",
     897             :                                 e->adx_offset);
     898           0 :                         return false;
     899             :                 }
     900             : 
     901           0 :                 if ((e->adx_offset + e->adx_length) < e->adx_offset) {
     902           0 :                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
     903             :                                 e->adx_length);
     904           0 :                         return false;
     905             :                 }
     906             : 
     907           0 :                 if ((e->adx_offset + e->adx_length) >
     908           0 :                     ad->adx_header.adx_total_size)
     909             :                 {
     910           0 :                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
     911             :                                 e->adx_length);
     912           0 :                         return false;
     913             :                 }
     914             : 
     915           0 :                 if (e->adx_namelen == 0) {
     916           0 :                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
     917             :                                 e->adx_namelen);
     918           0 :                         return false;
     919             :                 }
     920           0 :                 if ((hoff + 11 + e->adx_namelen) < hoff + 11) {
     921           0 :                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
     922             :                                 e->adx_namelen);
     923           0 :                         return false;
     924             :                 }
     925           0 :                 if ((hoff + 11 + e->adx_namelen) >
     926           0 :                     ad->adx_header.adx_data_start)
     927             :                 {
     928           0 :                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
     929             :                                 e->adx_namelen);
     930           0 :                         return false;
     931             :                 }
     932             : 
     933           0 :                 e->adx_name = talloc_strndup(ad->adx_entries,
     934           0 :                                              p + hoff + 11,
     935           0 :                                              e->adx_namelen);
     936           0 :                 if (e->adx_name == NULL) {
     937           0 :                         return false;
     938             :                 }
     939             : 
     940           0 :                 DBG_DEBUG("xattr [%s] offset [0x%x] size [0x%x]\n",
     941             :                           e->adx_name, e->adx_offset, e->adx_length);
     942           0 :                 dump_data(10, (uint8_t *)(ad->ad_data + e->adx_offset),
     943           0 :                           e->adx_length);
     944             : 
     945           0 :                 hoff += 11 + e->adx_namelen;
     946             :         }
     947             : 
     948           0 :         return true;
     949             : }
     950             : 
     951             : /**
     952             :  * Unpack an AppleDouble blob into a struct adoble
     953             :  **/
     954           0 : static bool ad_unpack(struct adouble *ad, const size_t nentries,
     955             :                       size_t filesize)
     956             : {
     957           0 :         size_t bufsize = talloc_get_size(ad->ad_data);
     958             :         size_t adentries, i;
     959             :         uint32_t eid, len, off;
     960             :         bool ok;
     961             : 
     962             :         /*
     963             :          * The size of the buffer ad->ad_data is checked when read, so
     964             :          * we wouldn't have to check our own offsets, a few extra
     965             :          * checks won't hurt though. We have to check the offsets we
     966             :          * read from the buffer anyway.
     967             :          */
     968             : 
     969           0 :         if (bufsize < (AD_HEADER_LEN + (AD_ENTRY_LEN * nentries))) {
     970           0 :                 DEBUG(1, ("bad size\n"));
     971           0 :                 return false;
     972             :         }
     973             : 
     974           0 :         ad->ad_magic = RIVAL(ad->ad_data, 0);
     975           0 :         ad->ad_version = RIVAL(ad->ad_data, ADEDOFF_VERSION);
     976           0 :         if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION)) {
     977           0 :                 DEBUG(1, ("wrong magic or version\n"));
     978           0 :                 return false;
     979             :         }
     980             : 
     981           0 :         memcpy(ad->ad_filler, ad->ad_data + ADEDOFF_FILLER, ADEDLEN_FILLER);
     982             : 
     983           0 :         adentries = RSVAL(ad->ad_data, ADEDOFF_NENTRIES);
     984           0 :         if (adentries != nentries) {
     985           0 :                 DEBUG(1, ("invalid number of entries: %zu\n",
     986             :                           adentries));
     987           0 :                 return false;
     988             :         }
     989             : 
     990             :         /* now, read in the entry bits */
     991           0 :         for (i = 0; i < adentries; i++) {
     992           0 :                 eid = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN));
     993           0 :                 eid = get_eid(eid);
     994           0 :                 off = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 4);
     995           0 :                 len = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 8);
     996             : 
     997           0 :                 if (!eid || eid >= ADEID_MAX) {
     998           0 :                         DEBUG(1, ("bogus eid %d\n", eid));
     999           0 :                         return false;
    1000             :                 }
    1001             : 
    1002             :                 /*
    1003             :                  * All entries other than the resource fork are
    1004             :                  * expected to be read into the ad_data buffer, so
    1005             :                  * ensure the specified offset is within that bound
    1006             :                  */
    1007           0 :                 if ((off > bufsize) && (eid != ADEID_RFORK)) {
    1008           0 :                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
    1009             :                                   eid, off, len));
    1010           0 :                         return false;
    1011             :                 }
    1012             : 
    1013           0 :                 ok = ad_entry_check_size(eid, bufsize, off, len);
    1014           0 :                 if (!ok) {
    1015           0 :                         DBG_ERR("bogus eid [%"PRIu32"] bufsize [%zu] "
    1016             :                                 "off [%"PRIu32"] len [%"PRIu32"]\n",
    1017             :                                 eid, bufsize, off, len);
    1018           0 :                         return false;
    1019             :                 }
    1020             : 
    1021             :                 /*
    1022             :                  * That would be obviously broken
    1023             :                  */
    1024           0 :                 if (off > filesize) {
    1025           0 :                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
    1026             :                                   eid, off, len));
    1027           0 :                         return false;
    1028             :                 }
    1029             : 
    1030             :                 /*
    1031             :                  * Check for any entry that has its end beyond the
    1032             :                  * filesize.
    1033             :                  */
    1034           0 :                 if (off + len < off) {
    1035           0 :                         DEBUG(1, ("offset wrap in eid %d: off: %" PRIu32
    1036             :                                   ", len: %" PRIu32 "\n",
    1037             :                                   eid, off, len));
    1038           0 :                         return false;
    1039             : 
    1040             :                 }
    1041           0 :                 if (off + len > filesize) {
    1042             :                         /*
    1043             :                          * If this is the resource fork entry, we fix
    1044             :                          * up the length, for any other entry we bail
    1045             :                          * out.
    1046             :                          */
    1047           0 :                         if (eid != ADEID_RFORK) {
    1048           0 :                                 DEBUG(1, ("bogus eid %d: off: %" PRIu32
    1049             :                                           ", len: %" PRIu32 "\n",
    1050             :                                           eid, off, len));
    1051           0 :                                 return false;
    1052             :                         }
    1053             : 
    1054             :                         /*
    1055             :                          * Fixup the resource fork entry by limiting
    1056             :                          * the size to entryoffset - filesize.
    1057             :                          */
    1058           0 :                         len = filesize - off;
    1059           0 :                         DEBUG(1, ("Limiting ADEID_RFORK: off: %" PRIu32
    1060             :                                   ", len: %" PRIu32 "\n", off, len));
    1061             :                 }
    1062             : 
    1063           0 :                 ad->ad_eid[eid].ade_off = off;
    1064           0 :                 ad->ad_eid[eid].ade_len = len;
    1065             :         }
    1066             : 
    1067           0 :         if (ad->ad_type == ADOUBLE_RSRC) {
    1068           0 :                 ok = ad_unpack_xattrs(ad);
    1069           0 :                 if (!ok) {
    1070           0 :                         return false;
    1071             :                 }
    1072             :         }
    1073             : 
    1074           0 :         return true;
    1075             : }
    1076             : 
    1077           0 : static bool ad_convert_move_reso(vfs_handle_struct *handle,
    1078             :                                  struct adouble *ad,
    1079             :                                  const struct smb_filename *smb_fname)
    1080             : {
    1081           0 :         char *buf = NULL;
    1082             :         size_t rforklen;
    1083             :         size_t rforkoff;
    1084             :         ssize_t n;
    1085             :         int ret;
    1086             : 
    1087           0 :         rforklen = ad_getentrylen(ad, ADEID_RFORK);
    1088           0 :         if (rforklen == 0) {
    1089           0 :                 return true;
    1090             :         }
    1091             : 
    1092           0 :         buf = talloc_size(ad, rforklen);
    1093           0 :         if (buf == NULL) {
    1094             :                 /*
    1095             :                  * This allocates a buffer for reading the resource fork data in
    1096             :                  * one big swoop. Resource forks won't be larger then, say, 64
    1097             :                  * MB, I swear, so just doing the allocation with the talloc
    1098             :                  * limit as safeguard seems safe.
    1099             :                  */
    1100           0 :                 DBG_ERR("Failed to allocate %zu bytes for rfork\n",
    1101             :                         rforklen);
    1102           0 :                 return false;
    1103             :         }
    1104             : 
    1105           0 :         rforkoff = ad_getentryoff(ad, ADEID_RFORK);
    1106             : 
    1107           0 :         n = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, rforkoff);
    1108           0 :         if (n != rforklen) {
    1109           0 :                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
    1110             :                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1111           0 :                 return false;
    1112             :         }
    1113             : 
    1114           0 :         rforkoff = ADEDOFF_RFORK_DOT_UND;
    1115             : 
    1116           0 :         n = SMB_VFS_PWRITE(ad->ad_fsp, buf, rforklen, rforkoff);
    1117           0 :         if (n != rforklen) {
    1118           0 :                 DBG_ERR("Writing %zu bytes to rfork [%s] failed: %s\n",
    1119             :                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1120           0 :                 return false;
    1121             :         }
    1122             : 
    1123           0 :         ad_setentryoff(ad, ADEID_RFORK, ADEDOFF_RFORK_DOT_UND);
    1124             : 
    1125           0 :         ret = ad_fset(handle, ad, ad->ad_fsp);
    1126           0 :         if (ret != 0) {
    1127           0 :                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
    1128           0 :                 return false;
    1129             :         }
    1130             : 
    1131           0 :         return true;
    1132             : }
    1133             : 
    1134           0 : static bool ad_convert_xattr(vfs_handle_struct *handle,
    1135             :                              struct adouble *ad,
    1136             :                              const struct smb_filename *smb_fname,
    1137             :                              const char *catia_mappings,
    1138             :                              bool *converted_xattr)
    1139             : {
    1140             :         static struct char_mappings **string_replace_cmaps = NULL;
    1141             :         uint16_t i;
    1142           0 :         int saved_errno = 0;
    1143             :         NTSTATUS status;
    1144             :         int rc;
    1145             :         bool ok;
    1146             : 
    1147           0 :         *converted_xattr = false;
    1148             : 
    1149           0 :         if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
    1150           0 :                 return true;
    1151             :         }
    1152             : 
    1153           0 :         if (string_replace_cmaps == NULL) {
    1154           0 :                 const char **mappings = NULL;
    1155             : 
    1156           0 :                 mappings = str_list_make_v3_const(
    1157             :                         talloc_tos(), catia_mappings, NULL);
    1158           0 :                 if (mappings == NULL) {
    1159           0 :                         return false;
    1160             :                 }
    1161           0 :                 string_replace_cmaps = string_replace_init_map(
    1162           0 :                         handle->conn->sconn, mappings);
    1163           0 :                 TALLOC_FREE(mappings);
    1164             :         }
    1165             : 
    1166           0 :         for (i = 0; i < ad->adx_header.adx_num_attrs; i++) {
    1167           0 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
    1168           0 :                 char *mapped_name = NULL;
    1169           0 :                 char *tmp = NULL;
    1170           0 :                 struct smb_filename *stream_name = NULL;
    1171           0 :                 files_struct *fsp = NULL;
    1172             :                 ssize_t nwritten;
    1173             : 
    1174           0 :                 status = string_replace_allocate(handle->conn,
    1175           0 :                                                  e->adx_name,
    1176             :                                                  string_replace_cmaps,
    1177             :                                                  talloc_tos(),
    1178             :                                                  &mapped_name,
    1179             :                                                  vfs_translate_to_windows);
    1180           0 :                 if (!NT_STATUS_IS_OK(status) &&
    1181           0 :                     !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
    1182             :                 {
    1183           0 :                         DBG_ERR("string_replace_allocate failed\n");
    1184           0 :                         ok = false;
    1185           0 :                         goto fail;
    1186             :                 }
    1187             : 
    1188           0 :                 tmp = mapped_name;
    1189           0 :                 mapped_name = talloc_asprintf(talloc_tos(), ":%s", tmp);
    1190           0 :                 TALLOC_FREE(tmp);
    1191           0 :                 if (mapped_name == NULL) {
    1192           0 :                         ok = false;
    1193           0 :                         goto fail;
    1194             :                 }
    1195             : 
    1196           0 :                 stream_name = synthetic_smb_fname(talloc_tos(),
    1197           0 :                                                   smb_fname->base_name,
    1198             :                                                   mapped_name,
    1199             :                                                   NULL,
    1200           0 :                                                   smb_fname->twrp,
    1201           0 :                                                   smb_fname->flags);
    1202           0 :                 TALLOC_FREE(mapped_name);
    1203           0 :                 if (stream_name == NULL) {
    1204           0 :                         DBG_ERR("synthetic_smb_fname failed\n");
    1205           0 :                         ok = false;
    1206           0 :                         goto fail;
    1207             :                 }
    1208             : 
    1209           0 :                 DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
    1210             : 
    1211           0 :                 status = openat_pathref_fsp(handle->conn->cwd_fsp, stream_name);
    1212           0 :                 if (!NT_STATUS_IS_OK(status) &&
    1213           0 :                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
    1214             :                 {
    1215           0 :                         ok = false;
    1216           0 :                         goto fail;
    1217             :                 }
    1218             : 
    1219           0 :                 status = SMB_VFS_CREATE_FILE(
    1220             :                         handle->conn,                        /* conn */
    1221             :                         NULL,                           /* req */
    1222             :                         NULL,                           /* dirfsp */
    1223             :                         stream_name,                    /* fname */
    1224             :                         FILE_GENERIC_WRITE,             /* access_mask */
    1225             :                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* share_access */
    1226             :                         FILE_OPEN_IF,                   /* create_disposition */
    1227             :                         0,                              /* create_options */
    1228             :                         0,                              /* file_attributes */
    1229             :                         INTERNAL_OPEN_ONLY,             /* oplock_request */
    1230             :                         NULL,                           /* lease */
    1231             :                         0,                              /* allocation_size */
    1232             :                         0,                              /* private_flags */
    1233             :                         NULL,                           /* sd */
    1234             :                         NULL,                           /* ea_list */
    1235             :                         &fsp,                               /* result */
    1236             :                         NULL,                           /* psbuf */
    1237             :                         NULL, NULL);                    /* create context */
    1238           0 :                 TALLOC_FREE(stream_name);
    1239           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1240           0 :                         DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
    1241           0 :                         ok = false;
    1242           0 :                         goto fail;
    1243             :                 }
    1244             : 
    1245           0 :                 nwritten = SMB_VFS_PWRITE(fsp,
    1246             :                                           ad->ad_data + e->adx_offset,
    1247             :                                           e->adx_length,
    1248             :                                           0);
    1249           0 :                 if (nwritten == -1) {
    1250           0 :                         DBG_ERR("SMB_VFS_PWRITE failed\n");
    1251           0 :                         saved_errno = errno;
    1252           0 :                         close_file_free(NULL, &fsp, ERROR_CLOSE);
    1253           0 :                         errno = saved_errno;
    1254           0 :                         ok = false;
    1255           0 :                         goto fail;
    1256             :                 }
    1257             : 
    1258           0 :                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1259           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1260           0 :                         ok = false;
    1261           0 :                         goto fail;
    1262             :                 }
    1263           0 :                 fsp = NULL;
    1264             :         }
    1265             : 
    1266           0 :         ad->adx_header.adx_num_attrs = 0;
    1267           0 :         TALLOC_FREE(ad->adx_entries);
    1268             : 
    1269           0 :         ad_setentrylen(ad, ADEID_FINDERI, ADEDLEN_FINDERI);
    1270             : 
    1271           0 :         rc = ad_fset(handle, ad, ad->ad_fsp);
    1272           0 :         if (rc != 0) {
    1273           0 :                 DBG_ERR("ad_fset on [%s] failed: %s\n",
    1274             :                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1275           0 :                 ok = false;
    1276           0 :                 goto fail;
    1277             :         }
    1278             : 
    1279           0 :         ok = ad_convert_move_reso(handle, ad, smb_fname);
    1280           0 :         if (!ok) {
    1281           0 :                 goto fail;
    1282             :         }
    1283             : 
    1284           0 :         *converted_xattr = true;
    1285           0 :         ok = true;
    1286             : 
    1287           0 : fail:
    1288           0 :         return ok;
    1289             : }
    1290             : 
    1291           0 : static bool ad_convert_finderinfo(vfs_handle_struct *handle,
    1292             :                                   struct adouble *ad,
    1293             :                                   const struct smb_filename *smb_fname)
    1294             : {
    1295           0 :         char *p_ad = NULL;
    1296           0 :         AfpInfo *ai = NULL;
    1297             :         DATA_BLOB aiblob;
    1298           0 :         struct smb_filename *stream_name = NULL;
    1299           0 :         files_struct *fsp = NULL;
    1300             :         size_t size;
    1301             :         ssize_t nwritten;
    1302             :         NTSTATUS status;
    1303           0 :         int saved_errno = 0;
    1304             :         int cmp;
    1305             : 
    1306           0 :         cmp = memcmp(ad->ad_filler, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
    1307           0 :         if (cmp != 0) {
    1308           0 :                 return true;
    1309             :         }
    1310             : 
    1311           0 :         p_ad = ad_get_entry(ad, ADEID_FINDERI);
    1312           0 :         if (p_ad == NULL) {
    1313           0 :                 return false;
    1314             :         }
    1315             : 
    1316           0 :         ai = afpinfo_new(talloc_tos());
    1317           0 :         if (ai == NULL) {
    1318           0 :                 return false;
    1319             :         }
    1320             : 
    1321           0 :         memcpy(ai->afpi_FinderInfo, p_ad, ADEDLEN_FINDERI);
    1322             : 
    1323           0 :         aiblob = data_blob_talloc(talloc_tos(), NULL, AFP_INFO_SIZE);
    1324           0 :         if (aiblob.data == NULL) {
    1325           0 :                 TALLOC_FREE(ai);
    1326           0 :                 return false;
    1327             :         }
    1328             : 
    1329           0 :         size = afpinfo_pack(ai, (char *)aiblob.data);
    1330           0 :         TALLOC_FREE(ai);
    1331           0 :         if (size != AFP_INFO_SIZE) {
    1332           0 :                 return false;
    1333             :         }
    1334             : 
    1335           0 :         stream_name = synthetic_smb_fname(talloc_tos(),
    1336           0 :                                           smb_fname->base_name,
    1337             :                                           AFPINFO_STREAM,
    1338             :                                           NULL,
    1339           0 :                                           smb_fname->twrp,
    1340           0 :                                           smb_fname->flags);
    1341           0 :         if (stream_name == NULL) {
    1342           0 :                 data_blob_free(&aiblob);
    1343           0 :                 DBG_ERR("synthetic_smb_fname failed\n");
    1344           0 :                 return false;
    1345             :         }
    1346             : 
    1347           0 :         DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
    1348             : 
    1349           0 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, stream_name);
    1350           0 :         if (!NT_STATUS_IS_OK(status) &&
    1351           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
    1352             :         {
    1353           0 :                 return false;
    1354             :         }
    1355             : 
    1356           0 :         status = SMB_VFS_CREATE_FILE(
    1357             :                 handle->conn,                        /* conn */
    1358             :                 NULL,                           /* req */
    1359             :                 NULL,                           /* dirfsp */
    1360             :                 stream_name,                    /* fname */
    1361             :                 FILE_GENERIC_WRITE,             /* access_mask */
    1362             :                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
    1363             :                 FILE_OPEN_IF,                   /* create_disposition */
    1364             :                 0,                              /* create_options */
    1365             :                 0,                              /* file_attributes */
    1366             :                 INTERNAL_OPEN_ONLY,             /* oplock_request */
    1367             :                 NULL,                           /* lease */
    1368             :                 0,                              /* allocation_size */
    1369             :                 0,                              /* private_flags */
    1370             :                 NULL,                           /* sd */
    1371             :                 NULL,                           /* ea_list */
    1372             :                 &fsp,                               /* result */
    1373             :                 NULL,                           /* psbuf */
    1374             :                 NULL, NULL);                    /* create context */
    1375           0 :         TALLOC_FREE(stream_name);
    1376           0 :         if (!NT_STATUS_IS_OK(status)) {
    1377           0 :                 DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
    1378           0 :                 return false;
    1379             :         }
    1380             : 
    1381           0 :         nwritten = SMB_VFS_PWRITE(fsp,
    1382             :                                   aiblob.data,
    1383             :                                   aiblob.length,
    1384             :                                   0);
    1385           0 :         if (nwritten == -1) {
    1386           0 :                 DBG_ERR("SMB_VFS_PWRITE failed\n");
    1387           0 :                 saved_errno = errno;
    1388           0 :                 close_file_free(NULL, &fsp, ERROR_CLOSE);
    1389           0 :                 errno = saved_errno;
    1390           0 :                 return false;
    1391             :         }
    1392             : 
    1393           0 :         status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1394           0 :         if (!NT_STATUS_IS_OK(status)) {
    1395           0 :                 return false;
    1396             :         }
    1397           0 :         fsp = NULL;
    1398             : 
    1399           0 :         return true;
    1400             : }
    1401             : 
    1402           0 : static bool ad_convert_truncate(vfs_handle_struct *handle,
    1403             :                                 struct adouble *ad,
    1404             :                                 const struct smb_filename *smb_fname)
    1405             : {
    1406             :         int rc;
    1407             :         off_t newlen;
    1408             : 
    1409           0 :         newlen = ADEDOFF_RFORK_DOT_UND + ad_getentrylen(ad, ADEID_RFORK);
    1410             : 
    1411           0 :         rc = SMB_VFS_FTRUNCATE(ad->ad_fsp, newlen);
    1412           0 :         if (rc != 0) {
    1413           0 :                 return false;
    1414             :         }
    1415             : 
    1416           0 :         return true;
    1417             : }
    1418             : 
    1419           0 : static bool ad_convert_blank_rfork(vfs_handle_struct *handle,
    1420             :                                    struct adouble *ad,
    1421             :                                    uint32_t flags,
    1422             :                                    bool *blank)
    1423           0 : {
    1424           0 :         size_t rforklen = sizeof(empty_resourcefork);
    1425           0 :         char buf[rforklen];
    1426             :         ssize_t nread;
    1427             :         int cmp;
    1428             :         int rc;
    1429             : 
    1430           0 :         *blank = false;
    1431             : 
    1432           0 :         if (!(flags & AD_CONV_WIPE_BLANK)) {
    1433           0 :                 return true;
    1434             :         }
    1435             : 
    1436           0 :         if (ad_getentrylen(ad, ADEID_RFORK) != rforklen) {
    1437           0 :                 return true;
    1438             :         }
    1439             : 
    1440           0 :         nread = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, ADEDOFF_RFORK_DOT_UND);
    1441           0 :         if (nread != rforklen) {
    1442           0 :                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
    1443             :                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1444           0 :                 return false;
    1445             :         }
    1446             : 
    1447           0 :         cmp = memcmp(buf, empty_resourcefork, rforklen);
    1448           0 :         if (cmp != 0) {
    1449           0 :                 return true;
    1450             :         }
    1451             : 
    1452           0 :         ad_setentrylen(ad, ADEID_RFORK, 0);
    1453             : 
    1454           0 :         rc = ad_fset(handle, ad, ad->ad_fsp);
    1455           0 :         if (rc != 0) {
    1456           0 :                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
    1457           0 :                 return false;
    1458             :         }
    1459             : 
    1460           0 :         *blank = true;
    1461           0 :         return true;
    1462             : }
    1463             : 
    1464           0 : static bool ad_convert_delete_adfile(vfs_handle_struct *handle,
    1465             :                                 struct adouble *ad,
    1466             :                                 const struct smb_filename *smb_fname,
    1467             :                                 uint32_t flags)
    1468             : {
    1469           0 :         struct smb_filename *parent_fname = NULL;
    1470           0 :         struct smb_filename *at_fname = NULL;
    1471           0 :         struct smb_filename *ad_name = NULL;
    1472             :         NTSTATUS status;
    1473             :         int rc;
    1474             : 
    1475           0 :         if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
    1476           0 :                 return true;
    1477             :         }
    1478             : 
    1479           0 :         if (!(flags & AD_CONV_DELETE)) {
    1480           0 :                 return true;
    1481             :         }
    1482             : 
    1483           0 :         rc = adouble_path(talloc_tos(), smb_fname, &ad_name);
    1484           0 :         if (rc != 0) {
    1485           0 :                 return false;
    1486             :         }
    1487             : 
    1488           0 :         status = parent_pathref(talloc_tos(),
    1489           0 :                                 handle->conn->cwd_fsp,
    1490             :                                 ad_name,
    1491             :                                 &parent_fname,
    1492             :                                 &at_fname);
    1493           0 :         TALLOC_FREE(ad_name);
    1494           0 :         if (!NT_STATUS_IS_OK(status)) {
    1495           0 :                 return false;
    1496             :         }
    1497             : 
    1498           0 :         rc = SMB_VFS_NEXT_UNLINKAT(handle,
    1499             :                         parent_fname->fsp,
    1500             :                         at_fname,
    1501             :                         0);
    1502           0 :         if (rc != 0) {
    1503           0 :                 DBG_ERR("Unlinking [%s/%s] failed: %s\n",
    1504             :                         smb_fname_str_dbg(parent_fname),
    1505             :                         smb_fname_str_dbg(at_fname), strerror(errno));
    1506           0 :                 TALLOC_FREE(parent_fname);
    1507           0 :                 return false;
    1508             :         }
    1509             : 
    1510           0 :         DBG_WARNING("Unlinked [%s/%s] after conversion\n",
    1511             :                     smb_fname_str_dbg(parent_fname),
    1512             :                     smb_fname_str_dbg(at_fname));
    1513           0 :         TALLOC_FREE(parent_fname);
    1514             : 
    1515           0 :         return true;
    1516             : }
    1517             : 
    1518             : /**
    1519             :  * Convert from Apple's ._ file to Netatalk
    1520             :  *
    1521             :  * Apple's AppleDouble may contain a FinderInfo entry longer then 32
    1522             :  * bytes containing packed xattrs.
    1523             :  *
    1524             :  * @return -1 in case an error occurred, 0 if no conversion was done, 1
    1525             :  * otherwise
    1526             :  **/
    1527           0 : int ad_convert(struct vfs_handle_struct *handle,
    1528             :                 const struct smb_filename *smb_fname,
    1529             :                 const char *catia_mappings,
    1530             :                 uint32_t flags)
    1531             : {
    1532           0 :         struct adouble *ad = NULL;
    1533             :         bool ok;
    1534           0 :         bool converted_xattr = false;
    1535             :         bool blank;
    1536             :         int ret;
    1537             : 
    1538           0 :         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
    1539           0 :         if (ad == NULL) {
    1540           0 :                 return 0;
    1541             :         }
    1542             : 
    1543           0 :         ok = ad_convert_xattr(handle,
    1544             :                               ad,
    1545             :                               smb_fname,
    1546             :                               catia_mappings,
    1547             :                               &converted_xattr);
    1548           0 :         if (!ok) {
    1549           0 :                 ret = -1;
    1550           0 :                 goto done;
    1551             :         }
    1552             : 
    1553           0 :         ok = ad_convert_blank_rfork(handle, ad, flags, &blank);
    1554           0 :         if (!ok) {
    1555           0 :                 ret = -1;
    1556           0 :                 goto done;
    1557             :         }
    1558             : 
    1559           0 :         if (converted_xattr || blank) {
    1560           0 :                 ok = ad_convert_truncate(handle, ad, smb_fname);
    1561           0 :                 if (!ok) {
    1562           0 :                         ret = -1;
    1563           0 :                         goto done;
    1564             :                 }
    1565             :         }
    1566             : 
    1567           0 :         ok = ad_convert_finderinfo(handle, ad, smb_fname);
    1568           0 :         if (!ok) {
    1569           0 :                 DBG_ERR("Failed to convert [%s]\n",
    1570             :                         smb_fname_str_dbg(smb_fname));
    1571           0 :                 ret = -1;
    1572           0 :                 goto done;
    1573             :         }
    1574             : 
    1575           0 :         ok = ad_convert_delete_adfile(handle,
    1576             :                         ad,
    1577             :                         smb_fname,
    1578             :                         flags);
    1579           0 :         if (!ok) {
    1580           0 :                 ret = -1;
    1581           0 :                 goto done;
    1582             :         }
    1583             : 
    1584           0 :         ret = 0;
    1585           0 : done:
    1586           0 :         TALLOC_FREE(ad);
    1587           0 :         return ret;
    1588             : }
    1589             : 
    1590           0 : static bool ad_unconvert_open_ad(TALLOC_CTX *mem_ctx,
    1591             :                                  struct vfs_handle_struct *handle,
    1592             :                                  struct smb_filename *smb_fname,
    1593             :                                  struct smb_filename *adpath,
    1594             :                                  files_struct **_fsp)
    1595             : {
    1596           0 :         files_struct *fsp = NULL;
    1597             :         NTSTATUS status;
    1598             :         int ret;
    1599             : 
    1600           0 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, adpath);
    1601           0 :         if (!NT_STATUS_IS_OK(status) &&
    1602           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
    1603           0 :                 return false;
    1604             :         }
    1605             : 
    1606           0 :         status = SMB_VFS_CREATE_FILE(
    1607             :                 handle->conn,
    1608             :                 NULL,                           /* req */
    1609             :                 NULL,                           /* dirfsp */
    1610             :                 adpath,
    1611             :                 FILE_READ_DATA|FILE_WRITE_DATA,
    1612             :                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
    1613             :                 FILE_OPEN_IF,
    1614             :                 0,                              /* create_options */
    1615             :                 0,                              /* file_attributes */
    1616             :                 INTERNAL_OPEN_ONLY,
    1617             :                 NULL,                           /* lease */
    1618             :                 0,                              /* allocation_size */
    1619             :                 0,                              /* private_flags */
    1620             :                 NULL,                           /* sd */
    1621             :                 NULL,                           /* ea_list */
    1622             :                 &fsp,
    1623             :                 NULL,                           /* info */
    1624             :                 NULL, NULL);                    /* create context */
    1625           0 :         if (!NT_STATUS_IS_OK(status)) {
    1626           0 :                 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed: %s\n",
    1627             :                         smb_fname_str_dbg(adpath), nt_errstr(status));
    1628           0 :                 return false;
    1629             :         }
    1630             : 
    1631           0 :         if (fsp->fsp_name->st.st_ex_uid != smb_fname->st.st_ex_uid ||
    1632           0 :             fsp->fsp_name->st.st_ex_gid != smb_fname->st.st_ex_gid)
    1633             :         {
    1634           0 :                 ret = SMB_VFS_FCHOWN(fsp,
    1635             :                                      smb_fname->st.st_ex_uid,
    1636             :                                      smb_fname->st.st_ex_gid);
    1637           0 :                 if (ret != 0) {
    1638           0 :                         DBG_ERR("SMB_VFS_FCHOWN [%s] failed: %s\n",
    1639             :                                 fsp_str_dbg(fsp), nt_errstr(status));
    1640           0 :                         close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1641           0 :                         return false;
    1642             :                 }
    1643             :         }
    1644             : 
    1645           0 :         *_fsp = fsp;
    1646           0 :         return true;
    1647             : }
    1648             : 
    1649           0 : static bool ad_unconvert_get_streams(struct vfs_handle_struct *handle,
    1650             :                                      struct smb_filename *smb_fname,
    1651             :                                      TALLOC_CTX *mem_ctx,
    1652             :                                      unsigned int *num_streams,
    1653             :                                      struct stream_struct **streams)
    1654             : {
    1655           0 :         files_struct *fsp = NULL;
    1656             :         NTSTATUS status;
    1657             : 
    1658           0 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, smb_fname);
    1659           0 :         if (!NT_STATUS_IS_OK(status)) {
    1660           0 :                 return false;
    1661             :         }
    1662             : 
    1663           0 :         status = SMB_VFS_CREATE_FILE(
    1664             :                 handle->conn,                                /* conn */
    1665             :                 NULL,                                   /* req */
    1666             :                 NULL,                                   /* dirfsp */
    1667             :                 smb_fname,                              /* fname */
    1668             :                 FILE_READ_ATTRIBUTES,                   /* access_mask */
    1669             :                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
    1670             :                         FILE_SHARE_DELETE),
    1671             :                 FILE_OPEN,                              /* create_disposition*/
    1672             :                 0,                                      /* create_options */
    1673             :                 0,                                      /* file_attributes */
    1674             :                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
    1675             :                 NULL,                                   /* lease */
    1676             :                 0,                                      /* allocation_size */
    1677             :                 0,                                      /* private_flags */
    1678             :                 NULL,                                   /* sd */
    1679             :                 NULL,                                   /* ea_list */
    1680             :                 &fsp,                                       /* result */
    1681             :                 NULL,                                   /* pinfo */
    1682             :                 NULL, NULL);                            /* create context */
    1683           0 :         if (!NT_STATUS_IS_OK(status)) {
    1684           0 :                 DBG_ERR("Opening [%s] failed: %s\n",
    1685             :                         smb_fname_str_dbg(smb_fname),
    1686             :                         nt_errstr(status));
    1687           0 :                 return false;
    1688             :         }
    1689             : 
    1690           0 :         status = vfs_fstreaminfo(fsp,
    1691             :                                 mem_ctx,
    1692             :                                 num_streams,
    1693             :                                 streams);
    1694           0 :         if (!NT_STATUS_IS_OK(status)) {
    1695           0 :                 close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1696           0 :                 DBG_ERR("streaminfo on [%s] failed: %s\n",
    1697             :                         smb_fname_str_dbg(smb_fname),
    1698             :                         nt_errstr(status));
    1699           0 :                 return false;
    1700             :         }
    1701             : 
    1702           0 :         status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1703           0 :         if (!NT_STATUS_IS_OK(status)) {
    1704           0 :                 DBG_ERR("close_file [%s] failed: %s\n",
    1705             :                         smb_fname_str_dbg(smb_fname),
    1706             :                         nt_errstr(status));
    1707           0 :                 return false;
    1708             :         }
    1709             : 
    1710           0 :         return true;
    1711             : }
    1712             : 
    1713             : struct ad_collect_state {
    1714             :         bool have_adfile;
    1715             :         size_t adx_data_off;
    1716             :         char *rsrc_data_buf;
    1717             : };
    1718             : 
    1719           0 : static bool ad_collect_one_stream(struct vfs_handle_struct *handle,
    1720             :                                   struct char_mappings **cmaps,
    1721             :                                   struct smb_filename *smb_fname,
    1722             :                                   const struct stream_struct *stream,
    1723             :                                   struct adouble *ad,
    1724             :                                   struct ad_collect_state *state)
    1725             : {
    1726           0 :         struct smb_filename *sname = NULL;
    1727           0 :         files_struct *fsp = NULL;
    1728           0 :         struct ad_xattr_entry *e = NULL;
    1729           0 :         char *mapped_name = NULL;
    1730           0 :         char *p = NULL;
    1731             :         size_t needed_size;
    1732             :         ssize_t nread;
    1733             :         NTSTATUS status;
    1734             :         bool ok;
    1735             : 
    1736           0 :         sname = synthetic_smb_fname(ad,
    1737           0 :                                     smb_fname->base_name,
    1738           0 :                                     stream->name,
    1739             :                                     NULL,
    1740             :                                     smb_fname->twrp,
    1741             :                                     0);
    1742           0 :         if (sname == NULL) {
    1743           0 :                 return false;
    1744             :         }
    1745             : 
    1746           0 :         if (is_ntfs_default_stream_smb_fname(sname)) {
    1747           0 :                 TALLOC_FREE(sname);
    1748           0 :                 return true;
    1749             :         }
    1750             : 
    1751           0 :         DBG_DEBUG("Collecting stream [%s]\n", smb_fname_str_dbg(sname));
    1752             : 
    1753           0 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, sname);
    1754           0 :         if (!NT_STATUS_IS_OK(status)) {
    1755           0 :                 ok = false;
    1756           0 :                 goto out;
    1757             :         }
    1758             : 
    1759           0 :         status = SMB_VFS_CREATE_FILE(
    1760             :                 handle->conn,
    1761             :                 NULL,                           /* req */
    1762             :                 NULL,                           /* dirfsp */
    1763             :                 sname,
    1764             :                 FILE_READ_DATA|DELETE_ACCESS,
    1765             :                 FILE_SHARE_READ,
    1766             :                 FILE_OPEN,
    1767             :                 0,                              /* create_options */
    1768             :                 0,                              /* file_attributes */
    1769             :                 INTERNAL_OPEN_ONLY,             /* oplock_request */
    1770             :                 NULL,                           /* lease */
    1771             :                 0,                              /* allocation_size */
    1772             :                 0,                              /* private_flags */
    1773             :                 NULL,                           /* sd */
    1774             :                 NULL,                           /* ea_list */
    1775             :                 &fsp,
    1776             :                 NULL,                           /* info */
    1777             :                 NULL, NULL);                    /* create context */
    1778           0 :         if (!NT_STATUS_IS_OK(status)) {
    1779           0 :                 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed\n",
    1780             :                         smb_fname_str_dbg(sname));
    1781           0 :                 ok = false;
    1782           0 :                 goto out;
    1783             :         }
    1784             : 
    1785           0 :         if (is_afpinfo_stream(stream->name)) {
    1786             :                 char buf[AFP_INFO_SIZE];
    1787             : 
    1788           0 :                 if (stream->size != AFP_INFO_SIZE) {
    1789           0 :                         DBG_ERR("Bad size [%zd] on [%s]\n",
    1790             :                                 (ssize_t)stream->size,
    1791             :                                 smb_fname_str_dbg(sname));
    1792           0 :                         ok = false;
    1793           0 :                         goto out;
    1794             :                 }
    1795             : 
    1796           0 :                 nread = SMB_VFS_PREAD(fsp, buf, stream->size, 0);
    1797           0 :                 if (nread != AFP_INFO_SIZE) {
    1798           0 :                         DBG_ERR("Bad size [%zd] on [%s]\n",
    1799             :                                 (ssize_t)stream->size,
    1800             :                                 smb_fname_str_dbg(sname));
    1801           0 :                         ok = false;
    1802           0 :                         goto out;
    1803             :                 }
    1804             : 
    1805           0 :                 memcpy(ad->ad_data + ADEDOFF_FINDERI_DOT_UND,
    1806             :                        buf + AFP_OFF_FinderInfo,
    1807             :                        AFP_FinderSize);
    1808             : 
    1809           0 :                 ok = set_delete_on_close(fsp,
    1810             :                                          true,
    1811           0 :                                          fsp->conn->session_info->security_token,
    1812           0 :                                          fsp->conn->session_info->unix_token);
    1813           0 :                 if (!ok) {
    1814           0 :                         DBG_ERR("Deleting [%s] failed\n",
    1815             :                                 smb_fname_str_dbg(sname));
    1816           0 :                         ok = false;
    1817           0 :                         goto out;
    1818             :                 }
    1819           0 :                 ok = true;
    1820           0 :                 goto out;
    1821             :         }
    1822             : 
    1823           0 :         if (is_afpresource_stream(stream->name)) {
    1824           0 :                 ad->ad_rsrc_data = talloc_size(ad, stream->size);
    1825           0 :                 if (ad->ad_rsrc_data == NULL) {
    1826           0 :                         ok = false;
    1827           0 :                         goto out;
    1828             :                 }
    1829             : 
    1830           0 :                 nread = SMB_VFS_PREAD(fsp,
    1831             :                                       ad->ad_rsrc_data,
    1832             :                                       stream->size,
    1833             :                                       0);
    1834           0 :                 if (nread != stream->size) {
    1835           0 :                         DBG_ERR("Bad size [%zd] on [%s]\n",
    1836             :                                 (ssize_t)stream->size,
    1837             :                                 smb_fname_str_dbg(sname));
    1838           0 :                         ok = false;
    1839           0 :                         goto out;
    1840             :                 }
    1841             : 
    1842           0 :                 ad_setentrylen(ad, ADEID_RFORK, stream->size);
    1843             : 
    1844           0 :                 if (!state->have_adfile) {
    1845             :                         /*
    1846             :                          * We have a resource *stream* but no AppleDouble
    1847             :                          * sidecar file, this means the share is configured with
    1848             :                          * fruit:resource=stream. So we should delete the
    1849             :                          * resource stream.
    1850             :                          */
    1851           0 :                         ok = set_delete_on_close(
    1852             :                                 fsp,
    1853             :                                 true,
    1854           0 :                                 fsp->conn->session_info->security_token,
    1855           0 :                                 fsp->conn->session_info->unix_token);
    1856           0 :                         if (!ok) {
    1857           0 :                                 DBG_ERR("Deleting [%s] failed\n",
    1858             :                                         smb_fname_str_dbg(sname));
    1859           0 :                                 ok = false;
    1860           0 :                                 goto out;
    1861             :                         }
    1862             :                 }
    1863           0 :                 ok = true;
    1864           0 :                 goto out;
    1865             :         }
    1866             : 
    1867           0 :         ad->adx_entries = talloc_realloc(ad,
    1868             :                                          ad->adx_entries,
    1869             :                                          struct ad_xattr_entry,
    1870             :                                          ad->adx_header.adx_num_attrs + 1);
    1871           0 :         if (ad->adx_entries == NULL) {
    1872           0 :                 ok = false;
    1873           0 :                 goto out;
    1874             :         }
    1875             : 
    1876           0 :         e = &ad->adx_entries[ad->adx_header.adx_num_attrs];
    1877           0 :         *e = (struct ad_xattr_entry) {
    1878           0 :                 .adx_length = stream->size,
    1879             :         };
    1880           0 :         e->adx_name = talloc_strdup(ad, stream->name + 1);
    1881           0 :         if (e->adx_name == NULL) {
    1882           0 :                 ok = false;
    1883           0 :                 goto out;
    1884             :         }
    1885           0 :         p = strchr(e->adx_name, ':');
    1886           0 :         if (p != NULL) {
    1887           0 :                 *p = '\0';
    1888             :         }
    1889             : 
    1890           0 :         status = string_replace_allocate(handle->conn,
    1891           0 :                                          e->adx_name,
    1892             :                                          cmaps,
    1893             :                                          ad,
    1894             :                                          &mapped_name,
    1895             :                                          vfs_translate_to_unix);
    1896           0 :         if (!NT_STATUS_IS_OK(status) &&
    1897           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
    1898             :         {
    1899           0 :                 DBG_ERR("string_replace_allocate failed\n");
    1900           0 :                 ok = false;
    1901           0 :                 goto out;
    1902             :         }
    1903             : 
    1904           0 :         e->adx_name = mapped_name;
    1905           0 :         e->adx_namelen = strlen(e->adx_name) + 1,
    1906             : 
    1907           0 :         DBG_DEBUG("%u: name (%s) size (%zu)\n",
    1908             :                   ad->adx_header.adx_num_attrs,
    1909             :                   e->adx_name,
    1910             :                   (size_t)e->adx_length);
    1911             : 
    1912           0 :         ad->adx_header.adx_num_attrs++;
    1913             : 
    1914           0 :         needed_size = state->adx_data_off + stream->size;
    1915           0 :         if (needed_size > talloc_get_size(ad->adx_data)) {
    1916           0 :                 ad->adx_data = talloc_realloc(ad,
    1917             :                                               ad->adx_data,
    1918             :                                               char,
    1919             :                                               needed_size);
    1920           0 :                 if (ad->adx_data == NULL) {
    1921           0 :                         ok = false;
    1922           0 :                         goto out;
    1923             :                 }
    1924             :         }
    1925             : 
    1926           0 :         nread = SMB_VFS_PREAD(fsp,
    1927             :                               ad->adx_data + state->adx_data_off,
    1928             :                               stream->size,
    1929             :                               0);
    1930           0 :         if (nread != stream->size) {
    1931           0 :                 DBG_ERR("Bad size [%zd] on [%s]\n",
    1932             :                         (ssize_t)stream->size,
    1933             :                         smb_fname_str_dbg(sname));
    1934           0 :                 ok = false;
    1935           0 :                 goto out;
    1936             :         }
    1937           0 :         state->adx_data_off += nread;
    1938             : 
    1939           0 :         ok = set_delete_on_close(fsp,
    1940             :                                  true,
    1941           0 :                                  fsp->conn->session_info->security_token,
    1942           0 :                                  fsp->conn->session_info->unix_token);
    1943           0 :         if (!ok) {
    1944           0 :                 DBG_ERR("Deleting [%s] failed\n",
    1945             :                         smb_fname_str_dbg(sname));
    1946           0 :                 ok = false;
    1947           0 :                 goto out;
    1948             :         }
    1949             : 
    1950           0 : out:
    1951           0 :         TALLOC_FREE(sname);
    1952           0 :         if (fsp != NULL) {
    1953           0 :                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1954           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1955           0 :                         DBG_ERR("close_file [%s] failed: %s\n",
    1956             :                                 smb_fname_str_dbg(smb_fname),
    1957             :                                 nt_errstr(status));
    1958           0 :                         ok = false;
    1959             :                 }
    1960             :         }
    1961             : 
    1962           0 :         return ok;
    1963             : }
    1964             : 
    1965             : /**
    1966             :  * Convert filesystem metadata to AppleDouble file
    1967             :  **/
    1968           0 : bool ad_unconvert(TALLOC_CTX *mem_ctx,
    1969             :                   struct vfs_handle_struct *handle,
    1970             :                   const char *catia_mappings,
    1971             :                   struct smb_filename *smb_fname,
    1972             :                   bool *converted)
    1973             : {
    1974             :         static struct char_mappings **cmaps = NULL;
    1975           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1976             :         struct ad_collect_state state;
    1977           0 :         struct stream_struct *streams = NULL;
    1978           0 :         struct smb_filename *adpath = NULL;
    1979           0 :         struct adouble *ad = NULL;
    1980           0 :         unsigned int num_streams = 0;
    1981           0 :         size_t to_convert = 0;
    1982           0 :         bool have_rsrc = false;
    1983           0 :         files_struct *fsp = NULL;
    1984             :         size_t i;
    1985             :         NTSTATUS status;
    1986             :         int ret;
    1987             :         bool ok;
    1988             : 
    1989           0 :         *converted = false;
    1990             : 
    1991           0 :         if (cmaps == NULL) {
    1992           0 :                 const char **mappings = NULL;
    1993             : 
    1994           0 :                 mappings = str_list_make_v3_const(
    1995             :                         frame, catia_mappings, NULL);
    1996           0 :                 if (mappings == NULL) {
    1997           0 :                         ok = false;
    1998           0 :                         goto out;
    1999             :                 }
    2000           0 :                 cmaps = string_replace_init_map(mem_ctx, mappings);
    2001           0 :                 TALLOC_FREE(mappings);
    2002             :         }
    2003             : 
    2004           0 :         ok = ad_unconvert_get_streams(handle,
    2005             :                                       smb_fname,
    2006             :                                       frame,
    2007             :                                       &num_streams,
    2008             :                                       &streams);
    2009           0 :         if (!ok) {
    2010           0 :                 goto out;
    2011             :         }
    2012             : 
    2013           0 :         for (i = 0; i < num_streams; i++) {
    2014           0 :                 if (strcasecmp_m(streams[i].name, "::$DATA") == 0) {
    2015           0 :                         continue;
    2016             :                 }
    2017           0 :                 to_convert++;
    2018           0 :                 if (is_afpresource_stream(streams[i].name)) {
    2019           0 :                         have_rsrc = true;
    2020             :                 }
    2021             :         }
    2022             : 
    2023           0 :         if (to_convert == 0) {
    2024           0 :                 ok = true;
    2025           0 :                 goto out;
    2026             :         }
    2027             : 
    2028           0 :         state = (struct ad_collect_state) {
    2029             :                 .adx_data_off = 0,
    2030             :         };
    2031             : 
    2032           0 :         ret = adouble_path(frame, smb_fname, &adpath);
    2033           0 :         if (ret != 0) {
    2034           0 :                 ok = false;
    2035           0 :                 goto out;
    2036             :         }
    2037             : 
    2038           0 :         ret = SMB_VFS_STAT(handle->conn, adpath);
    2039           0 :         if (ret == 0) {
    2040           0 :                 state.have_adfile = true;
    2041             :         } else {
    2042           0 :                 if (errno != ENOENT) {
    2043           0 :                         ok = false;
    2044           0 :                         goto out;
    2045             :                 }
    2046           0 :                 state.have_adfile = false;
    2047             :         }
    2048             : 
    2049           0 :         if (to_convert == 1 && have_rsrc && state.have_adfile) {
    2050             :                 /*
    2051             :                  * So we have just a single stream, the resource fork stream
    2052             :                  * from an AppleDouble file. Fine, that means there's nothing to
    2053             :                  * convert.
    2054             :                  */
    2055           0 :                 ok = true;
    2056           0 :                 goto out;
    2057             :         }
    2058             : 
    2059           0 :         ad = ad_init(frame, ADOUBLE_RSRC);
    2060           0 :         if (ad == NULL) {
    2061           0 :                 ok = false;
    2062           0 :                 goto out;
    2063             :         }
    2064             : 
    2065           0 :         for (i = 0; i < num_streams; i++) {
    2066           0 :                 ok = ad_collect_one_stream(handle,
    2067             :                                            cmaps,
    2068             :                                            smb_fname,
    2069           0 :                                            &streams[i],
    2070             :                                            ad,
    2071             :                                            &state);
    2072           0 :                 if (!ok) {
    2073           0 :                         goto out;
    2074             :                 }
    2075             :         }
    2076             : 
    2077           0 :         ok = ad_unconvert_open_ad(frame, handle, smb_fname, adpath, &fsp);
    2078           0 :         if (!ok) {
    2079           0 :                 DBG_ERR("Failed to open adfile [%s]\n",
    2080             :                         smb_fname_str_dbg(smb_fname));
    2081           0 :                 goto out;
    2082             :         }
    2083             : 
    2084           0 :         ret = ad_fset(handle, ad, fsp);
    2085           0 :         if (ret != 0) {
    2086           0 :                 ok = false;
    2087           0 :                 goto out;
    2088             :         }
    2089             : 
    2090           0 :         *converted = true;
    2091           0 :         ok = true;
    2092             : 
    2093           0 : out:
    2094           0 :         if (fsp != NULL) {
    2095           0 :                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    2096           0 :                 if (!NT_STATUS_IS_OK(status)) {
    2097           0 :                         DBG_ERR("close_file_free() [%s] failed: %s\n",
    2098             :                                 smb_fname_str_dbg(smb_fname),
    2099             :                                 nt_errstr(status));
    2100           0 :                         ok = false;
    2101             :                 }
    2102             :         }
    2103           0 :         TALLOC_FREE(frame);
    2104           0 :         return ok;
    2105             : }
    2106             : 
    2107             : /**
    2108             :  * Read and parse Netatalk AppleDouble metadata xattr
    2109             :  **/
    2110           0 : static ssize_t ad_read_meta(vfs_handle_struct *handle,
    2111             :                             struct adouble *ad,
    2112             :                             const struct smb_filename *smb_fname)
    2113             : {
    2114           0 :         int      rc = 0;
    2115             :         ssize_t  ealen;
    2116             :         bool     ok;
    2117           0 :         struct files_struct *fsp = smb_fname->fsp;
    2118             : 
    2119           0 :         DEBUG(10, ("reading meta xattr for %s\n", smb_fname->base_name));
    2120             : 
    2121           0 :         fsp = metadata_fsp(fsp);
    2122             : 
    2123           0 :         ealen = SMB_VFS_FGETXATTR(fsp,
    2124             :                                   AFPINFO_EA_NETATALK,
    2125             :                                   ad->ad_data,
    2126             :                                   AD_DATASZ_XATTR);
    2127             : 
    2128           0 :         if (ealen == -1) {
    2129           0 :                 switch (errno) {
    2130           0 :                 case ENOATTR:
    2131             :                 case ENOENT:
    2132           0 :                         if (errno == ENOATTR) {
    2133           0 :                                 errno = ENOENT;
    2134             :                         }
    2135           0 :                         rc = -1;
    2136           0 :                         goto exit;
    2137           0 :                 default:
    2138           0 :                         DEBUG(2, ("error reading meta xattr: %s\n",
    2139             :                                   strerror(errno)));
    2140           0 :                         rc = -1;
    2141           0 :                         goto exit;
    2142             :                 }
    2143             :         }
    2144           0 :         if (ealen != AD_DATASZ_XATTR) {
    2145           0 :                 DEBUG(2, ("bad size %zd\n", ealen));
    2146           0 :                 errno = EINVAL;
    2147           0 :                 rc = -1;
    2148           0 :                 goto exit;
    2149             :         }
    2150             : 
    2151             :         /* Now parse entries */
    2152           0 :         ok = ad_unpack(ad, ADEID_NUM_XATTR, AD_DATASZ_XATTR);
    2153           0 :         if (!ok) {
    2154           0 :                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
    2155           0 :                 errno = EINVAL;
    2156           0 :                 rc = -1;
    2157           0 :                 goto exit;
    2158             :         }
    2159             : 
    2160           0 :         if (!ad_getentryoff(ad, ADEID_FINDERI)
    2161           0 :             || !ad_getentryoff(ad, ADEID_COMMENT)
    2162           0 :             || !ad_getentryoff(ad, ADEID_FILEDATESI)
    2163           0 :             || !ad_getentryoff(ad, ADEID_AFPFILEI)
    2164           0 :             || !ad_getentryoff(ad, ADEID_PRIVDEV)
    2165           0 :             || !ad_getentryoff(ad, ADEID_PRIVINO)
    2166           0 :             || !ad_getentryoff(ad, ADEID_PRIVSYN)
    2167           0 :             || !ad_getentryoff(ad, ADEID_PRIVID)) {
    2168           0 :                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
    2169           0 :                 errno = EINVAL;
    2170           0 :                 rc = -1;
    2171           0 :                 goto exit;
    2172             :         }
    2173             : 
    2174           0 : exit:
    2175           0 :         DEBUG(10, ("reading meta xattr for %s, rc: %d\n",
    2176             :                 smb_fname->base_name, rc));
    2177             : 
    2178           0 :         if (rc != 0) {
    2179           0 :                 ealen = -1;
    2180           0 :                 if (errno == EINVAL) {
    2181           0 :                         become_root();
    2182           0 :                         (void)SMB_VFS_FREMOVEXATTR(fsp,
    2183             :                                                    AFPINFO_EA_NETATALK);
    2184           0 :                         unbecome_root();
    2185           0 :                         errno = ENOENT;
    2186             :                 }
    2187             :         }
    2188           0 :         return ealen;
    2189             : }
    2190             : 
    2191           0 : static NTSTATUS adouble_open_rsrc_fsp(const struct files_struct *dirfsp,
    2192             :                                       const struct smb_filename *smb_base_fname,
    2193             :                                       int in_flags,
    2194             :                                       mode_t mode,
    2195             :                                       struct files_struct **_ad_fsp)
    2196             : {
    2197           0 :         int rc = 0;
    2198           0 :         struct adouble *ad = NULL;
    2199           0 :         struct smb_filename *adp_smb_fname = NULL;
    2200           0 :         struct files_struct *ad_fsp = NULL;
    2201             :         NTSTATUS status;
    2202           0 :         struct vfs_open_how how = { .flags = in_flags, .mode = mode, };
    2203             : 
    2204           0 :         rc = adouble_path(talloc_tos(),
    2205             :                           smb_base_fname,
    2206             :                           &adp_smb_fname);
    2207           0 :         if (rc != 0) {
    2208           0 :                 return NT_STATUS_NO_MEMORY;
    2209             :         }
    2210             : 
    2211           0 :         status = create_internal_fsp(dirfsp->conn,
    2212             :                                      adp_smb_fname,
    2213             :                                      &ad_fsp);
    2214           0 :         if (!NT_STATUS_IS_OK(status)) {
    2215           0 :                 return status;
    2216             :         }
    2217             : 
    2218             : #ifdef O_PATH
    2219           0 :         how.flags &= ~(O_PATH);
    2220             : #endif
    2221           0 :         if (how.flags & (O_CREAT | O_TRUNC | O_WRONLY)) {
    2222             :                 /* We always need read/write access for the metadata header too */
    2223           0 :                 how.flags &= ~(O_WRONLY);
    2224           0 :                 how.flags |= O_RDWR;
    2225             :         }
    2226             : 
    2227           0 :         status = fd_openat(dirfsp,
    2228             :                            adp_smb_fname,
    2229             :                            ad_fsp,
    2230             :                            &how);
    2231           0 :         if (!NT_STATUS_IS_OK(status)) {
    2232           0 :                 file_free(NULL, ad_fsp);
    2233           0 :                 return status;
    2234             :         }
    2235             : 
    2236           0 :         if (how.flags & (O_CREAT | O_TRUNC)) {
    2237           0 :                 ad = ad_init(talloc_tos(), ADOUBLE_RSRC);
    2238           0 :                 if (ad == NULL) {
    2239           0 :                         file_free(NULL, ad_fsp);
    2240           0 :                         return NT_STATUS_NO_MEMORY;
    2241             :                 }
    2242             : 
    2243           0 :                 rc = ad_fset(ad_fsp->conn->vfs_handles, ad, ad_fsp);
    2244           0 :                 if (rc != 0) {
    2245           0 :                         file_free(NULL, ad_fsp);
    2246           0 :                         return NT_STATUS_IO_DEVICE_ERROR;
    2247             :                 }
    2248           0 :                 TALLOC_FREE(ad);
    2249             :         }
    2250             : 
    2251           0 :         *_ad_fsp = ad_fsp;
    2252           0 :         return NT_STATUS_OK;
    2253             : }
    2254             : 
    2255           0 : NTSTATUS adouble_open_from_base_fsp(const struct files_struct *dirfsp,
    2256             :                                     struct files_struct *base_fsp,
    2257             :                                     adouble_type_t type,
    2258             :                                     int flags,
    2259             :                                     mode_t mode,
    2260             :                                     struct files_struct **_ad_fsp)
    2261             : {
    2262           0 :         *_ad_fsp = NULL;
    2263             : 
    2264           0 :         SMB_ASSERT(base_fsp != NULL);
    2265           0 :         SMB_ASSERT(!fsp_is_alternate_stream(base_fsp));
    2266             : 
    2267           0 :         switch (type) {
    2268           0 :         case ADOUBLE_META:
    2269           0 :                 return NT_STATUS_INTERNAL_ERROR;
    2270           0 :         case ADOUBLE_RSRC:
    2271           0 :                 return adouble_open_rsrc_fsp(dirfsp,
    2272           0 :                                              base_fsp->fsp_name,
    2273             :                                              flags,
    2274             :                                              mode,
    2275             :                                              _ad_fsp);
    2276             :         }
    2277             : 
    2278           0 :         return NT_STATUS_INTERNAL_ERROR;
    2279             : }
    2280             : 
    2281             : /*
    2282             :  * Here's the deal: for ADOUBLE_META we can do without an fd as we can issue
    2283             :  * path based xattr calls. For ADOUBLE_RSRC however we need a full-fledged fd
    2284             :  * for file IO on the ._ file.
    2285             :  */
    2286           0 : static int ad_open(vfs_handle_struct *handle,
    2287             :                    struct adouble *ad,
    2288             :                    files_struct *fsp,
    2289             :                    const struct smb_filename *smb_fname,
    2290             :                    int flags,
    2291             :                    mode_t mode)
    2292             : {
    2293             :         NTSTATUS status;
    2294             : 
    2295           0 :         DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name,
    2296             :                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
    2297             : 
    2298           0 :         if (ad->ad_type == ADOUBLE_META) {
    2299           0 :                 return 0;
    2300             :         }
    2301             : 
    2302           0 :         if (fsp != NULL) {
    2303           0 :                 ad->ad_fsp = fsp;
    2304           0 :                 ad->ad_opened = false;
    2305           0 :                 return 0;
    2306             :         }
    2307             : 
    2308           0 :         status = adouble_open_rsrc_fsp(handle->conn->cwd_fsp,
    2309             :                                        smb_fname,
    2310             :                                        flags,
    2311             :                                        mode,
    2312           0 :                                        &ad->ad_fsp);
    2313           0 :         if (!NT_STATUS_IS_OK(status)) {
    2314           0 :                 errno = map_errno_from_nt_status(status);
    2315           0 :                 return -1;
    2316             :         }
    2317           0 :         ad->ad_opened = true;
    2318             : 
    2319           0 :         DBG_DEBUG("Path [%s] type [%s]\n",
    2320             :                   smb_fname->base_name,
    2321             :                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
    2322             : 
    2323           0 :         return 0;
    2324             : }
    2325             : 
    2326           0 : static ssize_t ad_read_rsrc_adouble(vfs_handle_struct *handle,
    2327             :                                     struct adouble *ad,
    2328             :                                     const struct smb_filename *smb_fname)
    2329             : {
    2330             :         size_t to_read;
    2331             :         ssize_t len;
    2332             :         int ret;
    2333             :         bool ok;
    2334             : 
    2335           0 :         ret = SMB_VFS_NEXT_FSTAT(handle, ad->ad_fsp, &ad->ad_fsp->fsp_name->st);
    2336           0 :         if (ret != 0) {
    2337           0 :                 DBG_ERR("fstat [%s] failed: %s\n",
    2338             :                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
    2339           0 :                 return -1;
    2340             :         }
    2341             : 
    2342           0 :         to_read = ad->ad_fsp->fsp_name->st.st_ex_size;
    2343           0 :         if (to_read > AD_XATTR_MAX_HDR_SIZE) {
    2344           0 :                 to_read = AD_XATTR_MAX_HDR_SIZE;
    2345             :         }
    2346             : 
    2347           0 :         len = SMB_VFS_NEXT_PREAD(handle,
    2348             :                                  ad->ad_fsp,
    2349             :                                  ad->ad_data,
    2350             :                                  to_read,
    2351             :                                  0);
    2352           0 :         if (len != to_read)  {
    2353           0 :                 DBG_NOTICE("%s %s: bad size: %zd\n",
    2354             :                            smb_fname->base_name, strerror(errno), len);
    2355           0 :                 return -1;
    2356             :         }
    2357             : 
    2358             :         /* Now parse entries */
    2359           0 :         ok = ad_unpack(ad,
    2360             :                        ADEID_NUM_DOT_UND,
    2361           0 :                        ad->ad_fsp->fsp_name->st.st_ex_size);
    2362           0 :         if (!ok) {
    2363           0 :                 DBG_ERR("invalid AppleDouble resource %s\n",
    2364             :                         smb_fname->base_name);
    2365           0 :                 errno = EINVAL;
    2366           0 :                 return -1;
    2367             :         }
    2368             : 
    2369           0 :         if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
    2370           0 :             || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
    2371           0 :             || (ad_getentryoff(ad, ADEID_RFORK) < ADEDOFF_RFORK_DOT_UND))
    2372             :         {
    2373           0 :                 DBG_ERR("invalid AppleDouble resource %s\n",
    2374             :                         smb_fname->base_name);
    2375           0 :                 errno = EINVAL;
    2376           0 :                 return -1;
    2377             :         }
    2378             : 
    2379           0 :         return len;
    2380             : }
    2381             : 
    2382             : /**
    2383             :  * Read and parse resource fork, either ._ AppleDouble file or xattr
    2384             :  **/
    2385           0 : static ssize_t ad_read_rsrc(vfs_handle_struct *handle,
    2386             :                             struct adouble *ad,
    2387             :                             const struct smb_filename *smb_fname)
    2388             : {
    2389           0 :         return ad_read_rsrc_adouble(handle, ad, smb_fname);
    2390             : }
    2391             : 
    2392             : /**
    2393             :  * Read and unpack an AppleDouble metadata xattr or resource
    2394             :  **/
    2395           0 : static ssize_t ad_read(vfs_handle_struct *handle,
    2396             :                        struct adouble *ad,
    2397             :                        const struct smb_filename *smb_fname)
    2398             : {
    2399           0 :         switch (ad->ad_type) {
    2400           0 :         case ADOUBLE_META:
    2401           0 :                 return ad_read_meta(handle, ad, smb_fname);
    2402           0 :         case ADOUBLE_RSRC:
    2403           0 :                 return ad_read_rsrc(handle, ad, smb_fname);
    2404           0 :         default:
    2405           0 :                 return -1;
    2406             :         }
    2407             : }
    2408             : 
    2409           0 : static int adouble_destructor(struct adouble *ad)
    2410             : {
    2411             :         NTSTATUS status;
    2412             : 
    2413           0 :         if (!ad->ad_opened) {
    2414           0 :                 return 0;
    2415             :         }
    2416             : 
    2417           0 :         SMB_ASSERT(ad->ad_fsp != NULL);
    2418             : 
    2419           0 :         status = fd_close(ad->ad_fsp);
    2420           0 :         if (!NT_STATUS_IS_OK(status)) {
    2421           0 :                 DBG_ERR("Closing [%s] failed: %s\n",
    2422             :                         fsp_str_dbg(ad->ad_fsp), nt_errstr(status));
    2423             :         }
    2424           0 :         file_free(NULL, ad->ad_fsp);
    2425           0 :         ad->ad_fsp = NULL;
    2426           0 :         ad->ad_opened = false;
    2427             : 
    2428           0 :         return 0;
    2429             : }
    2430             : 
    2431             : /**
    2432             :  * Allocate a struct adouble without initialiing it
    2433             :  *
    2434             :  * The struct is either hang of the fsp extension context or if fsp is
    2435             :  * NULL from ctx.
    2436             :  *
    2437             :  * @param[in] ctx        talloc context
    2438             :  * @param[in] handle     vfs handle
    2439             :  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2440             :  *
    2441             :  * @return               adouble handle
    2442             :  **/
    2443           0 : static struct adouble *ad_alloc(TALLOC_CTX *ctx,
    2444             :                                 adouble_type_t type)
    2445             : {
    2446           0 :         int rc = 0;
    2447           0 :         size_t adsize = 0;
    2448             :         struct adouble *ad;
    2449             : 
    2450           0 :         switch (type) {
    2451           0 :         case ADOUBLE_META:
    2452           0 :                 adsize = AD_DATASZ_XATTR;
    2453           0 :                 break;
    2454           0 :         case ADOUBLE_RSRC:
    2455             :                 /*
    2456             :                  * AppleDouble ._ file case, optimize for fewer (but larger)
    2457             :                  * IOs. Two cases:
    2458             :                  *
    2459             :                  * - without xattrs size of the header is exactly
    2460             :                  *   AD_DATASZ_DOT_UND (82) bytes
    2461             :                  *
    2462             :                  * - with embedded xattrs it can be larger, up to
    2463             :                  *   AD_XATTR_MAX_HDR_SIZE
    2464             :                  *
    2465             :                  * Larger headers are not supported, but this is a reasonable
    2466             :                  * limit that is also employed by the macOS client.
    2467             :                  *
    2468             :                  * We used the largest possible size to be able to read the full
    2469             :                  * header with one IO.
    2470             :                  */
    2471           0 :                 adsize = AD_XATTR_MAX_HDR_SIZE;
    2472           0 :                 break;
    2473           0 :         default:
    2474           0 :                 return NULL;
    2475             :         }
    2476             : 
    2477           0 :         ad = talloc_zero(ctx, struct adouble);
    2478           0 :         if (ad == NULL) {
    2479           0 :                 rc = -1;
    2480           0 :                 goto exit;
    2481             :         }
    2482             : 
    2483           0 :         if (adsize) {
    2484           0 :                 ad->ad_data = talloc_zero_array(ad, char, adsize);
    2485           0 :                 if (ad->ad_data == NULL) {
    2486           0 :                         rc = -1;
    2487           0 :                         goto exit;
    2488             :                 }
    2489             :         }
    2490             : 
    2491           0 :         ad->ad_type = type;
    2492           0 :         ad->ad_magic = AD_MAGIC;
    2493           0 :         ad->ad_version = AD_VERSION;
    2494             : 
    2495           0 :         talloc_set_destructor(ad, adouble_destructor);
    2496             : 
    2497           0 : exit:
    2498           0 :         if (rc != 0) {
    2499           0 :                 TALLOC_FREE(ad);
    2500             :         }
    2501           0 :         return ad;
    2502             : }
    2503             : 
    2504             : /**
    2505             :  * Allocate and initialize a new struct adouble
    2506             :  *
    2507             :  * @param[in] ctx        talloc context
    2508             :  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2509             :  *
    2510             :  * @return               adouble handle, initialized
    2511             :  **/
    2512           0 : struct adouble *ad_init(TALLOC_CTX *ctx, adouble_type_t type)
    2513             : {
    2514           0 :         int rc = 0;
    2515             :         const struct ad_entry_order  *eid;
    2516           0 :         struct adouble *ad = NULL;
    2517           0 :         time_t t = time(NULL);
    2518             : 
    2519           0 :         switch (type) {
    2520           0 :         case ADOUBLE_META:
    2521           0 :                 eid = entry_order_meta_xattr;
    2522           0 :                 break;
    2523           0 :         case ADOUBLE_RSRC:
    2524           0 :                 eid = entry_order_dot_und;
    2525           0 :                 break;
    2526           0 :         default:
    2527           0 :                 return NULL;
    2528             :         }
    2529             : 
    2530           0 :         ad = ad_alloc(ctx, type);
    2531           0 :         if (ad == NULL) {
    2532           0 :                 return NULL;
    2533             :         }
    2534             : 
    2535           0 :         while (eid->id) {
    2536           0 :                 ad->ad_eid[eid->id].ade_off = eid->offset;
    2537           0 :                 ad->ad_eid[eid->id].ade_len = eid->len;
    2538           0 :                 eid++;
    2539             :         }
    2540             : 
    2541             :         /* put something sane in the date fields */
    2542           0 :         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, t);
    2543           0 :         ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, t);
    2544           0 :         ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, t);
    2545           0 :         ad_setdate(ad, AD_DATE_BACKUP, htonl(AD_DATE_START));
    2546             : 
    2547           0 :         if (rc != 0) {
    2548           0 :                 TALLOC_FREE(ad);
    2549             :         }
    2550           0 :         return ad;
    2551             : }
    2552             : 
    2553           0 : static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
    2554             :                                        vfs_handle_struct *handle,
    2555             :                                        files_struct *fsp,
    2556             :                                        const struct smb_filename *smb_fname,
    2557             :                                        adouble_type_t type)
    2558             : {
    2559           0 :         int rc = 0;
    2560             :         ssize_t len;
    2561           0 :         struct adouble *ad = NULL;
    2562             :         int mode;
    2563             : 
    2564           0 :         if (fsp != NULL) {
    2565           0 :                 if (fsp_is_alternate_stream(fsp)) {
    2566           0 :                         smb_fname = fsp->base_fsp->fsp_name;
    2567             :                 } else {
    2568           0 :                         smb_fname = fsp->fsp_name;
    2569             :                 }
    2570             :         }
    2571             : 
    2572           0 :         DEBUG(10, ("ad_get(%s) called for %s\n",
    2573             :                    type == ADOUBLE_META ? "meta" : "rsrc",
    2574             :                    smb_fname != NULL ? smb_fname->base_name : "???"));
    2575             : 
    2576           0 :         ad = ad_alloc(ctx, type);
    2577           0 :         if (ad == NULL) {
    2578           0 :                 rc = -1;
    2579           0 :                 goto exit;
    2580             :         }
    2581             : 
    2582             :         /* Try rw first so we can use the fd in ad_convert() */
    2583           0 :         mode = O_RDWR;
    2584             : 
    2585           0 :         rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
    2586           0 :         if (rc == -1 && ((errno == EROFS) || (errno == EACCES))) {
    2587           0 :                 mode = O_RDONLY;
    2588           0 :                 rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
    2589             :         }
    2590           0 :         if (rc == -1) {
    2591           0 :                 DBG_DEBUG("ad_open [%s] error [%s]\n",
    2592             :                           smb_fname->base_name, strerror(errno));
    2593           0 :                 goto exit;
    2594             : 
    2595             :         }
    2596             : 
    2597           0 :         len = ad_read(handle, ad, smb_fname);
    2598           0 :         if (len == -1) {
    2599           0 :                 DEBUG(10, ("error reading AppleDouble for %s\n",
    2600             :                         smb_fname->base_name));
    2601           0 :                 rc = -1;
    2602           0 :                 goto exit;
    2603             :         }
    2604             : 
    2605           0 : exit:
    2606           0 :         DEBUG(10, ("ad_get(%s) for %s returning %d\n",
    2607             :                   type == ADOUBLE_META ? "meta" : "rsrc",
    2608             :                   smb_fname->base_name, rc));
    2609             : 
    2610           0 :         if (rc != 0) {
    2611           0 :                 TALLOC_FREE(ad);
    2612             :         }
    2613           0 :         return ad;
    2614             : }
    2615             : 
    2616             : /**
    2617             :  * Return AppleDouble data for a file
    2618             :  *
    2619             :  * @param[in] ctx      talloc context
    2620             :  * @param[in] handle   vfs handle
    2621             :  * @param[in] smb_fname pathname to file or directory
    2622             :  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2623             :  *
    2624             :  * @return             talloced struct adouble or NULL on error
    2625             :  **/
    2626           0 : struct adouble *ad_get(TALLOC_CTX *ctx,
    2627             :                               vfs_handle_struct *handle,
    2628             :                               const struct smb_filename *smb_fname,
    2629             :                               adouble_type_t type)
    2630             : {
    2631           0 :         return ad_get_internal(ctx, handle, NULL, smb_fname, type);
    2632             : }
    2633             : 
    2634             : /**
    2635             :  * Return AppleDouble data for a file
    2636             :  *
    2637             :  * @param[in] ctx      talloc context
    2638             :  * @param[in] handle   vfs handle
    2639             :  * @param[in] fsp      fsp to use for IO
    2640             :  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2641             :  *
    2642             :  * @return             talloced struct adouble or NULL on error
    2643             :  **/
    2644           0 : struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
    2645             :                         files_struct *fsp, adouble_type_t type)
    2646             : {
    2647           0 :         return ad_get_internal(ctx, handle, fsp, NULL, type);
    2648             : }
    2649             : 
    2650             : /**
    2651             :  * Set AppleDouble metadata on a file or directory
    2652             :  *
    2653             :  * @param[in] ad      adouble handle
    2654             :  * @param[in] fsp     file handle
    2655             :  *
    2656             :  * @return            status code, 0 means success
    2657             :  **/
    2658           0 : int ad_fset(struct vfs_handle_struct *handle,
    2659             :             struct adouble *ad,
    2660             :             files_struct *fsp)
    2661             : {
    2662           0 :         int rc = -1;
    2663             :         ssize_t len;
    2664             :         bool ok;
    2665             : 
    2666           0 :         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
    2667             : 
    2668           0 :         ok = ad_pack(handle, ad, fsp);
    2669           0 :         if (!ok) {
    2670           0 :                 return -1;
    2671             :         }
    2672             : 
    2673           0 :         switch (ad->ad_type) {
    2674           0 :         case ADOUBLE_META:
    2675           0 :                 rc = SMB_VFS_NEXT_FSETXATTR(handle,
    2676             :                                    fsp->base_fsp ? fsp->base_fsp : fsp,
    2677             :                                    AFPINFO_EA_NETATALK,
    2678             :                                    ad->ad_data,
    2679             :                                    AD_DATASZ_XATTR, 0);
    2680           0 :                 break;
    2681           0 :         case ADOUBLE_RSRC:
    2682           0 :                 len = SMB_VFS_NEXT_PWRITE(handle,
    2683             :                                           fsp,
    2684             :                                           ad->ad_data,
    2685             :                                           ad_getentryoff(ad, ADEID_RFORK),
    2686             :                                           0);
    2687           0 :                 if (len != ad_getentryoff(ad, ADEID_RFORK)) {
    2688           0 :                         DBG_ERR("short write on %s: %zd", fsp_str_dbg(fsp), len);
    2689           0 :                         return -1;
    2690             :                 }
    2691           0 :                 rc = 0;
    2692           0 :                 break;
    2693             : 
    2694           0 :         default:
    2695           0 :                 return -1;
    2696             :         }
    2697             : 
    2698           0 :         DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
    2699             : 
    2700           0 :         return rc;
    2701             : }
    2702             : 
    2703           0 : bool is_adouble_file(const char *path)
    2704             : {
    2705           0 :         const char *p = NULL;
    2706             :         int match;
    2707             : 
    2708           0 :         p = strrchr(path, '/');
    2709           0 :         if (p == NULL) {
    2710           0 :                 p = path;
    2711             :         } else {
    2712           0 :                 p++;
    2713             :         }
    2714             : 
    2715           0 :         match = strncmp(p,
    2716             :                         ADOUBLE_NAME_PREFIX,
    2717             :                         strlen(ADOUBLE_NAME_PREFIX));
    2718           0 :         if (match != 0) {
    2719           0 :                 return false;
    2720             :         }
    2721           0 :         return true;
    2722             : }
    2723             : 
    2724             : /**
    2725             :  * Prepend "._" to a basename
    2726             :  * Return a new struct smb_filename with stream_name == NULL.
    2727             :  **/
    2728           0 : int adouble_path(TALLOC_CTX *ctx,
    2729             :                  const struct smb_filename *smb_fname_in,
    2730             :                  struct smb_filename **pp_smb_fname_out)
    2731             : {
    2732             :         char *parent;
    2733             :         const char *base;
    2734           0 :         struct smb_filename *smb_fname = NULL;
    2735             : 
    2736           0 :         smb_fname = cp_smb_filename_nostream(ctx, smb_fname_in);
    2737           0 :         if (smb_fname == NULL) {
    2738           0 :                 return -1;
    2739             :         }
    2740             : 
    2741             :         /* We're replacing base_name. */
    2742           0 :         TALLOC_FREE(smb_fname->base_name);
    2743             : 
    2744           0 :         SET_STAT_INVALID(smb_fname->st);
    2745             : 
    2746           0 :         if (!parent_dirname(smb_fname, smb_fname_in->base_name,
    2747             :                                 &parent, &base)) {
    2748           0 :                 TALLOC_FREE(smb_fname);
    2749           0 :                 return -1;
    2750             :         }
    2751             : 
    2752           0 :         if (ISDOT(parent)) {
    2753           0 :                 smb_fname->base_name = talloc_asprintf(smb_fname,
    2754             :                                         "._%s", base);
    2755             :         } else {
    2756           0 :                 smb_fname->base_name = talloc_asprintf(smb_fname,
    2757             :                                         "%s/._%s", parent, base);
    2758             :         }
    2759           0 :         if (smb_fname->base_name == NULL) {
    2760           0 :                 TALLOC_FREE(smb_fname);
    2761           0 :                 return -1;
    2762             :         }
    2763             : 
    2764           0 :         *pp_smb_fname_out = smb_fname;
    2765             : 
    2766           0 :         return 0;
    2767             : }
    2768             : 
    2769             : /**
    2770             :  * Allocate and initialize an AfpInfo struct
    2771             :  **/
    2772           0 : AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
    2773             : {
    2774           0 :         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
    2775           0 :         if (ai == NULL) {
    2776           0 :                 return NULL;
    2777             :         }
    2778           0 :         ai->afpi_Signature = AFP_Signature;
    2779           0 :         ai->afpi_Version = AFP_Version;
    2780           0 :         ai->afpi_BackupTime = AD_DATE_START;
    2781           0 :         return ai;
    2782             : }
    2783             : 
    2784             : /**
    2785             :  * Pack an AfpInfo struct into a buffer
    2786             :  *
    2787             :  * Buffer size must be at least AFP_INFO_SIZE
    2788             :  * Returns size of packed buffer
    2789             :  **/
    2790           0 : ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
    2791             : {
    2792           0 :         memset(buf, 0, AFP_INFO_SIZE);
    2793             : 
    2794           0 :         RSIVAL(buf, 0, ai->afpi_Signature);
    2795           0 :         RSIVAL(buf, 4, ai->afpi_Version);
    2796           0 :         RSIVAL(buf, 12, ai->afpi_BackupTime);
    2797           0 :         memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
    2798             : 
    2799           0 :         return AFP_INFO_SIZE;
    2800             : }
    2801             : 
    2802             : /**
    2803             :  * Unpack a buffer into a AfpInfo structure
    2804             :  *
    2805             :  * Buffer size must be at least AFP_INFO_SIZE
    2806             :  * Returns allocated AfpInfo struct
    2807             :  **/
    2808           0 : AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data)
    2809             : {
    2810           0 :         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
    2811           0 :         if (ai == NULL) {
    2812           0 :                 return NULL;
    2813             :         }
    2814             : 
    2815           0 :         ai->afpi_Signature = RIVAL(data, 0);
    2816           0 :         ai->afpi_Version = RIVAL(data, 4);
    2817           0 :         ai->afpi_BackupTime = RIVAL(data, 12);
    2818           0 :         memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
    2819             :                sizeof(ai->afpi_FinderInfo));
    2820             : 
    2821           0 :         if (ai->afpi_Signature != AFP_Signature
    2822           0 :             || ai->afpi_Version != AFP_Version) {
    2823           0 :                 DEBUG(1, ("Bad AfpInfo signature or version\n"));
    2824           0 :                 TALLOC_FREE(ai);
    2825             :         }
    2826             : 
    2827           0 :         return ai;
    2828             : }

Generated by: LCOV version 1.13