netatalk  4.6.0
Free and Open Source Apple Filing Protocol (AFP) Server
Loading...
Searching...
No Matches
ofork.c File Reference
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
#include <bstrlib.h>
#include <atalk/ea.h>
#include <atalk/fce_api.h>
#include <atalk/globals.h>
#include <atalk/logger.h>
#include <atalk/server_ipc.h>
#include <atalk/spotlight.h>
#include <atalk/unix.h>
#include <atalk/util.h>
#include "ad_cache.h"
#include "desktop.h"
#include "dircache.h"
#include "directory.h"
#include "fork.h"
#include "virtual_icon.h"
#include "volume.h"

Macros

#define OFORK_HASHSIZE   64

Functions

static unsigned long hashfn (const struct file_key *key)
static void of_hash (struct ofork *of)
static void of_unhash (struct ofork *of)
static bool of_freeq_empty (void)
static void of_freeq_push (uint16_t slot)
static int of_freeq_pop (void)
void of_pforkdesc (FILE *f)
int of_flush (const struct vol *vol)
int of_rename (const struct vol *vol, struct ofork *s_of, struct dir *olddir, const char *oldpath, struct dir *newdir, const char *newpath)
struct oforkof_alloc (struct vol *vol, struct dir *dir, char *path, uint16_t *ofrefnum, const int eid, struct adouble *ad, struct stat *st)
struct oforkof_find (const uint16_t ofrefnum)
int of_stat (const struct vol *vol, struct path *path)
int of_fstatat (int dirfd, struct path *path)
int of_statdir (struct vol *vol, struct path *path)
 stat the current directory.
struct oforkof_findname (const struct vol *vol, struct path *path)
struct oforkof_findnameat (int dirfd, struct path *path)
 Search for open fork by dirfd/name.
int of_delete_blocked (const struct ofork *of, uint16_t *band, int *content)
 Does this child hold a delete-blocking claim on the fork's file?
void of_close_inode_forks (const AFPObj *obj, const struct vol *vol, struct path *path)
 Close every fork this child holds on path's inode.
int of_get_locks (const struct vol *vol, int dirfd, struct path *path, int df_get, off_t df_off, off_t df_len, int rf_get, off_t rf_off, off_t rf_len, uint16_t band_request, int try_root, int *df_locked, int *rf_locked, uint16_t *band_held)
 Conflict GET (F_GETLK only): read another holder's locks on a file.
void of_dealloc (struct ofork *of)
void of_log_highwater (void)
int of_closefork (const AFPObj *obj, struct ofork *ofork)
struct adoubleof_ad (const struct vol *vol, struct path *path, struct adouble *ad)
void of_closevol (const AFPObj *obj, const struct vol *vol)
void of_close_all_forks (const AFPObj *obj)

Variables

static struct oforkofork_table [OFORK_HASHSIZE]
static struct ofork ** oforks = NULL
static int nforks = 0
static uint16_t * of_freeq = NULL
static int of_freeq_cap = 0
static int of_freeq_head = 0
static int of_freeq_tail = 0
static int of_curr_forks = 0
static int of_peak_forks = 0

Macro Definition Documentation

◆ OFORK_HASHSIZE

#define OFORK_HASHSIZE   64

Function Documentation

◆ hashfn()

unsigned long hashfn ( const struct file_key * key)
static

◆ of_ad()

struct adouble * of_ad ( const struct vol * vol,
struct path * path,
struct adouble * ad )

◆ of_alloc()

struct ofork * of_alloc ( struct vol * vol,
struct dir * dir,
char * path,
uint16_t * ofrefnum,
const int eid,
struct adouble * ad,
struct stat * st )

◆ of_close_all_forks()

void of_close_all_forks ( const AFPObj * obj)

close all forks

◆ of_close_inode_forks()

void of_close_inode_forks ( const AFPObj * obj,
const struct vol * vol,
struct path * path )

Close every fork this child holds on path's inode.

Same-session sweep for FPDelete, called after a successful delete: every refusal condition (DeleteInhibit, peer claims, the session's own claims via of_delete_blocked()) has already passed and the file is unlinked, so only claim-free forks (any OPEN_* access, no deny mode, no content lock) reach this sweep. Each fork is closed individually — the blocking check needs one fork (shared adouble), the close needs them all. of_closefork() deallocs even on flush error (nothing is stranded), so a failed close is logged and the sweep continues — matching of_closevol().

Parameters
[in]objthe AFP session object
[in]volvolume the deleted file lived on
[in]pathdeleted file; path->st must be the pre-delete stat (the file no longer exists, so a re-stat cannot rebuild it)

◆ of_closefork()

int of_closefork ( const AFPObj * obj,
struct ofork * ofork )

◆ of_closevol()

void of_closevol ( const AFPObj * obj,
const struct vol * vol )

close all forks for a volume

◆ of_dealloc()

void of_dealloc ( struct ofork * of)

◆ of_delete_blocked()

int of_delete_blocked ( const struct ofork * of,
uint16_t * band,
int * content )

Does this child hold a delete-blocking claim on the fork's file?

The cross-process conflict check (deletefile()'s F_GETLK read) cannot by POSIX report the calling process's own locks, so the delete path asks this helper for the local complement: scan the session's own lock bookkeeping for the same claims and apply the same DELETE_BLOCKING_BAND_BITS policy — a deny mode or content byte-range lock refuses the delete whether its holder is a peer process or this session itself. OPEN_* markers never block (an open is just an open; only declared claims do).

Any one fork on the file suffices as of: sibling forks on an inode share one adouble, whose data-fork adf_lock[] holds ALL of the session's band entries (OPEN/DENY incl. the RSRC_* mirrors via rf2off) and its own content ranges; the rfork's adf_lock[] (reached via ad_rfp on the same adouble) holds only rfork content ranges. So one lookup sees every claim — unlike the post-delete sweep, which must visit each fork to close it.

Parameters
[in]ofa fork this child holds on the file
[out]bandheld blocking band bits, positional (may be NULL)
[out]contentset if a content byte-range lock is held (may be NULL)
Returns
nonzero if the delete must be refused

◆ of_find()

struct ofork * of_find ( const uint16_t ofrefnum)

◆ of_findname()

struct ofork * of_findname ( const struct vol * vol,
struct path * path )

◆ of_findnameat()

struct ofork * of_findnameat ( int dirfd,
struct path * path )

Search for open fork by dirfd/name.

Function call of_fstatat with dirfd and path and uses dev and ino to search the open fork table.

Parameters
[in]dirfddirectory fd
[in,out]pathpointer to struct path

◆ of_flush()

int of_flush ( const struct vol * vol)

◆ of_freeq_empty()

bool of_freeq_empty ( void )
inlinestatic

◆ of_freeq_pop()

int of_freeq_pop ( void )
inlinestatic

◆ of_freeq_push()

void of_freeq_push ( uint16_t slot)
inlinestatic

◆ of_fstatat()

int of_fstatat ( int dirfd,
struct path * path )

◆ of_get_locks()

int of_get_locks ( const struct vol * vol,
int dirfd,
struct path * path,
int df_get,
off_t df_off,
off_t df_len,
int rf_get,
off_t rf_off,
off_t rf_len,
uint16_t band_request,
int try_root,
int * df_locked,
int * rf_locked,
uint16_t * band_held )

Conflict GET (F_GETLK only): read another holder's locks on a file.

Reuses a held fork's fd when one exists, else opens+closes a transient one. Reading through a held fd (never a transient open+close on an inode we hold a lock on) is what keeps the held byte locks from being dropped on close. The rfork is never opened onto of->of_ad (would corrupt ad_rlen / underflow the v2 meta refcount).

Parameters
[in]volvolume the target lives on
[in]dirfddirectory fd for openat-style resolution, or -1
[in]pathtarget; both fork inodes derive from it
[in]df_getprobe data-fork content if non-zero
[in]df_offdata-fork content offset
[in]df_lendata-fork content length (0 = whole data zone)
[in]rf_getprobe resource-fork content if non-zero
[in]rf_offresource-fork content offset
[in]rf_lenresource-fork content length (0 = whole zone)
[in]band_requestshare-mode band bitmap; OR together the per-offset *_BIT aliases from adouble.h (or ALL_BAND_BITS for all ten). Bit n maps to offset AD_FILELOCK_BASE + n.
[in]try_rootretry the open as root on EACCES (the band is the server's own bookkeeping, not a user permission)
[out]df_lockedset if the data-fork content range is locked
[out]rf_lockedset if the resource-fork content range is locked
[out]band_heldpositional bitmap of held band bits (same positions as band_request)
Returns
OF_LOCKS_OK (0) outputs valid (all 0 == nothing locked) OF_LOCKS_NOENT (1) target absent; outputs stay zeroed OF_LOCKS_ERROR(-1) lock state indeterminate -> caller must fail closed Outputs are zeroed on entry and only populated on OF_LOCKS_OK, so a caller that ignores the return still reads zeros, never stale data - but the return MUST be checked (zeros do not mean "no locks").

Data/band fd is fail-closed (any non-ENOENT failure -> ERROR). The rfork-content leg is best-effort (rf_locked stays 0 on open failure / the HAVE_EAFD && SOLARIS skip; the rfork band is still read via the data fd).

◆ of_hash()

void of_hash ( struct ofork * of)
static

◆ of_log_highwater()

void of_log_highwater ( void )

◆ of_pforkdesc()

void of_pforkdesc ( FILE * f)

◆ of_rename()

int of_rename ( const struct vol * vol,
struct ofork * s_of,
struct dir * olddir,
const char * oldpath,
struct dir * newdir,
const char * newpath )

◆ of_stat()

int of_stat ( const struct vol * vol,
struct path * path )

◆ of_statdir()

int of_statdir ( struct vol * vol,
struct path * path )

stat the current directory.

Note
stat(".") works even if "." is deleted thus we have to stat ../name because we want to know if it's there

◆ of_unhash()

void of_unhash ( struct ofork * of)
static

Variable Documentation

◆ nforks

int nforks = 0
static

◆ of_curr_forks

int of_curr_forks = 0
static

◆ of_freeq

uint16_t* of_freeq = NULL
static

◆ of_freeq_cap

int of_freeq_cap = 0
static

◆ of_freeq_head

int of_freeq_head = 0
static

◆ of_freeq_tail

int of_freeq_tail = 0
static

◆ of_peak_forks

int of_peak_forks = 0
static

◆ ofork_table

struct ofork* ofork_table[OFORK_HASHSIZE]
static

◆ oforks

struct ofork** oforks = NULL
static