GNU/Linux >> Tutoriels Linux >  >> Linux

Comment créer un fichier uniquement s'il n'existe pas ?

homme 2 ouvert :

O_EXCL Assurez-vous que cet appel crée le fichier :si cet indicateur est spécifié en conjonction avec O_CREAT, et que le chemin existe déjà, alors open() échouera. Le comportement de O_EXCL est indéfini si O_CREAT n'est pas spécifié.

donc, vous pouvez appeler fd = open(name, O_CREAT | O_EXCL, 0644); /* Open() est atomique. (pour une raison) */

MISE À JOUR :et vous devez bien sûr OR l'un des drapeaux O_RDONLY, O_WRONLY ou O_RDWR dans l'argument flags.


J'ai appris la démonisation appropriée ici (à l'époque):

  • http://www.enderunix.org/docs/eng/daemon.php

C'est une bonne lecture. Depuis, j'ai amélioré le code de verrouillage pour éliminer les conditions de concurrence sur les plates-formes qui permettent le verrouillage des fichiers consultatifs avec des régions spécifiques spécifiées.

Voici un extrait pertinent d'un projet auquel j'ai participé :

static int zfsfuse_do_locking(int in_child)
{
    /* Ignores errors since the directory might already exist */
    mkdir(LOCKDIR, 0700);

    if (!in_child)
    {
        ASSERT(lock_fd == -1);
        /*
         * before the fork, we create the file, truncating it, and locking the
         * first byte
         */
        lock_fd = creat(LOCKFILE, S_IRUSR | S_IWUSR);
        if(lock_fd == -1)
            return -1;

        /*
         * only if we /could/ lock all of the file,
         * we shall lock just the first byte; this way
         * we can let the daemon child process lock the
         * remainder of the file after forking
         */
        if (0==lockf(lock_fd, F_TEST, 0))
            return lockf(lock_fd, F_TLOCK, 1);
        else
            return -1;
    } else
    {
        ASSERT(lock_fd != -1);
        /*
         * after the fork, we instead try to lock only the region /after/ the
         * first byte; the file /must/ already exist. Only in this way can we
         * prevent races with locking before or after the daemonization
         */
        lock_fd = open(LOCKFILE, O_WRONLY);
        if(lock_fd == -1)
            return -1;

        ASSERT(-1 == lockf(lock_fd, F_TEST, 0)); /* assert that parent still has the lock on the first byte */
        if (-1 == lseek(lock_fd, 1, SEEK_SET))
        {
            perror("lseek");
            return -1;
        }

        return lockf(lock_fd, F_TLOCK, 0);
    }
}

void do_daemon(const char *pidfile)
{
    chdir("/");
    if (pidfile) {
        struct stat dummy;
        if (0 == stat(pidfile, &dummy)) {
            cmn_err(CE_WARN, "%s already exists; aborting.", pidfile);
            exit(1);
        }
    }

    /*
     * info gleaned from the web, notably
     * http://www.enderunix.org/docs/eng/daemon.php
     *
     * and
     *
     * http://sourceware.org/git/?p=glibc.git;a=blob;f=misc/daemon.c;h=7597ce9996d5fde1c4ba622e7881cf6e821a12b4;hb=HEAD
     */
    {
        int forkres, devnull;

        if(getppid()==1)
            return; /* already a daemon */

        forkres=fork();
        if (forkres<0)
        { /* fork error */
            cmn_err(CE_WARN, "Cannot fork (%s)", strerror(errno));
            exit(1);
        }
        if (forkres>0)
        {
            int i;
            /* parent */
            for (i=getdtablesize();i>=0;--i)
                if ((lock_fd!=i) && (ioctl_fd!=i))       /* except for the lockfile and the comm socket */
                    close(i);                            /* close all descriptors */

            /* allow for airtight lockfile semantics... */
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 200000;  /* 0.2 seconds */
            select(0, NULL, NULL, NULL, &tv);

            VERIFY(0 == close(lock_fd));
            lock_fd == -1;
            exit(0);
        }

        /* child (daemon) continues */
        setsid();                         /* obtain a new process group */
        VERIFY(0 == chdir("/"));          /* change working directory */
        umask(027);                       /* set newly created file permissions */
        devnull=open("/dev/null",O_RDWR); /* handle standard I/O */
        ASSERT(-1 != devnull);
        dup2(devnull, 0); /* stdin  */
        dup2(devnull, 1); /* stdout */
        dup2(devnull, 2); /* stderr */
        if (devnull>2)
            close(devnull);

        /*
         * contrary to recommendation, do _not_ ignore SIGCHLD:
         * it will break exec-ing subprocesses, e.g. for kstat mount and
         * (presumably) nfs sharing!
         *
         * this will lead to really bad performance too
         */
        signal(SIGTSTP,SIG_IGN);     /* ignore tty signals */
        signal(SIGTTOU,SIG_IGN);
        signal(SIGTTIN,SIG_IGN);
    }

    if (0 != zfsfuse_do_locking(1))
    {
        cmn_err(CE_WARN, "Unexpected locking conflict (%s: %s)", strerror(errno), LOCKFILE);
        exit(1);
    }

    if (pidfile) {
        FILE *f = fopen(pidfile, "w");
        if (!f) {
            cmn_err(CE_WARN, "Error opening %s.", pidfile);
            exit(1);
        }
        if (fprintf(f, "%d\n", getpid()) < 0) {
            unlink(pidfile);
            exit(1);
        }
        if (fclose(f) != 0) {
            unlink(pidfile);
            exit(1);
        }
    }
}

Voir aussi http://gitweb.zfs-fuse.net/?p=sehe;a=blob;f=src/zfs-fuse/util.c;h=7c9816cc895db4f65b94592eebf96d05cd2c369a;hb=refs/heads/maint


Linux
  1. Comment créer un fichier ZIP protégé par mot de passe sous Linux

  2. Comment créer ou augmenter l'espace d'échange sous Linux

  3. Comment créer un fichier d'échange sous Linux

  4. Comment rediriger uniquement Stderr ?

  5. Comment créer un fichier avec une taille donnée sous Linux ?

Comment créer des répertoires à partir d'un fichier texte sous Linux

Comment créer un gros fichier de 1 Go ou 10 Go sous Linux

Comment créer et utiliser un fichier d'échange sous Linux

Comment créer un fichier de site Web

Comment créer un fichier Tar gz

Comment créer un système de fichiers XFS