summaryrefslogtreecommitdiff
path: root/libdiskfs/dir-init.c
blob: a085a00a3d4b0d77a2bef2903f2f6b59f84b0098 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* 
   Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

#include "priv.h"

/* Locked node DP is a new directory; add whatever links are necessary
   to give it structure; its parent is the (locked) node PDP. 
   This routine may not call diskfs_lookup on PDP.  The new directory
   must be clear within the meaning of diskfs_dirempty. 
   CRED identifies the user making the call.  */
error_t
diskfs_init_dir (struct node *dp, struct node *pdp, struct protid *cred)
{
  struct dirstat *ds = alloca (diskfs_dirstat_size);
  struct node *foo;
  error_t err;

  /* Fabricate a protid that represents root credentials. */
  static uid_t zero = 0;
  static struct idvec vec = {&zero, 1, 1};
  static struct iouser user = {&vec, &vec, 0};
  struct protid lookupcred = {{ .refcounts = { .references = {1, 0}}},
			      &user, cred->po, 0, 0};

  /* New links */
  if (pdp->dn_stat.st_nlink == diskfs_link_max - 1)
    return EMLINK;

  dp->dn_stat.st_nlink++;	/* for `.' */
  dp->dn_set_ctime = 1;
  err = diskfs_lookup (dp, ".", CREATE, &foo, ds, &lookupcred);
  assert_backtrace (err == ENOENT);
  err = diskfs_direnter (dp, ".", dp, ds, cred);
  if (err)
    {
      dp->dn_stat.st_nlink--;
      dp->dn_set_ctime = 1;
      return err;
    }

  pdp->dn_stat.st_nlink++;	/* for `..' */
  pdp->dn_set_ctime = 1;
  err = diskfs_lookup (dp, "..", CREATE, &foo, ds, &lookupcred);
  assert_backtrace (err == ENOENT);
  err = diskfs_direnter (dp, "..", pdp, ds, cred);
  if (err)
    {
      pdp->dn_stat.st_nlink--;
      pdp->dn_set_ctime = 1;
      return err;
    }

  diskfs_node_update (dp, diskfs_synchronous);
  return 0;
}