Fix one missing STAT -> LSTAT with POSIX pathnames in vfs_xattr_tdb.c. Caught by...
[ira/wip.git] / source3 / modules / vfs_xattr_tdb.c
index c707a1828f146641d1b2482cbabc58b3421f64d1..f7fbfce4cb979f2232d9c301a78faab41996e5b1 100644 (file)
@@ -100,6 +100,7 @@ static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
        NTSTATUS status;
        TDB_DATA data;
 
+       /* For backwards compatibility only store the dev/inode. */
        push_file_id_16((char *)id_buf, id);
 
        if (db_ctx->fetch(db_ctx, mem_ctx,
@@ -122,6 +123,8 @@ static struct db_record *xattr_tdb_lock_attrs(TALLOC_CTX *mem_ctx,
                                              const struct file_id *id)
 {
        uint8 id_buf[16];
+
+       /* For backwards compatibility only store the dev/inode. */
        push_file_id_16((char *)id_buf, id);
        return db_ctx->fetch_locked(db_ctx, mem_ctx,
                                    make_tdb_data(id_buf, sizeof(id_buf)));
@@ -177,25 +180,25 @@ static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
                return -1;
        }
 
-       for (i=0; i<attribs->num_xattrs; i++) {
-               if (strcmp(attribs->xattrs[i].name, name) == 0) {
+       for (i=0; i<attribs->num_eas; i++) {
+               if (strcmp(attribs->eas[i].name, name) == 0) {
                        break;
                }
        }
 
-       if (i == attribs->num_xattrs) {
+       if (i == attribs->num_eas) {
                errno = ENOATTR;
                goto fail;
        }
 
-       if (attribs->xattrs[i].value.length > size) {
+       if (attribs->eas[i].value.length > size) {
                errno = ERANGE;
                goto fail;
        }
 
-       memcpy(value, attribs->xattrs[i].value.data,
-              attribs->xattrs[i].value.length);
-       result = attribs->xattrs[i].value.length;
+       memcpy(value, attribs->eas[i].value.data,
+              attribs->eas[i].value.length);
+       result = attribs->eas[i].value.length;
 
  fail:
        TALLOC_FREE(attribs);
@@ -212,11 +215,11 @@ static ssize_t xattr_tdb_getxattr(struct vfs_handle_struct *handle,
 
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
-       if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_getattr(db, &id, name, value, size);
 }
@@ -235,7 +238,7 @@ static ssize_t xattr_tdb_fgetxattr(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_getattr(db, &id, name, value, size);
 }
@@ -273,8 +276,8 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
                return -1;
        }
 
-       for (i=0; i<attribs->num_xattrs; i++) {
-               if (strcmp(attribs->xattrs[i].name, name) == 0) {
+       for (i=0; i<attribs->num_eas; i++) {
+               if (strcmp(attribs->eas[i].name, name) == 0) {
                        if (flags & XATTR_CREATE) {
                                TALLOC_FREE(rec);
                                errno = EEXIST;
@@ -284,8 +287,8 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
                }
        }
 
-       if (i == attribs->num_xattrs) {
-               struct tdb_xattr *tmp;
+       if (i == attribs->num_eas) {
+               struct xattr_EA *tmp;
 
                if (flags & XATTR_REPLACE) {
                        TALLOC_FREE(rec);
@@ -294,8 +297,8 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
                }
 
                tmp = TALLOC_REALLOC_ARRAY(
-                       attribs, attribs->xattrs, struct tdb_xattr,
-                       attribs->num_xattrs + 1);
+                       attribs, attribs->eas, struct xattr_EA,
+                       attribs->num_eas+ 1);
 
                if (tmp == NULL) {
                        DEBUG(0, ("TALLOC_REALLOC_ARRAY failed\n"));
@@ -304,13 +307,13 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
                        return -1;
                }
 
-               attribs->xattrs = tmp;
-               attribs->num_xattrs += 1;
+               attribs->eas = tmp;
+               attribs->num_eas += 1;
        }
 
-       attribs->xattrs[i].name = name;
-       attribs->xattrs[i].value.data = CONST_DISCARD(uint8 *, value);
-       attribs->xattrs[i].value.length = size;
+       attribs->eas[i].name = name;
+       attribs->eas[i].value.data = CONST_DISCARD(uint8 *, value);
+       attribs->eas[i].value.length = size;
 
        status = xattr_tdb_save_attrs(rec, attribs);
 
@@ -334,11 +337,11 @@ static int xattr_tdb_setxattr(struct vfs_handle_struct *handle,
 
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
-       if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_setattr(db, &id, name, value, size, flags);
 }
@@ -358,7 +361,7 @@ static int xattr_tdb_fsetxattr(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_setattr(db, &id, name, value, size, flags);
 }
@@ -386,15 +389,15 @@ static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
        }
 
        DEBUG(10, ("xattr_tdb_listattr: Found %d xattrs\n",
-                  attribs->num_xattrs));
+                  attribs->num_eas));
 
-       for (i=0; i<attribs->num_xattrs; i++) {
+       for (i=0; i<attribs->num_eas; i++) {
                size_t tmp;
 
                DEBUG(10, ("xattr_tdb_listattr: xattrs[i].name: %s\n",
-                          attribs->xattrs[i].name));
+                          attribs->eas[i].name));
 
-               tmp = strlen(attribs->xattrs[i].name);
+               tmp = strlen(attribs->eas[i].name);
 
                /*
                 * Try to protect against overflow
@@ -420,10 +423,10 @@ static ssize_t xattr_tdb_listattr(struct db_context *db_ctx,
 
        len = 0;
 
-       for (i=0; i<attribs->num_xattrs; i++) {
-               strlcpy(list+len, attribs->xattrs[i].name,
+       for (i=0; i<attribs->num_eas; i++) {
+               strlcpy(list+len, attribs->eas[i].name,
                        size-len);
-               len += (strlen(attribs->xattrs[i].name) + 1);
+               len += (strlen(attribs->eas[i].name) + 1);
        }
 
        TALLOC_FREE(attribs);
@@ -439,11 +442,11 @@ static ssize_t xattr_tdb_listxattr(struct vfs_handle_struct *handle,
 
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
-       if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_listattr(db, &id, list, size);
 }
@@ -462,7 +465,7 @@ static ssize_t xattr_tdb_flistxattr(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_listattr(db, &id, list, size);
 }
@@ -496,23 +499,23 @@ static int xattr_tdb_removeattr(struct db_context *db_ctx,
                return -1;
        }
 
-       for (i=0; i<attribs->num_xattrs; i++) {
-               if (strcmp(attribs->xattrs[i].name, name) == 0) {
+       for (i=0; i<attribs->num_eas; i++) {
+               if (strcmp(attribs->eas[i].name, name) == 0) {
                        break;
                }
        }
 
-       if (i == attribs->num_xattrs) {
+       if (i == attribs->num_eas) {
                TALLOC_FREE(rec);
                errno = ENOATTR;
                return -1;
        }
 
-       attribs->xattrs[i] =
-               attribs->xattrs[attribs->num_xattrs-1];
-       attribs->num_xattrs -= 1;
+       attribs->eas[i] =
+               attribs->eas[attribs->num_eas-1];
+       attribs->num_eas -= 1;
 
-       if (attribs->num_xattrs == 0) {
+       if (attribs->num_eas == 0) {
                rec->delete_rec(rec);
                TALLOC_FREE(rec);
                return 0;
@@ -539,11 +542,11 @@ static int xattr_tdb_removexattr(struct vfs_handle_struct *handle,
 
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
-       if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_removeattr(db, &id, name);
 }
@@ -561,7 +564,7 @@ static int xattr_tdb_fremovexattr(struct vfs_handle_struct *handle,
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        return xattr_tdb_removeattr(db, &id, name);
 }
@@ -574,15 +577,18 @@ static bool xattr_tdb_init(int snum, struct db_context **p_db)
 {
        struct db_context *db;
        const char *dbname;
+       char *def_dbname;
 
-       dbname = lp_parm_const_string(snum, "xattr_tdb", "file",
-                                     lock_path("xattr.tdb"));
-
-       if (dbname == NULL) {
+       def_dbname = state_path("xattr.tdb");
+       if (def_dbname == NULL) {
                errno = ENOSYS;
                return false;
        }
 
+       dbname = lp_parm_const_string(snum, "xattr_tdb", "file", def_dbname);
+
+       /* now we know dbname is not NULL */
+
        become_root();
        db = db_open(NULL, dbname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
        unbecome_root();
@@ -593,37 +599,62 @@ static bool xattr_tdb_init(int snum, struct db_context **p_db)
 #else
                errno = ENOSYS;
 #endif
+               TALLOC_FREE(def_dbname);
                return false;
        }
 
        *p_db = db;
+       TALLOC_FREE(def_dbname);
        return true;
 }
 
 /*
  * On unlink we need to delete the tdb record
  */
-static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path)
+static int xattr_tdb_unlink(vfs_handle_struct *handle,
+                           const struct smb_filename *smb_fname)
 {
-       SMB_STRUCT_STAT sbuf;
+       struct smb_filename *smb_fname_tmp = NULL;
        struct file_id id;
        struct db_context *db;
        struct db_record *rec;
-       int ret;
+       NTSTATUS status;
+       int ret = -1;
+       bool remove_record = false;
 
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
-       if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+       status = copy_smb_filename(talloc_tos(), smb_fname, &smb_fname_tmp);
+       if (!NT_STATUS_IS_OK(status)) {
+               errno = map_errno_from_nt_status(status);
                return -1;
        }
 
-       ret = SMB_VFS_NEXT_UNLINK(handle, path);
+       if (lp_posix_pathnames()) {
+               ret = SMB_VFS_LSTAT(handle->conn, smb_fname_tmp);
+       } else {
+               ret = SMB_VFS_STAT(handle->conn, smb_fname_tmp);
+       }
+       if (ret == -1) {
+               goto out;
+       }
+
+       if (smb_fname_tmp->st.st_ex_nlink == 1) {
+               /* Only remove record on last link to file. */
+               remove_record = true;
+       }
+
+       ret = SMB_VFS_NEXT_UNLINK(handle, smb_fname_tmp);
 
        if (ret == -1) {
-               return -1;
+               goto out;
+       }
+
+       if (!remove_record) {
+               goto out;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &smb_fname_tmp->st);
 
        rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
 
@@ -636,7 +667,9 @@ static int xattr_tdb_unlink(vfs_handle_struct *handle, const char *path)
                TALLOC_FREE(rec);
        }
 
-       return 0;
+ out:
+       TALLOC_FREE(smb_fname_tmp);
+       return ret;
 }
 
 /*
@@ -652,7 +685,7 @@ static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
 
        SMB_VFS_HANDLE_GET_DATA(handle, db, struct db_context, return -1);
 
-       if (SMB_VFS_STAT(handle->conn, path, &sbuf) == -1) {
+       if (vfs_stat_smb_fname(handle->conn, path, &sbuf) == -1) {
                return -1;
        }
 
@@ -662,7 +695,7 @@ static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
                return -1;
        }
 
-       id = SMB_VFS_FILE_ID_CREATE(handle->conn, sbuf.st_dev, sbuf.st_ino);
+       id = SMB_VFS_FILE_ID_CREATE(handle->conn, &sbuf);
 
        rec = xattr_tdb_lock_attrs(talloc_tos(), db, &id);
 
@@ -723,37 +756,23 @@ static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
        return 0;
 }
 
-/* VFS operations structure */
-
-static const vfs_op_tuple xattr_tdb_ops[] = {
-       {SMB_VFS_OP(xattr_tdb_getxattr), SMB_VFS_OP_GETXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_fgetxattr), SMB_VFS_OP_FGETXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_setxattr), SMB_VFS_OP_SETXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_fsetxattr), SMB_VFS_OP_FSETXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_listxattr), SMB_VFS_OP_LISTXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_flistxattr), SMB_VFS_OP_FLISTXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_removexattr), SMB_VFS_OP_REMOVEXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_fremovexattr), SMB_VFS_OP_FREMOVEXATTR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_unlink), SMB_VFS_OP_UNLINK,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_rmdir), SMB_VFS_OP_RMDIR,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(xattr_tdb_connect), SMB_VFS_OP_CONNECT,
-        SMB_VFS_LAYER_TRANSPARENT},
-       {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+static struct vfs_fn_pointers vfs_xattr_tdb_fns = {
+       .getxattr = xattr_tdb_getxattr,
+       .fgetxattr = xattr_tdb_fgetxattr,
+       .setxattr = xattr_tdb_setxattr,
+       .fsetxattr = xattr_tdb_fsetxattr,
+       .listxattr = xattr_tdb_listxattr,
+       .flistxattr = xattr_tdb_flistxattr,
+       .removexattr = xattr_tdb_removexattr,
+       .fremovexattr = xattr_tdb_fremovexattr,
+       .unlink = xattr_tdb_unlink,
+       .rmdir = xattr_tdb_rmdir,
+       .connect_fn = xattr_tdb_connect,
 };
 
 NTSTATUS vfs_xattr_tdb_init(void);
 NTSTATUS vfs_xattr_tdb_init(void)
 {
        return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "xattr_tdb",
-                               xattr_tdb_ops);
+                               &vfs_xattr_tdb_fns);
 }