]> git.saurik.com Git - apple/hfs.git/blob - hfs_util/hfsutil_jnl.c
hfs-116.10.tar.gz
[apple/hfs.git] / hfs_util / hfsutil_jnl.c
1 /*
2 * Copyright (c) 1999-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 Copyright (c) 2002 Apple Computer, Inc.
24 All Rights Reserved.
25
26 This file contains the routine to make an HFS+ volume journaled
27 and a corresponding routine to turn it off.
28
29 */
30
31 #include <sys/types.h>
32 #include <sys/attr.h>
33 #include <sys/stat.h>
34 #include <sys/time.h>
35 #include <sys/sysctl.h>
36 #include <sys/resource.h>
37 #include <sys/vmmeter.h>
38 #include <sys/mount.h>
39 #include <sys/wait.h>
40
41 #include <dev/disk.h>
42 #include <sys/loadable_fs.h>
43 #include <hfs/hfs_format.h>
44
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <libgen.h>
48 #include <pwd.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53
54 #include <architecture/byte_order.h>
55
56 //
57 // Secret HFS sysctl's to instruct it to turn
58 // journaling on/off for a volume.
59 //
60 #define HFS_BECOME_JOURNALED 0x082969
61 #define HFS_BECOME_UNJOURNALED 0x031272
62
63
64 /* getattrlist buffers start with an extra length field */
65 struct ExtentsAttrBuf {
66 unsigned long infoLength;
67 HFSPlusExtentRecord extents;
68 };
69 typedef struct ExtentsAttrBuf ExtentsAttrBuf;
70
71
72
73 #define kIsInvisible 0x4000
74
75 /*
76 * Generic Finder file/dir data
77 */
78 struct FinderInfo {
79 u_int32_t opaque_1[2];
80 u_int16_t fdFlags; /* Finder flags */
81 int16_t opaque_2[11];
82 };
83 typedef struct FinderInfo FinderInfo;
84
85 /* getattrlist buffers start with an extra length field */
86 struct FinderAttrBuf {
87 unsigned long infoLength;
88 FinderInfo finderInfo;
89 };
90 typedef struct FinderAttrBuf FinderAttrBuf;
91
92
93 int hide_file(const char * file)
94 {
95 struct attrlist alist = {0};
96 FinderAttrBuf finderInfoBuf = {0};
97 int result;
98
99 alist.bitmapcount = ATTR_BIT_MAP_COUNT;
100 alist.commonattr = ATTR_CMN_FNDRINFO;
101
102 result = getattrlist(file, &alist, &finderInfoBuf, sizeof(finderInfoBuf), 0);
103 if (result) {
104 return (errno);
105 }
106
107 if (finderInfoBuf.finderInfo.fdFlags & kIsInvisible) {
108 printf("hide: %s is alreadly invisible\n", file);
109 return (0);
110 }
111
112 finderInfoBuf.finderInfo.fdFlags |= kIsInvisible;
113
114 result = setattrlist(file, &alist, &finderInfoBuf.finderInfo, sizeof(FinderInfo), 0);
115
116 return (result == -1 ? errno : result);
117 }
118
119 int
120 get_start_block(const char *file)
121 {
122 struct attrlist alist = {0};
123 ExtentsAttrBuf extentsbuf = {0};
124
125 alist.bitmapcount = ATTR_BIT_MAP_COUNT;
126 alist.fileattr = ATTR_FILE_DATAEXTENTS;
127
128 if (getattrlist(file, &alist, &extentsbuf, sizeof(extentsbuf), 0)) {
129 fprintf(stderr, "could not get attrlist for %s (%s)", file, strerror(errno));
130 return -1;
131 }
132
133 if (extentsbuf.extents[1].startBlock != 0) {
134 fprintf(stderr, "Journal File not contiguous!\n");
135 return -1;
136 }
137
138 return extentsbuf.extents[0].startBlock;
139 }
140
141 static const char *journal_fname = ".journal";
142 static const char *jib_fname = ".journal_info_block";
143
144 int
145 DoMakeJournaled(char *volname, int jsize)
146 {
147 int fd, i, block_size, journal_size = 8*1024*1024;
148 char *buf;
149 int ret;
150 fstore_t fst;
151 int jstart_block, jinfo_block, sysctl_info[8];
152 JournalInfoBlock jib;
153 struct statfs sfs;
154 static char tmpname[MAXPATHLEN];
155
156 if (jsize != 0) {
157 journal_size = jsize;
158 }
159
160 if (statfs(volname, &sfs) != 0) {
161 fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno));
162 return 10;
163 }
164
165 // Make sure that we're HFS+. First we check the fstypename.
166 // If that's ok then we try to create a symlink (which won't
167 // work on plain hfs volumes but will work on hfs+ volumes).
168 //
169 sprintf(tmpname, "%s/is_vol_hfs_plus", volname);
170 if (strcmp(sfs.f_fstypename, "hfs") != 0 ||
171 ((ret = symlink(tmpname, tmpname)) != 0 && errno == ENOTSUP)) {
172 fprintf(stderr, "%s is not an HFS+ volume. Journaling only works on HFS+ volumes.\n",
173 volname);
174 return 10;
175 }
176 unlink(tmpname);
177
178 if (sfs.f_flags & MNT_JOURNALED) {
179 fprintf(stderr, "Volume %s is already journaled.\n", volname);
180 return 1;
181 }
182
183 if (chdir(volname) != 0) {
184 fprintf(stderr, "Can't locate volume %s to make it journaled (%s).\n",
185 volname, strerror(errno));
186 return 10;
187 }
188
189 fd = open(journal_fname, O_CREAT|O_TRUNC|O_RDWR, 000);
190 if (fd < 0) {
191 fprintf(stderr, "Can't create journal file on volume %s (%s)\n",
192 volname, strerror(errno));
193 return 5;
194 }
195
196 // make sure that it has no r/w/x privs (only could happen if
197 // the file already existed since open() doesn't reset the mode
198 // bits).
199 //
200 fchmod(fd, 0);
201
202 block_size = sfs.f_bsize;
203 if ((journal_size % block_size) != 0) {
204 fprintf(stderr, "Journal size %dk is not a multiple of volume %s block size (%d).\n",
205 journal_size/1024, volname, block_size);
206 close(fd);
207 unlink(journal_fname);
208 return 5;
209 }
210
211 memset(&fst, 0, sizeof(fst));
212 fst.fst_flags = F_ALLOCATECONTIG|F_ALLOCATEALL;
213 fst.fst_length = journal_size;
214 fst.fst_posmode = F_PEOFPOSMODE;
215
216 ret = fcntl(fd, F_PREALLOCATE, &fst);
217 if (ret < 0) {
218 fprintf(stderr, "Pre-allocating the journal file failed on volume %s (%s)\n",
219 volname, strerror(errno));
220 fprintf(stderr, "Try using a smaller (%d k) journal size\n", journal_size/2/1024);
221 close(fd);
222 unlink(journal_fname);
223 return 10;
224 }
225
226 printf("Allocated %lldK for journal file.\n", fst.fst_bytesalloc/1024LL);
227 buf = (char *)calloc(block_size, 1);
228 if (buf) {
229 for(i=0; i < journal_size/block_size; i++) {
230 ret = write(fd, buf, block_size);
231 if (ret != block_size) {
232 break;
233 }
234 }
235
236 if (i*block_size != journal_size) {
237 fprintf(stderr, "Failed to write %dk to journal on volume %s (%s)\n",
238 journal_size/1024, volname, strerror(errno));
239 }
240 } else {
241 printf("Could not allocate memory to write to the journal on volume %s (%s)\n",
242 volname, strerror(errno));
243 }
244
245 fsync(fd);
246 close(fd);
247 hide_file(journal_fname);
248
249 jstart_block = get_start_block(journal_fname);
250
251 memset(&jib, 0, sizeof(jib));
252 jib.flags = kJIJournalInFSMask;
253 jib.offset = (off_t)jstart_block * (off_t)block_size;
254 jib.size = (off_t)journal_size;
255
256 fd = open(jib_fname, O_CREAT|O_TRUNC|O_RDWR, 000);
257 if (fd < 0) {
258 fprintf(stderr, "Could not create journal info block file on volume %s (%s)\n",
259 volname, strerror(errno));
260 unlink(journal_fname);
261 return 5;
262 }
263
264 memcpy(buf, &jib, sizeof(jib));
265 if (write(fd, buf, block_size) != block_size) {
266 fprintf(stderr, "Failed to write journal info block on volume %s (%s)!\n",
267 volname, strerror(errno));
268 unlink(journal_fname);
269 return 10;
270 }
271
272 fsync(fd);
273 close(fd);
274 hide_file(jib_fname);
275
276 jinfo_block = get_start_block(jib_fname);
277
278
279 //
280 // Now make the volume journaled!
281 //
282 memset(sysctl_info, 0, sizeof(sysctl_info));
283 sysctl_info[0] = CTL_VFS;
284 sysctl_info[1] = sfs.f_fsid.val[1];
285 sysctl_info[2] = HFS_BECOME_JOURNALED;
286 sysctl_info[3] = jinfo_block;
287 sysctl_info[4] = jstart_block;
288 sysctl_info[5] = journal_size;
289
290 //printf("fs type: 0x%x\n", sysctl_info[1]);
291 //printf("jinfo block : 0x%x\n", jinfo_block);
292 //printf("jstart block: 0x%x\n", jstart_block);
293 //printf("journal size: 0x%x\n", journal_size);
294
295 ret = sysctl((void *)sysctl_info, 6, NULL, NULL, NULL, 0);
296 if (ret != 0) {
297 fprintf(stderr, "Failed to make volume %s journaled (%s)\n",
298 volname, strerror(errno));
299 unlink(journal_fname);
300 unlink(jib_fname);
301 return 20;
302 }
303
304 return 0;
305 }
306
307
308 int
309 DoUnJournal(char *volname)
310 {
311 int result;
312 int sysctl_info[8];
313 struct statfs sfs;
314 char jbuf[MAXPATHLEN];
315
316 if (statfs(volname, &sfs) != 0) {
317 fprintf(stderr, "Can't stat volume %s (%s).\n", volname, strerror(errno));
318 return 10;
319 }
320
321 if ((sfs.f_flags & MNT_JOURNALED) == 0) {
322 fprintf(stderr, "Volume %s is not journaled.\n", volname);
323 return 1;
324 }
325
326 if (chdir(volname) != 0) {
327 fprintf(stderr, "Can't locate volume %s to turn off journaling (%s).\n",
328 volname, strerror(errno));
329 return 10;
330 }
331
332 memset(sysctl_info, 0, sizeof(sysctl_info));
333 sysctl_info[0] = CTL_VFS;
334 sysctl_info[1] = sfs.f_fsid.val[1];
335 sysctl_info[2] = HFS_BECOME_UNJOURNALED;
336
337 result = sysctl((void *)sysctl_info, 6, NULL, NULL, NULL, 0);
338 if (result != 0) {
339 fprintf(stderr, "Failed to make volume %s UN-journaled (%s)\n",
340 volname, strerror(errno));
341 return 20;
342 }
343
344 sprintf(jbuf, "%s/%s", volname, journal_fname);
345 if (unlink(jbuf) != 0) {
346 fprintf(stderr, "Failed to remove the journal %s (%s)\n",
347 jbuf, strerror(errno));
348 }
349
350 sprintf(jbuf, "%s/%s", volname, jib_fname);
351 if (unlink(jbuf) != 0) {
352 fprintf(stderr, "Failed to remove the journal info block %s (%s)\n",
353 jbuf, strerror(errno));
354 }
355
356 printf("Journaling disabled on %s\n", volname);
357
358 return 0;
359 }