#include "messages.h"
#include "libcli/security/security.h"
#include "../libcli/smb/smb2_create_ctx.h"
-#include "lib/util/sys_rw.h"
#include "lib/util/tevent_ntstatus.h"
#include "lib/util/tevent_unix.h"
+#include "lib/util/util_file.h"
#include "offload_token.h"
#include "string_replace.h"
-
-#include <gnutls/gnutls.h>
-#include <gnutls/crypto.h>
+#include "hash_inode.h"
+#include "lib/adouble.h"
+#include "lib/util_macstreams.h"
+#include "source3/smbd/dir.h"
/*
* Enhanced OS X and Netatalk compatibility
* streams are deferred to vfs_streams_xattr.
*
* The OS X client maps all NTFS illegal characters to the Unicode
- * private range. This module optionally stores the charcters using
+ * private range. This module optionally stores the characters using
* their native ASCII encoding using vfs_catia. If you're not enabling
* this feature, you can skip catia from vfs modules.
*
#define DBGC_CLASS vfs_fruit_debug_level
#define FRUIT_PARAM_TYPE_NAME "fruit"
-#define ADOUBLE_NAME_PREFIX "._"
-
-#define NETATALK_META_XATTR "org.netatalk.Metadata"
-#define NETATALK_RSRC_XATTR "org.netatalk.ResourceFork"
-
-#if defined(HAVE_ATTROPEN)
-#define AFPINFO_EA_NETATALK NETATALK_META_XATTR
-#define AFPRESOURCE_EA_NETATALK NETATALK_RSRC_XATTR
-#else
-#define AFPINFO_EA_NETATALK "user." NETATALK_META_XATTR
-#define AFPRESOURCE_EA_NETATALK "user." NETATALK_RSRC_XATTR
-#endif
enum apple_fork {APPLE_FORK_DATA, APPLE_FORK_RSRC};
const char *model;
bool time_machine;
off_t time_machine_max_size;
+ bool convert_adouble;
bool wipe_intentionally_left_blank_rfork;
bool delete_empty_adfiles;
+ bool validate_afpinfo;
/*
* Additional options, all enabled by default,
bool readdir_attr_rsize;
bool readdir_attr_finder_info;
bool readdir_attr_max_access;
+ /* Recursion guard. Will go away when we have STATX. */
+ bool in_openat_pathref_fsp;
};
static const struct enum_list fruit_rsrc[] = {
{ -1, NULL}
};
-static const char *fruit_catia_maps =
- "0x01:0xf001,0x02:0xf002,0x03:0xf003,0x04:0xf004,"
- "0x05:0xf005,0x06:0xf006,0x07:0xf007,0x08:0xf008,"
- "0x09:0xf009,0x0a:0xf00a,0x0b:0xf00b,0x0c:0xf00c,"
- "0x0d:0xf00d,0x0e:0xf00e,0x0f:0xf00f,0x10:0xf010,"
- "0x11:0xf011,0x12:0xf012,0x13:0xf013,0x14:0xf014,"
- "0x15:0xf015,0x16:0xf016,0x17:0xf017,0x18:0xf018,"
- "0x19:0xf019,0x1a:0xf01a,0x1b:0xf01b,0x1c:0xf01c,"
- "0x1d:0xf01d,0x1e:0xf01e,0x1f:0xf01f,"
- "0x22:0xf020,0x2a:0xf021,0x3a:0xf022,0x3c:0xf023,"
- "0x3e:0xf024,0x3f:0xf025,0x5c:0xf026,0x7c:0xf027,"
- "0x0d:0xf00d";
-
-/*****************************************************************************
- * Defines, functions and data structures that deal with AppleDouble
- *****************************************************************************/
-
-/*
- * There are two AppleDouble blobs we deal with:
- *
- * - ADOUBLE_META - AppleDouble blob used by Netatalk for storing
- * metadata in an xattr
- *
- * - ADOUBLE_RSRC - AppleDouble blob used by OS X and Netatalk in
- * ._ files
- */
-typedef enum {ADOUBLE_META, ADOUBLE_RSRC} adouble_type_t;
-
-/* Version info */
-#define AD_VERSION2 0x00020000
-#define AD_VERSION AD_VERSION2
-
-/*
- * AppleDouble entry IDs.
- */
-#define ADEID_DFORK 1
-#define ADEID_RFORK 2
-#define ADEID_NAME 3
-#define ADEID_COMMENT 4
-#define ADEID_ICONBW 5
-#define ADEID_ICONCOL 6
-#define ADEID_FILEI 7
-#define ADEID_FILEDATESI 8
-#define ADEID_FINDERI 9
-#define ADEID_MACFILEI 10
-#define ADEID_PRODOSFILEI 11
-#define ADEID_MSDOSFILEI 12
-#define ADEID_SHORTNAME 13
-#define ADEID_AFPFILEI 14
-#define ADEID_DID 15
-
-/* Private Netatalk entries */
-#define ADEID_PRIVDEV 16
-#define ADEID_PRIVINO 17
-#define ADEID_PRIVSYN 18
-#define ADEID_PRIVID 19
-#define ADEID_MAX (ADEID_PRIVID + 1)
-
-/*
- * These are the real ids for the private entries,
- * as stored in the adouble file
- */
-#define AD_DEV 0x80444556
-#define AD_INO 0x80494E4F
-#define AD_SYN 0x8053594E
-#define AD_ID 0x8053567E
-
-/* Number of actually used entries */
-#define ADEID_NUM_XATTR 8
-#define ADEID_NUM_DOT_UND 2
-#define ADEID_NUM_RSRC_XATTR 1
-
-/* AppleDouble magic */
-#define AD_APPLESINGLE_MAGIC 0x00051600
-#define AD_APPLEDOUBLE_MAGIC 0x00051607
-#define AD_MAGIC AD_APPLEDOUBLE_MAGIC
-
-/* Sizes of relevant entry bits */
-#define ADEDLEN_MAGIC 4
-#define ADEDLEN_VERSION 4
-#define ADEDLEN_FILLER 16
-#define AD_FILLER_TAG "Netatalk " /* should be 16 bytes */
-#define AD_FILLER_TAG_OSX "Mac OS X " /* should be 16 bytes */
-#define ADEDLEN_NENTRIES 2
-#define AD_HEADER_LEN (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
- ADEDLEN_FILLER + ADEDLEN_NENTRIES) /* 26 */
-#define AD_ENTRY_LEN_EID 4
-#define AD_ENTRY_LEN_OFF 4
-#define AD_ENTRY_LEN_LEN 4
-#define AD_ENTRY_LEN (AD_ENTRY_LEN_EID + AD_ENTRY_LEN_OFF + AD_ENTRY_LEN_LEN)
-
-/* Field widths */
-#define ADEDLEN_NAME 255
-#define ADEDLEN_COMMENT 200
-#define ADEDLEN_FILEI 16
-#define ADEDLEN_FINDERI 32
-#define ADEDLEN_FILEDATESI 16
-#define ADEDLEN_SHORTNAME 12 /* length up to 8.3 */
-#define ADEDLEN_AFPFILEI 4
-#define ADEDLEN_MACFILEI 4
-#define ADEDLEN_PRODOSFILEI 8
-#define ADEDLEN_MSDOSFILEI 2
-#define ADEDLEN_DID 4
-#define ADEDLEN_PRIVDEV 8
-#define ADEDLEN_PRIVINO 8
-#define ADEDLEN_PRIVSYN 8
-#define ADEDLEN_PRIVID 4
-
-/* Offsets */
-#define ADEDOFF_MAGIC 0
-#define ADEDOFF_VERSION (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
-#define ADEDOFF_FILLER (ADEDOFF_VERSION + ADEDLEN_VERSION)
-#define ADEDOFF_NENTRIES (ADEDOFF_FILLER + ADEDLEN_FILLER)
-
-#define ADEDOFF_FINDERI_XATTR (AD_HEADER_LEN + \
- (ADEID_NUM_XATTR * AD_ENTRY_LEN))
-#define ADEDOFF_COMMENT_XATTR (ADEDOFF_FINDERI_XATTR + ADEDLEN_FINDERI)
-#define ADEDOFF_FILEDATESI_XATTR (ADEDOFF_COMMENT_XATTR + ADEDLEN_COMMENT)
-#define ADEDOFF_AFPFILEI_XATTR (ADEDOFF_FILEDATESI_XATTR + \
- ADEDLEN_FILEDATESI)
-#define ADEDOFF_PRIVDEV_XATTR (ADEDOFF_AFPFILEI_XATTR + ADEDLEN_AFPFILEI)
-#define ADEDOFF_PRIVINO_XATTR (ADEDOFF_PRIVDEV_XATTR + ADEDLEN_PRIVDEV)
-#define ADEDOFF_PRIVSYN_XATTR (ADEDOFF_PRIVINO_XATTR + ADEDLEN_PRIVINO)
-#define ADEDOFF_PRIVID_XATTR (ADEDOFF_PRIVSYN_XATTR + ADEDLEN_PRIVSYN)
-
-#define ADEDOFF_FINDERI_DOT_UND (AD_HEADER_LEN + \
- (ADEID_NUM_DOT_UND * AD_ENTRY_LEN))
-#define ADEDOFF_RFORK_DOT_UND (ADEDOFF_FINDERI_DOT_UND + ADEDLEN_FINDERI)
-
-#define AD_DATASZ_XATTR (AD_HEADER_LEN + \
- (ADEID_NUM_XATTR * AD_ENTRY_LEN) + \
- ADEDLEN_FINDERI + ADEDLEN_COMMENT + \
- ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + \
- ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
- ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
-
-#if AD_DATASZ_XATTR != 402
-#error bad size for AD_DATASZ_XATTR
-#endif
-
-#define AD_DATASZ_DOT_UND (AD_HEADER_LEN + \
- (ADEID_NUM_DOT_UND * AD_ENTRY_LEN) + \
- ADEDLEN_FINDERI)
-#if AD_DATASZ_DOT_UND != 82
-#error bad size for AD_DATASZ_DOT_UND
-#endif
-
-/*
- * Sharemode locks fcntl() offsets
- */
-#if _FILE_OFFSET_BITS == 64 || defined(HAVE_LARGEFILE)
-#define AD_FILELOCK_BASE (UINT64_C(0x7FFFFFFFFFFFFFFF) - 9)
-#else
-#define AD_FILELOCK_BASE (UINT32_C(0x7FFFFFFF) - 9)
-#endif
-#define BYTELOCK_MAX (AD_FILELOCK_BASE - 1)
-
-#define AD_FILELOCK_OPEN_WR (AD_FILELOCK_BASE + 0)
-#define AD_FILELOCK_OPEN_RD (AD_FILELOCK_BASE + 1)
-#define AD_FILELOCK_RSRC_OPEN_WR (AD_FILELOCK_BASE + 2)
-#define AD_FILELOCK_RSRC_OPEN_RD (AD_FILELOCK_BASE + 3)
-#define AD_FILELOCK_DENY_WR (AD_FILELOCK_BASE + 4)
-#define AD_FILELOCK_DENY_RD (AD_FILELOCK_BASE + 5)
-#define AD_FILELOCK_RSRC_DENY_WR (AD_FILELOCK_BASE + 6)
-#define AD_FILELOCK_RSRC_DENY_RD (AD_FILELOCK_BASE + 7)
-#define AD_FILELOCK_OPEN_NONE (AD_FILELOCK_BASE + 8)
-#define AD_FILELOCK_RSRC_OPEN_NONE (AD_FILELOCK_BASE + 9)
-
-/* Time stuff we overload the bits a little */
-#define AD_DATE_CREATE 0
-#define AD_DATE_MODIFY 4
-#define AD_DATE_BACKUP 8
-#define AD_DATE_ACCESS 12
-#define AD_DATE_MASK (AD_DATE_CREATE | AD_DATE_MODIFY | \
- AD_DATE_BACKUP | AD_DATE_ACCESS)
-#define AD_DATE_UNIX (1 << 10)
-#define AD_DATE_START 0x80000000
-#define AD_DATE_DELTA 946684800
-#define AD_DATE_FROM_UNIX(x) (htonl((x) - AD_DATE_DELTA))
-#define AD_DATE_TO_UNIX(x) (ntohl(x) + AD_DATE_DELTA)
-
-#define AD_XATTR_HDR_MAGIC 0x41545452 /* 'ATTR' */
-#define AD_XATTR_MAX_ENTRIES 1024 /* Some arbitrarily enforced limit */
-#define AD_XATTR_HDR_SIZE 36
-#define AD_XATTR_MAX_HDR_SIZE 65536
-
-/* Accessor macros */
-#define ad_getentrylen(ad,eid) ((ad)->ad_eid[(eid)].ade_len)
-#define ad_getentryoff(ad,eid) ((ad)->ad_eid[(eid)].ade_off)
-#define ad_setentrylen(ad,eid,len) ((ad)->ad_eid[(eid)].ade_len = (len))
-#define ad_setentryoff(ad,eid,off) ((ad)->ad_eid[(eid)].ade_off = (off))
-
-/*
- * Both struct ad_xattr_header and struct ad_xattr_entry describe the in memory
- * representation as well as the on-disk format.
- *
- * The ad_xattr_header follows the FinderInfo data in the FinderInfo entry if
- * the length of the FinderInfo entry is larger then 32 bytes. It is then
- * preceeded with 2 bytes padding.
- *
- * Cf: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/vfs/vfs_xattr.c
- */
-
-struct ad_xattr_header {
- uint32_t adx_magic; /* ATTR_HDR_MAGIC */
- uint32_t adx_debug_tag; /* for debugging == file id of owning file */
- uint32_t adx_total_size; /* file offset of end of attribute header + entries + data */
- uint32_t adx_data_start; /* file offset to attribute data area */
- uint32_t adx_data_length; /* length of attribute data area */
- uint32_t adx_reserved[3];
- uint16_t adx_flags;
- uint16_t adx_num_attrs;
-};
-
-/* On-disk entries are aligned on 4 byte boundaries */
-struct ad_xattr_entry {
- uint32_t adx_offset; /* file offset to data */
- uint32_t adx_length; /* size of attribute data */
- uint16_t adx_flags;
- uint8_t adx_namelen; /* included the NULL terminator */
- char *adx_name; /* NULL-terminated UTF-8 name */
-};
-
-struct ad_entry {
- size_t ade_off;
- size_t ade_len;
-};
-
-struct adouble {
- int ad_fd;
- bool ad_opened;
- adouble_type_t ad_type;
- uint32_t ad_magic;
- uint32_t ad_version;
- uint8_t ad_filler[ADEDLEN_FILLER];
- struct ad_entry ad_eid[ADEID_MAX];
- char *ad_data;
- struct ad_xattr_header adx_header;
- struct ad_xattr_entry *adx_entries;
-};
-
-struct ad_entry_order {
- uint32_t id, offset, len;
-};
-
-/* Netatalk AppleDouble metadata xattr */
-static const
-struct ad_entry_order entry_order_meta_xattr[ADEID_NUM_XATTR + 1] = {
- {ADEID_FINDERI, ADEDOFF_FINDERI_XATTR, ADEDLEN_FINDERI},
- {ADEID_COMMENT, ADEDOFF_COMMENT_XATTR, 0},
- {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_XATTR, ADEDLEN_FILEDATESI},
- {ADEID_AFPFILEI, ADEDOFF_AFPFILEI_XATTR, ADEDLEN_AFPFILEI},
- {ADEID_PRIVDEV, ADEDOFF_PRIVDEV_XATTR, 0},
- {ADEID_PRIVINO, ADEDOFF_PRIVINO_XATTR, 0},
- {ADEID_PRIVSYN, ADEDOFF_PRIVSYN_XATTR, 0},
- {ADEID_PRIVID, ADEDOFF_PRIVID_XATTR, 0},
- {0, 0, 0}
-};
-
-/* AppleDouble resource fork file (the ones prefixed by "._") */
-static const
-struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
- {ADEID_FINDERI, ADEDOFF_FINDERI_DOT_UND, ADEDLEN_FINDERI},
- {ADEID_RFORK, ADEDOFF_RFORK_DOT_UND, 0},
- {0, 0, 0}
-};
-
-/* Conversion from enumerated id to on-disk AppleDouble id */
-#define AD_EID_DISK(a) (set_eid[a])
-static const uint32_t set_eid[] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- AD_DEV, AD_INO, AD_SYN, AD_ID
-};
-
-static char empty_resourcefork[] = {
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
- 0x54, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73,
- 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x66, 0x6F,
- 0x72, 0x6B, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E,
- 0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x6C, 0x79,
- 0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x62, 0x6C,
- 0x61, 0x6E, 0x6B, 0x20, 0x20, 0x20, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x1C, 0x00, 0x1E, 0xFF, 0xFF
-};
-
struct fio {
+ vfs_handle_struct *handle;
+ files_struct *fsp; /* backlink to itself */
+
/* tcon config handle */
struct fruit_config_data *config;
+ /* Backend fsp for AppleDouble file, can be NULL */
+ files_struct *ad_fsp;
+ /* link from adouble_open_from_base_fsp() to fio */
+ struct fio *real_fio;
+
/* Denote stream type, meta or rsrc */
adouble_type_t type;
- /* Whether the create created the stream */
- bool created;
-
/*
* AFP_AfpInfo stream created, but not written yet, thus still a fake
* pipe fd. This is set to true in fruit_open_meta if there was no
- * exisiting stream but the caller requested O_CREAT. It is later set to
+ * existing stream but the caller requested O_CREAT. It is later set to
* false when we get a write on the stream that then does open and
* create the stream.
*/
int mode;
};
-/*
- * Forward declarations
- */
-static struct adouble *ad_init(TALLOC_CTX *ctx,
- adouble_type_t type);
-static struct adouble *ad_get(TALLOC_CTX *ctx,
- vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- adouble_type_t type);
-static int ad_set(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname);
-static int ad_fset(struct vfs_handle_struct *handle,
- struct adouble *ad,
- files_struct *fsp);
-static int adouble_path(TALLOC_CTX *ctx,
- const struct smb_filename *smb_fname__in,
- struct smb_filename **ppsmb_fname_out);
-static AfpInfo *afpinfo_new(TALLOC_CTX *ctx);
-static ssize_t afpinfo_pack(const AfpInfo *ai, char *buf);
-static AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data);
-
+/*****************************************************************************
+ * Helper functions
+ *****************************************************************************/
-/**
- * Return a pointer to an AppleDouble entry
- *
- * Returns NULL if the entry is not present
- **/
-static char *ad_get_entry(const struct adouble *ad, int eid)
+static struct adouble *ad_get_meta_fsp(TALLOC_CTX *ctx,
+ vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
{
- off_t off = ad_getentryoff(ad, eid);
- size_t len = ad_getentrylen(ad, eid);
+ NTSTATUS status;
+ struct adouble *ad = NULL;
+ struct smb_filename *smb_fname_cp = NULL;
+ struct fruit_config_data *config = NULL;
- if (off == 0 || len == 0) {
- return NULL;
+ if (smb_fname->fsp != NULL) {
+ return ad_get(ctx, handle, smb_fname, ADOUBLE_META);
}
- return ad->ad_data + off;
-}
-
-/**
- * Get a date
- **/
-static int ad_getdate(const struct adouble *ad,
- unsigned int dateoff,
- uint32_t *date)
-{
- bool xlate = (dateoff & AD_DATE_UNIX);
- char *p = NULL;
+ SMB_VFS_HANDLE_GET_DATA(handle,
+ config,
+ struct fruit_config_data,
+ return NULL);
- dateoff &= AD_DATE_MASK;
- p = ad_get_entry(ad, ADEID_FILEDATESI);
- if (p == NULL) {
- return -1;
+ if (config->in_openat_pathref_fsp) {
+ return NULL;
}
- if (dateoff > AD_DATE_ACCESS) {
- return -1;
+ smb_fname_cp = cp_smb_filename(ctx,
+ smb_fname);
+ if (smb_fname_cp == NULL) {
+ return NULL;
}
-
- memcpy(date, p + dateoff, sizeof(uint32_t));
-
- if (xlate) {
- *date = AD_DATE_TO_UNIX(*date);
+ TALLOC_FREE(smb_fname_cp->stream_name);
+ config->in_openat_pathref_fsp = true;
+ status = openat_pathref_fsp(handle->conn->cwd_fsp,
+ smb_fname_cp);
+ config->in_openat_pathref_fsp = false;
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(smb_fname_cp);
+ return NULL;
}
- return 0;
+
+ ad = ad_get(ctx, handle, smb_fname_cp, ADOUBLE_META);
+ TALLOC_FREE(smb_fname_cp);
+ return ad;
}
-/**
- * Set a date
- **/
-static int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
+static struct fio *fruit_get_complete_fio(vfs_handle_struct *handle,
+ files_struct *fsp)
{
- bool xlate = (dateoff & AD_DATE_UNIX);
- char *p = NULL;
-
- p = ad_get_entry(ad, ADEID_FILEDATESI);
- if (p == NULL) {
- return -1;
- }
-
- dateoff &= AD_DATE_MASK;
- if (xlate) {
- date = AD_DATE_FROM_UNIX(date);
- }
+ struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
- if (dateoff > AD_DATE_ACCESS) {
- return -1;
+ if (fio == NULL) {
+ return NULL;
}
- memcpy(p + dateoff, &date, sizeof(date));
-
- return 0;
-}
-
-
-/**
- * Map on-disk AppleDouble id to enumerated id
- **/
-static uint32_t get_eid(uint32_t eid)
-{
- if (eid <= 15) {
- return eid;
- }
-
- switch (eid) {
- case AD_DEV:
- return ADEID_PRIVDEV;
- case AD_INO:
- return ADEID_PRIVINO;
- case AD_SYN:
- return ADEID_PRIVSYN;
- case AD_ID:
- return ADEID_PRIVID;
- default:
- break;
+ if (fio->real_fio != NULL) {
+ /*
+ * This is an fsp from adouble_open_from_base_fsp()
+ * we should just pass this to the next
+ * module.
+ */
+ return NULL;
}
- return 0;
+ return fio;
}
/**
- * Pack AppleDouble structure into data buffer
+ * Initialize config struct from our smb.conf config parameters
**/
-static bool ad_pack(struct adouble *ad)
-{
- uint32_t eid;
- uint16_t nent;
- uint32_t bufsize;
- uint32_t offset = 0;
-
- bufsize = talloc_get_size(ad->ad_data);
- if (bufsize < AD_DATASZ_DOT_UND) {
- DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
- return false;
- }
-
- if (offset + ADEDLEN_MAGIC < offset ||
- offset + ADEDLEN_MAGIC >= bufsize) {
- return false;
- }
- RSIVAL(ad->ad_data, offset, ad->ad_magic);
- offset += ADEDLEN_MAGIC;
-
- if (offset + ADEDLEN_VERSION < offset ||
- offset + ADEDLEN_VERSION >= bufsize) {
- return false;
- }
- RSIVAL(ad->ad_data, offset, ad->ad_version);
- offset += ADEDLEN_VERSION;
-
- if (offset + ADEDLEN_FILLER < offset ||
- offset + ADEDLEN_FILLER >= bufsize) {
- return false;
- }
- if (ad->ad_type == ADOUBLE_RSRC) {
- memcpy(ad->ad_data + offset, AD_FILLER_TAG, ADEDLEN_FILLER);
- }
- offset += ADEDLEN_FILLER;
-
- if (offset + ADEDLEN_NENTRIES < offset ||
- offset + ADEDLEN_NENTRIES >= bufsize) {
- return false;
- }
- offset += ADEDLEN_NENTRIES;
-
- for (eid = 0, nent = 0; eid < ADEID_MAX; eid++) {
- if (ad->ad_eid[eid].ade_off == 0) {
- /*
- * ade_off is also used as indicator whether a
- * specific entry is used or not
- */
- continue;
- }
-
- if (offset + AD_ENTRY_LEN_EID < offset ||
- offset + AD_ENTRY_LEN_EID >= bufsize) {
- return false;
- }
- RSIVAL(ad->ad_data, offset, AD_EID_DISK(eid));
- offset += AD_ENTRY_LEN_EID;
-
- if (offset + AD_ENTRY_LEN_OFF < offset ||
- offset + AD_ENTRY_LEN_OFF >= bufsize) {
- return false;
- }
- RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_off);
- offset += AD_ENTRY_LEN_OFF;
-
- if (offset + AD_ENTRY_LEN_LEN < offset ||
- offset + AD_ENTRY_LEN_LEN >= bufsize) {
- return false;
- }
- RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_len);
- offset += AD_ENTRY_LEN_LEN;
-
- nent++;
- }
-
- if (ADEDOFF_NENTRIES + 2 >= bufsize) {
- return false;
- }
- RSSVAL(ad->ad_data, ADEDOFF_NENTRIES, nent);
-
- return true;
-}
-
-static bool ad_unpack_xattrs(struct adouble *ad)
+static int init_fruit_config(vfs_handle_struct *handle)
{
- struct ad_xattr_header *h = &ad->adx_header;
- const char *p = ad->ad_data;
- uint32_t hoff;
- uint32_t i;
-
- if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) {
- return true;
- }
-
- /* 2 bytes padding */
- hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2;
-
- h->adx_magic = RIVAL(p, hoff + 0);
- h->adx_debug_tag = RIVAL(p, hoff + 4); /* Not used -> not checked */
- h->adx_total_size = RIVAL(p, hoff + 8);
- h->adx_data_start = RIVAL(p, hoff + 12);
- h->adx_data_length = RIVAL(p, hoff + 16);
- h->adx_flags = RSVAL(p, hoff + 32); /* Not used -> not checked */
- h->adx_num_attrs = RSVAL(p, hoff + 34);
-
- if (h->adx_magic != AD_XATTR_HDR_MAGIC) {
- DBG_ERR("Bad magic: 0x%" PRIx32 "\n", h->adx_magic);
- return false;
- }
+ struct fruit_config_data *config;
+ int enumval = -1;
+ const char *tm_size_str = NULL;
- if (h->adx_total_size > ad_getentryoff(ad, ADEID_RFORK)) {
- DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
- return false;
- }
- if (h->adx_total_size > AD_XATTR_MAX_HDR_SIZE) {
- DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
- return false;
+ config = talloc_zero(handle->conn, struct fruit_config_data);
+ if (!config) {
+ DEBUG(1, ("talloc_zero() failed\n"));
+ errno = ENOMEM;
+ return -1;
}
- if (h->adx_data_start < (hoff + AD_XATTR_HDR_SIZE)) {
- DBG_ERR("Bad start: 0x%" PRIx32 "\n", h->adx_data_start);
- return false;
+ enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "resource", fruit_rsrc, FRUIT_RSRC_ADFILE);
+ if (enumval == -1) {
+ DEBUG(1, ("value for %s: resource type unknown\n",
+ FRUIT_PARAM_TYPE_NAME));
+ return -1;
}
+ config->rsrc = (enum fruit_rsrc)enumval;
- if ((h->adx_data_start + h->adx_data_length) < h->adx_data_start) {
- DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
- return false;
- }
- if ((h->adx_data_start + h->adx_data_length) >
- ad->adx_header.adx_total_size)
- {
- DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
- return false;
+ enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "metadata", fruit_meta, FRUIT_META_NETATALK);
+ if (enumval == -1) {
+ DEBUG(1, ("value for %s: metadata type unknown\n",
+ FRUIT_PARAM_TYPE_NAME));
+ return -1;
}
+ config->meta = (enum fruit_meta)enumval;
- if (h->adx_num_attrs > AD_XATTR_MAX_ENTRIES) {
- DBG_ERR("Bad num xattrs: %" PRIu16 "\n", h->adx_num_attrs);
- return false;
+ enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "locking", fruit_locking, FRUIT_LOCKING_NONE);
+ if (enumval == -1) {
+ DEBUG(1, ("value for %s: locking type unknown\n",
+ FRUIT_PARAM_TYPE_NAME));
+ return -1;
}
+ config->locking = (enum fruit_locking)enumval;
- if (h->adx_num_attrs == 0) {
- return true;
+ enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "encoding", fruit_encoding, FRUIT_ENC_PRIVATE);
+ if (enumval == -1) {
+ DEBUG(1, ("value for %s: encoding type unknown\n",
+ FRUIT_PARAM_TYPE_NAME));
+ return -1;
}
+ config->encoding = (enum fruit_encoding)enumval;
- ad->adx_entries = talloc_zero_array(
- ad, struct ad_xattr_entry, h->adx_num_attrs);
- if (ad->adx_entries == NULL) {
- return false;
+ if (config->rsrc == FRUIT_RSRC_ADFILE) {
+ config->veto_appledouble = lp_parm_bool(SNUM(handle->conn),
+ FRUIT_PARAM_TYPE_NAME,
+ "veto_appledouble",
+ true);
}
- hoff += AD_XATTR_HDR_SIZE;
-
- for (i = 0; i < h->adx_num_attrs; i++) {
- struct ad_xattr_entry *e = &ad->adx_entries[i];
-
- hoff = (hoff + 3) & ~3;
-
- e->adx_offset = RIVAL(p, hoff + 0);
- e->adx_length = RIVAL(p, hoff + 4);
- e->adx_flags = RSVAL(p, hoff + 8);
- e->adx_namelen = *(p + hoff + 10);
-
- if (e->adx_offset >= ad->adx_header.adx_total_size) {
- DBG_ERR("Bad adx_offset: %" PRIx32 "\n",
- e->adx_offset);
- return false;
- }
-
- if ((e->adx_offset + e->adx_length) < e->adx_offset) {
- DBG_ERR("Bad adx_length: %" PRIx32 "\n",
- e->adx_length);
- return false;
- }
-
- if ((e->adx_offset + e->adx_length) >
- ad->adx_header.adx_total_size)
- {
- DBG_ERR("Bad adx_length: %" PRIx32 "\n",
- e->adx_length);
- return false;
- }
+ config->use_aapl = lp_parm_bool(
+ -1, FRUIT_PARAM_TYPE_NAME, "aapl", true);
- if (e->adx_namelen == 0) {
- DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
- e->adx_namelen);
- return false;
- }
- if ((hoff + 11 + e->adx_namelen) < hoff + 11) {
- DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
- e->adx_namelen);
- return false;
- }
- if ((hoff + 11 + e->adx_namelen) >
- ad->adx_header.adx_data_start)
- {
- DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
- e->adx_namelen);
- return false;
- }
+ config->time_machine = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "time machine", false);
- e->adx_name = talloc_strndup(ad->adx_entries,
- p + hoff + 11,
- e->adx_namelen);
- if (e->adx_name == NULL) {
- return false;
- }
+ config->unix_info_enabled = lp_parm_bool(
+ -1, FRUIT_PARAM_TYPE_NAME, "nfs_aces", true);
- DBG_DEBUG("xattr [%s] offset [0x%x] size [0x%x]\n",
- e->adx_name, e->adx_offset, e->adx_length);
- dump_data(10, (uint8_t *)(ad->ad_data + e->adx_offset),
- e->adx_length);
+ config->use_copyfile = lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME,
+ "copyfile", false);
- hoff += 11 + e->adx_namelen;
- }
+ config->posix_rename = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "posix_rename", true);
- return true;
-}
+ config->aapl_zero_file_id =
+ lp_parm_bool(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "zero_file_id", true);
-/**
- * Unpack an AppleDouble blob into a struct adoble
- **/
-static bool ad_unpack(struct adouble *ad, const size_t nentries,
- size_t filesize)
-{
- size_t bufsize = talloc_get_size(ad->ad_data);
- size_t adentries, i;
- uint32_t eid, len, off;
- bool ok;
-
- /*
- * The size of the buffer ad->ad_data is checked when read, so
- * we wouldn't have to check our own offsets, a few extra
- * checks won't hurt though. We have to check the offsets we
- * read from the buffer anyway.
- */
-
- if (bufsize < (AD_HEADER_LEN + (AD_ENTRY_LEN * nentries))) {
- DEBUG(1, ("bad size\n"));
- return false;
- }
-
- ad->ad_magic = RIVAL(ad->ad_data, 0);
- ad->ad_version = RIVAL(ad->ad_data, ADEDOFF_VERSION);
- if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION)) {
- DEBUG(1, ("wrong magic or version\n"));
- return false;
- }
-
- memcpy(ad->ad_filler, ad->ad_data + ADEDOFF_FILLER, ADEDLEN_FILLER);
-
- adentries = RSVAL(ad->ad_data, ADEDOFF_NENTRIES);
- if (adentries != nentries) {
- DEBUG(1, ("invalid number of entries: %zu\n",
- adentries));
- return false;
- }
-
- /* now, read in the entry bits */
- for (i = 0; i < adentries; i++) {
- eid = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN));
- eid = get_eid(eid);
- off = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 4);
- len = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 8);
-
- if (!eid || eid >= ADEID_MAX) {
- DEBUG(1, ("bogus eid %d\n", eid));
- return false;
- }
-
- /*
- * All entries other than the resource fork are
- * expected to be read into the ad_data buffer, so
- * ensure the specified offset is within that bound
- */
- if ((off > bufsize) && (eid != ADEID_RFORK)) {
- DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
- eid, off, len));
- return false;
- }
-
- /*
- * All entries besides FinderInfo and resource fork
- * must fit into the buffer. FinderInfo is special as
- * it may be larger then the default 32 bytes (if it
- * contains marshalled xattrs), but we will fixup that
- * in ad_convert(). And the resource fork is never
- * accessed directly by the ad_data buf (also see
- * comment above) anyway.
- */
- if ((eid != ADEID_RFORK) &&
- (eid != ADEID_FINDERI) &&
- ((off + len) > bufsize)) {
- DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
- eid, off, len));
- return false;
- }
-
- /*
- * That would be obviously broken
- */
- if (off > filesize) {
- DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
- eid, off, len));
- return false;
- }
-
- /*
- * Check for any entry that has its end beyond the
- * filesize.
- */
- if (off + len < off) {
- DEBUG(1, ("offset wrap in eid %d: off: %" PRIu32
- ", len: %" PRIu32 "\n",
- eid, off, len));
- return false;
-
- }
- if (off + len > filesize) {
- /*
- * If this is the resource fork entry, we fix
- * up the length, for any other entry we bail
- * out.
- */
- if (eid != ADEID_RFORK) {
- DEBUG(1, ("bogus eid %d: off: %" PRIu32
- ", len: %" PRIu32 "\n",
- eid, off, len));
- return false;
- }
-
- /*
- * Fixup the resource fork entry by limiting
- * the size to entryoffset - filesize.
- */
- len = filesize - off;
- DEBUG(1, ("Limiting ADEID_RFORK: off: %" PRIu32
- ", len: %" PRIu32 "\n", off, len));
- }
-
- ad->ad_eid[eid].ade_off = off;
- ad->ad_eid[eid].ade_len = len;
- }
-
- ok = ad_unpack_xattrs(ad);
- if (!ok) {
- return false;
- }
-
- return true;
-}
-
-static bool ad_convert_move_reso(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- char *map = MAP_FAILED;
- size_t maplen;
- ssize_t len;
- int rc;
- bool ok;
-
- if (ad_getentrylen(ad, ADEID_RFORK) == 0) {
- return true;
- }
-
- maplen = ad_getentryoff(ad, ADEID_RFORK) +
- ad_getentrylen(ad, ADEID_RFORK);
-
- /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
- map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
- ad->ad_fd, 0);
- if (map == MAP_FAILED) {
- DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
- return false;
- }
-
-
- memmove(map + ADEDOFF_RFORK_DOT_UND,
- map + ad_getentryoff(ad, ADEID_RFORK),
- ad_getentrylen(ad, ADEID_RFORK));
-
- rc = munmap(map, maplen);
- if (rc != 0) {
- DBG_ERR("munmap failed: %s\n", strerror(errno));
- return false;
- }
-
- ad_setentryoff(ad, ADEID_RFORK, ADEDOFF_RFORK_DOT_UND);
-
- ok = ad_pack(ad);
- if (!ok) {
- DBG_WARNING("ad_pack [%s] failed\n", smb_fname->base_name);
- return false;
- }
-
- len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
- if (len != AD_DATASZ_DOT_UND) {
- DBG_ERR("%s: bad size: %zd\n", smb_fname->base_name, len);
- return false;
- }
-
- return true;
-}
-
-static bool ad_convert_xattr(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname,
- bool *converted_xattr)
-{
- static struct char_mappings **string_replace_cmaps = NULL;
- char *map = MAP_FAILED;
- size_t maplen;
- uint16_t i;
- ssize_t len;
- int saved_errno = 0;
- NTSTATUS status;
- int rc;
- bool ok;
-
- *converted_xattr = false;
-
- if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
- return true;
- }
-
- if (string_replace_cmaps == NULL) {
- const char **mappings = NULL;
-
- mappings = str_list_make_v3_const(
- talloc_tos(), fruit_catia_maps, NULL);
- if (mappings == NULL) {
- return false;
- }
- string_replace_cmaps = string_replace_init_map(mappings);
- TALLOC_FREE(mappings);
- }
-
- maplen = ad_getentryoff(ad, ADEID_RFORK) +
- ad_getentrylen(ad, ADEID_RFORK);
-
- /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
- map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
- ad->ad_fd, 0);
- if (map == MAP_FAILED) {
- DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
- return false;
- }
-
- for (i = 0; i < ad->adx_header.adx_num_attrs; i++) {
- struct ad_xattr_entry *e = &ad->adx_entries[i];
- char *mapped_name = NULL;
- char *tmp = NULL;
- struct smb_filename *stream_name = NULL;
- files_struct *fsp = NULL;
- ssize_t nwritten;
-
- status = string_replace_allocate(handle->conn,
- e->adx_name,
- string_replace_cmaps,
- talloc_tos(),
- &mapped_name,
- vfs_translate_to_windows);
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
- {
- DBG_ERR("string_replace_allocate failed\n");
- ok = false;
- goto fail;
- }
-
- tmp = mapped_name;
- mapped_name = talloc_asprintf(talloc_tos(), ":%s", tmp);
- TALLOC_FREE(tmp);
- if (mapped_name == NULL) {
- ok = false;
- goto fail;
- }
-
- stream_name = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- mapped_name,
- NULL,
- smb_fname->flags);
- TALLOC_FREE(mapped_name);
- if (stream_name == NULL) {
- DBG_ERR("synthetic_smb_fname failed\n");
- ok = false;
- goto fail;
- }
-
- DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
-
- status = SMB_VFS_CREATE_FILE(
- handle->conn, /* conn */
- NULL, /* req */
- 0, /* root_dir_fid */
- stream_name, /* fname */
- FILE_GENERIC_WRITE, /* access_mask */
- FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
- FILE_OPEN_IF, /* create_disposition */
- 0, /* create_options */
- 0, /* file_attributes */
- INTERNAL_OPEN_ONLY, /* oplock_request */
- NULL, /* lease */
- 0, /* allocation_size */
- 0, /* private_flags */
- NULL, /* sd */
- NULL, /* ea_list */
- &fsp, /* result */
- NULL, /* psbuf */
- NULL, NULL); /* create context */
- TALLOC_FREE(stream_name);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
- ok = false;
- goto fail;
- }
-
- nwritten = SMB_VFS_PWRITE(fsp,
- map + e->adx_offset,
- e->adx_length,
- 0);
- if (nwritten == -1) {
- DBG_ERR("SMB_VFS_PWRITE failed\n");
- saved_errno = errno;
- close_file(NULL, fsp, ERROR_CLOSE);
- errno = saved_errno;
- ok = false;
- goto fail;
- }
-
- status = close_file(NULL, fsp, NORMAL_CLOSE);
- if (!NT_STATUS_IS_OK(status)) {
- ok = false;
- goto fail;
- }
- fsp = NULL;
- }
-
- ad_setentrylen(ad, ADEID_FINDERI, ADEDLEN_FINDERI);
-
- ok = ad_pack(ad);
- if (!ok) {
- DBG_WARNING("ad_pack [%s] failed\n", smb_fname->base_name);
- goto fail;
- }
-
- len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
- if (len != AD_DATASZ_DOT_UND) {
- DBG_ERR("%s: bad size: %zd\n", smb_fname->base_name, len);
- ok = false;
- goto fail;
- }
-
- ok = ad_convert_move_reso(handle, ad, smb_fname);
- if (!ok) {
- goto fail;
- }
-
- *converted_xattr = true;
- ok = true;
-
-fail:
- rc = munmap(map, maplen);
- if (rc != 0) {
- DBG_ERR("munmap failed: %s\n", strerror(errno));
- return false;
- }
-
- return ok;
-}
-
-static bool ad_convert_finderinfo(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- char *p_ad = NULL;
- AfpInfo *ai = NULL;
- DATA_BLOB aiblob;
- struct smb_filename *stream_name = NULL;
- files_struct *fsp = NULL;
- size_t size;
- ssize_t nwritten;
- NTSTATUS status;
- int saved_errno = 0;
- int cmp;
-
- cmp = memcmp(ad->ad_filler, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
- if (cmp != 0) {
- return true;
- }
-
- p_ad = ad_get_entry(ad, ADEID_FINDERI);
- if (p_ad == NULL) {
- return false;
- }
-
- ai = afpinfo_new(talloc_tos());
- if (ai == NULL) {
- return false;
- }
-
- memcpy(ai->afpi_FinderInfo, p_ad, ADEDLEN_FINDERI);
-
- aiblob = data_blob_talloc(talloc_tos(), NULL, AFP_INFO_SIZE);
- if (aiblob.data == NULL) {
- TALLOC_FREE(ai);
- return false;
- }
-
- size = afpinfo_pack(ai, (char *)aiblob.data);
- TALLOC_FREE(ai);
- if (size != AFP_INFO_SIZE) {
- return false;
- }
-
- stream_name = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- AFPINFO_STREAM,
- NULL,
- smb_fname->flags);
- if (stream_name == NULL) {
- data_blob_free(&aiblob);
- DBG_ERR("synthetic_smb_fname failed\n");
- return false;
- }
-
- DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
-
- status = SMB_VFS_CREATE_FILE(
- handle->conn, /* conn */
- NULL, /* req */
- 0, /* root_dir_fid */
- stream_name, /* fname */
- FILE_GENERIC_WRITE, /* access_mask */
- FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
- FILE_OPEN_IF, /* create_disposition */
- 0, /* create_options */
- 0, /* file_attributes */
- INTERNAL_OPEN_ONLY, /* oplock_request */
- NULL, /* lease */
- 0, /* allocation_size */
- 0, /* private_flags */
- NULL, /* sd */
- NULL, /* ea_list */
- &fsp, /* result */
- NULL, /* psbuf */
- NULL, NULL); /* create context */
- TALLOC_FREE(stream_name);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
- return false;
- }
-
- nwritten = SMB_VFS_PWRITE(fsp,
- aiblob.data,
- aiblob.length,
- 0);
- if (nwritten == -1) {
- DBG_ERR("SMB_VFS_PWRITE failed\n");
- saved_errno = errno;
- close_file(NULL, fsp, ERROR_CLOSE);
- errno = saved_errno;
- return false;
- }
-
- status = close_file(NULL, fsp, NORMAL_CLOSE);
- if (!NT_STATUS_IS_OK(status)) {
- return false;
- }
- fsp = NULL;
-
- return true;
-}
-
-static bool ad_convert_truncate(struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- int rc;
-
- /*
- * FIXME: direct ftruncate(), but we don't have a fsp for the
- * VFS call
- */
- rc = ftruncate(ad->ad_fd, ADEDOFF_RFORK_DOT_UND +
- ad_getentrylen(ad, ADEID_RFORK));
- if (rc != 0) {
- return false;
- }
-
- return true;
-}
-
-static bool ad_convert_blank_rfork(vfs_handle_struct *handle,
- struct adouble *ad,
- bool *blank)
-{
- struct fruit_config_data *config = NULL;
- uint8_t *map = MAP_FAILED;
- size_t maplen;
- int cmp;
- ssize_t len;
- int rc;
- bool ok;
-
- *blank = false;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct fruit_config_data, return false);
-
- if (!config->wipe_intentionally_left_blank_rfork) {
- return true;
- }
-
- if (ad_getentrylen(ad, ADEID_RFORK) != sizeof(empty_resourcefork)) {
- return true;
- }
-
- maplen = ad_getentryoff(ad, ADEID_RFORK) +
- ad_getentrylen(ad, ADEID_RFORK);
-
- /* FIXME: direct use of mmap(), vfs_aio_fork does it too */
- map = mmap(NULL, maplen, PROT_READ|PROT_WRITE, MAP_SHARED,
- ad->ad_fd, 0);
- if (map == MAP_FAILED) {
- DBG_ERR("mmap AppleDouble: %s\n", strerror(errno));
- return false;
- }
-
- cmp = memcmp(map + ADEDOFF_RFORK_DOT_UND,
- empty_resourcefork,
- sizeof(empty_resourcefork));
- rc = munmap(map, maplen);
- if (rc != 0) {
- DBG_ERR("munmap failed: %s\n", strerror(errno));
- return false;
- }
-
- if (cmp != 0) {
- return true;
- }
-
- ad_setentrylen(ad, ADEID_RFORK, 0);
-
- ok = ad_pack(ad);
- if (!ok) {
- return false;
- }
-
- len = sys_pwrite(ad->ad_fd, ad->ad_data, AD_DATASZ_DOT_UND, 0);
- if (len != AD_DATASZ_DOT_UND) {
- return false;
- }
-
- *blank = true;
- return true;
-}
-
-static bool ad_convert_delete_adfile(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- struct fruit_config_data *config = NULL;
- struct smb_filename *ad_name = NULL;
- int rc;
-
- if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
- return true;
- }
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct fruit_config_data, return false);
-
- if (!config->delete_empty_adfiles) {
- return true;
- }
-
- rc = adouble_path(talloc_tos(), smb_fname, &ad_name);
- if (rc != 0) {
- return false;
- }
-
- rc = SMB_VFS_NEXT_UNLINK(handle, ad_name);
- if (rc != 0) {
- DBG_ERR("Unlinking [%s] failed: %s\n",
- smb_fname_str_dbg(ad_name), strerror(errno));
- TALLOC_FREE(ad_name);
- return false;
- }
-
- DBG_WARNING("Unlinked [%s] after conversion\n", smb_fname_str_dbg(ad_name));
- TALLOC_FREE(ad_name);
-
- return true;
-}
-
-/**
- * Convert from Apple's ._ file to Netatalk
- *
- * Apple's AppleDouble may contain a FinderInfo entry longer then 32
- * bytes containing packed xattrs.
- *
- * @return -1 in case an error occurred, 0 if no conversion was done, 1
- * otherwise
- **/
-static int ad_convert(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
-{
- struct adouble *ad = NULL;
- bool ok;
- bool converted_xattr = false;
- bool blank;
- int ret;
-
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
- if (ad == NULL) {
- return 0;
- }
-
- ok = ad_convert_xattr(handle, ad, smb_fname, &converted_xattr);
- if (!ok) {
- ret = -1;
- goto done;
- }
-
- ok = ad_convert_blank_rfork(handle, ad, &blank);
- if (!ok) {
- ret = -1;
- goto done;
- }
-
- if (converted_xattr || blank) {
- ok = ad_convert_truncate(ad, smb_fname);
- if (!ok) {
- ret = -1;
- goto done;
- }
- }
-
- ok = ad_convert_finderinfo(handle, ad, smb_fname);
- if (!ok) {
- DBG_ERR("Failed to convert [%s]\n",
- smb_fname_str_dbg(smb_fname));
- ret = -1;
- goto done;
- }
-
- ok = ad_convert_delete_adfile(handle, ad, smb_fname);
- if (!ok) {
- ret = -1;
- goto done;
- }
-
- ret = 0;
-done:
- TALLOC_FREE(ad);
- return ret;
-}
-
-/**
- * Read and parse Netatalk AppleDouble metadata xattr
- **/
-static ssize_t ad_read_meta(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- int rc = 0;
- ssize_t ealen;
- bool ok;
-
- DEBUG(10, ("reading meta xattr for %s\n", smb_fname->base_name));
-
- ealen = SMB_VFS_GETXATTR(handle->conn, smb_fname,
- AFPINFO_EA_NETATALK, ad->ad_data,
- AD_DATASZ_XATTR);
- if (ealen == -1) {
- switch (errno) {
- case ENOATTR:
- case ENOENT:
- if (errno == ENOATTR) {
- errno = ENOENT;
- }
- rc = -1;
- goto exit;
- default:
- DEBUG(2, ("error reading meta xattr: %s\n",
- strerror(errno)));
- rc = -1;
- goto exit;
- }
- }
- if (ealen != AD_DATASZ_XATTR) {
- DEBUG(2, ("bad size %zd\n", ealen));
- errno = EINVAL;
- rc = -1;
- goto exit;
- }
-
- /* Now parse entries */
- ok = ad_unpack(ad, ADEID_NUM_XATTR, AD_DATASZ_XATTR);
- if (!ok) {
- DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
- errno = EINVAL;
- rc = -1;
- goto exit;
- }
-
- if (!ad_getentryoff(ad, ADEID_FINDERI)
- || !ad_getentryoff(ad, ADEID_COMMENT)
- || !ad_getentryoff(ad, ADEID_FILEDATESI)
- || !ad_getentryoff(ad, ADEID_AFPFILEI)
- || !ad_getentryoff(ad, ADEID_PRIVDEV)
- || !ad_getentryoff(ad, ADEID_PRIVINO)
- || !ad_getentryoff(ad, ADEID_PRIVSYN)
- || !ad_getentryoff(ad, ADEID_PRIVID)) {
- DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
- errno = EINVAL;
- rc = -1;
- goto exit;
- }
-
-exit:
- DEBUG(10, ("reading meta xattr for %s, rc: %d\n",
- smb_fname->base_name, rc));
-
- if (rc != 0) {
- ealen = -1;
- if (errno == EINVAL) {
- become_root();
- (void)SMB_VFS_REMOVEXATTR(handle->conn,
- smb_fname,
- AFPINFO_EA_NETATALK);
- unbecome_root();
- errno = ENOENT;
- }
- }
- return ealen;
-}
-
-static int ad_open_rsrc(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- int flags,
- mode_t mode)
-{
- int ret;
- int fd;
- struct smb_filename *adp_smb_fname = NULL;
-
- ret = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
- if (ret != 0) {
- return -1;
- }
-
- fd = open(adp_smb_fname->base_name, flags, mode);
- TALLOC_FREE(adp_smb_fname);
-
- return fd;
-}
-
-/*
- * Here's the deal: for ADOUBLE_META we can do without an fd as we can issue
- * path based xattr calls. For ADOUBLE_RSRC however we need a full-fledged fd
- * for file IO on the ._ file.
- */
-static int ad_open(vfs_handle_struct *handle,
- struct adouble *ad,
- files_struct *fsp,
- const struct smb_filename *smb_fname,
- int flags,
- mode_t mode)
-{
- int fd;
-
- DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name,
- ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
-
- if (ad->ad_type == ADOUBLE_META) {
- return 0;
- }
-
- if ((fsp != NULL) && (fsp->fh != NULL) && (fsp->fh->fd != -1)) {
- ad->ad_fd = fsp->fh->fd;
- ad->ad_opened = false;
- return 0;
- }
-
- fd = ad_open_rsrc(handle, smb_fname, flags, mode);
- if (fd == -1) {
- return -1;
- }
- ad->ad_opened = true;
- ad->ad_fd = fd;
-
- DBG_DEBUG("Path [%s] type [%s] fd [%d]\n",
- smb_fname->base_name,
- ad->ad_type == ADOUBLE_META ? "meta" : "rsrc", fd);
-
- return 0;
-}
-
-static ssize_t ad_read_rsrc_adouble(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- SMB_STRUCT_STAT sbuf;
- char *p_ad = NULL;
- size_t size;
- ssize_t len;
- int ret;
- bool ok;
-
- ret = sys_fstat(ad->ad_fd, &sbuf, lp_fake_directory_create_times(
- SNUM(handle->conn)));
- if (ret != 0) {
- return -1;
- }
-
- /*
- * AppleDouble file header content and size, two cases:
- *
- * - without xattrs it is exactly AD_DATASZ_DOT_UND (82) bytes large
- * - with embedded xattrs it can be larger, up to AD_XATTR_MAX_HDR_SIZE
- *
- * Read as much as we can up to AD_XATTR_MAX_HDR_SIZE.
- */
- size = sbuf.st_ex_size;
- if (size > talloc_array_length(ad->ad_data)) {
- if (size > AD_XATTR_MAX_HDR_SIZE) {
- size = AD_XATTR_MAX_HDR_SIZE;
- }
- p_ad = talloc_realloc(ad, ad->ad_data, char, size);
- if (p_ad == NULL) {
- return -1;
- }
- ad->ad_data = p_ad;
- }
-
- len = sys_pread(ad->ad_fd, ad->ad_data,
- talloc_array_length(ad->ad_data), 0);
- if (len != talloc_array_length(ad->ad_data)) {
- DBG_NOTICE("%s %s: bad size: %zd\n",
- smb_fname->base_name, strerror(errno), len);
- return -1;
- }
-
- /* Now parse entries */
- ok = ad_unpack(ad, ADEID_NUM_DOT_UND, sbuf.st_ex_size);
- if (!ok) {
- DBG_ERR("invalid AppleDouble resource %s\n",
- smb_fname->base_name);
- errno = EINVAL;
- return -1;
- }
-
- if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
- || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
- || (ad_getentryoff(ad, ADEID_RFORK) < ADEDOFF_RFORK_DOT_UND)) {
- DBG_ERR("invalid AppleDouble resource %s\n",
- smb_fname->base_name);
- errno = EINVAL;
- return -1;
- }
-
- return len;
-}
-
-/**
- * Read and parse resource fork, either ._ AppleDouble file or xattr
- **/
-static ssize_t ad_read_rsrc(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- return ad_read_rsrc_adouble(handle, ad, smb_fname);
-}
-
-/**
- * Read and unpack an AppleDouble metadata xattr or resource
- **/
-static ssize_t ad_read(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- switch (ad->ad_type) {
- case ADOUBLE_META:
- return ad_read_meta(handle, ad, smb_fname);
- case ADOUBLE_RSRC:
- return ad_read_rsrc(handle, ad, smb_fname);
- default:
- return -1;
- }
-}
-
-static int adouble_destructor(struct adouble *ad)
-{
- if ((ad->ad_fd != -1) && ad->ad_opened) {
- close(ad->ad_fd);
- ad->ad_fd = -1;
- }
- return 0;
-}
-
-/**
- * Allocate a struct adouble without initialiing it
- *
- * The struct is either hang of the fsp extension context or if fsp is
- * NULL from ctx.
- *
- * @param[in] ctx talloc context
- * @param[in] handle vfs handle
- * @param[in] type type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
- *
- * @return adouble handle
- **/
-static struct adouble *ad_alloc(TALLOC_CTX *ctx,
- adouble_type_t type)
-{
- int rc = 0;
- size_t adsize = 0;
- struct adouble *ad;
-
- switch (type) {
- case ADOUBLE_META:
- adsize = AD_DATASZ_XATTR;
- break;
- case ADOUBLE_RSRC:
- adsize = AD_DATASZ_DOT_UND;
- break;
- default:
- return NULL;
- }
-
- ad = talloc_zero(ctx, struct adouble);
- if (ad == NULL) {
- rc = -1;
- goto exit;
- }
-
- if (adsize) {
- ad->ad_data = talloc_zero_array(ad, char, adsize);
- if (ad->ad_data == NULL) {
- rc = -1;
- goto exit;
- }
- }
-
- ad->ad_type = type;
- ad->ad_magic = AD_MAGIC;
- ad->ad_version = AD_VERSION;
- ad->ad_fd = -1;
-
- talloc_set_destructor(ad, adouble_destructor);
-
-exit:
- if (rc != 0) {
- TALLOC_FREE(ad);
- }
- return ad;
-}
-
-/**
- * Allocate and initialize a new struct adouble
- *
- * @param[in] ctx talloc context
- * @param[in] type type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
- *
- * @return adouble handle, initialized
- **/
-static struct adouble *ad_init(TALLOC_CTX *ctx,
- adouble_type_t type)
-{
- int rc = 0;
- const struct ad_entry_order *eid;
- struct adouble *ad = NULL;
- time_t t = time(NULL);
-
- switch (type) {
- case ADOUBLE_META:
- eid = entry_order_meta_xattr;
- break;
- case ADOUBLE_RSRC:
- eid = entry_order_dot_und;
- break;
- default:
- return NULL;
- }
-
- ad = ad_alloc(ctx, type);
- if (ad == NULL) {
- return NULL;
- }
-
- while (eid->id) {
- ad->ad_eid[eid->id].ade_off = eid->offset;
- ad->ad_eid[eid->id].ade_len = eid->len;
- eid++;
- }
-
- /* put something sane in the date fields */
- ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, t);
- ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, t);
- ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, t);
- ad_setdate(ad, AD_DATE_BACKUP, htonl(AD_DATE_START));
-
- if (rc != 0) {
- TALLOC_FREE(ad);
- }
- return ad;
-}
-
-static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
- vfs_handle_struct *handle,
- files_struct *fsp,
- const struct smb_filename *smb_fname,
- adouble_type_t type)
-{
- int rc = 0;
- ssize_t len;
- struct adouble *ad = NULL;
- int mode;
-
- if (fsp != NULL) {
- smb_fname = fsp->base_fsp->fsp_name;
- }
-
- DEBUG(10, ("ad_get(%s) called for %s\n",
- type == ADOUBLE_META ? "meta" : "rsrc",
- smb_fname->base_name));
-
- ad = ad_alloc(ctx, type);
- if (ad == NULL) {
- rc = -1;
- goto exit;
- }
-
- /* Try rw first so we can use the fd in ad_convert() */
- mode = O_RDWR;
-
- rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
- if (rc == -1 && ((errno == EROFS) || (errno == EACCES))) {
- mode = O_RDONLY;
- rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
- }
- if (rc == -1) {
- DBG_DEBUG("ad_open [%s] error [%s]\n",
- smb_fname->base_name, strerror(errno));
- goto exit;
-
- }
-
- len = ad_read(handle, ad, smb_fname);
- if (len == -1) {
- DEBUG(10, ("error reading AppleDouble for %s\n",
- smb_fname->base_name));
- rc = -1;
- goto exit;
- }
-
-exit:
- DEBUG(10, ("ad_get(%s) for %s returning %d\n",
- type == ADOUBLE_META ? "meta" : "rsrc",
- smb_fname->base_name, rc));
-
- if (rc != 0) {
- TALLOC_FREE(ad);
- }
- return ad;
-}
-
-/**
- * Return AppleDouble data for a file
- *
- * @param[in] ctx talloc context
- * @param[in] handle vfs handle
- * @param[in] smb_fname pathname to file or directory
- * @param[in] type type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
- *
- * @return talloced struct adouble or NULL on error
- **/
-static struct adouble *ad_get(TALLOC_CTX *ctx,
- vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- adouble_type_t type)
-{
- return ad_get_internal(ctx, handle, NULL, smb_fname, type);
-}
-
-/**
- * Return AppleDouble data for a file
- *
- * @param[in] ctx talloc context
- * @param[in] handle vfs handle
- * @param[in] fsp fsp to use for IO
- * @param[in] type type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
- *
- * @return talloced struct adouble or NULL on error
- **/
-static struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
- files_struct *fsp, adouble_type_t type)
-{
- return ad_get_internal(ctx, handle, fsp, NULL, type);
-}
-
-/**
- * Set AppleDouble metadata on a file or directory
- *
- * @param[in] ad adouble handle
- *
- * @param[in] smb_fname pathname to file or directory
- *
- * @return status code, 0 means success
- **/
-static int ad_set(vfs_handle_struct *handle,
- struct adouble *ad,
- const struct smb_filename *smb_fname)
-{
- bool ok;
- int ret;
-
- DBG_DEBUG("Path [%s]\n", smb_fname->base_name);
-
- if (ad->ad_type != ADOUBLE_META) {
- DBG_ERR("ad_set on [%s] used with ADOUBLE_RSRC\n",
- smb_fname->base_name);
- return -1;
- }
-
- ok = ad_pack(ad);
- if (!ok) {
- return -1;
- }
-
- ret = SMB_VFS_SETXATTR(handle->conn,
- smb_fname,
- AFPINFO_EA_NETATALK,
- ad->ad_data,
- AD_DATASZ_XATTR, 0);
-
- DBG_DEBUG("Path [%s] ret [%d]\n", smb_fname->base_name, ret);
-
- return ret;
-}
-
-/**
- * Set AppleDouble metadata on a file or directory
- *
- * @param[in] ad adouble handle
- * @param[in] fsp file handle
- *
- * @return status code, 0 means success
- **/
-static int ad_fset(struct vfs_handle_struct *handle,
- struct adouble *ad,
- files_struct *fsp)
-{
- int rc = -1;
- ssize_t len;
- bool ok;
-
- DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
-
- if ((fsp == NULL)
- || (fsp->fh == NULL)
- || (fsp->fh->fd == -1))
- {
- smb_panic("bad fsp");
- }
-
- ok = ad_pack(ad);
- if (!ok) {
- return -1;
- }
-
- switch (ad->ad_type) {
- case ADOUBLE_META:
- rc = SMB_VFS_NEXT_SETXATTR(handle,
- fsp->fsp_name,
- AFPINFO_EA_NETATALK,
- ad->ad_data,
- AD_DATASZ_XATTR, 0);
- break;
-
- case ADOUBLE_RSRC:
- len = SMB_VFS_NEXT_PWRITE(handle,
- fsp,
- ad->ad_data,
- AD_DATASZ_DOT_UND,
- 0);
- if (len != AD_DATASZ_DOT_UND) {
- DBG_ERR("short write on %s: %zd", fsp_str_dbg(fsp), len);
- return -1;
- }
- rc = 0;
- break;
-
- default:
- return -1;
- }
-
- DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
-
- return rc;
-}
-
-/*****************************************************************************
- * Helper functions
- *****************************************************************************/
-
-static bool is_afpinfo_stream(const struct smb_filename *smb_fname)
-{
- if (strncasecmp_m(smb_fname->stream_name,
- AFPINFO_STREAM_NAME,
- strlen(AFPINFO_STREAM_NAME)) == 0) {
- return true;
- }
- return false;
-}
-
-static bool is_afpresource_stream(const struct smb_filename *smb_fname)
-{
- if (strncasecmp_m(smb_fname->stream_name,
- AFPRESOURCE_STREAM_NAME,
- strlen(AFPRESOURCE_STREAM_NAME)) == 0) {
- return true;
- }
- return false;
-}
-
-/**
- * Test whether stream is an Apple stream.
- **/
-static bool is_apple_stream(const struct smb_filename *smb_fname)
-{
- if (is_afpinfo_stream(smb_fname)) {
- return true;
- }
- if (is_afpresource_stream(smb_fname)) {
- return true;
- }
- return false;
-}
-
-static bool is_adouble_file(const char *path)
-{
- const char *p = NULL;
- int match;
-
- p = strrchr(path, '/');
- if (p == NULL) {
- p = path;
- } else {
- p++;
- }
-
- match = strncmp(p,
- ADOUBLE_NAME_PREFIX,
- strlen(ADOUBLE_NAME_PREFIX));
- if (match != 0) {
- return false;
- }
- return true;
-}
-
-/**
- * Initialize config struct from our smb.conf config parameters
- **/
-static int init_fruit_config(vfs_handle_struct *handle)
-{
- struct fruit_config_data *config;
- int enumval;
- const char *tm_size_str = NULL;
-
- config = talloc_zero(handle->conn, struct fruit_config_data);
- if (!config) {
- DEBUG(1, ("talloc_zero() failed\n"));
- errno = ENOMEM;
- return -1;
- }
-
- /*
- * Versions up to Samba 4.5.x had a spelling bug in the
- * fruit:resource option calling lp_parm_enum with
- * "res*s*ource" (ie two s).
- *
- * In Samba 4.6 we accept both the wrong and the correct
- * spelling, in Samba 4.7 the bad spelling will be removed.
- */
- enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "ressource", fruit_rsrc, FRUIT_RSRC_ADFILE);
- if (enumval == -1) {
- DEBUG(1, ("value for %s: resource type unknown\n",
- FRUIT_PARAM_TYPE_NAME));
- return -1;
- }
- config->rsrc = (enum fruit_rsrc)enumval;
-
- enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "resource", fruit_rsrc, enumval);
- if (enumval == -1) {
- DEBUG(1, ("value for %s: resource type unknown\n",
- FRUIT_PARAM_TYPE_NAME));
- return -1;
- }
- config->rsrc = (enum fruit_rsrc)enumval;
-
- enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "metadata", fruit_meta, FRUIT_META_NETATALK);
- if (enumval == -1) {
- DEBUG(1, ("value for %s: metadata type unknown\n",
- FRUIT_PARAM_TYPE_NAME));
- return -1;
- }
- config->meta = (enum fruit_meta)enumval;
-
- enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "locking", fruit_locking, FRUIT_LOCKING_NONE);
- if (enumval == -1) {
- DEBUG(1, ("value for %s: locking type unknown\n",
- FRUIT_PARAM_TYPE_NAME));
- return -1;
- }
- config->locking = (enum fruit_locking)enumval;
-
- enumval = lp_parm_enum(SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "encoding", fruit_encoding, FRUIT_ENC_PRIVATE);
- if (enumval == -1) {
- DEBUG(1, ("value for %s: encoding type unknown\n",
- FRUIT_PARAM_TYPE_NAME));
- return -1;
- }
- config->encoding = (enum fruit_encoding)enumval;
-
- if (config->rsrc == FRUIT_RSRC_ADFILE) {
- config->veto_appledouble = lp_parm_bool(SNUM(handle->conn),
- FRUIT_PARAM_TYPE_NAME,
- "veto_appledouble",
- true);
- }
-
- config->use_aapl = lp_parm_bool(
- -1, FRUIT_PARAM_TYPE_NAME, "aapl", true);
-
- config->time_machine = lp_parm_bool(
- SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "time machine", false);
-
- config->unix_info_enabled = lp_parm_bool(
- -1, FRUIT_PARAM_TYPE_NAME, "nfs_aces", true);
-
- config->use_copyfile = lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME,
- "copyfile", false);
-
- config->posix_rename = lp_parm_bool(
- SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME, "posix_rename", true);
-
- config->aapl_zero_file_id =
- lp_parm_bool(-1, FRUIT_PARAM_TYPE_NAME, "zero_file_id", true);
-
- config->readdir_attr_rsize = lp_parm_bool(
- SNUM(handle->conn), "readdir_attr", "aapl_rsize", true);
-
- config->readdir_attr_finder_info = lp_parm_bool(
- SNUM(handle->conn), "readdir_attr", "aapl_finder_info", true);
-
- config->readdir_attr_max_access = lp_parm_bool(
- SNUM(handle->conn), "readdir_attr", "aapl_max_access", true);
-
- config->model = lp_parm_const_string(
- -1, FRUIT_PARAM_TYPE_NAME, "model", "MacSamba");
-
- tm_size_str = lp_parm_const_string(
- SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "time machine max size", NULL);
- if (tm_size_str != NULL) {
- config->time_machine_max_size = conv_str_size(tm_size_str);
- }
-
- config->wipe_intentionally_left_blank_rfork = lp_parm_bool(
- SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "wipe_intentionally_left_blank_rfork", false);
-
- config->delete_empty_adfiles = lp_parm_bool(
- SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
- "delete_empty_adfiles", false);
-
- SMB_VFS_HANDLE_SET_DATA(handle, config,
- NULL, struct fruit_config_data,
- return -1);
-
- return 0;
-}
-
-/**
- * Prepend "._" to a basename
- * Return a new struct smb_filename with stream_name == NULL.
- **/
-static int adouble_path(TALLOC_CTX *ctx,
- const struct smb_filename *smb_fname_in,
- struct smb_filename **pp_smb_fname_out)
-{
- char *parent;
- const char *base;
- struct smb_filename *smb_fname = cp_smb_filename(ctx,
- smb_fname_in);
-
- if (smb_fname == NULL) {
- return -1;
- }
-
- /* We need streamname to be NULL */
- TALLOC_FREE(smb_fname->stream_name);
-
- /* And we're replacing base_name. */
- TALLOC_FREE(smb_fname->base_name);
-
- if (!parent_dirname(smb_fname, smb_fname_in->base_name,
- &parent, &base)) {
- TALLOC_FREE(smb_fname);
- return -1;
- }
-
- smb_fname->base_name = talloc_asprintf(smb_fname,
- "%s/._%s", parent, base);
- if (smb_fname->base_name == NULL) {
- TALLOC_FREE(smb_fname);
- return -1;
- }
-
- *pp_smb_fname_out = smb_fname;
-
- return 0;
-}
-
-/**
- * Allocate and initialize an AfpInfo struct
- **/
-static AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
-{
- AfpInfo *ai = talloc_zero(ctx, AfpInfo);
- if (ai == NULL) {
- return NULL;
- }
- ai->afpi_Signature = AFP_Signature;
- ai->afpi_Version = AFP_Version;
- ai->afpi_BackupTime = AD_DATE_START;
- return ai;
-}
-
-/**
- * Pack an AfpInfo struct into a buffer
- *
- * Buffer size must be at least AFP_INFO_SIZE
- * Returns size of packed buffer
- **/
-static ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
-{
- memset(buf, 0, AFP_INFO_SIZE);
-
- RSIVAL(buf, 0, ai->afpi_Signature);
- RSIVAL(buf, 4, ai->afpi_Version);
- RSIVAL(buf, 12, ai->afpi_BackupTime);
- memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
-
- return AFP_INFO_SIZE;
-}
-
-/**
- * Unpack a buffer into a AfpInfo structure
- *
- * Buffer size must be at least AFP_INFO_SIZE
- * Returns allocated AfpInfo struct
- **/
-static AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data)
-{
- AfpInfo *ai = talloc_zero(ctx, AfpInfo);
- if (ai == NULL) {
- return NULL;
- }
-
- ai->afpi_Signature = RIVAL(data, 0);
- ai->afpi_Version = RIVAL(data, 4);
- ai->afpi_BackupTime = RIVAL(data, 12);
- memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
- sizeof(ai->afpi_FinderInfo));
-
- if (ai->afpi_Signature != AFP_Signature
- || ai->afpi_Version != AFP_Version) {
- DEBUG(1, ("Bad AfpInfo signature or version\n"));
- TALLOC_FREE(ai);
- }
-
- return ai;
-}
+ config->readdir_attr_rsize = lp_parm_bool(
+ SNUM(handle->conn), "readdir_attr", "aapl_rsize", true);
-/**
- * Fake an inode number from the md5 hash of the (xattr) name
- **/
-static SMB_INO_T fruit_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
-{
- gnutls_hash_hd_t hash_hnd = NULL;
- unsigned char hash[16];
- SMB_INO_T result = 0;
- char *upper_sname;
- int rc;
+ config->readdir_attr_finder_info = lp_parm_bool(
+ SNUM(handle->conn), "readdir_attr", "aapl_finder_info", true);
- DBG_DEBUG("fruit_inode called for %ju/%ju [%s]\n",
- (uintmax_t)sbuf->st_ex_dev,
- (uintmax_t)sbuf->st_ex_ino, sname);
+ config->readdir_attr_max_access = lp_parm_bool(
+ SNUM(handle->conn), "readdir_attr", "aapl_max_access", true);
- upper_sname = talloc_strdup_upper(talloc_tos(), sname);
- SMB_ASSERT(upper_sname != NULL);
+ config->model = lp_parm_const_string(
+ -1, FRUIT_PARAM_TYPE_NAME, "model", "MacSamba");
- rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
- if (rc < 0) {
- goto out;
+ tm_size_str = lp_parm_const_string(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "time machine max size", NULL);
+ if (tm_size_str != NULL) {
+ config->time_machine_max_size = conv_str_size(tm_size_str);
}
- rc = gnutls_hash(hash_hnd, &(sbuf->st_ex_dev), sizeof(sbuf->st_ex_dev));
- if (rc < 0) {
- gnutls_hash_deinit(hash_hnd, NULL);
- goto out;
- }
- rc = gnutls_hash(hash_hnd,
- &(sbuf->st_ex_ino),
- sizeof(sbuf->st_ex_ino));
- if (rc < 0) {
- gnutls_hash_deinit(hash_hnd, NULL);
- goto out;
- }
- rc = gnutls_hash(hash_hnd,
- upper_sname,
- talloc_get_size(upper_sname) - 1);
- if (rc < 0) {
- gnutls_hash_deinit(hash_hnd, NULL);
- goto out;
- }
+ config->convert_adouble = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "convert_adouble", true);
- gnutls_hash_deinit(hash_hnd, hash);
+ config->wipe_intentionally_left_blank_rfork = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "wipe_intentionally_left_blank_rfork", false);
- /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
- memcpy(&result, hash, sizeof(result));
- ZERO_ARRAY(hash);
+ config->delete_empty_adfiles = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "delete_empty_adfiles", false);
- DBG_DEBUG("fruit_inode \"%s\": ino=%ju\n",
- sname, (uintmax_t)result);
+ config->validate_afpinfo = lp_parm_bool(
+ SNUM(handle->conn), FRUIT_PARAM_TYPE_NAME,
+ "validate_afpinfo", true);
-out:
- TALLOC_FREE(upper_sname);
+ SMB_VFS_HANDLE_SET_DATA(handle, config,
+ NULL, struct fruit_config_data,
+ return -1);
- return result;
+ return 0;
}
static bool add_fruit_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
}
TALLOC_FREE(tmp[i].name);
- if (*num_streams - 1 > i) {
- memmove(&tmp[i], &tmp[i+1],
- (*num_streams - i - 1) * sizeof(struct stream_struct));
- }
-
+ ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
*num_streams -= 1;
return true;
}
}
TALLOC_FREE(tmp[i].name);
- if (*num_streams - 1 > i) {
- memmove(&tmp[i], &tmp[i+1],
- (*num_streams - i - 1) * sizeof(struct stream_struct));
- }
-
+ ARRAY_DEL_ELEMENT(tmp, i, *num_streams);
*num_streams -= 1;
return true;
}
return;
}
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
return;
}
/**
* Call fcntl() with an exclusive F_GETLK request in order to
- * determine if there's an exisiting shared lock
+ * determine if there's an existing shared lock
*
* @return true if the requested lock was found or any error occurred
* false if the lock was not found
bool netatalk_already_open_for_writing = false;
bool netatalk_already_open_with_deny_read = false;
bool netatalk_already_open_with_deny_write = false;
+ struct GUID req_guid = GUID_random();
/* FIXME: hardcoded data fork, add resource fork */
enum apple_fork fork_type = APPLE_FORK_DATA;
access_mask & FILE_WRITE_DATA ? "WRITE" : "-",
share_mode);
- if (fsp->fh->fd == -1) {
+ if (fsp_get_io_fd(fsp) == -1) {
return NT_STATUS_OK;
}
/* Set NetAtalk locks matching our access */
if (access_mask & FILE_READ_DATA) {
- struct byte_range_lock *br_lck = NULL;
-
off = access_to_netatalk_brl(fork_type, FILE_READ_DATA);
- br_lck = do_lock(
- handle->conn->sconn->msg_ctx, fsp,
- fsp->op->global->open_persistent_id, 1, off,
- READ_LOCK, POSIX_LOCK, false,
- &status, NULL);
-
- TALLOC_FREE(br_lck);
+ req_guid.time_hi_and_version = __LINE__;
+ status = do_lock(
+ fsp,
+ talloc_tos(),
+ &req_guid,
+ fsp->op->global->open_persistent_id,
+ 1,
+ off,
+ READ_LOCK,
+ POSIX_LOCK,
+ NULL,
+ NULL);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (!share_for_read) {
- struct byte_range_lock *br_lck = NULL;
-
off = denymode_to_netatalk_brl(fork_type, DENY_READ);
- br_lck = do_lock(
- handle->conn->sconn->msg_ctx, fsp,
- fsp->op->global->open_persistent_id, 1, off,
- READ_LOCK, POSIX_LOCK, false,
- &status, NULL);
-
- TALLOC_FREE(br_lck);
+ req_guid.time_hi_and_version = __LINE__;
+ status = do_lock(
+ fsp,
+ talloc_tos(),
+ &req_guid,
+ fsp->op->global->open_persistent_id,
+ 1,
+ off,
+ READ_LOCK,
+ POSIX_LOCK,
+ NULL,
+ NULL);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (access_mask & FILE_WRITE_DATA) {
- struct byte_range_lock *br_lck = NULL;
-
off = access_to_netatalk_brl(fork_type, FILE_WRITE_DATA);
- br_lck = do_lock(
- handle->conn->sconn->msg_ctx, fsp,
- fsp->op->global->open_persistent_id, 1, off,
- READ_LOCK, POSIX_LOCK, false,
- &status, NULL);
-
- TALLOC_FREE(br_lck);
+ req_guid.time_hi_and_version = __LINE__;
+ status = do_lock(
+ fsp,
+ talloc_tos(),
+ &req_guid,
+ fsp->op->global->open_persistent_id,
+ 1,
+ off,
+ READ_LOCK,
+ POSIX_LOCK,
+ NULL,
+ NULL);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
if (!share_for_write) {
- struct byte_range_lock *br_lck = NULL;
-
off = denymode_to_netatalk_brl(fork_type, DENY_WRITE);
- br_lck = do_lock(
- handle->conn->sconn->msg_ctx, fsp,
- fsp->op->global->open_persistent_id, 1, off,
- READ_LOCK, POSIX_LOCK, false,
- &status, NULL);
-
- TALLOC_FREE(br_lck);
+ req_guid.time_hi_and_version = __LINE__;
+ status = do_lock(
+ fsp,
+ talloc_tos(),
+ &req_guid,
+ fsp->op->global->open_persistent_id,
+ 1,
+ off,
+ READ_LOCK,
+ POSIX_LOCK,
+ NULL,
+ NULL);
if (!NT_STATUS_IS_OK(status)) {
return status;
if (req_bitmap & SMB2_CRTCTX_AAPL_SERVER_CAPS) {
if ((client_caps & SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR) &&
- (handle->conn->tcon->compat->fs_capabilities & FILE_NAMED_STREAMS)) {
+ (handle->conn->fs_capabilities & FILE_NAMED_STREAMS)) {
server_caps |= SMB2_CRTCTX_AAPL_SUPPORTS_READ_DIR_ATTR;
config->readdir_attr_enabled = true;
}
}
if (req_bitmap & SMB2_CRTCTX_AAPL_VOLUME_CAPS) {
- int val = lp_case_sensitive(SNUM(handle->conn->tcon->compat));
+ int val = lp_case_sensitive(SNUM(handle->conn));
uint64_t caps = 0;
switch (val) {
blob);
if (NT_STATUS_IS_OK(status)) {
global_fruit_config.nego_aapl = true;
- if (config->aapl_zero_file_id) {
- aapl_force_zero_file_id(handle->conn->sconn);
- }
}
return status;
files_struct *fsp = NULL;
ssize_t nread;
NTSTATUS status;
- int ret;
bool ok;
uint8_t buf[AFP_INFO_SIZE];
- stream_name = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- AFPINFO_STREAM_NAME,
- NULL, smb_fname->flags);
- if (stream_name == NULL) {
- return false;
- }
-
- ret = SMB_VFS_STAT(handle->conn, stream_name);
- if (ret != 0) {
+ status = synthetic_pathref(talloc_tos(),
+ handle->conn->cwd_fsp,
+ smb_fname->base_name,
+ AFPINFO_STREAM_NAME,
+ NULL,
+ smb_fname->twrp,
+ smb_fname->flags,
+ &stream_name);
+ if (!NT_STATUS_IS_OK(status)) {
return false;
}
status = SMB_VFS_CREATE_FILE(
handle->conn, /* conn */
NULL, /* req */
- 0, /* root_dir_fid */
+ NULL, /* dirfsp */
stream_name, /* fname */
FILE_READ_DATA, /* access_mask */
(FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
fail:
if (fsp != NULL) {
- close_file(NULL, fsp, NORMAL_CLOSE);
+ close_file_free(NULL, &fsp, NORMAL_CLOSE);
}
return ok;
struct adouble *ad = NULL;
char *p = NULL;
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
return false;
}
stream_name = synthetic_smb_fname(talloc_tos(),
smb_fname->base_name,
AFPRESOURCE_STREAM_NAME,
- NULL, 0);
+ NULL,
+ smb_fname->twrp,
+ 0);
if (stream_name == NULL) {
return 0;
}
int rc;
char *list = NULL, *newlist = NULL;
struct fruit_config_data *config;
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
DEBUG(10, ("fruit_connect\n"));
struct fruit_config_data, return -1);
if (config->veto_appledouble) {
- list = lp_veto_files(talloc_tos(), SNUM(handle->conn));
+ list = lp_veto_files(talloc_tos(), lp_sub, SNUM(handle->conn));
if (list) {
if (strstr(list, "/" ADOUBLE_NAME_PREFIX "*/") == NULL) {
if (config->encoding == FRUIT_ENC_NATIVE) {
lp_do_parameter(SNUM(handle->conn),
"catia:mappings",
- fruit_catia_maps);
+ macos_string_replace_map);
}
if (config->time_machine) {
return rc;
}
-static int fruit_fake_fd(void)
+static void fio_ref_destroy_fn(void *p_data)
{
- int pipe_fds[2];
- int fd;
- int ret;
+ struct fio *ref_fio = (struct fio *)p_data;
+ if (ref_fio->real_fio != NULL) {
+ SMB_ASSERT(ref_fio->real_fio->ad_fsp == ref_fio->fsp);
+ ref_fio->real_fio->ad_fsp = NULL;
+ ref_fio->real_fio = NULL;
+ }
+}
- /*
- * Return a valid fd, but ensure any attempt to use it returns
- * an error (EPIPE). Once we get a write on the handle, we open
- * the real fd.
- */
- ret = pipe(pipe_fds);
- if (ret != 0) {
- return -1;
+static void fio_close_ad_fsp(struct fio *fio)
+{
+ if (fio->ad_fsp != NULL) {
+ fd_close(fio->ad_fsp);
+ file_free(NULL, fio->ad_fsp);
+ /* fio_ref_destroy_fn() should have cleared this */
+ SMB_ASSERT(fio->ad_fsp == NULL);
}
- fd = pipe_fds[0];
- close(pipe_fds[1]);
+}
- return fd;
+static void fio_destroy_fn(void *p_data)
+{
+ struct fio *fio = (struct fio *)p_data;
+ fio_close_ad_fsp(fio);
}
static int fruit_open_meta_stream(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
files_struct *fsp,
int flags,
mode_t mode)
{
struct fruit_config_data *config = NULL;
struct fio *fio = NULL;
- int open_flags = flags & ~O_CREAT;
+ struct vfs_open_how how = {
+ .flags = flags & ~O_CREAT,
+ .mode = mode,
+ };
int fd;
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
+ fio->handle = handle;
+ fio->fsp = fsp;
fio->type = ADOUBLE_META;
fio->config = config;
- fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, open_flags, mode);
+ fd = SMB_VFS_NEXT_OPENAT(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ &how);
if (fd != -1) {
return fd;
}
return -1;
}
- fd = fruit_fake_fd();
+ fd = vfs_fake_fd();
if (fd == -1) {
VFS_REMOVE_FSP_EXTENSION(handle, fsp);
return -1;
}
static int fruit_open_meta_netatalk(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
files_struct *fsp,
int flags,
mode_t mode)
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ /*
+ * We know this is a stream open, so fsp->base_fsp must
+ * already be open.
+ */
+ SMB_ASSERT(fsp_is_alternate_stream(fsp));
+ SMB_ASSERT(fsp->base_fsp->fsp_name->fsp == fsp->base_fsp);
+
+ ad = ad_get(talloc_tos(), handle, fsp->base_fsp->fsp_name, ADOUBLE_META);
if (ad != NULL) {
meta_exists = true;
}
return -1;
}
- fd = fruit_fake_fd();
+ fd = vfs_fake_fd();
if (fd == -1) {
return -1;
}
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
+ fio->handle = handle;
+ fio->fsp = fsp;
fio->type = ADOUBLE_META;
fio->config = config;
fio->fake_fd = true;
}
static int fruit_open_meta(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
files_struct *fsp, int flags, mode_t mode)
{
int fd;
switch (config->meta) {
case FRUIT_META_STREAM:
- fd = fruit_open_meta_stream(handle, smb_fname,
+ fd = fruit_open_meta_stream(handle, dirfsp, smb_fname,
fsp, flags, mode);
break;
case FRUIT_META_NETATALK:
- fd = fruit_open_meta_netatalk(handle, smb_fname,
+ fd = fruit_open_meta_netatalk(handle, dirfsp, smb_fname,
fsp, flags, mode);
break;
}
static int fruit_open_rsrc_adouble(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
files_struct *fsp,
int flags,
mode_t mode)
{
int rc = 0;
- struct adouble *ad = NULL;
- struct smb_filename *smb_fname_base = NULL;
struct fruit_config_data *config = NULL;
- int hostfd = -1;
+ struct files_struct *ad_fsp = NULL;
+ struct fio *fio = NULL;
+ struct fio *ref_fio = NULL;
+ NTSTATUS status;
+ int fd = -1;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
if ((!(flags & O_CREAT)) &&
S_ISDIR(fsp->base_fsp->fsp_name->st.st_ex_mode))
{
- /* sorry, but directories don't habe a resource fork */
+ /* sorry, but directories don't have a resource fork */
+ errno = ENOENT;
rc = -1;
goto exit;
}
- rc = adouble_path(talloc_tos(), smb_fname, &smb_fname_base);
- if (rc != 0) {
+ /*
+ * We return a fake_fd to the vfs modules above,
+ * while we open an internal backend fsp for the
+ * '._' file for the next vfs modules.
+ *
+ * Note that adouble_open_from_base_fsp() recurses
+ * into fruit_openat(), but it'll just pass to
+ * the next module as just opens a flat file on
+ * disk.
+ */
+
+ fd = vfs_fake_fd();
+ if (fd == -1) {
+ rc = fd;
goto exit;
}
- /* We always need read/write access for the metadata header too */
- flags &= ~(O_RDONLY | O_WRONLY);
- flags |= O_RDWR;
-
- hostfd = SMB_VFS_NEXT_OPEN(handle, smb_fname_base, fsp,
- flags, mode);
- if (hostfd == -1) {
+ status = adouble_open_from_base_fsp(fsp->conn->cwd_fsp,
+ fsp->base_fsp,
+ ADOUBLE_RSRC,
+ flags,
+ mode,
+ &ad_fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
rc = -1;
goto exit;
}
- if (flags & (O_CREAT | O_TRUNC)) {
- ad = ad_init(fsp, ADOUBLE_RSRC);
- if (ad == NULL) {
- rc = -1;
- goto exit;
- }
-
- fsp->fh->fd = hostfd;
+ /*
+ * Now we need to glue both handles together,
+ * so that they automatically detach each other
+ * on close.
+ */
+ fio = fruit_get_complete_fio(handle, fsp);
+ if (fio == NULL) {
+ DBG_ERR("fio=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ rc = -1;
+ goto exit;
+ }
- rc = ad_fset(handle, ad, fsp);
- fsp->fh->fd = -1;
- if (rc != 0) {
- rc = -1;
- goto exit;
- }
- TALLOC_FREE(ad);
+ ref_fio = VFS_ADD_FSP_EXTENSION(handle, ad_fsp,
+ struct fio,
+ fio_ref_destroy_fn);
+ if (ref_fio == NULL) {
+ int saved_errno = errno;
+ fd_close(ad_fsp);
+ file_free(NULL, ad_fsp);
+ ad_fsp = NULL;
+ errno = saved_errno;
+ rc = -1;
+ goto exit;
}
-exit:
+ SMB_ASSERT(ref_fio->fsp == NULL);
+ ref_fio->handle = handle;
+ ref_fio->fsp = ad_fsp;
+ ref_fio->type = ADOUBLE_RSRC;
+ ref_fio->config = config;
+ ref_fio->real_fio = fio;
+ SMB_ASSERT(fio->ad_fsp == NULL);
+ fio->ad_fsp = ad_fsp;
+ fio->fake_fd = true;
- TALLOC_FREE(smb_fname_base);
+exit:
- DEBUG(10, ("fruit_open resource fork: rc=%d, fd=%d\n", rc, hostfd));
+ DEBUG(10, ("fruit_open resource fork: rc=%d\n", rc));
if (rc != 0) {
int saved_errno = errno;
- if (hostfd >= 0) {
- /*
- * BUGBUGBUG -- we would need to call
- * fd_close_posix here, but we don't have a
- * full fsp yet
- */
- fsp->fh->fd = hostfd;
- SMB_VFS_CLOSE(fsp);
+ if (fd != -1) {
+ vfs_fake_fd_close(fd);
}
- hostfd = -1;
errno = saved_errno;
+ return rc;
}
- return hostfd;
+ return fd;
}
static int fruit_open_rsrc_xattr(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
files_struct *fsp,
int flags,
mode_t mode)
#ifdef HAVE_ATTROPEN
int fd = -1;
+ /*
+ * As there's no attropenat() this is only going to work with AT_FDCWD.
+ */
+ SMB_ASSERT(fsp_get_pathref_fd(dirfsp) == AT_FDCWD);
+
fd = attropen(smb_fname->base_name,
AFPRESOURCE_EA_NETATALK,
flags,
}
static int fruit_open_rsrc(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
files_struct *fsp, int flags, mode_t mode)
{
int fd;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
+ fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, fio_destroy_fn);
+ fio->handle = handle;
+ fio->fsp = fsp;
+ fio->type = ADOUBLE_RSRC;
+ fio->config = config;
+
switch (config->rsrc) {
- case FRUIT_RSRC_STREAM:
- fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+ case FRUIT_RSRC_STREAM: {
+ struct vfs_open_how how = {
+ .flags = flags, .mode = mode,
+ };
+ fd = SMB_VFS_NEXT_OPENAT(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ &how);
break;
+ }
case FRUIT_RSRC_ADFILE:
- fd = fruit_open_rsrc_adouble(handle, smb_fname,
+ fd = fruit_open_rsrc_adouble(handle, dirfsp, smb_fname,
fsp, flags, mode);
break;
case FRUIT_RSRC_XATTR:
- fd = fruit_open_rsrc_xattr(handle, smb_fname,
+ fd = fruit_open_rsrc_xattr(handle, dirfsp, smb_fname,
fsp, flags, mode);
break;
default:
DBG_ERR("Unexpected rsrc config [%d]\n", config->rsrc);
+ errno = EINVAL;
return -1;
}
return -1;
}
- fio = VFS_ADD_FSP_EXTENSION(handle, fsp, struct fio, NULL);
- fio->type = ADOUBLE_RSRC;
- fio->config = config;
-
return fd;
}
-static int fruit_open(vfs_handle_struct *handle,
- struct smb_filename *smb_fname,
- files_struct *fsp, int flags, mode_t mode)
+static int fruit_openat(vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ files_struct *fsp,
+ const struct vfs_open_how *how)
{
int fd;
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
- if (!is_ntfs_stream_smb_fname(smb_fname)) {
- return SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+ if (!is_named_stream(smb_fname)) {
+ return SMB_VFS_NEXT_OPENAT(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ how);
+ }
+
+ if (how->resolve != 0) {
+ errno = ENOSYS;
+ return -1;
}
- if (is_afpinfo_stream(smb_fname)) {
- fd = fruit_open_meta(handle, smb_fname, fsp, flags, mode);
- } else if (is_afpresource_stream(smb_fname)) {
- fd = fruit_open_rsrc(handle, smb_fname, fsp, flags, mode);
+ SMB_ASSERT(fsp_is_alternate_stream(fsp));
+
+ if (is_afpinfo_stream(smb_fname->stream_name)) {
+ fd = fruit_open_meta(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ how->flags,
+ how->mode);
+ } else if (is_afpresource_stream(smb_fname->stream_name)) {
+ fd = fruit_open_rsrc(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ how->flags,
+ how->mode);
} else {
- fd = SMB_VFS_NEXT_OPEN(handle, smb_fname, fsp, flags, mode);
+ fd = SMB_VFS_NEXT_OPENAT(handle,
+ dirfsp,
+ smb_fname,
+ fsp,
+ how);
}
DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(smb_fname), fd);
+ /* Prevent reopen optimisation */
+ fsp->fsp_flags.have_proc_fds = false;
return fd;
}
switch (config->meta) {
case FRUIT_META_STREAM:
- ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ {
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+ if (fio == NULL) {
+ return -1;
+ }
+ if (fio->fake_fd) {
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
+ } else {
+ ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ }
break;
-
+ }
case FRUIT_META_NETATALK:
- ret = close(fsp->fh->fd);
- fsp->fh->fd = -1;
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
break;
default:
switch (config->rsrc) {
case FRUIT_RSRC_STREAM:
- case FRUIT_RSRC_ADFILE:
ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
break;
+ case FRUIT_RSRC_ADFILE:
+ {
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+ if (fio == NULL) {
+ return -1;
+ }
+ fio_close_ad_fsp(fio);
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
+ break;
+ }
+
case FRUIT_RSRC_XATTR:
- ret = close(fsp->fh->fd);
- fsp->fh->fd = -1;
+ ret = vfs_fake_fd_close(fsp_get_pathref_fd(fsp));
+ fsp_set_fd(fsp, -1);
break;
default:
int ret;
int fd;
- fd = fsp->fh->fd;
+ fd = fsp_get_pathref_fd(fsp);
DBG_DEBUG("Path [%s] fd [%d]\n", smb_fname_str_dbg(fsp->fsp_name), fd);
- if (!is_ntfs_stream_smb_fname(fsp->fsp_name)) {
+ if (!fsp_is_alternate_stream(fsp)) {
return SMB_VFS_NEXT_CLOSE(handle, fsp);
}
- if (is_afpinfo_stream(fsp->fsp_name)) {
+ if (is_afpinfo_stream(fsp->fsp_name->stream_name)) {
ret = fruit_close_meta(handle, fsp);
- } else if (is_afpresource_stream(fsp->fsp_name)) {
+ } else if (is_afpresource_stream(fsp->fsp_name->stream_name)) {
ret = fruit_close_rsrc(handle, fsp);
} else {
ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
return ret;
}
-static int fruit_rename(struct vfs_handle_struct *handle,
+static int fruit_renameat(struct vfs_handle_struct *handle,
+ files_struct *srcfsp,
const struct smb_filename *smb_fname_src,
- const struct smb_filename *smb_fname_dst)
+ files_struct *dstfsp,
+ const struct smb_filename *smb_fname_dst,
+ const struct vfs_rename_how *how)
{
int rc = -1;
struct fruit_config_data *config = NULL;
return -1;
}
- rc = SMB_VFS_NEXT_RENAME(handle, smb_fname_src, smb_fname_dst);
+ rc = SMB_VFS_NEXT_RENAMEAT(handle,
+ srcfsp,
+ smb_fname_src,
+ dstfsp,
+ smb_fname_dst,
+ how);
if (rc != 0) {
return -1;
}
smb_fname_str_dbg(src_adp_smb_fname),
smb_fname_str_dbg(dst_adp_smb_fname));
- rc = SMB_VFS_NEXT_RENAME(handle, src_adp_smb_fname, dst_adp_smb_fname);
+ rc = SMB_VFS_NEXT_RENAMEAT(handle,
+ srcfsp,
+ src_adp_smb_fname,
+ dstfsp,
+ dst_adp_smb_fname,
+ how);
if (errno == ENOENT) {
rc = 0;
}
}
static int fruit_unlink_meta_stream(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname)
{
- return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ 0);
}
static int fruit_unlink_meta_netatalk(vfs_handle_struct *handle,
const struct smb_filename *smb_fname)
{
- return SMB_VFS_REMOVEXATTR(handle->conn,
- smb_fname,
+ SMB_ASSERT(smb_fname->fsp != NULL);
+ SMB_ASSERT(fsp_is_alternate_stream(smb_fname->fsp));
+ return SMB_VFS_FREMOVEXATTR(smb_fname->fsp->base_fsp,
AFPINFO_EA_NETATALK);
}
static int fruit_unlink_meta(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname)
{
struct fruit_config_data *config = NULL;
int rc;
switch (config->meta) {
case FRUIT_META_STREAM:
- rc = fruit_unlink_meta_stream(handle, smb_fname);
+ rc = fruit_unlink_meta_stream(handle,
+ dirfsp,
+ smb_fname);
break;
case FRUIT_META_NETATALK:
}
static int fruit_unlink_rsrc_stream(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- bool force_unlink)
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ bool force_unlink)
{
int ret;
if (!force_unlink) {
- struct smb_filename *smb_fname_cp = NULL;
+ struct smb_filename *full_fname = NULL;
off_t size;
- smb_fname_cp = cp_smb_filename(talloc_tos(), smb_fname);
- if (smb_fname_cp == NULL) {
+ /*
+ * TODO: use SMB_VFS_STATX() once we have it.
+ */
+
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
return -1;
}
* deletion doesn't remove the resourcefork stream.
*/
- ret = SMB_VFS_NEXT_STAT(handle, smb_fname_cp);
+ ret = SMB_VFS_NEXT_STAT(handle, full_fname);
if (ret != 0) {
- TALLOC_FREE(smb_fname_cp);
+ TALLOC_FREE(full_fname);
DBG_ERR("stat [%s] failed [%s]\n",
- smb_fname_str_dbg(smb_fname_cp), strerror(errno));
+ smb_fname_str_dbg(full_fname), strerror(errno));
return -1;
}
- size = smb_fname_cp->st.st_ex_size;
- TALLOC_FREE(smb_fname_cp);
+ size = full_fname->st.st_ex_size;
+ TALLOC_FREE(full_fname);
if (size > 0) {
/* OS X ignores resource fork stream delete requests */
}
}
- ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname);
+ ret = SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ 0);
if ((ret != 0) && (errno == ENOENT) && force_unlink) {
ret = 0;
}
}
static int fruit_unlink_rsrc_adouble(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- bool force_unlink)
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ bool force_unlink)
{
int rc;
struct adouble *ad = NULL;
struct smb_filename *adp_smb_fname = NULL;
if (!force_unlink) {
- ad = ad_get(talloc_tos(), handle, smb_fname,
+ struct smb_filename *full_fname = NULL;
+
+ full_fname = full_path_from_dirfsp_atname(talloc_tos(),
+ dirfsp,
+ smb_fname);
+ if (full_fname == NULL) {
+ return -1;
+ }
+
+ ad = ad_get(talloc_tos(), handle, full_fname,
ADOUBLE_RSRC);
+ TALLOC_FREE(full_fname);
if (ad == NULL) {
errno = ENOENT;
return -1;
return -1;
}
- rc = SMB_VFS_NEXT_UNLINK(handle, adp_smb_fname);
+ rc = SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ adp_smb_fname,
+ 0);
TALLOC_FREE(adp_smb_fname);
- if ((rc != 0) && (errno == ENOENT) && force_unlink) {
+ if ((rc != 0) && (errno == ENOENT || errno == ENAMETOOLONG) && force_unlink) {
rc = 0;
}
}
static int fruit_unlink_rsrc(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- bool force_unlink)
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ bool force_unlink)
{
struct fruit_config_data *config = NULL;
int rc;
switch (config->rsrc) {
case FRUIT_RSRC_STREAM:
- rc = fruit_unlink_rsrc_stream(handle, smb_fname, force_unlink);
+ rc = fruit_unlink_rsrc_stream(handle,
+ dirfsp,
+ smb_fname,
+ force_unlink);
break;
case FRUIT_RSRC_ADFILE:
- rc = fruit_unlink_rsrc_adouble(handle, smb_fname, force_unlink);
+ rc = fruit_unlink_rsrc_adouble(handle,
+ dirfsp,
+ smb_fname,
+ force_unlink);
break;
case FRUIT_RSRC_XATTR:
return rc;
}
-static int fruit_unlink(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
-{
- int rc;
- struct fruit_config_data *config = NULL;
- struct smb_filename *rsrc_smb_fname = NULL;
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct fruit_config_data, return -1);
-
- if (is_afpinfo_stream(smb_fname)) {
- return fruit_unlink_meta(handle, smb_fname);
- } else if (is_afpresource_stream(smb_fname)) {
- return fruit_unlink_rsrc(handle, smb_fname, false);
- } else if (is_ntfs_stream_smb_fname(smb_fname)) {
- return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
- } else if (is_adouble_file(smb_fname->base_name)) {
- return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
- }
-
- /*
- * A request to delete the base file. Because 0 byte resource
- * fork streams are not listed by fruit_streaminfo,
- * delete_all_streams() can't remove 0 byte resource fork
- * streams, so we have to cleanup this here.
- */
- rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- AFPRESOURCE_STREAM_NAME,
- NULL,
- smb_fname->flags);
- if (rsrc_smb_fname == NULL) {
- return -1;
- }
-
- rc = fruit_unlink_rsrc(handle, rsrc_smb_fname, true);
- if ((rc != 0) && (errno != ENOENT)) {
- DBG_ERR("Forced unlink of [%s] failed [%s]\n",
- smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
- TALLOC_FREE(rsrc_smb_fname);
- return -1;
- }
- TALLOC_FREE(rsrc_smb_fname);
-
- return SMB_VFS_NEXT_UNLINK(handle, smb_fname);
-}
-
-static int fruit_chmod(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- mode_t mode)
+static int fruit_fchmod(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ mode_t mode)
{
int rc = -1;
struct fruit_config_data *config = NULL;
struct smb_filename *smb_fname_adp = NULL;
+ const struct smb_filename *smb_fname = NULL;
+ NTSTATUS status;
- rc = SMB_VFS_NEXT_CHMOD(handle, smb_fname, mode);
+ rc = SMB_VFS_NEXT_FCHMOD(handle, fsp, mode);
if (rc != 0) {
return rc;
}
+ smb_fname = fsp->fsp_name;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
return -1;
}
- DEBUG(10, ("fruit_chmod: %s\n", smb_fname_adp->base_name));
-
- rc = SMB_VFS_NEXT_CHMOD(handle, smb_fname_adp, mode);
- if (errno == ENOENT) {
- rc = 0;
- }
-
- TALLOC_FREE(smb_fname_adp);
- return rc;
-}
-
-static int fruit_chown(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- uid_t uid,
- gid_t gid)
-{
- int rc = -1;
- struct fruit_config_data *config = NULL;
- struct smb_filename *adp_smb_fname = NULL;
-
- rc = SMB_VFS_NEXT_CHOWN(handle, smb_fname, uid, gid);
- if (rc != 0) {
- return rc;
- }
-
- SMB_VFS_HANDLE_GET_DATA(handle, config,
- struct fruit_config_data, return -1);
-
- if (config->rsrc != FRUIT_RSRC_ADFILE) {
- return 0;
- }
-
- if (!VALID_STAT(smb_fname->st)) {
- return 0;
- }
-
- if (!S_ISREG(smb_fname->st.st_ex_mode)) {
- return 0;
- }
-
- rc = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
- if (rc != 0) {
- goto done;
- }
-
- DEBUG(10, ("fruit_chown: %s\n", adp_smb_fname->base_name));
+ status = openat_pathref_fsp(handle->conn->cwd_fsp,
+ smb_fname_adp);
+ if (!NT_STATUS_IS_OK(status)) {
+ /* detect ENOENT (mapped to OBJECT_NAME_NOT_FOUND) */
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_OBJECT_NAME_NOT_FOUND)){
+ rc = 0;
+ goto out;
+ }
+ rc = -1;
+ goto out;
+ }
+
+ DBG_DEBUG("%s\n", smb_fname_adp->base_name);
- rc = SMB_VFS_NEXT_CHOWN(handle, adp_smb_fname, uid, gid);
+ rc = SMB_VFS_NEXT_FCHMOD(handle, smb_fname_adp->fsp, mode);
if (errno == ENOENT) {
rc = 0;
}
-
- done:
- TALLOC_FREE(adp_smb_fname);
+out:
+ TALLOC_FREE(smb_fname_adp);
return rc;
}
-static int fruit_rmdir(struct vfs_handle_struct *handle,
- const struct smb_filename *smb_fname)
+static int fruit_unlinkat(vfs_handle_struct *handle,
+ struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ int flags)
{
- DIR *dh = NULL;
- struct dirent *de;
- struct fruit_config_data *config;
+ struct fruit_config_data *config = NULL;
+ struct smb_filename *rsrc_smb_fname = NULL;
+ int ret;
+
+ if (flags & AT_REMOVEDIR) {
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ AT_REMOVEDIR);
+ }
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data, return -1);
- if (config->rsrc != FRUIT_RSRC_ADFILE) {
- goto exit_rmdir;
+ if (is_afpinfo_stream(smb_fname->stream_name)) {
+ return fruit_unlink_meta(handle,
+ dirfsp,
+ smb_fname);
+ } else if (is_afpresource_stream(smb_fname->stream_name)) {
+ return fruit_unlink_rsrc(handle,
+ dirfsp,
+ smb_fname,
+ false);
+ } else if (is_named_stream(smb_fname)) {
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ 0);
+ } else if (is_adouble_file(smb_fname->base_name)) {
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ 0);
}
/*
- * Due to there is no way to change bDeleteVetoFiles variable
- * from this module, need to clean up ourselves
+ * A request to delete the base file. Because 0 byte resource
+ * fork streams are not listed by fruit_streaminfo,
+ * delete_all_streams() can't remove 0 byte resource fork
+ * streams, so we have to cleanup this here.
*/
-
- dh = SMB_VFS_OPENDIR(handle->conn, smb_fname, NULL, 0);
- if (dh == NULL) {
- goto exit_rmdir;
+ rsrc_smb_fname = synthetic_smb_fname(talloc_tos(),
+ smb_fname->base_name,
+ AFPRESOURCE_STREAM_NAME,
+ NULL,
+ smb_fname->twrp,
+ smb_fname->flags);
+ if (rsrc_smb_fname == NULL) {
+ return -1;
}
- while ((de = SMB_VFS_READDIR(handle->conn, dh, NULL)) != NULL) {
- struct adouble *ad = NULL;
- char *p = NULL;
- struct smb_filename *ad_smb_fname = NULL;
- int ret;
-
- if (!is_adouble_file(de->d_name)) {
- continue;
- }
-
- p = talloc_asprintf(talloc_tos(), "%s/%s",
- smb_fname->base_name, de->d_name);
- if (p == NULL) {
- DBG_ERR("talloc_asprintf failed\n");
- return -1;
- }
-
- ad_smb_fname = synthetic_smb_fname(talloc_tos(), p,
- NULL, NULL,
- smb_fname->flags);
- TALLOC_FREE(p);
- if (ad_smb_fname == NULL) {
- DBG_ERR("synthetic_smb_fname failed\n");
- return -1;
- }
-
- /*
- * Check whether it's a valid AppleDouble file, if
- * yes, delete it, ignore it otherwise.
- */
- ad = ad_get(talloc_tos(), handle, ad_smb_fname, ADOUBLE_RSRC);
- if (ad == NULL) {
- TALLOC_FREE(ad_smb_fname);
- TALLOC_FREE(p);
- continue;
- }
- TALLOC_FREE(ad);
-
- ret = SMB_VFS_NEXT_UNLINK(handle, ad_smb_fname);
- if (ret != 0) {
- DBG_ERR("Deleting [%s] failed\n",
- smb_fname_str_dbg(ad_smb_fname));
- }
- TALLOC_FREE(ad_smb_fname);
+ ret = fruit_unlink_rsrc(handle, dirfsp, rsrc_smb_fname, true);
+ if ((ret != 0) && (errno != ENOENT)) {
+ DBG_ERR("Forced unlink of [%s] failed [%s]\n",
+ smb_fname_str_dbg(rsrc_smb_fname), strerror(errno));
+ TALLOC_FREE(rsrc_smb_fname);
+ return -1;
}
+ TALLOC_FREE(rsrc_smb_fname);
-exit_rmdir:
- if (dh) {
- SMB_VFS_CLOSEDIR(handle->conn, dh);
- }
- return SMB_VFS_NEXT_RMDIR(handle, smb_fname);
+ return SMB_VFS_NEXT_UNLINKAT(handle,
+ dirfsp,
+ smb_fname,
+ 0);
}
static ssize_t fruit_pread_meta_stream(vfs_handle_struct *handle,
files_struct *fsp, void *data,
size_t n, off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
int ret;
+ if ((fio == NULL) || fio->fake_fd) {
+ return -1;
+ }
+
nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
if (nread == -1 || nread == n) {
return nread;
DBG_ERR("Removing [%s] after short read [%zd]\n",
fsp_str_dbg(fsp), nread);
- ret = SMB_VFS_NEXT_UNLINK(handle, fsp->fsp_name);
+ ret = SMB_VFS_NEXT_UNLINKAT(handle,
+ fsp->conn->cwd_fsp,
+ fsp->fsp_name,
+ 0);
if (ret != 0) {
DBG_ERR("Removing [%s] failed\n", fsp_str_dbg(fsp));
return -1;
files_struct *fsp, void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
ssize_t to_return;
}
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
return -1;
}
- if (nread == -1 && fio->created) {
+ if (nread == -1 && fio->fake_fd) {
AfpInfo *ai = NULL;
char afpinfo_buf[AFP_INFO_SIZE];
files_struct *fsp, void *data,
size_t n, off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct adouble *ad = NULL;
ssize_t nread;
- ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
- nread = SMB_VFS_NEXT_PREAD(handle, fsp, data, n,
+ nread = SMB_VFS_NEXT_PREAD(handle, fio->ad_fsp, data, n,
offset + ad_getentryoff(ad, ADEID_RFORK));
TALLOC_FREE(ad);
files_struct *fsp, void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
if (fio == NULL) {
files_struct *fsp, void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nread;
DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
struct fruit_pread_state *state = NULL;
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
req = tevent_req_create(mem_ctx, &state,
struct fruit_pread_state);
{
struct fruit_pread_state *state = tevent_req_data(
req, struct fruit_pread_state);
+ ssize_t retval = -1;
if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ tevent_req_received(req);
return -1;
}
*vfs_aio_state = state->vfs_aio_state;
- return state->nread;
+ retval = state->nread;
+ tevent_req_received(req);
+ return retval;
}
static ssize_t fruit_pwrite_meta_stream(vfs_handle_struct *handle,
- files_struct *fsp, const void *data,
+ files_struct *fsp, const void *indata,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+ const void *data = indata;
+ char afpinfo_buf[AFP_INFO_SIZE];
AfpInfo *ai = NULL;
size_t nwritten;
int ret;
}
if (fio->fake_fd) {
- int fd;
+ struct vfs_open_how how = {
+ .flags = fio->flags, .mode = fio->mode,
+ };
+ int fd = fsp_get_pathref_fd(fsp);
- ret = SMB_VFS_NEXT_CLOSE(handle, fsp);
+ ret = vfs_fake_fd_close(fd);
+ fsp_set_fd(fsp, -1);
if (ret != 0) {
DBG_ERR("Close [%s] failed: %s\n",
fsp_str_dbg(fsp), strerror(errno));
- fsp->fh->fd = -1;
return -1;
}
- fd = SMB_VFS_NEXT_OPEN(handle,
- fsp->fsp_name,
- fsp,
- fio->flags,
- fio->mode);
+ fd = SMB_VFS_NEXT_OPENAT(handle,
+ NULL, /* opening a stream */
+ fsp->fsp_name,
+ fsp,
+ &how);
if (fd == -1) {
DBG_ERR("On-demand create [%s] in write failed: %s\n",
fsp_str_dbg(fsp), strerror(errno));
return -1;
}
- fsp->fh->fd = fd;
+ fsp_set_fd(fsp, fd);
fio->fake_fd = false;
}
- ai = afpinfo_unpack(talloc_tos(), data);
+ ai = afpinfo_unpack(talloc_tos(), data, fio->config->validate_afpinfo);
if (ai == NULL) {
return -1;
}
return n;
}
+ if (!fio->config->validate_afpinfo) {
+ /*
+ * Ensure the buffer contains a valid header, so marshall
+ * the data from the afpinfo struck back into a buffer
+ * and write that instead of the possibly malformed data
+ * we got from the client.
+ */
+ nwritten = afpinfo_pack(ai, afpinfo_buf);
+ if (nwritten != AFP_INFO_SIZE) {
+ errno = EINVAL;
+ return -1;
+ }
+ data = afpinfo_buf;
+ }
+
nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
if (nwritten != n) {
return -1;
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
+ struct fruit_config_data *config = NULL;
struct adouble *ad = NULL;
AfpInfo *ai = NULL;
char *p = NULL;
int ret;
bool ok;
- ai = afpinfo_unpack(talloc_tos(), data);
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct fruit_config_data, return -1);
+
+ ai = afpinfo_unpack(talloc_tos(), data, config->validate_afpinfo);
if (ai == NULL) {
return -1;
}
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nwritten;
uint8_t buf[AFP_INFO_SIZE];
size_t to_write;
int cmp;
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
return -1;
}
- cmp = memcmp(data, "AFP", 3);
- if (cmp != 0) {
- errno = EINVAL;
- return -1;
+ if (fio->config->validate_afpinfo) {
+ cmp = memcmp(data, "AFP", 3);
+ if (cmp != 0) {
+ errno = EINVAL;
+ return -1;
+ }
}
if (n <= AFP_OFF_FinderInfo) {
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct adouble *ad = NULL;
ssize_t nwritten;
int ret;
- ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
- DBG_ERR("ad_get [%s] failed\n", fsp_str_dbg(fsp));
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
- nwritten = SMB_VFS_NEXT_PWRITE(handle, fsp, data, n,
+ nwritten = SMB_VFS_NEXT_PWRITE(handle, fio->ad_fsp, data, n,
offset + ad_getentryoff(ad, ADEID_RFORK));
if (nwritten != n) {
DBG_ERR("Short write on [%s] [%zd/%zd]\n",
- fsp_str_dbg(fsp), nwritten, n);
+ fsp_str_dbg(fio->ad_fsp), nwritten, n);
TALLOC_FREE(ad);
return -1;
}
if ((n + offset) > ad_getentrylen(ad, ADEID_RFORK)) {
ad_setentrylen(ad, ADEID_RFORK, n + offset);
- ret = ad_fset(handle, ad, fsp);
+ ret = ad_fset(handle, ad, fio->ad_fsp);
if (ret != 0) {
- DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fsp));
+ DBG_ERR("ad_pwrite [%s] failed\n", fsp_str_dbg(fio->ad_fsp));
TALLOC_FREE(ad);
return -1;
}
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nwritten;
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
files_struct *fsp, const void *data,
size_t n, off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
ssize_t nwritten;
DBG_DEBUG("Path [%s] offset=%"PRIdMAX", size=%zd\n",
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
struct fruit_pwrite_state *state = NULL;
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
req = tevent_req_create(mem_ctx, &state,
struct fruit_pwrite_state);
{
struct fruit_pwrite_state *state = tevent_req_data(
req, struct fruit_pwrite_state);
+ ssize_t retval = -1;
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ tevent_req_received(req);
+ return -1;
+ }
+
+ *vfs_aio_state = state->vfs_aio_state;
+ retval = state->nwritten;
+ tevent_req_received(req);
+ return retval;
+}
+
+struct fruit_fsync_state {
+ int ret;
+ struct vfs_aio_state vfs_aio_state;
+};
+
+static void fruit_fsync_done(struct tevent_req *subreq);
+
+static struct tevent_req *fruit_fsync_send(
+ struct vfs_handle_struct *handle,
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct files_struct *fsp)
+{
+ struct tevent_req *req = NULL;
+ struct tevent_req *subreq = NULL;
+ struct fruit_fsync_state *state = NULL;
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct fruit_fsync_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (fruit_must_handle_aio_stream(fio)) {
+ struct adouble *ad = NULL;
+
+ if (fio->type == ADOUBLE_META) {
+ /*
+ * We must never pass a fake_fd
+ * to lower level fsync calls.
+ * Everything is already done
+ * synchronously, so just return
+ * true.
+ */
+ SMB_ASSERT(fio->fake_fd);
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * We know the following must be true,
+ * as it's the condition for fruit_must_handle_aio_stream()
+ * to return true if fio->type == ADOUBLE_RSRC.
+ */
+ SMB_ASSERT(fio->config->rsrc == FRUIT_RSRC_ADFILE);
+ if (fio->ad_fsp == NULL) {
+ tevent_req_error(req, EBADF);
+ return tevent_req_post(req, ev);
+ }
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
+ if (ad == NULL) {
+ tevent_req_error(req, ENOMEM);
+ return tevent_req_post(req, ev);
+ }
+ fsp = fio->ad_fsp;
+ }
+
+ subreq = SMB_VFS_NEXT_FSYNC_SEND(state, ev, handle, fsp);
+ if (tevent_req_nomem(req, subreq)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq, fruit_fsync_done, req);
+ return req;
+}
+
+static void fruit_fsync_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct fruit_fsync_state *state = tevent_req_data(
+ req, struct fruit_fsync_state);
+
+ state->ret = SMB_VFS_FSYNC_RECV(subreq, &state->vfs_aio_state);
+ TALLOC_FREE(subreq);
+ if (state->ret != 0) {
+ tevent_req_error(req, errno);
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static int fruit_fsync_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
+{
+ struct fruit_fsync_state *state = tevent_req_data(
+ req, struct fruit_fsync_state);
+ int retval = -1;
if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ tevent_req_received(req);
return -1;
}
*vfs_aio_state = state->vfs_aio_state;
- return state->nwritten;
+ retval = state->ret;
+ tevent_req_received(req);
+ return retval;
}
/**
return -1;
}
- ino = fruit_inode(&smb_fname->st, smb_fname->stream_name);
+ ino = hash_inode(&smb_fname->st, smb_fname->stream_name);
if (follow_links) {
ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
{
struct adouble *ad = NULL;
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ /* Populate the stat struct with info from the base file. */
+ if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
+ return -1;
+ }
+
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
DBG_INFO("fruit_stat_meta %s: %s\n",
smb_fname_str_dbg(smb_fname), strerror(errno));
}
TALLOC_FREE(ad);
- /* Populate the stat struct with info from the base file. */
- if (fruit_stat_base(handle, smb_fname, follow_links) == -1) {
- return -1;
- }
smb_fname->st.st_ex_size = AFP_INFO_SIZE;
- smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
+ smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
smb_fname->stream_name);
return 0;
}
}
smb_fname->st.st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
- smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
+ smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
smb_fname->stream_name);
TALLOC_FREE(ad);
return 0;
close(fd);
fd = -1;
- smb_fname->st.st_ex_ino = fruit_inode(&smb_fname->st,
- smb_fname->stream_name);
+ smb_fname->st.st_ex_ino = hash_inode(&smb_fname->st,
+ smb_fname->stream_name);
return ret;
DEBUG(10, ("fruit_stat called for %s\n",
smb_fname_str_dbg(smb_fname)));
- if (!is_ntfs_stream_smb_fname(smb_fname)
- || is_ntfs_default_stream_smb_fname(smb_fname)) {
+ if (!is_named_stream(smb_fname)) {
rc = SMB_VFS_NEXT_STAT(handle, smb_fname);
if (rc == 0) {
update_btime(handle, smb_fname);
* not following links here.
*/
- if (is_afpinfo_stream(smb_fname)) {
+ if (is_afpinfo_stream(smb_fname->stream_name)) {
rc = fruit_stat_meta(handle, smb_fname, true);
- } else if (is_afpresource_stream(smb_fname)) {
+ } else if (is_afpresource_stream(smb_fname->stream_name)) {
rc = fruit_stat_rsrc(handle, smb_fname, true);
} else {
return SMB_VFS_NEXT_STAT(handle, smb_fname);
DEBUG(10, ("fruit_lstat called for %s\n",
smb_fname_str_dbg(smb_fname)));
- if (!is_ntfs_stream_smb_fname(smb_fname)
- || is_ntfs_default_stream_smb_fname(smb_fname)) {
+ if (!is_named_stream(smb_fname)) {
rc = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
if (rc == 0) {
update_btime(handle, smb_fname);
return rc;
}
- if (is_afpinfo_stream(smb_fname)) {
+ if (is_afpinfo_stream(smb_fname->stream_name)) {
rc = fruit_stat_meta(handle, smb_fname, false);
- } else if (is_afpresource_stream(smb_fname)) {
+ } else if (is_afpresource_stream(smb_fname->stream_name)) {
rc = fruit_stat_rsrc(handle, smb_fname, false);
} else {
return SMB_VFS_NEXT_LSTAT(handle, smb_fname);
files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct smb_filename smb_fname;
ino_t ino;
int ret;
*sbuf = fsp->base_fsp->fsp_name->st;
sbuf->st_ex_size = AFP_INFO_SIZE;
- sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
+ sbuf->st_ex_ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
return 0;
}
smb_fname = (struct smb_filename) {
.base_name = fsp->fsp_name->base_name,
+ .twrp = fsp->fsp_name->twrp,
};
ret = fruit_stat_base(handle, &smb_fname, false);
}
*sbuf = smb_fname.st;
- ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
+ ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
if (ret != 0) {
*sbuf = fsp->base_fsp->fsp_name->st;
sbuf->st_ex_size = AFP_INFO_SIZE;
- sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
+ sbuf->st_ex_ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
return 0;
}
files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
struct adouble *ad = NULL;
int ret;
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
/* Populate the stat struct with info from the base file. */
ret = fruit_stat_base(handle, fsp->base_fsp->fsp_name, false);
if (ret == -1) {
return -1;
}
- ad = ad_get(talloc_tos(), handle,
- fsp->base_fsp->fsp_name,
- ADOUBLE_RSRC);
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
- DBG_ERR("ad_get [%s] failed [%s]\n",
- fsp_str_dbg(fsp), strerror(errno));
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
*sbuf = fsp->base_fsp->fsp_name->st;
sbuf->st_ex_size = ad_getentrylen(ad, ADEID_RFORK);
- sbuf->st_ex_ino = fruit_inode(sbuf, fsp->fsp_name->stream_name);
+ sbuf->st_ex_ino = hash_inode(sbuf, fsp->fsp_name->stream_name);
TALLOC_FREE(ad);
return 0;
static int fruit_fstat(vfs_handle_struct *handle, files_struct *fsp,
SMB_STRUCT_STAT *sbuf)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int rc;
if (fio == NULL) {
off_t size)
{
struct smb_filename *sname = NULL;
+ NTSTATUS status;
int ret;
bool ok;
return NT_STATUS_OK;
}
- sname = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- AFPINFO_STREAM_NAME,
- NULL, 0);
- if (sname == NULL) {
+ status = synthetic_pathref(talloc_tos(),
+ handle->conn->cwd_fsp,
+ smb_fname->base_name,
+ AFPINFO_STREAM_NAME,
+ NULL,
+ smb_fname->twrp,
+ 0,
+ &sname);
+ if (!NT_STATUS_IS_OK(status)) {
return NT_STATUS_NO_MEMORY;
}
- ret = SMB_VFS_NEXT_UNLINK(handle, sname);
- TALLOC_FREE(sname);
+ ret = SMB_VFS_NEXT_UNLINKAT(handle,
+ handle->conn->cwd_fsp,
+ sname,
+ 0);
if (ret != 0) {
DBG_ERR("Removing [%s] failed\n", smb_fname_str_dbg(sname));
+ TALLOC_FREE(sname);
return map_nt_error_from_unix(errno);
}
+ TALLOC_FREE(sname);
return NT_STATUS_OK;
}
}
}
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_get_meta_fsp(talloc_tos(), handle, smb_fname);
if (ad == NULL) {
return NT_STATUS_OK;
}
struct fruit_config_data *config = NULL;
NTSTATUS status;
+ if (S_ISDIR(smb_fname->st.st_ex_mode)) {
+ return NT_STATUS_OK;
+ }
+
SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
return NT_STATUS_INTERNAL_ERROR);
*pnum_streams = num_streams;
}
-static NTSTATUS fruit_streaminfo(vfs_handle_struct *handle,
+static NTSTATUS fruit_fstreaminfo(vfs_handle_struct *handle,
struct files_struct *fsp,
- const struct smb_filename *smb_fname,
TALLOC_CTX *mem_ctx,
unsigned int *pnum_streams,
struct stream_struct **pstreams)
{
struct fruit_config_data *config = NULL;
+ const struct smb_filename *smb_fname = NULL;
NTSTATUS status;
+ smb_fname = fsp->fsp_name;
+
SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
return NT_STATUS_UNSUCCESSFUL);
DBG_DEBUG("Path [%s]\n", smb_fname_str_dbg(smb_fname));
- status = SMB_VFS_NEXT_STREAMINFO(handle, fsp, smb_fname, mem_ctx,
+ status = SMB_VFS_NEXT_FSTREAMINFO(handle, fsp, mem_ctx,
pnum_streams, pstreams);
if (!NT_STATUS_IS_OK(status)) {
return status;
return NT_STATUS_OK;
}
-static int fruit_ntimes(vfs_handle_struct *handle,
- const struct smb_filename *smb_fname,
- struct smb_file_time *ft)
+static int fruit_fntimes(vfs_handle_struct *handle,
+ files_struct *fsp,
+ struct smb_file_time *ft)
{
int rc = 0;
struct adouble *ad = NULL;
return -1);
if ((config->meta != FRUIT_META_NETATALK) ||
- null_timespec(ft->create_time))
+ is_omit_timespec(&ft->create_time))
{
- return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
+ return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
}
- DEBUG(10,("set btime for %s to %s\n", smb_fname_str_dbg(smb_fname),
- time_to_asc(convert_timespec_to_time_t(ft->create_time))));
+ DBG_DEBUG("set btime for %s to %s", fsp_str_dbg(fsp),
+ time_to_asc(convert_timespec_to_time_t(ft->create_time)));
- ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_META);
+ ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_META);
if (ad == NULL) {
goto exit;
}
ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX,
convert_time_t_to_uint32_t(ft->create_time.tv_sec));
- rc = ad_set(handle, ad, smb_fname);
+ rc = ad_fset(handle, ad, fsp);
exit:
TALLOC_FREE(ad);
if (rc != 0) {
- DEBUG(1, ("fruit_ntimes: %s\n", smb_fname_str_dbg(smb_fname)));
+ DBG_WARNING("%s\n", fsp_str_dbg(fsp));
return -1;
}
- return SMB_VFS_NEXT_NTIMES(handle, smb_fname, ft);
+ return SMB_VFS_NEXT_FNTIMES(handle, fsp, ft);
}
static int fruit_fallocate(struct vfs_handle_struct *handle,
off_t offset,
off_t len)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
if (fio == NULL) {
return SMB_VFS_NEXT_FALLOCATE(handle, fsp, mode, offset, len);
struct files_struct *fsp,
off_t offset)
{
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int rc;
struct adouble *ad = NULL;
off_t ad_off;
- ad = ad_fget(talloc_tos(), handle, fsp, ADOUBLE_RSRC);
+ if (fio == NULL || fio->ad_fsp == NULL) {
+ DBG_ERR("fio/ad_fsp=NULL for [%s]\n", fsp_str_dbg(fsp));
+ errno = EBADF;
+ return -1;
+ }
+
+ ad = ad_fget(talloc_tos(), handle, fio->ad_fsp, ADOUBLE_RSRC);
if (ad == NULL) {
- DBG_DEBUG("ad_get [%s] failed [%s]\n",
- fsp_str_dbg(fsp), strerror(errno));
+ DBG_ERR("ad_fget [%s] failed [%s]\n",
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
return -1;
}
ad_off = ad_getentryoff(ad, ADEID_RFORK);
- rc = ftruncate(fsp->fh->fd, offset + ad_off);
+ rc = SMB_VFS_NEXT_FTRUNCATE(handle, fio->ad_fsp, offset + ad_off);
if (rc != 0) {
TALLOC_FREE(ad);
return -1;
ad_setentrylen(ad, ADEID_RFORK, offset);
- rc = ad_fset(handle, ad, fsp);
+ rc = ad_fset(handle, ad, fio->ad_fsp);
if (rc != 0) {
DBG_ERR("ad_fset [%s] failed [%s]\n",
- fsp_str_dbg(fsp), strerror(errno));
+ fsp_str_dbg(fio->ad_fsp), strerror(errno));
TALLOC_FREE(ad);
return -1;
}
struct files_struct *fsp,
off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int ret;
if (fio == NULL) {
- DBG_ERR("Failed to fetch fsp extension");
+ DBG_ERR("Failed to fetch fsp extension\n");
return -1;
}
off_t offset)
{
if (offset > 60) {
- DBG_WARNING("ftruncate %s to %jd",
+ DBG_WARNING("ftruncate %s to %jd\n",
fsp_str_dbg(fsp), (intmax_t)offset);
/* OS X returns NT_STATUS_ALLOTTED_SPACE_EXCEEDED */
errno = EOVERFLOW;
struct files_struct *fsp,
off_t offset)
{
- struct fio *fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct fio *fio = fruit_get_complete_fio(handle, fsp);
int ret;
DBG_DEBUG("Path [%s] offset [%"PRIdMAX"]\n", fsp_str_dbg(fsp),
static NTSTATUS fruit_create_file(vfs_handle_struct *handle,
struct smb_request *req,
- uint16_t root_dir_fid,
+ struct files_struct *dirfsp,
struct smb_filename *smb_fname,
uint32_t access_mask,
uint32_t share_access,
uint32_t create_options,
uint32_t file_attributes,
uint32_t oplock_request,
- struct smb2_lease *lease,
+ const struct smb2_lease *lease,
uint64_t allocation_size,
uint32_t private_flags,
struct security_descriptor *sd,
NTSTATUS status;
struct fruit_config_data *config = NULL;
files_struct *fsp = NULL;
- struct fio *fio = NULL;
bool internal_open = (oplock_request & INTERNAL_OPEN_ONLY);
int ret;
SMB_VFS_HANDLE_GET_DATA(handle, config, struct fruit_config_data,
return NT_STATUS_UNSUCCESSFUL);
- if (is_apple_stream(smb_fname) && !internal_open) {
- ret = ad_convert(handle, smb_fname);
+ if (is_apple_stream(smb_fname->stream_name) &&
+ !internal_open &&
+ config->convert_adouble)
+ {
+ uint32_t conv_flags = 0;
+
+ if (config->wipe_intentionally_left_blank_rfork) {
+ conv_flags |= AD_CONV_WIPE_BLANK;
+ }
+ if (config->delete_empty_adfiles) {
+ conv_flags |= AD_CONV_DELETE;
+ }
+
+ ret = ad_convert(handle,
+ smb_fname,
+ macos_string_replace_map,
+ conv_flags);
if (ret != 0) {
- DBG_ERR("ad_convert() failed\n");
- return NT_STATUS_UNSUCCESSFUL;
+ DBG_ERR("ad_convert(\"%s\") failed\n",
+ smb_fname_str_dbg(smb_fname));
}
}
status = SMB_VFS_NEXT_CREATE_FILE(
- handle, req, root_dir_fid, smb_fname,
+ handle, req, dirfsp, smb_fname,
access_mask, share_access,
create_disposition, create_options,
file_attributes, oplock_request,
fsp = *result;
if (global_fruit_config.nego_aapl) {
- if (config->posix_rename && fsp->is_directory) {
+ if (config->posix_rename && fsp->fsp_flags.is_directory) {
/*
* Enable POSIX directory rename behaviour
*/
if (global_fruit_config.nego_aapl &&
create_disposition == FILE_OPEN &&
smb_fname->st.st_ex_size == 0 &&
- is_ntfs_stream_smb_fname(smb_fname) &&
- !(is_ntfs_default_stream_smb_fname(smb_fname)))
+ is_named_stream(smb_fname))
{
status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
goto fail;
}
- fio = (struct fio *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
- if (fio != NULL && pinfo != NULL && *pinfo == FILE_WAS_CREATED) {
- fio->created = true;
- }
-
- if (is_ntfs_stream_smb_fname(smb_fname)
- || fsp->is_directory) {
+ if (is_named_stream(smb_fname) || fsp->fsp_flags.is_directory) {
return status;
}
if ((config->locking == FRUIT_LOCKING_NETATALK) &&
- (fsp->op != NULL))
+ (fsp->op != NULL) &&
+ !fsp->fsp_flags.is_pathref)
{
status = fruit_check_access(
handle, *result,
DEBUG(10, ("fruit_create_file: %s\n", nt_errstr(status)));
if (fsp) {
- close_file(req, fsp, ERROR_CLOSE);
- *result = fsp = NULL;
+ close_file_free(req, &fsp, ERROR_CLOSE);
+ *result = NULL;
}
return status;
}
-static NTSTATUS fruit_readdir_attr(struct vfs_handle_struct *handle,
- const struct smb_filename *fname,
- TALLOC_CTX *mem_ctx,
- struct readdir_attr_data **pattr_data)
+static NTSTATUS fruit_freaddir_attr(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ TALLOC_CTX *mem_ctx,
+ struct readdir_attr_data **pattr_data)
{
struct fruit_config_data *config = NULL;
struct readdir_attr_data *attr_data;
+ uint32_t conv_flags = 0;
NTSTATUS status;
int ret;
return NT_STATUS_UNSUCCESSFUL);
if (!global_fruit_config.nego_aapl) {
- return SMB_VFS_NEXT_READDIR_ATTR(handle, fname, mem_ctx, pattr_data);
+ return SMB_VFS_NEXT_FREADDIR_ATTR(handle,
+ fsp,
+ mem_ctx,
+ pattr_data);
}
- DEBUG(10, ("fruit_readdir_attr %s\n", fname->base_name));
+ DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
- ret = ad_convert(handle, fname);
- if (ret != 0) {
- DBG_ERR("ad_convert() failed\n");
- return NT_STATUS_UNSUCCESSFUL;
+ if (config->convert_adouble) {
+ if (config->wipe_intentionally_left_blank_rfork) {
+ conv_flags |= AD_CONV_WIPE_BLANK;
+ }
+ if (config->delete_empty_adfiles) {
+ conv_flags |= AD_CONV_DELETE;
+ }
+
+ ret = ad_convert(handle,
+ fsp->fsp_name,
+ macos_string_replace_map,
+ conv_flags);
+ if (ret != 0) {
+ DBG_ERR("ad_convert(\"%s\") failed\n",
+ fsp_str_dbg(fsp));
+ }
}
*pattr_data = talloc_zero(mem_ctx, struct readdir_attr_data);
if (*pattr_data == NULL) {
- return NT_STATUS_UNSUCCESSFUL;
+ return NT_STATUS_NO_MEMORY;
}
attr_data = *pattr_data;
attr_data->type = RDATTR_AAPL;
* Mac metadata: compressed FinderInfo, resource fork length
* and creation date
*/
- status = readdir_attr_macmeta(handle, fname, attr_data);
+ status = readdir_attr_macmeta(handle, fsp->fsp_name, attr_data);
if (!NT_STATUS_IS_OK(status)) {
/*
* Error handling is tricky: if we return failure from
* UNIX mode
*/
if (config->unix_info_enabled) {
- attr_data->attr_data.aapl.unix_mode = fname->st.st_ex_mode;
+ attr_data->attr_data.aapl.unix_mode =
+ fsp->fsp_name->st.st_ex_mode;
}
/*
if (!config->readdir_attr_max_access) {
attr_data->attr_data.aapl.max_access = FILE_GENERIC_ALL;
} else {
- status = smbd_calculate_access_mask(
- handle->conn,
- fname,
+ status = smbd_calculate_access_mask_fsp(fsp->conn->cwd_fsp,
+ fsp,
false,
SEC_FLAG_MAXIMUM_ALLOWED,
&attr_data->attr_data.aapl.max_access);
return NT_STATUS_OK;
fail:
- DEBUG(1, ("fruit_readdir_attr %s, error: %s\n",
- fname->base_name, nt_errstr(status)));
+ DBG_WARNING("Path [%s], error: %s\n", fsp_str_dbg(fsp),
+ nt_errstr(status));
TALLOC_FREE(*pattr_data);
return status;
}
return NT_STATUS_NO_MEMORY;
}
- DBG_DEBUG("fruit_fset_nt_acl: %s\n", fsp_str_dbg(fsp));
+ DBG_DEBUG("%s\n", fsp_str_dbg(fsp));
status = check_ms_nfs(handle, fsp, psd, &ms_nfs_mode, &do_chmod);
if (!NT_STATUS_IS_OK(status)) {
}
if (do_chmod) {
- if (fsp->fh->fd != -1) {
- result = SMB_VFS_FCHMOD(fsp, ms_nfs_mode);
- } else {
- result = SMB_VFS_CHMOD(fsp->conn,
- fsp->fsp_name,
- ms_nfs_mode);
- }
-
+ result = SMB_VFS_FCHMOD(fsp, ms_nfs_mode);
if (result != 0) {
- DEBUG(1, ("chmod: %s, result: %d, %04o error %s\n", fsp_str_dbg(fsp),
- result, (unsigned)ms_nfs_mode,
- strerror(errno)));
+ DBG_WARNING("%s, result: %d, %04o error %s\n",
+ fsp_str_dbg(fsp),
+ result,
+ (unsigned)ms_nfs_mode,
+ strerror(errno));
status = map_nt_error_from_unix(errno);
TALLOC_FREE(psd);
return status;
struct tevent_context *ev;
files_struct *fsp;
uint32_t fsctl;
+ uint32_t flags;
+ uint64_t xferlen;
DATA_BLOB token;
};
status = SMB_VFS_NEXT_OFFLOAD_READ_RECV(subreq,
state->handle,
state,
+ &state->flags,
+ &state->xferlen,
&state->token);
TALLOC_FREE(subreq);
if (tevent_req_nterror(req, status)) {
static NTSTATUS fruit_offload_read_recv(struct tevent_req *req,
struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
+ uint32_t *flags,
+ uint64_t *xferlen,
DATA_BLOB *token)
{
struct fruit_offload_read_state *state = tevent_req_data(
return status;
}
+ *flags = state->flags;
+ *xferlen = state->xferlen;
token->length = state->token.length;
token->data = talloc_move(mem_ctx, &state->token.data);
* streams, because we're in vfs_fruit. We don't do this async
* because streams are few and small.
*/
- status = vfs_streaminfo(state->handle->conn, state->src_fsp,
- state->src_fsp->fsp_name,
+ status = vfs_fstreaminfo(state->src_fsp,
req, &num_streams, &streams);
if (tevent_req_nterror(req, status)) {
return;
state->src_fsp->fsp_name->base_name,
streams[i].name,
NULL,
+ state->src_fsp->fsp_name->twrp,
state->src_fsp->fsp_name->flags);
if (tevent_req_nomem(src_fname_tmp, req)) {
return;
state->dst_fsp->fsp_name->base_name,
streams[i].name,
NULL,
+ state->dst_fsp->fsp_name->twrp,
state->dst_fsp->fsp_name->flags);
if (tevent_req_nomem(dst_fname_tmp, req)) {
TALLOC_FREE(src_fname_tmp);
state->handle->conn,
src_fname_tmp,
dst_fname_tmp,
- OPENX_FILE_CREATE_IF_NOT_EXIST,
- 0, false);
+ FILE_CREATE);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("%s: copy %s to %s failed: %s\n", __func__,
smb_fname_str_dbg(src_fname_tmp),
goto out;
}
- smb_fname = synthetic_smb_fname(talloc_tos(), plist, NULL, NULL, 0);
+ smb_fname = synthetic_smb_fname(talloc_tos(),
+ plist,
+ NULL,
+ NULL,
+ 0,
+ 0);
if (smb_fname == NULL) {
ok = false;
goto out;
status = SMB_VFS_NEXT_CREATE_FILE(
handle, /* conn */
NULL, /* req */
- 0, /* root_dir_fid */
+ NULL, /* dirfsp */
smb_fname, /* fname */
FILE_GENERIC_READ, /* access_mask */
FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
goto out;
}
- file_data = talloc_array(talloc_tos(), uint8_t, plist_file_size);
+ file_data = talloc_zero_array(talloc_tos(),
+ uint8_t,
+ plist_file_size + 1);
if (file_data == NULL) {
ok = false;
goto out;
}
- status = close_file(NULL, fsp, NORMAL_CLOSE);
- fsp = NULL;
+ status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("close_file failed: %s\n", nt_errstr(status));
ok = false;
out:
if (fsp != NULL) {
- status = close_file(NULL, fsp, NORMAL_CLOSE);
+ status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("close_file failed: %s\n", nt_errstr(status));
}
- fsp = NULL;
}
TALLOC_FREE(plist);
TALLOC_FREE(smb_fname);
};
static bool fruit_get_num_bands(vfs_handle_struct *handle,
- char *bundle,
+ const char *bundle,
size_t *_nbands)
{
char *path = NULL;
struct smb_filename *bands_dir = NULL;
- DIR *d = NULL;
- struct dirent *e = NULL;
+ struct smb_Dir *dir_hnd = NULL;
+ const char *dname = NULL;
+ char *talloced = NULL;
size_t nbands;
- int ret;
+ NTSTATUS status;
path = talloc_asprintf(talloc_tos(),
"%s/%s/bands",
path,
NULL,
NULL,
+ 0,
0);
TALLOC_FREE(path);
if (bands_dir == NULL) {
return false;
}
- d = SMB_VFS_NEXT_OPENDIR(handle, bands_dir, NULL, 0);
- if (d == NULL) {
+ status = OpenDir(talloc_tos(),
+ handle->conn,
+ bands_dir,
+ NULL,
+ 0,
+ &dir_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(bands_dir);
+ errno = map_errno_from_nt_status(status);
return false;
}
nbands = 0;
- for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
- e != NULL;
- e = SMB_VFS_NEXT_READDIR(handle, d, NULL))
- {
- if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) {
+ while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
continue;
}
nbands++;
}
-
- ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
- if (ret != 0) {
- TALLOC_FREE(bands_dir);
- return false;
- }
+ TALLOC_FREE(dir_hnd);
DBG_DEBUG("%zu bands in [%s]\n", nbands, smb_fname_str_dbg(bands_dir));
static bool fruit_tmsize_do_dirent(vfs_handle_struct *handle,
struct fruit_disk_free_state *state,
- struct dirent *e)
+ const char *name)
{
bool ok;
char *p = NULL;
size_t nbands;
off_t tm_size;
- p = strstr(e->d_name, "sparsebundle");
+ p = strstr(name, "sparsebundle");
if (p == NULL) {
return true;
}
return true;
}
- DBG_DEBUG("Processing sparsebundle [%s]\n", e->d_name);
+ DBG_DEBUG("Processing sparsebundle [%s]\n", name);
- ok = fruit_get_bandsize(handle, e->d_name, &bandsize);
+ ok = fruit_get_bandsize(handle, name, &bandsize);
if (!ok) {
/*
* Beware of race conditions: this may be an uninitialized
* Info.plist that a client is just creating. We don't want let
* this to trigger complete failure.
*/
- DBG_ERR("Processing sparsebundle [%s] failed\n", e->d_name);
+ DBG_ERR("Processing sparsebundle [%s] failed\n", name);
return true;
}
- ok = fruit_get_num_bands(handle, e->d_name, &nbands);
+ ok = fruit_get_num_bands(handle, name, &nbands);
if (!ok) {
/*
* Beware of race conditions: this may be a backup sparsebundle
* in an early stage lacking a bands subdirectory. We don't want
* let this to trigger complete failure.
*/
- DBG_ERR("Processing sparsebundle [%s] failed\n", e->d_name);
+ DBG_ERR("Processing sparsebundle [%s] failed\n", name);
return true;
}
+ /*
+ * Arithmetic on 32-bit systems may cause overflow, depending on
+ * size_t precision. First we check its unlikely, then we
+ * force the precision into target off_t, then we check that
+ * the total did not overflow either.
+ */
if (bandsize > SIZE_MAX/nbands) {
- DBG_ERR("tmsize overflow: bandsize [%zu] nbands [%zu]\n",
+ DBG_ERR("tmsize potential overflow: bandsize [%zu] nbands [%zu]\n",
bandsize, nbands);
return false;
}
- tm_size = bandsize * nbands;
+ tm_size = (off_t)bandsize * (off_t)nbands;
if (state->total_size + tm_size < state->total_size) {
- DBG_ERR("tmsize overflow: bandsize [%zu] nbands [%zu]\n",
+ DBG_ERR("tm total size overflow: bandsize [%zu] nbands [%zu]\n",
bandsize, nbands);
return false;
}
state->total_size += tm_size;
DBG_DEBUG("[%s] tm_size [%jd] total_size [%jd]\n",
- e->d_name, (intmax_t)tm_size, (intmax_t)state->total_size);
+ name, (intmax_t)tm_size, (intmax_t)state->total_size);
return true;
}
{
struct fruit_config_data *config = NULL;
struct fruit_disk_free_state state = {0};
- DIR *d = NULL;
- struct dirent *e = NULL;
+ struct smb_Dir *dir_hnd = NULL;
+ const char *dname = NULL;
+ char *talloced = NULL;
uint64_t dfree;
uint64_t dsize;
- int ret;
bool ok;
+ NTSTATUS status;
SMB_VFS_HANDLE_GET_DATA(handle, config,
struct fruit_config_data,
_dsize);
}
- d = SMB_VFS_NEXT_OPENDIR(handle, smb_fname, NULL, 0);
- if (d == NULL) {
+ status = OpenDir(talloc_tos(),
+ handle->conn,
+ smb_fname,
+ NULL,
+ 0,
+ &dir_hnd);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
return UINT64_MAX;
}
- for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
- e != NULL;
- e = SMB_VFS_NEXT_READDIR(handle, d, NULL))
- {
- ok = fruit_tmsize_do_dirent(handle, &state, e);
+ while ((dname = ReadDirName(dir_hnd, &talloced)) != NULL) {
+ ok = fruit_tmsize_do_dirent(handle, &state, dname);
if (!ok) {
- SMB_VFS_NEXT_CLOSEDIR(handle, d);
+ TALLOC_FREE(talloced);
+ TALLOC_FREE(dir_hnd);
return UINT64_MAX;
}
+ TALLOC_FREE(talloced);
}
- ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
- if (ret != 0) {
- return UINT64_MAX;
- }
+ TALLOC_FREE(dir_hnd);
dsize = config->time_machine_max_size / 512;
dfree = dsize - (state.total_size / 512);
return dfree / 2;
}
+static uint64_t fruit_fs_file_id(struct vfs_handle_struct *handle,
+ const SMB_STRUCT_STAT *psbuf)
+{
+ struct fruit_config_data *config = NULL;
+
+ SMB_VFS_HANDLE_GET_DATA(handle, config,
+ struct fruit_config_data,
+ return 0);
+
+ if (global_fruit_config.nego_aapl &&
+ config->aapl_zero_file_id)
+ {
+ return 0;
+ }
+
+ return SMB_VFS_NEXT_FS_FILE_ID(handle, psbuf);
+}
+
static struct vfs_fn_pointers vfs_fruit_fns = {
.connect_fn = fruit_connect,
.disk_free_fn = fruit_disk_free,
/* File operations */
- .chmod_fn = fruit_chmod,
- .chown_fn = fruit_chown,
- .unlink_fn = fruit_unlink,
- .rename_fn = fruit_rename,
- .rmdir_fn = fruit_rmdir,
- .open_fn = fruit_open,
+ .fchmod_fn = fruit_fchmod,
+ .unlinkat_fn = fruit_unlinkat,
+ .renameat_fn = fruit_renameat,
+ .openat_fn = fruit_openat,
.close_fn = fruit_close,
.pread_fn = fruit_pread,
.pwrite_fn = fruit_pwrite,
.pread_recv_fn = fruit_pread_recv,
.pwrite_send_fn = fruit_pwrite_send,
.pwrite_recv_fn = fruit_pwrite_recv,
+ .fsync_send_fn = fruit_fsync_send,
+ .fsync_recv_fn = fruit_fsync_recv,
.stat_fn = fruit_stat,
.lstat_fn = fruit_lstat,
.fstat_fn = fruit_fstat,
- .streaminfo_fn = fruit_streaminfo,
- .ntimes_fn = fruit_ntimes,
+ .fstreaminfo_fn = fruit_fstreaminfo,
+ .fntimes_fn = fruit_fntimes,
.ftruncate_fn = fruit_ftruncate,
.fallocate_fn = fruit_fallocate,
.create_file_fn = fruit_create_file,
- .readdir_attr_fn = fruit_readdir_attr,
+ .freaddir_attr_fn = fruit_freaddir_attr,
.offload_read_send_fn = fruit_offload_read_send,
.offload_read_recv_fn = fruit_offload_read_recv,
.offload_write_send_fn = fruit_offload_write_send,
.offload_write_recv_fn = fruit_offload_write_recv,
+ .fs_file_id_fn = fruit_fs_file_id,
/* NT ACL operations */
.fget_nt_acl_fn = fruit_fget_nt_acl,