source: trunk/athena/bin/syncupdate/syncupdate.c @ 16698

Revision 16698, 4.7 KB checked in by amb, 23 years ago (diff)
fsync() directories as well under linux.
Line 
1/* Copyright 1999 by the Massachusetts Institute of Technology.
2 *
3 * Permission to use, copy, modify, and distribute this
4 * software and its documentation for any purpose and without
5 * fee is hereby granted, provided that the above copyright
6 * notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting
8 * documentation, and that the name of M.I.T. not be used in
9 * advertising or publicity pertaining to distribution of the
10 * software without specific, written prior permission.
11 * M.I.T. makes no representations about the suitability of
12 * this software for any purpose.  It is provided "as is"
13 * without express or implied warranty.
14 */
15
16static const char rcsid[] = "$Id: syncupdate.c,v 1.4 2001-10-23 21:59:02 amb Exp $";
17
18#include <sys/types.h>
19#include <sys/stat.h>
20#include <stdio.h>
21#include <string.h>
22#include <stdlib.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <errno.h>
26
27#ifdef linux
28#include <libgen.h>
29#endif
30
31#ifndef S_IAMB
32#define S_IAMB 0x1FF    /* Access bits part of struct stat st_mode field */
33#endif
34
35static void copy(const char *source, const char *tempfile);
36static void open_and_sync(const char *filename);
37static void usage(void);
38#ifdef linux
39static void open_dir_and_sync(const char *filename);
40#endif
41
42int main(int argc, char **argv)
43{
44  int c;
45  char *tempfile = NULL, *source, *dest;
46
47  while ((c = getopt(argc, argv, "c:")) != EOF)
48    {
49      switch (c)
50        {
51        case 'c':
52          tempfile = optarg;
53          break;
54        case '?':
55          usage();
56        }
57    }
58  argc -= optind;
59  argv += optind;
60  if (argc != 2)
61    usage();
62  source = argv[0];
63  dest = argv[1];
64
65  /* Set up for the move. */
66  if (tempfile)
67    {
68      copy(source, tempfile);
69      source = tempfile;
70    }
71  else
72    open_and_sync(source);
73
74  if (rename(source, dest) == -1)
75    {
76      fprintf(stderr, "syncupdate: can't rename %s to %s: %s\n",
77              source, dest, strerror(errno));
78      exit(1);
79    }
80
81#ifdef linux
82  open_dir_and_sync(dirname(dest));
83#endif
84
85  exit(0);
86}
87
88static void copy(const char *source, const char *tempfile)
89{
90  int sfd, tfd, count, pos, n;
91  struct stat statbuf;
92  unsigned char buf[8192];
93
94  /* Open the source file and get its status information. */
95  sfd = open(source, O_RDONLY, 0);
96  if (sfd == -1)
97    {   
98      fprintf(stderr, "syncupdate: can't read %s: %s\n", source,
99              strerror(errno));
100      exit(1);
101    }
102  if (fstat(sfd, &statbuf) == -1)
103    {
104      fprintf(stderr, "syncupdate: can't stat %s: %s\n", source,
105              strerror(errno));
106      exit(1);
107    }
108
109  /* Remove, open, and set mode on the temp file. */
110  if (unlink(tempfile) == -1 && errno != ENOENT)
111    {
112      fprintf(stderr, "syncupdate: can't remove %s: %s\n", tempfile,
113              strerror(errno));
114      exit(1);
115    }
116  tfd = open(tempfile, O_RDWR | O_CREAT | O_EXCL, 0);
117  if (tfd == -1)
118    {
119      fprintf(stderr, "syncupdate: can't create %s: %s\n", tempfile,
120              strerror(errno));
121      exit(1);
122    }
123  if (fchmod(tfd, statbuf.st_mode & S_IAMB) == -1)
124    {
125      fprintf(stderr, "syncupdate: can't fchmod %s: %s\n", tempfile,
126              strerror(errno));
127      unlink(tempfile);
128      exit(1);
129    }
130
131  /* Now copy and fsync. */
132  while ((count = read(sfd, buf, sizeof(buf))) > 0)
133    {
134      for (pos = 0; pos < count; pos += n)
135        {
136          n = write(tfd, buf + pos, count - pos);
137          if (n == -1)
138            {
139              fprintf(stderr, "syncupdate: can't write to %s: %s\n", tempfile,
140                      strerror(errno));
141              unlink(tempfile);
142              exit(1);
143            }
144        }
145    }
146  if (count == -1)
147    {
148      fprintf(stderr, "syncupdate: can't read from %s: %s\n", source,
149              strerror(errno));
150    }
151
152  if (fsync(tfd) == -1)
153    {
154      fprintf(stderr, "syncupdate: can't fsync %s: %s\n", tempfile,
155              strerror(errno));
156      unlink(tempfile);
157      exit(1);
158    }
159
160  close(sfd);
161  close(tfd);
162}
163
164static void open_and_sync(const char *filename)
165{
166  int fd;
167
168  fd = open(filename, O_RDWR, 0);
169  if (fd == -1)
170    {
171      fprintf(stderr, "syncupdate: can't open %s: %s\n", filename,
172              strerror(errno));
173      exit(1);
174    }
175
176  if (fsync(fd) == -1)
177    {
178      fprintf(stderr, "syncupdate: can't fsync %s: %s\n", filename,
179              strerror(errno));
180      exit(1);
181    }
182
183  close(fd);
184}
185
186#ifdef linux
187/* Despite the implication of the man page that fsync() will only work on
188   RDWR file descriptors, it also works on directories open RDONLY.
189   Since linux fsync() doesn't flush directory entries, force the issue. */
190static void open_dir_and_sync(const char *filename)
191{
192  int fd;
193
194  fd = open(filename, O_RDONLY, 0);
195  if (fd == -1)
196    {
197      fprintf(stderr, "syncupdate: can't open %s: %s\n", filename,
198              strerror(errno));
199      exit(1);
200    }
201
202  fsync(fd);
203  close(fd);
204}
205#endif
206
207static void usage(void)
208{
209  fprintf(stderr, "Usage: syncupdate [-c tempfile] source dest\n");
210  exit(1);
211}
Note: See TracBrowser for help on using the repository browser.