source: mainline/uspace/lib/c/generic/vol.c@ 08e103d4

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

  • Property mode set to 100644
File size: 13.4 KB
Line 
1/*
2 * Copyright (c) 2015 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libc
30 * @{
31 */
32/** @file Volume service API
33 */
34
35#include <abi/ipc/interfaces.h>
36#include <errno.h>
37#include <ipc/services.h>
38#include <ipc/vol.h>
39#include <loc.h>
40#include <stdlib.h>
41#include <str.h>
42#include <vfs/vfs.h>
43#include <vol.h>
44
45/** Create Volume service session.
46 *
47 * @param rvol Place to store pointer to volume service session.
48 * @return EOK on success, ENOMEM if out of memory, EIO if service
49 * cannot be contacted.
50 */
51errno_t vol_create(vol_t **rvol)
52{
53 vol_t *vol;
54 service_id_t vol_svcid;
55 errno_t rc;
56
57 vol = calloc(1, sizeof(vol_t));
58 if (vol == NULL) {
59 rc = ENOMEM;
60 goto error;
61 }
62
63 rc = loc_service_get_id(SERVICE_NAME_VOLSRV, &vol_svcid, 0);
64 if (rc != EOK) {
65 rc = ENOENT;
66 goto error;
67 }
68
69 vol->sess = loc_service_connect(vol_svcid, INTERFACE_VOL, 0);
70 if (vol->sess == NULL) {
71 rc = EIO;
72 goto error;
73 }
74
75 *rvol = vol;
76 return EOK;
77error:
78 free(vol);
79 return rc;
80}
81
82/** Destroy volume service session.
83 *
84 * @param vol Volume service session
85 */
86void vol_destroy(vol_t *vol)
87{
88 if (vol == NULL)
89 return;
90
91 async_hangup(vol->sess);
92 free(vol);
93}
94
95/** Get list of IDs into a buffer of fixed size.
96 *
97 * @param vol Volume service
98 * @param method IPC method
99 * @param arg1 First argument
100 * @param id_buf Buffer to store IDs
101 * @param buf_size Buffer size
102 * @param act_size Place to store actual size of complete data.
103 *
104 * @return EOK on success or an error code.
105 */
106static errno_t vol_get_ids_once(vol_t *vol, sysarg_t method, sysarg_t arg1,
107 sysarg_t *id_buf, size_t buf_size, size_t *act_size)
108{
109 async_exch_t *exch = async_exchange_begin(vol->sess);
110
111 ipc_call_t answer;
112 aid_t req = async_send_1(exch, method, arg1, &answer);
113 errno_t rc = async_data_read_start(exch, id_buf, buf_size);
114
115 async_exchange_end(exch);
116
117 if (rc != EOK) {
118 async_forget(req);
119 return rc;
120 }
121
122 errno_t retval;
123 async_wait_for(req, &retval);
124
125 if (retval != EOK) {
126 return retval;
127 }
128
129 *act_size = IPC_GET_ARG1(answer);
130 return EOK;
131}
132
133/** Get list of IDs.
134 *
135 * Returns an allocated array of service IDs.
136 *
137 * @param vol Volume service
138 * @param method IPC method
139 * @param arg1 IPC argument 1
140 * @param data Place to store pointer to array of IDs
141 * @param count Place to store number of IDs
142 * @return EOK on success or an error code
143 */
144static errno_t vol_get_ids_internal(vol_t *vol, sysarg_t method, sysarg_t arg1,
145 sysarg_t **data, size_t *count)
146{
147 *data = NULL;
148 *count = 0;
149
150 size_t act_size = 0;
151 errno_t rc = vol_get_ids_once(vol, method, arg1, NULL, 0, &act_size);
152 if (rc != EOK)
153 return rc;
154
155 size_t alloc_size = act_size;
156 service_id_t *ids = malloc(alloc_size);
157 if (ids == NULL)
158 return ENOMEM;
159
160 while (true) {
161 rc = vol_get_ids_once(vol, method, arg1, ids, alloc_size,
162 &act_size);
163 if (rc != EOK)
164 return rc;
165
166 if (act_size <= alloc_size)
167 break;
168
169 alloc_size = act_size;
170 ids = realloc(ids, alloc_size);
171 if (ids == NULL)
172 return ENOMEM;
173 }
174
175 *count = act_size / sizeof(service_id_t);
176 *data = ids;
177 return EOK;
178}
179
180/** Get list of partitions as array of service IDs.
181 *
182 * @param vol Volume service
183 * @param data Place to store pointer to array
184 * @param count Place to store length of array (number of entries)
185 *
186 * @return EOK on success or an error code
187 */
188errno_t vol_get_parts(vol_t *vol, service_id_t **data, size_t *count)
189{
190 return vol_get_ids_internal(vol, VOL_GET_PARTS, 0, data, count);
191}
192
193/** Add partition.
194 *
195 * After a partition is created (e.g. as a result of deleting a label
196 * the dummy partition is created), it can take some (unknown) time
197 * until it is discovered.
198 *
199 * @param vol Volume service
200 * @param sid Service ID of the partition
201 * @return EOK on success or an error code
202 */
203errno_t vol_part_add(vol_t *vol, service_id_t sid)
204{
205 async_exch_t *exch;
206 errno_t retval;
207
208 exch = async_exchange_begin(vol->sess);
209 retval = async_req_1_0(exch, VOL_PART_ADD, sid);
210 async_exchange_end(exch);
211
212 if (retval != EOK)
213 return retval;
214
215 return EOK;
216}
217
218/** Get partition information.
219 *
220 * @param vol Volume service
221 * @param sid Service ID of the partition
222 * @param vinfo Place to store partition information
223 * @return EOK on success or an error code
224 */
225errno_t vol_part_info(vol_t *vol, service_id_t sid, vol_part_info_t *vinfo)
226{
227 async_exch_t *exch;
228 errno_t retval;
229 ipc_call_t answer;
230
231 exch = async_exchange_begin(vol->sess);
232 aid_t req = async_send_1(exch, VOL_PART_INFO, sid, &answer);
233
234 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_part_info_t));
235 async_exchange_end(exch);
236 if (rc != EOK) {
237 async_forget(req);
238 return EIO;
239 }
240
241 async_wait_for(req, &retval);
242 if (retval != EOK)
243 return EIO;
244
245 return EOK;
246}
247
248/** Unmount partition (and possibly eject the media).
249 *
250 * @param vol Volume service
251 * @param sid Service ID of the partition
252 * @return EOK on success or an error code
253 */
254errno_t vol_part_eject(vol_t *vol, service_id_t sid)
255{
256 async_exch_t *exch;
257 errno_t retval;
258
259 exch = async_exchange_begin(vol->sess);
260 retval = async_req_1_0(exch, VOL_PART_EJECT, sid);
261 async_exchange_end(exch);
262
263 if (retval != EOK)
264 return retval;
265
266 return EOK;
267}
268
269/** Erase partition (to the extent where we will consider it not containing
270 * a file system.
271 *
272 * @param vol Volume service
273 * @param sid Service ID of the partition
274 * @return EOK on success or an error code
275 */
276errno_t vol_part_empty(vol_t *vol, service_id_t sid)
277{
278 async_exch_t *exch;
279 errno_t retval;
280
281 exch = async_exchange_begin(vol->sess);
282 retval = async_req_1_0(exch, VOL_PART_EMPTY, sid);
283 async_exchange_end(exch);
284
285 if (retval != EOK)
286 return retval;
287
288 return EOK;
289}
290
291/** Insert volume.
292 *
293 * This will re-mount the volume if it has been ejected previously.
294 *
295 * @param vol Volume service
296 * @param sid Service ID of the partition
297 * @return EOK on success or an error code
298 */
299errno_t vol_part_insert(vol_t *vol, service_id_t sid)
300{
301 async_exch_t *exch;
302 errno_t retval;
303
304 exch = async_exchange_begin(vol->sess);
305 retval = async_req_1_0(exch, VOL_PART_INSERT, sid);
306 async_exchange_end(exch);
307
308 if (retval != EOK)
309 return retval;
310
311 return EOK;
312}
313
314/** Insert volume by path.
315 *
316 * @param vol Volume service
317 * @param path Filesystem path
318 *
319 * @return EOK on success or an error code
320 */
321errno_t vol_part_insert_by_path(vol_t *vol, const char *path)
322{
323 async_exch_t *exch;
324 ipc_call_t answer;
325 errno_t retval;
326
327 exch = async_exchange_begin(vol->sess);
328 aid_t req = async_send_0(exch, VOL_PART_INSERT_BY_PATH, &answer);
329
330 retval = async_data_write_start(exch, path, str_bytes(path));
331 if (retval != EOK) {
332 async_exchange_end(exch);
333 async_forget(req);
334 return retval;
335 }
336
337 async_exchange_end(exch);
338 async_wait_for(req, &retval);
339
340 if (retval != EOK)
341 return retval;
342
343 return EOK;
344}
345
346/** Get volume label support.
347 *
348 * @param vol Volume service
349 * @param fstype File system type
350 * @param vlsupp Place to store volume label support information
351 * @return EOK on success or an error code
352 */
353errno_t vol_part_get_lsupp(vol_t *vol, vol_fstype_t fstype,
354 vol_label_supp_t *vlsupp)
355{
356 async_exch_t *exch;
357 errno_t retval;
358 ipc_call_t answer;
359
360 exch = async_exchange_begin(vol->sess);
361 aid_t req = async_send_1(exch, VOL_PART_LSUPP, fstype, &answer);
362 errno_t rc = async_data_read_start(exch, vlsupp, sizeof(vol_label_supp_t));
363 async_exchange_end(exch);
364
365 if (rc != EOK) {
366 async_forget(req);
367 return EIO;
368 }
369
370 async_wait_for(req, &retval);
371 if (retval != EOK)
372 return EIO;
373
374 return EOK;
375}
376
377/** Create file system.
378 *
379 * @param vol Volume service
380 * @param sid Partition service ID
381 * @param fstype File system type
382 * @param label Volume label
383 * @param mountp Mount point
384 *
385 * @return EOK on success or an error code
386 */
387errno_t vol_part_mkfs(vol_t *vol, service_id_t sid, vol_fstype_t fstype,
388 const char *label, const char *mountp)
389{
390 async_exch_t *exch;
391 ipc_call_t answer;
392 errno_t retval;
393
394 exch = async_exchange_begin(vol->sess);
395 aid_t req = async_send_2(exch, VOL_PART_MKFS, sid, fstype, &answer);
396
397 retval = async_data_write_start(exch, label, str_bytes(label));
398 if (retval != EOK) {
399 async_exchange_end(exch);
400 async_forget(req);
401 return retval;
402 }
403
404 retval = async_data_write_start(exch, mountp, str_bytes(mountp));
405 if (retval != EOK) {
406 async_exchange_end(exch);
407 async_forget(req);
408 return retval;
409 }
410
411 async_exchange_end(exch);
412 async_wait_for(req, &retval);
413
414 if (retval != EOK)
415 return retval;
416
417 return EOK;
418}
419
420/** Set mount point for partition.
421 *
422 * @param vol Volume service
423 * @param sid Partition service ID
424 * @param mountp Mount point
425 *
426 * @return EOK on success or an error code
427 */
428errno_t vol_part_set_mountp(vol_t *vol, service_id_t sid,
429 const char *mountp)
430{
431 async_exch_t *exch;
432 ipc_call_t answer;
433 errno_t retval;
434
435 exch = async_exchange_begin(vol->sess);
436 aid_t req = async_send_1(exch, VOL_PART_SET_MOUNTP, sid,
437 &answer);
438
439 retval = async_data_write_start(exch, mountp, str_bytes(mountp));
440 if (retval != EOK) {
441 async_exchange_end(exch);
442 async_forget(req);
443 return retval;
444 }
445
446 async_exchange_end(exch);
447 async_wait_for(req, &retval);
448
449 if (retval != EOK)
450 return retval;
451
452 return EOK;
453}
454
455/** Format file system type as string.
456 *
457 * @param fstype File system type
458 * @param rstr Place to store pointer to newly allocated string
459 * @return EOK on success, ENOMEM if out of memory
460 */
461errno_t vol_fstype_format(vol_fstype_t fstype, char **rstr)
462{
463 const char *sfstype;
464 char *s;
465
466 sfstype = NULL;
467 switch (fstype) {
468 case fs_exfat:
469 sfstype = "ExFAT";
470 break;
471 case fs_fat:
472 sfstype = "FAT";
473 break;
474 case fs_minix:
475 sfstype = "MINIX";
476 break;
477 case fs_ext4:
478 sfstype = "Ext4";
479 break;
480 case fs_cdfs:
481 sfstype = "ISO 9660";
482 break;
483 }
484
485 s = str_dup(sfstype);
486 if (s == NULL)
487 return ENOMEM;
488
489 *rstr = s;
490 return EOK;
491}
492
493/** Format partition content / file system type as string.
494 *
495 * @param pcnt Partition content
496 * @param fstype File system type
497 * @param rstr Place to store pointer to newly allocated string
498 * @return EOK on success, ENOMEM if out of memory
499 */
500errno_t vol_pcnt_fs_format(vol_part_cnt_t pcnt, vol_fstype_t fstype,
501 char **rstr)
502{
503 int rc;
504 char *s = NULL;
505
506 switch (pcnt) {
507 case vpc_empty:
508 s = str_dup("Empty");
509 if (s == NULL)
510 return ENOMEM;
511 break;
512 case vpc_fs:
513 rc = vol_fstype_format(fstype, &s);
514 if (rc != EOK)
515 return ENOMEM;
516 break;
517 case vpc_unknown:
518 s = str_dup("Unknown");
519 if (s == NULL)
520 return ENOMEM;
521 break;
522 }
523
524 assert(s != NULL);
525 *rstr = s;
526 return EOK;
527}
528
529/** Validate mount point.
530 *
531 * Verify that mount point is valid. A valid mount point is
532 * one of:
533 * - 'Auto'
534 * - 'None'
535 * - /path (string beginning with '/') to an existing directory
536 *
537 * @return EOK if mount point is in valid, EINVAL if the format is invalid,
538 * ENOENT if the directory does not exist
539 */
540errno_t vol_mountp_validate(const char *mountp)
541{
542 errno_t rc;
543 vfs_stat_t stat;
544
545 if (str_cmp(mountp, "Auto") == 0 || str_cmp(mountp, "auto") == 0)
546 return EOK;
547
548 if (str_casecmp(mountp, "None") == 0 || str_cmp(mountp, "none") == 0)
549 return EOK;
550
551 if (mountp[0] == '/') {
552 rc = vfs_stat_path(mountp, &stat);
553 if (rc != EOK || !stat.is_directory)
554 return ENOENT;
555
556 return EOK;
557 }
558
559 return EINVAL;
560}
561
562/** Get list of volumes as array of volume IDs.
563 *
564 * @param vol Volume service
565 * @param data Place to store pointer to array
566 * @param count Place to store length of array (number of entries)
567 *
568 * @return EOK on success or an error code
569 */
570errno_t vol_get_volumes(vol_t *vol, volume_id_t **data, size_t *count)
571{
572 return vol_get_ids_internal(vol, VOL_GET_VOLUMES, 0,
573 (sysarg_t **) data, count);
574}
575
576/** Get volume configuration information.
577 *
578 * @param vol Volume service
579 * @param vid Volume ID
580 * @param vinfo Place to store volume configuration information
581 * @return EOK on success or an error code
582 */
583errno_t vol_info(vol_t *vol, volume_id_t vid, vol_info_t *vinfo)
584{
585 async_exch_t *exch;
586 errno_t retval;
587 ipc_call_t answer;
588
589 exch = async_exchange_begin(vol->sess);
590 aid_t req = async_send_1(exch, VOL_INFO, vid.id, &answer);
591
592 errno_t rc = async_data_read_start(exch, vinfo, sizeof(vol_info_t));
593 async_exchange_end(exch);
594 if (rc != EOK) {
595 async_forget(req);
596 return EIO;
597 }
598
599 async_wait_for(req, &retval);
600 if (retval != EOK)
601 return EIO;
602
603 return EOK;
604}
605
606/** @}
607 */
Note: See TracBrowser for help on using the repository browser.