netatalk 4.5.0
Free and Open Source Apple Filing Protocol (AFP) Server
Loading...
Searching...
No Matches
directory.h File Reference
`#include <arpa/inet.h>`
`#include <dirent.h>`
`#include <stdbool.h>`
`#include <sys/sysmacros.h>`
`#include <sys/types.h>`
`#include <atalk/adouble.h>`
`#include <atalk/directory.h>`
`#include <atalk/globals.h>`
`#include "volume.h"`

Go to the source code of this file.

## Data Structures
struct | dir_modify_args
| Parameters for dir_modify() selective field updates. More...
struct | maccess

## Macros
#define | DCMOD_PATH (1 << 0)
#define | DCMOD_STAT (1 << 1)
#define | DCMOD_AD (1 << 2)
#define | DCMOD_AD_INV (1 << 3)
#define | DCMOD_NO_PROMOTE (1 << 4) /* Skip ARC promotion (cross-process hints) */
#define | DIRPBIT_ATTR 0
#define | DIRPBIT_PDID 1
#define | DIRPBIT_CDATE 2
#define | DIRPBIT_MDATE 3
#define | DIRPBIT_BDATE 4
#define | DIRPBIT_FINFO 5
#define | DIRPBIT_LNAME 6
#define | DIRPBIT_SNAME 7
#define | DIRPBIT_DID 8
#define | DIRPBIT_OFFCNT 9
#define | DIRPBIT_UID 10
#define | DIRPBIT_GID 11
#define | DIRPBIT_ACCESS 12
#define | DIRPBIT_PDINFO 13
#define | DIRPBIT_UNIXPR 15
#define | FILDIRBIT_ISDIR (1 << 7)
#define | FILDIRBIT_ISFILE (0)
#define | CNID(a, b)
#define | AR_USEARCH (1<<0)
#define | AR_UREAD (1<<1)
#define | AR_UWRITE (1<<2)
#define | AR_UOWN (1<<7)

## Typedefs
typedef int(* | dir_loop) (struct dirent *, char *, void *)

## Functions
void | dir_remove_and_free (const struct vol *, struct dir *)
| Remove a cache entry and free it immediately.
void | dir_free_invalid_q (void)
| Free the queue with invalid struct dirs.
struct dir * | dir_new (const char *mname, const char *uname, const struct vol *, cnid_t pdid, cnid_t did, bstring fullpath, struct stat *)
| Construct struct dir.
void | dir_free (struct dir *)
| Free a struct dir and all its members.
struct dir * | dir_add (struct vol *, const struct dir *, struct path *, int)
| Create struct dir from struct path.
int | dir_modify (const struct vol *vol, struct dir *dir, const struct dir_modify_args *args)
| Update a cached entry in-place with selective field updates.
int | dir_remove (const struct vol *vol, struct dir *dir, int report_invalid)
| Remove a file/directory from dircache with automatic curdir recovery.
struct dir * | dirlookup (const struct vol *, cnid_t)
| Optimistic CNID resolution for read/safe code paths.
struct dir * | dirlookup_strict (const struct vol *, cnid_t)
| Validated DID resolution for write/change code paths.
struct dir * | dirlookup_bypath (const struct vol *vol, const char *path)
int | movecwd (const struct vol *, struct dir *)
| chdir() to dir
struct path * | cname (struct vol *, struct dir *, char **)
| Resolve a catalog node name path.
int | deletecurdir (struct vol *)
mode_t | mtoumode (struct maccess *)
int | getdirparams (const AFPObj *obj, const struct vol *, uint16_t, struct path *, struct dir *, char *, size_t *)
int | setdirparams (struct vol *, struct path *, uint16_t, char *)
int | renamedir (struct vol *, int, char *, char *, struct dir *, char *)
| Rename a directory.
int | path_error (struct path *, int error)
void | setdiroffcnt (struct dir *dir, struct stat *st, uint32_t count)
int | dirreenumerate (struct dir *dir, struct stat *st)
int | for_each_dirent (const struct vol *, char *, dir_loop, void *)
int | check_access (const AFPObj *obj, struct vol *, char *name, int mode)
int | file_access (const AFPObj *obj, struct vol *vol, struct path *path, int mode)
int | netatalk_unlink (const char *name)
| system unlink with afp error code.
char * | check_dirent (const struct vol *, char *)
int | afp_createdir (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_opendir (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_setdirparams (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_closedir (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_mapid (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_mapname (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_syncdir (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_enumerate (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_enumerate_ext (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_enumerate_ext2 (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_catsearch (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
int | afp_catsearch_ext (AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)

## Variables
q_t * | invalid_dircache_entries

## Macro Definition Documentation

## ◆ AR_UOWN

#define AR_UOWN (1<<7)

## ◆ AR_UREAD

#define AR_UREAD (1<<1)

## ◆ AR_USEARCH

#define AR_USEARCH (1<<0)

## ◆ AR_UWRITE

#define AR_UWRITE (1<<2)

## ◆ CNID

#define CNID | ( |  | a,
|  |  | b )

Value:
((a)->st_ino & 0xffffffff)

## ◆ DCMOD_AD

#define DCMOD_AD (1 << 2)

AD cache: finderinfo/filedatesi/afpfilei/rlen (Phase 2)

## ◆ DCMOD_AD_INV

#define DCMOD_AD_INV (1 << 3)

AD invalidate: zero AD fields, set rlen = -1 (Phase 2)

## ◆ DCMOD_NO_PROMOTE

#define DCMOD_NO_PROMOTE (1 << 4) /* Skip ARC promotion (cross-process hints) */

## ◆ DCMOD_PATH

#define DCMOD_PATH (1 << 0)

Identity/navigation: d_pdid, names, d_fullpath

## ◆ DCMOD_STAT

#define DCMOD_STAT (1 << 1)

Stat cache: dcache_ctime/ino/mode/mtime/uid/gid/size

## ◆ DIRPBIT_ACCESS

#define DIRPBIT_ACCESS 12

## ◆ DIRPBIT_ATTR

#define DIRPBIT_ATTR 0

## ◆ DIRPBIT_BDATE

#define DIRPBIT_BDATE 4

## ◆ DIRPBIT_CDATE

#define DIRPBIT_CDATE 2

## ◆ DIRPBIT_DID

#define DIRPBIT_DID 8

## ◆ DIRPBIT_FINFO

#define DIRPBIT_FINFO 5

## ◆ DIRPBIT_GID

#define DIRPBIT_GID 11

## ◆ DIRPBIT_LNAME

#define DIRPBIT_LNAME 6

## ◆ DIRPBIT_MDATE

#define DIRPBIT_MDATE 3

## ◆ DIRPBIT_OFFCNT

#define DIRPBIT_OFFCNT 9

## ◆ DIRPBIT_PDID

#define DIRPBIT_PDID 1

## ◆ DIRPBIT_PDINFO

#define DIRPBIT_PDINFO 13

ProDOS Info

## ◆ DIRPBIT_SNAME

#define DIRPBIT_SNAME 7

## ◆ DIRPBIT_UID

#define DIRPBIT_UID 10

## ◆ DIRPBIT_UNIXPR

#define DIRPBIT_UNIXPR 15

## ◆ FILDIRBIT_ISDIR

#define FILDIRBIT_ISDIR (1 << 7)

is a directory

## ◆ FILDIRBIT_ISFILE

#define FILDIRBIT_ISFILE (0)

is a file

## Typedef Documentation

## ◆ dir_loop

typedef int(* dir_loop) (struct dirent *, char *, void *)

## Function Documentation

## ◆ afp_catsearch()

int afp_catsearch | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_catsearch_ext()

int afp_catsearch_ext | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_closedir()

int afp_closedir | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_createdir()

int afp_createdir | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_enumerate()

int afp_enumerate | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_enumerate_ext()

int afp_enumerate_ext | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_enumerate_ext2()

int afp_enumerate_ext2 | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_mapid()

int afp_mapid | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_mapname()

int afp_mapname | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_opendir()

int afp_opendir | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_setdirparams()

int afp_setdirparams | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ afp_syncdir()

int afp_syncdir | ( | AFPObj * | obj,
|  | char * | ibuf,
|  | size_t | ibuflen,
|  | char * | rbuf,
|  | size_t * | rbuflen )

## ◆ check_access()

int check_access | ( | const AFPObj * | obj,
|  | struct vol * | vol,
|  | char * | path,
|  | int | mode )
| extern

We can't use unix file's perm to support Apple's inherited protection modes. If we aren't the file's owner we can't change its perms when moving it and smb nfs,... don't even try.

## ◆ check_dirent()

char * check_dirent | ( | const struct vol * | vol,
|  | char * | name )
| extern

Bug
  Doesn't work with dangling symlink i.e.:
  - Move a folder with a dangling symlink in the trash
  - empty the trash

afp_enumerate return an empty listing but offspring count != 0 in afp_getdirparams and the client doesn't try to call afp_delete!

See also
  https://sourceforge.net/p/netatalk/bugs/97/

## ◆ cname()

struct path * cname | ( | struct vol * | vol,
|  | struct dir * | dir,
|  | char ** | cpath )
| extern

Resolve a catalog node name path.

1. Evaluate path type
2. Move to start dir, if we can't, it might be e.g. because of EACCES, build path from dirname, so e.g. getdirparams has sth it can chew on. curdir is dir parent then. All this is done in path_from_dir().
3. Parse next cnode name in path, cases:
4. single "\0" -> do nothing
5. two or more consecutive "\0" -> chdir("..") one or more times
6. cnode name -> copy it to path.m_name
7. Get unix name from mac name
8. Special handling of request with did 1
9. stat the cnode name
10. If it's not there, it's probably an afp_createfile|dir, return with curdir = dir parent, struct path = dirname
11. If it's there and it's a file, it must should be the last element of the requested path. Return with curdir = cnode name parent dir, struct path = filename
12. Treat symlinks like files, don't follow them
13. If it's a dir:
14. Search the dircache for it
15. If it's not in the cache, create a struct dir for it and add it to the cache
16. chdir into the dir and
17. set m_name to the mac equivalent of "."
18. goto 3

## ◆ deletecurdir()

int deletecurdir | ( | struct vol * | vol | ) |
| extern

delete an empty directory

## ◆ dir_add()

struct dir * dir_add | ( | struct vol * | vol,
|  | const struct dir * | dir,
|  | struct path * | path,
|  | int | len )
| extern

Create struct dir from struct path.

Create a new struct dir from struct path. Then add it to the cache.

1. Open adouble file, get CNID from it.
2. Search the database, hinting with the CNID from (1).
3. Build fullpath and create struct dir.
4. Add it to the cache.

Parameters

  [in] | vol | pointer to struct vol, possibly modified in callee
  [in] | dir | pointer to parent directory
  [in,out] | path | pointer to struct path with valid path->u_name
  [in] | len | strlen of path->u_name

Returns
  Pointer to new struct dir or NULL on error.

Note
  Function also assigns path->m_name from path->u_name.

## ◆ dir_free()

void dir_free | ( | struct dir * | dir | ) |
| extern

Free a struct dir and all its members.

Parameters

  dir | (rw) pointer to struct dir

## ◆ dir_free_invalid_q()

void dir_free_invalid_q | ( | void |  | ) |
| extern

Free the queue with invalid struct dirs.

Note
  This gets called at the end of every AFP func.

## ◆ dir_modify()

int dir_modify | ( | const struct vol * | vol,
|  | struct dir * | dir,
|  | const struct dir_modify_args * | args )
| extern

Update a cached entry in-place with selective field updates.

Modifies specified field groups on an existing cache entry while maintaining hash table consistency. The DCMOD_* bitmask in args->flags controls which fields are updated — unset groups are not touched.

When DCMOD_PATH is set and new_uname or new_pdid differs from current values, the DID/name index is automatically reindexed. The CNID index (d_vid, d_did) is NEVER changed.

Always promotes the entry in ARC (signals recency to eviction algorithm).

Common call patterns: Rename: DCMOD_PATH | DCMOD_STAT After setfilparams: DCMOD_STAT | DCMOD_AD (Phase 2) Stat-only refresh: DCMOD_STAT

Parameters

  [in] | vol | Volume (required)
  [in,out] | dir | Cache entry to update (required)
  [in] | args | Parameter struct with DCMOD_* flags and field values

Returns
  0 on success, -1 on error (hash re-insert failure)

## ◆ dir_new()

struct dir * dir_new | ( | const char * | m_name,
|  | const char * | u_name,
|  | const struct vol * | vol,
|  | cnid_t | pdid,
|  | cnid_t | did,
|  | bstring | path,
|  | struct stat * | st )
| extern

Construct struct dir.

Construct struct dir from parameters.

Parameters

  [in] | m_name | directory name in UTF8-dec
  [in] | u_name | directory name in server side encoding
  [in] | vol | pointer to struct vol
  [in] | pdid | Parent CNID
  [in] | did | CNID
  [in] | path | Full unix path to object
  [in] | st | struct stat of object

Returns
  pointer to new struct dir or NULL on error

Note
  Most of the time mac name and unix name are the same.

## ◆ dir_remove()

int dir_remove | ( | const struct vol * | vol,
|  | struct dir * | dir,
|  | int | report_invalid )
| extern

Remove a file/directory from dircache with automatic curdir recovery.

This function centralizes global curdir safety for all callers. When removing a cache entry that is curdir, it attempts curdir recovery via CNID database and falls back to volume root if recovery fails.

1. Check the dir
2. Detect if removing curdir and save DID
3. Remove from cache and queue for deallocation
4. Set curdir=NULL if removing curdir (safer than dangling pointer)
5. Attempt recovery via dirlookup(saved_did)
6. If recovery fails, fallback to vol->v_root or rootParent
7. Mark entry invalid

Parameters

  [in] | vol | volume pointer
  [in,out] | dir | directory/file entry to remove from cache
  [in] | report_invalid | 1 = report as invalid_on_use (entry was used and found stale), 0 = don't report (proactive cleanup, user deletion, etc.)

Returns
  0 on success, -1 if curdir was removed and recovery failed (curdir guaranteed non-NULL on return)

## ◆ dir_remove_and_free()

void dir_remove_and_free | ( | const struct vol * | vol,
|  | struct dir * | dir )
| extern

Remove a cache entry and free it immediately.

Unlike dir_remove(), this function:

- Does NOT enqueue into invalid_dircache_entries (frees immediately)
- Does NOT check or modify curdir (caller must ensure entry != curdir)
- Does NOT attempt curdir recovery via dirlookup()

DIRCACHE_NOSHRINK prevents hash table shrink during worker iteration.

Used by idle worker during temporal separation AND by dircache_flush_deferred_for_vol() during synchronous volume close.

## ◆ dirlookup()

struct dir * dirlookup | ( | const struct vol * | vol,
|  | cnid_t | did )
| extern

Optimistic CNID resolution for read/safe code paths.

Resolves a CNID to its cached entry using probabilistic validation. Safe for read operations (enumerate, getparams, opendir, openfork) because stale entries are detected on use and recovered via movecwd().

Parameters

  [in] | vol | pointer to struct vol
  [in] | did | DID to resolve

Returns
  pointer to struct dir (may have DIRF_ISFILE flag for files)

## ◆ dirlookup_bypath()

struct dir * dirlookup_bypath | ( | const struct vol * | vol,
|  | const char * | path )
| extern

## ◆ dirlookup_strict()

struct dir * dirlookup_strict | ( | const struct vol * | vol,
|  | cnid_t | did )
| extern

Validated DID resolution for write/change code paths.

Like dirlookup(), but performs stat()+inode validation to ensure the cached entry matches the current filesystem state. Gurantees operating on valid entry. Use for all write/change operations: delete, setdirparams, setfilparams, setfildirparams, setacl, copyfile (dest), exchangefiles, createdir, createfile

Parameters

  [in] | vol | pointer to struct vol
  [in] | did | DID to resolve

Returns
  pointer to validated struct dir, or NULL with afp_errno set

## ◆ dirreenumerate()

int dirreenumerate | ( | struct dir * | dir,
|  | struct stat * | st )
| extern

## ◆ file_access()

int file_access | ( | const AFPObj * | obj,
|  | struct vol * | vol,
|  | struct path * | path,
|  | int | mode )
| extern

## ◆ for_each_dirent()

int for_each_dirent | ( | const struct vol * | vol,
|  | char * | name,
|  | dir_loop | fn,
|  | void * | data )
| extern

## ◆ getdirparams()

int getdirparams | ( | const AFPObj * | obj,
|  | const struct vol * | vol,
|  | uint16_t | bitmap,
|  | struct path * | s_path,
|  | struct dir * | dir,
|  | char * | buf,
|  | size_t * | buflen )
| extern

## ◆ movecwd()

int movecwd | ( | const struct vol * | vol,
|  | struct dir * | dir )
| extern

chdir() to dir

Parameters

  [in] | vol | pointer to struct vol
  [in] | dir | pointer to struct dir

Returns
  0 on success, -1 on error with afp_errno set appropriately

## ◆ mtoumode()

mode_t mtoumode | ( | struct maccess * | ma | ) |
| extern

## ◆ netatalk_unlink()

int netatalk_unlink | ( | const char * | name | ) |
| extern

system unlink with afp error code.

Note
  ENOENT is not an error.

## ◆ path_error()

int path_error | ( | struct path * | path,
|  | int | error )
| extern

## ◆ renamedir()

int renamedir | ( | struct vol * | vol,
|  | int | dirfd,
|  | char * | src,
|  | char * | dst,
|  | struct dir * | newparent,
|  | char * | newname )
| extern

Rename a directory.

Parameters

  vol | volume
  dirfd | -1 means ignore dirfd (or use AT_FDCWD), otherwise src is relative to dirfd
  src | old unix filename (not a pathname)
  dst | new unix filename (not a pathname)
  newparent | curdir
  newname | new mac name

## ◆ setdiroffcnt()

void setdiroffcnt | ( | struct dir * | dir,
|  | struct stat * | st,
|  | uint32_t | count )
| extern

## ◆ setdirparams()

int setdirparams | ( | struct vol * | vol,
|  | struct path * | path,
|  | uint16_t | d_bitmap,
|  | char * | buf )
| extern

Note
  assume path == '\0' e.g. it's a directory in canonical form

## Variable Documentation

## ◆ invalid_dircache_entries

q_t* invalid_dircache_entries
| extern