LCOV - code coverage report
Current view: top level - source3/lib - adouble.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 833 1160 71.8 %
Date: 2021-09-23 10:06:22 Functions: 43 54 79.6 %

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

Generated by: LCOV version 1.13