LCOV - code coverage report
Current view: top level - source3/lib - adouble.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 858 1250 68.6 %
Date: 2024-04-21 15:09:00 Functions: 44 44 100.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             :  * preceded 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        9397 : size_t ad_getentrylen(const struct adouble *ad, int eid)
     253             : {
     254        9397 :         return ad->ad_eid[eid].ade_len;
     255             : }
     256             : 
     257       17327 : size_t ad_getentryoff(const struct adouble *ad, int eid)
     258             : {
     259       17327 :         return ad->ad_eid[eid].ade_off;
     260             : }
     261             : 
     262         196 : size_t ad_setentrylen(struct adouble *ad, int eid, size_t len)
     263             : {
     264         196 :         return ad->ad_eid[eid].ade_len = len;
     265             : }
     266             : 
     267          34 : size_t ad_setentryoff(struct adouble *ad, int eid, size_t off)
     268             : {
     269          34 :         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       16265 : static bool ad_entry_check_size(uint32_t eid,
     281             :                                 size_t bufsize,
     282             :                                 uint32_t off,
     283             :                                 uint32_t got_len)
     284             : {
     285          15 :         struct {
     286             :                 off_t expected_len;
     287             :                 bool fixed_size;
     288             :                 bool minimum_size;
     289       16265 :         } 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       16265 :         if (eid >= ADEID_MAX) {
     312           0 :                 return false;
     313             :         }
     314       16265 :         if (got_len == 0) {
     315             :                 /* Entry present, but empty, allow */
     316        7060 :                 return true;
     317             :         }
     318        9201 :         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        9201 :         if (ad_checks[eid].expected_len == -1) {
     326             :                 /* Unused or no limit */
     327        1618 :                 return true;
     328             :         }
     329        7581 :         if (ad_checks[eid].fixed_size) {
     330        3545 :                 if (ad_checks[eid].expected_len != got_len) {
     331             :                         /* Wrong size for fixed size entry. */
     332           0 :                         return false;
     333             :                 }
     334             :         } else {
     335        4036 :                 if (ad_checks[eid].minimum_size) {
     336        4035 :                         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           1 :                         if (got_len > ad_checks[eid].expected_len) {
     345             :                                 /* Too big for variable sized entry. */
     346           0 :                                 return false;
     347             :                         }
     348             :                 }
     349             :         }
     350        7579 :         if (off + got_len < off) {
     351             :                 /* wrap around */
     352           0 :                 return false;
     353             :         }
     354        7579 :         if (off + got_len > bufsize) {
     355             :                 /* overflow */
     356           2 :                 return false;
     357             :         }
     358        7572 :         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        1973 : char *ad_get_entry(const struct adouble *ad, int eid)
     367             : {
     368        1973 :         size_t bufsize = talloc_get_size(ad->ad_data);
     369        1973 :         off_t off = ad_getentryoff(ad, eid);
     370        1973 :         size_t len = ad_getentrylen(ad, eid);
     371           3 :         bool valid;
     372             : 
     373        1973 :         valid = ad_entry_check_size(eid, bufsize, off, len);
     374        1973 :         if (!valid) {
     375           0 :                 return NULL;
     376             :         }
     377             : 
     378        1973 :         if (off == 0 || len == 0) {
     379         576 :                 return NULL;
     380             :         }
     381             : 
     382        1395 :         return ad->ad_data + off;
     383             : }
     384             : 
     385             : /**
     386             :  * Get a date
     387             :  **/
     388         364 : int ad_getdate(const struct adouble *ad, unsigned int dateoff, uint32_t *date)
     389             : {
     390         364 :         bool xlate = (dateoff & AD_DATE_UNIX);
     391         364 :         char *p = NULL;
     392             : 
     393         364 :         dateoff &= AD_DATE_MASK;
     394         364 :         p = ad_get_entry(ad, ADEID_FILEDATESI);
     395         364 :         if (p == NULL) {
     396           0 :                 return -1;
     397             :         }
     398             : 
     399         364 :         if (dateoff > AD_DATE_ACCESS) {
     400           0 :             return -1;
     401             :         }
     402             : 
     403         364 :         memcpy(date, p + dateoff, sizeof(uint32_t));
     404             : 
     405         364 :         if (xlate) {
     406         364 :                 *date = AD_DATE_TO_UNIX(*date);
     407             :         }
     408         364 :         return 0;
     409             : }
     410             : 
     411             : /**
     412             :  * Set a date
     413             :  **/
     414        1064 : int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
     415             : {
     416        1064 :         bool xlate = (dateoff & AD_DATE_UNIX);
     417        1064 :         char *p = NULL;
     418             : 
     419        1064 :         p = ad_get_entry(ad, ADEID_FILEDATESI);
     420        1064 :         if (p == NULL) {
     421         576 :                 return -1;
     422             :         }
     423             : 
     424         488 :         dateoff &= AD_DATE_MASK;
     425         488 :         if (xlate) {
     426         366 :                 date = AD_DATE_FROM_UNIX(date);
     427             :         }
     428             : 
     429         488 :         if (dateoff > AD_DATE_ACCESS) {
     430           0 :                 return -1;
     431             :         }
     432             : 
     433         488 :         memcpy(p + dateoff, &date, sizeof(date));
     434             : 
     435         488 :         return 0;
     436             : }
     437             : 
     438             : 
     439             : /**
     440             :  * Map on-disk AppleDouble id to enumerated id
     441             :  **/
     442       14292 : static uint32_t get_eid(uint32_t eid)
     443             : {
     444       14292 :         if (eid <= 15) {
     445        9408 :                 return eid;
     446             :         }
     447             : 
     448        4872 :         switch (eid) {
     449        1218 :         case AD_DEV:
     450        1218 :                 return ADEID_PRIVDEV;
     451        1218 :         case AD_INO:
     452        1218 :                 return ADEID_PRIVINO;
     453        1218 :         case AD_SYN:
     454        1218 :                 return ADEID_PRIVSYN;
     455        1218 :         case AD_ID:
     456        1218 :                 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           6 : static bool ad_pack_move_reso(struct vfs_handle_struct *handle,
     476             :                               struct adouble *ad,
     477             :                               files_struct *fsp)
     478             : {
     479           0 :         size_t reso_len;
     480           0 :         size_t reso_off;
     481           0 :         size_t n;
     482           0 :         bool ok;
     483             : 
     484           6 :         reso_len = ad_getentrylen(ad, ADEID_RFORK);
     485           6 :         reso_off = ad_getentryoff(ad, ADEID_RFORK);
     486             : 
     487           6 :         if (reso_len == 0) {
     488           0 :                 return true;
     489             :         }
     490             : 
     491           6 :         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           6 :         n = SMB_VFS_NEXT_PWRITE(handle,
     517             :                                 fsp,
     518             :                                 ad->ad_rsrc_data,
     519             :                                 reso_len,
     520             :                                 reso_off);
     521           6 :         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           6 :         ok = true;
     529           6 : out:
     530           6 :         return ok;
     531             : }
     532             : 
     533         492 : static bool ad_pack_xattrs(struct vfs_handle_struct *handle,
     534             :                            struct adouble *ad,
     535             :                            files_struct *fsp)
     536             : {
     537         492 :         struct ad_xattr_header *h = &ad->adx_header;
     538           0 :         size_t oldsize;
     539           0 :         uint32_t off;
     540           0 :         uint32_t data_off;
     541           0 :         uint16_t i;
     542           0 :         bool ok;
     543             : 
     544         492 :         if (ad->adx_entries == NULL) {
     545             :                 /* No xattrs, nothing to pack */
     546         486 :                 return true;
     547             :         }
     548             : 
     549           6 :         if (fsp == NULL) {
     550           0 :                 DBG_ERR("fsp unexpectedly NULL\n");
     551           0 :                 return false;
     552             :         }
     553             : 
     554           6 :         oldsize = talloc_get_size(ad->ad_data);
     555           6 :         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           6 :         data_off = ad_getentryoff(ad, ADEID_FINDERI);
     574           6 :         data_off += ADEDLEN_FINDERI + AD_XATTR_HDR_SIZE;
     575             :         /* 2 bytes padding */
     576           6 :         data_off += 2;
     577             : 
     578          12 :         for (i = 0; i < h->adx_num_attrs; i++) {
     579           6 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
     580             : 
     581             :                 /* Align on 4 byte boundary */
     582           6 :                 data_off = (data_off + 3) & ~3;
     583             : 
     584           6 :                 data_off += e->adx_namelen + ADX_ENTRY_FIXED_SIZE;
     585           6 :                 if (data_off >= AD_XATTR_MAX_HDR_SIZE) {
     586           0 :                         return false;
     587             :                 }
     588             :         }
     589             : 
     590           6 :         off = ad_getentryoff(ad, ADEID_FINDERI);
     591           6 :         off +=  ADEDLEN_FINDERI + AD_XATTR_HDR_SIZE;
     592             :         /* 2 bytes padding */
     593           6 :         off += 2;
     594             : 
     595          12 :         for (i = 0; i < h->adx_num_attrs; i++) {
     596           6 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
     597             : 
     598             :                 /* Align on 4 byte boundary */
     599           6 :                 off = (off + 3) & ~3;
     600             : 
     601           6 :                 e->adx_offset = data_off;
     602           6 :                 data_off += e->adx_length;
     603             : 
     604           6 :                 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           6 :                 if (off + 4 >= AD_XATTR_MAX_HDR_SIZE) {
     614           0 :                         return false;
     615             :                 }
     616           6 :                 RSIVAL(ad->ad_data, off, e->adx_offset);
     617           6 :                 off += 4;
     618             : 
     619           6 :                 if (off + 4 >= AD_XATTR_MAX_HDR_SIZE) {
     620           0 :                         return false;
     621             :                 }
     622           6 :                 RSIVAL(ad->ad_data, off, e->adx_length);
     623           6 :                 off += 4;
     624             : 
     625           6 :                 if (off + 2 >= AD_XATTR_MAX_HDR_SIZE) {
     626           0 :                         return false;
     627             :                 }
     628           6 :                 RSSVAL(ad->ad_data, off, e->adx_flags);
     629           6 :                 off += 2;
     630             : 
     631           6 :                 if (off + 1 >= AD_XATTR_MAX_HDR_SIZE) {
     632           0 :                         return false;
     633             :                 }
     634           6 :                 SCVAL(ad->ad_data, off, e->adx_namelen);
     635           6 :                 off += 1;
     636             : 
     637           6 :                 if (off + e->adx_namelen >= AD_XATTR_MAX_HDR_SIZE) {
     638           0 :                         return false;
     639             :                 }
     640           6 :                 memcpy(ad->ad_data + off, e->adx_name, e->adx_namelen);
     641           6 :                 off += e->adx_namelen;
     642             :         }
     643             : 
     644           6 :         h->adx_data_start = off;
     645           6 :         h->adx_data_length = talloc_get_size(ad->adx_data);
     646           6 :         h->adx_total_size = h->adx_data_start + h->adx_data_length;
     647             : 
     648           6 :         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           6 :         memcpy(ad->ad_data + h->adx_data_start,
     659           6 :                ad->adx_data,
     660           6 :                h->adx_data_length);
     661             : 
     662           6 :         ad_setentrylen(ad,
     663             :                        ADEID_FINDERI,
     664           6 :                        h->adx_total_size - ad_getentryoff(ad, ADEID_FINDERI));
     665             : 
     666           6 :         ad_setentryoff(ad,
     667             :                        ADEID_RFORK,
     668           6 :                        ad_getentryoff(ad, ADEID_FINDERI) +
     669           6 :                        ad_getentrylen(ad, ADEID_FINDERI));
     670             : 
     671           6 :         memcpy(ad->ad_data + ADEDOFF_FILLER, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
     672             : 
     673             :         /*
     674             :          * Rewind, then update the header fields.
     675             :          */
     676             : 
     677           6 :         off = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI;
     678             :         /* 2 bytes padding */
     679           6 :         off += 2;
     680             : 
     681           6 :         RSIVAL(ad->ad_data, off, AD_XATTR_HDR_MAGIC);
     682           6 :         off += 4;
     683           6 :         RSIVAL(ad->ad_data, off, 0);
     684           6 :         off += 4;
     685           6 :         RSIVAL(ad->ad_data, off, h->adx_total_size);
     686           6 :         off += 4;
     687           6 :         RSIVAL(ad->ad_data, off, h->adx_data_start);
     688           6 :         off += 4;
     689           6 :         RSIVAL(ad->ad_data, off, h->adx_data_length);
     690           6 :         off += 4;
     691             : 
     692             :         /* adx_reserved and adx_flags */
     693           6 :         memset(ad->ad_data + off, 0, 3 * 4 + 2);
     694           6 :         off += 3 * 4 + 2;
     695             : 
     696           6 :         RSSVAL(ad->ad_data, off, h->adx_num_attrs);
     697           6 :         off += 2;
     698             : 
     699           6 :         ok = ad_pack_move_reso(handle, ad, fsp);
     700           6 :         if (!ok) {
     701           0 :                 DBG_ERR("Moving resourcefork of [%s] failed\n",
     702             :                         fsp_str_dbg(fsp));
     703           0 :                 return false;
     704             :         }
     705             : 
     706           6 :         return true;
     707             : }
     708             : 
     709             : /**
     710             :  * Pack AppleDouble structure into data buffer
     711             :  **/
     712         492 : static bool ad_pack(struct vfs_handle_struct *handle,
     713             :                     struct adouble *ad,
     714             :                     files_struct *fsp)
     715             : {
     716           0 :         uint32_t       eid;
     717           0 :         uint16_t       nent;
     718           0 :         uint32_t       bufsize;
     719         492 :         uint32_t       offset = 0;
     720           0 :         bool ok;
     721             : 
     722         492 :         bufsize = talloc_get_size(ad->ad_data);
     723         492 :         if (bufsize < AD_DATASZ_DOT_UND) {
     724           0 :                 DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
     725           0 :                 return false;
     726             :         }
     727             : 
     728         492 :         if (offset + ADEDLEN_MAGIC < offset ||
     729         492 :                         offset + ADEDLEN_MAGIC >= bufsize) {
     730           0 :                 return false;
     731             :         }
     732         492 :         RSIVAL(ad->ad_data, offset, ad->ad_magic);
     733         492 :         offset += ADEDLEN_MAGIC;
     734             : 
     735         492 :         if (offset + ADEDLEN_VERSION < offset ||
     736         492 :                         offset + ADEDLEN_VERSION >= bufsize) {
     737           0 :                 return false;
     738             :         }
     739         492 :         RSIVAL(ad->ad_data, offset, ad->ad_version);
     740         492 :         offset += ADEDLEN_VERSION;
     741             : 
     742         492 :         if (offset + ADEDLEN_FILLER < offset ||
     743         492 :                         offset + ADEDLEN_FILLER >= bufsize) {
     744           0 :                 return false;
     745             :         }
     746         492 :         if (ad->ad_type == ADOUBLE_RSRC) {
     747         356 :                 memcpy(ad->ad_data + offset, AD_FILLER_TAG, ADEDLEN_FILLER);
     748             :         }
     749         492 :         offset += ADEDLEN_FILLER;
     750             : 
     751         492 :         if (offset + ADEDLEN_NENTRIES < offset ||
     752         492 :                         offset + ADEDLEN_NENTRIES >= bufsize) {
     753           0 :                 return false;
     754             :         }
     755         492 :         offset += ADEDLEN_NENTRIES;
     756             : 
     757         492 :         ok = ad_pack_xattrs(handle, ad, fsp);
     758         492 :         if (!ok) {
     759           0 :                 return false;
     760             :         }
     761             : 
     762       10332 :         for (eid = 0, nent = 0; eid < ADEID_MAX; eid++) {
     763        9840 :                 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        8040 :                         continue;
     769             :                 }
     770             : 
     771        1800 :                 if (offset + AD_ENTRY_LEN_EID < offset ||
     772        1800 :                                 offset + AD_ENTRY_LEN_EID >= bufsize) {
     773           0 :                         return false;
     774             :                 }
     775        1800 :                 RSIVAL(ad->ad_data, offset, AD_EID_DISK(eid));
     776        1800 :                 offset += AD_ENTRY_LEN_EID;
     777             : 
     778        1800 :                 if (offset + AD_ENTRY_LEN_OFF < offset ||
     779        1800 :                                 offset + AD_ENTRY_LEN_OFF >= bufsize) {
     780           0 :                         return false;
     781             :                 }
     782        1800 :                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_off);
     783        1800 :                 offset += AD_ENTRY_LEN_OFF;
     784             : 
     785        1800 :                 if (offset + AD_ENTRY_LEN_LEN < offset ||
     786        1800 :                                 offset + AD_ENTRY_LEN_LEN >= bufsize) {
     787           0 :                         return false;
     788             :                 }
     789        1800 :                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_len);
     790        1800 :                 offset += AD_ENTRY_LEN_LEN;
     791             : 
     792        1800 :                 nent++;
     793             :         }
     794             : 
     795         492 :         if (ADEDOFF_NENTRIES + 2 >= bufsize) {
     796           0 :                 return false;
     797             :         }
     798         492 :         RSSVAL(ad->ad_data, ADEDOFF_NENTRIES, nent);
     799             : 
     800         492 :         return true;
     801             : }
     802             : 
     803        2268 : static bool ad_unpack_xattrs(struct adouble *ad)
     804             : {
     805        2268 :         struct ad_xattr_header *h = &ad->adx_header;
     806        2268 :         size_t bufsize = talloc_get_size(ad->ad_data);
     807        2268 :         const char *p = ad->ad_data;
     808           0 :         uint32_t hoff;
     809           0 :         uint32_t i;
     810             : 
     811        2268 :         if (ad->ad_type != ADOUBLE_RSRC) {
     812           0 :                 return false;
     813             :         }
     814             : 
     815        2268 :         if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) {
     816        2234 :                 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          34 :         if (bufsize != AD_XATTR_MAX_HDR_SIZE) {
     824           0 :                 return false;
     825             :         }
     826             : 
     827             :         /* 2 bytes padding */
     828          34 :         hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2;
     829             : 
     830          34 :         h->adx_magic       = RIVAL(p, hoff + 0);
     831          34 :         h->adx_debug_tag   = RIVAL(p, hoff + 4); /* Not used -> not checked */
     832          34 :         h->adx_total_size  = RIVAL(p, hoff + 8);
     833          34 :         h->adx_data_start  = RIVAL(p, hoff + 12);
     834          34 :         h->adx_data_length = RIVAL(p, hoff + 16);
     835          34 :         h->adx_flags       = RSVAL(p, hoff + 32); /* Not used -> not checked */
     836          34 :         h->adx_num_attrs   = RSVAL(p, hoff + 34);
     837             : 
     838          34 :         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          34 :         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          34 :         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          34 :         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          34 :         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          34 :         if ((h->adx_data_start + h->adx_data_length) >
     862          34 :             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          34 :         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          34 :         if (h->adx_num_attrs == 0) {
     874           0 :                 return true;
     875             :         }
     876             : 
     877          34 :         ad->adx_entries = talloc_zero_array(
     878             :                 ad, struct ad_xattr_entry, h->adx_num_attrs);
     879          34 :         if (ad->adx_entries == NULL) {
     880           0 :                 return false;
     881             :         }
     882             : 
     883          34 :         hoff += AD_XATTR_HDR_SIZE;
     884             : 
     885          86 :         for (i = 0; i < h->adx_num_attrs; i++) {
     886          52 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
     887             : 
     888          52 :                 hoff = (hoff + 3) & ~3;
     889             : 
     890          52 :                 e->adx_offset  = RIVAL(p, hoff + 0);
     891          52 :                 e->adx_length  = RIVAL(p, hoff + 4);
     892          52 :                 e->adx_flags   = RSVAL(p, hoff + 8);
     893          52 :                 e->adx_namelen = *(p + hoff + 10);
     894             : 
     895          52 :                 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          52 :                 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          52 :                 if ((e->adx_offset + e->adx_length) >
     908          52 :                     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          52 :                 if (e->adx_namelen == 0) {
     916           0 :                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
     917             :                                 e->adx_namelen);
     918           0 :                         return false;
     919             :                 }
     920          52 :                 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          52 :                 if ((hoff + 11 + e->adx_namelen) >
     926          52 :                     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         104 :                 e->adx_name = talloc_strndup(ad->adx_entries,
     934          52 :                                              p + hoff + 11,
     935          52 :                                              e->adx_namelen);
     936          52 :                 if (e->adx_name == NULL) {
     937           0 :                         return false;
     938             :                 }
     939             : 
     940          52 :                 DBG_DEBUG("xattr [%s] offset [0x%x] size [0x%x]\n",
     941             :                           e->adx_name, e->adx_offset, e->adx_length);
     942          52 :                 dump_data(10, (uint8_t *)(ad->ad_data + e->adx_offset),
     943          52 :                           e->adx_length);
     944             : 
     945          52 :                 hoff += 11 + e->adx_namelen;
     946             :         }
     947             : 
     948          34 :         return true;
     949             : }
     950             : 
     951             : /**
     952             :  * Unpack an AppleDouble blob into a struct adoble
     953             :  **/
     954        3493 : static bool ad_unpack(struct adouble *ad, const size_t nentries,
     955             :                       size_t filesize)
     956             : {
     957        3493 :         size_t bufsize = talloc_get_size(ad->ad_data);
     958           7 :         size_t adentries, i;
     959           7 :         uint32_t eid, len, off;
     960           7 :         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        3493 :         if (bufsize < (AD_HEADER_LEN + (AD_ENTRY_LEN * nentries))) {
     970           0 :                 DBG_NOTICE("Bad size\n");
     971           0 :                 return false;
     972             :         }
     973             : 
     974        3493 :         ad->ad_magic = RIVAL(ad->ad_data, 0);
     975        3493 :         ad->ad_version = RIVAL(ad->ad_data, ADEDOFF_VERSION);
     976        3493 :         if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION)) {
     977           0 :                 DBG_NOTICE("Wrong magic or version\n");
     978           0 :                 return false;
     979             :         }
     980             : 
     981        3493 :         memcpy(ad->ad_filler, ad->ad_data + ADEDOFF_FILLER, ADEDLEN_FILLER);
     982             : 
     983        3493 :         adentries = RSVAL(ad->ad_data, ADEDOFF_NENTRIES);
     984        3493 :         if (adentries != nentries) {
     985           0 :                 DBG_NOTICE("Invalid number of entries: %zu\n", adentries);
     986           0 :                 return false;
     987             :         }
     988             : 
     989             :         /* now, read in the entry bits */
     990       17781 :         for (i = 0; i < adentries; i++) {
     991       14292 :                 eid = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN));
     992       14292 :                 eid = get_eid(eid);
     993       14292 :                 off = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 4);
     994       14292 :                 len = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 8);
     995             : 
     996       14292 :                 if (!eid || eid >= ADEID_MAX) {
     997           0 :                         DBG_NOTICE("Bogus eid %d\n", eid);
     998           0 :                         return false;
     999             :                 }
    1000             : 
    1001             :                 /*
    1002             :                  * All entries other than the resource fork are
    1003             :                  * expected to be read into the ad_data buffer, so
    1004             :                  * ensure the specified offset is within that bound
    1005             :                  */
    1006       14292 :                 if ((off > bufsize) && (eid != ADEID_RFORK)) {
    1007           0 :                         DBG_NOTICE("Bogus eid %d: off: %" PRIu32
    1008             :                                    ", len: %" PRIu32 "\n",
    1009             :                                    eid,
    1010             :                                    off,
    1011             :                                    len);
    1012           0 :                         return false;
    1013             :                 }
    1014             : 
    1015       14292 :                 ok = ad_entry_check_size(eid, bufsize, off, len);
    1016       14292 :                 if (!ok) {
    1017           4 :                         DBG_NOTICE("Bogus eid [%" PRIu32 "] bufsize [%zu] "
    1018             :                                    "off [%" PRIu32 "] len [%" PRIu32 "]\n",
    1019             :                                    eid,
    1020             :                                    bufsize,
    1021             :                                    off,
    1022             :                                    len);
    1023           4 :                         return false;
    1024             :                 }
    1025             : 
    1026             :                 /*
    1027             :                  * That would be obviously broken
    1028             :                  */
    1029       14288 :                 if (off > filesize) {
    1030           0 :                         DBG_NOTICE("Bogus eid %d: off: %" PRIu32
    1031             :                                    ", len: %" PRIu32 "\n",
    1032             :                                    eid,
    1033             :                                    off,
    1034             :                                    len);
    1035           0 :                         return false;
    1036             :                 }
    1037             : 
    1038             :                 /*
    1039             :                  * Check for any entry that has its end beyond the
    1040             :                  * filesize.
    1041             :                  */
    1042       14288 :                 if (off + len < off) {
    1043           0 :                         DBG_NOTICE("offset wrap in eid %d: off: %" PRIu32
    1044             :                                    ", len: %" PRIu32 "\n",
    1045             :                                    eid,
    1046             :                                    off,
    1047             :                                    len);
    1048           0 :                         return false;
    1049             : 
    1050             :                 }
    1051       14288 :                 if (off + len > filesize) {
    1052             :                         /*
    1053             :                          * If this is the resource fork entry, we fix
    1054             :                          * up the length, for any other entry we bail
    1055             :                          * out.
    1056             :                          */
    1057           0 :                         if (eid != ADEID_RFORK) {
    1058           0 :                                 DBG_NOTICE("Bogus eid %d: off: %" PRIu32
    1059             :                                            ", len: %" PRIu32 "\n",
    1060             :                                            eid,
    1061             :                                            off,
    1062             :                                            len);
    1063           0 :                                 return false;
    1064             :                         }
    1065             : 
    1066             :                         /*
    1067             :                          * Fixup the resource fork entry by limiting
    1068             :                          * the size to entryoffset - filesize.
    1069             :                          */
    1070           0 :                         len = filesize - off;
    1071           0 :                         DBG_NOTICE("Limiting ADEID_RFORK: off: %" PRIu32
    1072             :                                    ", len: %" PRIu32 "\n",
    1073             :                                    off,
    1074             :                                    len);
    1075             :                 }
    1076             : 
    1077       14288 :                 ad->ad_eid[eid].ade_off = off;
    1078       14288 :                 ad->ad_eid[eid].ade_len = len;
    1079             :         }
    1080             : 
    1081        3489 :         if (ad->ad_type == ADOUBLE_RSRC) {
    1082        2268 :                 ok = ad_unpack_xattrs(ad);
    1083        2268 :                 if (!ok) {
    1084           0 :                         return false;
    1085             :                 }
    1086             :         }
    1087             : 
    1088        3486 :         return true;
    1089             : }
    1090             : 
    1091          28 : static bool ad_convert_move_reso(vfs_handle_struct *handle,
    1092             :                                  struct adouble *ad,
    1093             :                                  const struct smb_filename *smb_fname)
    1094             : {
    1095          28 :         char *buf = NULL;
    1096           0 :         size_t rforklen;
    1097           0 :         size_t rforkoff;
    1098           0 :         ssize_t n;
    1099           0 :         int ret;
    1100             : 
    1101          28 :         rforklen = ad_getentrylen(ad, ADEID_RFORK);
    1102          28 :         if (rforklen == 0) {
    1103           0 :                 return true;
    1104             :         }
    1105             : 
    1106          28 :         buf = talloc_size(ad, rforklen);
    1107          28 :         if (buf == NULL) {
    1108             :                 /*
    1109             :                  * This allocates a buffer for reading the resource fork data in
    1110             :                  * one big swoop. Resource forks won't be larger then, say, 64
    1111             :                  * MB, I swear, so just doing the allocation with the talloc
    1112             :                  * limit as safeguard seems safe.
    1113             :                  */
    1114           0 :                 DBG_ERR("Failed to allocate %zu bytes for rfork\n",
    1115             :                         rforklen);
    1116           0 :                 return false;
    1117             :         }
    1118             : 
    1119          28 :         rforkoff = ad_getentryoff(ad, ADEID_RFORK);
    1120             : 
    1121          28 :         n = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, rforkoff);
    1122          28 :         if (n != rforklen) {
    1123           0 :                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
    1124             :                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1125           0 :                 return false;
    1126             :         }
    1127             : 
    1128          28 :         rforkoff = ADEDOFF_RFORK_DOT_UND;
    1129             : 
    1130          28 :         n = SMB_VFS_PWRITE(ad->ad_fsp, buf, rforklen, rforkoff);
    1131          28 :         if (n != rforklen) {
    1132           0 :                 DBG_ERR("Writing %zu bytes to rfork [%s] failed: %s\n",
    1133             :                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1134           0 :                 return false;
    1135             :         }
    1136             : 
    1137          28 :         ad_setentryoff(ad, ADEID_RFORK, ADEDOFF_RFORK_DOT_UND);
    1138             : 
    1139          28 :         ret = ad_fset(handle, ad, ad->ad_fsp);
    1140          28 :         if (ret != 0) {
    1141           0 :                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
    1142           0 :                 return false;
    1143             :         }
    1144             : 
    1145          28 :         return true;
    1146             : }
    1147             : 
    1148         516 : static bool ad_convert_xattr(vfs_handle_struct *handle,
    1149             :                              struct adouble *ad,
    1150             :                              const struct smb_filename *smb_fname,
    1151             :                              const char *catia_mappings,
    1152             :                              bool *converted_xattr)
    1153             : {
    1154           0 :         static struct char_mappings **string_replace_cmaps = NULL;
    1155           0 :         uint16_t i;
    1156         516 :         int saved_errno = 0;
    1157           0 :         NTSTATUS status;
    1158           0 :         int rc;
    1159           0 :         bool ok;
    1160             : 
    1161         516 :         *converted_xattr = false;
    1162             : 
    1163         516 :         if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
    1164         488 :                 return true;
    1165             :         }
    1166             : 
    1167          28 :         if (string_replace_cmaps == NULL) {
    1168          20 :                 const char **mappings = NULL;
    1169             : 
    1170          20 :                 mappings = str_list_make_v3_const(
    1171             :                         talloc_tos(), catia_mappings, NULL);
    1172          20 :                 if (mappings == NULL) {
    1173           0 :                         return false;
    1174             :                 }
    1175          40 :                 string_replace_cmaps = string_replace_init_map(
    1176          20 :                         handle->conn->sconn, mappings);
    1177          20 :                 TALLOC_FREE(mappings);
    1178             :         }
    1179             : 
    1180          68 :         for (i = 0; i < ad->adx_header.adx_num_attrs; i++) {
    1181          40 :                 struct ad_xattr_entry *e = &ad->adx_entries[i];
    1182          40 :                 char *mapped_name = NULL;
    1183          40 :                 char *tmp = NULL;
    1184          40 :                 struct smb_filename *stream_name = NULL;
    1185          40 :                 files_struct *fsp = NULL;
    1186           0 :                 ssize_t nwritten;
    1187             : 
    1188          40 :                 status = string_replace_allocate(handle->conn,
    1189          40 :                                                  e->adx_name,
    1190             :                                                  string_replace_cmaps,
    1191             :                                                  talloc_tos(),
    1192             :                                                  &mapped_name,
    1193             :                                                  vfs_translate_to_windows);
    1194          40 :                 if (!NT_STATUS_IS_OK(status) &&
    1195           0 :                     !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
    1196             :                 {
    1197           0 :                         DBG_ERR("string_replace_allocate failed\n");
    1198           0 :                         ok = false;
    1199           0 :                         goto fail;
    1200             :                 }
    1201             : 
    1202          40 :                 tmp = mapped_name;
    1203          40 :                 mapped_name = talloc_asprintf(talloc_tos(), ":%s", tmp);
    1204          40 :                 TALLOC_FREE(tmp);
    1205          40 :                 if (mapped_name == NULL) {
    1206           0 :                         ok = false;
    1207           0 :                         goto fail;
    1208             :                 }
    1209             : 
    1210          40 :                 stream_name = synthetic_smb_fname(talloc_tos(),
    1211          40 :                                                   smb_fname->base_name,
    1212             :                                                   mapped_name,
    1213             :                                                   NULL,
    1214          40 :                                                   smb_fname->twrp,
    1215          40 :                                                   smb_fname->flags);
    1216          40 :                 TALLOC_FREE(mapped_name);
    1217          40 :                 if (stream_name == NULL) {
    1218           0 :                         DBG_ERR("synthetic_smb_fname failed\n");
    1219           0 :                         ok = false;
    1220           0 :                         goto fail;
    1221             :                 }
    1222             : 
    1223          40 :                 DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
    1224             : 
    1225          40 :                 status = openat_pathref_fsp(handle->conn->cwd_fsp, stream_name);
    1226          40 :                 if (!NT_STATUS_IS_OK(status) &&
    1227          32 :                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
    1228             :                 {
    1229           0 :                         ok = false;
    1230           0 :                         goto fail;
    1231             :                 }
    1232             : 
    1233          40 :                 status = SMB_VFS_CREATE_FILE(
    1234             :                         handle->conn,                        /* conn */
    1235             :                         NULL,                           /* req */
    1236             :                         NULL,                           /* dirfsp */
    1237             :                         stream_name,                    /* fname */
    1238             :                         FILE_GENERIC_WRITE,             /* access_mask */
    1239             :                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* share_access */
    1240             :                         FILE_OPEN_IF,                   /* create_disposition */
    1241             :                         0,                              /* create_options */
    1242             :                         0,                              /* file_attributes */
    1243             :                         INTERNAL_OPEN_ONLY,             /* oplock_request */
    1244             :                         NULL,                           /* lease */
    1245             :                         0,                              /* allocation_size */
    1246             :                         0,                              /* private_flags */
    1247             :                         NULL,                           /* sd */
    1248             :                         NULL,                           /* ea_list */
    1249             :                         &fsp,                               /* result */
    1250             :                         NULL,                           /* psbuf */
    1251             :                         NULL, NULL);                    /* create context */
    1252          40 :                 TALLOC_FREE(stream_name);
    1253          40 :                 if (!NT_STATUS_IS_OK(status)) {
    1254           0 :                         DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
    1255           0 :                         ok = false;
    1256           0 :                         goto fail;
    1257             :                 }
    1258             : 
    1259          40 :                 nwritten = SMB_VFS_PWRITE(fsp,
    1260             :                                           ad->ad_data + e->adx_offset,
    1261             :                                           e->adx_length,
    1262             :                                           0);
    1263          40 :                 if (nwritten == -1) {
    1264           0 :                         DBG_ERR("SMB_VFS_PWRITE failed\n");
    1265           0 :                         saved_errno = errno;
    1266           0 :                         close_file_free(NULL, &fsp, ERROR_CLOSE);
    1267           0 :                         errno = saved_errno;
    1268           0 :                         ok = false;
    1269           0 :                         goto fail;
    1270             :                 }
    1271             : 
    1272          40 :                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1273          40 :                 if (!NT_STATUS_IS_OK(status)) {
    1274           0 :                         ok = false;
    1275           0 :                         goto fail;
    1276             :                 }
    1277          40 :                 fsp = NULL;
    1278             :         }
    1279             : 
    1280          28 :         ad->adx_header.adx_num_attrs = 0;
    1281          28 :         TALLOC_FREE(ad->adx_entries);
    1282             : 
    1283          28 :         ad_setentrylen(ad, ADEID_FINDERI, ADEDLEN_FINDERI);
    1284             : 
    1285          28 :         rc = ad_fset(handle, ad, ad->ad_fsp);
    1286          28 :         if (rc != 0) {
    1287           0 :                 DBG_ERR("ad_fset on [%s] failed: %s\n",
    1288             :                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1289           0 :                 ok = false;
    1290           0 :                 goto fail;
    1291             :         }
    1292             : 
    1293          28 :         ok = ad_convert_move_reso(handle, ad, smb_fname);
    1294          28 :         if (!ok) {
    1295           0 :                 goto fail;
    1296             :         }
    1297             : 
    1298          28 :         *converted_xattr = true;
    1299          28 :         ok = true;
    1300             : 
    1301          28 : fail:
    1302          28 :         return ok;
    1303             : }
    1304             : 
    1305         516 : static bool ad_convert_finderinfo(vfs_handle_struct *handle,
    1306             :                                   struct adouble *ad,
    1307             :                                   const struct smb_filename *smb_fname)
    1308             : {
    1309         516 :         char *p_ad = NULL;
    1310         516 :         AfpInfo *ai = NULL;
    1311           0 :         DATA_BLOB aiblob;
    1312         516 :         struct smb_filename *stream_name = NULL;
    1313         516 :         files_struct *fsp = NULL;
    1314           0 :         size_t size;
    1315           0 :         ssize_t nwritten;
    1316           0 :         NTSTATUS status;
    1317         516 :         int saved_errno = 0;
    1318           0 :         int cmp;
    1319             : 
    1320         516 :         cmp = memcmp(ad->ad_filler, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
    1321         516 :         if (cmp != 0) {
    1322         446 :                 return true;
    1323             :         }
    1324             : 
    1325          70 :         p_ad = ad_get_entry(ad, ADEID_FINDERI);
    1326          70 :         if (p_ad == NULL) {
    1327           0 :                 return false;
    1328             :         }
    1329             : 
    1330          70 :         ai = afpinfo_new(talloc_tos());
    1331          70 :         if (ai == NULL) {
    1332           0 :                 return false;
    1333             :         }
    1334             : 
    1335          70 :         memcpy(ai->afpi_FinderInfo, p_ad, ADEDLEN_FINDERI);
    1336             : 
    1337          70 :         aiblob = data_blob_talloc(talloc_tos(), NULL, AFP_INFO_SIZE);
    1338          70 :         if (aiblob.data == NULL) {
    1339           0 :                 TALLOC_FREE(ai);
    1340           0 :                 return false;
    1341             :         }
    1342             : 
    1343          70 :         size = afpinfo_pack(ai, (char *)aiblob.data);
    1344          70 :         TALLOC_FREE(ai);
    1345          70 :         if (size != AFP_INFO_SIZE) {
    1346           0 :                 return false;
    1347             :         }
    1348             : 
    1349          70 :         stream_name = synthetic_smb_fname(talloc_tos(),
    1350          70 :                                           smb_fname->base_name,
    1351             :                                           AFPINFO_STREAM,
    1352             :                                           NULL,
    1353          70 :                                           smb_fname->twrp,
    1354          70 :                                           smb_fname->flags);
    1355          70 :         if (stream_name == NULL) {
    1356           0 :                 data_blob_free(&aiblob);
    1357           0 :                 DBG_ERR("synthetic_smb_fname failed\n");
    1358           0 :                 return false;
    1359             :         }
    1360             : 
    1361          70 :         DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
    1362             : 
    1363          70 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, stream_name);
    1364          70 :         if (!NT_STATUS_IS_OK(status) &&
    1365          28 :             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
    1366             :         {
    1367           0 :                 return false;
    1368             :         }
    1369             : 
    1370          70 :         status = SMB_VFS_CREATE_FILE(
    1371             :                 handle->conn,                        /* conn */
    1372             :                 NULL,                           /* req */
    1373             :                 NULL,                           /* dirfsp */
    1374             :                 stream_name,                    /* fname */
    1375             :                 FILE_GENERIC_WRITE,             /* access_mask */
    1376             :                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
    1377             :                 FILE_OPEN_IF,                   /* create_disposition */
    1378             :                 0,                              /* create_options */
    1379             :                 0,                              /* file_attributes */
    1380             :                 INTERNAL_OPEN_ONLY,             /* oplock_request */
    1381             :                 NULL,                           /* lease */
    1382             :                 0,                              /* allocation_size */
    1383             :                 0,                              /* private_flags */
    1384             :                 NULL,                           /* sd */
    1385             :                 NULL,                           /* ea_list */
    1386             :                 &fsp,                               /* result */
    1387             :                 NULL,                           /* psbuf */
    1388             :                 NULL, NULL);                    /* create context */
    1389          70 :         TALLOC_FREE(stream_name);
    1390          70 :         if (!NT_STATUS_IS_OK(status)) {
    1391           6 :                 DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
    1392           6 :                 return false;
    1393             :         }
    1394             : 
    1395          64 :         nwritten = SMB_VFS_PWRITE(fsp,
    1396             :                                   aiblob.data,
    1397             :                                   aiblob.length,
    1398             :                                   0);
    1399          64 :         if (nwritten == -1) {
    1400           0 :                 DBG_ERR("SMB_VFS_PWRITE failed\n");
    1401           0 :                 saved_errno = errno;
    1402           0 :                 close_file_free(NULL, &fsp, ERROR_CLOSE);
    1403           0 :                 errno = saved_errno;
    1404           0 :                 return false;
    1405             :         }
    1406             : 
    1407          64 :         status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1408          64 :         if (!NT_STATUS_IS_OK(status)) {
    1409           0 :                 return false;
    1410             :         }
    1411          64 :         fsp = NULL;
    1412             : 
    1413          64 :         return true;
    1414             : }
    1415             : 
    1416          28 : static bool ad_convert_truncate(vfs_handle_struct *handle,
    1417             :                                 struct adouble *ad,
    1418             :                                 const struct smb_filename *smb_fname)
    1419             : {
    1420           0 :         int rc;
    1421           0 :         off_t newlen;
    1422             : 
    1423          28 :         newlen = ADEDOFF_RFORK_DOT_UND + ad_getentrylen(ad, ADEID_RFORK);
    1424             : 
    1425          28 :         rc = SMB_VFS_FTRUNCATE(ad->ad_fsp, newlen);
    1426          28 :         if (rc != 0) {
    1427           0 :                 return false;
    1428             :         }
    1429             : 
    1430          28 :         return true;
    1431             : }
    1432             : 
    1433         516 : static bool ad_convert_blank_rfork(vfs_handle_struct *handle,
    1434             :                                    struct adouble *ad,
    1435             :                                    uint32_t flags,
    1436             :                                    bool *blank)
    1437         516 : {
    1438         516 :         size_t rforklen = sizeof(empty_resourcefork);
    1439         516 :         char buf[rforklen];
    1440           0 :         ssize_t nread;
    1441           0 :         int cmp;
    1442           0 :         int rc;
    1443             : 
    1444         516 :         *blank = false;
    1445             : 
    1446         516 :         if (!(flags & AD_CONV_WIPE_BLANK)) {
    1447         362 :                 return true;
    1448             :         }
    1449             : 
    1450         154 :         if (ad_getentrylen(ad, ADEID_RFORK) != rforklen) {
    1451         126 :                 return true;
    1452             :         }
    1453             : 
    1454          28 :         nread = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, ADEDOFF_RFORK_DOT_UND);
    1455          28 :         if (nread != rforklen) {
    1456           0 :                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
    1457             :                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
    1458           0 :                 return false;
    1459             :         }
    1460             : 
    1461          28 :         cmp = memcmp(buf, empty_resourcefork, rforklen);
    1462          28 :         if (cmp != 0) {
    1463          20 :                 return true;
    1464             :         }
    1465             : 
    1466           8 :         ad_setentrylen(ad, ADEID_RFORK, 0);
    1467             : 
    1468           8 :         rc = ad_fset(handle, ad, ad->ad_fsp);
    1469           8 :         if (rc != 0) {
    1470           0 :                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
    1471           0 :                 return false;
    1472             :         }
    1473             : 
    1474           8 :         *blank = true;
    1475           8 :         return true;
    1476             : }
    1477             : 
    1478         510 : static bool ad_convert_delete_adfile(vfs_handle_struct *handle,
    1479             :                                 struct adouble *ad,
    1480             :                                 const struct smb_filename *smb_fname,
    1481             :                                 uint32_t flags)
    1482             : {
    1483         510 :         struct smb_filename *parent_fname = NULL;
    1484         510 :         struct smb_filename *at_fname = NULL;
    1485         510 :         struct smb_filename *ad_name = NULL;
    1486           0 :         NTSTATUS status;
    1487           0 :         int rc;
    1488             : 
    1489         510 :         if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
    1490         394 :                 return true;
    1491             :         }
    1492             : 
    1493         116 :         if (!(flags & AD_CONV_DELETE)) {
    1494          96 :                 return true;
    1495             :         }
    1496             : 
    1497          20 :         rc = adouble_path(talloc_tos(), smb_fname, &ad_name);
    1498          20 :         if (rc != 0) {
    1499           0 :                 return false;
    1500             :         }
    1501             : 
    1502          20 :         status = parent_pathref(talloc_tos(),
    1503          20 :                                 handle->conn->cwd_fsp,
    1504             :                                 ad_name,
    1505             :                                 &parent_fname,
    1506             :                                 &at_fname);
    1507          20 :         TALLOC_FREE(ad_name);
    1508          20 :         if (!NT_STATUS_IS_OK(status)) {
    1509           0 :                 return false;
    1510             :         }
    1511             : 
    1512          20 :         rc = SMB_VFS_NEXT_UNLINKAT(handle,
    1513             :                         parent_fname->fsp,
    1514             :                         at_fname,
    1515             :                         0);
    1516          20 :         if (rc != 0) {
    1517           0 :                 DBG_ERR("Unlinking [%s/%s] failed: %s\n",
    1518             :                         smb_fname_str_dbg(parent_fname),
    1519             :                         smb_fname_str_dbg(at_fname), strerror(errno));
    1520           0 :                 TALLOC_FREE(parent_fname);
    1521           0 :                 return false;
    1522             :         }
    1523             : 
    1524          20 :         DBG_WARNING("Unlinked [%s/%s] after conversion\n",
    1525             :                     smb_fname_str_dbg(parent_fname),
    1526             :                     smb_fname_str_dbg(at_fname));
    1527          20 :         TALLOC_FREE(parent_fname);
    1528             : 
    1529          20 :         return true;
    1530             : }
    1531             : 
    1532             : /**
    1533             :  * Convert from Apple's ._ file to Netatalk
    1534             :  *
    1535             :  * Apple's AppleDouble may contain a FinderInfo entry longer then 32
    1536             :  * bytes containing packed xattrs.
    1537             :  *
    1538             :  * @return -1 in case an error occurred, 0 if no conversion was done, 1
    1539             :  * otherwise
    1540             :  **/
    1541        3796 : int ad_convert(struct vfs_handle_struct *handle,
    1542             :                 const struct smb_filename *smb_fname,
    1543             :                 const char *catia_mappings,
    1544             :                 uint32_t flags)
    1545             : {
    1546        3796 :         struct adouble *ad = NULL;
    1547           0 :         bool ok;
    1548        3796 :         bool converted_xattr = false;
    1549           0 :         bool blank;
    1550           0 :         int ret;
    1551             : 
    1552        3796 :         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
    1553        3796 :         if (ad == NULL) {
    1554        3280 :                 return 0;
    1555             :         }
    1556             : 
    1557         516 :         ok = ad_convert_xattr(handle,
    1558             :                               ad,
    1559             :                               smb_fname,
    1560             :                               catia_mappings,
    1561             :                               &converted_xattr);
    1562         516 :         if (!ok) {
    1563           0 :                 ret = -1;
    1564           0 :                 goto done;
    1565             :         }
    1566             : 
    1567         516 :         ok = ad_convert_blank_rfork(handle, ad, flags, &blank);
    1568         516 :         if (!ok) {
    1569           0 :                 ret = -1;
    1570           0 :                 goto done;
    1571             :         }
    1572             : 
    1573         516 :         if (converted_xattr || blank) {
    1574          28 :                 ok = ad_convert_truncate(handle, ad, smb_fname);
    1575          28 :                 if (!ok) {
    1576           0 :                         ret = -1;
    1577           0 :                         goto done;
    1578             :                 }
    1579             :         }
    1580             : 
    1581         516 :         ok = ad_convert_finderinfo(handle, ad, smb_fname);
    1582         516 :         if (!ok) {
    1583           6 :                 DBG_ERR("Failed to convert [%s]\n",
    1584             :                         smb_fname_str_dbg(smb_fname));
    1585           6 :                 ret = -1;
    1586           6 :                 goto done;
    1587             :         }
    1588             : 
    1589         510 :         ok = ad_convert_delete_adfile(handle,
    1590             :                         ad,
    1591             :                         smb_fname,
    1592             :                         flags);
    1593         510 :         if (!ok) {
    1594           0 :                 ret = -1;
    1595           0 :                 goto done;
    1596             :         }
    1597             : 
    1598         510 :         ret = 0;
    1599         516 : done:
    1600         516 :         TALLOC_FREE(ad);
    1601         516 :         return ret;
    1602             : }
    1603             : 
    1604           6 : static bool ad_unconvert_open_ad(TALLOC_CTX *mem_ctx,
    1605             :                                  struct vfs_handle_struct *handle,
    1606             :                                  struct smb_filename *smb_fname,
    1607             :                                  struct smb_filename *adpath,
    1608             :                                  files_struct **_fsp)
    1609             : {
    1610           6 :         files_struct *fsp = NULL;
    1611           0 :         NTSTATUS status;
    1612           0 :         int ret;
    1613             : 
    1614           6 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, adpath);
    1615           6 :         if (!NT_STATUS_IS_OK(status) &&
    1616           2 :             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
    1617           0 :                 return false;
    1618             :         }
    1619             : 
    1620           6 :         status = SMB_VFS_CREATE_FILE(
    1621             :                 handle->conn,
    1622             :                 NULL,                           /* req */
    1623             :                 NULL,                           /* dirfsp */
    1624             :                 adpath,
    1625             :                 FILE_READ_DATA|FILE_WRITE_DATA,
    1626             :                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
    1627             :                 FILE_OPEN_IF,
    1628             :                 0,                              /* create_options */
    1629             :                 0,                              /* file_attributes */
    1630             :                 INTERNAL_OPEN_ONLY,
    1631             :                 NULL,                           /* lease */
    1632             :                 0,                              /* allocation_size */
    1633             :                 0,                              /* private_flags */
    1634             :                 NULL,                           /* sd */
    1635             :                 NULL,                           /* ea_list */
    1636             :                 &fsp,
    1637             :                 NULL,                           /* info */
    1638             :                 NULL, NULL);                    /* create context */
    1639           6 :         if (!NT_STATUS_IS_OK(status)) {
    1640           0 :                 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed: %s\n",
    1641             :                         smb_fname_str_dbg(adpath), nt_errstr(status));
    1642           0 :                 return false;
    1643             :         }
    1644             : 
    1645           6 :         if (fsp->fsp_name->st.st_ex_uid != smb_fname->st.st_ex_uid ||
    1646           6 :             fsp->fsp_name->st.st_ex_gid != smb_fname->st.st_ex_gid)
    1647             :         {
    1648           0 :                 ret = SMB_VFS_FCHOWN(fsp,
    1649             :                                      smb_fname->st.st_ex_uid,
    1650             :                                      smb_fname->st.st_ex_gid);
    1651           0 :                 if (ret != 0) {
    1652           0 :                         DBG_ERR("SMB_VFS_FCHOWN [%s] failed: %s\n",
    1653             :                                 fsp_str_dbg(fsp), nt_errstr(status));
    1654           0 :                         close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1655           0 :                         return false;
    1656             :                 }
    1657             :         }
    1658             : 
    1659           6 :         *_fsp = fsp;
    1660           6 :         return true;
    1661             : }
    1662             : 
    1663          12 : static bool ad_unconvert_get_streams(struct vfs_handle_struct *handle,
    1664             :                                      struct smb_filename *smb_fname,
    1665             :                                      TALLOC_CTX *mem_ctx,
    1666             :                                      unsigned int *num_streams,
    1667             :                                      struct stream_struct **streams)
    1668             : {
    1669          12 :         files_struct *fsp = NULL;
    1670           0 :         NTSTATUS status;
    1671             : 
    1672          12 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, smb_fname);
    1673          12 :         if (!NT_STATUS_IS_OK(status)) {
    1674           0 :                 return false;
    1675             :         }
    1676             : 
    1677          12 :         status = SMB_VFS_CREATE_FILE(
    1678             :                 handle->conn,                                /* conn */
    1679             :                 NULL,                                   /* req */
    1680             :                 NULL,                                   /* dirfsp */
    1681             :                 smb_fname,                              /* fname */
    1682             :                 FILE_READ_ATTRIBUTES,                   /* access_mask */
    1683             :                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
    1684             :                         FILE_SHARE_DELETE),
    1685             :                 FILE_OPEN,                              /* create_disposition*/
    1686             :                 0,                                      /* create_options */
    1687             :                 0,                                      /* file_attributes */
    1688             :                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
    1689             :                 NULL,                                   /* lease */
    1690             :                 0,                                      /* allocation_size */
    1691             :                 0,                                      /* private_flags */
    1692             :                 NULL,                                   /* sd */
    1693             :                 NULL,                                   /* ea_list */
    1694             :                 &fsp,                                       /* result */
    1695             :                 NULL,                                   /* pinfo */
    1696             :                 NULL, NULL);                            /* create context */
    1697          12 :         if (!NT_STATUS_IS_OK(status)) {
    1698           0 :                 DBG_ERR("Opening [%s] failed: %s\n",
    1699             :                         smb_fname_str_dbg(smb_fname),
    1700             :                         nt_errstr(status));
    1701           0 :                 return false;
    1702             :         }
    1703             : 
    1704          12 :         status = vfs_fstreaminfo(fsp,
    1705             :                                 mem_ctx,
    1706             :                                 num_streams,
    1707             :                                 streams);
    1708          12 :         if (!NT_STATUS_IS_OK(status)) {
    1709           0 :                 close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1710           0 :                 DBG_ERR("streaminfo on [%s] failed: %s\n",
    1711             :                         smb_fname_str_dbg(smb_fname),
    1712             :                         nt_errstr(status));
    1713           0 :                 return false;
    1714             :         }
    1715             : 
    1716          12 :         status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1717          12 :         if (!NT_STATUS_IS_OK(status)) {
    1718           0 :                 DBG_ERR("close_file [%s] failed: %s\n",
    1719             :                         smb_fname_str_dbg(smb_fname),
    1720             :                         nt_errstr(status));
    1721           0 :                 return false;
    1722             :         }
    1723             : 
    1724          12 :         return true;
    1725             : }
    1726             : 
    1727             : struct ad_collect_state {
    1728             :         bool have_adfile;
    1729             :         size_t adx_data_off;
    1730             :         char *rsrc_data_buf;
    1731             : };
    1732             : 
    1733          24 : static bool ad_collect_one_stream(struct vfs_handle_struct *handle,
    1734             :                                   struct char_mappings **cmaps,
    1735             :                                   struct smb_filename *smb_fname,
    1736             :                                   const struct stream_struct *stream,
    1737             :                                   struct adouble *ad,
    1738             :                                   struct ad_collect_state *state)
    1739             : {
    1740          24 :         struct smb_filename *sname = NULL;
    1741          24 :         files_struct *fsp = NULL;
    1742          24 :         struct ad_xattr_entry *e = NULL;
    1743          24 :         char *mapped_name = NULL;
    1744          24 :         char *p = NULL;
    1745           0 :         size_t needed_size;
    1746           0 :         ssize_t nread;
    1747           0 :         NTSTATUS status;
    1748           0 :         bool ok;
    1749             : 
    1750          24 :         sname = synthetic_smb_fname(ad,
    1751          24 :                                     smb_fname->base_name,
    1752          24 :                                     stream->name,
    1753             :                                     NULL,
    1754             :                                     smb_fname->twrp,
    1755             :                                     0);
    1756          24 :         if (sname == NULL) {
    1757           0 :                 return false;
    1758             :         }
    1759             : 
    1760          24 :         if (is_ntfs_default_stream_smb_fname(sname)) {
    1761           6 :                 TALLOC_FREE(sname);
    1762           6 :                 return true;
    1763             :         }
    1764             : 
    1765          18 :         DBG_DEBUG("Collecting stream [%s]\n", smb_fname_str_dbg(sname));
    1766             : 
    1767          18 :         status = openat_pathref_fsp(handle->conn->cwd_fsp, sname);
    1768          18 :         if (!NT_STATUS_IS_OK(status)) {
    1769           0 :                 ok = false;
    1770           0 :                 goto out;
    1771             :         }
    1772             : 
    1773          18 :         status = SMB_VFS_CREATE_FILE(
    1774             :                 handle->conn,
    1775             :                 NULL,                           /* req */
    1776             :                 NULL,                           /* dirfsp */
    1777             :                 sname,
    1778             :                 FILE_READ_DATA|DELETE_ACCESS,
    1779             :                 FILE_SHARE_READ,
    1780             :                 FILE_OPEN,
    1781             :                 0,                              /* create_options */
    1782             :                 0,                              /* file_attributes */
    1783             :                 INTERNAL_OPEN_ONLY,             /* oplock_request */
    1784             :                 NULL,                           /* lease */
    1785             :                 0,                              /* allocation_size */
    1786             :                 0,                              /* private_flags */
    1787             :                 NULL,                           /* sd */
    1788             :                 NULL,                           /* ea_list */
    1789             :                 &fsp,
    1790             :                 NULL,                           /* info */
    1791             :                 NULL, NULL);                    /* create context */
    1792          18 :         if (!NT_STATUS_IS_OK(status)) {
    1793           0 :                 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed\n",
    1794             :                         smb_fname_str_dbg(sname));
    1795           0 :                 ok = false;
    1796           0 :                 goto out;
    1797             :         }
    1798             : 
    1799          18 :         if (is_afpinfo_stream(stream->name)) {
    1800           0 :                 char buf[AFP_INFO_SIZE];
    1801             : 
    1802           6 :                 if (stream->size != AFP_INFO_SIZE) {
    1803           0 :                         DBG_ERR("Bad size [%zd] on [%s]\n",
    1804             :                                 (ssize_t)stream->size,
    1805             :                                 smb_fname_str_dbg(sname));
    1806           0 :                         ok = false;
    1807           0 :                         goto out;
    1808             :                 }
    1809             : 
    1810           6 :                 nread = SMB_VFS_PREAD(fsp, buf, stream->size, 0);
    1811           6 :                 if (nread != AFP_INFO_SIZE) {
    1812           0 :                         DBG_ERR("Bad size [%zd] on [%s]\n",
    1813             :                                 (ssize_t)stream->size,
    1814             :                                 smb_fname_str_dbg(sname));
    1815           0 :                         ok = false;
    1816           0 :                         goto out;
    1817             :                 }
    1818             : 
    1819           6 :                 memcpy(ad->ad_data + ADEDOFF_FINDERI_DOT_UND,
    1820             :                        buf + AFP_OFF_FinderInfo,
    1821             :                        AFP_FinderSize);
    1822             : 
    1823           6 :                 ok = set_delete_on_close(fsp,
    1824             :                                          true,
    1825           6 :                                          fsp->conn->session_info->security_token,
    1826           6 :                                          fsp->conn->session_info->unix_token);
    1827           6 :                 if (!ok) {
    1828           0 :                         DBG_ERR("Deleting [%s] failed\n",
    1829             :                                 smb_fname_str_dbg(sname));
    1830           0 :                         ok = false;
    1831           0 :                         goto out;
    1832             :                 }
    1833           6 :                 ok = true;
    1834           6 :                 goto out;
    1835             :         }
    1836             : 
    1837          12 :         if (is_afpresource_stream(stream->name)) {
    1838           6 :                 ad->ad_rsrc_data = talloc_size(ad, stream->size);
    1839           6 :                 if (ad->ad_rsrc_data == NULL) {
    1840           0 :                         ok = false;
    1841           0 :                         goto out;
    1842             :                 }
    1843             : 
    1844           6 :                 nread = SMB_VFS_PREAD(fsp,
    1845             :                                       ad->ad_rsrc_data,
    1846             :                                       stream->size,
    1847             :                                       0);
    1848           6 :                 if (nread != stream->size) {
    1849           0 :                         DBG_ERR("Bad size [%zd] on [%s]\n",
    1850             :                                 (ssize_t)stream->size,
    1851             :                                 smb_fname_str_dbg(sname));
    1852           0 :                         ok = false;
    1853           0 :                         goto out;
    1854             :                 }
    1855             : 
    1856           6 :                 ad_setentrylen(ad, ADEID_RFORK, stream->size);
    1857             : 
    1858           6 :                 if (!state->have_adfile) {
    1859             :                         /*
    1860             :                          * We have a resource *stream* but no AppleDouble
    1861             :                          * sidecar file, this means the share is configured with
    1862             :                          * fruit:resource=stream. So we should delete the
    1863             :                          * resource stream.
    1864             :                          */
    1865           2 :                         ok = set_delete_on_close(
    1866             :                                 fsp,
    1867             :                                 true,
    1868           2 :                                 fsp->conn->session_info->security_token,
    1869           2 :                                 fsp->conn->session_info->unix_token);
    1870           2 :                         if (!ok) {
    1871           0 :                                 DBG_ERR("Deleting [%s] failed\n",
    1872             :                                         smb_fname_str_dbg(sname));
    1873           0 :                                 ok = false;
    1874           0 :                                 goto out;
    1875             :                         }
    1876             :                 }
    1877           6 :                 ok = true;
    1878           6 :                 goto out;
    1879             :         }
    1880             : 
    1881           6 :         ad->adx_entries = talloc_realloc(ad,
    1882             :                                          ad->adx_entries,
    1883             :                                          struct ad_xattr_entry,
    1884             :                                          ad->adx_header.adx_num_attrs + 1);
    1885           6 :         if (ad->adx_entries == NULL) {
    1886           0 :                 ok = false;
    1887           0 :                 goto out;
    1888             :         }
    1889             : 
    1890           6 :         e = &ad->adx_entries[ad->adx_header.adx_num_attrs];
    1891           6 :         *e = (struct ad_xattr_entry) {
    1892           6 :                 .adx_length = stream->size,
    1893             :         };
    1894           6 :         e->adx_name = talloc_strdup(ad, stream->name + 1);
    1895           6 :         if (e->adx_name == NULL) {
    1896           0 :                 ok = false;
    1897           0 :                 goto out;
    1898             :         }
    1899           6 :         p = strchr(e->adx_name, ':');
    1900           6 :         if (p != NULL) {
    1901           6 :                 *p = '\0';
    1902             :         }
    1903             : 
    1904           6 :         status = string_replace_allocate(handle->conn,
    1905           6 :                                          e->adx_name,
    1906             :                                          cmaps,
    1907             :                                          ad,
    1908             :                                          &mapped_name,
    1909             :                                          vfs_translate_to_unix);
    1910           6 :         if (!NT_STATUS_IS_OK(status) &&
    1911           0 :             !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
    1912             :         {
    1913           0 :                 DBG_ERR("string_replace_allocate failed\n");
    1914           0 :                 ok = false;
    1915           0 :                 goto out;
    1916             :         }
    1917             : 
    1918           6 :         e->adx_name = mapped_name;
    1919           6 :         e->adx_namelen = strlen(e->adx_name) + 1,
    1920             : 
    1921           6 :         DBG_DEBUG("%u: name (%s) size (%zu)\n",
    1922             :                   ad->adx_header.adx_num_attrs,
    1923             :                   e->adx_name,
    1924             :                   (size_t)e->adx_length);
    1925             : 
    1926           6 :         ad->adx_header.adx_num_attrs++;
    1927             : 
    1928           6 :         needed_size = state->adx_data_off + stream->size;
    1929           6 :         if (needed_size > talloc_get_size(ad->adx_data)) {
    1930           6 :                 ad->adx_data = talloc_realloc(ad,
    1931             :                                               ad->adx_data,
    1932             :                                               char,
    1933             :                                               needed_size);
    1934           6 :                 if (ad->adx_data == NULL) {
    1935           0 :                         ok = false;
    1936           0 :                         goto out;
    1937             :                 }
    1938             :         }
    1939             : 
    1940           6 :         nread = SMB_VFS_PREAD(fsp,
    1941             :                               ad->adx_data + state->adx_data_off,
    1942             :                               stream->size,
    1943             :                               0);
    1944           6 :         if (nread != stream->size) {
    1945           0 :                 DBG_ERR("Bad size [%zd] on [%s]\n",
    1946             :                         (ssize_t)stream->size,
    1947             :                         smb_fname_str_dbg(sname));
    1948           0 :                 ok = false;
    1949           0 :                 goto out;
    1950             :         }
    1951           6 :         state->adx_data_off += nread;
    1952             : 
    1953           6 :         ok = set_delete_on_close(fsp,
    1954             :                                  true,
    1955           6 :                                  fsp->conn->session_info->security_token,
    1956           6 :                                  fsp->conn->session_info->unix_token);
    1957           6 :         if (!ok) {
    1958           0 :                 DBG_ERR("Deleting [%s] failed\n",
    1959             :                         smb_fname_str_dbg(sname));
    1960           0 :                 ok = false;
    1961           0 :                 goto out;
    1962             :         }
    1963             : 
    1964           6 : out:
    1965          18 :         TALLOC_FREE(sname);
    1966          18 :         if (fsp != NULL) {
    1967          18 :                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    1968          18 :                 if (!NT_STATUS_IS_OK(status)) {
    1969           0 :                         DBG_ERR("close_file [%s] failed: %s\n",
    1970             :                                 smb_fname_str_dbg(smb_fname),
    1971             :                                 nt_errstr(status));
    1972           0 :                         ok = false;
    1973             :                 }
    1974             :         }
    1975             : 
    1976          18 :         return ok;
    1977             : }
    1978             : 
    1979             : /**
    1980             :  * Convert filesystem metadata to AppleDouble file
    1981             :  **/
    1982          12 : bool ad_unconvert(TALLOC_CTX *mem_ctx,
    1983             :                   struct vfs_handle_struct *handle,
    1984             :                   const char *catia_mappings,
    1985             :                   struct smb_filename *smb_fname,
    1986             :                   bool *converted)
    1987             : {
    1988           0 :         static struct char_mappings **cmaps = NULL;
    1989          12 :         TALLOC_CTX *frame = talloc_stackframe();
    1990           0 :         struct ad_collect_state state;
    1991          12 :         struct stream_struct *streams = NULL;
    1992          12 :         struct smb_filename *adpath = NULL;
    1993          12 :         struct adouble *ad = NULL;
    1994          12 :         unsigned int num_streams = 0;
    1995          12 :         size_t to_convert = 0;
    1996          12 :         bool have_rsrc = false;
    1997          12 :         files_struct *fsp = NULL;
    1998           0 :         size_t i;
    1999           0 :         NTSTATUS status;
    2000           0 :         int ret;
    2001           0 :         bool ok;
    2002             : 
    2003          12 :         *converted = false;
    2004             : 
    2005          12 :         if (cmaps == NULL) {
    2006           6 :                 const char **mappings = NULL;
    2007             : 
    2008           6 :                 mappings = str_list_make_v3_const(
    2009             :                         frame, catia_mappings, NULL);
    2010           6 :                 if (mappings == NULL) {
    2011           0 :                         ok = false;
    2012           0 :                         goto out;
    2013             :                 }
    2014           6 :                 cmaps = string_replace_init_map(mem_ctx, mappings);
    2015           6 :                 TALLOC_FREE(mappings);
    2016             :         }
    2017             : 
    2018          12 :         ok = ad_unconvert_get_streams(handle,
    2019             :                                       smb_fname,
    2020             :                                       frame,
    2021             :                                       &num_streams,
    2022             :                                       &streams);
    2023          12 :         if (!ok) {
    2024           0 :                 goto out;
    2025             :         }
    2026             : 
    2027          36 :         for (i = 0; i < num_streams; i++) {
    2028          24 :                 if (strcasecmp_m(streams[i].name, "::$DATA") == 0) {
    2029           6 :                         continue;
    2030             :                 }
    2031          18 :                 to_convert++;
    2032          18 :                 if (is_afpresource_stream(streams[i].name)) {
    2033           6 :                         have_rsrc = true;
    2034             :                 }
    2035             :         }
    2036             : 
    2037          12 :         if (to_convert == 0) {
    2038           6 :                 ok = true;
    2039           6 :                 goto out;
    2040             :         }
    2041             : 
    2042           6 :         state = (struct ad_collect_state) {
    2043             :                 .adx_data_off = 0,
    2044             :         };
    2045             : 
    2046           6 :         ret = adouble_path(frame, smb_fname, &adpath);
    2047           6 :         if (ret != 0) {
    2048           0 :                 ok = false;
    2049           0 :                 goto out;
    2050             :         }
    2051             : 
    2052           6 :         ret = SMB_VFS_STAT(handle->conn, adpath);
    2053           6 :         if (ret == 0) {
    2054           4 :                 state.have_adfile = true;
    2055             :         } else {
    2056           2 :                 if (errno != ENOENT) {
    2057           0 :                         ok = false;
    2058           0 :                         goto out;
    2059             :                 }
    2060           2 :                 state.have_adfile = false;
    2061             :         }
    2062             : 
    2063           6 :         if (to_convert == 1 && have_rsrc && state.have_adfile) {
    2064             :                 /*
    2065             :                  * So we have just a single stream, the resource fork stream
    2066             :                  * from an AppleDouble file. Fine, that means there's nothing to
    2067             :                  * convert.
    2068             :                  */
    2069           0 :                 ok = true;
    2070           0 :                 goto out;
    2071             :         }
    2072             : 
    2073           6 :         ad = ad_init(frame, ADOUBLE_RSRC);
    2074           6 :         if (ad == NULL) {
    2075           0 :                 ok = false;
    2076           0 :                 goto out;
    2077             :         }
    2078             : 
    2079          30 :         for (i = 0; i < num_streams; i++) {
    2080          24 :                 ok = ad_collect_one_stream(handle,
    2081             :                                            cmaps,
    2082             :                                            smb_fname,
    2083          24 :                                            &streams[i],
    2084             :                                            ad,
    2085             :                                            &state);
    2086          24 :                 if (!ok) {
    2087           0 :                         goto out;
    2088             :                 }
    2089             :         }
    2090             : 
    2091           6 :         ok = ad_unconvert_open_ad(frame, handle, smb_fname, adpath, &fsp);
    2092           6 :         if (!ok) {
    2093           0 :                 DBG_ERR("Failed to open adfile [%s]\n",
    2094             :                         smb_fname_str_dbg(smb_fname));
    2095           0 :                 goto out;
    2096             :         }
    2097             : 
    2098           6 :         ret = ad_fset(handle, ad, fsp);
    2099           6 :         if (ret != 0) {
    2100           0 :                 ok = false;
    2101           0 :                 goto out;
    2102             :         }
    2103             : 
    2104           6 :         *converted = true;
    2105           6 :         ok = true;
    2106             : 
    2107          12 : out:
    2108          12 :         if (fsp != NULL) {
    2109           6 :                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
    2110           6 :                 if (!NT_STATUS_IS_OK(status)) {
    2111           0 :                         DBG_ERR("close_file_free() [%s] failed: %s\n",
    2112             :                                 smb_fname_str_dbg(smb_fname),
    2113             :                                 nt_errstr(status));
    2114           0 :                         ok = false;
    2115             :                 }
    2116             :         }
    2117          12 :         TALLOC_FREE(frame);
    2118          12 :         return ok;
    2119             : }
    2120             : 
    2121             : /**
    2122             :  * Read and parse Netatalk AppleDouble metadata xattr
    2123             :  **/
    2124       25238 : static ssize_t ad_read_meta(vfs_handle_struct *handle,
    2125             :                             struct adouble *ad,
    2126             :                             const struct smb_filename *smb_fname)
    2127             : {
    2128       25238 :         int      rc = 0;
    2129           0 :         ssize_t  ealen;
    2130           0 :         bool     ok;
    2131       25238 :         struct files_struct *fsp = smb_fname->fsp;
    2132             : 
    2133       25238 :         DEBUG(10, ("reading meta xattr for %s\n", smb_fname->base_name));
    2134             : 
    2135       25238 :         fsp = metadata_fsp(fsp);
    2136             : 
    2137       25238 :         ealen = SMB_VFS_FGETXATTR(fsp,
    2138             :                                   AFPINFO_EA_NETATALK,
    2139             :                                   ad->ad_data,
    2140             :                                   AD_DATASZ_XATTR);
    2141             : 
    2142       25238 :         if (ealen == -1) {
    2143       24020 :                 switch (errno) {
    2144       24020 :                 case ENOATTR:
    2145             :                 case ENOENT:
    2146       24020 :                         if (errno == ENOATTR) {
    2147       24020 :                                 errno = ENOENT;
    2148             :                         }
    2149       24020 :                         rc = -1;
    2150       24020 :                         goto exit;
    2151           0 :                 default:
    2152           0 :                         DEBUG(2, ("error reading meta xattr: %s\n",
    2153             :                                   strerror(errno)));
    2154           0 :                         rc = -1;
    2155           0 :                         goto exit;
    2156             :                 }
    2157             :         }
    2158        1218 :         if (ealen != AD_DATASZ_XATTR) {
    2159           0 :                 DEBUG(2, ("bad size %zd\n", ealen));
    2160           0 :                 errno = EINVAL;
    2161           0 :                 rc = -1;
    2162           0 :                 goto exit;
    2163             :         }
    2164             : 
    2165             :         /* Now parse entries */
    2166        1218 :         ok = ad_unpack(ad, ADEID_NUM_XATTR, AD_DATASZ_XATTR);
    2167        1218 :         if (!ok) {
    2168           0 :                 DBG_WARNING(
    2169             :                         "Invalid AppleDouble xattr metadata (%s) in file: %s - "
    2170             :                         "Consider deleting the corrupted file.\n",
    2171             :                         smb_fname->base_name,
    2172             :                         ad->ad_fsp->fsp_name->base_name);
    2173           0 :                 errno = EINVAL;
    2174           0 :                 rc = -1;
    2175           0 :                 goto exit;
    2176             :         }
    2177             : 
    2178        1218 :         if (!ad_getentryoff(ad, ADEID_FINDERI)
    2179        1218 :             || !ad_getentryoff(ad, ADEID_COMMENT)
    2180        1218 :             || !ad_getentryoff(ad, ADEID_FILEDATESI)
    2181        1218 :             || !ad_getentryoff(ad, ADEID_AFPFILEI)
    2182        1218 :             || !ad_getentryoff(ad, ADEID_PRIVDEV)
    2183        1218 :             || !ad_getentryoff(ad, ADEID_PRIVINO)
    2184        1218 :             || !ad_getentryoff(ad, ADEID_PRIVSYN)
    2185        1218 :             || !ad_getentryoff(ad, ADEID_PRIVID)) {
    2186           0 :                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
    2187           0 :                 errno = EINVAL;
    2188           0 :                 rc = -1;
    2189           0 :                 goto exit;
    2190             :         }
    2191             : 
    2192        1218 : exit:
    2193       25238 :         DEBUG(10, ("reading meta xattr for %s, rc: %d\n",
    2194             :                 smb_fname->base_name, rc));
    2195             : 
    2196       25238 :         if (rc != 0) {
    2197       24020 :                 ealen = -1;
    2198       24020 :                 if (errno == EINVAL) {
    2199           0 :                         become_root();
    2200           0 :                         (void)SMB_VFS_FREMOVEXATTR(fsp,
    2201             :                                                    AFPINFO_EA_NETATALK);
    2202           0 :                         unbecome_root();
    2203           0 :                         errno = ENOENT;
    2204             :                 }
    2205             :         }
    2206       25238 :         return ealen;
    2207             : }
    2208             : 
    2209        9214 : static NTSTATUS adouble_open_rsrc_fsp(const struct files_struct *dirfsp,
    2210             :                                       const struct smb_filename *smb_base_fname,
    2211             :                                       int in_flags,
    2212             :                                       mode_t mode,
    2213             :                                       struct files_struct **_ad_fsp)
    2214             : {
    2215        9214 :         int rc = 0;
    2216        9214 :         struct adouble *ad = NULL;
    2217        9214 :         struct smb_filename *adp_smb_fname = NULL;
    2218        9214 :         struct files_struct *ad_fsp = NULL;
    2219           0 :         NTSTATUS status;
    2220        9214 :         struct vfs_open_how how = { .flags = in_flags, .mode = mode, };
    2221             : 
    2222        9214 :         rc = adouble_path(talloc_tos(),
    2223             :                           smb_base_fname,
    2224             :                           &adp_smb_fname);
    2225        9214 :         if (rc != 0) {
    2226           0 :                 return NT_STATUS_NO_MEMORY;
    2227             :         }
    2228             : 
    2229        9214 :         status = create_internal_fsp(dirfsp->conn,
    2230             :                                      adp_smb_fname,
    2231             :                                      &ad_fsp);
    2232        9214 :         if (!NT_STATUS_IS_OK(status)) {
    2233           0 :                 return status;
    2234             :         }
    2235             : 
    2236             : #ifdef O_PATH
    2237        4607 :         how.flags &= ~(O_PATH);
    2238             : #endif
    2239        9214 :         if (how.flags & (O_CREAT | O_TRUNC | O_WRONLY)) {
    2240             :                 /* We always need read/write access for the metadata header too */
    2241         144 :                 how.flags &= ~(O_WRONLY);
    2242         144 :                 how.flags |= O_RDWR;
    2243             :         }
    2244             : 
    2245        9214 :         status = fd_openat(dirfsp,
    2246             :                            adp_smb_fname,
    2247             :                            ad_fsp,
    2248             :                            &how);
    2249        9214 :         if (!NT_STATUS_IS_OK(status)) {
    2250        7326 :                 file_free(NULL, ad_fsp);
    2251        7326 :                 return status;
    2252             :         }
    2253             : 
    2254        1888 :         if (how.flags & (O_CREAT | O_TRUNC)) {
    2255         138 :                 ad = ad_init(talloc_tos(), ADOUBLE_RSRC);
    2256         138 :                 if (ad == NULL) {
    2257           0 :                         file_free(NULL, ad_fsp);
    2258           0 :                         return NT_STATUS_NO_MEMORY;
    2259             :                 }
    2260             : 
    2261         138 :                 rc = ad_fset(ad_fsp->conn->vfs_handles, ad, ad_fsp);
    2262         138 :                 if (rc != 0) {
    2263           0 :                         file_free(NULL, ad_fsp);
    2264           0 :                         return NT_STATUS_IO_DEVICE_ERROR;
    2265             :                 }
    2266         138 :                 TALLOC_FREE(ad);
    2267             :         }
    2268             : 
    2269        1888 :         *_ad_fsp = ad_fsp;
    2270        1888 :         return NT_STATUS_OK;
    2271             : }
    2272             : 
    2273        1012 : NTSTATUS adouble_open_from_base_fsp(const struct files_struct *dirfsp,
    2274             :                                     struct files_struct *base_fsp,
    2275             :                                     adouble_type_t type,
    2276             :                                     int flags,
    2277             :                                     mode_t mode,
    2278             :                                     struct files_struct **_ad_fsp)
    2279             : {
    2280        1012 :         *_ad_fsp = NULL;
    2281             : 
    2282        1012 :         SMB_ASSERT(base_fsp != NULL);
    2283        1012 :         SMB_ASSERT(!fsp_is_alternate_stream(base_fsp));
    2284             : 
    2285        1012 :         switch (type) {
    2286           0 :         case ADOUBLE_META:
    2287           0 :                 return NT_STATUS_INTERNAL_ERROR;
    2288        1012 :         case ADOUBLE_RSRC:
    2289        1012 :                 return adouble_open_rsrc_fsp(dirfsp,
    2290        1012 :                                              base_fsp->fsp_name,
    2291             :                                              flags,
    2292             :                                              mode,
    2293             :                                              _ad_fsp);
    2294             :         }
    2295             : 
    2296           0 :         return NT_STATUS_INTERNAL_ERROR;
    2297             : }
    2298             : 
    2299             : /*
    2300             :  * Here's the deal: for ADOUBLE_META we can do without an fd as we can issue
    2301             :  * path based xattr calls. For ADOUBLE_RSRC however we need a full-fledged fd
    2302             :  * for file IO on the ._ file.
    2303             :  */
    2304       34642 : static int ad_open(vfs_handle_struct *handle,
    2305             :                    struct adouble *ad,
    2306             :                    files_struct *fsp,
    2307             :                    const struct smb_filename *smb_fname,
    2308             :                    int flags,
    2309             :                    mode_t mode)
    2310             : {
    2311           0 :         NTSTATUS status;
    2312             : 
    2313       34642 :         DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name,
    2314             :                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
    2315             : 
    2316       34642 :         if (ad->ad_type == ADOUBLE_META) {
    2317       25238 :                 return 0;
    2318             :         }
    2319             : 
    2320        9404 :         if (fsp != NULL) {
    2321        1202 :                 ad->ad_fsp = fsp;
    2322        1202 :                 ad->ad_opened = false;
    2323        1202 :                 return 0;
    2324             :         }
    2325             : 
    2326        8202 :         status = adouble_open_rsrc_fsp(handle->conn->cwd_fsp,
    2327             :                                        smb_fname,
    2328             :                                        flags,
    2329             :                                        mode,
    2330        8202 :                                        &ad->ad_fsp);
    2331        8202 :         if (!NT_STATUS_IS_OK(status)) {
    2332        7136 :                 errno = map_errno_from_nt_status(status);
    2333        7136 :                 return -1;
    2334             :         }
    2335        1066 :         ad->ad_opened = true;
    2336             : 
    2337        1066 :         DBG_DEBUG("Path [%s] type [%s]\n",
    2338             :                   smb_fname->base_name,
    2339             :                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
    2340             : 
    2341        1066 :         return 0;
    2342             : }
    2343             : 
    2344        2268 : static ssize_t ad_read_rsrc_adouble(vfs_handle_struct *handle,
    2345             :                                     struct adouble *ad,
    2346             :                                     const struct smb_filename *smb_fname)
    2347             : {
    2348           0 :         size_t to_read;
    2349           0 :         ssize_t len;
    2350           0 :         int ret;
    2351           0 :         bool ok;
    2352             : 
    2353        2268 :         ret = SMB_VFS_NEXT_FSTAT(handle, ad->ad_fsp, &ad->ad_fsp->fsp_name->st);
    2354        2268 :         if (ret != 0) {
    2355           0 :                 DBG_ERR("fstat [%s] failed: %s\n",
    2356             :                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
    2357           0 :                 return -1;
    2358             :         }
    2359             : 
    2360        2268 :         to_read = ad->ad_fsp->fsp_name->st.st_ex_size;
    2361        2268 :         if (to_read > AD_XATTR_MAX_HDR_SIZE) {
    2362          72 :                 to_read = AD_XATTR_MAX_HDR_SIZE;
    2363             :         }
    2364             : 
    2365        2268 :         len = SMB_VFS_NEXT_PREAD(handle,
    2366             :                                  ad->ad_fsp,
    2367             :                                  ad->ad_data,
    2368             :                                  to_read,
    2369             :                                  0);
    2370        2268 :         if (len != to_read)  {
    2371           0 :                 DBG_NOTICE("%s %s: bad size: %zd\n",
    2372             :                            smb_fname->base_name, strerror(errno), len);
    2373           0 :                 return -1;
    2374             :         }
    2375             : 
    2376             :         /* Now parse entries */
    2377        2268 :         ok = ad_unpack(ad,
    2378             :                        ADEID_NUM_DOT_UND,
    2379        2268 :                        ad->ad_fsp->fsp_name->st.st_ex_size);
    2380        2268 :         if (!ok) {
    2381           0 :                 DBG_WARNING("Invalid AppleDouble resource (%s) in file: %s - "
    2382             :                             "Consider deleting the corrupted file.\n",
    2383             :                             smb_fname->base_name,
    2384             :                             ad->ad_fsp->fsp_name->base_name);
    2385           0 :                 errno = EINVAL;
    2386           0 :                 return -1;
    2387             :         }
    2388             : 
    2389        2268 :         if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
    2390        2268 :             || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
    2391        2268 :             || (ad_getentryoff(ad, ADEID_RFORK) < ADEDOFF_RFORK_DOT_UND))
    2392             :         {
    2393           0 :                 DBG_WARNING("Invalid AppleDouble resource (%s) in file: %s - "
    2394             :                             "Consider deleting the corrupted file.\n",
    2395             :                             smb_fname->base_name,
    2396             :                             ad->ad_fsp->fsp_name->base_name);
    2397           0 :                 errno = EINVAL;
    2398           0 :                 return -1;
    2399             :         }
    2400             : 
    2401        2268 :         return len;
    2402             : }
    2403             : 
    2404             : /**
    2405             :  * Read and parse resource fork, either ._ AppleDouble file or xattr
    2406             :  **/
    2407        2268 : static ssize_t ad_read_rsrc(vfs_handle_struct *handle,
    2408             :                             struct adouble *ad,
    2409             :                             const struct smb_filename *smb_fname)
    2410             : {
    2411        2268 :         return ad_read_rsrc_adouble(handle, ad, smb_fname);
    2412             : }
    2413             : 
    2414             : /**
    2415             :  * Read and unpack an AppleDouble metadata xattr or resource
    2416             :  **/
    2417       27506 : static ssize_t ad_read(vfs_handle_struct *handle,
    2418             :                        struct adouble *ad,
    2419             :                        const struct smb_filename *smb_fname)
    2420             : {
    2421       27506 :         switch (ad->ad_type) {
    2422       25238 :         case ADOUBLE_META:
    2423       25238 :                 return ad_read_meta(handle, ad, smb_fname);
    2424        2268 :         case ADOUBLE_RSRC:
    2425        2268 :                 return ad_read_rsrc(handle, ad, smb_fname);
    2426           0 :         default:
    2427           0 :                 return -1;
    2428             :         }
    2429             : }
    2430             : 
    2431       34908 : static int adouble_destructor(struct adouble *ad)
    2432             : {
    2433           0 :         NTSTATUS status;
    2434             : 
    2435       34908 :         if (!ad->ad_opened) {
    2436       33842 :                 return 0;
    2437             :         }
    2438             : 
    2439        1066 :         SMB_ASSERT(ad->ad_fsp != NULL);
    2440             : 
    2441        1066 :         status = fd_close(ad->ad_fsp);
    2442        1066 :         if (!NT_STATUS_IS_OK(status)) {
    2443           0 :                 DBG_ERR("Closing [%s] failed: %s\n",
    2444             :                         fsp_str_dbg(ad->ad_fsp), nt_errstr(status));
    2445             :         }
    2446        1066 :         file_free(NULL, ad->ad_fsp);
    2447        1066 :         ad->ad_fsp = NULL;
    2448        1066 :         ad->ad_opened = false;
    2449             : 
    2450        1066 :         return 0;
    2451             : }
    2452             : 
    2453             : /**
    2454             :  * Allocate a struct adouble without initialiing it
    2455             :  *
    2456             :  * The struct is either hang of the fsp extension context or if fsp is
    2457             :  * NULL from ctx.
    2458             :  *
    2459             :  * @param[in] ctx        talloc context
    2460             :  * @param[in] handle     vfs handle
    2461             :  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2462             :  *
    2463             :  * @return               adouble handle
    2464             :  **/
    2465       34908 : static struct adouble *ad_alloc(TALLOC_CTX *ctx,
    2466             :                                 adouble_type_t type)
    2467             : {
    2468       34908 :         int rc = 0;
    2469       34908 :         size_t adsize = 0;
    2470           0 :         struct adouble *ad;
    2471             : 
    2472       34908 :         switch (type) {
    2473       25360 :         case ADOUBLE_META:
    2474       25360 :                 adsize = AD_DATASZ_XATTR;
    2475       25360 :                 break;
    2476        9548 :         case ADOUBLE_RSRC:
    2477             :                 /*
    2478             :                  * AppleDouble ._ file case, optimize for fewer (but larger)
    2479             :                  * IOs. Two cases:
    2480             :                  *
    2481             :                  * - without xattrs size of the header is exactly
    2482             :                  *   AD_DATASZ_DOT_UND (82) bytes
    2483             :                  *
    2484             :                  * - with embedded xattrs it can be larger, up to
    2485             :                  *   AD_XATTR_MAX_HDR_SIZE
    2486             :                  *
    2487             :                  * Larger headers are not supported, but this is a reasonable
    2488             :                  * limit that is also employed by the macOS client.
    2489             :                  *
    2490             :                  * We used the largest possible size to be able to read the full
    2491             :                  * header with one IO.
    2492             :                  */
    2493        9548 :                 adsize = AD_XATTR_MAX_HDR_SIZE;
    2494        9548 :                 break;
    2495           0 :         default:
    2496           0 :                 return NULL;
    2497             :         }
    2498             : 
    2499       34908 :         ad = talloc_zero(ctx, struct adouble);
    2500       34908 :         if (ad == NULL) {
    2501           0 :                 rc = -1;
    2502           0 :                 goto exit;
    2503             :         }
    2504             : 
    2505       34908 :         if (adsize) {
    2506       34908 :                 ad->ad_data = talloc_zero_array(ad, char, adsize);
    2507       34908 :                 if (ad->ad_data == NULL) {
    2508           0 :                         rc = -1;
    2509           0 :                         goto exit;
    2510             :                 }
    2511             :         }
    2512             : 
    2513       34908 :         ad->ad_type = type;
    2514       34908 :         ad->ad_magic = AD_MAGIC;
    2515       34908 :         ad->ad_version = AD_VERSION;
    2516             : 
    2517       34908 :         talloc_set_destructor(ad, adouble_destructor);
    2518             : 
    2519       34908 : exit:
    2520       34908 :         if (rc != 0) {
    2521           0 :                 TALLOC_FREE(ad);
    2522             :         }
    2523       34908 :         return ad;
    2524             : }
    2525             : 
    2526             : /**
    2527             :  * Allocate and initialize a new struct adouble
    2528             :  *
    2529             :  * @param[in] ctx        talloc context
    2530             :  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2531             :  *
    2532             :  * @return               adouble handle, initialized
    2533             :  **/
    2534         266 : struct adouble *ad_init(TALLOC_CTX *ctx, adouble_type_t type)
    2535             : {
    2536         266 :         int rc = 0;
    2537           0 :         const struct ad_entry_order  *eid;
    2538         266 :         struct adouble *ad = NULL;
    2539         266 :         time_t t = time(NULL);
    2540             : 
    2541         266 :         switch (type) {
    2542         122 :         case ADOUBLE_META:
    2543         122 :                 eid = entry_order_meta_xattr;
    2544         122 :                 break;
    2545         144 :         case ADOUBLE_RSRC:
    2546         144 :                 eid = entry_order_dot_und;
    2547         144 :                 break;
    2548           0 :         default:
    2549           0 :                 return NULL;
    2550             :         }
    2551             : 
    2552         266 :         ad = ad_alloc(ctx, type);
    2553         266 :         if (ad == NULL) {
    2554           0 :                 return NULL;
    2555             :         }
    2556             : 
    2557        1530 :         while (eid->id) {
    2558        1264 :                 ad->ad_eid[eid->id].ade_off = eid->offset;
    2559        1264 :                 ad->ad_eid[eid->id].ade_len = eid->len;
    2560        1264 :                 eid++;
    2561             :         }
    2562             : 
    2563             :         /* put something sane in the date fields */
    2564         266 :         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, t);
    2565         266 :         ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, t);
    2566         266 :         ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, t);
    2567         266 :         ad_setdate(ad, AD_DATE_BACKUP, htonl(AD_DATE_START));
    2568             : 
    2569         266 :         if (rc != 0) {
    2570           0 :                 TALLOC_FREE(ad);
    2571             :         }
    2572         266 :         return ad;
    2573             : }
    2574             : 
    2575       34642 : static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
    2576             :                                        vfs_handle_struct *handle,
    2577             :                                        files_struct *fsp,
    2578             :                                        const struct smb_filename *smb_fname,
    2579             :                                        adouble_type_t type)
    2580             : {
    2581       34642 :         int rc = 0;
    2582           0 :         ssize_t len;
    2583       34642 :         struct adouble *ad = NULL;
    2584           0 :         int mode;
    2585             : 
    2586       34642 :         if (fsp != NULL) {
    2587        1476 :                 if (fsp_is_alternate_stream(fsp)) {
    2588         274 :                         smb_fname = fsp->base_fsp->fsp_name;
    2589             :                 } else {
    2590        1202 :                         smb_fname = fsp->fsp_name;
    2591             :                 }
    2592             :         }
    2593             : 
    2594       34642 :         DEBUG(10, ("ad_get(%s) called for %s\n",
    2595             :                    type == ADOUBLE_META ? "meta" : "rsrc",
    2596             :                    smb_fname != NULL ? smb_fname->base_name : "???"));
    2597             : 
    2598       34642 :         ad = ad_alloc(ctx, type);
    2599       34642 :         if (ad == NULL) {
    2600           0 :                 rc = -1;
    2601           0 :                 goto exit;
    2602             :         }
    2603             : 
    2604             :         /* Try rw first so we can use the fd in ad_convert() */
    2605       34642 :         mode = O_RDWR;
    2606             : 
    2607       34642 :         rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
    2608       34642 :         if (rc == -1 && ((errno == EROFS) || (errno == EACCES))) {
    2609           0 :                 mode = O_RDONLY;
    2610           0 :                 rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
    2611             :         }
    2612       34642 :         if (rc == -1) {
    2613        7136 :                 DBG_DEBUG("ad_open [%s] error [%s]\n",
    2614             :                           smb_fname->base_name, strerror(errno));
    2615        7136 :                 goto exit;
    2616             : 
    2617             :         }
    2618             : 
    2619       27506 :         len = ad_read(handle, ad, smb_fname);
    2620       27506 :         if (len == -1) {
    2621       24020 :                 DEBUG(10, ("error reading AppleDouble for %s\n",
    2622             :                         smb_fname->base_name));
    2623       24020 :                 rc = -1;
    2624       24020 :                 goto exit;
    2625             :         }
    2626             : 
    2627        3486 : exit:
    2628       34642 :         DEBUG(10, ("ad_get(%s) for %s returning %d\n",
    2629             :                   type == ADOUBLE_META ? "meta" : "rsrc",
    2630             :                   smb_fname->base_name, rc));
    2631             : 
    2632       34642 :         if (rc != 0) {
    2633       31156 :                 TALLOC_FREE(ad);
    2634             :         }
    2635       34642 :         return ad;
    2636             : }
    2637             : 
    2638             : /**
    2639             :  * Return AppleDouble data for a file
    2640             :  *
    2641             :  * @param[in] ctx      talloc context
    2642             :  * @param[in] handle   vfs handle
    2643             :  * @param[in] smb_fname pathname to file or directory
    2644             :  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2645             :  *
    2646             :  * @return             talloced struct adouble or NULL on error
    2647             :  **/
    2648       33166 : struct adouble *ad_get(TALLOC_CTX *ctx,
    2649             :                               vfs_handle_struct *handle,
    2650             :                               const struct smb_filename *smb_fname,
    2651             :                               adouble_type_t type)
    2652             : {
    2653       33166 :         return ad_get_internal(ctx, handle, NULL, smb_fname, type);
    2654             : }
    2655             : 
    2656             : /**
    2657             :  * Return AppleDouble data for a file
    2658             :  *
    2659             :  * @param[in] ctx      talloc context
    2660             :  * @param[in] handle   vfs handle
    2661             :  * @param[in] fsp      fsp to use for IO
    2662             :  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
    2663             :  *
    2664             :  * @return             talloced struct adouble or NULL on error
    2665             :  **/
    2666        1476 : struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
    2667             :                         files_struct *fsp, adouble_type_t type)
    2668             : {
    2669        1476 :         return ad_get_internal(ctx, handle, fsp, NULL, type);
    2670             : }
    2671             : 
    2672             : /**
    2673             :  * Set AppleDouble metadata on a file or directory
    2674             :  *
    2675             :  * @param[in] ad      adouble handle
    2676             :  * @param[in] fsp     file handle
    2677             :  *
    2678             :  * @return            status code, 0 means success
    2679             :  **/
    2680         492 : int ad_fset(struct vfs_handle_struct *handle,
    2681             :             struct adouble *ad,
    2682             :             files_struct *fsp)
    2683             : {
    2684         492 :         int rc = -1;
    2685           0 :         ssize_t len;
    2686           0 :         bool ok;
    2687             : 
    2688         492 :         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
    2689             : 
    2690         492 :         ok = ad_pack(handle, ad, fsp);
    2691         492 :         if (!ok) {
    2692           0 :                 return -1;
    2693             :         }
    2694             : 
    2695         492 :         switch (ad->ad_type) {
    2696         136 :         case ADOUBLE_META:
    2697         136 :                 rc = SMB_VFS_NEXT_FSETXATTR(handle,
    2698             :                                    fsp->base_fsp ? fsp->base_fsp : fsp,
    2699             :                                    AFPINFO_EA_NETATALK,
    2700             :                                    ad->ad_data,
    2701             :                                    AD_DATASZ_XATTR, 0);
    2702         136 :                 break;
    2703         356 :         case ADOUBLE_RSRC:
    2704         356 :                 len = SMB_VFS_NEXT_PWRITE(handle,
    2705             :                                           fsp,
    2706             :                                           ad->ad_data,
    2707             :                                           ad_getentryoff(ad, ADEID_RFORK),
    2708             :                                           0);
    2709         356 :                 if (len != ad_getentryoff(ad, ADEID_RFORK)) {
    2710           0 :                         DBG_ERR("short write on %s: %zd\n", fsp_str_dbg(fsp), len);
    2711           0 :                         return -1;
    2712             :                 }
    2713         356 :                 rc = 0;
    2714         356 :                 break;
    2715             : 
    2716           0 :         default:
    2717           0 :                 return -1;
    2718             :         }
    2719             : 
    2720         492 :         DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
    2721             : 
    2722         492 :         return rc;
    2723             : }
    2724             : 
    2725         722 : bool is_adouble_file(const char *path)
    2726             : {
    2727         722 :         const char *p = NULL;
    2728           0 :         int match;
    2729             : 
    2730         722 :         p = strrchr(path, '/');
    2731         722 :         if (p == NULL) {
    2732         722 :                 p = path;
    2733             :         } else {
    2734           0 :                 p++;
    2735             :         }
    2736             : 
    2737         722 :         match = strncmp(p,
    2738             :                         ADOUBLE_NAME_PREFIX,
    2739             :                         strlen(ADOUBLE_NAME_PREFIX));
    2740         722 :         if (match != 0) {
    2741         704 :                 return false;
    2742             :         }
    2743          18 :         return true;
    2744             : }
    2745             : 
    2746             : /**
    2747             :  * Prepend "._" to a basename
    2748             :  * Return a new struct smb_filename with stream_name == NULL.
    2749             :  **/
    2750        9826 : int adouble_path(TALLOC_CTX *ctx,
    2751             :                  const struct smb_filename *smb_fname_in,
    2752             :                  struct smb_filename **pp_smb_fname_out)
    2753             : {
    2754           0 :         char *parent;
    2755           0 :         const char *base;
    2756        9826 :         struct smb_filename *smb_fname = NULL;
    2757             : 
    2758        9826 :         smb_fname = cp_smb_filename_nostream(ctx, smb_fname_in);
    2759        9826 :         if (smb_fname == NULL) {
    2760           0 :                 return -1;
    2761             :         }
    2762             : 
    2763             :         /* We're replacing base_name. */
    2764        9826 :         TALLOC_FREE(smb_fname->base_name);
    2765             : 
    2766        9826 :         SET_STAT_INVALID(smb_fname->st);
    2767             : 
    2768        9826 :         if (!parent_dirname(smb_fname, smb_fname_in->base_name,
    2769             :                                 &parent, &base)) {
    2770           0 :                 TALLOC_FREE(smb_fname);
    2771           0 :                 return -1;
    2772             :         }
    2773             : 
    2774        9826 :         if (ISDOT(parent)) {
    2775        5248 :                 smb_fname->base_name = talloc_asprintf(smb_fname,
    2776             :                                         "._%s", base);
    2777             :         } else {
    2778        4578 :                 smb_fname->base_name = talloc_asprintf(smb_fname,
    2779             :                                         "%s/._%s", parent, base);
    2780             :         }
    2781        9826 :         if (smb_fname->base_name == NULL) {
    2782           0 :                 TALLOC_FREE(smb_fname);
    2783           0 :                 return -1;
    2784             :         }
    2785             : 
    2786        9826 :         *pp_smb_fname_out = smb_fname;
    2787             : 
    2788        9826 :         return 0;
    2789             : }
    2790             : 
    2791             : /**
    2792             :  * Allocate and initialize an AfpInfo struct
    2793             :  **/
    2794         224 : AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
    2795             : {
    2796         224 :         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
    2797         224 :         if (ai == NULL) {
    2798           0 :                 return NULL;
    2799             :         }
    2800         224 :         ai->afpi_Signature = AFP_Signature;
    2801         224 :         ai->afpi_Version = AFP_Version;
    2802         224 :         ai->afpi_BackupTime = AD_DATE_START;
    2803         224 :         return ai;
    2804             : }
    2805             : 
    2806             : /**
    2807             :  * Pack an AfpInfo struct into a buffer
    2808             :  *
    2809             :  * Buffer size must be at least AFP_INFO_SIZE
    2810             :  * Returns size of packed buffer
    2811             :  **/
    2812         224 : ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
    2813             : {
    2814         224 :         memset(buf, 0, AFP_INFO_SIZE);
    2815             : 
    2816         224 :         RSIVAL(buf, 0, ai->afpi_Signature);
    2817         224 :         RSIVAL(buf, 4, ai->afpi_Version);
    2818         224 :         RSIVAL(buf, 12, ai->afpi_BackupTime);
    2819         224 :         memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
    2820             : 
    2821         224 :         return AFP_INFO_SIZE;
    2822             : }
    2823             : 
    2824             : /**
    2825             :  * Unpack a buffer into a AfpInfo structure
    2826             :  *
    2827             :  * Buffer size must be at least AFP_INFO_SIZE
    2828             :  * Returns allocated AfpInfo struct
    2829             :  **/
    2830         540 : AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data, bool validate)
    2831             : {
    2832         540 :         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
    2833         540 :         if (ai == NULL) {
    2834           0 :                 return NULL;
    2835             :         }
    2836             : 
    2837         540 :         ai->afpi_Signature = RIVAL(data, 0);
    2838         540 :         ai->afpi_Version = RIVAL(data, 4);
    2839         540 :         ai->afpi_BackupTime = RIVAL(data, 12);
    2840         540 :         memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
    2841             :                sizeof(ai->afpi_FinderInfo));
    2842             : 
    2843         540 :         if (validate) {
    2844         536 :                 if (ai->afpi_Signature != AFP_Signature
    2845         536 :                     || ai->afpi_Version != AFP_Version)
    2846             :                 {
    2847           0 :                         DEBUG(1, ("Bad AfpInfo signature or version\n"));
    2848           0 :                         TALLOC_FREE(ai);
    2849             :                 }
    2850             :         } else {
    2851           4 :                 ai->afpi_Signature = AFP_Signature;
    2852           4 :                 ai->afpi_Version = AFP_Version;
    2853             :         }
    2854             : 
    2855         540 :         return ai;
    2856             : }

Generated by: LCOV version 1.14