summaryrefslogtreecommitdiff
path: root/fatfs/main.c
blob: 5ece199b73f98f6bca4a0076b61c4659e6605941 (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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
/* main.c - FAT filesystem.

   Copyright (C) 1997, 1998, 1999, 2002, 2003, 2007
     Free Software Foundation, Inc.

   Written by Thomas Bushnell, n/BSG and Marcus Brinkmann.

   This file is part of the GNU Hurd.

   The GNU Hurd 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.

   The GNU Hurd 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */

#include <string.h>
#include <error.h>
#include <argp.h>
#include <argz.h>
#include <limits.h>

#include <version.h>
#include "fatfs.h"
#include "libdiskfs/fsys_S.h"

struct node *diskfs_root_node;

struct store *store = 0;
struct store_parsed *store_parsed = 0;
char *diskfs_disk_name = 0;

char *diskfs_server_name = "fatfs";
char *diskfs_server_version = HURD_VERSION;
char *diskfs_extra_version = "GNU Hurd";
int diskfs_synchronous = 0;

int diskfs_link_max = 1;
int diskfs_name_max = FAT_NAME_MAX;
int diskfs_maxsymlinks = 8;     /* XXX */

/* Handy source of zeroes.  */
vm_address_t zerocluster;

struct dirrect dr_root_node;

/* The UID and GID for all files in the filesystem.  */
uid_t default_fs_uid;
gid_t default_fs_gid;
uid_t fs_uid;
gid_t fs_gid;

/* fatfs specific options.  */
static const struct argp_option options[] =
  {
    { "uid", 'U', "uid", 0, "Default uid for files" },
    { "gid", 'G', "gid", 0, "Default gid for files" },
    { 0 }
  };

static error_t
parse_opt (int key, char *arg, struct argp_state *state)
{
  switch (key)
    {
    case 'U':
      if (arg)
	fs_uid = atoi (arg);
      refresh_node_stats ();
      break;
    case 'G':
      if (arg)
	fs_gid = atoi (arg);
      refresh_node_stats ();
      break;
    case ARGP_KEY_INIT:
      state->child_inputs[0] = state->input;
      break;
    case ARGP_KEY_SUCCESS:
      break;
    default:
      return ARGP_ERR_UNKNOWN;
    }
  
  return 0;
}

/* Add our startup arguments to the standard diskfs set.  */
static const struct argp_child startup_children[] =
 { { &diskfs_store_startup_argp }, { 0 } };
static struct argp startup_argp =
  { options, parse_opt, 0, 0, startup_children };

/* Similarly at runtime.  */
static const struct argp_child runtime_children[] =
 { { &diskfs_std_runtime_argp }, { 0 } };
static struct argp runtime_argp =
  { options, parse_opt, 0, 0, runtime_children };

struct argp *diskfs_runtime_argp = (struct argp *) &runtime_argp;


/* Override the standard diskfs routine so we can add our own
   output.  */
error_t
diskfs_append_args (char **argz, size_t *argz_len)
{
  error_t err;
  char buf[100];

  /* Get the standard things.  */
  err = diskfs_append_std_options (argz, argz_len);

  if (!err && fs_uid != default_fs_uid)
    {
      snprintf (buf, sizeof buf, "--uid=%d", fs_uid);
      err = argz_add (argz, argz_len, buf);
    }

  if (!err && fs_gid != default_fs_gid)
    {
      snprintf (buf, sizeof buf, "--gid=%d", fs_gid);
      err = argz_add (argz, argz_len, buf);
    }

  if (! err)
    err = store_parsed_append_args (store_parsed, argz, argz_len);

  return err;
}


/* Fetch the root node.  */
static void
fetch_root (void)
{
  error_t err;
  ino_t inum;
  struct lookup_context ctx;

  memset (&dr_root_node, 0, sizeof(struct dirrect));

  /* Fill root directory entry.  XXX Should partially be in fat.c  */
  dr_root_node.attribute = FAT_DIR_ATTR_DIR;
  if (fat_type == FAT32)
    {
      /* FAT12/16: There is no such thing as a start cluster, because
	 the whole root dir is in a special region after the FAT.  The
	 start cluster of the root node is undefined.  */
      dr_root_node.first_cluster_high[1]
	= sblock->compat.fat32.root_cluster[3];
      dr_root_node.first_cluster_high[0]
	= sblock->compat.fat32.root_cluster[2];
      dr_root_node.first_cluster_low[1] = sblock->compat.fat32.root_cluster[1];
      dr_root_node.first_cluster_low[0] = sblock->compat.fat32.root_cluster[0];
    }

  /* Determine size of the directory (different for fat12/16 vs 32).  */
  switch (fat_type)
    {
    case FAT12:
    case FAT16:
      write_dword(dr_root_node.file_size, nr_of_root_dir_sectors
		  << log2_bytes_per_sector);
      break;

    case FAT32:
      {
	/* Extend the cluster chain of the root directory and calculate
	   file_size based on that.  */
	cluster_t rootdir;
	int cs = 0;

	rootdir = (cluster_t) *sblock->compat.fat32.root_cluster;
	while (rootdir != FAT_EOC)
	  {
	    fat_get_next_cluster (rootdir, &rootdir);
	    cs++;
	  }
	write_dword (dr_root_node.file_size, cs << log2_bytes_per_cluster);
      }
      break;

    default:
      assert_backtrace (!"don't know how to set size of root dir");
    };

  /* The magic vi_key {0, 1} for the root directory is distinguished
     from the vi_zero_key (in the dir_offset value) as well as all
     normal virtual inode keys (in the dir_inode value).  Enter the
     disknode into the inode table.  */
  err = vi_new ((struct vi_key) {0, 1}, &inum, &ctx.inode);
  assert_perror_backtrace (err);

  /* Allocate a node for the root directory disknode in
     diskfs_root_node.  */
  if (!err)
    err = diskfs_cached_lookup_context (inum, &diskfs_root_node, &ctx);

  assert_perror_backtrace (err);

  pthread_mutex_unlock (&diskfs_root_node->lock);
}


int
main (int argc, char **argv)
{
  mach_port_t bootstrap;

  default_fs_uid = getuid ();
  default_fs_gid = getgid ();
  fs_uid = default_fs_uid;
  fs_gid = default_fs_gid;

  /* This filesystem is not capable of writing yet.  */
  diskfs_readonly = 1;
  diskfs_hard_readonly = 1;

  /* Initialize the diskfs library, parse arguments, and open the
     store.  This starts the first diskfs thread for us.  */
  store = diskfs_init_main (&startup_argp, argc, argv, &store_parsed,
			    &bootstrap);

  fat_read_sblock ();

  create_fat_pager ();

  zerocluster = (vm_address_t) mmap (0, bytes_per_cluster, PROT_READ|PROT_WRITE,
				     MAP_ANON, 0, 0);

  fetch_root ();

  diskfs_startup_diskfs (bootstrap, 0);

  pthread_exit (NULL);

  return 0;
}


/* Nothing to do for read-only medium.  */
error_t
diskfs_reload_global_state (void)
{
  return 0;
}


error_t
diskfs_set_hypermetadata (int wait, int clean)
{
  return 0;
}


void
diskfs_readonly_changed (int readonly)
{
  /* We should never get here because we set diskfs_hard_readonly above.  */
  abort ();
}

/* FIXME: libdiskfs doesn't lock the parent dir when looking up a node
   for fsys_getfile, so we disable NFS.  */
error_t
diskfs_S_fsys_getfile (struct diskfs_control *pt,
                      mach_port_t reply, mach_msg_type_name_t reply_type,
                      const uid_t *uids, mach_msg_type_number_t nuids,
                      const gid_t *gids, mach_msg_type_number_t ngids,
                      const_data_t handle, mach_msg_type_number_t handle_len,
                      mach_port_t *file, mach_msg_type_name_t *file_type)
{
  return EOPNOTSUPP;
}